1/*
2 * Copyright (c) 2018-2021, 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	/* Skip UART initialization if it is already enabled */
50	ldr	r3, [r0, #USART_CR1]
51	ands	r3, r3, #USART_CR1_UE
52	bne	1f
53#endif /* IMAGE_BL2 */
54	/* Check baud rate and uart clock for sanity */
55	cmp	r1, #0
56	beq	core_init_fail
57	cmp	r2, #0
58	beq	core_init_fail
59	/* Disable UART */
60	ldr	r3, [r0, #USART_CR1]
61	bic	r3, r3, #USART_CR1_UE
62	str	r3, [r0, #USART_CR1]
63	/* Configure UART */
64	orr	r3, r3, #(USART_CR1_TE | USART_CR1_FIFOEN)
65	str	r3, [r0, #USART_CR1]
66	ldr	r3, [r0, #USART_CR2]
67	bic	r3, r3, #USART_CR2_STOP
68	str	r3, [r0, #USART_CR2]
69	/* Divisor =  (Uart clock + (baudrate / 2)) / baudrate */
70	lsl	r3, r2, #1
71	add	r3, r1, r3
72	udiv	r3, r3, r2
73	str	r3, [r0, #USART_BRR]
74	/* Enable UART */
75	ldr	r3, [r0, #USART_CR1]
76	orr	r3, r3, #USART_CR1_UE
77	str	r3, [r0, #USART_CR1]
78	/* Check TEACK bit */
79	mov	r2, #USART_TIMEOUT
80teack_loop:
81	subs	r2, r2, #1
82	beq	core_init_fail
83	ldr	r3, [r0, #USART_ISR]
84	tst	r3, #USART_ISR_TEACK
85	beq	teack_loop
861:
87	mov	r0, #1
88	bx	lr
89core_init_fail:
90	mov	r0, #0
91	bx	lr
92endfunc console_stm32_core_init
93
94	.globl console_stm32_register
95
96	/* -------------------------------------------------------
97	 * int console_stm32_register(uintptr_t baseaddr,
98	 *     uint32_t clock, uint32_t baud,
99	 *     console_t *console);
100	 * Function to initialize and register a new STM32
101	 * console. Storage passed in for the console struct
102	 * *must* be persistent (i.e. not from the stack).
103	 * In: r0 - UART register base address
104	 *     r1 - UART clock in Hz
105	 *     r2 - Baud rate
106	 *     r3 - pointer to empty console_t struct
107	 * Out: return 1 on success, 0 on error
108	 * Clobber list : r0, r1, r2
109	 * -------------------------------------------------------
110	 */
111func console_stm32_register
112	push	{r4, lr}
113	mov	r4, r3
114	cmp	r4, #0
115	beq	register_fail
116	str	r0, [r4, #CONSOLE_T_BASE]
117
118	bl console_stm32_core_init
119	cmp	r0, #0
120	beq	register_fail
121
122	mov	r0, r4
123	pop	{r4, lr}
124	finish_console_register stm32 putc=1, getc=0, flush=1
125
126register_fail:
127	pop	{r4, pc}
128endfunc console_stm32_register
129
130	/* ---------------------------------------------------------------
131	 * int console_core_putc(int c, uintptr_t base_addr)
132	 *
133	 * Function to output a character over the console. It returns the
134	 * character printed on success or -1 on error.
135	 *
136	 * In : r0 - character to be printed
137	 *      r1 - console base address
138	 * Out : return -1 on error else return character.
139	 * Clobber list : r2
140	 * ---------------------------------------------------------------
141	 */
142func console_stm32_core_putc
143	/* Check the input parameter */
144	cmp	r1, #0
145	beq	putc_error
146
147	/* Check Transmit Data Register Empty */
148txe_loop:
149	ldr	r2, [r1, #USART_ISR]
150	tst	r2, #USART_ISR_TXE
151	beq	txe_loop
152	str	r0, [r1, #USART_TDR]
153	/* Check transmit complete flag */
154tc_loop:
155	ldr	r2, [r1, #USART_ISR]
156	tst	r2, #USART_ISR_TC
157	beq	tc_loop
158	bx	lr
159putc_error:
160	mov	r0, #-1
161	bx	lr
162endfunc console_stm32_core_putc
163
164	/* ------------------------------------------------------------
165	 * int console_stm32_putc(int c, console_t *console)
166	 * Function to output a character over the console. It
167	 * returns the character printed on success or -1 on error.
168	 * In: r0 - character to be printed
169	 *     r1 - pointer to console_t structure
170	 * Out : return -1 on error else return character.
171	 * Clobber list: r2
172	 * ------------------------------------------------------------
173	 */
174func console_stm32_putc
175#if ENABLE_ASSERTIONS
176	cmp	r1, #0
177	ASM_ASSERT(ne)
178#endif /* ENABLE_ASSERTIONS */
179	ldr	r1, [r1, #CONSOLE_T_BASE]
180	b	console_stm32_core_putc
181endfunc console_stm32_putc
182
183	/* -----------------------------------------------------------
184	 * int console_core_getc(uintptr_t base_addr)
185	 *
186	 * Function to get a character from the console.
187	 * It returns the character grabbed on success or -1 on error.
188	 *
189	 * In : r0 - console base address
190	 * Out : return -1.
191	 * Clobber list : r0, r1
192	 * -----------------------------------------------------------
193	 */
194func console_stm32_core_getc
195	/* Not supported */
196	mov	r0, #-1
197	bx	lr
198endfunc console_stm32_core_getc
199
200	/* ---------------------------------------------------------------
201	 * void console_core_flush(uintptr_t base_addr)
202	 *
203	 * Function to force a write of all buffered data that hasn't been
204	 * output.
205	 *
206	 * In : r0 - console base address
207	 * Out : void.
208	 * Clobber list : r0, r1
209	 * ---------------------------------------------------------------
210	 */
211func console_stm32_core_flush
212#if ENABLE_ASSERTIONS
213	cmp	r0, #0
214	ASM_ASSERT(ne)
215#endif /* ENABLE_ASSERTIONS */
216	/* Check Transmit Data Register Empty */
217txe_loop_3:
218	ldr	r1, [r0, #USART_ISR]
219	tst	r1, #USART_ISR_TXE
220	beq	txe_loop_3
221	bx	lr
222endfunc console_stm32_core_flush
223
224	/* ------------------------------------------------------
225	 * void console_stm32_flush(console_t *console)
226	 * Function to force a write of all buffered
227	 * data that hasn't been output.
228	 * In : r0 - pointer to console_t structure
229	 * Out : void.
230	 * Clobber list: r0, r1
231	 * ------------------------------------------------------
232	 */
233func console_stm32_flush
234#if ENABLE_ASSERTIONS
235	cmp	r0, #0
236	ASM_ASSERT(ne)
237#endif /* ENABLE_ASSERTIONS */
238	ldr	r0, [r0, #CONSOLE_T_BASE]
239	b	console_stm32_core_flush
240endfunc console_stm32_flush
241