1/*
2 * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <asm_macros.S>
9#include <assert_macros.S>
10#include <platform_def.h>
11#include <cortex_a72.h>
12
13	.globl	plat_crash_console_flush
14	.globl	plat_crash_console_init
15	.globl	plat_crash_console_putc
16	.globl	platform_mem_init
17	.globl	plat_get_my_entrypoint
18	.globl	plat_is_my_cpu_primary
19	.globl	plat_my_core_pos
20	.globl	plat_reset_handler
21	.globl	plat_rpi3_calc_core_pos
22	.globl	plat_secondary_cold_boot_setup
23	.globl	plat_rpi_get_model
24
25	/* -----------------------------------------------------
26	 *  unsigned int plat_my_core_pos(void)
27	 *
28	 *  This function uses the plat_rpi3_calc_core_pos()
29	 *  definition to get the index of the calling CPU.
30	 *
31	 *  When MT is set, lowest affinity represents the thread ID.
32	 *  Since we only support one thread per core, discard this field
33	 *  so cluster and core IDs go back into Aff1 and Aff0 respectively.
34	 *  The upper bits are also affected, but plat_rpi3_calc_core_pos()
35	 *  does not use them.
36	 * -----------------------------------------------------
37	 */
38func plat_my_core_pos
39	mrs	x0, mpidr_el1
40	tst	x0, #MPIDR_MT_MASK
41	lsr	x1, x0, #MPIDR_AFFINITY_BITS
42	csel	x0, x1, x0, ne
43	b	plat_rpi3_calc_core_pos
44endfunc plat_my_core_pos
45
46	/* -----------------------------------------------------
47	 *  unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
48	 *
49	 *  CorePos = (ClusterId * 4) + CoreId
50	 * -----------------------------------------------------
51	 */
52func plat_rpi3_calc_core_pos
53	and	x1, x0, #MPIDR_CPU_MASK
54	and	x0, x0, #MPIDR_CLUSTER_MASK
55	add	x0, x1, x0, LSR #6
56	ret
57endfunc plat_rpi3_calc_core_pos
58
59	/* -----------------------------------------------------
60	 * unsigned int plat_is_my_cpu_primary (void);
61	 *
62	 * Find out whether the current cpu is the primary
63	 * cpu.
64	 * -----------------------------------------------------
65	 */
66func plat_is_my_cpu_primary
67	mrs	x0, mpidr_el1
68	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
69	cmp	x0, #RPI_PRIMARY_CPU
70	cset	w0, eq
71	ret
72endfunc plat_is_my_cpu_primary
73
74	/* -----------------------------------------------------
75	 * void plat_wait_for_warm_boot (void);
76	 *
77	 * This function performs any platform specific actions
78	 * needed for a CPU to be put into holding pen to wait
79	 * for a warm boot request.
80	 * The function will never return.
81	 * -----------------------------------------------------
82	 */
83func plat_wait_for_warm_boot
84	/*
85	 * Calculate address of our hold entry.
86	 * As the function will never return, there is no need to save LR.
87	 */
88	bl	plat_my_core_pos
89	lsl	x0, x0, #3
90	mov_imm	x2, PLAT_RPI3_TM_HOLD_BASE
91	add	x0, x0, x2
92	/*
93	 * This code runs way before requesting the warmboot of this core,
94	 * so it is possible to clear the mailbox before getting a request
95	 * to boot.
96	 */
97	mov	x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
98	str	x1,[x0]
99
100	/* Wait until we have a go */
101poll_mailbox:
102	wfe
103	ldr	x1, [x0]
104	cmp	x1, PLAT_RPI3_TM_HOLD_STATE_GO
105	bne	poll_mailbox
106
107	/* Jump to the provided entrypoint */
108	mov_imm	x0, PLAT_RPI3_TM_ENTRYPOINT
109	ldr	x1, [x0]
110	br	x1
111endfunc plat_wait_for_warm_boot
112
113	/* -----------------------------------------------------
114	 * void plat_secondary_cold_boot_setup (void);
115	 *
116	 * This function performs any platform specific actions
117	 * needed for a secondary cpu after a cold reset e.g
118	 * mark the cpu's presence, mechanism to place it in a
119	 * holding pen etc.
120	 * -----------------------------------------------------
121	 */
122func plat_secondary_cold_boot_setup
123	b	plat_wait_for_warm_boot
124endfunc plat_secondary_cold_boot_setup
125
126	/* ---------------------------------------------------------------------
127	 * uintptr_t plat_get_my_entrypoint (void);
128	 *
129	 * Main job of this routine is to distinguish between a cold and a warm
130	 * boot.
131	 *
132	 * This functions returns:
133	 *  - 0 for a cold boot.
134	 *  - Any other value for a warm boot.
135	 * ---------------------------------------------------------------------
136	 */
137func plat_get_my_entrypoint
138	mov	x1, x30
139	bl	plat_is_my_cpu_primary
140	/*
141	 * Secondaries always cold boot.
142	*/
143	cbz	w0, 1f
144	/*
145	 * Primaries warm boot if they are requested
146	 * to power off.
147	 */
148	mov_imm	x0, PLAT_RPI3_TM_HOLD_BASE
149	ldr	x0, [x0]
150	cmp	x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF
151	adr	x0, plat_wait_for_warm_boot
152	csel	x0, x0, xzr, eq
153	ret	x1
1541:	mov	x0, #0
155	ret	x1
156endfunc plat_get_my_entrypoint
157
158	/* ---------------------------------------------
159	 * void platform_mem_init (void);
160	 *
161	 * No need to carry out any memory initialization.
162	 * ---------------------------------------------
163	 */
164func platform_mem_init
165	ret
166endfunc platform_mem_init
167
168	/* ---------------------------------------------
169	 * int plat_crash_console_init(void)
170	 * Function to initialize the crash console
171	 * without a C Runtime to print crash report.
172	 * Clobber list : x0 - x3
173	 * ---------------------------------------------
174	 */
175func plat_crash_console_init
176	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
177#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
178	mov_imm	x1, RPI4_PL011_UART_CLOCK
179	mov_imm	x2, PLAT_RPI_UART_BAUDRATE
180	b	console_pl011_core_init
181#else
182	mov	x1, xzr
183	mov	x2, xzr
184	b	console_16550_core_init
185#endif
186endfunc plat_crash_console_init
187
188	/* ---------------------------------------------
189	 * int plat_crash_console_putc(int c)
190	 * Function to print a character on the crash
191	 * console without a C Runtime.
192	 * Clobber list : x1, x2
193	 * ---------------------------------------------
194	 */
195func plat_crash_console_putc
196	mov_imm	x1, PLAT_RPI_CRASH_UART_BASE
197#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
198	b	console_pl011_core_putc
199#else
200	b	console_16550_core_putc
201#endif
202endfunc plat_crash_console_putc
203
204	/* ---------------------------------------------
205	 * void plat_crash_console_flush()
206	 * Function to force a write of all buffered
207	 * data that hasn't been output.
208	 * Out : void.
209	 * Clobber list : x0, x1
210	 * ---------------------------------------------
211	 */
212func plat_crash_console_flush
213	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
214#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
215	b	console_pl011_core_flush
216#else
217	b	console_16550_core_flush
218#endif
219endfunc plat_crash_console_flush
220
221	/* ---------------------------------------------
222	 * int plat_rpi_get_model()
223	 * Macro to determine whether we are running on
224	 * a Raspberry Pi 3 or 4. Just checks the MIDR for
225	 * being either a Cortex-A72 or a Cortex-A53.
226	 * Out : return 4 if RPi4, 3 otherwise.
227	 * Clobber list : x0
228	 * ---------------------------------------------
229	 */
230	.macro _plat_rpi_get_model
231	mrs	x0, midr_el1
232	and	x0, x0, #0xf0	/* Isolate low byte of part number */
233	cmp	w0, #0x80	/* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */
234	mov	w0, #3
235	csinc	w0, w0, w0, ne
236	.endm
237
238	func plat_rpi_get_model
239	_plat_rpi_get_model
240	ret
241	endfunc plat_rpi_get_model
242
243	/* ---------------------------------------------
244	 * void plat_reset_handler(void);
245	 * ---------------------------------------------
246	 */
247func plat_reset_handler
248	/* L2 cache setup only needed on RPi4 */
249	_plat_rpi_get_model
250	cmp	w0, #4
251	b.ne	1f
252
253	/* ------------------------------------------------
254	 * Set L2 read/write cache latency:
255	 * - L2 Data RAM latency: 3 cycles (0b010)
256	 * - L2 Data RAM setup: 1 cycle (bit 5)
257	 * ------------------------------------------------
258	 */
259	mrs	x0, CORTEX_A72_L2CTLR_EL1
260	mov	x1, #0x22
261	orr	x0, x0, x1
262	msr	CORTEX_A72_L2CTLR_EL1, x0
263	isb
264
2651:
266	ret
267endfunc plat_reset_handler
268