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