xref: /arm-trusted-firmware/drivers/ti/uart/aarch32/16550_console.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2015-2020, 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#include <drivers/ti/uart/uart_16550.h>
12*91f16700Schasinglulu
13*91f16700Schasinglulu	/*
14*91f16700Schasinglulu	 * "core" functions are low-level implementations that don't require
15*91f16700Schasinglulu	 * writable memory and are thus safe to call in BL1 crash context.
16*91f16700Schasinglulu	 */
17*91f16700Schasinglulu	.globl console_16550_core_init
18*91f16700Schasinglulu	.globl console_16550_core_putc
19*91f16700Schasinglulu	.globl console_16550_core_getc
20*91f16700Schasinglulu	.globl console_16550_core_flush
21*91f16700Schasinglulu
22*91f16700Schasinglulu	.globl console_16550_putc
23*91f16700Schasinglulu	.globl console_16550_getc
24*91f16700Schasinglulu	.globl console_16550_flush
25*91f16700Schasinglulu
26*91f16700Schasinglulu	/* -----------------------------------------------
27*91f16700Schasinglulu	 * int console_16550_core_init(uintptr_t base_addr,
28*91f16700Schasinglulu	 * unsigned int uart_clk, unsigned int baud_rate)
29*91f16700Schasinglulu	 * Function to initialize the console without a
30*91f16700Schasinglulu	 * C Runtime to print debug information. This
31*91f16700Schasinglulu	 * function will be accessed by console_init and
32*91f16700Schasinglulu	 * crash reporting.
33*91f16700Schasinglulu	 * In: r0 - console base address
34*91f16700Schasinglulu	 *     r1 - Uart clock in Hz
35*91f16700Schasinglulu	 *     r2 - Baud rate
36*91f16700Schasinglulu	 * Out: return 1 on success, 0 on error
37*91f16700Schasinglulu	 * Clobber list : r1, r2, r3
38*91f16700Schasinglulu	 * -----------------------------------------------
39*91f16700Schasinglulu	 */
40*91f16700Schasinglulufunc console_16550_core_init
41*91f16700Schasinglulu	/* Check the input base address */
42*91f16700Schasinglulu	cmp	r0, #0
43*91f16700Schasinglulu	beq	init_fail
44*91f16700Schasinglulu	/* Check baud rate and uart clock for sanity */
45*91f16700Schasinglulu	cmp	r1, #0
46*91f16700Schasinglulu	beq	init_fail
47*91f16700Schasinglulu	cmp	r2, #0
48*91f16700Schasinglulu	beq	init_fail
49*91f16700Schasinglulu
50*91f16700Schasinglulu	/* Program the baudrate */
51*91f16700Schasinglulu	/* Divisor =  Uart clock / (16 * baudrate) */
52*91f16700Schasinglulu	lsl	r2, r2, #4
53*91f16700Schasinglulu	udiv	r2, r1, r2
54*91f16700Schasinglulu	and	r1, r2, #0xff		/* w1 = DLL */
55*91f16700Schasinglulu	lsr	r2, r2, #8
56*91f16700Schasinglulu	and	r2, r2, #0xff		/* w2 = DLLM */
57*91f16700Schasinglulu	ldr	r3, [r0, #UARTLCR]
58*91f16700Schasinglulu	orr	r3, r3, #UARTLCR_DLAB
59*91f16700Schasinglulu	str	r3, [r0, #UARTLCR]	/* enable DLL, DLLM programming */
60*91f16700Schasinglulu	str	r1, [r0, #UARTDLL]	/* program DLL */
61*91f16700Schasinglulu	str	r2, [r0, #UARTDLLM]	/* program DLLM */
62*91f16700Schasinglulu	mov	r2, #~UARTLCR_DLAB
63*91f16700Schasinglulu	and	r3, r3, r2
64*91f16700Schasinglulu	str	r3, [r0, #UARTLCR]	/* disable DLL, DLLM programming */
65*91f16700Schasinglulu
66*91f16700Schasinglulu	/* 8n1 */
67*91f16700Schasinglulu	mov	r3, #3
68*91f16700Schasinglulu	str	r3, [r0, #UARTLCR]
69*91f16700Schasinglulu	/* no interrupt */
70*91f16700Schasinglulu	mov	r3, #0
71*91f16700Schasinglulu	str	r3, [r0, #UARTIER]
72*91f16700Schasinglulu#ifdef TI_16550_MDR_QUIRK
73*91f16700Schasinglulu	/* UART must be enabled on some platforms via the MDR register */
74*91f16700Schasinglulu	str	r3, [r0, #UARTMDR1]
75*91f16700Schasinglulu#endif /* TI_16550_MDR_QUIRK */
76*91f16700Schasinglulu	/* enable fifo, DMA */
77*91f16700Schasinglulu	mov	r3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN)
78*91f16700Schasinglulu	str	r3, [r0, #UARTFCR]
79*91f16700Schasinglulu	/* DTR + RTS */
80*91f16700Schasinglulu	mov	r3, #3
81*91f16700Schasinglulu	str	r3, [r0, #UARTMCR]
82*91f16700Schasinglulu	mov	r0, #1
83*91f16700Schasinglulu	bx	lr
84*91f16700Schasingluluinit_fail:
85*91f16700Schasinglulu	mov	r0, #0
86*91f16700Schasinglulu	bx	lr
87*91f16700Schasingluluendfunc console_16550_core_init
88*91f16700Schasinglulu
89*91f16700Schasinglulu	.globl console_16550_register
90*91f16700Schasinglulu
91*91f16700Schasinglulu	/* -------------------------------------------------------
92*91f16700Schasinglulu	 * int console_16550_register(uintptr_t baseaddr,
93*91f16700Schasinglulu	 *     uint32_t clock, uint32_t baud,
94*91f16700Schasinglulu	 *     console_t *console);
95*91f16700Schasinglulu	 * Function to initialize and register a new 16550
96*91f16700Schasinglulu	 * console. Storage passed in for the console struct
97*91f16700Schasinglulu	 * *must* be persistent (i.e. not from the stack).
98*91f16700Schasinglulu	 * If r1 (UART clock) is 0, initialisation will be
99*91f16700Schasinglulu         * skipped, relying on previous code to have done
100*91f16700Schasinglulu         * this already. r2 is ignored then as well.
101*91f16700Schasinglulu	 * In: r0 - UART register base address
102*91f16700Schasinglulu	 *     r1 - UART clock in Hz
103*91f16700Schasinglulu	 *     r2 - Baud rate (ignored if r1 is 0)
104*91f16700Schasinglulu	 *     r3 - pointer to empty console_t struct
105*91f16700Schasinglulu	 * Out: return 1 on success, 0 on error
106*91f16700Schasinglulu	 * Clobber list : r0, r1, r2
107*91f16700Schasinglulu	 * -------------------------------------------------------
108*91f16700Schasinglulu	 */
109*91f16700Schasinglulufunc console_16550_register
110*91f16700Schasinglulu	push	{r4, lr}
111*91f16700Schasinglulu	mov	r4, r3
112*91f16700Schasinglulu	cmp	r4, #0
113*91f16700Schasinglulu	beq	register_fail
114*91f16700Schasinglulu	str	r0, [r4, #CONSOLE_T_BASE]
115*91f16700Schasinglulu
116*91f16700Schasinglulu	/* A clock rate of zero means to skip the initialisation. */
117*91f16700Schasinglulu	cmp	r1, #0
118*91f16700Schasinglulu	beq	register_16550
119*91f16700Schasinglulu
120*91f16700Schasinglulu	bl	console_16550_core_init
121*91f16700Schasinglulu	cmp	r0, #0
122*91f16700Schasinglulu	beq	register_fail
123*91f16700Schasinglulu
124*91f16700Schasingluluregister_16550:
125*91f16700Schasinglulu	mov	r0, r4
126*91f16700Schasinglulu	pop	{r4, lr}
127*91f16700Schasinglulu	finish_console_register 16550 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
128*91f16700Schasinglulu
129*91f16700Schasingluluregister_fail:
130*91f16700Schasinglulu	pop	{r4, pc}
131*91f16700Schasingluluendfunc console_16550_register
132*91f16700Schasinglulu
133*91f16700Schasinglulu	/* --------------------------------------------------------
134*91f16700Schasinglulu	 * int console_16550_core_putc(int c, uintptr_t base_addr)
135*91f16700Schasinglulu	 * Function to output a character over the console. It
136*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
137*91f16700Schasinglulu	 * In : r0 - character to be printed
138*91f16700Schasinglulu	 *      r1 - console base address
139*91f16700Schasinglulu	 * Out : return -1 on error else return character.
140*91f16700Schasinglulu	 * Clobber list : r2
141*91f16700Schasinglulu	 * --------------------------------------------------------
142*91f16700Schasinglulu	 */
143*91f16700Schasinglulufunc console_16550_core_putc
144*91f16700Schasinglulu#if ENABLE_ASSERTIONS
145*91f16700Schasinglulu	cmp	r1, #0
146*91f16700Schasinglulu	ASM_ASSERT(ne)
147*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
148*91f16700Schasinglulu
149*91f16700Schasinglulu	/* Prepend '\r' to '\n' */
150*91f16700Schasinglulu	cmp	r0, #0xA
151*91f16700Schasinglulu	bne	2f
152*91f16700Schasinglulu	/* Check if the transmit FIFO is full */
153*91f16700Schasinglulu1:	ldr	r2, [r1, #UARTLSR]
154*91f16700Schasinglulu	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
155*91f16700Schasinglulu	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
156*91f16700Schasinglulu	bne	1b
157*91f16700Schasinglulu	mov	r2, #0xD		/* '\r' */
158*91f16700Schasinglulu	str	r2, [r1, #UARTTX]
159*91f16700Schasinglulu
160*91f16700Schasinglulu	/* Check if the transmit FIFO is full */
161*91f16700Schasinglulu2:	ldr	r2, [r1, #UARTLSR]
162*91f16700Schasinglulu	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
163*91f16700Schasinglulu	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
164*91f16700Schasinglulu	bne	2b
165*91f16700Schasinglulu	str	r0, [r1, #UARTTX]
166*91f16700Schasinglulu	bx	lr
167*91f16700Schasingluluendfunc console_16550_core_putc
168*91f16700Schasinglulu
169*91f16700Schasinglulu	/* --------------------------------------------------------
170*91f16700Schasinglulu	 * int console_16550_putc(int c, console_t *console)
171*91f16700Schasinglulu	 * Function to output a character over the console. It
172*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
173*91f16700Schasinglulu	 * In : r0 - character to be printed
174*91f16700Schasinglulu	 *      r1 - pointer to console_t structure
175*91f16700Schasinglulu	 * Out : return -1 on error else return character.
176*91f16700Schasinglulu	 * Clobber list : r2
177*91f16700Schasinglulu	 * --------------------------------------------------------
178*91f16700Schasinglulu	 */
179*91f16700Schasinglulufunc console_16550_putc
180*91f16700Schasinglulu#if ENABLE_ASSERTIONS
181*91f16700Schasinglulu	cmp	r1, #0
182*91f16700Schasinglulu	ASM_ASSERT(ne)
183*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
184*91f16700Schasinglulu	ldr	r1, [r1, #CONSOLE_T_BASE]
185*91f16700Schasinglulu	b	console_16550_core_putc
186*91f16700Schasingluluendfunc console_16550_putc
187*91f16700Schasinglulu
188*91f16700Schasinglulu	/* ---------------------------------------------
189*91f16700Schasinglulu	 * int console_16550_core_getc(uintptr_t base_addr)
190*91f16700Schasinglulu	 * Function to get a character from the console.
191*91f16700Schasinglulu	 * It returns the character grabbed on success
192*91f16700Schasinglulu	 * or -1 on if no character is available.
193*91f16700Schasinglulu	 * In :  r0 - console base address
194*91f16700Schasinglulu	 * Clobber list : r0, r1
195*91f16700Schasinglulu	 * ---------------------------------------------
196*91f16700Schasinglulu	 */
197*91f16700Schasinglulufunc console_16550_core_getc
198*91f16700Schasinglulu#if ENABLE_ASSERTIONS
199*91f16700Schasinglulu	cmp	r0, #0
200*91f16700Schasinglulu	ASM_ASSERT(ne)
201*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
202*91f16700Schasinglulu
203*91f16700Schasinglulu	/* Check if the receive FIFO is empty */
204*91f16700Schasinglulu1:	ldr	r1, [r0, #UARTLSR]
205*91f16700Schasinglulu	tst	r1, #UARTLSR_RDR_BIT
206*91f16700Schasinglulu	beq	no_char
207*91f16700Schasinglulu	ldr	r1, [r0, #UARTRX]
208*91f16700Schasinglulu	mov	r0, r1
209*91f16700Schasinglulu	bx	lr
210*91f16700Schasingluluno_char:
211*91f16700Schasinglulu	mov	r0, #ERROR_NO_PENDING_CHAR
212*91f16700Schasinglulu	bx	lr
213*91f16700Schasingluluendfunc console_16550_core_getc
214*91f16700Schasinglulu
215*91f16700Schasinglulu	/* ---------------------------------------------
216*91f16700Schasinglulu	 * int console_16550_getc(console_t *console)
217*91f16700Schasinglulu	 * Function to get a character from the console.
218*91f16700Schasinglulu	 * It returns the character grabbed on success
219*91f16700Schasinglulu	 * or -1 on if no character is available.
220*91f16700Schasinglulu	 * In :  r0 - pointer to console_t stucture
221*91f16700Schasinglulu	 * Out : r0 - character if available, else -1
222*91f16700Schasinglulu	 * Clobber list : r0, r1
223*91f16700Schasinglulu	 * ---------------------------------------------
224*91f16700Schasinglulu	 */
225*91f16700Schasinglulufunc console_16550_getc
226*91f16700Schasinglulu#if ENABLE_ASSERTIONS
227*91f16700Schasinglulu	cmp	r0, #0
228*91f16700Schasinglulu	ASM_ASSERT(ne)
229*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
230*91f16700Schasinglulu	ldr	r0, [r0, #CONSOLE_T_BASE]
231*91f16700Schasinglulu	b	console_16550_core_getc
232*91f16700Schasingluluendfunc console_16550_getc
233*91f16700Schasinglulu
234*91f16700Schasinglulu	/* ---------------------------------------------
235*91f16700Schasinglulu	 * void console_16550_core_flush(uintptr_t base_addr)
236*91f16700Schasinglulu	 * Function to force a write of all buffered
237*91f16700Schasinglulu	 * data that hasn't been output.
238*91f16700Schasinglulu	 * In : r0 - console base address
239*91f16700Schasinglulu	 * Out : void.
240*91f16700Schasinglulu	 * Clobber list : r0, r1
241*91f16700Schasinglulu	 * ---------------------------------------------
242*91f16700Schasinglulu	 */
243*91f16700Schasinglulufunc console_16550_core_flush
244*91f16700Schasinglulu#if ENABLE_ASSERTIONS
245*91f16700Schasinglulu	cmp	r0, #0
246*91f16700Schasinglulu	ASM_ASSERT(ne)
247*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
248*91f16700Schasinglulu
249*91f16700Schasinglulu	/* Loop until the transmit FIFO is empty */
250*91f16700Schasinglulu1:	ldr	r1, [r0, #UARTLSR]
251*91f16700Schasinglulu	and	r1, r1, #(UARTLSR_TEMT | UARTLSR_THRE)
252*91f16700Schasinglulu	cmp	r1, #(UARTLSR_TEMT | UARTLSR_THRE)
253*91f16700Schasinglulu	bne	1b
254*91f16700Schasinglulu
255*91f16700Schasinglulu	bx	lr
256*91f16700Schasingluluendfunc console_16550_core_flush
257*91f16700Schasinglulu
258*91f16700Schasinglulu	/* ---------------------------------------------
259*91f16700Schasinglulu	 * void console_16550_flush(console_t *console)
260*91f16700Schasinglulu	 * Function to force a write of all buffered
261*91f16700Schasinglulu	 * data that hasn't been output.
262*91f16700Schasinglulu	 * In : r0 - pointer to console_t structure
263*91f16700Schasinglulu	 * Out : void
264*91f16700Schasinglulu	 * Clobber list : r0, r1
265*91f16700Schasinglulu	 * ---------------------------------------------
266*91f16700Schasinglulu	 */
267*91f16700Schasinglulufunc console_16550_flush
268*91f16700Schasinglulu#if ENABLE_ASSERTIONS
269*91f16700Schasinglulu	cmp	r0, #0
270*91f16700Schasinglulu	ASM_ASSERT(ne)
271*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
272*91f16700Schasinglulu	ldr	r0, [r0, #CONSOLE_T_BASE]
273*91f16700Schasinglulu	b	console_16550_core_flush
274*91f16700Schasingluluendfunc console_16550_flush
275