1*306946b0SGhennadi Procopciuc/* 2*306946b0SGhennadi Procopciuc * Copyright 2024 NXP 3*306946b0SGhennadi Procopciuc * 4*306946b0SGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 5*306946b0SGhennadi Procopciuc */ 6*306946b0SGhennadi Procopciuc 7*306946b0SGhennadi Procopciuc#include <lib/libc/errno.h> 8*306946b0SGhennadi Procopciuc 9*306946b0SGhennadi Procopciuc#include <asm_macros.S> 10*306946b0SGhennadi Procopciuc#include <console_macros.S> 11*306946b0SGhennadi Procopciuc#include <lib/utils_def.h> 12*306946b0SGhennadi Procopciuc 13*306946b0SGhennadi Procopciuc#define LDIV_MULTIPLIER U(16) 14*306946b0SGhennadi Procopciuc 15*306946b0SGhennadi Procopciuc#define LINFLEX_LINCR1 (0x0) 16*306946b0SGhennadi Procopciuc#define LINCR1_INIT BIT_32(0) 17*306946b0SGhennadi Procopciuc#define LINCR1_MME BIT_32(4) 18*306946b0SGhennadi Procopciuc 19*306946b0SGhennadi Procopciuc#define LINFLEX_LINSR (0x8) 20*306946b0SGhennadi Procopciuc#define LINSR_LINS_INITMODE (0x00001000) 21*306946b0SGhennadi Procopciuc#define LINSR_LINS_MASK (0x0000F000) 22*306946b0SGhennadi Procopciuc 23*306946b0SGhennadi Procopciuc#define LINFLEX_UARTCR (0x10) 24*306946b0SGhennadi Procopciuc#define UARTCR_ROSE BIT_32(23) 25*306946b0SGhennadi Procopciuc 26*306946b0SGhennadi Procopciuc#define LINFLEX_UARTSR (0x14) 27*306946b0SGhennadi Procopciuc#define LINFLEX_LINIBRR (0x28) 28*306946b0SGhennadi Procopciuc#define LINFLEX_LINFBRR (0x24) 29*306946b0SGhennadi Procopciuc#define LINFLEX_BDRL (0x38) 30*306946b0SGhennadi Procopciuc#define LINFLEX_UARTPTO (0x50) 31*306946b0SGhennadi Procopciuc 32*306946b0SGhennadi Procopciuc#define UARTCR_UART BIT_32(0) 33*306946b0SGhennadi Procopciuc#define UARTCR_WL0 BIT_32(1) 34*306946b0SGhennadi Procopciuc#define UARTCR_PC0 BIT_32(3) 35*306946b0SGhennadi Procopciuc#define UARTCR_TXEN BIT_32(4) 36*306946b0SGhennadi Procopciuc#define UARTCR_RXEN BIT_32(5) 37*306946b0SGhennadi Procopciuc#define UARTCR_PC1 BIT_32(6) 38*306946b0SGhennadi Procopciuc#define UARTCR_TFBM BIT_32(8) 39*306946b0SGhennadi Procopciuc#define UARTCR_RFBM BIT_32(9) 40*306946b0SGhennadi Procopciuc#define UARTCR_OSR_SHIFT U(24) 41*306946b0SGhennadi Procopciuc#define UARTCR_OSR_WIDTH U(4) 42*306946b0SGhennadi Procopciuc 43*306946b0SGhennadi Procopciuc#define UARTSR_DTF BIT_32(1) 44*306946b0SGhennadi Procopciuc 45*306946b0SGhennadi Procopciuc/* 46*306946b0SGhennadi Procopciuc * "core" functions are low-level implementations that do not require 47*306946b0SGhennadi Procopciuc * writable memory and are thus safe to call in BL1 crash context. 48*306946b0SGhennadi Procopciuc */ 49*306946b0SGhennadi Procopciuc.globl console_linflex_core_init 50*306946b0SGhennadi Procopciuc.globl console_linflex_core_putc 51*306946b0SGhennadi Procopciuc 52*306946b0SGhennadi Procopciuc.globl console_linflex_register 53*306946b0SGhennadi Procopciuc.globl console_linflex_putc 54*306946b0SGhennadi Procopciuc 55*306946b0SGhennadi Procopciuc/** 56*306946b0SGhennadi Procopciuc * uint32_t get_ldiv_mult(uintptr_t baseaddr, uint32_t clock, 57*306946b0SGhennadi Procopciuc * uint32_t baud, console_t *console,); 58*306946b0SGhennadi Procopciuc * 59*306946b0SGhennadi Procopciuc * Clobber list : x0 - x6 60*306946b0SGhennadi Procopciuc * Out x4: LDIV multiplier 61*306946b0SGhennadi Procopciuc */ 62*306946b0SGhennadi Procopciucfunc get_ldiv_mult 63*306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_UARTCR] 64*306946b0SGhennadi Procopciuc mov w5, w4 65*306946b0SGhennadi Procopciuc 66*306946b0SGhennadi Procopciuc /* Prepare choices in w5 and w6 */ 67*306946b0SGhennadi Procopciuc ubfx x5, x5, #UARTCR_OSR_SHIFT, #UARTCR_OSR_WIDTH 68*306946b0SGhennadi Procopciuc mov w6, #LDIV_MULTIPLIER 69*306946b0SGhennadi Procopciuc 70*306946b0SGhennadi Procopciuc and w4, w4, #UARTCR_ROSE 71*306946b0SGhennadi Procopciuc cmp w4, #0x0 72*306946b0SGhennadi Procopciuc csel w4, w5, w6, ne 73*306946b0SGhennadi Procopciuc ret 74*306946b0SGhennadi Procopciucendfunc get_ldiv_mult 75*306946b0SGhennadi Procopciuc 76*306946b0SGhennadi Procopciuc/* 77*306946b0SGhennadi Procopciuc * void linflex_set_brg(uintptr_t baseaddr, uint32_t clock 78*306946b0SGhennadi Procopciuc * uint32_t baud, console_t *console); 79*306946b0SGhennadi Procopciuc * 80*306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 81*306946b0SGhennadi Procopciuc */ 82*306946b0SGhennadi Procopciucfunc linflex_set_brg 83*306946b0SGhennadi Procopciuc mov x13, x30 84*306946b0SGhennadi Procopciuc bl get_ldiv_mult 85*306946b0SGhennadi Procopciuc mov x30, x13 86*306946b0SGhennadi Procopciuc 87*306946b0SGhennadi Procopciuc /* (x4) dividr = baudrate * ldiv_mult */ 88*306946b0SGhennadi Procopciuc mul x4, x4, x2 89*306946b0SGhennadi Procopciuc /* (x5) divisr = clock rate */ 90*306946b0SGhennadi Procopciuc mov x5, x1 91*306946b0SGhennadi Procopciuc /* (x6) ibr = divisr / dividr */ 92*306946b0SGhennadi Procopciuc udiv x6, x5, x4 93*306946b0SGhennadi Procopciuc /* (x7) fbr = divisr % dividr */ 94*306946b0SGhennadi Procopciuc msub x7, x6, x4, x5 95*306946b0SGhennadi Procopciuc /* fbr *= 16 / dividr */ 96*306946b0SGhennadi Procopciuc lsl x7, x7, #4 97*306946b0SGhennadi Procopciuc udiv x7, x7, x4 98*306946b0SGhennadi Procopciuc /* fbr &= 0xf */ 99*306946b0SGhennadi Procopciuc and w7, w7, #0xf 100*306946b0SGhennadi Procopciuc str w6, [x0, LINFLEX_LINIBRR] 101*306946b0SGhennadi Procopciuc str w7, [x0, LINFLEX_LINFBRR] 102*306946b0SGhennadi Procopciuc ret 103*306946b0SGhennadi Procopciucendfunc linflex_set_brg 104*306946b0SGhennadi Procopciuc 105*306946b0SGhennadi Procopciuc/** 106*306946b0SGhennadi Procopciuc * int console_linflex_core_init(uintptr_t baseaddr, uint32_t clock, 107*306946b0SGhennadi Procopciuc * uint32_t baud); 108*306946b0SGhennadi Procopciuc * 109*306946b0SGhennadi Procopciuc * In: x0 - Linflex base address 110*306946b0SGhennadi Procopciuc * x1 - clock frequency 111*306946b0SGhennadi Procopciuc * x2 - baudrate 112*306946b0SGhennadi Procopciuc * Out: x0 - 1 on success, 0 on error 113*306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 - x14 114*306946b0SGhennadi Procopciuc */ 115*306946b0SGhennadi Procopciucfunc console_linflex_core_init 116*306946b0SGhennadi Procopciuc /* Set master mode and init mode */ 117*306946b0SGhennadi Procopciuc mov w4, #(LINCR1_INIT) 118*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 119*306946b0SGhennadi Procopciuc mov w4, #(LINCR1_MME | LINCR1_INIT) 120*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 121*306946b0SGhennadi Procopciuc 122*306946b0SGhennadi Procopciuc /* wait for init mode entry */ 123*306946b0SGhennadi Procopciucwait_init_entry: 124*306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_LINSR] 125*306946b0SGhennadi Procopciuc and w4, w4, #LINSR_LINS_MASK 126*306946b0SGhennadi Procopciuc cmp w4, #LINSR_LINS_INITMODE 127*306946b0SGhennadi Procopciuc b.ne wait_init_entry 128*306946b0SGhennadi Procopciuc 129*306946b0SGhennadi Procopciuc /* Set UART bit */ 130*306946b0SGhennadi Procopciuc mov w4, #UARTCR_UART 131*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTCR] 132*306946b0SGhennadi Procopciuc 133*306946b0SGhennadi Procopciuc mov x14, x30 134*306946b0SGhennadi Procopciuc bl linflex_set_brg 135*306946b0SGhennadi Procopciuc mov x30, x14 136*306946b0SGhennadi Procopciuc 137*306946b0SGhennadi Procopciuc /* Set preset timeout register value. */ 138*306946b0SGhennadi Procopciuc mov w4, #0xf 139*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTPTO] 140*306946b0SGhennadi Procopciuc 141*306946b0SGhennadi Procopciuc /* 8-bit data, no parity, Tx/Rx enabled, UART mode */ 142*306946b0SGhennadi Procopciuc mov w4, #(UARTCR_PC1 | UARTCR_RXEN | UARTCR_TXEN | UARTCR_PC0 | \ 143*306946b0SGhennadi Procopciuc UARTCR_WL0 | UARTCR_UART | UARTCR_RFBM | UARTCR_TFBM) 144*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTCR] 145*306946b0SGhennadi Procopciuc 146*306946b0SGhennadi Procopciuc /* End init mode */ 147*306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_LINCR1] 148*306946b0SGhennadi Procopciuc bic w4, w4, #LINCR1_INIT 149*306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 150*306946b0SGhennadi Procopciuc ret 151*306946b0SGhennadi Procopciucendfunc console_linflex_core_init 152*306946b0SGhennadi Procopciuc 153*306946b0SGhennadi Procopciuc/** 154*306946b0SGhennadi Procopciuc * int console_linflex_register(uintptr_t baseaddr, uint32_t clock, 155*306946b0SGhennadi Procopciuc * uint32_t clock, uint32_t baud); 156*306946b0SGhennadi Procopciuc * 157*306946b0SGhennadi Procopciuc * Function to initialize and register the console. 158*306946b0SGhennadi Procopciuc * The caller needs to pass an empty console_linflex_t 159*306946b0SGhennadi Procopciuc * structure in which *MUST* be allocated in 160*306946b0SGhennadi Procopciuc * persistent memory (e.g. a global or static local 161*306946b0SGhennadi Procopciuc * variable, *NOT* on the stack). 162*306946b0SGhennadi Procopciuc * In: x0 - Linflex base address 163*306946b0SGhennadi Procopciuc * x1 - clock frequency 164*306946b0SGhennadi Procopciuc * x2 - baudrate 165*306946b0SGhennadi Procopciuc * x3 - pointer to empty console_t structure 166*306946b0SGhennadi Procopciuc * Out: x0 - 1 on success, 0 on error 167*306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 - x15 168*306946b0SGhennadi Procopciuc */ 169*306946b0SGhennadi Procopciucfunc console_linflex_register 170*306946b0SGhennadi Procopciuc mov x15, x30 171*306946b0SGhennadi Procopciuc bl console_linflex_core_init 172*306946b0SGhennadi Procopciuc mov x30, x15 173*306946b0SGhennadi Procopciuc 174*306946b0SGhennadi Procopciuc /* Populate the base address */ 175*306946b0SGhennadi Procopciuc str x0, [x3, #CONSOLE_T_BASE] 176*306946b0SGhennadi Procopciuc 177*306946b0SGhennadi Procopciuc mov x0, x3 178*306946b0SGhennadi Procopciuc finish_console_register linflex, putc=1, getc=0, flush=0 179*306946b0SGhennadi Procopciucendfunc console_linflex_register 180*306946b0SGhennadi Procopciuc 181*306946b0SGhennadi Procopciuc/** 182*306946b0SGhennadi Procopciuc * int console_linflex_core_putc(int c, uintptr_t baseaddr); 183*306946b0SGhennadi Procopciuc 184*306946b0SGhennadi Procopciuc * Out: w0 - printed character on success, < 0 on error. 185*306946b0SGhennadi Procopciuc * Clobber list : x0 - x3 186*306946b0SGhennadi Procopciuc */ 187*306946b0SGhennadi Procopciucfunc console_linflex_core_putc 188*306946b0SGhennadi Procopciuc cbz x1, putc_error 189*306946b0SGhennadi Procopciuc 190*306946b0SGhennadi Procopciuc cmp w0, #'\n' 191*306946b0SGhennadi Procopciuc b.ne print_char 192*306946b0SGhennadi Procopciuc 193*306946b0SGhennadi Procopciuc /* Print '\r\n' for each '\n' */ 194*306946b0SGhennadi Procopciuc mov x0, #'\r' 195*306946b0SGhennadi Procopciuc mov x14, x30 196*306946b0SGhennadi Procopciuc bl console_linflex_core_putc 197*306946b0SGhennadi Procopciuc mov x30, x14 198*306946b0SGhennadi Procopciuc mov x0, #'\n' 199*306946b0SGhennadi Procopciuc 200*306946b0SGhennadi Procopciucprint_char: 201*306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTCR] 202*306946b0SGhennadi Procopciuc and w2, w2, #UARTCR_TFBM 203*306946b0SGhennadi Procopciuc cmp w2, #0x0 204*306946b0SGhennadi Procopciuc b.eq buffer_mode 205*306946b0SGhennadi Procopciuc 206*306946b0SGhennadi Procopciucfifo_mode: 207*306946b0SGhennadi Procopciuc /* UART is in FIFO mode */ 208*306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTSR] 209*306946b0SGhennadi Procopciuc and w2, w2, #UARTSR_DTF 210*306946b0SGhennadi Procopciuc cmp w2, #0 211*306946b0SGhennadi Procopciuc b.ne fifo_mode 212*306946b0SGhennadi Procopciuc 213*306946b0SGhennadi Procopciuc strb w0, [x1, LINFLEX_BDRL] 214*306946b0SGhennadi Procopciuc b no_error 215*306946b0SGhennadi Procopciuc 216*306946b0SGhennadi Procopciucbuffer_mode: 217*306946b0SGhennadi Procopciuc strb w0, [x1, LINFLEX_BDRL] 218*306946b0SGhennadi Procopciuc 219*306946b0SGhennadi Procopciucbuffer_loop: 220*306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTSR] 221*306946b0SGhennadi Procopciuc and w3, w2, #UARTSR_DTF 222*306946b0SGhennadi Procopciuc cmp w3, #0 223*306946b0SGhennadi Procopciuc b.eq buffer_loop 224*306946b0SGhennadi Procopciuc 225*306946b0SGhennadi Procopciuc /** 226*306946b0SGhennadi Procopciuc * In Buffer Mode the DTFTFF bit of UARTSR register 227*306946b0SGhennadi Procopciuc * has to be set in software 228*306946b0SGhennadi Procopciuc */ 229*306946b0SGhennadi Procopciuc mov w2, #UARTSR_DTF 230*306946b0SGhennadi Procopciuc str w2, [x1, LINFLEX_UARTSR] 231*306946b0SGhennadi Procopciuc 232*306946b0SGhennadi Procopciucno_error: 233*306946b0SGhennadi Procopciuc mov x0, #0 234*306946b0SGhennadi Procopciuc ret 235*306946b0SGhennadi Procopciuc 236*306946b0SGhennadi Procopciucputc_error: 237*306946b0SGhennadi Procopciuc mov x0, #-EINVAL 238*306946b0SGhennadi Procopciuc ret 239*306946b0SGhennadi Procopciucendfunc console_linflex_core_putc 240*306946b0SGhennadi Procopciuc 241*306946b0SGhennadi Procopciuc/** 242*306946b0SGhennadi Procopciuc * int console_linflex_putc(int c, console_t *console); 243*306946b0SGhennadi Procopciuc * 244*306946b0SGhennadi Procopciuc * Function to output a character over the console. It 245*306946b0SGhennadi Procopciuc * returns the character printed on success or -EINVAL on error. 246*306946b0SGhennadi Procopciuc * In : w0 - character to be printed 247*306946b0SGhennadi Procopciuc * x1 - pointer to console_t struct 248*306946b0SGhennadi Procopciuc * Out: w0 - printed character on success, < 0 on error. 249*306946b0SGhennadi Procopciuc * Clobber list : x0 - x3, x15 250*306946b0SGhennadi Procopciuc */ 251*306946b0SGhennadi Procopciucfunc console_linflex_putc 252*306946b0SGhennadi Procopciuc cbz x1, putc_error 253*306946b0SGhennadi Procopciuc ldr x1, [x1, #CONSOLE_T_BASE] 254*306946b0SGhennadi Procopciuc 255*306946b0SGhennadi Procopciuc b console_linflex_core_putc 256*306946b0SGhennadi Procopciucpuct_error: 257*306946b0SGhennadi Procopciuc mov x0, #-EINVAL 258*306946b0SGhennadi Procopciuc ret 259*306946b0SGhennadi Procopciucendfunc console_linflex_putc 260