xref: /arm-trusted-firmware/drivers/st/uart/aarch64/stm32_console.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (C) 2023, STMicroelectronics - All Rights Reserved
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu
7*91f16700Schasinglulu#include <asm_macros.S>
8*91f16700Schasinglulu#include <assert_macros.S>
9*91f16700Schasinglulu#include <console_macros.S>
10*91f16700Schasinglulu#include <drivers/st/stm32_console.h>
11*91f16700Schasinglulu#include <drivers/st/stm32_uart_regs.h>
12*91f16700Schasinglulu
13*91f16700Schasinglulu#define USART_TIMEOUT		0x1000
14*91f16700Schasinglulu
15*91f16700Schasinglulu	/*
16*91f16700Schasinglulu	 * "core" functions are low-level implementations that don't require
17*91f16700Schasinglulu	 * writeable memory and are thus safe to call in BL1 crash context.
18*91f16700Schasinglulu	 */
19*91f16700Schasinglulu	.globl	console_stm32_core_init
20*91f16700Schasinglulu	.globl	console_stm32_core_putc
21*91f16700Schasinglulu	.globl	console_stm32_core_getc
22*91f16700Schasinglulu	.globl	console_stm32_core_flush
23*91f16700Schasinglulu
24*91f16700Schasinglulu	.globl	console_stm32_putc
25*91f16700Schasinglulu	.globl	console_stm32_flush
26*91f16700Schasinglulu
27*91f16700Schasinglulu
28*91f16700Schasinglulu
29*91f16700Schasinglulu	/* -----------------------------------------------------------------
30*91f16700Schasinglulu	 * int console_core_init(uintptr_t base_addr,
31*91f16700Schasinglulu	 *			 unsigned int uart_clk,
32*91f16700Schasinglulu	 *			 unsigned int baud_rate)
33*91f16700Schasinglulu	 *
34*91f16700Schasinglulu	 * Function to initialize the console without a C Runtime to print
35*91f16700Schasinglulu	 * debug information. This function will be accessed by console_init
36*91f16700Schasinglulu	 * and crash reporting.
37*91f16700Schasinglulu	 *
38*91f16700Schasinglulu	 * In: x0 - console base address
39*91f16700Schasinglulu	 *     w1 - Uart clock in Hz
40*91f16700Schasinglulu	 *     w2 - Baud rate
41*91f16700Schasinglulu	 * Out: return 1 on success else 0 on error
42*91f16700Schasinglulu	 * Clobber list : x1, x2, x3, x4
43*91f16700Schasinglulu	 * -----------------------------------------------
44*91f16700Schasinglulu	 */
45*91f16700Schasinglulufunc console_stm32_core_init
46*91f16700Schasinglulu	/* Check the input base address */
47*91f16700Schasinglulu	cbz	x0, core_init_fail
48*91f16700Schasinglulu#if !defined(IMAGE_BL2)
49*91f16700Schasinglulu#if STM32MP_RECONFIGURE_CONSOLE
50*91f16700Schasinglulu	/* UART clock rate is set to 0 in BL32, skip init in that case */
51*91f16700Schasinglulu	cbz	x1, 1f
52*91f16700Schasinglulu#else /* STM32MP_RECONFIGURE_CONSOLE */
53*91f16700Schasinglulu	/* Skip UART initialization if it is already enabled */
54*91f16700Schasinglulu	ldr	w3, [x0, #USART_CR1]
55*91f16700Schasinglulu	tst	w3, #USART_CR1_UE
56*91f16700Schasinglulu	b.ne	1f
57*91f16700Schasinglulu#endif /* STM32MP_RECONFIGURE_CONSOLE */
58*91f16700Schasinglulu#endif /* IMAGE_BL2 */
59*91f16700Schasinglulu	/* Check baud rate and uart clock for sanity */
60*91f16700Schasinglulu	cbz	w1, core_init_fail
61*91f16700Schasinglulu	cbz	w2, core_init_fail
62*91f16700Schasinglulu	/* Disable UART */
63*91f16700Schasinglulu	ldr	w3, [x0, #USART_CR1]
64*91f16700Schasinglulu	mov	w4, #USART_CR1_UE
65*91f16700Schasinglulu	bic	w3, w3, w4
66*91f16700Schasinglulu	str	w3, [x0, #USART_CR1]
67*91f16700Schasinglulu	/* Configure UART */
68*91f16700Schasinglulu	mov	w4, #(USART_CR1_TE)
69*91f16700Schasinglulu	orr	w4, w4, #(USART_CR1_FIFOEN)
70*91f16700Schasinglulu	orr	w3, w3, w4
71*91f16700Schasinglulu	str	w3, [x0, #USART_CR1]
72*91f16700Schasinglulu	ldr	w3, [x0, #USART_CR2]
73*91f16700Schasinglulu	mov	w4, #USART_CR2_STOP
74*91f16700Schasinglulu	bic	w3, w3, w4
75*91f16700Schasinglulu	str	w3, [x0, #USART_CR2]
76*91f16700Schasinglulu	/* Divisor =  (Uart clock + (baudrate / 2)) / baudrate */
77*91f16700Schasinglulu	lsr	w3, w2, #1
78*91f16700Schasinglulu	add	w3, w1, w3
79*91f16700Schasinglulu	udiv	w3, w3, w2
80*91f16700Schasinglulu	cmp	w3, #16
81*91f16700Schasinglulu	b.hi	2f
82*91f16700Schasinglulu	/* Oversampling 8 */
83*91f16700Schasinglulu	/* Divisor =  (2 * Uart clock + (baudrate / 2)) / baudrate */
84*91f16700Schasinglulu	lsr	w3, w2, #1
85*91f16700Schasinglulu	add	w3, w3, w1, lsl #1
86*91f16700Schasinglulu	udiv	w3, w3, w2
87*91f16700Schasinglulu	and	w1, w3, #USART_BRR_DIV_FRACTION
88*91f16700Schasinglulu	lsr	w1, w1, #1
89*91f16700Schasinglulu	bic	w3, w3, #USART_BRR_DIV_FRACTION
90*91f16700Schasinglulu	orr	w3, w3, w1
91*91f16700Schasinglulu	ldr	w1, [x0, #USART_CR1]
92*91f16700Schasinglulu	orr	w1, w1, #USART_CR1_OVER8
93*91f16700Schasinglulu	str	w1, [x0, #USART_CR1]
94*91f16700Schasinglulu2:
95*91f16700Schasinglulu	str	w3, [x0, #USART_BRR]
96*91f16700Schasinglulu	/* Enable UART */
97*91f16700Schasinglulu	ldr	w3, [x0, #USART_CR1]
98*91f16700Schasinglulu	mov	w4, #USART_CR1_UE
99*91f16700Schasinglulu	orr	w3, w3, w4
100*91f16700Schasinglulu	str	w3, [x0, #USART_CR1]
101*91f16700Schasinglulu	/* Check TEACK bit */
102*91f16700Schasinglulu	mov	w2, #USART_TIMEOUT
103*91f16700Schasingluluteack_loop:
104*91f16700Schasinglulu	subs	w2, w2, #1
105*91f16700Schasinglulu	beq	core_init_fail
106*91f16700Schasinglulu	ldr	w3, [x0, #USART_ISR]
107*91f16700Schasinglulu	tst	w3, #USART_ISR_TEACK
108*91f16700Schasinglulu	beq	teack_loop
109*91f16700Schasinglulu1:
110*91f16700Schasinglulu	mov	w0, #1
111*91f16700Schasinglulu	ret
112*91f16700Schasinglulucore_init_fail:
113*91f16700Schasinglulu	mov	w0, wzr
114*91f16700Schasinglulu	ret
115*91f16700Schasingluluendfunc console_stm32_core_init
116*91f16700Schasinglulu
117*91f16700Schasinglulu	.globl console_stm32_register
118*91f16700Schasinglulu
119*91f16700Schasinglulu	/* -------------------------------------------------------
120*91f16700Schasinglulu	 * int console_stm32_register(uintptr_t baseaddr,
121*91f16700Schasinglulu	 *     uint32_t clock, uint32_t baud,
122*91f16700Schasinglulu	 *     console_t *console);
123*91f16700Schasinglulu	 * Function to initialize and register a new STM32
124*91f16700Schasinglulu	 * console. Storage passed in for the console struct
125*91f16700Schasinglulu	 * *must* be persistent (i.e. not from the stack).
126*91f16700Schasinglulu	 * In: x0 - UART register base address
127*91f16700Schasinglulu	 *     w1 - UART clock in Hz
128*91f16700Schasinglulu	 *     w2 - Baud rate
129*91f16700Schasinglulu	 *     x3 - pointer to empty console_t struct
130*91f16700Schasinglulu	 * Out: return 1 on success, 0 on error
131*91f16700Schasinglulu	 * Clobber list : x0, x1, x2, x6, x7, x14
132*91f16700Schasinglulu	 * -------------------------------------------------------
133*91f16700Schasinglulu	 */
134*91f16700Schasinglulufunc console_stm32_register
135*91f16700Schasinglulu	mov	x7, x30
136*91f16700Schasinglulu	mov	x6, x3
137*91f16700Schasinglulu	cbz	x6, register_fail
138*91f16700Schasinglulu	str	x0, [x6, #CONSOLE_T_BASE]
139*91f16700Schasinglulu
140*91f16700Schasinglulu	bl	console_stm32_core_init
141*91f16700Schasinglulu	cbz	x0, register_fail
142*91f16700Schasinglulu
143*91f16700Schasinglulu	mov	x0, x6
144*91f16700Schasinglulu	mov	x30, x7
145*91f16700Schasinglulu	finish_console_register stm32 putc=1, getc=0, flush=1
146*91f16700Schasinglulu
147*91f16700Schasingluluregister_fail:
148*91f16700Schasinglulu	ret	x7
149*91f16700Schasingluluendfunc console_stm32_register
150*91f16700Schasinglulu
151*91f16700Schasinglulu	/* --------------------------------------------------------
152*91f16700Schasinglulu	 * int console_stm32_core_putc(int c, uintptr_t base_addr)
153*91f16700Schasinglulu	 * Function to output a character over the console. It
154*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
155*91f16700Schasinglulu	 * In : w0 - character to be printed
156*91f16700Schasinglulu	 *      x1 - console base address
157*91f16700Schasinglulu	 * Out : return -1 on error else return character.
158*91f16700Schasinglulu	 * Clobber list : x2
159*91f16700Schasinglulu	 * --------------------------------------------------------
160*91f16700Schasinglulu	 */
161*91f16700Schasinglulufunc console_stm32_core_putc
162*91f16700Schasinglulu#if ENABLE_ASSERTIONS
163*91f16700Schasinglulu	cmp	x1, #0
164*91f16700Schasinglulu	ASM_ASSERT(ne)
165*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
166*91f16700Schasinglulu
167*91f16700Schasinglulu	/* Check Transmit Data Register Empty */
168*91f16700Schasinglulutxe_loop:
169*91f16700Schasinglulu	ldr	w2, [x1, #USART_ISR]
170*91f16700Schasinglulu	tst	w2, #USART_ISR_TXE
171*91f16700Schasinglulu	beq	txe_loop
172*91f16700Schasinglulu	str	w0, [x1, #USART_TDR]
173*91f16700Schasinglulu	/* Check transmit complete flag */
174*91f16700Schasinglulutc_loop:
175*91f16700Schasinglulu	ldr	w2, [x1, #USART_ISR]
176*91f16700Schasinglulu	tst	w2, #USART_ISR_TC
177*91f16700Schasinglulu	beq	tc_loop
178*91f16700Schasinglulu	ret
179*91f16700Schasingluluendfunc console_stm32_core_putc
180*91f16700Schasinglulu
181*91f16700Schasinglulu	/* --------------------------------------------------------
182*91f16700Schasinglulu	 * int console_stm32_putc(int c, console_t *console)
183*91f16700Schasinglulu	 * Function to output a character over the console. It
184*91f16700Schasinglulu	 * returns the character printed on success or -1 on error.
185*91f16700Schasinglulu	 * In : w0 - character to be printed
186*91f16700Schasinglulu	 *      x1 - pointer to console_t structure
187*91f16700Schasinglulu	 * Out : return -1 on error else return character.
188*91f16700Schasinglulu	 * Clobber list : x2
189*91f16700Schasinglulu	 * --------------------------------------------------------
190*91f16700Schasinglulu	 */
191*91f16700Schasinglulufunc console_stm32_putc
192*91f16700Schasinglulu#if ENABLE_ASSERTIONS
193*91f16700Schasinglulu	cmp	x1, #0
194*91f16700Schasinglulu	ASM_ASSERT(ne)
195*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
196*91f16700Schasinglulu	ldr	x1, [x1, #CONSOLE_T_BASE]
197*91f16700Schasinglulu	b	console_stm32_core_putc
198*91f16700Schasingluluendfunc console_stm32_putc
199*91f16700Schasinglulu
200*91f16700Schasinglulu	/* ---------------------------------------------
201*91f16700Schasinglulu	 * int console_stm32_core_getc(uintptr_t base_addr)
202*91f16700Schasinglulu	 * Function to get a character from the console.
203*91f16700Schasinglulu	 * It returns the character grabbed on success
204*91f16700Schasinglulu	 * or -1 if no character is available.
205*91f16700Schasinglulu	 * In : x0 - console base address
206*91f16700Schasinglulu	 * Out: w0 - character if available, else -1
207*91f16700Schasinglulu	 * Clobber list : x0, x1
208*91f16700Schasinglulu	 * ---------------------------------------------
209*91f16700Schasinglulu	 */
210*91f16700Schasinglulufunc console_stm32_core_getc
211*91f16700Schasinglulu	/* Not supported */
212*91f16700Schasinglulu	mov	w0, #-1
213*91f16700Schasinglulu	ret
214*91f16700Schasingluluendfunc console_stm32_core_getc
215*91f16700Schasinglulu
216*91f16700Schasinglulu	/* ---------------------------------------------
217*91f16700Schasinglulu	 * int console_stm32_core_flush(uintptr_t base_addr)
218*91f16700Schasinglulu	 * Function to force a write of all buffered
219*91f16700Schasinglulu	 * data that hasn't been output.
220*91f16700Schasinglulu	 * In : x0 - console base address
221*91f16700Schasinglulu	 * Out : return -1 on error else return 0.
222*91f16700Schasinglulu	 * Clobber list : x0, x1
223*91f16700Schasinglulu	 * ---------------------------------------------
224*91f16700Schasinglulu	 */
225*91f16700Schasinglulufunc console_stm32_core_flush
226*91f16700Schasinglulu#if ENABLE_ASSERTIONS
227*91f16700Schasinglulu	cmp	x0, #0
228*91f16700Schasinglulu	ASM_ASSERT(ne)
229*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
230*91f16700Schasinglulu	/* Check Transmit Data Register Empty */
231*91f16700Schasinglulutxe_loop_3:
232*91f16700Schasinglulu	ldr	w1, [x0, #USART_ISR]
233*91f16700Schasinglulu	tst	w1, #USART_ISR_TXE
234*91f16700Schasinglulu	beq	txe_loop_3
235*91f16700Schasinglulu	mov	w0, #0
236*91f16700Schasinglulu	ret
237*91f16700Schasingluluendfunc console_stm32_core_flush
238*91f16700Schasinglulu
239*91f16700Schasinglulu	/* ---------------------------------------------
240*91f16700Schasinglulu	 * int console_stm32_flush(console_t *console)
241*91f16700Schasinglulu	 * Function to force a write of all buffered
242*91f16700Schasinglulu	 * data that hasn't been output.
243*91f16700Schasinglulu	 * In : x0 - pointer to console_t structure
244*91f16700Schasinglulu	 * Out : return -1 on error else return 0.
245*91f16700Schasinglulu	 * Clobber list : x0, x1
246*91f16700Schasinglulu	 * ---------------------------------------------
247*91f16700Schasinglulu	 */
248*91f16700Schasinglulufunc console_stm32_flush
249*91f16700Schasinglulu#if ENABLE_ASSERTIONS
250*91f16700Schasinglulu	cmp	x0, #0
251*91f16700Schasinglulu	ASM_ASSERT(ne)
252*91f16700Schasinglulu#endif /* ENABLE_ASSERTIONS */
253*91f16700Schasinglulu	ldr	x0, [x0, #CONSOLE_T_BASE]
254*91f16700Schasinglulu	b	console_stm32_core_flush
255*91f16700Schasingluluendfunc console_stm32_flush
256