1 /* 2 * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 #include <arch.h> 7 #include <stdint.h> 8 #include <mmio.h> 9 #include <platform_def.h> 10 #include <imx_uart.h> 11 12 /* TX/RX FIFO threshold */ 13 #define TX_RX_THRESH 2 14 15 struct clk_div_factors { 16 uint32_t fcr_div; 17 uint32_t bmr_div; 18 }; 19 20 static struct clk_div_factors clk_div[] = { 21 { 22 .fcr_div = IMX_UART_FCR_RFDIV1, 23 .bmr_div = 1, 24 }, 25 { 26 .fcr_div = IMX_UART_FCR_RFDIV2, 27 .bmr_div = 2, 28 }, 29 { 30 .fcr_div = IMX_UART_FCR_RFDIV3, 31 .bmr_div = 3, 32 }, 33 { 34 .fcr_div = IMX_UART_FCR_RFDIV4, 35 .bmr_div = 4, 36 }, 37 { 38 .fcr_div = IMX_UART_FCR_RFDIV5, 39 .bmr_div = 5, 40 }, 41 { 42 .fcr_div = IMX_UART_FCR_RFDIV6, 43 .bmr_div = 6, 44 }, 45 { 46 .fcr_div = IMX_UART_FCR_RFDIV7, 47 .bmr_div = 7, 48 }, 49 }; 50 51 static void write_reg(uintptr_t base, uint32_t offset, uint32_t val) 52 { 53 mmio_write_32(base + offset, val); 54 } 55 56 static uint32_t read_reg(uintptr_t base, uint32_t offset) 57 { 58 return mmio_read_32(base + offset); 59 } 60 61 int console_core_init(uintptr_t base_addr, unsigned int uart_clk, 62 unsigned int baud_rate) 63 { 64 uint32_t val; 65 uint8_t clk_idx = 1; 66 67 /* Reset UART */ 68 write_reg(base_addr, IMX_UART_CR2_OFFSET, 0); 69 do { 70 val = read_reg(base_addr, IMX_UART_CR2_OFFSET); 71 } while (!(val & IMX_UART_CR2_SRST)); 72 73 /* Enable UART */ 74 write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN); 75 76 /* Ignore RTS, 8N1, enable tx/rx, disable reset */ 77 val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | 78 IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST); 79 write_reg(base_addr, IMX_UART_CR2_OFFSET, val); 80 81 /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */ 82 val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL; 83 write_reg(base_addr, IMX_UART_CR3_OFFSET, val); 84 85 /* Set CTS FIFO trigger to 32 bytes bits 15:10 */ 86 write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000); 87 88 /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */ 89 val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | 90 clk_div[clk_idx].fcr_div; 91 #ifdef IMX_UART_DTE 92 /* Set DTE (bit6 = 1) */ 93 val |= IMX_UART_FCR_DCEDTE; 94 #endif 95 write_reg(base_addr, IMX_UART_FCR_OFFSET, val); 96 97 /* 98 * The equation for BAUD rate calculation is 99 * RefClk = Supplied clock / FCR_DIVx 100 * 101 * BAUD = Refclk 102 * ------------ 103 * 16 x (UBMR + 1/ UBIR + 1) 104 * 105 * We write 0x0f into UBIR to remove the 16 mult 106 * BAUD = 6000000 107 * ------------ 108 * 16 x (UBMR + 1/ 15 + 1) 109 */ 110 111 write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f); 112 val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1; 113 write_reg(base_addr, IMX_UART_BMR_OFFSET, val); 114 115 return 0; 116 } 117 118 /* -------------------------------------------------------- 119 * int console_core_putc(int c, uintptr_t base_addr) 120 * Function to output a character over the console. It 121 * returns the character printed on success or -1 on error. 122 * In : r0 - character to be printed 123 * r1 - console base address 124 * Out : return -1 on error else return character. 125 * Clobber list : r2 126 * -------------------------------------------------------- 127 */ 128 int console_core_putc(int c, uintptr_t base_addr) 129 { 130 uint32_t val; 131 132 if (c == '\n') 133 console_core_putc('\r', base_addr); 134 135 /* Write data */ 136 write_reg(base_addr, IMX_UART_TXD_OFFSET, c); 137 138 /* Wait for transmit */ 139 do { 140 val = read_reg(base_addr, IMX_UART_STAT2_OFFSET); 141 } while (!(val & IMX_UART_STAT2_TXDC)); 142 143 return 0; 144 } 145 146 /* 147 * Function to get a character from the console. 148 * It returns the character grabbed on success 149 * or -1 on error. 150 * In : r0 - console base address 151 * Clobber list : r0, r1 152 * --------------------------------------------- 153 */ 154 int console_core_getc(uintptr_t base_addr) 155 { 156 uint32_t val; 157 158 val = read_reg(base_addr, IMX_UART_TS_OFFSET); 159 if (val & IMX_UART_TS_RXEMPTY) 160 return -1; 161 162 val = read_reg(base_addr, IMX_UART_RXD_OFFSET); 163 return (int)(val & 0x000000FF); 164 } 165 166 /* 167 * Function to force a write of all buffered 168 * data that hasn't been output. 169 * In : r0 - console base address 170 * Out : return -1 on error else return 0. 171 * Clobber list : r0, r1 172 * --------------------------------------------- 173 */ 174 int console_core_flush(uintptr_t base_addr) 175 { 176 return 0; 177 } 178 179