summaryrefslogtreecommitdiff
path: root/src/cpu/ti/am335x/uart.c
diff options
context:
space:
mode:
authorGabe Black <gabeblack@chromium.org>2013-06-11 21:58:18 -0400
committerRonald G. Minnich <rminnich@gmail.com>2013-07-06 00:46:18 +0200
commit8cfa33eb7c93c0b4fb24a520b4c521591720999d (patch)
treeec784e7c2853f2cf1a46e6f8002bf6a067ae1e6f /src/cpu/ti/am335x/uart.c
parent8522f9940af8291772e37eef077339d6f3ffcda9 (diff)
am335x: Implement support for the UART.
This patch was started by Dave Hendricks and implements the procedure for setting up the UART as described in the manual. Some unused code was removed. Change-Id: If26a424cac401ef3eafaec081147f41184fbcee9 Signed-off-by: Gabe Black <gabeblack@chromium.org> Reviewed-on: http://review.coreboot.org/3490 Reviewed-by: Ronald G. Minnich <rminnich@gmail.com> Tested-by: build bot (Jenkins)
Diffstat (limited to 'src/cpu/ti/am335x/uart.c')
-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)