xref: /rk3399_ARM-atf/plat/qti/bear/msm8916/aarch64/uartdm_console.S (revision 06253784b32034cb510c0caa4edd4b24580d69f1)
1*22170af6Sdongnanw/*
2*22170af6Sdongnanw * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
3*22170af6Sdongnanw *
4*22170af6Sdongnanw * Based on aarch64/skeleton_console.S:
5*22170af6Sdongnanw * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
6*22170af6Sdongnanw *
7*22170af6Sdongnanw * SPDX-License-Identifier: BSD-3-Clause
8*22170af6Sdongnanw */
9*22170af6Sdongnanw
10*22170af6Sdongnanw#include <asm_macros.S>
11*22170af6Sdongnanw#include <console_macros.S>
12*22170af6Sdongnanw
13*22170af6Sdongnanw/* UART DM registers */
14*22170af6Sdongnanw#define UART_DM_DMEN		0x03c		/* DMA / data packing */
15*22170af6Sdongnanw#define UART_DM_SR		0x0a4		/* status register */
16*22170af6Sdongnanw#define UART_DM_CR		0x0a8		/* command register */
17*22170af6Sdongnanw#define UART_DM_TF		0x100		/* transmit FIFO */
18*22170af6Sdongnanw
19*22170af6Sdongnanw#define UART_DM_DMEN_TX_SC	BIT_32(4)	/* TX single character mode */
20*22170af6Sdongnanw
21*22170af6Sdongnanw#define UART_DM_SR_TXRDY_BIT	2		/* TX FIFO has space */
22*22170af6Sdongnanw#define UART_DM_SR_TXEMT_BIT	3		/* TX FIFO is empty */
23*22170af6Sdongnanw
24*22170af6Sdongnanw#define UART_DM_CR_RESET_RX	(U(0x01) << 4)	/* reset receiver */
25*22170af6Sdongnanw#define UART_DM_CR_RESET_TX	(U(0x02) << 4)	/* reset transmitter */
26*22170af6Sdongnanw#define UART_DM_CR_TX_ENABLE	BIT_32(2)	/* enable transmitter */
27*22170af6Sdongnanw
28*22170af6Sdongnanw	.globl	console_uartdm_register
29*22170af6Sdongnanw	.globl	console_uartdm_core_init
30*22170af6Sdongnanw	.globl	console_uartdm_putc
31*22170af6Sdongnanw	.globl	console_uartdm_core_putc
32*22170af6Sdongnanw	.globl	console_uartdm_flush
33*22170af6Sdongnanw	.globl	console_uartdm_core_flush
34*22170af6Sdongnanw
35*22170af6Sdongnanw	/* -----------------------------------------------------------
36*22170af6Sdongnanw	 * int console_uartdm_register(console_t *console,
37*22170af6Sdongnanw	 * 	uintptr_t base_addr)
38*22170af6Sdongnanw	 * Function to initialize and register the console. The caller
39*22170af6Sdongnanw	 * needs to pass an empty console_t structure in which *MUST*
40*22170af6Sdongnanw	 * be allocated in persistent memory (e.g. a global or static
41*22170af6Sdongnanw	 * local variable, *NOT* on the stack).
42*22170af6Sdongnanw	 * In : x0 - pointer to empty console_t structure
43*22170af6Sdongnanw	 *      x1 - base address
44*22170af6Sdongnanw	 * Out: x0 - 1 on success, 0 on error
45*22170af6Sdongnanw	 * Clobber list : x0 - x7
46*22170af6Sdongnanw	 * -----------------------------------------------------------
47*22170af6Sdongnanw	 */
48*22170af6Sdongnanwfunc console_uartdm_register
49*22170af6Sdongnanw	str	x1, [x0, #CONSOLE_T_BASE]
50*22170af6Sdongnanw	mov	x7, lr
51*22170af6Sdongnanw	bl	console_uartdm_core_init
52*22170af6Sdongnanw	mov	lr, x7
53*22170af6Sdongnanw
54*22170af6Sdongnanw	/* Register the new console */
55*22170af6Sdongnanw	finish_console_register uartdm putc=1, flush=1
56*22170af6Sdongnanwendfunc console_uartdm_register
57*22170af6Sdongnanw
58*22170af6Sdongnanw	/* -----------------------------------------------------------
59*22170af6Sdongnanw	 * void console_uartdm_core_init(unused, uintptr_t base_addr)
60*22170af6Sdongnanw	 * Function to initialize the console.
61*22170af6Sdongnanw	 * In : x0 - unused
62*22170af6Sdongnanw	 *      x1 - base address
63*22170af6Sdongnanw	 * Out: void
64*22170af6Sdongnanw	 * Clobber list : x1, x2, x3
65*22170af6Sdongnanw	 * -----------------------------------------------------------
66*22170af6Sdongnanw	 */
67*22170af6Sdongnanwfunc console_uartdm_core_init
68*22170af6Sdongnanw	/*
69*22170af6Sdongnanw	 * Try to flush remaining characters from the TX FIFO before resetting
70*22170af6Sdongnanw	 * the transmitter. Unfortunately there is no good way to check if
71*22170af6Sdongnanw	 * the transmitter is actually enabled (and will finish eventually),
72*22170af6Sdongnanw	 * so use a timeout to avoid looping forever.
73*22170af6Sdongnanw	 */
74*22170af6Sdongnanw	mov	w2, #65536
75*22170af6Sdongnanw1:
76*22170af6Sdongnanw	ldr	w3, [x1, #UART_DM_SR]
77*22170af6Sdongnanw	tbnz	w3, #UART_DM_SR_TXEMT_BIT, 2f
78*22170af6Sdongnanw	subs	w2, w2, #1
79*22170af6Sdongnanw	b.ne	1b
80*22170af6Sdongnanw	/* Timeout */
81*22170af6Sdongnanw
82*22170af6Sdongnanw2:	/* Reset receiver */
83*22170af6Sdongnanw	mov	w3, #UART_DM_CR_RESET_RX
84*22170af6Sdongnanw	str	w3, [x1, #UART_DM_CR]
85*22170af6Sdongnanw
86*22170af6Sdongnanw	/* Reset transmitter */
87*22170af6Sdongnanw	mov	w3, #UART_DM_CR_RESET_TX
88*22170af6Sdongnanw	str	w3, [x1, #UART_DM_CR]
89*22170af6Sdongnanw
90*22170af6Sdongnanw	/*
91*22170af6Sdongnanw	 * Disable BAM/DMA modes but enable single-character mode for TX.
92*22170af6Sdongnanw	 * The single character mode allows simplifying the putc implementation
93*22170af6Sdongnanw	 * since characters can be written directly to the FIFO instead of
94*22170af6Sdongnanw	 * having to initiate a new transfer and waiting for its completion.
95*22170af6Sdongnanw	 */
96*22170af6Sdongnanw	mov	w3, #UART_DM_DMEN_TX_SC
97*22170af6Sdongnanw	str	w3, [x1, #UART_DM_DMEN]
98*22170af6Sdongnanw
99*22170af6Sdongnanw	/* Enable transmitter */
100*22170af6Sdongnanw	mov	w3, #UART_DM_CR_TX_ENABLE
101*22170af6Sdongnanw	str	w3, [x1, #UART_DM_CR]
102*22170af6Sdongnanw
103*22170af6Sdongnanw	ret
104*22170af6Sdongnanwendfunc console_uartdm_core_init
105*22170af6Sdongnanw
106*22170af6Sdongnanw	/* -----------------------------------------------------------
107*22170af6Sdongnanw	 * int console_uartdm_putc(int c, console_t *console)
108*22170af6Sdongnanw	 * Function to output a character over the console.
109*22170af6Sdongnanw	 * In : w0 - character to be printed
110*22170af6Sdongnanw	 *      x1 - pointer to console_t struct
111*22170af6Sdongnanw	 * Out: w0 - printed character on success, < 0 on error.
112*22170af6Sdongnanw	 * Clobber list : x0, x1, x2
113*22170af6Sdongnanw	 * -----------------------------------------------------------
114*22170af6Sdongnanw	 */
115*22170af6Sdongnanwfunc console_uartdm_putc
116*22170af6Sdongnanw	ldr	x1, [x1, #CONSOLE_T_BASE]
117*22170af6Sdongnanw	b	console_uartdm_core_putc
118*22170af6Sdongnanwendfunc console_uartdm_putc
119*22170af6Sdongnanw
120*22170af6Sdongnanw	/* -----------------------------------------------------------
121*22170af6Sdongnanw	 * int console_uartdm_core_putc(int c, uintptr_t base_addr)
122*22170af6Sdongnanw	 * Function to output a character over the console.
123*22170af6Sdongnanw	 * In : w0 - character to be printed
124*22170af6Sdongnanw	 *      x1 - base address
125*22170af6Sdongnanw	 * Out: w0 - printed character on success, < 0 on error.
126*22170af6Sdongnanw	 * Clobber list : x2
127*22170af6Sdongnanw	 * -----------------------------------------------------------
128*22170af6Sdongnanw	 */
129*22170af6Sdongnanwfunc console_uartdm_core_putc
130*22170af6Sdongnanw	cmp	w0, #'\n'
131*22170af6Sdongnanw	b.ne	2f
132*22170af6Sdongnanw
133*22170af6Sdongnanw1:	/* Loop until TX FIFO has space */
134*22170af6Sdongnanw	ldr	w2, [x1, #UART_DM_SR]
135*22170af6Sdongnanw	tbz	w2, #UART_DM_SR_TXRDY_BIT, 1b
136*22170af6Sdongnanw
137*22170af6Sdongnanw	/* Prepend '\r' to '\n' */
138*22170af6Sdongnanw	mov	w2, #'\r'
139*22170af6Sdongnanw	str	w2, [x1, #UART_DM_TF]
140*22170af6Sdongnanw
141*22170af6Sdongnanw2:	/* Loop until TX FIFO has space */
142*22170af6Sdongnanw	ldr	w2, [x1, #UART_DM_SR]
143*22170af6Sdongnanw	tbz	w2, #UART_DM_SR_TXRDY_BIT, 2b
144*22170af6Sdongnanw
145*22170af6Sdongnanw	/* Write character to FIFO */
146*22170af6Sdongnanw	str	w0, [x1, #UART_DM_TF]
147*22170af6Sdongnanw	ret
148*22170af6Sdongnanwendfunc console_uartdm_core_putc
149*22170af6Sdongnanw
150*22170af6Sdongnanw	/* -----------------------------------------------------------
151*22170af6Sdongnanw	 * void console_uartdm_flush(console_t *console)
152*22170af6Sdongnanw	 * Function to force a write of all buffered data
153*22170af6Sdongnanw	 * that has not been output.
154*22170af6Sdongnanw	 * In : x0 - pointer to console_t struct
155*22170af6Sdongnanw	 * Out: void
156*22170af6Sdongnanw	 * Clobber list : x0, x1, x2, x3, x4, x5
157*22170af6Sdongnanw	 * -----------------------------------------------------------
158*22170af6Sdongnanw	 */
159*22170af6Sdongnanwfunc console_uartdm_flush
160*22170af6Sdongnanw	ldr	x1, [x0, #CONSOLE_T_BASE]
161*22170af6Sdongnanw	b	console_uartdm_core_flush
162*22170af6Sdongnanwendfunc console_uartdm_flush
163*22170af6Sdongnanw
164*22170af6Sdongnanw	/* -----------------------------------------------------------
165*22170af6Sdongnanw	 * void console_uartdm_core_flush(unused, uintptr_t base_addr)
166*22170af6Sdongnanw	 * Function to force a write of all buffered data
167*22170af6Sdongnanw	 * that has not been output.
168*22170af6Sdongnanw	 * In : x0 - unused
169*22170af6Sdongnanw	 *      x1 - base address
170*22170af6Sdongnanw	 * Out: void
171*22170af6Sdongnanw	 * Clobber list : x2
172*22170af6Sdongnanw	 * -----------------------------------------------------------
173*22170af6Sdongnanw	 */
174*22170af6Sdongnanwfunc console_uartdm_core_flush
175*22170af6Sdongnanw1:	/* Loop until TX FIFO is empty */
176*22170af6Sdongnanw	ldr	w2, [x1, #UART_DM_SR]
177*22170af6Sdongnanw	tbz	w2, #UART_DM_SR_TXEMT_BIT, 1b
178*22170af6Sdongnanw	ret
179*22170af6Sdongnanwendfunc console_uartdm_core_flush
180