xref: /rk3399_ARM-atf/drivers/nxp/console/linflex_console.S (revision 306946b01490cfe0675300412cf738840bd099ef)
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