1/*
2 * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <platform_def.h>
8
9#include <arch.h>
10#include <asm_macros.S>
11#include <common/bl_common.h>
12#include <drivers/st/stm32_gpio.h>
13
14#define GPIO_TX_SHIFT		(DEBUG_UART_TX_GPIO_PORT << 1)
15
16	.globl	platform_mem_init
17	.globl	plat_report_exception
18	.globl	plat_report_prefetch_abort
19	.globl	plat_report_data_abort
20	.globl	plat_get_my_entrypoint
21	.globl	plat_secondary_cold_boot_setup
22	.globl	plat_reset_handler
23	.globl	plat_is_my_cpu_primary
24	.globl	plat_my_core_pos
25	.globl	plat_crash_console_init
26	.globl	plat_crash_console_flush
27	.globl	plat_crash_console_putc
28	.globl	plat_panic_handler
29
30func platform_mem_init
31	/* Nothing to do, don't need to init SYSRAM */
32	bx	lr
33endfunc platform_mem_init
34
35#if DEBUG
36func plat_report_exception
37	mov	r8, lr
38
39	/*
40	 * Test if an abort occurred
41	 * In this case the error message has already been displayed
42	 * by dedicated functions
43	 */
44	cmp	r0, #MODE32_abt
45	beq	1f
46
47	/* Test for an undefined instruction */
48	cmp	r0, #MODE32_und
49	bne	other_exception_lbl
50	ldr	r4, =undefined_str
51	bl	asm_print_str
52	mrs	r4, lr_und
53	b	print_exception_info
54
55other_exception_lbl:
56	/* Other exceptions */
57	mov	r9, r0
58	ldr	r4, =exception_start_str
59	bl	asm_print_str
60	mov	r4, r9
61	bl	asm_print_hex
62	ldr	r4, =exception_end_str
63	bl	asm_print_str
64	mov	r4, r6
65
66print_exception_info:
67	bl	asm_print_hex
68
69	ldr	r4, =end_error_str
70	bl	asm_print_str
71
721:
73	bx	r8
74endfunc plat_report_exception
75
76func plat_report_prefetch_abort
77	mov	r8, lr
78	mov	r9, r0
79
80	ldr	r4, =prefetch_abort_str
81	bl	asm_print_str
82
83	mov	r4, r9
84	sub	r4, r4, #4
85	bl	asm_print_hex
86
87	ldr	r4, =ifsr_str
88	bl	asm_print_str
89
90	ldcopr	r4, IFSR
91	bl	asm_print_hex
92
93	ldr	r4, =ifar_str
94	bl	asm_print_str
95
96	ldcopr	r4, IFAR
97	bl	asm_print_hex
98
99	ldr	r4, =end_error_str
100	bl	asm_print_str
101
102	bx	r8
103endfunc plat_report_prefetch_abort
104
105func plat_report_data_abort
106	mov	r8, lr
107	mov	r9, r0
108
109	ldr	r4, =data_abort_str
110	bl	asm_print_str
111
112	mov	r4, r9
113	sub	r4, r4, #8
114	bl	asm_print_hex
115
116	ldr	r4, =dfsr_str
117	bl	asm_print_str
118
119	ldcopr	r4, DFSR
120	bl	asm_print_hex
121
122	ldr	r4, =dfar_str
123	bl	asm_print_str
124
125	ldcopr	r4, DFAR
126	bl	asm_print_hex
127
128	ldr	r4, =end_error_str
129	bl	asm_print_str
130
131	bx	r8
132endfunc plat_report_data_abort
133#endif /* DEBUG */
134
135func plat_reset_handler
136	bx	lr
137endfunc plat_reset_handler
138
139	/* ------------------------------------------------------------------
140	 * unsigned long plat_get_my_entrypoint (void);
141	 *
142	 * Main job of this routine is to distinguish between a cold and warm
143	 * boot.
144	 *
145	 * Currently supports only cold boot
146	 * ------------------------------------------------------------------
147	 */
148func plat_get_my_entrypoint
149	mov	r0, #0
150	bx	lr
151endfunc plat_get_my_entrypoint
152
153	/* ---------------------------------------------
154	 * void plat_secondary_cold_boot_setup (void);
155	 *
156	 * Cold-booting secondary CPUs is not supported.
157	 * ---------------------------------------------
158	 */
159func plat_secondary_cold_boot_setup
160	b	.
161endfunc plat_secondary_cold_boot_setup
162
163	/* -----------------------------------------------------
164	 * unsigned int plat_is_my_cpu_primary (void);
165	 *
166	 * Find out whether the current cpu is the primary cpu.
167	 * -----------------------------------------------------
168	 */
169func plat_is_my_cpu_primary
170	ldcopr	r0, MPIDR
171	ldr	r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
172	and	r0, r1
173	cmp	r0, #STM32MP_PRIMARY_CPU
174	moveq	r0, #1
175	movne	r0, #0
176	bx	lr
177endfunc plat_is_my_cpu_primary
178
179	/* -------------------------------------------
180	 *  int plat_stm32mp1_get_core_pos(int mpidr);
181	 *
182	 *  Return CorePos = (ClusterId * 4) + CoreId
183	 * -------------------------------------------
184	 */
185func plat_stm32mp1_get_core_pos
186	and	r1, r0, #MPIDR_CPU_MASK
187	and	r0, r0, #MPIDR_CLUSTER_MASK
188	add	r0, r1, r0, LSR #6
189	bx	lr
190endfunc plat_stm32mp1_get_core_pos
191
192	/* ------------------------------------
193	 *  unsigned int plat_my_core_pos(void)
194	 * ------------------------------------
195	 */
196func plat_my_core_pos
197	ldcopr	r0, MPIDR
198	b	plat_stm32mp1_get_core_pos
199endfunc plat_my_core_pos
200
201	/* ---------------------------------------------
202	 * int plat_crash_console_init(void)
203	 *
204	 * Initialize the crash console without a C Runtime stack.
205	 * ---------------------------------------------
206	 */
207func plat_crash_console_init
208	/* Reset UART peripheral */
209	ldr	r1, =(RCC_BASE + DEBUG_UART_RST_REG)
210	ldr	r2, =DEBUG_UART_RST_BIT
211	str	r2, [r1]
2121:
213	ldr	r0, [r1]
214	ands	r2, r0, r2
215	beq	1b
216	str	r2, [r1, #4] /* RSTCLR register */
2172:
218	ldr	r0, [r1]
219	ands	r2, r0, r2
220	bne	2b
221	/* Enable GPIOs for UART TX */
222	ldr	r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG)
223	ldr	r2, [r1]
224	/* Configure GPIO */
225	orr	r2, r2, #DEBUG_UART_TX_GPIO_BANK_CLK_EN
226	str	r2, [r1]
227	ldr	r1, =DEBUG_UART_TX_GPIO_BANK_ADDRESS
228	/* Set GPIO mode alternate */
229	ldr	r2, [r1, #GPIO_MODE_OFFSET]
230	bic	r2, r2, #(GPIO_MODE_MASK << GPIO_TX_SHIFT)
231	orr	r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT)
232	str	r2, [r1, #GPIO_MODE_OFFSET]
233	/* Set GPIO speed low */
234	ldr	r2, [r1, #GPIO_SPEED_OFFSET]
235	bic	r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT)
236	str	r2, [r1, #GPIO_SPEED_OFFSET]
237	/* Set no-pull */
238	ldr	r2, [r1, #GPIO_PUPD_OFFSET]
239	bic	r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT)
240	str	r2, [r1, #GPIO_PUPD_OFFSET]
241	/* Set alternate */
242#if DEBUG_UART_TX_GPIO_PORT >= GPIO_ALT_LOWER_LIMIT
243	ldr	r2, [r1, #GPIO_AFRH_OFFSET]
244	bic	r2, r2, #(GPIO_ALTERNATE_MASK << \
245				((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
246	orr	r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << \
247				((DEBUG_UART_TX_GPIO_PORT - GPIO_ALT_LOWER_LIMIT) << 2))
248	str	r2, [r1, #GPIO_AFRH_OFFSET]
249#else
250	ldr	r2, [r1, #GPIO_AFRL_OFFSET]
251	bic	r2, r2, #(GPIO_ALTERNATE_MASK << (DEBUG_UART_TX_GPIO_PORT << 2))
252	orr	r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << (DEBUG_UART_TX_GPIO_PORT << 2))
253	str	r2, [r1, #GPIO_AFRL_OFFSET]
254#endif
255	/* Enable UART clock, with its source */
256	ldr	r1, =(RCC_BASE + DEBUG_UART_TX_CLKSRC_REG)
257	mov	r2, #DEBUG_UART_TX_CLKSRC
258	str	r2, [r1]
259	ldr	r1, =(RCC_BASE + DEBUG_UART_TX_EN_REG)
260	ldr	r2, [r1]
261	orr	r2, r2, #DEBUG_UART_TX_EN
262	str	r2, [r1]
263
264	ldr	r0, =STM32MP_DEBUG_USART_BASE
265	ldr	r1, =STM32MP_DEBUG_USART_CLK_FRQ
266	ldr	r2, =STM32MP_UART_BAUDRATE
267	b	console_stm32_core_init
268endfunc plat_crash_console_init
269
270	/* ---------------------------------------------
271	 * void plat_crash_console_flush(void)
272	 *
273	 * Flush the crash console without a C Runtime stack.
274	 * ---------------------------------------------
275	 */
276func plat_crash_console_flush
277	ldr	r0, =STM32MP_DEBUG_USART_BASE
278	b	console_stm32_core_flush
279endfunc plat_crash_console_flush
280
281	/* ---------------------------------------------
282	 * int plat_crash_console_putc(int c)
283	 *
284	 * Print a character on the crash console without a C Runtime stack.
285	 * Clobber list : r1 - r3
286	 *
287	 * In case of bootloading through uart, we keep console crash as this.
288	 * Characters could be sent to the programmer, but will be ignored.
289	 * No specific code in that case.
290	 * ---------------------------------------------
291	 */
292func plat_crash_console_putc
293	ldr	r1, =STM32MP_DEBUG_USART_BASE
294	b	console_stm32_core_putc
295endfunc plat_crash_console_putc
296
297	/* ----------------------------------------------------------
298	 * void plat_panic_handler(void) __dead2;
299	 * Report exception + endless loop.
300	 *
301	 * r6 holds the address where the fault occurred.
302	 * Filling lr with this value allows debuggers to reconstruct
303	 * the backtrace.
304	 * ----------------------------------------------------------
305	 */
306func plat_panic_handler
307	mrs	r0, cpsr
308	and	r0, #MODE32_MASK
309	bl	plat_report_exception
310	mov	lr, r6
311	b	.
312endfunc plat_panic_handler
313
314#if DEBUG
315.section .rodata.rev_err_str, "aS"
316prefetch_abort_str:
317	.asciz "\nPrefetch Abort at: 0x"
318data_abort_str:
319	.asciz "\nData Abort at: 0x"
320undefined_str:
321	.asciz "\nUndefined instruction at: 0x"
322exception_start_str:
323	.asciz "\nException mode=0x"
324exception_end_str:
325	.asciz " at: 0x"
326dfsr_str:
327	.asciz " DFSR = 0x"
328dfar_str:
329	.asciz " DFAR = 0x"
330ifsr_str:
331	.asciz " IFSR = 0x"
332ifar_str:
333	.asciz " IFAR = 0x"
334end_error_str:
335	.asciz "\n\r"
336#endif
337