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