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