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