drivers: imx: uart: Add mxc_console
- Adds a simple register read/write abstraction to cut-down on the
amount of typing and text required to access UART registers in this driver.
- Adds a console getc() callback.
- Adds a console putc() callback, translating '\n' to '\r' + '\n'.
- Initializes the MXC UART, take a crude method of calculating the
BAUD rate generator. The UART clock-gates must have been enabled prior
to launching the UART init code.
Special care needs to be taken to ensure the UBIR is initialized before the
UBMR and we need to ensure that UCR2.SRST comes good before trying to
program other registers associated with the UART.
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
diff --git a/drivers/imx/uart/imx_uart.c b/drivers/imx/uart/imx_uart.c
new file mode 100644
index 0000000..0250a41
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <stdint.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <imx_uart.h>
+
+/* TX/RX FIFO threshold */
+#define TX_RX_THRESH 2
+
+struct clk_div_factors {
+ uint32_t fcr_div;
+ uint32_t bmr_div;
+};
+
+static struct clk_div_factors clk_div[] = {
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV1,
+ .bmr_div = 1,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV2,
+ .bmr_div = 2,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV3,
+ .bmr_div = 3,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV4,
+ .bmr_div = 4,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV5,
+ .bmr_div = 5,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV6,
+ .bmr_div = 6,
+ },
+ {
+ .fcr_div = IMX_UART_FCR_RFDIV7,
+ .bmr_div = 7,
+ },
+};
+
+static void write_reg(uintptr_t base, uint32_t offset, uint32_t val)
+{
+ mmio_write_32(base + offset, val);
+}
+
+static uint32_t read_reg(uintptr_t base, uint32_t offset)
+{
+ return mmio_read_32(base + offset);
+}
+
+int console_core_init(uintptr_t base_addr, unsigned int uart_clk,
+ unsigned int baud_rate)
+{
+ uint32_t val;
+ uint8_t clk_idx = 1;
+
+ /* Reset UART */
+ write_reg(base_addr, IMX_UART_CR2_OFFSET, 0);
+ do {
+ val = read_reg(base_addr, IMX_UART_CR2_OFFSET);
+ } while (!(val & IMX_UART_CR2_SRST));
+
+ /* Enable UART */
+ write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN);
+
+ /* Ignore RTS, 8N1, enable tx/rx, disable reset */
+ val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN |
+ IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST);
+ write_reg(base_addr, IMX_UART_CR2_OFFSET, val);
+
+ /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */
+ val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL;
+ write_reg(base_addr, IMX_UART_CR3_OFFSET, val);
+
+ /* Set CTS FIFO trigger to 32 bytes bits 15:10 */
+ write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000);
+
+ /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */
+ val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) |
+ clk_div[clk_idx].fcr_div;
+ #ifdef IMX_UART_DTE
+ /* Set DTE (bit6 = 1) */
+ val |= IMX_UART_FCR_DCEDTE;
+ #endif
+ write_reg(base_addr, IMX_UART_FCR_OFFSET, val);
+
+ /*
+ * The equation for BAUD rate calculation is
+ * RefClk = Supplied clock / FCR_DIVx
+ *
+ * BAUD = Refclk
+ * ------------
+ * 16 x (UBMR + 1/ UBIR + 1)
+ *
+ * We write 0x0f into UBIR to remove the 16 mult
+ * BAUD = 6000000
+ * ------------
+ * 16 x (UBMR + 1/ 15 + 1)
+ */
+
+ write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f);
+ val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1;
+ write_reg(base_addr, IMX_UART_BMR_OFFSET, val);
+
+ return 0;
+}
+
+/* --------------------------------------------------------
+ * int console_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or -1 on error.
+ * In : r0 - character to be printed
+ * r1 - console base address
+ * Out : return -1 on error else return character.
+ * Clobber list : r2
+ * --------------------------------------------------------
+ */
+int console_core_putc(int c, uintptr_t base_addr)
+{
+ uint32_t val;
+
+ if (c == '\n')
+ console_core_putc('\r', base_addr);
+
+ /* Write data */
+ write_reg(base_addr, IMX_UART_TXD_OFFSET, c);
+
+ /* Wait for transmit */
+ do {
+ val = read_reg(base_addr, IMX_UART_STAT2_OFFSET);
+ } while (!(val & IMX_UART_STAT2_TXDC));
+
+ return 0;
+}
+
+/*
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or -1 on error.
+ * In : r0 - console base address
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+int console_core_getc(uintptr_t base_addr)
+{
+ uint32_t val;
+
+ val = read_reg(base_addr, IMX_UART_TS_OFFSET);
+ if (val & IMX_UART_TS_RXEMPTY)
+ return -1;
+
+ val = read_reg(base_addr, IMX_UART_RXD_OFFSET);
+ return (int)(val & 0x000000FF);
+}
+
+/*
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - console base address
+ * Out : return -1 on error else return 0.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+int console_core_flush(uintptr_t base_addr)
+{
+ return 0;
+}
+
diff --git a/drivers/imx/uart/imx_uart.h b/drivers/imx/uart/imx_uart.h
new file mode 100644
index 0000000..de42125
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __IMX_CONSOLE_H__
+#define __IMX_CONSOLE_H__
+
+#define IMX_UART_RXD_OFFSET 0x00
+#define IMX_UART_RXD_CHARRDY BIT(15)
+#define IMX_UART_RXD_ERR BIT(14)
+#define IMX_UART_RXD_OVERRUN BIT(13)
+#define IMX_UART_RXD_FRMERR BIT(12)
+#define IMX_UART_RXD_BRK BIT(11)
+#define IMX_UART_RXD_PRERR BIT(10)
+
+#define IMX_UART_TXD_OFFSET 0x40
+
+#define IMX_UART_CR1_OFFSET 0x80
+#define IMX_UART_CR1_ADEN BIT(15)
+#define IMX_UART_CR1_ADBR BIT(14)
+#define IMX_UART_CR1_TRDYEN BIT(13)
+#define IMX_UART_CR1_IDEN BIT(12)
+#define IMX_UART_CR1_RRDYEN BIT(9)
+#define IMX_UART_CR1_RXDMAEN BIT(8)
+#define IMX_UART_CR1_IREN BIT(7)
+#define IMX_UART_CR1_TXMPTYEN BIT(6)
+#define IMX_UART_CR1_RTSDEN BIT(5)
+#define IMX_UART_CR1_SNDBRK BIT(4)
+#define IMX_UART_CR1_TXDMAEN BIT(3)
+#define IMX_UART_CR1_ATDMAEN BIT(2)
+#define IMX_UART_CR1_DOZE BIT(1)
+#define IMX_UART_CR1_UARTEN BIT(0)
+
+#define IMX_UART_CR2_OFFSET 0x84
+#define IMX_UART_CR2_ESCI BIT(15)
+#define IMX_UART_CR2_IRTS BIT(14)
+#define IMX_UART_CR2_CTSC BIT(13)
+#define IMX_UART_CR2_CTS BIT(12)
+#define IMX_UART_CR2_ESCEN BIT(11)
+#define IMX_UART_CR2_PREN BIT(8)
+#define IMX_UART_CR2_PROE BIT(7)
+#define IMX_UART_CR2_STPB BIT(6)
+#define IMX_UART_CR2_WS BIT(5)
+#define IMX_UART_CR2_RTSEN BIT(4)
+#define IMX_UART_CR2_ATEN BIT(3)
+#define IMX_UART_CR2_TXEN BIT(2)
+#define IMX_UART_CR2_RXEN BIT(1)
+#define IMX_UART_CR2_SRST BIT(0)
+
+#define IMX_UART_CR3_OFFSET 0x88
+#define IMX_UART_CR3_DTREN BIT(13)
+#define IMX_UART_CR3_PARERREN BIT(12)
+#define IMX_UART_CR3_FARERREN BIT(11)
+#define IMX_UART_CR3_DSD BIT(10)
+#define IMX_UART_CR3_DCD BIT(9)
+#define IMX_UART_CR3_RI BIT(8)
+#define IMX_UART_CR3_ADNIMP BIT(7)
+#define IMX_UART_CR3_RXDSEN BIT(6)
+#define IMX_UART_CR3_AIRINTEN BIT(5)
+#define IMX_UART_CR3_AWAKEN BIT(4)
+#define IMX_UART_CR3_DTRDEN BIT(3)
+#define IMX_UART_CR3_RXDMUXSEL BIT(2)
+#define IMX_UART_CR3_INVT BIT(1)
+#define IMX_UART_CR3_ACIEN BIT(0)
+
+#define IMX_UART_CR4_OFFSET 0x8c
+#define IMX_UART_CR4_INVR BIT(9)
+#define IMX_UART_CR4_ENIRI BIT(8)
+#define IMX_UART_CR4_WKEN BIT(7)
+#define IMX_UART_CR4_IDDMAEN BIT(6)
+#define IMX_UART_CR4_IRSC BIT(5)
+#define IMX_UART_CR4_LPBYP BIT(4)
+#define IMX_UART_CR4_TCEN BIT(3)
+#define IMX_UART_CR4_BKEN BIT(2)
+#define IMX_UART_CR4_OREN BIT(1)
+#define IMX_UART_CR4_DREN BIT(0)
+
+#define IMX_UART_FCR_OFFSET 0x90
+#define IMX_UART_FCR_TXTL_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) |\
+ BIT(11) | BIT(10))
+#define IMX_UART_FCR_TXTL(x) ((x) << 10)
+#define IMX_UART_FCR_RFDIV_MASK (BIT(9) | BIT(8) | BIT(7))
+#define IMX_UART_FCR_RFDIV7 (BIT(9) | BIT(8))
+#define IMX_UART_FCR_RFDIV1 (BIT(9) | BIT(7))
+#define IMX_UART_FCR_RFDIV2 BIT(9)
+#define IMX_UART_FCR_RFDIV3 (BIT(8) | BIT(7))
+#define IMX_UART_FCR_RFDIV4 BIT(8)
+#define IMX_UART_FCR_RFDIV5 BIT(7)
+#define IMX_UART_FCR_RFDIV6 0
+#define IMX_UART_FCR_DCEDTE BIT(6)
+#define IMX_UART_FCR_RXTL_MASK (BIT(5) | BIT(4) | BIT(3) | BIT(2) |\
+ BIT(1) | BIT(0))
+#define IMX_UART_FCR_RXTL(x) x
+
+#define IMX_UART_STAT1_OFFSET 0x94
+#define IMX_UART_STAT1_PARITYERR BIT(15)
+#define IMX_UART_STAT1_RTSS BIT(14)
+#define IMX_UART_STAT1_TRDY BIT(13)
+#define IMX_UART_STAT1_RTSD BIT(12)
+#define IMX_UART_STAT1_ESCF BIT(11)
+#define IMX_UART_STAT1_FRAMEERR BIT(10)
+#define IMX_UART_STAT1_RRDY BIT(9)
+#define IMX_UART_STAT1_AGTIM BIT(8)
+#define IMX_UART_STAT1_DTRD BIT(7)
+#define IMX_UART_STAT1_RXDS BIT(6)
+#define IMX_UART_STAT1_AIRINT BIT(5)
+#define IMX_UART_STAT1_AWAKE BIT(4)
+#define IMX_UART_STAT1_SAD BIT(3)
+
+#define IMX_UART_STAT2_OFFSET 0x98
+#define IMX_UART_STAT2_ADET BIT(15)
+#define IMX_UART_STAT2_TXFE BIT(14)
+#define IMX_UART_STAT2_DTRF BIT(13)
+#define IMX_UART_STAT2_IDLE BIT(12)
+#define IMX_UART_STAT2_ACST BIT(11)
+#define IMX_UART_STAT2_RIDELT BIT(10)
+#define IMX_UART_STAT2_RIIN BIT(9)
+#define IMX_UART_STAT2_IRINT BIT(8)
+#define IMX_UART_STAT2_WAKE BIT(7)
+#define IMX_UART_STAT2_DCDDELT BIT(6)
+#define IMX_UART_STAT2_DCDIN BIT(5)
+#define IMX_UART_STAT2_RTSF BIT(4)
+#define IMX_UART_STAT2_TXDC BIT(3)
+#define IMX_UART_STAT2_BRCD BIT(2)
+#define IMX_UART_STAT2_ORE BIT(1)
+#define IMX_UART_STAT2_RCR BIT(0)
+
+#define IMX_UART_ESC_OFFSET 0x9c
+
+#define IMX_UART_TIM_OFFSET 0xa0
+
+#define IMX_UART_BIR_OFFSET 0xa4
+
+#define IMX_UART_BMR_OFFSET 0xa8
+
+#define IMX_UART_BRC_OFFSET 0xac
+
+#define IMX_UART_ONEMS_OFFSET 0xb0
+
+#define IMX_UART_TS_OFFSET 0xb4
+#define IMX_UART_TS_FRCPERR BIT(13)
+#define IMX_UART_TS_LOOP BIT(12)
+#define IMX_UART_TS_DBGEN BIT(11)
+#define IMX_UART_TS_LOOPIR BIT(10)
+#define IMX_UART_TS_RXDBG BIT(9)
+#define IMX_UART_TS_TXEMPTY BIT(6)
+#define IMX_UART_TS_RXEMPTY BIT(5)
+#define IMX_UART_TS_TXFULL BIT(4)
+#define IMX_UART_TS_RXFULL BIT(3)
+#define IMX_UART_TS_SOFTRST BIT(0)
+
+#endif /* __IMX_UART_H__ */