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