xref: /rk3399_ARM-atf/drivers/arm/pl011/aarch32/pl011_console.S (revision 831b0e9824e6c7cb07308830c12977acb79156c7)
166be868eSSoby Mathew/*
2*831b0e98SJimmy Brisson * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
366be868eSSoby Mathew *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
566be868eSSoby Mathew */
666be868eSSoby Mathew#include <arch.h>
766be868eSSoby Mathew#include <asm_macros.S>
87e2bbef9SDaniel Boulby#include <assert_macros.S>
97e2bbef9SDaniel Boulby#include <console_macros.S>
1009d40e0eSAntonio Nino Diaz#include <drivers/arm/pl011.h>
1166be868eSSoby Mathew
127e2bbef9SDaniel Boulby	/*
137e2bbef9SDaniel Boulby	 * "core" functions are low-level implementations that don't require
147e2bbef9SDaniel Boulby	 * writeable memory and are thus safe to call in BL1 crash context.
157e2bbef9SDaniel Boulby	 */
167e2bbef9SDaniel Boulby	.globl	console_pl011_core_init
177e2bbef9SDaniel Boulby	.globl	console_pl011_core_putc
187e2bbef9SDaniel Boulby	.globl	console_pl011_core_getc
197e2bbef9SDaniel Boulby	.globl	console_pl011_core_flush
207e2bbef9SDaniel Boulby
217e2bbef9SDaniel Boulby	.globl	console_pl011_putc
227e2bbef9SDaniel Boulby	.globl	console_pl011_getc
237e2bbef9SDaniel Boulby	.globl	console_pl011_flush
2466be868eSSoby Mathew
2566be868eSSoby Mathew
2666be868eSSoby Mathew	/* -----------------------------------------------
2766be868eSSoby Mathew	 * int console_core_init(uintptr_t base_addr,
2866be868eSSoby Mathew	 * unsigned int uart_clk, unsigned int baud_rate)
2966be868eSSoby Mathew	 * Function to initialize the console without a
3066be868eSSoby Mathew	 * C Runtime to print debug information. This
3166be868eSSoby Mathew	 * function will be accessed by console_init and
3266be868eSSoby Mathew	 * crash reporting.
3366be868eSSoby Mathew	 * In: r0 - console base address
3466be868eSSoby Mathew	 *     r1 - Uart clock in Hz
3566be868eSSoby Mathew	 *     r2 - Baud rate
3666be868eSSoby Mathew	 * Out: return 1 on success else 0 on error
3766be868eSSoby Mathew	 * Clobber list : r1, r2, r3
3866be868eSSoby Mathew	 * -----------------------------------------------
3966be868eSSoby Mathew	 */
407e2bbef9SDaniel Boulbyfunc console_pl011_core_init
4166be868eSSoby Mathew	/* Check the input base address */
4266be868eSSoby Mathew	cmp	r0, #0
4366be868eSSoby Mathew	beq	core_init_fail
4466be868eSSoby Mathew#if !PL011_GENERIC_UART
4566be868eSSoby Mathew	/* Check baud rate and uart clock for sanity */
4666be868eSSoby Mathew	cmp	r1, #0
4766be868eSSoby Mathew	beq	core_init_fail
4866be868eSSoby Mathew	cmp	r2, #0
4966be868eSSoby Mathew	beq	core_init_fail
5066be868eSSoby Mathew	/* Disable the UART before initialization */
5166be868eSSoby Mathew	ldr	r3, [r0, #UARTCR]
5266be868eSSoby Mathew	bic	r3, r3, #PL011_UARTCR_UARTEN
5366be868eSSoby Mathew	str	r3, [r0, #UARTCR]
5466be868eSSoby Mathew	/* Program the baudrate */
5566be868eSSoby Mathew	/* Divisor =  (Uart clock * 4) / baudrate */
5666be868eSSoby Mathew	lsl	r1, r1, #2
57a5aa25afSUsama Arif#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
58a5aa25afSUsama Arif	push	{r0,r3}
59a5aa25afSUsama Arif	softudiv	r0,r1,r2,r3
6038d5e150SAvinash Mehta	mov	r2, r0
61a5aa25afSUsama Arif	pop	{r0,r3}
62a5aa25afSUsama Arif#else
6366be868eSSoby Mathew	udiv	r2, r1, r2
64a5aa25afSUsama Arif#endif
6566be868eSSoby Mathew	/* IBRD = Divisor >> 6 */
6666be868eSSoby Mathew	lsr	r1, r2, #6
6766be868eSSoby Mathew	/* Write the IBRD */
6866be868eSSoby Mathew	str	r1, [r0, #UARTIBRD]
6966be868eSSoby Mathew	/* FBRD = Divisor & 0x3F */
7066be868eSSoby Mathew	and	r1, r2, #0x3f
7166be868eSSoby Mathew	/* Write the FBRD */
7266be868eSSoby Mathew	str	r1, [r0, #UARTFBRD]
7366be868eSSoby Mathew	mov	r1, #PL011_LINE_CONTROL
7466be868eSSoby Mathew	str	r1, [r0, #UARTLCR_H]
7566be868eSSoby Mathew	/* Clear any pending errors */
7666be868eSSoby Mathew	mov	r1, #0
7766be868eSSoby Mathew	str	r1, [r0, #UARTECR]
7866be868eSSoby Mathew	/* Enable tx, rx, and uart overall */
7966be868eSSoby Mathew	ldr	r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
8066be868eSSoby Mathew	str	r1, [r0, #UARTCR]
8166be868eSSoby Mathew#endif
8266be868eSSoby Mathew	mov	r0, #1
8366be868eSSoby Mathew	bx	lr
8466be868eSSoby Mathewcore_init_fail:
8566be868eSSoby Mathew	mov	r0, #0
8666be868eSSoby Mathew	bx	lr
877e2bbef9SDaniel Boulbyendfunc console_pl011_core_init
887e2bbef9SDaniel Boulby
897e2bbef9SDaniel Boulby	.globl console_pl011_register
907e2bbef9SDaniel Boulby
917e2bbef9SDaniel Boulby	/* -------------------------------------------------------
9265199dc8SAntonio Nino Diaz	 * int console_pl011_register(uintptr_t baseaddr,
9365199dc8SAntonio Nino Diaz	 *     uint32_t clock, uint32_t baud,
94f695e1e0SAndre Przywara	 *     console_t *console);
957e2bbef9SDaniel Boulby	 * Function to initialize and register a new PL011
967e2bbef9SDaniel Boulby	 * console. Storage passed in for the console struct
977e2bbef9SDaniel Boulby	 * *must* be persistent (i.e. not from the stack).
987e2bbef9SDaniel Boulby	 * In: r0 - UART register base address
997e2bbef9SDaniel Boulby	 *     r1 - UART clock in Hz
1007e2bbef9SDaniel Boulby	 *     r2 - Baud rate
101f695e1e0SAndre Przywara	 *     r3 - pointer to empty console_t struct
1027e2bbef9SDaniel Boulby	 * Out: return 1 on success, 0 on error
1037e2bbef9SDaniel Boulby	 * Clobber list : r0, r1, r2
1047e2bbef9SDaniel Boulby	 * -------------------------------------------------------
1057e2bbef9SDaniel Boulby	 */
1067e2bbef9SDaniel Boulbyfunc console_pl011_register
1077e2bbef9SDaniel Boulby	push	{r4, lr}
1087e2bbef9SDaniel Boulby	mov	r4, r3
1097e2bbef9SDaniel Boulby	cmp	r4, #0
1107e2bbef9SDaniel Boulby	beq	register_fail
111f695e1e0SAndre Przywara	str	r0, [r4, #CONSOLE_T_BASE]
1127e2bbef9SDaniel Boulby
1137e2bbef9SDaniel Boulby	bl console_pl011_core_init
1147e2bbef9SDaniel Boulby	cmp	r0, #0
1157e2bbef9SDaniel Boulby	beq	register_fail
1167e2bbef9SDaniel Boulby
1177e2bbef9SDaniel Boulby	mov	r0, r4
1187e2bbef9SDaniel Boulby	pop	{r4, lr}
119cc5859caSSoby Mathew	finish_console_register pl011 putc=1, getc=1, flush=1
1207e2bbef9SDaniel Boulby
1217e2bbef9SDaniel Boulbyregister_fail:
1227e2bbef9SDaniel Boulby	pop	{r4, pc}
1237e2bbef9SDaniel Boulbyendfunc console_pl011_register
12466be868eSSoby Mathew
12566be868eSSoby Mathew	/* --------------------------------------------------------
12666be868eSSoby Mathew	 * int console_core_putc(int c, uintptr_t base_addr)
12766be868eSSoby Mathew	 * Function to output a character over the console. It
12866be868eSSoby Mathew	 * returns the character printed on success or -1 on error.
12966be868eSSoby Mathew	 * In : r0 - character to be printed
13066be868eSSoby Mathew	 *      r1 - console base address
13166be868eSSoby Mathew	 * Out : return -1 on error else return character.
13266be868eSSoby Mathew	 * Clobber list : r2
13366be868eSSoby Mathew	 * --------------------------------------------------------
13466be868eSSoby Mathew	 */
1357e2bbef9SDaniel Boulbyfunc console_pl011_core_putc
13666be868eSSoby Mathew	/* Check the input parameter */
13766be868eSSoby Mathew	cmp	r1, #0
13866be868eSSoby Mathew	beq	putc_error
13966be868eSSoby Mathew	/* Prepend '\r' to '\n' */
14066be868eSSoby Mathew	cmp	r0, #0xA
14166be868eSSoby Mathew	bne	2f
14266be868eSSoby Mathew1:
14366be868eSSoby Mathew	/* Check if the transmit FIFO is full */
14466be868eSSoby Mathew	ldr	r2, [r1, #UARTFR]
14569d59e0cSYatharth Kochar	tst	r2, #PL011_UARTFR_TXFF
14669d59e0cSYatharth Kochar	bne	1b
14766be868eSSoby Mathew	mov	r2, #0xD
14866be868eSSoby Mathew	str	r2, [r1, #UARTDR]
14966be868eSSoby Mathew2:
15066be868eSSoby Mathew	/* Check if the transmit FIFO is full */
15166be868eSSoby Mathew	ldr	r2, [r1, #UARTFR]
15269d59e0cSYatharth Kochar	tst	r2, #PL011_UARTFR_TXFF
15369d59e0cSYatharth Kochar	bne	2b
15466be868eSSoby Mathew	str	r0, [r1, #UARTDR]
15566be868eSSoby Mathew	bx	lr
15666be868eSSoby Mathewputc_error:
15766be868eSSoby Mathew	mov	r0, #-1
15866be868eSSoby Mathew	bx	lr
1597e2bbef9SDaniel Boulbyendfunc console_pl011_core_putc
1607e2bbef9SDaniel Boulby
1617e2bbef9SDaniel Boulby	/* --------------------------------------------------------
162f695e1e0SAndre Przywara	 * int console_pl011_putc(int c, console_t *console)
1637e2bbef9SDaniel Boulby	 * Function to output a character over the console. It
1647e2bbef9SDaniel Boulby	 * returns the character printed on success or -1 on error.
1657e2bbef9SDaniel Boulby	 * In: r0 - character to be printed
1667e2bbef9SDaniel Boulby	 *     r1 - pointer to console_t structure
1677e2bbef9SDaniel Boulby	 * Out : return -1 on error else return character.
1687e2bbef9SDaniel Boulby	 * Clobber list: r2
1697e2bbef9SDaniel Boulby	 * -------------------------------------------------------
1707e2bbef9SDaniel Boulby	 */
1717e2bbef9SDaniel Boulbyfunc console_pl011_putc
1727e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS
1737e2bbef9SDaniel Boulby	cmp	r1, #0
1747e2bbef9SDaniel Boulby	ASM_ASSERT(ne)
1757e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */
176f695e1e0SAndre Przywara	ldr	r1, [r1, #CONSOLE_T_BASE]
1777e2bbef9SDaniel Boulby	b	console_pl011_core_putc
1787e2bbef9SDaniel Boulbyendfunc console_pl011_putc
17966be868eSSoby Mathew
18066be868eSSoby Mathew	/* ---------------------------------------------
18166be868eSSoby Mathew	 * int console_core_getc(uintptr_t base_addr)
18266be868eSSoby Mathew	 * Function to get a character from the console.
18366be868eSSoby Mathew	 * It returns the character grabbed on success
18466be868eSSoby Mathew	 * or -1 on error.
18566be868eSSoby Mathew	 * In : r0 - console base address
18666be868eSSoby Mathew	 * Clobber list : r0, r1
18766be868eSSoby Mathew	 * ---------------------------------------------
18866be868eSSoby Mathew	 */
1897e2bbef9SDaniel Boulbyfunc console_pl011_core_getc
19066be868eSSoby Mathew	cmp	r0, #0
19166be868eSSoby Mathew	beq	getc_error
19266be868eSSoby Mathew1:
19366be868eSSoby Mathew	/* Check if the receive FIFO is empty */
19466be868eSSoby Mathew	ldr	r1, [r0, #UARTFR]
19569d59e0cSYatharth Kochar	tst	r1, #PL011_UARTFR_RXFE
19669d59e0cSYatharth Kochar	bne	1b
19766be868eSSoby Mathew	ldr	r1, [r0, #UARTDR]
19866be868eSSoby Mathew	mov	r0, r1
19966be868eSSoby Mathew	bx	lr
20066be868eSSoby Mathewgetc_error:
20166be868eSSoby Mathew	mov	r0, #-1
20266be868eSSoby Mathew	bx	lr
2037e2bbef9SDaniel Boulbyendfunc console_pl011_core_getc
2047e2bbef9SDaniel Boulby
2057e2bbef9SDaniel Boulby	/* ------------------------------------------------
206f695e1e0SAndre Przywara	 * int console_pl011_getc(console_t *console)
2077e2bbef9SDaniel Boulby	 * Function to get a character from the console.
2087e2bbef9SDaniel Boulby	 * It returns the character grabbed on success
2097e2bbef9SDaniel Boulby	 * or -1 if no character is available.
2107e2bbef9SDaniel Boulby	 * In : r0 - pointer to console_t structure
2117e2bbef9SDaniel Boulby	 * Out: r0 - character if available, else -1
2127e2bbef9SDaniel Boulby	 * Clobber list: r0, r1
2137e2bbef9SDaniel Boulby	 * ------------------------------------------------
2147e2bbef9SDaniel Boulby	 */
2157e2bbef9SDaniel Boulbyfunc console_pl011_getc
2167e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS
2177e2bbef9SDaniel Boulby	cmp	r0, #0
2187e2bbef9SDaniel Boulby	ASM_ASSERT(ne)
2197e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */
220f695e1e0SAndre Przywara	ldr	r0, [r0, #CONSOLE_T_BASE]
2217e2bbef9SDaniel Boulby	b	console_pl011_core_getc
2227e2bbef9SDaniel Boulbyendfunc console_pl011_getc
22373e05284SAntonio Nino Diaz
22473e05284SAntonio Nino Diaz	/* ---------------------------------------------
225*831b0e98SJimmy Brisson	 * void console_core_flush(uintptr_t base_addr)
22673e05284SAntonio Nino Diaz	 * Function to force a write of all buffered
22773e05284SAntonio Nino Diaz	 * data that hasn't been output.
22873e05284SAntonio Nino Diaz	 * In : r0 - console base address
229*831b0e98SJimmy Brisson	 * Out : void
23073e05284SAntonio Nino Diaz	 * Clobber list : r0, r1
23173e05284SAntonio Nino Diaz	 * ---------------------------------------------
23273e05284SAntonio Nino Diaz	 */
2337e2bbef9SDaniel Boulbyfunc console_pl011_core_flush
234*831b0e98SJimmy Brisson#if ENABLE_ASSERTIONS
23573e05284SAntonio Nino Diaz	cmp	r0, #0
236*831b0e98SJimmy Brisson	ASM_ASSERT(ne)
237*831b0e98SJimmy Brisson#endif /* ENABLE_ASSERTIONS */
23873e05284SAntonio Nino Diaz
23973e05284SAntonio Nino Diaz1:
24073e05284SAntonio Nino Diaz	/* Loop while the transmit FIFO is busy */
24173e05284SAntonio Nino Diaz	ldr	r1, [r0, #UARTFR]
24273e05284SAntonio Nino Diaz	tst	r1, #PL011_UARTFR_BUSY
24373e05284SAntonio Nino Diaz	bne	1b
24473e05284SAntonio Nino Diaz
24573e05284SAntonio Nino Diaz	bx	lr
2467e2bbef9SDaniel Boulbyendfunc console_pl011_core_flush
2477e2bbef9SDaniel Boulby
2487e2bbef9SDaniel Boulby	/* ---------------------------------------------
249*831b0e98SJimmy Brisson	 * void console_pl011_flush(console_t *console)
2507e2bbef9SDaniel Boulby	 * Function to force a write of all buffered
2517e2bbef9SDaniel Boulby	 * data that hasn't been output.
2527e2bbef9SDaniel Boulby	 * In : r0 - pointer to console_t structure
253*831b0e98SJimmy Brisson	 * Out : void
2547e2bbef9SDaniel Boulby	 * Clobber list: r0, r1
2557e2bbef9SDaniel Boulby	 * ---------------------------------------------
2567e2bbef9SDaniel Boulby	 */
2577e2bbef9SDaniel Boulbyfunc console_pl011_flush
2587e2bbef9SDaniel Boulby#if ENABLE_ASSERTIONS
2597e2bbef9SDaniel Boulby	cmp	r0, #0
2607e2bbef9SDaniel Boulby	ASM_ASSERT(ne)
2617e2bbef9SDaniel Boulby#endif /* ENABLE_ASSERTIONS */
262f695e1e0SAndre Przywara	ldr	r0, [r0, #CONSOLE_T_BASE]
2637e2bbef9SDaniel Boulby	b	console_pl011_core_flush
2647e2bbef9SDaniel Boulbyendfunc console_pl011_flush
265