1/*
2 * Copyright (c) 2015-2020, 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	 */
32func plat_my_core_pos
33	mrs	x0, mpidr_el1
34	b	plat_rpi3_calc_core_pos
35endfunc plat_my_core_pos
36
37	/* -----------------------------------------------------
38	 *  unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
39	 *
40	 *  CorePos = (ClusterId * 4) + CoreId
41	 * -----------------------------------------------------
42	 */
43func plat_rpi3_calc_core_pos
44	and	x1, x0, #MPIDR_CPU_MASK
45	and	x0, x0, #MPIDR_CLUSTER_MASK
46	add	x0, x1, x0, LSR #6
47	ret
48endfunc plat_rpi3_calc_core_pos
49
50	/* -----------------------------------------------------
51	 * unsigned int plat_is_my_cpu_primary (void);
52	 *
53	 * Find out whether the current cpu is the primary
54	 * cpu.
55	 * -----------------------------------------------------
56	 */
57func plat_is_my_cpu_primary
58	mrs	x0, mpidr_el1
59	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
60	cmp	x0, #RPI_PRIMARY_CPU
61	cset	w0, eq
62	ret
63endfunc plat_is_my_cpu_primary
64
65	/* -----------------------------------------------------
66	 * void plat_wait_for_warm_boot (void);
67	 *
68	 * This function performs any platform specific actions
69	 * needed for a CPU to be put into holding pen to wait
70	 * for a warm boot request.
71	 * The function will never return.
72	 * -----------------------------------------------------
73	 */
74func plat_wait_for_warm_boot
75	/*
76	 * Calculate address of our hold entry.
77	 * As the function will never return, there is no need to save LR.
78	 */
79	bl	plat_my_core_pos
80	lsl	x0, x0, #3
81	mov_imm	x2, PLAT_RPI3_TM_HOLD_BASE
82	add	x0, x0, x2
83	/*
84	 * This code runs way before requesting the warmboot of this core,
85	 * so it is possible to clear the mailbox before getting a request
86	 * to boot.
87	 */
88	mov	x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
89	str	x1,[x0]
90
91	/* Wait until we have a go */
92poll_mailbox:
93	wfe
94	ldr	x1, [x0]
95	cmp	x1, PLAT_RPI3_TM_HOLD_STATE_GO
96	bne	poll_mailbox
97
98	/* Jump to the provided entrypoint */
99	mov_imm	x0, PLAT_RPI3_TM_ENTRYPOINT
100	ldr	x1, [x0]
101	br	x1
102endfunc plat_wait_for_warm_boot
103
104	/* -----------------------------------------------------
105	 * void plat_secondary_cold_boot_setup (void);
106	 *
107	 * This function performs any platform specific actions
108	 * needed for a secondary cpu after a cold reset e.g
109	 * mark the cpu's presence, mechanism to place it in a
110	 * holding pen etc.
111	 * -----------------------------------------------------
112	 */
113func plat_secondary_cold_boot_setup
114	b	plat_wait_for_warm_boot
115endfunc plat_secondary_cold_boot_setup
116
117	/* ---------------------------------------------------------------------
118	 * uintptr_t plat_get_my_entrypoint (void);
119	 *
120	 * Main job of this routine is to distinguish between a cold and a warm
121	 * boot.
122	 *
123	 * This functions returns:
124	 *  - 0 for a cold boot.
125	 *  - Any other value for a warm boot.
126	 * ---------------------------------------------------------------------
127	 */
128func plat_get_my_entrypoint
129	mov	x1, x30
130	bl	plat_is_my_cpu_primary
131	/*
132	 * Secondaries always cold boot.
133	*/
134	cbz	w0, 1f
135	/*
136	 * Primaries warm boot if they are requested
137	 * to power off.
138	 */
139	mov_imm	x0, PLAT_RPI3_TM_HOLD_BASE
140	ldr	x0, [x0]
141	cmp	x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF
142	adr	x0, plat_wait_for_warm_boot
143	csel	x0, x0, xzr, eq
144	ret	x1
1451:	mov	x0, #0
146	ret	x1
147endfunc plat_get_my_entrypoint
148
149	/* ---------------------------------------------
150	 * void platform_mem_init (void);
151	 *
152	 * No need to carry out any memory initialization.
153	 * ---------------------------------------------
154	 */
155func platform_mem_init
156	ret
157endfunc platform_mem_init
158
159	/* ---------------------------------------------
160	 * int plat_crash_console_init(void)
161	 * Function to initialize the crash console
162	 * without a C Runtime to print crash report.
163	 * Clobber list : x0 - x3
164	 * ---------------------------------------------
165	 */
166func plat_crash_console_init
167	mov_imm	x0, PLAT_RPI_MINI_UART_BASE
168	mov	x1, xzr
169	mov	x2, xzr
170	b	console_16550_core_init
171endfunc plat_crash_console_init
172
173	/* ---------------------------------------------
174	 * int plat_crash_console_putc(int c)
175	 * Function to print a character on the crash
176	 * console without a C Runtime.
177	 * Clobber list : x1, x2
178	 * ---------------------------------------------
179	 */
180func plat_crash_console_putc
181	mov_imm	x1, PLAT_RPI_MINI_UART_BASE
182	b	console_16550_core_putc
183endfunc plat_crash_console_putc
184
185	/* ---------------------------------------------
186	 * void plat_crash_console_flush()
187	 * Function to force a write of all buffered
188	 * data that hasn't been output.
189	 * Out : void.
190	 * Clobber list : x0, x1
191	 * ---------------------------------------------
192	 */
193func plat_crash_console_flush
194	mov_imm	x0, PLAT_RPI_MINI_UART_BASE
195	b	console_16550_core_flush
196endfunc plat_crash_console_flush
197
198	/* ---------------------------------------------
199	 * int plat_rpi_get_model()
200	 * Macro to determine whether we are running on
201	 * a Raspberry Pi 3 or 4. Just checks the MIDR for
202	 * being either a Cortex-A72 or a Cortex-A53.
203	 * Out : return 4 if RPi4, 3 otherwise.
204	 * Clobber list : x0
205	 * ---------------------------------------------
206	 */
207	.macro _plat_rpi_get_model
208	mrs	x0, midr_el1
209	and	x0, x0, #0xf0	/* Isolate low byte of part number */
210	cmp	w0, #0x80	/* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */
211	mov	w0, #3
212	csinc	w0, w0, w0, ne
213	.endm
214
215	func plat_rpi_get_model
216	_plat_rpi_get_model
217	ret
218	endfunc plat_rpi_get_model
219
220	/* ---------------------------------------------
221	 * void plat_reset_handler(void);
222	 * ---------------------------------------------
223	 */
224func plat_reset_handler
225	/* L2 cache setup only needed on RPi4 */
226	_plat_rpi_get_model
227	cmp	w0, #4
228	b.ne	1f
229
230	/* ------------------------------------------------
231	 * Set L2 read/write cache latency:
232	 * - L2 Data RAM latency: 3 cycles (0b010)
233	 * - L2 Data RAM setup: 1 cycle (bit 5)
234	 * ------------------------------------------------
235	 */
236	mrs	x0, CORTEX_A72_L2CTLR_EL1
237	mov	x1, #0x22
238	orr	x0, x0, x1
239	msr	CORTEX_A72_L2CTLR_EL1, x0
240	isb
241
2421:
243	ret
244endfunc plat_reset_handler
245