107aa0c7eSAndre Przywara/* 2*bbf92fe9SMario 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. 3007aa0c7eSAndre Przywara * ----------------------------------------------------- 3107aa0c7eSAndre Przywara */ 3207aa0c7eSAndre Przywarafunc plat_my_core_pos 3307aa0c7eSAndre Przywara mrs x0, mpidr_el1 3407aa0c7eSAndre Przywara b plat_rpi3_calc_core_pos 3507aa0c7eSAndre Przywaraendfunc plat_my_core_pos 3607aa0c7eSAndre Przywara 3707aa0c7eSAndre Przywara /* ----------------------------------------------------- 3807aa0c7eSAndre Przywara * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); 3907aa0c7eSAndre Przywara * 4007aa0c7eSAndre Przywara * CorePos = (ClusterId * 4) + CoreId 4107aa0c7eSAndre Przywara * ----------------------------------------------------- 4207aa0c7eSAndre Przywara */ 4307aa0c7eSAndre Przywarafunc plat_rpi3_calc_core_pos 4407aa0c7eSAndre Przywara and x1, x0, #MPIDR_CPU_MASK 4507aa0c7eSAndre Przywara and x0, x0, #MPIDR_CLUSTER_MASK 4607aa0c7eSAndre Przywara add x0, x1, x0, LSR #6 4707aa0c7eSAndre Przywara ret 4807aa0c7eSAndre Przywaraendfunc plat_rpi3_calc_core_pos 4907aa0c7eSAndre Przywara 5007aa0c7eSAndre Przywara /* ----------------------------------------------------- 5107aa0c7eSAndre Przywara * unsigned int plat_is_my_cpu_primary (void); 5207aa0c7eSAndre Przywara * 5307aa0c7eSAndre Przywara * Find out whether the current cpu is the primary 5407aa0c7eSAndre Przywara * cpu. 5507aa0c7eSAndre Przywara * ----------------------------------------------------- 5607aa0c7eSAndre Przywara */ 5707aa0c7eSAndre Przywarafunc plat_is_my_cpu_primary 5807aa0c7eSAndre Przywara mrs x0, mpidr_el1 5907aa0c7eSAndre Przywara and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) 6007aa0c7eSAndre Przywara cmp x0, #RPI_PRIMARY_CPU 6107aa0c7eSAndre Przywara cset w0, eq 6207aa0c7eSAndre Przywara ret 6307aa0c7eSAndre Przywaraendfunc plat_is_my_cpu_primary 6407aa0c7eSAndre Przywara 6507aa0c7eSAndre Przywara /* ----------------------------------------------------- 662e5f8443SAndrei Warkentin * void plat_wait_for_warm_boot (void); 6707aa0c7eSAndre Przywara * 6807aa0c7eSAndre Przywara * This function performs any platform specific actions 692e5f8443SAndrei Warkentin * needed for a CPU to be put into holding pen to wait 702e5f8443SAndrei Warkentin * for a warm boot request. 712e5f8443SAndrei Warkentin * The function will never return. 7207aa0c7eSAndre Przywara * ----------------------------------------------------- 7307aa0c7eSAndre Przywara */ 742e5f8443SAndrei Warkentinfunc plat_wait_for_warm_boot 752e5f8443SAndrei Warkentin /* 762e5f8443SAndrei Warkentin * Calculate address of our hold entry. 772e5f8443SAndrei Warkentin * As the function will never return, there is no need to save LR. 782e5f8443SAndrei Warkentin */ 7907aa0c7eSAndre Przywara bl plat_my_core_pos 8007aa0c7eSAndre Przywara lsl x0, x0, #3 8107aa0c7eSAndre Przywara mov_imm x2, PLAT_RPI3_TM_HOLD_BASE 8207aa0c7eSAndre Przywara add x0, x0, x2 8307aa0c7eSAndre Przywara /* 8407aa0c7eSAndre Przywara * This code runs way before requesting the warmboot of this core, 8507aa0c7eSAndre Przywara * so it is possible to clear the mailbox before getting a request 8607aa0c7eSAndre Przywara * to boot. 8707aa0c7eSAndre Przywara */ 8807aa0c7eSAndre Przywara mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT 8907aa0c7eSAndre Przywara str x1,[x0] 9007aa0c7eSAndre Przywara 9107aa0c7eSAndre Przywara /* Wait until we have a go */ 9207aa0c7eSAndre Przywarapoll_mailbox: 9307aa0c7eSAndre Przywara wfe 9407aa0c7eSAndre Przywara ldr x1, [x0] 9507aa0c7eSAndre Przywara cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO 9607aa0c7eSAndre Przywara bne poll_mailbox 9707aa0c7eSAndre Przywara 9807aa0c7eSAndre Przywara /* Jump to the provided entrypoint */ 9907aa0c7eSAndre Przywara mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT 10007aa0c7eSAndre Przywara ldr x1, [x0] 10107aa0c7eSAndre Przywara br x1 1022e5f8443SAndrei Warkentinendfunc plat_wait_for_warm_boot 1032e5f8443SAndrei Warkentin 1042e5f8443SAndrei Warkentin /* ----------------------------------------------------- 1052e5f8443SAndrei Warkentin * void plat_secondary_cold_boot_setup (void); 1062e5f8443SAndrei Warkentin * 1072e5f8443SAndrei Warkentin * This function performs any platform specific actions 1082e5f8443SAndrei Warkentin * needed for a secondary cpu after a cold reset e.g 1092e5f8443SAndrei Warkentin * mark the cpu's presence, mechanism to place it in a 1102e5f8443SAndrei Warkentin * holding pen etc. 1112e5f8443SAndrei Warkentin * ----------------------------------------------------- 1122e5f8443SAndrei Warkentin */ 1132e5f8443SAndrei Warkentinfunc plat_secondary_cold_boot_setup 1142e5f8443SAndrei Warkentin b plat_wait_for_warm_boot 11507aa0c7eSAndre Przywaraendfunc plat_secondary_cold_boot_setup 11607aa0c7eSAndre Przywara 11707aa0c7eSAndre Przywara /* --------------------------------------------------------------------- 11807aa0c7eSAndre Przywara * uintptr_t plat_get_my_entrypoint (void); 11907aa0c7eSAndre Przywara * 12007aa0c7eSAndre Przywara * Main job of this routine is to distinguish between a cold and a warm 12107aa0c7eSAndre Przywara * boot. 12207aa0c7eSAndre Przywara * 12307aa0c7eSAndre Przywara * This functions returns: 12407aa0c7eSAndre Przywara * - 0 for a cold boot. 12507aa0c7eSAndre Przywara * - Any other value for a warm boot. 12607aa0c7eSAndre Przywara * --------------------------------------------------------------------- 12707aa0c7eSAndre Przywara */ 12807aa0c7eSAndre Przywarafunc plat_get_my_entrypoint 1292e5f8443SAndrei Warkentin mov x1, x30 1302e5f8443SAndrei Warkentin bl plat_is_my_cpu_primary 1312e5f8443SAndrei Warkentin /* 1322e5f8443SAndrei Warkentin * Secondaries always cold boot. 1332e5f8443SAndrei Warkentin */ 1342e5f8443SAndrei Warkentin cbz w0, 1f 1352e5f8443SAndrei Warkentin /* 1362e5f8443SAndrei Warkentin * Primaries warm boot if they are requested 1372e5f8443SAndrei Warkentin * to power off. 1382e5f8443SAndrei Warkentin */ 1392e5f8443SAndrei Warkentin mov_imm x0, PLAT_RPI3_TM_HOLD_BASE 1402e5f8443SAndrei Warkentin ldr x0, [x0] 1412e5f8443SAndrei Warkentin cmp x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF 1422e5f8443SAndrei Warkentin adr x0, plat_wait_for_warm_boot 1432e5f8443SAndrei Warkentin csel x0, x0, xzr, eq 1442e5f8443SAndrei Warkentin ret x1 1452e5f8443SAndrei Warkentin1: mov x0, #0 1462e5f8443SAndrei Warkentin ret x1 14707aa0c7eSAndre Przywaraendfunc plat_get_my_entrypoint 14807aa0c7eSAndre Przywara 14907aa0c7eSAndre Przywara /* --------------------------------------------- 15007aa0c7eSAndre Przywara * void platform_mem_init (void); 15107aa0c7eSAndre Przywara * 15207aa0c7eSAndre Przywara * No need to carry out any memory initialization. 15307aa0c7eSAndre Przywara * --------------------------------------------- 15407aa0c7eSAndre Przywara */ 15507aa0c7eSAndre Przywarafunc platform_mem_init 15607aa0c7eSAndre Przywara ret 15707aa0c7eSAndre Przywaraendfunc platform_mem_init 15807aa0c7eSAndre Przywara 15907aa0c7eSAndre Przywara /* --------------------------------------------- 16007aa0c7eSAndre Przywara * int plat_crash_console_init(void) 16107aa0c7eSAndre Przywara * Function to initialize the crash console 16207aa0c7eSAndre Przywara * without a C Runtime to print crash report. 16307aa0c7eSAndre Przywara * Clobber list : x0 - x3 16407aa0c7eSAndre Przywara * --------------------------------------------- 16507aa0c7eSAndre Przywara */ 16607aa0c7eSAndre Przywarafunc plat_crash_console_init 167*bbf92fe9SMario Bălănică mov_imm x0, PLAT_RPI_CRASH_UART_BASE 168*bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE 169*bbf92fe9SMario Bălănică mov_imm x1, RPI4_PL011_UART_CLOCK 170*bbf92fe9SMario Bălănică mov_imm x2, PLAT_RPI_UART_BAUDRATE 171*bbf92fe9SMario Bălănică b console_pl011_core_init 172*bbf92fe9SMario Bălănică#else 17307aa0c7eSAndre Przywara mov x1, xzr 17407aa0c7eSAndre Przywara mov x2, xzr 17507aa0c7eSAndre Przywara b console_16550_core_init 176*bbf92fe9SMario Bălănică#endif 17707aa0c7eSAndre Przywaraendfunc plat_crash_console_init 17807aa0c7eSAndre Przywara 17907aa0c7eSAndre Przywara /* --------------------------------------------- 18007aa0c7eSAndre Przywara * int plat_crash_console_putc(int c) 18107aa0c7eSAndre Przywara * Function to print a character on the crash 18207aa0c7eSAndre Przywara * console without a C Runtime. 18307aa0c7eSAndre Przywara * Clobber list : x1, x2 18407aa0c7eSAndre Przywara * --------------------------------------------- 18507aa0c7eSAndre Przywara */ 18607aa0c7eSAndre Przywarafunc plat_crash_console_putc 187*bbf92fe9SMario Bălănică mov_imm x1, PLAT_RPI_CRASH_UART_BASE 188*bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE 189*bbf92fe9SMario Bălănică b console_pl011_core_putc 190*bbf92fe9SMario Bălănică#else 19107aa0c7eSAndre Przywara b console_16550_core_putc 192*bbf92fe9SMario Bălănică#endif 19307aa0c7eSAndre Przywaraendfunc plat_crash_console_putc 19407aa0c7eSAndre Przywara 19507aa0c7eSAndre Przywara /* --------------------------------------------- 196831b0e98SJimmy Brisson * void plat_crash_console_flush() 19707aa0c7eSAndre Przywara * Function to force a write of all buffered 19807aa0c7eSAndre Przywara * data that hasn't been output. 199831b0e98SJimmy Brisson * Out : void. 20007aa0c7eSAndre Przywara * Clobber list : x0, x1 20107aa0c7eSAndre Przywara * --------------------------------------------- 20207aa0c7eSAndre Przywara */ 20307aa0c7eSAndre Przywarafunc plat_crash_console_flush 204*bbf92fe9SMario Bălănică mov_imm x0, PLAT_RPI_CRASH_UART_BASE 205*bbf92fe9SMario Bălănică#if PLAT_RPI_CRASH_UART_BASE == PLAT_RPI_PL011_UART_BASE 206*bbf92fe9SMario Bălănică b console_pl011_core_flush 207*bbf92fe9SMario Bălănică#else 20807aa0c7eSAndre Przywara b console_16550_core_flush 209*bbf92fe9SMario Bălănică#endif 21007aa0c7eSAndre Przywaraendfunc plat_crash_console_flush 21107aa0c7eSAndre Przywara 21207aa0c7eSAndre Przywara /* --------------------------------------------- 21307aa0c7eSAndre Przywara * int plat_rpi_get_model() 21407aa0c7eSAndre Przywara * Macro to determine whether we are running on 21507aa0c7eSAndre Przywara * a Raspberry Pi 3 or 4. Just checks the MIDR for 21607aa0c7eSAndre Przywara * being either a Cortex-A72 or a Cortex-A53. 21707aa0c7eSAndre Przywara * Out : return 4 if RPi4, 3 otherwise. 21807aa0c7eSAndre Przywara * Clobber list : x0 21907aa0c7eSAndre Przywara * --------------------------------------------- 22007aa0c7eSAndre Przywara */ 22107aa0c7eSAndre Przywara .macro _plat_rpi_get_model 22207aa0c7eSAndre Przywara mrs x0, midr_el1 22307aa0c7eSAndre Przywara and x0, x0, #0xf0 /* Isolate low byte of part number */ 22407aa0c7eSAndre Przywara cmp w0, #0x80 /* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */ 22507aa0c7eSAndre Przywara mov w0, #3 22607aa0c7eSAndre Przywara csinc w0, w0, w0, ne 22707aa0c7eSAndre Przywara .endm 22807aa0c7eSAndre Przywara 22907aa0c7eSAndre Przywara func plat_rpi_get_model 23007aa0c7eSAndre Przywara _plat_rpi_get_model 23107aa0c7eSAndre Przywara ret 23207aa0c7eSAndre Przywara endfunc plat_rpi_get_model 23307aa0c7eSAndre Przywara 23407aa0c7eSAndre Przywara /* --------------------------------------------- 23507aa0c7eSAndre Przywara * void plat_reset_handler(void); 23607aa0c7eSAndre Przywara * --------------------------------------------- 23707aa0c7eSAndre Przywara */ 23807aa0c7eSAndre Przywarafunc plat_reset_handler 23907aa0c7eSAndre Przywara /* L2 cache setup only needed on RPi4 */ 24007aa0c7eSAndre Przywara _plat_rpi_get_model 24107aa0c7eSAndre Przywara cmp w0, #4 24207aa0c7eSAndre Przywara b.ne 1f 24307aa0c7eSAndre Przywara 24407aa0c7eSAndre Przywara /* ------------------------------------------------ 24507aa0c7eSAndre Przywara * Set L2 read/write cache latency: 24607aa0c7eSAndre Przywara * - L2 Data RAM latency: 3 cycles (0b010) 24707aa0c7eSAndre Przywara * - L2 Data RAM setup: 1 cycle (bit 5) 24807aa0c7eSAndre Przywara * ------------------------------------------------ 24907aa0c7eSAndre Przywara */ 25007aa0c7eSAndre Przywara mrs x0, CORTEX_A72_L2CTLR_EL1 25107aa0c7eSAndre Przywara mov x1, #0x22 25207aa0c7eSAndre Przywara orr x0, x0, x1 25307aa0c7eSAndre Przywara msr CORTEX_A72_L2CTLR_EL1, x0 25407aa0c7eSAndre Przywara isb 25507aa0c7eSAndre Przywara 25607aa0c7eSAndre Przywara1: 25707aa0c7eSAndre Przywara ret 25807aa0c7eSAndre Przywaraendfunc plat_reset_handler 259