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