blob: abcbb594ee44672c278d45eecbf735d5a78226f0 [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)
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