diff options
Diffstat (limited to 'plat/rpi/common')
-rw-r--r-- | plat/rpi/common/aarch64/plat_helpers.S | 244 | ||||
-rw-r--r-- | plat/rpi/common/include/rpi_shared.h | 4 | ||||
-rw-r--r-- | plat/rpi/common/rpi3_common.c | 39 | ||||
-rw-r--r-- | plat/rpi/common/rpi3_pm.c | 34 |
4 files changed, 308 insertions, 13 deletions
diff --git a/plat/rpi/common/aarch64/plat_helpers.S b/plat/rpi/common/aarch64/plat_helpers.S new file mode 100644 index 000000000..f045e2113 --- /dev/null +++ b/plat/rpi/common/aarch64/plat_helpers.S @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <assert_macros.S> +#include <platform_def.h> +#include <cortex_a72.h> + + .globl plat_crash_console_flush + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl platform_mem_init + .globl plat_get_my_entrypoint + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl plat_reset_handler + .globl plat_rpi3_calc_core_pos + .globl plat_secondary_cold_boot_setup + .globl plat_rpi_get_model + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * + * This function uses the plat_rpi3_calc_core_pos() + * definition to get the index of the calling CPU. + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_rpi3_calc_core_pos +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); + * + * CorePos = (ClusterId * 4) + CoreId + * ----------------------------------------------------- + */ +func plat_rpi3_calc_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_rpi3_calc_core_pos + + /* ----------------------------------------------------- + * unsigned int plat_is_my_cpu_primary (void); + * + * Find out whether the current cpu is the primary + * cpu. + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) + cmp x0, #RPI_PRIMARY_CPU + cset w0, eq + ret +endfunc plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * void plat_wait_for_warm_boot (void); + * + * This function performs any platform specific actions + * needed for a CPU to be put into holding pen to wait + * for a warm boot request. + * The function will never return. + * ----------------------------------------------------- + */ +func plat_wait_for_warm_boot + /* + * Calculate address of our hold entry. + * As the function will never return, there is no need to save LR. + */ + bl plat_my_core_pos + lsl x0, x0, #3 + mov_imm x2, PLAT_RPI3_TM_HOLD_BASE + add x0, x0, x2 + /* + * This code runs way before requesting the warmboot of this core, + * so it is possible to clear the mailbox before getting a request + * to boot. + */ + mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT + str x1,[x0] + + /* Wait until we have a go */ +poll_mailbox: + wfe + ldr x1, [x0] + cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO + bne poll_mailbox + + /* Jump to the provided entrypoint */ + mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT + ldr x1, [x0] + br x1 +endfunc plat_wait_for_warm_boot + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset e.g + * mark the cpu's presence, mechanism to place it in a + * holding pen etc. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + b plat_wait_for_warm_boot +endfunc plat_secondary_cold_boot_setup + + /* --------------------------------------------------------------------- + * uintptr_t plat_get_my_entrypoint (void); + * + * Main job of this routine is to distinguish between a cold and a warm + * boot. + * + * This functions returns: + * - 0 for a cold boot. + * - Any other value for a warm boot. + * --------------------------------------------------------------------- + */ +func plat_get_my_entrypoint + mov x1, x30 + bl plat_is_my_cpu_primary + /* + * Secondaries always cold boot. + */ + cbz w0, 1f + /* + * Primaries warm boot if they are requested + * to power off. + */ + mov_imm x0, PLAT_RPI3_TM_HOLD_BASE + ldr x0, [x0] + cmp x0, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF + adr x0, plat_wait_for_warm_boot + csel x0, x0, xzr, eq + ret x1 +1: mov x0, #0 + ret x1 +endfunc plat_get_my_entrypoint + + /* --------------------------------------------- + * void platform_mem_init (void); + * + * No need to carry out any memory initialization. + * --------------------------------------------- + */ +func platform_mem_init + ret +endfunc platform_mem_init + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * Function to initialize the crash console + * without a C Runtime to print crash report. + * Clobber list : x0 - x3 + * --------------------------------------------- + */ +func plat_crash_console_init + mov_imm x0, PLAT_RPI_MINI_UART_BASE + mov x1, xzr + mov x2, xzr + b console_16550_core_init +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(int c) + * Function to print a character on the crash + * console without a C Runtime. + * Clobber list : x1, x2 + * --------------------------------------------- + */ +func plat_crash_console_putc + mov_imm x1, PLAT_RPI_MINI_UART_BASE + b console_16550_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * void plat_crash_console_flush() + * Function to force a write of all buffered + * data that hasn't been output. + * Out : void. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x0, PLAT_RPI_MINI_UART_BASE + b console_16550_core_flush +endfunc plat_crash_console_flush + + /* --------------------------------------------- + * int plat_rpi_get_model() + * Macro to determine whether we are running on + * a Raspberry Pi 3 or 4. Just checks the MIDR for + * being either a Cortex-A72 or a Cortex-A53. + * Out : return 4 if RPi4, 3 otherwise. + * Clobber list : x0 + * --------------------------------------------- + */ + .macro _plat_rpi_get_model + mrs x0, midr_el1 + and x0, x0, #0xf0 /* Isolate low byte of part number */ + cmp w0, #0x80 /* Cortex-A72 (RPi4) is 0xd08, A53 is 0xd03 */ + mov w0, #3 + csinc w0, w0, w0, ne + .endm + + func plat_rpi_get_model + _plat_rpi_get_model + ret + endfunc plat_rpi_get_model + + /* --------------------------------------------- + * void plat_reset_handler(void); + * --------------------------------------------- + */ +func plat_reset_handler + /* L2 cache setup only needed on RPi4 */ + _plat_rpi_get_model + cmp w0, #4 + b.ne 1f + + /* ------------------------------------------------ + * Set L2 read/write cache latency: + * - L2 Data RAM latency: 3 cycles (0b010) + * - L2 Data RAM setup: 1 cycle (bit 5) + * ------------------------------------------------ + */ + mrs x0, CORTEX_A72_L2CTLR_EL1 + mov x1, #0x22 + orr x0, x0, x1 + msr CORTEX_A72_L2CTLR_EL1, x0 + isb + +1: + ret +endfunc plat_reset_handler diff --git a/plat/rpi/common/include/rpi_shared.h b/plat/rpi/common/include/rpi_shared.h index de8357162..ddf239eb5 100644 --- a/plat/rpi/common/include/rpi_shared.h +++ b/plat/rpi/common/include/rpi_shared.h @@ -14,7 +14,7 @@ ******************************************************************************/ /* Utility functions */ -void rpi3_console_init(unsigned int base_clk_rate); +void rpi3_console_init(void); void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit @@ -36,4 +36,6 @@ void plat_rpi3_io_setup(void); /* VideoCore firmware commands */ int rpi3_vc_hardware_get_board_revision(uint32_t *revision); +int plat_rpi_get_model(void); + #endif /* RPI3_PRIVATE_H */ diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c index ff3369427..ef88bf10e 100644 --- a/plat/rpi/common/rpi3_common.c +++ b/plat/rpi/common/rpi3_common.c @@ -13,7 +13,9 @@ #include <common/debug.h> #include <bl31/interrupt_mgmt.h> #include <drivers/console.h> +#include <drivers/rpi3/gpio/rpi3_gpio.h> #include <drivers/ti/uart/uart_16550.h> +#include <drivers/arm/pl011.h> #include <lib/xlat_tables/xlat_tables_v2.h> #include <rpi_hw.h> @@ -102,18 +104,35 @@ static const mmap_region_t plat_rpi3_mmap[] = { /******************************************************************************* * Function that sets up the console ******************************************************************************/ -static console_16550_t rpi3_console; +static console_t rpi3_console; -void rpi3_console_init(unsigned int base_clk_rate) + +static bool rpi3_use_mini_uart(void) +{ + return rpi3_gpio_get_select(14) == RPI3_GPIO_FUNC_ALT5; +} + +void rpi3_console_init(void) { int console_scope = CONSOLE_FLAG_BOOT; -#if RPI3_RUNTIME_UART != -1 - console_scope |= CONSOLE_FLAG_RUNTIME; -#endif - int rc = console_16550_register(PLAT_RPI3_UART_BASE, - base_clk_rate, - PLAT_RPI3_UART_BAUDRATE, - &rpi3_console); + int rc; + + if (RPI3_RUNTIME_UART != -1) + console_scope |= CONSOLE_FLAG_RUNTIME; + + rpi3_gpio_init(); + + if (rpi3_use_mini_uart()) + rc = console_16550_register(PLAT_RPI_MINI_UART_BASE, + 0, + PLAT_RPI_UART_BAUDRATE, + &rpi3_console); + else + rc = console_pl011_register(PLAT_RPI_PL011_UART_BASE, + PLAT_RPI_PL011_UART_CLOCK, + PLAT_RPI_UART_BAUDRATE, + &rpi3_console); + if (rc == 0) { /* * The crash console doesn't use the multi console API, it uses @@ -123,7 +142,7 @@ void rpi3_console_init(unsigned int base_clk_rate) panic(); } - console_set_scope(&rpi3_console.console, console_scope); + console_set_scope(&rpi3_console, console_scope); } /******************************************************************************* diff --git a/plat/rpi/common/rpi3_pm.c b/plat/rpi/common/rpi3_pm.c index 2a6bf076b..86c61f7a6 100644 --- a/plat/rpi/common/rpi3_pm.c +++ b/plat/rpi/common/rpi3_pm.c @@ -140,11 +140,14 @@ static int rpi3_pwr_domain_on(u_register_t mpidr) { int rc = PSCI_E_SUCCESS; unsigned int pos = plat_core_pos_by_mpidr(mpidr); - uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; + uintptr_t hold_base = PLAT_RPI3_TM_HOLD_BASE; assert(pos < PLATFORM_CORE_COUNT); - hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO; + hold_base += pos * PLAT_RPI3_TM_HOLD_ENTRY_SIZE; + + mmio_write_64(hold_base, PLAT_RPI3_TM_HOLD_STATE_GO); + /* No cache maintenance here, hold_base is mapped as device memory. */ /* Make sure that the write has completed */ dsb(); @@ -171,6 +174,32 @@ static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state) #endif } +static void __dead2 rpi3_pwr_down_wfi( + const psci_power_state_t *target_state) +{ + uintptr_t hold_base = PLAT_RPI3_TM_HOLD_BASE; + unsigned int pos = plat_my_core_pos(); + + if (pos == 0) { + /* + * The secondaries will always be in a wait + * for warm boot on reset, but the BSP needs + * to be able to distinguish between waiting + * for warm boot (e.g. after psci_off, waiting + * for psci_on) and a cold boot. + */ + mmio_write_64(hold_base, PLAT_RPI3_TM_HOLD_STATE_BSP_OFF); + /* No cache maintenance here, we run with caches off already. */ + dsb(); + isb(); + } + + write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); + + while (1) + ; +} + /******************************************************************************* * Platform handlers for system reset and system off. ******************************************************************************/ @@ -236,6 +265,7 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = { .pwr_domain_pwr_down_wfi = rpi3_pwr_domain_pwr_down_wfi, .pwr_domain_on = rpi3_pwr_domain_on, .pwr_domain_on_finish = rpi3_pwr_domain_on_finish, + .pwr_domain_pwr_down_wfi = rpi3_pwr_down_wfi, .system_off = rpi3_system_off, .system_reset = rpi3_system_reset, .validate_power_state = rpi3_validate_power_state, |