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