drivers: imx: uart: Add mxc_console
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>
Fri, 25 May 2018 16:36:56 +0000 (17:36 +0100)
committerBryan O'Donoghue <bryan.odonoghue@linaro.org>
Thu, 30 Aug 2018 16:38:32 +0000 (17:38 +0100)
- 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>
drivers/imx/uart/imx_uart.c [new file with mode: 0644]
drivers/imx/uart/imx_uart.h [new file with mode: 0644]

diff --git a/drivers/imx/uart/imx_uart.c b/drivers/imx/uart/imx_uart.c
new file mode 100644 (file)
index 0000000..0250a41
--- /dev/null
@@ -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 (file)
index 0000000..de42125
--- /dev/null
@@ -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__ */