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