summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/ti/am335x/uart.c178
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)