diff options
Diffstat (limited to 'chip/lm4/uart.c')
-rw-r--r-- | chip/lm4/uart.c | 352 |
1 files changed, 0 insertions, 352 deletions
diff --git a/chip/lm4/uart.c b/chip/lm4/uart.c deleted file mode 100644 index 7ccea9eb75..0000000000 --- a/chip/lm4/uart.c +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright 2012 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 "system.h" -#include "task.h" -#include "uart.h" -#include "util.h" - -#ifdef CONFIG_UART_HOST -#define IRQ_UART_HOST CONCAT2(LM4_IRQ_UART, CONFIG_UART_HOST) -#endif - -static int init_done; - -int uart_init_done(void) -{ - return init_done; -} - -void uart_tx_start(void) -{ - /* If interrupt is already enabled, nothing to do */ - if (LM4_UART_IM(0) & 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. - */ - LM4_UART_IM(0) |= 0x20; - task_trigger_irq(LM4_IRQ_UART0); -} - -void uart_tx_stop(void) -{ - LM4_UART_IM(0) &= ~0x20; - - /* Re-allow deep sleep */ - enable_sleep(SLEEP_MASK_UART); -} - -void uart_tx_flush(void) -{ - /* Wait for transmit FIFO empty */ - while (!(LM4_UART_FR(0) & 0x80)) - ; -} - -int uart_tx_ready(void) -{ - return !(LM4_UART_FR(0) & 0x20); -} - -int uart_tx_in_progress(void) -{ - /* Transmit is in progress if the TX busy bit is set. */ - return LM4_UART_FR(0) & 0x08; -} - -int uart_rx_available(void) -{ - return !(LM4_UART_FR(0) & 0x10); -} - -void uart_write_char(char c) -{ - /* Wait for space in transmit FIFO. */ - while (!uart_tx_ready()) - ; - - LM4_UART_DR(0) = c; -} - -int uart_read_char(void) -{ - return LM4_UART_DR(0); -} - -static void uart_clear_rx_fifo(int channel) -{ - int scratch __attribute__ ((unused)); - while (!(LM4_UART_FR(channel) & 0x10)) - scratch = LM4_UART_DR(channel); -} - -/** - * Interrupt handler for UART0 - */ -void uart_ec_interrupt(void) -{ - /* Clear transmit and receive interrupt status */ - LM4_UART_ICR(0) = 0x70; - - - /* Read input FIFO until empty, then fill output FIFO */ - uart_process_input(); - uart_process_output(); -} -DECLARE_IRQ(LM4_IRQ_UART0, uart_ec_interrupt, 1); - -#ifdef CONFIG_UART_HOST - -/** - * Interrupt handler for Host UART - */ -void uart_host_interrupt(void) -{ - /* Clear transmit and receive interrupt status */ - LM4_UART_ICR(CONFIG_UART_HOST) = 0x70; - -#ifdef CONFIG_HOSTCMD_LPC - /* - * If we have space in our FIFO and a character is pending in LPC, - * handle that character. - */ - if (!(LM4_UART_FR(CONFIG_UART_HOST) & 0x20) && lpc_comx_has_char()) { - /* Copy the next byte then disable transmit interrupt */ - LM4_UART_DR(CONFIG_UART_HOST) = lpc_comx_get_char(); - LM4_UART_IM(CONFIG_UART_HOST) &= ~0x20; - } - - /* - * Handle received character. There is no flow control on input; - * received characters are blindly forwarded to LPC. This is ok - * because LPC is much faster than UART, and we don't have flow control - * on the UART receive-side either. - */ - if (!(LM4_UART_FR(CONFIG_UART_HOST) & 0x10)) - lpc_comx_put_char(LM4_UART_DR(CONFIG_UART_HOST)); -#endif -} -/* Must be same prio as LPC interrupt handler so they don't preempt */ -DECLARE_IRQ(IRQ_UART_HOST, uart_host_interrupt, 2); - -#endif /* CONFIG_UART_HOST */ - -static void uart_config(int port) -{ - /* Disable the port */ - LM4_UART_CTL(port) = 0x0300; - /* Use the internal oscillator */ - LM4_UART_CC(port) = 0x1; - /* Set the baud rate divisor */ - LM4_UART_IBRD(port) = (INTERNAL_CLOCK / 16) / CONFIG_UART_BAUD_RATE; - LM4_UART_FBRD(port) = - (((INTERNAL_CLOCK / 16) % CONFIG_UART_BAUD_RATE) * 64 - + CONFIG_UART_BAUD_RATE / 2) / CONFIG_UART_BAUD_RATE; - /* - * 8-N-1, FIFO enabled. Must be done after setting - * the divisor for the new divisor to take effect. - */ - LM4_UART_LCRH(port) = 0x70; - /* - * Interrupt when RX fifo at minimum (>= 1/8 full), and TX fifo - * when <= 1/4 full - */ - LM4_UART_IFLS(port) = 0x01; - /* - * Unmask receive-FIFO, receive-timeout. We need - * receive-timeout because the minimum RX FIFO depth is 1/8 = 2 - * bytes; without the receive-timeout we'd never be notified - * about single received characters. - */ - LM4_UART_IM(port) = 0x50; - /* Enable the port */ - LM4_UART_CTL(port) |= 0x0001; -} - -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 |= 1; - clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL); - -#ifdef CONFIG_UART_HOST - mask |= BIT(CONFIG_UART_HOST); -#endif - - clock_enable_peripheral(CGC_OFFSET_UART, mask, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - gpio_config_module(MODULE_UART, 1); - - /* Configure UARTs (identically) */ - uart_config(0); - -#ifdef CONFIG_UART_HOST - uart_config(CONFIG_UART_HOST); -#endif - - /* - * 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(LM4_IRQ_UART0); - - init_done = 1; -} - -#ifdef CONFIG_LOW_POWER_IDLE -void uart_enter_dsleep(void) -{ - const struct gpio_info g = gpio_list[GPIO_UART0_RX]; - - /* Disable the UART0 module interrupt. */ - task_disable_irq(LM4_IRQ_UART0); - - /* Disable UART0 peripheral in deep sleep. */ - clock_disable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP); - - /* - * Set the UART0 RX pin to be a generic GPIO with the flags defined - * in the board.c file. - */ - gpio_reset(GPIO_UART0_RX); - - /* Clear any pending GPIO interrupts on the UART0 RX pin. */ - LM4_GPIO_ICR(g.port) = g.mask; - - /* Enable GPIO interrupts on the UART0 RX pin. */ - gpio_enable_interrupt(GPIO_UART0_RX); -} - -void uart_exit_dsleep(void) -{ - const struct gpio_info g = gpio_list[GPIO_UART0_RX]; - - /* - * If the UART0 RX GPIO interrupt has not fired, then no edge has been - * detected. Disable the GPIO interrupt so that switching the pin over - * to a UART pin doesn't inadvertently cause a GPIO edge interrupt. - * Note: we can't disable this interrupt if it has already fired - * because then the IRQ will not get called. - */ - if (!(LM4_GPIO_MIS(g.port) & g.mask)) - gpio_disable_interrupt(GPIO_UART0_RX); - - /* Configure UART0 pins for use in UART peripheral. */ - gpio_config_module(MODULE_UART, 1); - - /* Clear pending interrupts on UART peripheral and enable interrupts. */ - uart_clear_rx_fifo(0); - task_enable_irq(LM4_IRQ_UART0); - - /* Enable UART0 peripheral in deep sleep */ - clock_enable_peripheral(CGC_OFFSET_UART, 0x1, CGC_MODE_DSLEEP); -} - -void uart_deepsleep_interrupt(enum gpio_signal signal) -{ - /* - * 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. - */ - clock_refresh_console_in_use(); - - /* Disable interrupts on UART0 RX pin to avoid repeated interrupts. */ - gpio_disable_interrupt(GPIO_UART0_RX); -} -#endif /* CONFIG_LOW_POWER_IDLE */ - - -/*****************************************************************************/ -/* COMx functions */ - -#ifdef CONFIG_UART_HOST - -void uart_comx_enable(void) -{ - uart_clear_rx_fifo(CONFIG_UART_HOST); - task_enable_irq(IRQ_UART_HOST); -} - -int uart_comx_putc_ok(void) -{ - if (LM4_UART_FR(CONFIG_UART_HOST) & 0x20) { - /* - * FIFO is full, so enable transmit interrupt to let us know - * when it empties. - */ - LM4_UART_IM(CONFIG_UART_HOST) |= 0x20; - return 0; - } else { - return 1; - } -} - -void uart_comx_putc(int c) -{ - LM4_UART_DR(CONFIG_UART_HOST) = c; -} - -#endif /* CONFIG_UART_HOST */ - -/*****************************************************************************/ -/* Console commands */ - -#ifdef CONFIG_CMD_COMXTEST - -/** - * Write a character to COMx, waiting for space in the output buffer if - * necessary. - */ -static void uart_comx_putc_wait(int c) -{ - while (!uart_comx_putc_ok()) - ; - uart_comx_putc(c); -} - -static int command_comxtest(int argc, char **argv) -{ - /* Put characters to COMX port */ - const char *c = argc > 1 ? argv[1] : "testing comx output!"; - - ccprintf("Writing \"%s\\r\\n\" to COMx UART...\n", c); - - while (*c) - uart_comx_putc_wait(*c++); - - uart_comx_putc_wait('\r'); - uart_comx_putc_wait('\n'); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(comxtest, command_comxtest, - "[string]", - "Write test data to COMx uart"); - -#endif /* CONFIG_CMD_COMXTEST */ |