xref: /aosp_15_r20/external/arm-trusted-firmware/drivers/nxp/console/16550_console.S (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park/*
2*54fd6939SJiyong Park * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park#include <arch.h>
8*54fd6939SJiyong Park#include <asm_macros.S>
9*54fd6939SJiyong Park#include <assert_macros.S>
10*54fd6939SJiyong Park#include <console_macros.S>
11*54fd6939SJiyong Park
12*54fd6939SJiyong Park/* UART16550 Registers */
13*54fd6939SJiyong Park#define UARTTX			0x0
14*54fd6939SJiyong Park#define UARTRX			0x0
15*54fd6939SJiyong Park#define UARTDLL			0x0
16*54fd6939SJiyong Park#define UARTIER			0x1
17*54fd6939SJiyong Park#define UARTDLLM		0x1
18*54fd6939SJiyong Park#define UARTFCR			0x2
19*54fd6939SJiyong Park#define UARTLCR			0x3
20*54fd6939SJiyong Park#define UARTLSR			0x5
21*54fd6939SJiyong Park#define UARTMCR                 0x4
22*54fd6939SJiyong Park
23*54fd6939SJiyong Park/* FIFO Control Register bits */
24*54fd6939SJiyong Park#define UARTFCR_FIFOMD_16450	(0 << 6)
25*54fd6939SJiyong Park#define UARTFCR_FIFOMD_16550	(1 << 6)
26*54fd6939SJiyong Park#define UARTFCR_RXTRIG_1	(0 << 6)
27*54fd6939SJiyong Park#define UARTFCR_RXTRIG_4	(1 << 6)
28*54fd6939SJiyong Park#define UARTFCR_RXTRIG_8	(2 << 6)
29*54fd6939SJiyong Park#define UARTFCR_RXTRIG_16	(3 << 6)
30*54fd6939SJiyong Park#define UARTFCR_TXTRIG_1	(0 << 4)
31*54fd6939SJiyong Park#define UARTFCR_TXTRIG_4	(1 << 4)
32*54fd6939SJiyong Park#define UARTFCR_TXTRIG_8	(2 << 4)
33*54fd6939SJiyong Park#define UARTFCR_TXTRIG_16	(3 << 4)
34*54fd6939SJiyong Park#define UARTFCR_DMAEN		(1 << 3)	/* Enable DMA mode */
35*54fd6939SJiyong Park#define UARTFCR_TXCLR		(1 << 2)	/* Clear contents of Tx FIFO */
36*54fd6939SJiyong Park#define UARTFCR_RXCLR		(1 << 1)	/* Clear contents of Rx FIFO */
37*54fd6939SJiyong Park#define UARTFCR_FIFOEN		(1 << 0)	/* Enable the Tx/Rx FIFO */
38*54fd6939SJiyong Park#define UARTFCR_64FIFO          (1 << 5)
39*54fd6939SJiyong Park
40*54fd6939SJiyong Park/* Line Control Register bits */
41*54fd6939SJiyong Park#define UARTLCR_DLAB		(1 << 7)	/* Divisor Latch Access */
42*54fd6939SJiyong Park#define UARTLCR_SETB		(1 << 6)	/* Set BREAK Condition */
43*54fd6939SJiyong Park#define UARTLCR_SETP		(1 << 5)	/* Set Parity to LCR[4] */
44*54fd6939SJiyong Park#define UARTLCR_EVEN		(1 << 4)	/* Even Parity Format */
45*54fd6939SJiyong Park#define UARTLCR_PAR		(1 << 3)	/* Parity */
46*54fd6939SJiyong Park#define UARTLCR_STOP		(1 << 2)	/* Stop Bit */
47*54fd6939SJiyong Park#define UARTLCR_WORDSZ_5	0		/* Word Length of 5 */
48*54fd6939SJiyong Park#define UARTLCR_WORDSZ_6	1		/* Word Length of 6 */
49*54fd6939SJiyong Park#define UARTLCR_WORDSZ_7	2		/* Word Length of 7 */
50*54fd6939SJiyong Park#define UARTLCR_WORDSZ_8	3		/* Word Length of 8 */
51*54fd6939SJiyong Park
52*54fd6939SJiyong Park/* Line Status Register bits */
53*54fd6939SJiyong Park#define UARTLSR_RXFIFOEMT	(1 << 9)	/* Rx Fifo Empty */
54*54fd6939SJiyong Park#define UARTLSR_TXFIFOFULL	(1 << 8)	/* Tx Fifo Full */
55*54fd6939SJiyong Park#define UARTLSR_RXFIFOERR	(1 << 7)	/* Rx Fifo Error */
56*54fd6939SJiyong Park#define UARTLSR_TEMT		(1 << 6)	/* Tx Shift Register Empty */
57*54fd6939SJiyong Park#define UARTLSR_THRE		(1 << 5)	/* Tx Holding Register Empty */
58*54fd6939SJiyong Park#define UARTLSR_BRK		(1 << 4)	/* Break Condition Detected */
59*54fd6939SJiyong Park#define UARTLSR_FERR		(1 << 3)	/* Framing Error */
60*54fd6939SJiyong Park#define UARTLSR_PERR		(1 << 3)	/* Parity Error */
61*54fd6939SJiyong Park#define UARTLSR_OVRF		(1 << 2)	/* Rx Overrun Error */
62*54fd6939SJiyong Park#define UARTLSR_RDR		(1 << 2)	/* Rx Data Ready */
63*54fd6939SJiyong Park
64*54fd6939SJiyong Park#define CONSOLE_T_16550_BASE	CONSOLE_T_BASE
65*54fd6939SJiyong Park
66*54fd6939SJiyong Park	/*
67*54fd6939SJiyong Park	 * "core" functions are low-level implementations that don't require
68*54fd6939SJiyong Park	 * writable memory and are thus safe to call in BL1 crash context.
69*54fd6939SJiyong Park	 */
70*54fd6939SJiyong Park	.globl nxp_console_16550_core_init
71*54fd6939SJiyong Park	.globl nxp_console_16550_core_putc
72*54fd6939SJiyong Park	.globl nxp_console_16550_core_getc
73*54fd6939SJiyong Park	.globl nxp_console_16550_core_flush
74*54fd6939SJiyong Park
75*54fd6939SJiyong Park	.globl console_16550_putc
76*54fd6939SJiyong Park	.globl console_16550_getc
77*54fd6939SJiyong Park	.globl console_16550_flush
78*54fd6939SJiyong Park
79*54fd6939SJiyong Park	/* -----------------------------------------------
80*54fd6939SJiyong Park	 * int nxp_console_16550_core_init(uintptr_t base_addr,
81*54fd6939SJiyong Park	 * unsigned int uart_clk, unsigned int baud_rate)
82*54fd6939SJiyong Park	 * Function to initialize the console without a
83*54fd6939SJiyong Park	 * C Runtime to print debug information. This
84*54fd6939SJiyong Park	 * function will be accessed by console_init and
85*54fd6939SJiyong Park	 * crash reporting.
86*54fd6939SJiyong Park	 * In: x0 - console base address
87*54fd6939SJiyong Park	 *     w1 - Uart clock in Hz
88*54fd6939SJiyong Park	 *     w2 - Baud rate
89*54fd6939SJiyong Park	 * Out: return 1 on success, 0 on error
90*54fd6939SJiyong Park	 * Clobber list : x1, x2, x3
91*54fd6939SJiyong Park	 * -----------------------------------------------
92*54fd6939SJiyong Park	 */
93*54fd6939SJiyong Parkfunc nxp_console_16550_core_init
94*54fd6939SJiyong Park	/* Check the input base address */
95*54fd6939SJiyong Park	cbz	x0, init_fail
96*54fd6939SJiyong Park	/* Check baud rate and uart clock for sanity */
97*54fd6939SJiyong Park	cbz	w1, init_fail
98*54fd6939SJiyong Park	cbz	w2, init_fail
99*54fd6939SJiyong Park
100*54fd6939SJiyong Park	/* Program the baudrate */
101*54fd6939SJiyong Park	/* Divisor =  Uart clock / (16 * baudrate) */
102*54fd6939SJiyong Park	lsl	w2, w2, #4
103*54fd6939SJiyong Park	udiv	w2, w1, w2
104*54fd6939SJiyong Park	and	w1, w2, #0xff		/* w1 = DLL */
105*54fd6939SJiyong Park	lsr	w2, w2, #8
106*54fd6939SJiyong Park	and	w2, w2, #0xff		/* w2 = DLLM */
107*54fd6939SJiyong Park	ldrb	w3, [x0, #UARTLCR]
108*54fd6939SJiyong Park	orr	w3, w3, #UARTLCR_DLAB
109*54fd6939SJiyong Park	strb	w3, [x0, #UARTLCR]	/* enable DLL, DLLM programming */
110*54fd6939SJiyong Park	strb	w1, [x0, #UARTDLL]	/* program DLL */
111*54fd6939SJiyong Park	strb	w2, [x0, #UARTDLLM]	/* program DLLM */
112*54fd6939SJiyong Park	mov	w2, #~UARTLCR_DLAB
113*54fd6939SJiyong Park	and	w3, w3, w2
114*54fd6939SJiyong Park	strb	w3, [x0, #UARTLCR]	/* disable DLL, DLLM programming */
115*54fd6939SJiyong Park
116*54fd6939SJiyong Park	/* 8n1 */
117*54fd6939SJiyong Park	mov	w3, #3
118*54fd6939SJiyong Park	strb	w3, [x0, #UARTLCR]
119*54fd6939SJiyong Park	/* no interrupt */
120*54fd6939SJiyong Park	mov	w3, #0
121*54fd6939SJiyong Park	strb	w3, [x0, #UARTIER]
122*54fd6939SJiyong Park	/* enable fifo, DMA */
123*54fd6939SJiyong Park	mov	w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR)
124*54fd6939SJiyong Park	strb	w3, [x0, #UARTFCR]
125*54fd6939SJiyong Park	/* DTR + RTS */
126*54fd6939SJiyong Park	mov	w3, #3
127*54fd6939SJiyong Park	str	w3, [x0, #UARTMCR]
128*54fd6939SJiyong Park	mov	w0, #1
129*54fd6939SJiyong Park	ret
130*54fd6939SJiyong Parkinit_fail:
131*54fd6939SJiyong Park	mov	w0, #0
132*54fd6939SJiyong Park	ret
133*54fd6939SJiyong Parkendfunc nxp_console_16550_core_init
134*54fd6939SJiyong Park
135*54fd6939SJiyong Park	.globl nxp_console_16550_register
136*54fd6939SJiyong Park
137*54fd6939SJiyong Park	/* -----------------------------------------------
138*54fd6939SJiyong Park	 * int nxp_console_16550_register(uintptr_t baseaddr,
139*54fd6939SJiyong Park	 *     uint32_t clock, uint32_t baud,
140*54fd6939SJiyong Park	 *     console_t *console);
141*54fd6939SJiyong Park	 * Function to initialize and register a new 16550
142*54fd6939SJiyong Park	 * console. Storage passed in for the console struct
143*54fd6939SJiyong Park	 * *must* be persistent (i.e. not from the stack).
144*54fd6939SJiyong Park	 * If w1 (UART clock) is 0, initialisation will be
145*54fd6939SJiyong Park	 * skipped, relying on previous code to have done
146*54fd6939SJiyong Park	 * this already. w2 is ignored then as well.
147*54fd6939SJiyong Park	 * In: x0 - UART register base address
148*54fd6939SJiyong Park	 *     w1 - UART clock in Hz
149*54fd6939SJiyong Park	 *     w2 - Baud rate (ignored if w1 is 0)
150*54fd6939SJiyong Park	 *     x3 - pointer to empty console_t struct
151*54fd6939SJiyong Park	 * Out: return 1 on success, 0 on error
152*54fd6939SJiyong Park	 * Clobber list : x0, x1, x2, x6, x7, x14
153*54fd6939SJiyong Park	 * -----------------------------------------------
154*54fd6939SJiyong Park	 */
155*54fd6939SJiyong Parkfunc nxp_console_16550_register
156*54fd6939SJiyong Park	mov	x7, x30
157*54fd6939SJiyong Park	mov	x6, x3
158*54fd6939SJiyong Park	cbz	x6, register_fail
159*54fd6939SJiyong Park	str	x0, [x6, #CONSOLE_T_16550_BASE]
160*54fd6939SJiyong Park
161*54fd6939SJiyong Park	/* A clock rate of zero means to skip the initialisation. */
162*54fd6939SJiyong Park	cbz	w1, register_16550
163*54fd6939SJiyong Park
164*54fd6939SJiyong Park	bl	nxp_console_16550_core_init
165*54fd6939SJiyong Park	cbz	x0, register_fail
166*54fd6939SJiyong Park
167*54fd6939SJiyong Parkregister_16550:
168*54fd6939SJiyong Park	mov	x0, x6
169*54fd6939SJiyong Park	mov	x30, x7
170*54fd6939SJiyong Park	finish_console_register 16550 putc=1, getc=1, flush=1
171*54fd6939SJiyong Park
172*54fd6939SJiyong Parkregister_fail:
173*54fd6939SJiyong Park	ret	x7
174*54fd6939SJiyong Parkendfunc nxp_console_16550_register
175*54fd6939SJiyong Park
176*54fd6939SJiyong Park	/* --------------------------------------------------------
177*54fd6939SJiyong Park	 * int console_16550_core_putc(int c, uintptr_t base_addr)
178*54fd6939SJiyong Park	 * Function to output a character over the console. It
179*54fd6939SJiyong Park	 * returns the character printed on success or -1 on error.
180*54fd6939SJiyong Park	 * In : w0 - character to be printed
181*54fd6939SJiyong Park	 *      x1 - console base address
182*54fd6939SJiyong Park	 * Out : return -1 on error else return character.
183*54fd6939SJiyong Park	 * Clobber list : x2
184*54fd6939SJiyong Park	 * --------------------------------------------------------
185*54fd6939SJiyong Park	 */
186*54fd6939SJiyong Parkfunc nxp_console_16550_core_putc
187*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
188*54fd6939SJiyong Park	cmp	x1, #0
189*54fd6939SJiyong Park	ASM_ASSERT(ne)
190*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
191*54fd6939SJiyong Park
192*54fd6939SJiyong Park	/* Prepend '\r' to '\n' */
193*54fd6939SJiyong Park	cmp	w0, #'\n'
194*54fd6939SJiyong Park	b.ne	2f
195*54fd6939SJiyong Park	/* Check if the transmit FIFO is full */
196*54fd6939SJiyong Park1:	ldrb	w2, [x1, #UARTLSR]
197*54fd6939SJiyong Park	and	w2, w2, #UARTLSR_THRE        /* #(UARTLSR_TEMT | UARTLSR_THRE)*/
198*54fd6939SJiyong Park	cmp	w2, #(UARTLSR_THRE)
199*54fd6939SJiyong Park	b.ne	1b
200*54fd6939SJiyong Park	mov	w2, #'\r'
201*54fd6939SJiyong Park	strb	w2, [x1, #UARTTX]
202*54fd6939SJiyong Park	ldrb	w2, [x1, #UARTFCR]
203*54fd6939SJiyong Park	orr	w2, w2, #UARTFCR_TXCLR
204*54fd6939SJiyong Park
205*54fd6939SJiyong Park	/* Check if the transmit FIFO is full */
206*54fd6939SJiyong Park2:	ldrb	w2, [x1, #UARTLSR]
207*54fd6939SJiyong Park	and	w2, w2, #(UARTLSR_THRE)
208*54fd6939SJiyong Park	cmp	w2, #(UARTLSR_THRE)
209*54fd6939SJiyong Park	b.ne	2b
210*54fd6939SJiyong Park	strb	w0, [x1, #UARTTX]
211*54fd6939SJiyong Park	ret
212*54fd6939SJiyong Parkendfunc nxp_console_16550_core_putc
213*54fd6939SJiyong Park
214*54fd6939SJiyong Park	/* --------------------------------------------------------
215*54fd6939SJiyong Park	 * int console_16550_putc(int c, console_t *console)
216*54fd6939SJiyong Park	 * Function to output a character over the console. It
217*54fd6939SJiyong Park	 * returns the character printed on success or -1 on error.
218*54fd6939SJiyong Park	 * In : w0 - character to be printed
219*54fd6939SJiyong Park	 *      x1 - pointer to console_t structure
220*54fd6939SJiyong Park	 * Out : return -1 on error else return character.
221*54fd6939SJiyong Park	 * Clobber list : x2
222*54fd6939SJiyong Park	 * --------------------------------------------------------
223*54fd6939SJiyong Park	 */
224*54fd6939SJiyong Parkfunc console_16550_putc
225*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
226*54fd6939SJiyong Park	cmp	x1, #0
227*54fd6939SJiyong Park	ASM_ASSERT(ne)
228*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
229*54fd6939SJiyong Park	ldr	x1, [x1, #CONSOLE_T_16550_BASE]
230*54fd6939SJiyong Park	b	nxp_console_16550_core_putc
231*54fd6939SJiyong Parkendfunc console_16550_putc
232*54fd6939SJiyong Park
233*54fd6939SJiyong Park	/* ---------------------------------------------
234*54fd6939SJiyong Park	 * int console_16550_core_getc(uintptr_t base_addr)
235*54fd6939SJiyong Park	 * Function to get a character from the console.
236*54fd6939SJiyong Park	 * It returns the character grabbed on success
237*54fd6939SJiyong Park	 * or -1 on if no character is available.
238*54fd6939SJiyong Park	 * In :  x0 - console base address
239*54fd6939SJiyong Park	 * Out : w0 - character if available, else -1
240*54fd6939SJiyong Park	 * Clobber list : x0, x1
241*54fd6939SJiyong Park	 * ---------------------------------------------
242*54fd6939SJiyong Park	 */
243*54fd6939SJiyong Parkfunc nxp_console_16550_core_getc
244*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
245*54fd6939SJiyong Park	cmp	x0, #0
246*54fd6939SJiyong Park	ASM_ASSERT(ne)
247*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
248*54fd6939SJiyong Park
249*54fd6939SJiyong Park	/* Check if the receive FIFO is empty */
250*54fd6939SJiyong Park1:	ldrb	w1, [x0, #UARTLSR]
251*54fd6939SJiyong Park	tbz	w1, #UARTLSR_RDR, 1b
252*54fd6939SJiyong Park	ldrb	w0, [x0, #UARTRX]
253*54fd6939SJiyong Park	ret
254*54fd6939SJiyong Parkno_char:
255*54fd6939SJiyong Park	mov	w0, #ERROR_NO_PENDING_CHAR
256*54fd6939SJiyong Park	ret
257*54fd6939SJiyong Parkendfunc nxp_console_16550_core_getc
258*54fd6939SJiyong Park
259*54fd6939SJiyong Park	/* ---------------------------------------------
260*54fd6939SJiyong Park	 * int console_16550_getc(console_t *console)
261*54fd6939SJiyong Park	 * Function to get a character from the console.
262*54fd6939SJiyong Park	 * It returns the character grabbed on success
263*54fd6939SJiyong Park	 * or -1 on if no character is available.
264*54fd6939SJiyong Park	 * In :  x0 - pointer to console_t structure
265*54fd6939SJiyong Park	 * Out : w0 - character if available, else -1
266*54fd6939SJiyong Park	 * Clobber list : x0, x1
267*54fd6939SJiyong Park	 * ---------------------------------------------
268*54fd6939SJiyong Park	 */
269*54fd6939SJiyong Parkfunc console_16550_getc
270*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
271*54fd6939SJiyong Park	cmp	x1, #0
272*54fd6939SJiyong Park	ASM_ASSERT(ne)
273*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
274*54fd6939SJiyong Park	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
275*54fd6939SJiyong Park	b	nxp_console_16550_core_getc
276*54fd6939SJiyong Parkendfunc console_16550_getc
277*54fd6939SJiyong Park
278*54fd6939SJiyong Park	/* ---------------------------------------------
279*54fd6939SJiyong Park	 * int console_16550_core_flush(uintptr_t base_addr)
280*54fd6939SJiyong Park	 * Function to force a write of all buffered
281*54fd6939SJiyong Park	 * data that hasn't been output.
282*54fd6939SJiyong Park	 * In : x0 - console base address
283*54fd6939SJiyong Park	 * Out : return -1 on error else return 0.
284*54fd6939SJiyong Park	 * Clobber list : x0, x1
285*54fd6939SJiyong Park	 * ---------------------------------------------
286*54fd6939SJiyong Park	 */
287*54fd6939SJiyong Parkfunc nxp_console_16550_core_flush
288*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
289*54fd6939SJiyong Park	cmp	x0, #0
290*54fd6939SJiyong Park	ASM_ASSERT(ne)
291*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
292*54fd6939SJiyong Park
293*54fd6939SJiyong Park	/* Loop until the transmit FIFO is empty */
294*54fd6939SJiyong Park1:	ldrb	w1, [x0, #UARTLSR]
295*54fd6939SJiyong Park	and	w1, w1, #(UARTLSR_THRE)
296*54fd6939SJiyong Park	cmp	w1, #(UARTLSR_THRE)
297*54fd6939SJiyong Park	b.ne	1b
298*54fd6939SJiyong Park
299*54fd6939SJiyong Park	mov	w0, #0
300*54fd6939SJiyong Park	ret
301*54fd6939SJiyong Parkendfunc nxp_console_16550_core_flush
302*54fd6939SJiyong Park
303*54fd6939SJiyong Park	/* ---------------------------------------------
304*54fd6939SJiyong Park	 * int console_16550_flush(console_t *console)
305*54fd6939SJiyong Park	 * Function to force a write of all buffered
306*54fd6939SJiyong Park	 * data that hasn't been output.
307*54fd6939SJiyong Park	 * In : x0 - pointer to console_t structure
308*54fd6939SJiyong Park	 * Out : return -1 on error else return 0.
309*54fd6939SJiyong Park	 * Clobber list : x0, x1
310*54fd6939SJiyong Park	 * ---------------------------------------------
311*54fd6939SJiyong Park	 */
312*54fd6939SJiyong Parkfunc console_16550_flush
313*54fd6939SJiyong Park#if ENABLE_ASSERTIONS
314*54fd6939SJiyong Park	cmp	x0, #0
315*54fd6939SJiyong Park	ASM_ASSERT(ne)
316*54fd6939SJiyong Park#endif /* ENABLE_ASSERTIONS */
317*54fd6939SJiyong Park	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
318*54fd6939SJiyong Park	b	nxp_console_16550_core_flush
319*54fd6939SJiyong Parkendfunc console_16550_flush
320