1306946b0SGhennadi Procopciuc/* 2306946b0SGhennadi Procopciuc * Copyright 2024 NXP 3306946b0SGhennadi Procopciuc * 4306946b0SGhennadi Procopciuc * SPDX-License-Identifier: BSD-3-Clause 5306946b0SGhennadi Procopciuc */ 6306946b0SGhennadi Procopciuc 7306946b0SGhennadi Procopciuc#include <lib/libc/errno.h> 8306946b0SGhennadi Procopciuc 9306946b0SGhennadi Procopciuc#include <asm_macros.S> 10306946b0SGhennadi Procopciuc#include <console_macros.S> 11306946b0SGhennadi Procopciuc#include <lib/utils_def.h> 12306946b0SGhennadi Procopciuc 13306946b0SGhennadi Procopciuc#define LDIV_MULTIPLIER U(16) 14306946b0SGhennadi Procopciuc 15306946b0SGhennadi Procopciuc#define LINFLEX_LINCR1 (0x0) 16306946b0SGhennadi Procopciuc#define LINCR1_INIT BIT_32(0) 17306946b0SGhennadi Procopciuc#define LINCR1_MME BIT_32(4) 18306946b0SGhennadi Procopciuc 19306946b0SGhennadi Procopciuc#define LINFLEX_LINSR (0x8) 20306946b0SGhennadi Procopciuc#define LINSR_LINS_INITMODE (0x00001000) 21*95ac568bSGhennadi Procopciuc#define LINSR_LINS_RX_TX_MODE (0x00008000) 22306946b0SGhennadi Procopciuc#define LINSR_LINS_MASK (0x0000F000) 23306946b0SGhennadi Procopciuc 24306946b0SGhennadi Procopciuc#define LINFLEX_UARTCR (0x10) 25306946b0SGhennadi Procopciuc#define UARTCR_ROSE BIT_32(23) 26306946b0SGhennadi Procopciuc 27306946b0SGhennadi Procopciuc#define LINFLEX_UARTSR (0x14) 28306946b0SGhennadi Procopciuc#define LINFLEX_LINIBRR (0x28) 29306946b0SGhennadi Procopciuc#define LINFLEX_LINFBRR (0x24) 30306946b0SGhennadi Procopciuc#define LINFLEX_BDRL (0x38) 31306946b0SGhennadi Procopciuc#define LINFLEX_UARTPTO (0x50) 32306946b0SGhennadi Procopciuc 33306946b0SGhennadi Procopciuc#define UARTCR_UART BIT_32(0) 34306946b0SGhennadi Procopciuc#define UARTCR_WL0 BIT_32(1) 35306946b0SGhennadi Procopciuc#define UARTCR_PC0 BIT_32(3) 36306946b0SGhennadi Procopciuc#define UARTCR_TXEN BIT_32(4) 37306946b0SGhennadi Procopciuc#define UARTCR_RXEN BIT_32(5) 38306946b0SGhennadi Procopciuc#define UARTCR_PC1 BIT_32(6) 39306946b0SGhennadi Procopciuc#define UARTCR_TFBM BIT_32(8) 40306946b0SGhennadi Procopciuc#define UARTCR_RFBM BIT_32(9) 41306946b0SGhennadi Procopciuc#define UARTCR_OSR_SHIFT U(24) 42306946b0SGhennadi Procopciuc#define UARTCR_OSR_WIDTH U(4) 43306946b0SGhennadi Procopciuc 44306946b0SGhennadi Procopciuc#define UARTSR_DTF BIT_32(1) 45306946b0SGhennadi Procopciuc 46306946b0SGhennadi Procopciuc/* 47306946b0SGhennadi Procopciuc * "core" functions are low-level implementations that do not require 48306946b0SGhennadi Procopciuc * writable memory and are thus safe to call in BL1 crash context. 49306946b0SGhennadi Procopciuc */ 50306946b0SGhennadi Procopciuc.globl console_linflex_core_init 51306946b0SGhennadi Procopciuc.globl console_linflex_core_putc 52*95ac568bSGhennadi Procopciuc.globl console_linflex_core_flush 53306946b0SGhennadi Procopciuc 54306946b0SGhennadi Procopciuc.globl console_linflex_register 55306946b0SGhennadi Procopciuc.globl console_linflex_putc 56*95ac568bSGhennadi Procopciuc.globl console_linflex_flush 57306946b0SGhennadi Procopciuc 58306946b0SGhennadi Procopciuc/** 59306946b0SGhennadi Procopciuc * uint32_t get_ldiv_mult(uintptr_t baseaddr, uint32_t clock, 60306946b0SGhennadi Procopciuc * uint32_t baud, console_t *console,); 61306946b0SGhennadi Procopciuc * 62306946b0SGhennadi Procopciuc * Clobber list : x0 - x6 63306946b0SGhennadi Procopciuc * Out x4: LDIV multiplier 64306946b0SGhennadi Procopciuc */ 65306946b0SGhennadi Procopciucfunc get_ldiv_mult 66306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_UARTCR] 67306946b0SGhennadi Procopciuc mov w5, w4 68306946b0SGhennadi Procopciuc 69306946b0SGhennadi Procopciuc /* Prepare choices in w5 and w6 */ 70306946b0SGhennadi Procopciuc ubfx x5, x5, #UARTCR_OSR_SHIFT, #UARTCR_OSR_WIDTH 71306946b0SGhennadi Procopciuc mov w6, #LDIV_MULTIPLIER 72306946b0SGhennadi Procopciuc 73306946b0SGhennadi Procopciuc and w4, w4, #UARTCR_ROSE 74306946b0SGhennadi Procopciuc cmp w4, #0x0 75306946b0SGhennadi Procopciuc csel w4, w5, w6, ne 76306946b0SGhennadi Procopciuc ret 77306946b0SGhennadi Procopciucendfunc get_ldiv_mult 78306946b0SGhennadi Procopciuc 79306946b0SGhennadi Procopciuc/* 80306946b0SGhennadi Procopciuc * void linflex_set_brg(uintptr_t baseaddr, uint32_t clock 81306946b0SGhennadi Procopciuc * uint32_t baud, console_t *console); 82306946b0SGhennadi Procopciuc * 83306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 84306946b0SGhennadi Procopciuc */ 85306946b0SGhennadi Procopciucfunc linflex_set_brg 86306946b0SGhennadi Procopciuc mov x13, x30 87306946b0SGhennadi Procopciuc bl get_ldiv_mult 88306946b0SGhennadi Procopciuc mov x30, x13 89306946b0SGhennadi Procopciuc 90306946b0SGhennadi Procopciuc /* (x4) dividr = baudrate * ldiv_mult */ 91306946b0SGhennadi Procopciuc mul x4, x4, x2 92306946b0SGhennadi Procopciuc /* (x5) divisr = clock rate */ 93306946b0SGhennadi Procopciuc mov x5, x1 94306946b0SGhennadi Procopciuc /* (x6) ibr = divisr / dividr */ 95306946b0SGhennadi Procopciuc udiv x6, x5, x4 96306946b0SGhennadi Procopciuc /* (x7) fbr = divisr % dividr */ 97306946b0SGhennadi Procopciuc msub x7, x6, x4, x5 98306946b0SGhennadi Procopciuc /* fbr *= 16 / dividr */ 99306946b0SGhennadi Procopciuc lsl x7, x7, #4 100306946b0SGhennadi Procopciuc udiv x7, x7, x4 101306946b0SGhennadi Procopciuc /* fbr &= 0xf */ 102306946b0SGhennadi Procopciuc and w7, w7, #0xf 103306946b0SGhennadi Procopciuc str w6, [x0, LINFLEX_LINIBRR] 104306946b0SGhennadi Procopciuc str w7, [x0, LINFLEX_LINFBRR] 105306946b0SGhennadi Procopciuc ret 106306946b0SGhennadi Procopciucendfunc linflex_set_brg 107306946b0SGhennadi Procopciuc 108306946b0SGhennadi Procopciuc/** 109306946b0SGhennadi Procopciuc * int console_linflex_core_init(uintptr_t baseaddr, uint32_t clock, 110306946b0SGhennadi Procopciuc * uint32_t baud); 111306946b0SGhennadi Procopciuc * 112306946b0SGhennadi Procopciuc * In: x0 - Linflex base address 113306946b0SGhennadi Procopciuc * x1 - clock frequency 114306946b0SGhennadi Procopciuc * x2 - baudrate 115306946b0SGhennadi Procopciuc * Out: x0 - 1 on success, 0 on error 116306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 - x14 117306946b0SGhennadi Procopciuc */ 118306946b0SGhennadi Procopciucfunc console_linflex_core_init 119306946b0SGhennadi Procopciuc /* Set master mode and init mode */ 120306946b0SGhennadi Procopciuc mov w4, #(LINCR1_INIT) 121306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 122306946b0SGhennadi Procopciuc mov w4, #(LINCR1_MME | LINCR1_INIT) 123306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 124306946b0SGhennadi Procopciuc 125306946b0SGhennadi Procopciuc /* wait for init mode entry */ 126306946b0SGhennadi Procopciucwait_init_entry: 127306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_LINSR] 128306946b0SGhennadi Procopciuc and w4, w4, #LINSR_LINS_MASK 129306946b0SGhennadi Procopciuc cmp w4, #LINSR_LINS_INITMODE 130306946b0SGhennadi Procopciuc b.ne wait_init_entry 131306946b0SGhennadi Procopciuc 132306946b0SGhennadi Procopciuc /* Set UART bit */ 133306946b0SGhennadi Procopciuc mov w4, #UARTCR_UART 134306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTCR] 135306946b0SGhennadi Procopciuc 136306946b0SGhennadi Procopciuc mov x14, x30 137306946b0SGhennadi Procopciuc bl linflex_set_brg 138306946b0SGhennadi Procopciuc mov x30, x14 139306946b0SGhennadi Procopciuc 140306946b0SGhennadi Procopciuc /* Set preset timeout register value. */ 141306946b0SGhennadi Procopciuc mov w4, #0xf 142306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTPTO] 143306946b0SGhennadi Procopciuc 144306946b0SGhennadi Procopciuc /* 8-bit data, no parity, Tx/Rx enabled, UART mode */ 145306946b0SGhennadi Procopciuc mov w4, #(UARTCR_PC1 | UARTCR_RXEN | UARTCR_TXEN | UARTCR_PC0 | \ 146306946b0SGhennadi Procopciuc UARTCR_WL0 | UARTCR_UART | UARTCR_RFBM | UARTCR_TFBM) 147306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_UARTCR] 148306946b0SGhennadi Procopciuc 149306946b0SGhennadi Procopciuc /* End init mode */ 150306946b0SGhennadi Procopciuc ldr w4, [x0, LINFLEX_LINCR1] 151306946b0SGhennadi Procopciuc bic w4, w4, #LINCR1_INIT 152306946b0SGhennadi Procopciuc str w4, [x0, LINFLEX_LINCR1] 153306946b0SGhennadi Procopciuc ret 154306946b0SGhennadi Procopciucendfunc console_linflex_core_init 155306946b0SGhennadi Procopciuc 156306946b0SGhennadi Procopciuc/** 157306946b0SGhennadi Procopciuc * int console_linflex_register(uintptr_t baseaddr, uint32_t clock, 158306946b0SGhennadi Procopciuc * uint32_t clock, uint32_t baud); 159306946b0SGhennadi Procopciuc * 160306946b0SGhennadi Procopciuc * Function to initialize and register the console. 161306946b0SGhennadi Procopciuc * The caller needs to pass an empty console_linflex_t 162306946b0SGhennadi Procopciuc * structure in which *MUST* be allocated in 163306946b0SGhennadi Procopciuc * persistent memory (e.g. a global or static local 164306946b0SGhennadi Procopciuc * variable, *NOT* on the stack). 165306946b0SGhennadi Procopciuc * In: x0 - Linflex base address 166306946b0SGhennadi Procopciuc * x1 - clock frequency 167306946b0SGhennadi Procopciuc * x2 - baudrate 168306946b0SGhennadi Procopciuc * x3 - pointer to empty console_t structure 169306946b0SGhennadi Procopciuc * Out: x0 - 1 on success, 0 on error 170306946b0SGhennadi Procopciuc * Clobber list : x0 - x7, x13 - x15 171306946b0SGhennadi Procopciuc */ 172306946b0SGhennadi Procopciucfunc console_linflex_register 173306946b0SGhennadi Procopciuc mov x15, x30 174306946b0SGhennadi Procopciuc bl console_linflex_core_init 175306946b0SGhennadi Procopciuc mov x30, x15 176306946b0SGhennadi Procopciuc 177306946b0SGhennadi Procopciuc /* Populate the base address */ 178306946b0SGhennadi Procopciuc str x0, [x3, #CONSOLE_T_BASE] 179306946b0SGhennadi Procopciuc 180306946b0SGhennadi Procopciuc mov x0, x3 181*95ac568bSGhennadi Procopciuc finish_console_register linflex, putc=1, getc=0, flush=1 182306946b0SGhennadi Procopciucendfunc console_linflex_register 183306946b0SGhennadi Procopciuc 184306946b0SGhennadi Procopciuc/** 185*95ac568bSGhennadi Procopciuc * int console_linflex_core_flush(uintptr_t baseaddr); 186*95ac568bSGhennadi Procopciuc * 187*95ac568bSGhennadi Procopciuc * Loop while the TX fifo is not empty, depending on the selected UART mode. 188*95ac568bSGhennadi Procopciuc * 189*95ac568bSGhennadi Procopciuc * In: x0 - Linflex base address 190*95ac568bSGhennadi Procopciuc * Clobber list : x0 - x1 191*95ac568bSGhennadi Procopciuc */ 192*95ac568bSGhennadi Procopciucfunc console_linflex_core_flush 193*95ac568bSGhennadi Procopciucwait_rx_tx: 194*95ac568bSGhennadi Procopciuc ldr w1, [x0, LINFLEX_LINSR] 195*95ac568bSGhennadi Procopciuc and w1, w1, #LINSR_LINS_MASK 196*95ac568bSGhennadi Procopciuc cmp w1, #LINSR_LINS_RX_TX_MODE 197*95ac568bSGhennadi Procopciuc b.eq wait_rx_tx 198*95ac568bSGhennadi Procopciuc 199*95ac568bSGhennadi Procopciuc mov x0, #0 200*95ac568bSGhennadi Procopciuc ret 201*95ac568bSGhennadi Procopciucendfunc console_linflex_core_flush 202*95ac568bSGhennadi Procopciuc 203*95ac568bSGhennadi Procopciuc/** 204306946b0SGhennadi Procopciuc * int console_linflex_core_putc(int c, uintptr_t baseaddr); 205306946b0SGhennadi Procopciuc 206306946b0SGhennadi Procopciuc * Out: w0 - printed character on success, < 0 on error. 207306946b0SGhennadi Procopciuc * Clobber list : x0 - x3 208306946b0SGhennadi Procopciuc */ 209306946b0SGhennadi Procopciucfunc console_linflex_core_putc 210306946b0SGhennadi Procopciuc cbz x1, putc_error 211306946b0SGhennadi Procopciuc 212306946b0SGhennadi Procopciuc cmp w0, #'\n' 213306946b0SGhennadi Procopciuc b.ne print_char 214306946b0SGhennadi Procopciuc 215306946b0SGhennadi Procopciuc /* Print '\r\n' for each '\n' */ 216306946b0SGhennadi Procopciuc mov x0, #'\r' 217306946b0SGhennadi Procopciuc mov x14, x30 218306946b0SGhennadi Procopciuc bl console_linflex_core_putc 219306946b0SGhennadi Procopciuc mov x30, x14 220306946b0SGhennadi Procopciuc mov x0, #'\n' 221306946b0SGhennadi Procopciuc 222306946b0SGhennadi Procopciucprint_char: 223306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTCR] 224306946b0SGhennadi Procopciuc and w2, w2, #UARTCR_TFBM 225306946b0SGhennadi Procopciuc cmp w2, #0x0 226306946b0SGhennadi Procopciuc b.eq buffer_mode 227306946b0SGhennadi Procopciuc 228306946b0SGhennadi Procopciucfifo_mode: 229306946b0SGhennadi Procopciuc /* UART is in FIFO mode */ 230306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTSR] 231306946b0SGhennadi Procopciuc and w2, w2, #UARTSR_DTF 232306946b0SGhennadi Procopciuc cmp w2, #0 233306946b0SGhennadi Procopciuc b.ne fifo_mode 234306946b0SGhennadi Procopciuc 235306946b0SGhennadi Procopciuc strb w0, [x1, LINFLEX_BDRL] 236306946b0SGhennadi Procopciuc b no_error 237306946b0SGhennadi Procopciuc 238306946b0SGhennadi Procopciucbuffer_mode: 239306946b0SGhennadi Procopciuc strb w0, [x1, LINFLEX_BDRL] 240306946b0SGhennadi Procopciuc 241306946b0SGhennadi Procopciucbuffer_loop: 242306946b0SGhennadi Procopciuc ldr w2, [x1, LINFLEX_UARTSR] 243306946b0SGhennadi Procopciuc and w3, w2, #UARTSR_DTF 244306946b0SGhennadi Procopciuc cmp w3, #0 245306946b0SGhennadi Procopciuc b.eq buffer_loop 246306946b0SGhennadi Procopciuc 247306946b0SGhennadi Procopciuc /** 248306946b0SGhennadi Procopciuc * In Buffer Mode the DTFTFF bit of UARTSR register 249306946b0SGhennadi Procopciuc * has to be set in software 250306946b0SGhennadi Procopciuc */ 251306946b0SGhennadi Procopciuc mov w2, #UARTSR_DTF 252306946b0SGhennadi Procopciuc str w2, [x1, LINFLEX_UARTSR] 253306946b0SGhennadi Procopciuc 254306946b0SGhennadi Procopciucno_error: 255306946b0SGhennadi Procopciuc mov x0, #0 256306946b0SGhennadi Procopciuc ret 257306946b0SGhennadi Procopciuc 258306946b0SGhennadi Procopciucputc_error: 259306946b0SGhennadi Procopciuc mov x0, #-EINVAL 260306946b0SGhennadi Procopciuc ret 261306946b0SGhennadi Procopciucendfunc console_linflex_core_putc 262306946b0SGhennadi Procopciuc 263306946b0SGhennadi Procopciuc/** 264306946b0SGhennadi Procopciuc * int console_linflex_putc(int c, console_t *console); 265306946b0SGhennadi Procopciuc * 266306946b0SGhennadi Procopciuc * Function to output a character over the console. It 267306946b0SGhennadi Procopciuc * returns the character printed on success or -EINVAL on error. 268306946b0SGhennadi Procopciuc * In : w0 - character to be printed 269306946b0SGhennadi Procopciuc * x1 - pointer to console_t struct 270306946b0SGhennadi Procopciuc * Out: w0 - printed character on success, < 0 on error. 271306946b0SGhennadi Procopciuc * Clobber list : x0 - x3, x15 272306946b0SGhennadi Procopciuc */ 273306946b0SGhennadi Procopciucfunc console_linflex_putc 274306946b0SGhennadi Procopciuc cbz x1, putc_error 275306946b0SGhennadi Procopciuc ldr x1, [x1, #CONSOLE_T_BASE] 276306946b0SGhennadi Procopciuc 277306946b0SGhennadi Procopciuc b console_linflex_core_putc 278306946b0SGhennadi Procopciucpuct_error: 279306946b0SGhennadi Procopciuc mov x0, #-EINVAL 280306946b0SGhennadi Procopciuc ret 281306946b0SGhennadi Procopciucendfunc console_linflex_putc 282*95ac568bSGhennadi Procopciuc 283*95ac568bSGhennadi Procopciuc/** 284*95ac568bSGhennadi Procopciuc * int console_linflex_flush(console_t *console); 285*95ac568bSGhennadi Procopciuc * 286*95ac568bSGhennadi Procopciuc * Function to wait for the TX FIFO to be cleared. 287*95ac568bSGhennadi Procopciuc * In : x0 - pointer to console_t struct 288*95ac568bSGhennadi Procopciuc * Out: x0 - return -1 on error else return 0. 289*95ac568bSGhennadi Procopciuc * Clobber list : x0 - x1 290*95ac568bSGhennadi Procopciuc */ 291*95ac568bSGhennadi Procopciucfunc console_linflex_flush 292*95ac568bSGhennadi Procopciuc cbz x0, flush_error 293*95ac568bSGhennadi Procopciuc ldr x0, [x0, #CONSOLE_T_BASE] 294*95ac568bSGhennadi Procopciuc 295*95ac568bSGhennadi Procopciuc b console_linflex_core_flush 296*95ac568bSGhennadi Procopciucflush_error: 297*95ac568bSGhennadi Procopciuc mov x0, #-EINVAL 298*95ac568bSGhennadi Procopciuc ret 299*95ac568bSGhennadi Procopciucendfunc console_linflex_flush 300