diff options
-rw-r--r-- | src/cpu/ti/am335x/uart.c | 178 |
1 files changed, 123 insertions, 55 deletions
diff --git a/src/cpu/ti/am335x/uart.c b/src/cpu/ti/am335x/uart.c index fdf5c05908..395ed866d9 100644 --- a/src/cpu/ti/am335x/uart.c +++ b/src/cpu/ti/am335x/uart.c @@ -1,9 +1,5 @@ /* - * (C) Copyright 2009 SAMSUNG Electronics - * Minkyu Kang <mk7.kang@samsung.com> - * Heungjun Kim <riverful.kim@samsung.com> - * - * based on drivers/serial/s3c64xx.c + * Copyright 2013 Google Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ +#include <config.h> #include <types.h> #include <uart.h> #include <arch/io.h> @@ -29,9 +25,14 @@ #include <cpu/ti/am335x/uart.h> -#define RX_FIFO_COUNT_MASK 0xff -#define RX_FIFO_FULL_MASK (1 << 8) -#define TX_FIFO_FULL_MASK (1 << 24) +#define EFR_ENHANCED_EN (1 << 4) +#define FCR_FIFO_EN (1 << 0) +#define MCR_TCR_TLR (1 << 6) +#define SYSC_SOFTRESET (1 << 1) +#define SYSS_RESETDONE (1 << 0) + +#define LSR_RXFIFOE (1 << 0) +#define LSR_TXFIFOE (1 << 5) /* * Initialise the serial port with the given baudrate. The settings @@ -39,28 +40,109 @@ */ static void am335x_uart_init_dev(void) { - /* FIXME: implement this - * ref: section 19.4.1.1.1 for reset - * ref: section 19.4.1.1.2 for FIFO, skip DMA - * ref: section 19.4.1.1.3 for baud rate, skip - * interrupts and protocol stuff. - * */ -#if 0 - struct s5p_uart *uart = (struct s5p_uart *)base_port; - - // TODO initialize with correct peripheral id by base_port. - exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); - - /* enable FIFOs */ - writel(0x1, &uart->ufcon); - writel(0, &uart->umcon); - /* 8N1 */ - writel(0x3, &uart->ulcon); - /* No interrupts, no DMA, pure polling */ - writel(0x245, &uart->ucon); - - serial_setbrg_dev(); -#endif + struct am335x_uart *uart = (struct am335x_uart *) + CONFIG_CONSOLE_SERIAL_UART_ADDRESS; + uint16_t lcr_orig, efr_orig, mcr_orig; + + /* reset the UART */ + write16(uart->sysc | SYSC_SOFTRESET, &uart->sysc); + while (!(read16(&uart->syss) & SYSS_RESETDONE)) + ; + + /* 1. switch to register config mode B */ + lcr_orig = read16(&uart->lcr); + write16(0xbf, &uart->lcr); + + /* + * 2. Set EFR ENHANCED_EN bit. To access this bit, registers must + * be in TCR_TLR submode, meaning EFR[4] = 1 and MCR[6] = 1. + */ + efr_orig = read16(&uart->efr); + write16(efr_orig | EFR_ENHANCED_EN, &uart->efr); + + /* 3. Switch to register config mode A */ + write16(0x80, &uart->lcr); + + /* 4. Enable register submode TCR_TLR to access the UARTi.UART_TLR */ + mcr_orig = read16(&uart->mcr); + write16(mcr_orig | MCR_TCR_TLR, &uart->mcr); + + /* 5. Enable the FIFO. For now we'll ignore FIFO triggers and DMA */ + write16(FCR_FIFO_EN, &uart->fcr); + + /* 6. Switch to configuration mode B */ + write16(0xbf, &uart->lcr); + /* Skip steps 7 and 8 (setting up FIFO triggers for DMA) */ + + /* 9. Restore original EFR value */ + write16(efr_orig, &uart->efr); + + /* 10. Switch to config mode A */ + write16(0x80, &uart->lcr); + + /* 11. Restore original MCR value */ + write16(mcr_orig, &uart->mcr); + + /* 12. Restore original LCR value */ + write16(lcr_orig, &uart->lcr); + + /* Protocol, baud rate and interrupt settings */ + + /* 1. Disable UART access to DLL and DLH registers */ + write16(read16(&uart->mdr1) | 0x7, &uart->mdr1); + + /* 2. Switch to config mode B */ + write16(0xbf, &uart->lcr); + + /* 3. Enable access to IER[7:4] */ + write16(efr_orig | EFR_ENHANCED_EN, &uart->efr); + + /* 4. Switch to operational mode */ + write16(0x0, &uart->lcr); + + /* 5. Clear IER */ + write16(0x0, &uart->ier); + + /* 6. Switch to config mode B */ + write16(0xbf, &uart->lcr); + + /* 7. Set dll and dlh to the desired values (table 19-25) */ + if (CONFIG_CONSOLE_SERIAL_9600) { + write16(0x01, &uart->dlh); + write16(0x38, &uart->dll); + } else if (CONFIG_CONSOLE_SERIAL_19200) { + write16(0x00, &uart->dlh); + write16(0x9c, &uart->dll); + } else if (CONFIG_CONSOLE_SERIAL_38400) { + write16(0x00, &uart->dlh); + write16(0x4e, &uart->dll); + } else if (CONFIG_CONSOLE_SERIAL_57600) { + write16(0x00, &uart->dlh); + write16(0x34, &uart->dll); + } else if (CONFIG_CONSOLE_SERIAL_115200) { + write16(0x00, &uart->dlh); + write16(0x1a, &uart->dll); + } else { + /* Unrecognized baud rate? */ + } + + /* 8. Switch to operational mode to access ier */ + write16(0x0, &uart->lcr); + + /* 9. Clear ier to disable all interrupts */ + write16(0x0, &uart->ier); + + /* 10. Switch to config mode B */ + write16(0xbf, &uart->lcr); + + /* 11. Restore efr */ + write16(efr_orig, &uart->efr); + + /* 12. Set protocol formatting 8n1 (8 bit data, no parity, 1 stop bit) */ + write16(0x3, &uart->lcr); + + /* 13. Load the new UART mode */ + write16(0x0, &uart->mdr1); } /* @@ -70,20 +152,12 @@ static void am335x_uart_init_dev(void) */ static unsigned char am335x_uart_rx_byte(void) { - /* FIXME: stub */ -#if 0 - struct s5p_uart *uart = (struct s5p_uart *)base_port; - - /* wait for character to arrive */ - while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | - RX_FIFO_FULL_MASK))) { - if (exynos5_uart_err_check(0)) - return 0; - } + struct am335x_uart *uart = + (struct am335x_uart *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS; - return readb(&uart->urxh) & 0xff; -#endif - return 0xaa; + while (!(read16(&uart->lsr) & LSR_RXFIFOE)); + + return read8(&uart->rhr); } /* @@ -91,18 +165,12 @@ static unsigned char am335x_uart_rx_byte(void) */ static void am335x_uart_tx_byte(unsigned char data) { - /* FIXME: stub */ -#if 0 - struct s5p_uart *uart = (struct s5p_uart *)base_port; - - /* wait for room in the tx FIFO */ - while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) { - if (exynos5_uart_err_check(1)) - return; - } + struct am335x_uart *uart = + (struct am335x_uart *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS; - writeb(data, &uart->utxh); -#endif + while (!(read16(&uart->lsr) & LSR_TXFIFOE)); + + return write8(data, &uart->thr); } uint32_t uartmem_getbaseaddr(void) |