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