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