xref: /rk3399_ARM-atf/plat/qti/bear/msm8916/aarch32/uartdm_console.S (revision 06253784b32034cb510c0caa4edd4b24580d69f1)
1*22170af6Sdongnanw/*
2*22170af6Sdongnanw * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
3*22170af6Sdongnanw *
4*22170af6Sdongnanw * Based on aarch32/skeleton_console.S:
5*22170af6Sdongnanw * Copyright (c) 2016-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_32(2)	/* TX FIFO has space */
22*22170af6Sdongnanw#define UART_DM_SR_TXEMT	BIT_32(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 : r0 - pointer to empty console_t structure
43*22170af6Sdongnanw	 *      r1 - base address
44*22170af6Sdongnanw	 * Out: r0 - 1 on success, 0 on error
45*22170af6Sdongnanw	 * Clobber list : r0 - r7
46*22170af6Sdongnanw	 * -----------------------------------------------------------
47*22170af6Sdongnanw	 */
48*22170af6Sdongnanwfunc console_uartdm_register
49*22170af6Sdongnanw	str	r1, [r0, #CONSOLE_T_BASE]
50*22170af6Sdongnanw	mov	r7, lr
51*22170af6Sdongnanw	bl	console_uartdm_core_init
52*22170af6Sdongnanw	mov	lr, r7
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 : r0 - unused
62*22170af6Sdongnanw	 *      r1 - base address
63*22170af6Sdongnanw	 * Out: void
64*22170af6Sdongnanw	 * Clobber list : r1, r2, r3
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	r2, #65536
75*22170af6Sdongnanw1:
76*22170af6Sdongnanw	ldr	r3, [r1, #UART_DM_SR]
77*22170af6Sdongnanw	tst	r3, #UART_DM_SR_TXEMT
78*22170af6Sdongnanw	bne	2f
79*22170af6Sdongnanw	subs	r2, r2, #1
80*22170af6Sdongnanw	bne	1b
81*22170af6Sdongnanw	/* Timeout */
82*22170af6Sdongnanw
83*22170af6Sdongnanw2:	/* Reset receiver */
84*22170af6Sdongnanw	mov	r3, #UART_DM_CR_RESET_RX
85*22170af6Sdongnanw	str	r3, [r1, #UART_DM_CR]
86*22170af6Sdongnanw
87*22170af6Sdongnanw	/* Reset transmitter */
88*22170af6Sdongnanw	mov	r3, #UART_DM_CR_RESET_TX
89*22170af6Sdongnanw	str	r3, [r1, #UART_DM_CR]
90*22170af6Sdongnanw
91*22170af6Sdongnanw	/*
92*22170af6Sdongnanw	 * Disable BAM/DMA modes but enable single-character mode for TX.
93*22170af6Sdongnanw	 * The single character mode allows simplifying the putc implementation
94*22170af6Sdongnanw	 * since characters can be written directly to the FIFO instead of
95*22170af6Sdongnanw	 * having to initiate a new transfer and waiting for its completion.
96*22170af6Sdongnanw	 */
97*22170af6Sdongnanw	mov	r3, #UART_DM_DMEN_TX_SC
98*22170af6Sdongnanw	str	r3, [r1, #UART_DM_DMEN]
99*22170af6Sdongnanw
100*22170af6Sdongnanw	/* Enable transmitter */
101*22170af6Sdongnanw	mov	r3, #UART_DM_CR_TX_ENABLE
102*22170af6Sdongnanw	str	r3, [r1, #UART_DM_CR]
103*22170af6Sdongnanw
104*22170af6Sdongnanw	bx	lr
105*22170af6Sdongnanwendfunc console_uartdm_core_init
106*22170af6Sdongnanw
107*22170af6Sdongnanw	/* -----------------------------------------------------------
108*22170af6Sdongnanw	 * int console_uartdm_putc(int c, console_t *console)
109*22170af6Sdongnanw	 * Function to output a character over the console.
110*22170af6Sdongnanw	 * In : r0 - character to be printed
111*22170af6Sdongnanw	 *      r1 - pointer to console_t struct
112*22170af6Sdongnanw	 * Out: r0 - printed character on success, < 0 on error.
113*22170af6Sdongnanw	 * Clobber list : r0, r1, r2
114*22170af6Sdongnanw	 * -----------------------------------------------------------
115*22170af6Sdongnanw	 */
116*22170af6Sdongnanwfunc console_uartdm_putc
117*22170af6Sdongnanw	ldr	r1, [r1, #CONSOLE_T_BASE]
118*22170af6Sdongnanw	b	console_uartdm_core_putc
119*22170af6Sdongnanwendfunc console_uartdm_putc
120*22170af6Sdongnanw
121*22170af6Sdongnanw	/* -----------------------------------------------------------
122*22170af6Sdongnanw	 * int console_uartdm_core_putc(int c, uintptr_t base_addr)
123*22170af6Sdongnanw	 * Function to output a character over the console.
124*22170af6Sdongnanw	 * In : r0 - character to be printed
125*22170af6Sdongnanw	 *      r1 - base address
126*22170af6Sdongnanw	 * Out: r0 - printed character on success, < 0 on error.
127*22170af6Sdongnanw	 * Clobber list : r2
128*22170af6Sdongnanw	 * -----------------------------------------------------------
129*22170af6Sdongnanw	 */
130*22170af6Sdongnanwfunc console_uartdm_core_putc
131*22170af6Sdongnanw	cmp	r0, #'\n'
132*22170af6Sdongnanw	bne	2f
133*22170af6Sdongnanw
134*22170af6Sdongnanw1:	/* Loop until TX FIFO has space */
135*22170af6Sdongnanw	ldr	r2, [r1, #UART_DM_SR]
136*22170af6Sdongnanw	tst	r2, #UART_DM_SR_TXRDY
137*22170af6Sdongnanw	beq	1b
138*22170af6Sdongnanw
139*22170af6Sdongnanw	/* Prepend '\r' to '\n' */
140*22170af6Sdongnanw	mov	r2, #'\r'
141*22170af6Sdongnanw	str	r2, [r1, #UART_DM_TF]
142*22170af6Sdongnanw
143*22170af6Sdongnanw2:	/* Loop until TX FIFO has space */
144*22170af6Sdongnanw	ldr	r2, [r1, #UART_DM_SR]
145*22170af6Sdongnanw	tst	r2, #UART_DM_SR_TXRDY
146*22170af6Sdongnanw	beq	2b
147*22170af6Sdongnanw
148*22170af6Sdongnanw	/* Write character to FIFO */
149*22170af6Sdongnanw	str	r0, [r1, #UART_DM_TF]
150*22170af6Sdongnanw	bx	lr
151*22170af6Sdongnanwendfunc console_uartdm_core_putc
152*22170af6Sdongnanw
153*22170af6Sdongnanw	/* -----------------------------------------------------------
154*22170af6Sdongnanw	 * void console_uartdm_flush(console_t *console)
155*22170af6Sdongnanw	 * Function to force a write of all buffered data
156*22170af6Sdongnanw	 * that has not been output.
157*22170af6Sdongnanw	 * In : r0 - pointer to console_t struct
158*22170af6Sdongnanw	 * Out: void
159*22170af6Sdongnanw	 * Clobber list : r0, r1, r2, r3, r4, r5
160*22170af6Sdongnanw	 * -----------------------------------------------------------
161*22170af6Sdongnanw	 */
162*22170af6Sdongnanwfunc console_uartdm_flush
163*22170af6Sdongnanw	ldr	r1, [r0, #CONSOLE_T_BASE]
164*22170af6Sdongnanw	b	console_uartdm_core_flush
165*22170af6Sdongnanwendfunc console_uartdm_flush
166*22170af6Sdongnanw
167*22170af6Sdongnanw	/* -----------------------------------------------------------
168*22170af6Sdongnanw	 * void console_uartdm_core_flush(unused, uintptr_t base_addr)
169*22170af6Sdongnanw	 * Function to force a write of all buffered data
170*22170af6Sdongnanw	 * that has not been output.
171*22170af6Sdongnanw	 * In : r0 - unused
172*22170af6Sdongnanw	 *      r1 - base address
173*22170af6Sdongnanw	 * Out: void
174*22170af6Sdongnanw	 * Clobber list : r2
175*22170af6Sdongnanw	 * -----------------------------------------------------------
176*22170af6Sdongnanw	 */
177*22170af6Sdongnanwfunc console_uartdm_core_flush
178*22170af6Sdongnanw1:	/* Loop until TX FIFO is empty */
179*22170af6Sdongnanw	ldr	r2, [r1, #UART_DM_SR]
180*22170af6Sdongnanw	tst	r2, #UART_DM_SR_TXEMT
181*22170af6Sdongnanw	beq	1b
182*22170af6Sdongnanw	bx	lr
183*22170af6Sdongnanwendfunc console_uartdm_core_flush
184