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