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