xref: /arm-trusted-firmware/drivers/arm/pl011/aarch32/pl011_console.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu#include <arch.h>
7*91f16700Schasinglulu#include <asm_macros.S>
8*91f16700Schasinglulu#include <assert_macros.S>
9*91f16700Schasinglulu#include <console_macros.S>
10*91f16700Schasinglulu#include <drivers/arm/pl011.h>
11*91f16700Schasinglulu
12*91f16700Schasinglulu	/*
13*91f16700Schasinglulu	 * "core" functions are low-level implementations that don't require
14*91f16700Schasinglulu	 * writeable memory and are thus safe to call in BL1 crash context.
15*91f16700Schasinglulu	 */
16*91f16700Schasinglulu	.globl	console_pl011_core_init
17*91f16700Schasinglulu	.globl	console_pl011_core_putc
18*91f16700Schasinglulu	.globl	console_pl011_core_getc
19*91f16700Schasinglulu	.globl	console_pl011_core_flush
20*91f16700Schasinglulu
21*91f16700Schasinglulu	.globl	console_pl011_putc
22*91f16700Schasinglulu	.globl	console_pl011_getc
23*91f16700Schasinglulu	.globl	console_pl011_flush
24*91f16700Schasinglulu
25*91f16700Schasinglulu
26*91f16700Schasinglulu	/* -----------------------------------------------
27*91f16700Schasinglulu	 * int console_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 else 0 on error
37*91f16700Schasinglulu	 * Clobber list : r1, r2, r3
38*91f16700Schasinglulu	 * -----------------------------------------------
39*91f16700Schasinglulu	 */
40*91f16700Schasinglulufunc console_pl011_core_init
41*91f16700Schasinglulu	/* Check the input base address */
42*91f16700Schasinglulu	cmp	r0, #0
43*91f16700Schasinglulu	beq	core_init_fail
44*91f16700Schasinglulu#if !PL011_GENERIC_UART
45*91f16700Schasinglulu	/* Check baud rate and uart clock for sanity */
46*91f16700Schasinglulu	cmp	r1, #0
47*91f16700Schasinglulu	beq	core_init_fail
48*91f16700Schasinglulu	cmp	r2, #0
49*91f16700Schasinglulu	beq	core_init_fail
50*91f16700Schasinglulu	/* Disable the UART before initialization */
51*91f16700Schasinglulu	ldr	r3, [r0, #UARTCR]
52*91f16700Schasinglulu	bic	r3, r3, #PL011_UARTCR_UARTEN
53*91f16700Schasinglulu	str	r3, [r0, #UARTCR]
54*91f16700Schasinglulu	/* Program the baudrate */
55*91f16700Schasinglulu	/* Divisor =  (Uart clock * 4) / baudrate */
56*91f16700Schasinglulu	lsl	r1, r1, #2
57*91f16700Schasinglulu#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
58*91f16700Schasinglulu	push	{r0,r3}
59*91f16700Schasinglulu	softudiv	r0,r1,r2,r3
60*91f16700Schasinglulu	mov	r2, r0
61*91f16700Schasinglulu	pop	{r0,r3}
62*91f16700Schasinglulu#else
63*91f16700Schasinglulu	udiv	r2, r1, r2
64*91f16700Schasinglulu#endif
65*91f16700Schasinglulu	/* IBRD = Divisor >> 6 */
66*91f16700Schasinglulu	lsr	r1, r2, #6
67*91f16700Schasinglulu	/* Write the IBRD */
68*91f16700Schasinglulu	str	r1, [r0, #UARTIBRD]
69*91f16700Schasinglulu	/* FBRD = Divisor & 0x3F */
70*91f16700Schasinglulu	and	r1, r2, #0x3f
71*91f16700Schasinglulu	/* Write the FBRD */
72*91f16700Schasinglulu	str	r1, [r0, #UARTFBRD]
73*91f16700Schasinglulu	mov	r1, #PL011_LINE_CONTROL
74*91f16700Schasinglulu	str	r1, [r0, #UARTLCR_H]
75*91f16700Schasinglulu	/* Clear any pending errors */
76*91f16700Schasinglulu	mov	r1, #0
77*91f16700Schasinglulu	str	r1, [r0, #UARTECR]
78*91f16700Schasinglulu	/* Enable tx, rx, and uart overall */
79*91f16700Schasinglulu	ldr	r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
80*91f16700Schasinglulu	str	r1, [r0, #UARTCR]
81*91f16700Schasinglulu#endif
82*91f16700Schasinglulu	mov	r0, #1
83*91f16700Schasinglulu	bx	lr
84*91f16700Schasinglulucore_init_fail:
85*91f16700Schasinglulu	mov	r0, #0
86*91f16700Schasinglulu	bx	lr
87*91f16700Schasingluluendfunc console_pl011_core_init
88*91f16700Schasinglulu
89*91f16700Schasinglulu	.globl console_pl011_register
90*91f16700Schasinglulu
91*91f16700Schasinglulu	/* -------------------------------------------------------
92*91f16700Schasinglulu	 * int console_pl011_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 PL011
96*91f16700Schasinglulu	 * console. Storage passed in for the console struct
97*91f16700Schasinglulu	 * *must* be persistent (i.e. not from the stack).
98*91f16700Schasinglulu	 * In: r0 - UART register base address
99*91f16700Schasinglulu	 *     r1 - UART clock in Hz
100*91f16700Schasinglulu	 *     r2 - Baud rate
101*91f16700Schasinglulu	 *     r3 - pointer to empty console_t struct
102*91f16700Schasinglulu	 * Out: return 1 on success, 0 on error
103*91f16700Schasinglulu	 * Clobber list : r0, r1, r2
104*91f16700Schasinglulu	 * -------------------------------------------------------
105*91f16700Schasinglulu	 */
106*91f16700Schasinglulufunc console_pl011_register
107*91f16700Schasinglulu	push	{r4, lr}
108*91f16700Schasinglulu	mov	r4, r3
109*91f16700Schasinglulu	cmp	r4, #0
110*91f16700Schasinglulu	beq	register_fail
111*91f16700Schasinglulu	str	r0, [r4, #CONSOLE_T_BASE]
112*91f16700Schasinglulu
113*91f16700Schasinglulu	bl console_pl011_core_init
114*91f16700Schasinglulu	cmp	r0, #0
115*91f16700Schasinglulu	beq	register_fail
116*91f16700Schasinglulu
117*91f16700Schasinglulu	mov	r0, r4
118*91f16700Schasinglulu	pop	{r4, lr}
119*91f16700Schasinglulu	finish_console_register pl011 putc=1, getc=ENABLE_CONSOLE_GETC, flush=1
120*91f16700Schasinglulu
121*91f16700Schasingluluregister_fail:
122*91f16700Schasinglulu	pop	{r4, pc}
123*91f16700Schasingluluendfunc console_pl011_register
124*91f16700Schasinglulu
125*91f16700Schasinglulu	/* --------------------------------------------------------
126*91f16700Schasinglulu	 * int console_core_putc(int c, uintptr_t base_addr)
127*91f16700Schasinglulu	 * Function to output a character over the console. It
128*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
129*91f16700Schasinglulu	 * In : r0 - character to be printed
130*91f16700Schasinglulu	 *      r1 - console base address
131*91f16700Schasinglulu	 * Out : return -1 on error else return character.
132*91f16700Schasinglulu	 * Clobber list : r2
133*91f16700Schasinglulu	 * --------------------------------------------------------
134*91f16700Schasinglulu	 */
135*91f16700Schasinglulufunc console_pl011_core_putc
136*91f16700Schasinglulu	/* Check the input parameter */
137*91f16700Schasinglulu	cmp	r1, #0
138*91f16700Schasinglulu	beq	putc_error
139*91f16700Schasinglulu	/* Prepend '\r' to '\n' */
140*91f16700Schasinglulu	cmp	r0, #0xA
141*91f16700Schasinglulu	bne	2f
142*91f16700Schasinglulu1:
143*91f16700Schasinglulu	/* Check if the transmit FIFO is full */
144*91f16700Schasinglulu	ldr	r2, [r1, #UARTFR]
145*91f16700Schasinglulu	tst	r2, #PL011_UARTFR_TXFF
146*91f16700Schasinglulu	bne	1b
147*91f16700Schasinglulu	mov	r2, #0xD
148*91f16700Schasinglulu	str	r2, [r1, #UARTDR]
149*91f16700Schasinglulu2:
150*91f16700Schasinglulu	/* Check if the transmit FIFO is full */
151*91f16700Schasinglulu	ldr	r2, [r1, #UARTFR]
152*91f16700Schasinglulu	tst	r2, #PL011_UARTFR_TXFF
153*91f16700Schasinglulu	bne	2b
154*91f16700Schasinglulu	str	r0, [r1, #UARTDR]
155*91f16700Schasinglulu	bx	lr
156*91f16700Schasingluluputc_error:
157*91f16700Schasinglulu	mov	r0, #-1
158*91f16700Schasinglulu	bx	lr
159*91f16700Schasingluluendfunc console_pl011_core_putc
160*91f16700Schasinglulu
161*91f16700Schasinglulu	/* --------------------------------------------------------
162*91f16700Schasinglulu	 * int console_pl011_putc(int c, console_t *console)
163*91f16700Schasinglulu	 * Function to output a character over the console. It
164*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
165*91f16700Schasinglulu	 * In: r0 - character to be printed
166*91f16700Schasinglulu	 *     r1 - pointer to console_t structure
167*91f16700Schasinglulu	 * Out : return -1 on error else return character.
168*91f16700Schasinglulu	 * Clobber list: r2
169*91f16700Schasinglulu	 * -------------------------------------------------------
170*91f16700Schasinglulu	 */
171*91f16700Schasinglulufunc console_pl011_putc
172*91f16700Schasinglulu#if ENABLE_ASSERTIONS
173*91f16700Schasinglulu	cmp	r1, #0
174*91f16700Schasinglulu	ASM_ASSERT(ne)
175*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
176*91f16700Schasinglulu	ldr	r1, [r1, #CONSOLE_T_BASE]
177*91f16700Schasinglulu	b	console_pl011_core_putc
178*91f16700Schasingluluendfunc console_pl011_putc
179*91f16700Schasinglulu
180*91f16700Schasinglulu	/* ---------------------------------------------
181*91f16700Schasinglulu	 * int console_core_getc(uintptr_t base_addr)
182*91f16700Schasinglulu	 * Function to get a character from the console.
183*91f16700Schasinglulu	 * It returns the character grabbed on success
184*91f16700Schasinglulu	 * or -1 on error.
185*91f16700Schasinglulu	 * In : r0 - console base address
186*91f16700Schasinglulu	 * Clobber list : r0, r1
187*91f16700Schasinglulu	 * ---------------------------------------------
188*91f16700Schasinglulu	 */
189*91f16700Schasinglulufunc console_pl011_core_getc
190*91f16700Schasinglulu	cmp	r0, #0
191*91f16700Schasinglulu	beq	getc_error
192*91f16700Schasinglulu1:
193*91f16700Schasinglulu	/* Check if the receive FIFO is empty */
194*91f16700Schasinglulu	ldr	r1, [r0, #UARTFR]
195*91f16700Schasinglulu	tst	r1, #PL011_UARTFR_RXFE
196*91f16700Schasinglulu	bne	1b
197*91f16700Schasinglulu	ldr	r1, [r0, #UARTDR]
198*91f16700Schasinglulu	mov	r0, r1
199*91f16700Schasinglulu	bx	lr
200*91f16700Schasinglulugetc_error:
201*91f16700Schasinglulu	mov	r0, #-1
202*91f16700Schasinglulu	bx	lr
203*91f16700Schasingluluendfunc console_pl011_core_getc
204*91f16700Schasinglulu
205*91f16700Schasinglulu	/* ------------------------------------------------
206*91f16700Schasinglulu	 * int console_pl011_getc(console_t *console)
207*91f16700Schasinglulu	 * Function to get a character from the console.
208*91f16700Schasinglulu	 * It returns the character grabbed on success
209*91f16700Schasinglulu	 * or -1 if no character is available.
210*91f16700Schasinglulu	 * In : r0 - pointer to console_t structure
211*91f16700Schasinglulu	 * Out: r0 - character if available, else -1
212*91f16700Schasinglulu	 * Clobber list: r0, r1
213*91f16700Schasinglulu	 * ------------------------------------------------
214*91f16700Schasinglulu	 */
215*91f16700Schasinglulufunc console_pl011_getc
216*91f16700Schasinglulu#if ENABLE_ASSERTIONS
217*91f16700Schasinglulu	cmp	r0, #0
218*91f16700Schasinglulu	ASM_ASSERT(ne)
219*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
220*91f16700Schasinglulu	ldr	r0, [r0, #CONSOLE_T_BASE]
221*91f16700Schasinglulu	b	console_pl011_core_getc
222*91f16700Schasingluluendfunc console_pl011_getc
223*91f16700Schasinglulu
224*91f16700Schasinglulu	/* ---------------------------------------------
225*91f16700Schasinglulu	 * void console_core_flush(uintptr_t base_addr)
226*91f16700Schasinglulu	 * Function to force a write of all buffered
227*91f16700Schasinglulu	 * data that hasn't been output.
228*91f16700Schasinglulu	 * In : r0 - console base address
229*91f16700Schasinglulu	 * Out : void
230*91f16700Schasinglulu	 * Clobber list : r0, r1
231*91f16700Schasinglulu	 * ---------------------------------------------
232*91f16700Schasinglulu	 */
233*91f16700Schasinglulufunc console_pl011_core_flush
234*91f16700Schasinglulu#if ENABLE_ASSERTIONS
235*91f16700Schasinglulu	cmp	r0, #0
236*91f16700Schasinglulu	ASM_ASSERT(ne)
237*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
238*91f16700Schasinglulu
239*91f16700Schasinglulu1:
240*91f16700Schasinglulu	/* Loop while the transmit FIFO is busy */
241*91f16700Schasinglulu	ldr	r1, [r0, #UARTFR]
242*91f16700Schasinglulu	tst	r1, #PL011_UARTFR_BUSY
243*91f16700Schasinglulu	bne	1b
244*91f16700Schasinglulu
245*91f16700Schasinglulu	bx	lr
246*91f16700Schasingluluendfunc console_pl011_core_flush
247*91f16700Schasinglulu
248*91f16700Schasinglulu	/* ---------------------------------------------
249*91f16700Schasinglulu	 * void console_pl011_flush(console_t *console)
250*91f16700Schasinglulu	 * Function to force a write of all buffered
251*91f16700Schasinglulu	 * data that hasn't been output.
252*91f16700Schasinglulu	 * In : r0 - pointer to console_t structure
253*91f16700Schasinglulu	 * Out : void
254*91f16700Schasinglulu	 * Clobber list: r0, r1
255*91f16700Schasinglulu	 * ---------------------------------------------
256*91f16700Schasinglulu	 */
257*91f16700Schasinglulufunc console_pl011_flush
258*91f16700Schasinglulu#if ENABLE_ASSERTIONS
259*91f16700Schasinglulu	cmp	r0, #0
260*91f16700Schasinglulu	ASM_ASSERT(ne)
261*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
262*91f16700Schasinglulu	ldr	r0, [r0, #CONSOLE_T_BASE]
263*91f16700Schasinglulu	b	console_pl011_core_flush
264*91f16700Schasingluluendfunc console_pl011_flush
265