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