Files
OpenCellular/chip/npcx/uart.c
Mulin Chao 4123b5861e npcx: clock: uart: Add support for npcx7 series ec.
In old clock driver, the relationships between each clock sources are
ambiguous. For example, we treat OSC_CLK and FM_CLK as the same but
sometimes they're not on npcx5. (Only one OSC_CLK definition cannot
present the npcx ec's clock tree very well.) This CL added FM_CLK,
CORE_CLK, and APBx_CLK definitions and used macro functions to confine
the limitation of each clock sources in clock_chip.h to make it more
clearly.

We also modified the uart driver and fixed its source clock to 15MHz so
far in this CL. Since npcx7 already supports uart wake-up mechanism, we
removed the functions of switching pins from UART to GPIO by CHIP_FAMILY
definitions for saving code space.

It also includes:
1. Remove useless CHIP_VERSION definition.
2. Move frequency multiplier values M/N for OSC_CLK to clock_chip.h
3. Add clock_get_fm_freq() for the modules rely on it. Ex, peci.
4. Add clock turbo utilities for npcx7 series.
5. Support uart wake-up mechanism for npcx7 series.

BRANCH=none
BUG=none
TEST=No build errors for all boards using npcx5 series.
     Build poppy board and upload FW to platform. No issues found.
     Passed clock turbo, sysjump and wake-up from UART signals stress
     tests on npcx796f evb.

Change-Id: Id01a8a5d0263f0d2438e6346dfa33bcdef2be56e
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/486821
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
2017-04-25 21:19:57 -07:00

202 lines
4.3 KiB
C

/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* UART module for Chrome EC */
#include "clock.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "lpc.h"
#include "registers.h"
#include "clock_chip.h"
#include "system.h"
#include "task.h"
#include "uart.h"
#include "util.h"
static int init_done;
int uart_init_done(void)
{
return init_done;
}
void uart_tx_start(void)
{
/* We needn't to switch uart from gpio again in npcx7. */
#if defined(CHIP_FAMILY_NPCX5)
if (uart_is_enable_wakeup()) {
/* disable MIWU */
uart_enable_wakeup(0);
/* Set pin-mask for UART */
npcx_gpio2uart();
/* enable uart again from MIWU mode */
task_enable_irq(NPCX_IRQ_UART);
}
#endif
/* If interrupt is already enabled, nothing to do */
if (NPCX_UICTRL & 0x20)
return;
/* Do not allow deep sleep while transmit in progress */
disable_sleep(SLEEP_MASK_UART);
/*
* Re-enable the transmit interrupt, then forcibly trigger the
* interrupt. This works around a hardware problem with the
* UART where the FIFO only triggers the interrupt when its
* threshold is _crossed_, not just met.
*/
NPCX_UICTRL |= 0x20;
task_trigger_irq(NPCX_IRQ_UART);
}
void uart_tx_stop(void) /* Disable TX interrupt */
{
NPCX_UICTRL &= ~0x20;
/* Re-allow deep sleep */
enable_sleep(SLEEP_MASK_UART);
}
void uart_tx_flush(void)
{
/* Wait for transmit FIFO empty */
while (!(NPCX_UICTRL & 0x01))
;
/* Wait for transmitting completed */
while (NPCX_USTAT & 0x40)
;
}
int uart_tx_ready(void)
{
return NPCX_UICTRL & 0x01; /*if TX FIFO is empty return 1*/
}
int uart_tx_in_progress(void)
{
/* Transmit is in progress if the TX busy bit is set. */
return NPCX_USTAT & 0x40; /*BUSY bit , if busy return 1*/
}
int uart_rx_available(void)
{
uint8_t ctrl = NPCX_UICTRL;
#ifdef CONFIG_LOW_POWER_IDLE
/*
* Activity seen on UART RX pin while UART was disabled for deep sleep.
* The console won't see that character because the UART is disabled,
* so we need to inform the clock module of UART activity ourselves.
*/
if (ctrl & 0x02)
clock_refresh_console_in_use();
#endif
return ctrl & 0x02; /* If RX FIFO is empty return '0'*/
}
void uart_write_char(char c)
{
/* Wait for space in transmit FIFO. */
while (!uart_tx_ready())
;
NPCX_UTBUF = c;
}
int uart_read_char(void)
{
return NPCX_URBUF;
}
static void uart_clear_rx_fifo(int channel)
{
int scratch __attribute__ ((unused));
if (channel == 0) { /* suppose '0' is EC UART*/
/*if '1' that mean have a RX data on the FIFO register*/
while ((NPCX_UICTRL & 0x02))
scratch = NPCX_URBUF;
}
}
/**
* Interrupt handler for UART0
*/
void uart_ec_interrupt(void)
{
/* Read input FIFO until empty, then fill output FIFO */
uart_process_input();
uart_process_output();
}
DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 0);
static void uart_config(void)
{
/* Configure pins from GPIOs to CR_UART */
gpio_config_module(MODULE_UART, 1);
/* Enable MIWU IRQ of UART */
#if NPCX_UART_MODULE2
task_enable_irq(NPCX_IRQ_WKINTG_1);
#else
task_enable_irq(NPCX_IRQ_WKINTB_1);
#endif
/*
* Configure the UART wake-up event triggered from a falling edge
* on CR_SIN pin.
*/
#if defined(CHIP_FAMILY_NPCX7) && defined(CONFIG_LOW_POWER_IDLE)
SET_BIT(NPCX_WKEDG(MIWU_TABLE_1, MIWU_GROUP_8), 7);
#endif
/*
* If apb2's clock is not 15MHz, we need to find the other optimized
* values of UPSR and UBAUD for baud rate 115200.
*/
#if (NPCX_APB_CLOCK(2) != 15000000)
#error "Unsupported apb2 clock for UART!"
#endif
/* Fix baud rate to 115200 */
NPCX_UPSR = 0x38;
NPCX_UBAUD = 0x01;
/*
* 8-N-1, FIFO enabled. Must be done after setting
* the divisor for the new divisor to take effect.
*/
NPCX_UFRS = 0x00;
NPCX_UICTRL = 0x40; /* receive int enable only */
}
void uart_init(void)
{
uint32_t mask = 0;
/*
* Enable UART0 in run, sleep, and deep sleep modes. Enable the Host
* UART in run and sleep modes.
*/
mask = 0x10; /* bit 4 */
clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL);
/* Set pin-mask for UART */
npcx_gpio2uart();
/* Configure UARTs (identically) */
uart_config();
/*
* Enable interrupts for UART0 only. Host UART will have to wait
* until the LPC bus is initialized.
*/
uart_clear_rx_fifo(0);
task_enable_irq(NPCX_IRQ_UART);
init_done = 1;
}