xref: /rk3399_ARM-atf/plat/rpi/common/aarch64/plat_helpers.S (revision 5318255f12f88c91846b7261ce12254fb8395557)
107aa0c7eSAndre Przywara/*
2bbf92fe9SMario Bălănică * Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
307aa0c7eSAndre Przywara *
407aa0c7eSAndre Przywara * SPDX-License-Identifier: BSD-3-Clause
507aa0c7eSAndre Przywara */
607aa0c7eSAndre Przywara
707aa0c7eSAndre Przywara#include <arch.h>
807aa0c7eSAndre Przywara#include <asm_macros.S>
907aa0c7eSAndre Przywara#include <assert_macros.S>
1007aa0c7eSAndre Przywara#include <platform_def.h>
1107aa0c7eSAndre Przywara#include <cortex_a72.h>
1207aa0c7eSAndre Przywara
1307aa0c7eSAndre Przywara	.globl	plat_crash_console_flush
1407aa0c7eSAndre Przywara	.globl	plat_crash_console_init
1507aa0c7eSAndre Przywara	.globl	plat_crash_console_putc
1607aa0c7eSAndre Przywara	.globl	platform_mem_init
1707aa0c7eSAndre Przywara	.globl	plat_get_my_entrypoint
1807aa0c7eSAndre Przywara	.globl	plat_is_my_cpu_primary
1907aa0c7eSAndre Przywara	.globl	plat_my_core_pos
2007aa0c7eSAndre Przywara	.globl	plat_reset_handler
2107aa0c7eSAndre Przywara	.globl	plat_rpi3_calc_core_pos
2207aa0c7eSAndre Przywara	.globl	plat_secondary_cold_boot_setup
2307aa0c7eSAndre Przywara	.globl	plat_rpi_get_model
2407aa0c7eSAndre Przywara
2507aa0c7eSAndre Przywara	/* -----------------------------------------------------
2607aa0c7eSAndre Przywara	 *  unsigned int plat_my_core_pos(void)
2707aa0c7eSAndre Przywara	 *
2807aa0c7eSAndre Przywara	 *  This function uses the plat_rpi3_calc_core_pos()
2907aa0c7eSAndre Przywara	 *  definition to get the index of the calling CPU.
30*6744d07dSMario Bălănică	 *
31*6744d07dSMario Bălănică	 *  When MT is set, lowest affinity represents the thread ID.
32*6744d07dSMario Bălănică	 *  Since we only support one thread per core, discard this field
33*6744d07dSMario Bălănică	 *  so cluster and core IDs go back into Aff1 and Aff0 respectively.
34*6744d07dSMario Bălănică	 *  The upper bits are also affected, but plat_rpi3_calc_core_pos()
35*6744d07dSMario Bălănică	 *  does not use them.
3607aa0c7eSAndre Przywara	 * -----------------------------------------------------
3707aa0c7eSAndre Przywara	 */
3807aa0c7eSAndre Przywarafunc plat_my_core_pos
3907aa0c7eSAndre Przywara	mrs	x0, mpidr_el1
40*6744d07dSMario Bălănică	tst	x0, #MPIDR_MT_MASK
41*6744d07dSMario Bălănică	lsr	x1, x0, #MPIDR_AFFINITY_BITS
42*6744d07dSMario Bălănică	csel	x0, x1, x0, ne
4307aa0c7eSAndre Przywara	b	plat_rpi3_calc_core_pos
4407aa0c7eSAndre Przywaraendfunc plat_my_core_pos
4507aa0c7eSAndre Przywara
4607aa0c7eSAndre Przywara	/* -----------------------------------------------------
4707aa0c7eSAndre Przywara	 *  unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
4807aa0c7eSAndre Przywara	 *
4907aa0c7eSAndre Przywara	 *  CorePos = (ClusterId * 4) + CoreId
5007aa0c7eSAndre Przywara	 * -----------------------------------------------------
5107aa0c7eSAndre Przywara	 */
5207aa0c7eSAndre Przywarafunc plat_rpi3_calc_core_pos
5307aa0c7eSAndre Przywara	and	x1, x0, #MPIDR_CPU_MASK
5407aa0c7eSAndre Przywara	and	x0, x0, #MPIDR_CLUSTER_MASK
5507aa0c7eSAndre Przywara	add	x0, x1, x0, LSR #6
5607aa0c7eSAndre Przywara	ret
5707aa0c7eSAndre Przywaraendfunc plat_rpi3_calc_core_pos
5807aa0c7eSAndre Przywara
5907aa0c7eSAndre Przywara	/* -----------------------------------------------------
6007aa0c7eSAndre Przywara	 * unsigned int plat_is_my_cpu_primary (void);
6107aa0c7eSAndre Przywara	 *
6207aa0c7eSAndre Przywara	 * Find out whether the current cpu is the primary
6307aa0c7eSAndre Przywara	 * cpu.
6407aa0c7eSAndre Przywara	 * -----------------------------------------------------
6507aa0c7eSAndre Przywara	 */
6607aa0c7eSAndre Przywarafunc plat_is_my_cpu_primary
6707aa0c7eSAndre Przywara	mrs	x0, mpidr_el1
6807aa0c7eSAndre Przywara	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
6907aa0c7eSAndre Przywara	cmp	x0, #RPI_PRIMARY_CPU
7007aa0c7eSAndre Przywara	cset	w0, eq
7107aa0c7eSAndre Przywara	ret
7207aa0c7eSAndre Przywaraendfunc plat_is_my_cpu_primary
7307aa0c7eSAndre Przywara
7407aa0c7eSAndre Przywara	/* -----------------------------------------------------
752e5f8443SAndrei Warkentin	 * void plat_wait_for_warm_boot (void);
7607aa0c7eSAndre Przywara	 *
7707aa0c7eSAndre Przywara	 * This function performs any platform specific actions
782e5f8443SAndrei Warkentin	 * needed for a CPU to be put into holding pen to wait
792e5f8443SAndrei Warkentin	 * for a warm boot request.
802e5f8443SAndrei Warkentin	 * The function will never return.
8107aa0c7eSAndre Przywara	 * -----------------------------------------------------
8207aa0c7eSAndre Przywara	 */
832e5f8443SAndrei Warkentinfunc plat_wait_for_warm_boot
842e5f8443SAndrei Warkentin	/*
852e5f8443SAndrei Warkentin	 * Calculate address of our hold entry.
862e5f8443SAndrei Warkentin	 * As the function will never return, there is no need to save LR.
872e5f8443SAndrei Warkentin	 */
8807aa0c7eSAndre Przywara	bl	plat_my_core_pos
8907aa0c7eSAndre Przywara	lsl	x0, x0, #3
9007aa0c7eSAndre Przywara	mov_imm	x2, PLAT_RPI3_TM_HOLD_BASE
9107aa0c7eSAndre Przywara	add	x0, x0, x2
9207aa0c7eSAndre Przywara	/*
9307aa0c7eSAndre Przywara	 * This code runs way before requesting the warmboot of this core,
9407aa0c7eSAndre Przywara	 * so it is possible to clear the mailbox before getting a request
9507aa0c7eSAndre Przywara	 * to boot.
9607aa0c7eSAndre Przywara	 */
9707aa0c7eSAndre Przywara	mov	x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
9807aa0c7eSAndre Przywara	str	x1,[x0]
9907aa0c7eSAndre Przywara
10007aa0c7eSAndre Przywara	/* Wait until we have a go */
10107aa0c7eSAndre Przywarapoll_mailbox:
10207aa0c7eSAndre Przywara	wfe
10307aa0c7eSAndre Przywara	ldr	x1, [x0]
10407aa0c7eSAndre Przywara	cmp	x1, PLAT_RPI3_TM_HOLD_STATE_GO
10507aa0c7eSAndre Przywara	bne	poll_mailbox
10607aa0c7eSAndre Przywara
10707aa0c7eSAndre Przywara	/* Jump to the provided entrypoint */
10807aa0c7eSAndre Przywara	mov_imm	x0, PLAT_RPI3_TM_ENTRYPOINT
10907aa0c7eSAndre Przywara	ldr	x1, [x0]
11007aa0c7eSAndre Przywara	br	x1
1112e5f8443SAndrei Warkentinendfunc plat_wait_for_warm_boot
1122e5f8443SAndrei Warkentin
1132e5f8443SAndrei Warkentin	/* -----------------------------------------------------
1142e5f8443SAndrei Warkentin	 * void plat_secondary_cold_boot_setup (void);
1152e5f8443SAndrei Warkentin	 *
1162e5f8443SAndrei Warkentin	 * This function performs any platform specific actions
1172e5f8443SAndrei Warkentin	 * needed for a secondary cpu after a cold reset e.g
1182e5f8443SAndrei Warkentin	 * mark the cpu's presence, mechanism to place it in a
1192e5f8443SAndrei Warkentin	 * holding pen etc.
1202e5f8443SAndrei Warkentin	 * -----------------------------------------------------
1212e5f8443SAndrei Warkentin	 */
1222e5f8443SAndrei Warkentinfunc plat_secondary_cold_boot_setup
1232e5f8443SAndrei Warkentin	b	plat_wait_for_warm_boot
12407aa0c7eSAndre Przywaraendfunc plat_secondary_cold_boot_setup
12507aa0c7eSAndre Przywara
12607aa0c7eSAndre Przywara	/* ---------------------------------------------------------------------
12707aa0c7eSAndre Przywara	 * uintptr_t plat_get_my_entrypoint (void);
12807aa0c7eSAndre Przywara	 *
12907aa0c7eSAndre Przywara	 * Main job of this routine is to distinguish between a cold and a warm
13007aa0c7eSAndre Przywara	 * boot.
13107aa0c7eSAndre Przywara	 *
13207aa0c7eSAndre Przywara	 * This functions returns:
13307aa0c7eSAndre Przywara	 *  - 0 for a cold boot.
13407aa0c7eSAndre Przywara	 *  - Any other value for a warm boot.
13507aa0c7eSAndre Przywara	 * ---------------------------------------------------------------------
13607aa0c7eSAndre Przywara	 */
13707aa0c7eSAndre Przywarafunc plat_get_my_entrypoint
1382e5f8443SAndrei Warkentin	mov	x1, x30
1392e5f8443SAndrei Warkentin	bl	plat_is_my_cpu_primary
1402e5f8443SAndrei Warkentin	/*
1412e5f8443SAndrei Warkentin	 * Secondaries always cold boot.
1422e5f8443SAndrei Warkentin	*/
1432e5f8443SAndrei Warkentin	cbz	w0, 1f
1442e5f8443SAndrei Warkentin	/*
1452e5f8443SAndrei Warkentin	 * Primaries warm boot if they are requested
1462e5f8443SAndrei Warkentin	 * to power off.
1472e5f8443SAndrei Warkentin	 */
1482e5f8443SAndrei Warkentin	mov_imm	x0, PLAT_RPI3_TM_HOLD_BASE
1492e5f8443SAndrei Warkentin	ldr	x0, [x0]
1502e5f8443SAndrei Warkentin	cmp	x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF
1512e5f8443SAndrei Warkentin	adr	x0, plat_wait_for_warm_boot
1522e5f8443SAndrei Warkentin	csel	x0, x0, xzr, eq
1532e5f8443SAndrei Warkentin	ret	x1
1542e5f8443SAndrei Warkentin1:	mov	x0, #0
1552e5f8443SAndrei Warkentin	ret	x1
15607aa0c7eSAndre Przywaraendfunc plat_get_my_entrypoint
15707aa0c7eSAndre Przywara
15807aa0c7eSAndre Przywara	/* ---------------------------------------------
15907aa0c7eSAndre Przywara	 * void platform_mem_init (void);
16007aa0c7eSAndre Przywara	 *
16107aa0c7eSAndre Przywara	 * No need to carry out any memory initialization.
16207aa0c7eSAndre Przywara	 * ---------------------------------------------
16307aa0c7eSAndre Przywara	 */
16407aa0c7eSAndre Przywarafunc platform_mem_init
16507aa0c7eSAndre Przywara	ret
16607aa0c7eSAndre Przywaraendfunc platform_mem_init
16707aa0c7eSAndre Przywara
16807aa0c7eSAndre Przywara	/* ---------------------------------------------
16907aa0c7eSAndre Przywara	 * int plat_crash_console_init(void)
17007aa0c7eSAndre Przywara	 * Function to initialize the crash console
17107aa0c7eSAndre Przywara	 * without a C Runtime to print crash report.
17207aa0c7eSAndre Przywara	 * Clobber list : x0 - x3
17307aa0c7eSAndre Przywara	 * ---------------------------------------------
17407aa0c7eSAndre Przywara	 */
17507aa0c7eSAndre Przywarafunc plat_crash_console_init
176bbf92fe9SMario Bălănică	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
177bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
178bbf92fe9SMario Bălănică	mov_imm	x1, RPI4_PL011_UART_CLOCK
179bbf92fe9SMario Bălănică	mov_imm	x2, PLAT_RPI_UART_BAUDRATE
180bbf92fe9SMario Bălănică	b	console_pl011_core_init
181bbf92fe9SMario Bălănică#else
18207aa0c7eSAndre Przywara	mov	x1, xzr
18307aa0c7eSAndre Przywara	mov	x2, xzr
18407aa0c7eSAndre Przywara	b	console_16550_core_init
185bbf92fe9SMario Bălănică#endif
18607aa0c7eSAndre Przywaraendfunc plat_crash_console_init
18707aa0c7eSAndre Przywara
18807aa0c7eSAndre Przywara	/* ---------------------------------------------
18907aa0c7eSAndre Przywara	 * int plat_crash_console_putc(int c)
19007aa0c7eSAndre Przywara	 * Function to print a character on the crash
19107aa0c7eSAndre Przywara	 * console without a C Runtime.
19207aa0c7eSAndre Przywara	 * Clobber list : x1, x2
19307aa0c7eSAndre Przywara	 * ---------------------------------------------
19407aa0c7eSAndre Przywara	 */
19507aa0c7eSAndre Przywarafunc plat_crash_console_putc
196bbf92fe9SMario Bălănică	mov_imm	x1, PLAT_RPI_CRASH_UART_BASE
197bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
198bbf92fe9SMario Bălănică	b	console_pl011_core_putc
199bbf92fe9SMario Bălănică#else
20007aa0c7eSAndre Przywara	b	console_16550_core_putc
201bbf92fe9SMario Bălănică#endif
20207aa0c7eSAndre Przywaraendfunc plat_crash_console_putc
20307aa0c7eSAndre Przywara
20407aa0c7eSAndre Przywara	/* ---------------------------------------------
205831b0e98SJimmy Brisson	 * void plat_crash_console_flush()
20607aa0c7eSAndre Przywara	 * Function to force a write of all buffered
20707aa0c7eSAndre Przywara	 * data that hasn't been output.
208831b0e98SJimmy Brisson	 * Out : void.
20907aa0c7eSAndre Przywara	 * Clobber list : x0, x1
21007aa0c7eSAndre Przywara	 * ---------------------------------------------
21107aa0c7eSAndre Przywara	 */
21207aa0c7eSAndre Przywarafunc plat_crash_console_flush
213bbf92fe9SMario Bălănică	mov_imm	x0, PLAT_RPI_CRASH_UART_BASE
214bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE
215bbf92fe9SMario Bălănică	b	console_pl011_core_flush
216bbf92fe9SMario Bălănică#else
21707aa0c7eSAndre Przywara	b	console_16550_core_flush
218bbf92fe9SMario Bălănică#endif
21907aa0c7eSAndre Przywaraendfunc plat_crash_console_flush
22007aa0c7eSAndre Przywara
22107aa0c7eSAndre Przywara	/* ---------------------------------------------
22207aa0c7eSAndre Przywara	 * int plat_rpi_get_model()
22307aa0c7eSAndre Przywara	 * Macro to determine whether we are running on
22407aa0c7eSAndre Przywara	 * a Raspberry Pi 3 or 4. Just checks the MIDR for
22507aa0c7eSAndre Przywara	 * being either a Cortex-A72 or a Cortex-A53.
22607aa0c7eSAndre Przywara	 * Out : return 4 if RPi4, 3 otherwise.
22707aa0c7eSAndre Przywara	 * Clobber list : x0
22807aa0c7eSAndre Przywara	 * ---------------------------------------------
22907aa0c7eSAndre Przywara	 */
23007aa0c7eSAndre Przywara	.macro _plat_rpi_get_model
23107aa0c7eSAndre Przywara	mrs	x0, midr_el1
23207aa0c7eSAndre Przywara	and	x0, x0, #0xf0	/* Isolate low byte of part number */
23307aa0c7eSAndre Przywara	cmp	w0, #0x80	/* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */
23407aa0c7eSAndre Przywara	mov	w0, #3
23507aa0c7eSAndre Przywara	csinc	w0, w0, w0, ne
23607aa0c7eSAndre Przywara	.endm
23707aa0c7eSAndre Przywara
23807aa0c7eSAndre Przywara	func plat_rpi_get_model
23907aa0c7eSAndre Przywara	_plat_rpi_get_model
24007aa0c7eSAndre Przywara	ret
24107aa0c7eSAndre Przywara	endfunc plat_rpi_get_model
24207aa0c7eSAndre Przywara
24307aa0c7eSAndre Przywara	/* ---------------------------------------------
24407aa0c7eSAndre Przywara	 * void plat_reset_handler(void);
24507aa0c7eSAndre Przywara	 * ---------------------------------------------
24607aa0c7eSAndre Przywara	 */
24707aa0c7eSAndre Przywarafunc plat_reset_handler
24807aa0c7eSAndre Przywara	/* L2 cache setup only needed on RPi4 */
24907aa0c7eSAndre Przywara	_plat_rpi_get_model
25007aa0c7eSAndre Przywara	cmp	w0, #4
25107aa0c7eSAndre Przywara	b.ne	1f
25207aa0c7eSAndre Przywara
25307aa0c7eSAndre Przywara	/* ------------------------------------------------
25407aa0c7eSAndre Przywara	 * Set L2 read/write cache latency:
25507aa0c7eSAndre Przywara	 * - L2 Data RAM latency: 3 cycles (0b010)
25607aa0c7eSAndre Przywara	 * - L2 Data RAM setup: 1 cycle (bit 5)
25707aa0c7eSAndre Przywara	 * ------------------------------------------------
25807aa0c7eSAndre Przywara	 */
25907aa0c7eSAndre Przywara	mrs	x0, CORTEX_A72_L2CTLR_EL1
26007aa0c7eSAndre Przywara	mov	x1, #0x22
26107aa0c7eSAndre Przywara	orr	x0, x0, x1
26207aa0c7eSAndre Przywara	msr	CORTEX_A72_L2CTLR_EL1, x0
26307aa0c7eSAndre Przywara	isb
26407aa0c7eSAndre Przywara
26507aa0c7eSAndre Przywara1:
26607aa0c7eSAndre Przywara	ret
26707aa0c7eSAndre Przywaraendfunc plat_reset_handler
268