1/* 2 * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7#include <arch.h> 8#include <asm_macros.S> 9#include <assert_macros.S> 10#include <console_macros.S> 11 12/* UART16550 Registers */ 13#define UARTTX 0x0 14#define UARTRX 0x0 15#define UARTDLL 0x0 16#define UARTIER 0x1 17#define UARTDLLM 0x1 18#define UARTFCR 0x2 19#define UARTLCR 0x3 20#define UARTLSR 0x5 21#define UARTMCR 0x4 22 23/* FIFO Control Register bits */ 24#define UARTFCR_FIFOMD_16450 (0 << 6) 25#define UARTFCR_FIFOMD_16550 (1 << 6) 26#define UARTFCR_RXTRIG_1 (0 << 6) 27#define UARTFCR_RXTRIG_4 (1 << 6) 28#define UARTFCR_RXTRIG_8 (2 << 6) 29#define UARTFCR_RXTRIG_16 (3 << 6) 30#define UARTFCR_TXTRIG_1 (0 << 4) 31#define UARTFCR_TXTRIG_4 (1 << 4) 32#define UARTFCR_TXTRIG_8 (2 << 4) 33#define UARTFCR_TXTRIG_16 (3 << 4) 34#define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */ 35#define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */ 36#define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */ 37#define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */ 38#define UARTFCR_64FIFO (1 << 5) 39 40/* Line Control Register bits */ 41#define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */ 42#define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */ 43#define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */ 44#define UARTLCR_EVEN (1 << 4) /* Even Parity Format */ 45#define UARTLCR_PAR (1 << 3) /* Parity */ 46#define UARTLCR_STOP (1 << 2) /* Stop Bit */ 47#define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */ 48#define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */ 49#define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */ 50#define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */ 51 52/* Line Status Register bits */ 53#define UARTLSR_RXFIFOEMT (1 << 9) /* Rx Fifo Empty */ 54#define UARTLSR_TXFIFOFULL (1 << 8) /* Tx Fifo Full */ 55#define UARTLSR_RXFIFOERR (1 << 7) /* Rx Fifo Error */ 56#define UARTLSR_TEMT (1 << 6) /* Tx Shift Register Empty */ 57#define UARTLSR_THRE (1 << 5) /* Tx Holding Register Empty */ 58#define UARTLSR_BRK (1 << 4) /* Break Condition Detected */ 59#define UARTLSR_FERR (1 << 3) /* Framing Error */ 60#define UARTLSR_PERR (1 << 3) /* Parity Error */ 61#define UARTLSR_OVRF (1 << 2) /* Rx Overrun Error */ 62#define UARTLSR_RDR (1 << 2) /* Rx Data Ready */ 63 64#define CONSOLE_T_16550_BASE CONSOLE_T_BASE 65 66 /* 67 * "core" functions are low-level implementations that don't require 68 * writable memory and are thus safe to call in BL1 crash context. 69 */ 70 .globl nxp_console_16550_core_init 71 .globl nxp_console_16550_core_putc 72 .globl nxp_console_16550_core_getc 73 .globl nxp_console_16550_core_flush 74 75 .globl console_16550_putc 76 .globl console_16550_getc 77 .globl console_16550_flush 78 79 /* ----------------------------------------------- 80 * int nxp_console_16550_core_init(uintptr_t base_addr, 81 * unsigned int uart_clk, unsigned int baud_rate) 82 * Function to initialize the console without a 83 * C Runtime to print debug information. This 84 * function will be accessed by console_init and 85 * crash reporting. 86 * In: x0 - console base address 87 * w1 - Uart clock in Hz 88 * w2 - Baud rate 89 * Out: return 1 on success, 0 on error 90 * Clobber list : x1, x2, x3 91 * ----------------------------------------------- 92 */ 93func nxp_console_16550_core_init 94 /* Check the input base address */ 95 cbz x0, init_fail 96 /* Check baud rate and uart clock for sanity */ 97 cbz w1, init_fail 98 cbz w2, init_fail 99 100 /* Program the baudrate */ 101 /* Divisor = Uart clock / (16 * baudrate) */ 102 lsl w2, w2, #4 103 udiv w2, w1, w2 104 and w1, w2, #0xff /* w1 = DLL */ 105 lsr w2, w2, #8 106 and w2, w2, #0xff /* w2 = DLLM */ 107 ldrb w3, [x0, #UARTLCR] 108 orr w3, w3, #UARTLCR_DLAB 109 strb w3, [x0, #UARTLCR] /* enable DLL, DLLM programming */ 110 strb w1, [x0, #UARTDLL] /* program DLL */ 111 strb w2, [x0, #UARTDLLM] /* program DLLM */ 112 mov w2, #~UARTLCR_DLAB 113 and w3, w3, w2 114 strb w3, [x0, #UARTLCR] /* disable DLL, DLLM programming */ 115 116 /* 8n1 */ 117 mov w3, #3 118 strb w3, [x0, #UARTLCR] 119 /* no interrupt */ 120 mov w3, #0 121 strb w3, [x0, #UARTIER] 122 /* enable fifo, DMA */ 123 mov w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR) 124 strb w3, [x0, #UARTFCR] 125 /* DTR + RTS */ 126 mov w3, #3 127 str w3, [x0, #UARTMCR] 128 mov w0, #1 129 ret 130init_fail: 131 mov w0, #0 132 ret 133endfunc nxp_console_16550_core_init 134 135 .globl nxp_console_16550_register 136 137 /* ----------------------------------------------- 138 * int nxp_console_16550_register(uintptr_t baseaddr, 139 * uint32_t clock, uint32_t baud, 140 * console_t *console); 141 * Function to initialize and register a new 16550 142 * console. Storage passed in for the console struct 143 * *must* be persistent (i.e. not from the stack). 144 * If w1 (UART clock) is 0, initialisation will be 145 * skipped, relying on previous code to have done 146 * this already. w2 is ignored then as well. 147 * In: x0 - UART register base address 148 * w1 - UART clock in Hz 149 * w2 - Baud rate (ignored if w1 is 0) 150 * x3 - pointer to empty console_t struct 151 * Out: return 1 on success, 0 on error 152 * Clobber list : x0, x1, x2, x6, x7, x14 153 * ----------------------------------------------- 154 */ 155func nxp_console_16550_register 156 mov x7, x30 157 mov x6, x3 158 cbz x6, register_fail 159 str x0, [x6, #CONSOLE_T_16550_BASE] 160 161 /* A clock rate of zero means to skip the initialisation. */ 162 cbz w1, register_16550 163 164 bl nxp_console_16550_core_init 165 cbz x0, register_fail 166 167register_16550: 168 mov x0, x6 169 mov x30, x7 170 finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1 171 172register_fail: 173 ret x7 174endfunc nxp_console_16550_register 175 176 /* -------------------------------------------------------- 177 * int console_16550_core_putc(int c, uintptr_t base_addr) 178 * Function to output a character over the console. It 179 * returns the character printed on success or -1 on error. 180 * In : w0 - character to be printed 181 * x1 - console base address 182 * Out : return -1 on error else return character. 183 * Clobber list : x2 184 * -------------------------------------------------------- 185 */ 186func nxp_console_16550_core_putc 187#if ENABLE_ASSERTIONS 188 cmp x1, #0 189 ASM_ASSERT(ne) 190#endif /* ENABLE_ASSERTIONS */ 191 192 /* Prepend '\r' to '\n' */ 193 cmp w0, #'\n' 194 b.ne 2f 195 /* Check if the transmit FIFO is full */ 1961: ldrb w2, [x1, #UARTLSR] 197 and w2, w2, #UARTLSR_THRE /* #(UARTLSR_TEMT | UARTLSR_THRE)*/ 198 cmp w2, #(UARTLSR_THRE) 199 b.ne 1b 200 mov w2, #'\r' 201 strb w2, [x1, #UARTTX] 202 ldrb w2, [x1, #UARTFCR] 203 orr w2, w2, #UARTFCR_TXCLR 204 205 /* Check if the transmit FIFO is full */ 2062: ldrb w2, [x1, #UARTLSR] 207 and w2, w2, #(UARTLSR_THRE) 208 cmp w2, #(UARTLSR_THRE) 209 b.ne 2b 210 strb w0, [x1, #UARTTX] 211 ret 212endfunc nxp_console_16550_core_putc 213 214 /* -------------------------------------------------------- 215 * int console_16550_putc(int c, console_t *console) 216 * Function to output a character over the console. It 217 * returns the character printed on success or -1 on error. 218 * In : w0 - character to be printed 219 * x1 - pointer to console_t structure 220 * Out : return -1 on error else return character. 221 * Clobber list : x2 222 * -------------------------------------------------------- 223 */ 224func console_16550_putc 225#if ENABLE_ASSERTIONS 226 cmp x1, #0 227 ASM_ASSERT(ne) 228#endif /* ENABLE_ASSERTIONS */ 229 ldr x1, [x1, #CONSOLE_T_16550_BASE] 230 b nxp_console_16550_core_putc 231endfunc console_16550_putc 232 233 /* --------------------------------------------- 234 * int console_16550_core_getc(uintptr_t base_addr) 235 * Function to get a character from the console. 236 * It returns the character grabbed on success 237 * or -1 on if no character is available. 238 * In : x0 - console base address 239 * Out : w0 - character if available, else -1 240 * Clobber list : x0, x1 241 * --------------------------------------------- 242 */ 243func nxp_console_16550_core_getc 244#if ENABLE_ASSERTIONS 245 cmp x0, #0 246 ASM_ASSERT(ne) 247#endif /* ENABLE_ASSERTIONS */ 248 249 /* Check if the receive FIFO is empty */ 2501: ldrb w1, [x0, #UARTLSR] 251 tbz w1, #UARTLSR_RDR, 1b 252 ldrb w0, [x0, #UARTRX] 253 ret 254no_char: 255 mov w0, #ERROR_NO_PENDING_CHAR 256 ret 257endfunc nxp_console_16550_core_getc 258 259 /* --------------------------------------------- 260 * int console_16550_getc(console_t *console) 261 * Function to get a character from the console. 262 * It returns the character grabbed on success 263 * or -1 on if no character is available. 264 * In : x0 - pointer to console_t structure 265 * Out : w0 - character if available, else -1 266 * Clobber list : x0, x1 267 * --------------------------------------------- 268 */ 269func console_16550_getc 270#if ENABLE_ASSERTIONS 271 cmp x1, #0 272 ASM_ASSERT(ne) 273#endif /* ENABLE_ASSERTIONS */ 274 ldr x0, [x0, #CONSOLE_T_16550_BASE] 275 b nxp_console_16550_core_getc 276endfunc console_16550_getc 277 278 /* --------------------------------------------- 279 * int console_16550_core_flush(uintptr_t base_addr) 280 * Function to force a write of all buffered 281 * data that hasn't been output. 282 * In : x0 - console base address 283 * Out : return -1 on error else return 0. 284 * Clobber list : x0, x1 285 * --------------------------------------------- 286 */ 287func nxp_console_16550_core_flush 288#if ENABLE_ASSERTIONS 289 cmp x0, #0 290 ASM_ASSERT(ne) 291#endif /* ENABLE_ASSERTIONS */ 292 293 /* Loop until the transmit FIFO is empty */ 2941: ldrb w1, [x0, #UARTLSR] 295 and w1, w1, #(UARTLSR_THRE) 296 cmp w1, #(UARTLSR_THRE) 297 b.ne 1b 298 299 mov w0, #0 300 ret 301endfunc nxp_console_16550_core_flush 302 303 /* --------------------------------------------- 304 * int console_16550_flush(console_t *console) 305 * Function to force a write of all buffered 306 * data that hasn't been output. 307 * In : x0 - pointer to console_t structure 308 * Out : return -1 on error else return 0. 309 * Clobber list : x0, x1 310 * --------------------------------------------- 311 */ 312func console_16550_flush 313#if ENABLE_ASSERTIONS 314 cmp x0, #0 315 ASM_ASSERT(ne) 316#endif /* ENABLE_ASSERTIONS */ 317 ldr x0, [x0, #CONSOLE_T_16550_BASE] 318 b nxp_console_16550_core_flush 319endfunc console_16550_flush 320