/* 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; }