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