xref: /rk3399_ARM-atf/drivers/arm/pl011/aarch64/pl011_console.S (revision fd7b287cbe9147ca9e07dd9f30c49c58bbdd92a8)
1/*
2 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <arch.h>
7#include <asm_macros.S>
8#include <assert_macros.S>
9#include <console_macros.S>
10#include <drivers/arm/pl011.h>
11
12#if !MULTI_CONSOLE_API
13/*
14 * Pull in generic functions to provide backwards compatibility for
15 * platform makefiles
16 */
17#include "../../../console/aarch64/console.S"
18#endif
19
20	/*
21	 * "core" functions are low-level implementations that don't require
22	 * writable memory and are thus safe to call in BL1 crash context.
23	 */
24	.globl console_pl011_core_init
25	.globl console_pl011_core_putc
26	.globl console_pl011_core_getc
27	.globl console_pl011_core_flush
28
29	.globl	console_pl011_putc
30	.globl	console_pl011_getc
31	.globl	console_pl011_flush
32
33	/* -----------------------------------------------
34	 * int console_pl011_core_init(uintptr_t base_addr,
35	 * unsigned int uart_clk, unsigned int baud_rate)
36	 * Function to initialize the console without a
37	 * C Runtime to print debug information. This
38	 * function will be accessed by console_init and
39	 * crash reporting.
40	 * In: x0 - console base address
41	 *     w1 - Uart clock in Hz
42	 *     w2 - Baud rate
43	 * Out: return 1 on success else 0 on error
44	 * Clobber list : x1, x2, x3, x4
45	 * -----------------------------------------------
46	 */
47func console_pl011_core_init
48	/* Check the input base address */
49	cbz	x0, core_init_fail
50#if !PL011_GENERIC_UART
51	/* Check baud rate and uart clock for sanity */
52	cbz	w1, core_init_fail
53	cbz	w2, core_init_fail
54	/* Disable uart before programming */
55	ldr	w3, [x0, #UARTCR]
56	mov	w4, #PL011_UARTCR_UARTEN
57	bic	w3, w3, w4
58	str	w3, [x0, #UARTCR]
59	/* Program the baudrate */
60	/* Divisor =  (Uart clock * 4) / baudrate */
61	lsl	w1, w1, #2
62	udiv	w2, w1, w2
63	/* IBRD = Divisor >> 6 */
64	lsr	w1, w2, #6
65	/* Write the IBRD */
66	str	w1, [x0, #UARTIBRD]
67	/* FBRD = Divisor & 0x3F */
68	and	w1, w2, #0x3f
69	/* Write the FBRD */
70	str	w1, [x0, #UARTFBRD]
71	mov	w1, #PL011_LINE_CONTROL
72	str	w1, [x0, #UARTLCR_H]
73	/* Clear any pending errors */
74	str	wzr, [x0, #UARTECR]
75	/* Enable tx, rx, and uart overall */
76	mov	w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
77	str	w1, [x0, #UARTCR]
78#endif
79	mov	w0, #1
80	ret
81core_init_fail:
82	mov	w0, wzr
83	ret
84endfunc console_pl011_core_init
85
86#if MULTI_CONSOLE_API
87	.globl console_pl011_register
88
89	/* -----------------------------------------------
90	 * int console_pl011_register(uintptr_t baseaddr,
91	 *     uint32_t clock, uint32_t baud,
92	 *     console_pl011_t *console);
93	 * Function to initialize and register a new PL011
94	 * console. Storage passed in for the console struct
95	 * *must* be persistent (i.e. not from the stack).
96	 * In: x0 - UART register base address
97	 *     w1 - UART clock in Hz
98	 *     w2 - Baud rate
99	 *     x3 - pointer to empty console_pl011_t struct
100	 * Out: return 1 on success, 0 on error
101	 * Clobber list : x0, x1, x2, x6, x7, x14
102	 * -----------------------------------------------
103	 */
104func console_pl011_register
105	mov	x7, x30
106	mov	x6, x3
107	cbz	x6, register_fail
108	str	x0, [x6, #CONSOLE_T_PL011_BASE]
109
110	bl	console_pl011_core_init
111	cbz	x0, register_fail
112
113	mov	x0, x6
114	mov	x30, x7
115	finish_console_register pl011 putc=1, getc=1, flush=1
116
117register_fail:
118	ret	x7
119endfunc console_pl011_register
120#else
121	.globl console_core_init
122	.globl console_core_putc
123	.globl console_core_getc
124	.globl console_core_flush
125	.equ console_core_init,console_pl011_core_init
126	.equ console_core_putc,console_pl011_core_putc
127	.equ console_core_getc,console_pl011_core_getc
128	.equ console_core_flush,console_pl011_core_flush
129#endif
130
131	/* --------------------------------------------------------
132	 * int console_pl011_core_putc(int c, uintptr_t base_addr)
133	 * Function to output a character over the console. It
134	 * returns the character printed on success or -1 on error.
135	 * In : w0 - character to be printed
136	 *      x1 - console base address
137	 * Out : return -1 on error else return character.
138	 * Clobber list : x2
139	 * --------------------------------------------------------
140	 */
141func console_pl011_core_putc
142#if ENABLE_ASSERTIONS
143	cmp	x1, #0
144	ASM_ASSERT(ne)
145#endif /* ENABLE_ASSERTIONS */
146
147	/* Prepend '\r' to '\n' */
148	cmp	w0, #0xA
149	b.ne	2f
1501:
151	/* Check if the transmit FIFO is full */
152	ldr	w2, [x1, #UARTFR]
153	tbnz	w2, #PL011_UARTFR_TXFF_BIT, 1b
154	mov	w2, #0xD
155	str	w2, [x1, #UARTDR]
1562:
157	/* Check if the transmit FIFO is full */
158	ldr	w2, [x1, #UARTFR]
159	tbnz	w2, #PL011_UARTFR_TXFF_BIT, 2b
160	str	w0, [x1, #UARTDR]
161	ret
162endfunc console_pl011_core_putc
163
164	/* --------------------------------------------------------
165	 * int console_pl011_putc(int c, console_pl011_t *console)
166	 * Function to output a character over the console. It
167	 * returns the character printed on success or -1 on error.
168	 * In : w0 - character to be printed
169	 *      x1 - pointer to console_t structure
170	 * Out : return -1 on error else return character.
171	 * Clobber list : x2
172	 * --------------------------------------------------------
173	 */
174func console_pl011_putc
175#if ENABLE_ASSERTIONS
176	cmp	x1, #0
177	ASM_ASSERT(ne)
178#endif /* ENABLE_ASSERTIONS */
179	ldr	x1, [x1, #CONSOLE_T_PL011_BASE]
180	b	console_pl011_core_putc
181endfunc console_pl011_putc
182
183	/* ---------------------------------------------
184	 * int console_pl011_core_getc(uintptr_t base_addr)
185	 * Function to get a character from the console.
186	 * It returns the character grabbed on success
187	 * or -1 if no character is available.
188	 * In : x0 - console base address
189	 * Out: w0 - character if available, else -1
190	 * Clobber list : x0, x1
191	 * ---------------------------------------------
192	 */
193func console_pl011_core_getc
194#if ENABLE_ASSERTIONS
195	cmp	x0, #0
196	ASM_ASSERT(ne)
197#endif /* ENABLE_ASSERTIONS */
198
199	/* Check if the receive FIFO is empty */
200	ldr	w1, [x0, #UARTFR]
201	tbnz	w1, #PL011_UARTFR_RXFE_BIT, no_char
202	ldr	w1, [x0, #UARTDR]
203	mov	w0, w1
204	ret
205no_char:
206	mov	w0, #ERROR_NO_PENDING_CHAR
207	ret
208endfunc console_pl011_core_getc
209
210	/* ---------------------------------------------
211	 * int console_pl011_getc(console_pl011_t *console)
212	 * Function to get a character from the console.
213	 * It returns the character grabbed on success
214	 * or -1 if no character is available.
215	 * In : x0 - pointer to console_t structure
216	 * Out: w0 - character if available, else -1
217	 * Clobber list : x0, x1
218	 * ---------------------------------------------
219	 */
220func console_pl011_getc
221#if ENABLE_ASSERTIONS
222	cmp	x0, #0
223	ASM_ASSERT(ne)
224#endif /* ENABLE_ASSERTIONS */
225	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
226	b	console_pl011_core_getc
227endfunc console_pl011_getc
228
229	/* ---------------------------------------------
230	 * int console_pl011_core_flush(uintptr_t base_addr)
231	 * Function to force a write of all buffered
232	 * data that hasn't been output.
233	 * In : x0 - console base address
234	 * Out : return -1 on error else return 0.
235	 * Clobber list : x0, x1
236	 * ---------------------------------------------
237	 */
238func console_pl011_core_flush
239#if ENABLE_ASSERTIONS
240	cmp	x0, #0
241	ASM_ASSERT(ne)
242#endif /* ENABLE_ASSERTIONS */
2431:
244	/* Loop until the transmit FIFO is empty */
245	ldr	w1, [x0, #UARTFR]
246	tbnz	w1, #PL011_UARTFR_BUSY_BIT, 1b
247
248	mov	w0, #0
249	ret
250endfunc console_pl011_core_flush
251
252	/* ---------------------------------------------
253	 * int console_pl011_flush(console_pl011_t *console)
254	 * Function to force a write of all buffered
255	 * data that hasn't been output.
256	 * In : x0 - pointer to console_t structure
257	 * Out : return -1 on error else return 0.
258	 * Clobber list : x0, x1
259	 * ---------------------------------------------
260	 */
261func console_pl011_flush
262#if ENABLE_ASSERTIONS
263	cmp	x0, #0
264	ASM_ASSERT(ne)
265#endif /* ENABLE_ASSERTIONS */
266	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
267	b	console_pl011_core_flush
268endfunc console_pl011_flush
269