diff --git a/maintainers.rst b/maintainers.rst index 701ea17..c878f61 100644 --- a/maintainers.rst +++ b/maintainers.rst @@ -71,6 +71,15 @@ - plat/mediatek/\* +Raspberry Pi 3 platform sub-maintainer +-------------------------------------- + +Antonio Niño Díaz (antonio.ninodiaz@arm.com, `antonio-nino-diaz-arm`_) + +Files: + +- plat/rpi3/\* + RockChip platform sub-maintainer -------------------------------- @@ -96,6 +105,7 @@ Etienne Carriere (etienne.carriere@linaro.org, `etienne-lms`_) +.. _antonio-nino-diaz-arm: https://github.com/antonio-nino-diaz-arm .. _danh-arm: https://github.com/danh-arm .. _davidcunado-arm: https://github.com/davidcunado-arm .. _jenswi-linaro: https://github.com/jenswi-linaro diff --git a/plat/rpi3/aarch64/plat_helpers.S b/plat/rpi3/aarch64/plat_helpers.S new file mode 100644 index 0000000..76a542f --- /dev/null +++ b/plat/rpi3/aarch64/plat_helpers.S @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +#include "../rpi3_hw.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 + + /* ----------------------------------------------------- + * 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, #RPI3_PRIMARY_CPU + cset w0, eq + ret +endfunc plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * 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 + /* Calculate address of our hold entry */ + 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_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 + /* TODO: support warm boot */ + mov x0, #0 + ret +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_RPI3_UART_BASE + mov_imm x1, PLAT_RPI3_UART_CLK_IN_HZ + mov_imm x2, PLAT_RPI3_UART_BAUDRATE + b console_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_RPI3_UART_BASE + b console_core_putc +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * int plat_crash_console_flush() + * Function to force a write of all buffered + * data that hasn't been output. + * Out : return -1 on error else return 0. + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x1, PLAT_RPI3_UART_BASE + b console_core_flush +endfunc plat_crash_console_flush + + /* --------------------------------------------- + * void plat_reset_handler(void); + * --------------------------------------------- + */ +func plat_reset_handler + /* use the 19.2 MHz clock for the architected timer */ + mov x0, #RPI3_INTC_BASE_ADDRESS + mov w1, #0x80000000 + str wzr, [x0, #RPI3_INTC_CONTROL_OFFSET] + str w1, [x0, #RPI3_INTC_PRESCALER_OFFSET] + + /* wire mailbox 3 to the FIQ line */ + mov w1, RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ + str w1, [x0, #RPI3_INTC_MBOX_CONTROL_OFFSET] + ret +endfunc plat_reset_handler diff --git a/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c new file mode 100644 index 0000000..e3acfe9 --- /dev/null +++ b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +/******************************************************************************* + * Following descriptor provides BL image/ep information that gets used + * by BL2 to load the images and also subset of this information is + * passed to next BL image. The image loading sequence is managed by + * populating the images in required loading order. The image execution + * sequence is managed by populating the `next_handoff_image_id` with + * the next executable image id. + ******************************************************************************/ +static bl_mem_params_node_t bl2_mem_params_descs[] = { + + /* Fill BL31 related information */ + { + .image_id = BL31_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | EXECUTABLE | EP_FIRST_EXE), + .ep_info.pc = BL31_BASE, + .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS), +#if DEBUG + .ep_info.args.arg1 = RPI3_BL31_PLAT_PARAM_VAL, +#endif + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_PLAT_SETUP), + .image_info.image_base = BL31_BASE, + .image_info.image_max_size = BL31_LIMIT - BL31_BASE, + +# ifdef BL32_BASE + .next_handoff_image_id = BL32_IMAGE_ID, +# else + .next_handoff_image_id = BL33_IMAGE_ID, +# endif + }, + +# ifdef BL32_BASE + /* Fill BL32 related information */ + { + .image_id = BL32_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | EXECUTABLE), + .ep_info.pc = BL32_BASE, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, 0), + .image_info.image_base = BL32_BASE, + .image_info.image_max_size = BL32_LIMIT - BL32_BASE, + + .next_handoff_image_id = BL33_IMAGE_ID, + }, + + /* + * Fill BL32 external 1 related information. + * A typical use for extra1 image is with OP-TEE where it is the pager + * image. + */ + { + .image_id = BL32_EXTRA1_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + .image_info.image_base = BL32_BASE, + .image_info.image_max_size = BL32_LIMIT - BL32_BASE, + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, + + /* + * Fill BL32 external 2 related information. + * A typical use for extra2 image is with OP-TEE where it is the paged + * image. + */ + { + .image_id = BL32_EXTRA2_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | NON_EXECUTABLE), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), + .next_handoff_image_id = INVALID_IMAGE_ID, + }, +# endif /* BL32_BASE */ + + /* Fill BL33 related information */ + { + .image_id = BL33_IMAGE_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + NON_SECURE | EXECUTABLE), +# ifdef PRELOADED_BL33_BASE + .ep_info.pc = PRELOADED_BL33_BASE, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, + IMAGE_ATTRIB_SKIP_LOADING), +# else + .ep_info.pc = PLAT_RPI3_NS_IMAGE_OFFSET, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, 0), + .image_info.image_base = PLAT_RPI3_NS_IMAGE_OFFSET, + .image_info.image_max_size = PLAT_RPI3_NS_IMAGE_MAX_SIZE, +# endif /* PRELOADED_BL33_BASE */ + + .next_handoff_image_id = INVALID_IMAGE_ID, + } +}; + +REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) diff --git a/plat/rpi3/include/plat_macros.S b/plat/rpi3/include/plat_macros.S new file mode 100644 index 0000000..f5e057e --- /dev/null +++ b/plat/rpi3/include/plat_macros.S @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __PLAT_MACROS_S__ +#define __PLAT_MACROS_S__ + +#include +#include + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant platform registers + * whenever an unhandled exception is taken in + * BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + .endm + +#endif /* __PLAT_MACROS_S__ */ diff --git a/plat/rpi3/include/platform_def.h b/plat/rpi3/include/platform_def.h new file mode 100644 index 0000000..5e2f1da --- /dev/null +++ b/plat/rpi3/include/platform_def.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +#include +#include +#include +#include + +#include "../rpi3_hw.h" + +/* Special value used to verify platform parameters from BL2 to BL31 */ +#define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) + +#define PLATFORM_STACK_SIZE ULL(0x1000) + +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER +#define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT + +#define RPI3_PRIMARY_CPU U(0) + +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_RET_STATE U(1) +#define PLAT_MAX_OFF_STATE U(2) + +/* Local power state for power domains in Run state. */ +#define PLAT_LOCAL_STATE_RUN U(0) +/* Local power state for retention. Valid only for CPU power domains */ +#define PLAT_LOCAL_STATE_RET U(1) +/* + * Local power state for OFF/power-down. Valid for CPU and cluster power + * domains. + */ +#define PLAT_LOCAL_STATE_OFF U(2) + +/* + * Macros used to parse state information from State-ID if it is using the + * recommended encoding for State-ID. + */ +#define PLAT_LOCAL_PSTATE_WIDTH U(4) +#define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) + +/* + * Some data must be aligned on the biggest cache line size in the platform. + * This is known only to the platform as it might have a combination of + * integrated and external caches. + */ +#define CACHE_WRITEBACK_SHIFT U(6) +#define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) + +/* + * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and + * secure DRAM. Note that this is all actually DRAM with different names, + * there is no Secure RAM in the Raspberry Pi 3. + */ +#define SEC_ROM_BASE ULL(0x00000000) +#define SEC_ROM_SIZE ULL(0x00010000) + +/* FIP placed after ROM to append it to BL1 with very little padding. */ +#define PLAT_RPI3_FIP_BASE ULL(0x00010000) +#define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001F0000) + +/* We have 16M of memory reserved at at 256M */ +#define SEC_SRAM_BASE ULL(0x10000000) +#define SEC_SRAM_SIZE ULL(0x00100000) + +#define SEC_DRAM0_BASE ULL(0x10100000) +#define SEC_DRAM0_SIZE ULL(0x00200000) + +#define NS_DRAM0_BASE ULL(0x10300000) +#define NS_DRAM0_SIZE ULL(0x00D00000) +/* End of reserved memory */ + +/* + * BL33 entrypoint. + */ +#define PLAT_RPI3_NS_IMAGE_OFFSET NS_DRAM0_BASE +#define PLAT_RPI3_NS_IMAGE_MAX_SIZE NS_DRAM0_SIZE + +/* + * I/O registers. + */ +#define DEVICE0_BASE RPI3_IO_BASE +#define DEVICE0_SIZE RPI3_IO_SIZE + +/* + * Arm TF lives in SRAM, partition it here + */ +#define SHARED_RAM_BASE SEC_SRAM_BASE +#define SHARED_RAM_SIZE ULL(0x00001000) + +#define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) +#define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) + +/* + * Mailbox to control the secondary cores.All secondary cores are held in a wait + * loop in cold boot. To release them perform the following steps (plus any + * additional barriers that may be needed): + * + * uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT; + * *entrypoint = ADDRESS_TO_JUMP_TO; + * + * uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; + * mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO; + * + * sev(); + */ +#define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE + +#define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE +#define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8) + +#define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \ + PLAT_RPI3_TM_ENTRYPOINT_SIZE) +#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8) +#define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \ + PLATFORM_CORE_COUNT) + +#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \ + PLAT_RPI3_TM_HOLD_SIZE) + +#define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0) +#define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1) + +/* + * BL1 specific defines. + * + * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of + * addresses. + * + * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using + * the current BL1 RW debug size plus a little space for growth. + */ +#define PLAT_MAX_BL1_RW_SIZE ULL(0x12000) + +#define BL1_RO_BASE SEC_ROM_BASE +#define BL1_RO_LIMIT (SEC_ROM_BASE + SEC_ROM_SIZE) +#define BL1_RW_BASE (BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE) +#define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) + +/* + * BL2 specific defines. + * + * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug + * size plus a little space for growth. + */ +#define PLAT_MAX_BL2_SIZE ULL(0x2C000) + +#define BL2_BASE (BL2_LIMIT - PLAT_MAX_BL2_SIZE) +#define BL2_LIMIT BL31_BASE + +/* + * BL31 specific defines. + * + * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the + * current BL31 debug size plus a little space for growth. + */ +#define PLAT_MAX_BL31_SIZE ULL(0x20000) + +#define BL31_BASE (BL31_LIMIT - PLAT_MAX_BL31_SIZE) +#define BL31_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) +#define BL31_PROGBITS_LIMIT BL1_RW_BASE + +/* + * BL32 specific defines. + * + * BL32 can execute from Secure SRAM or Secure DRAM. + */ +#define BL32_SRAM_BASE BL_RAM_BASE +#define BL32_SRAM_LIMIT BL31_BASE +#define BL32_DRAM_BASE SEC_DRAM0_BASE +#define BL32_DRAM_LIMIT (SEC_DRAM0_BASE + SEC_DRAM0_SIZE) + +#define SEC_SRAM_ID 0 +#define SEC_DRAM_ID 1 + +#if RPI3_BL32_RAM_LOCATION_ID == SEC_SRAM_ID +# define BL32_MEM_BASE BL_RAM_BASE +# define BL32_MEM_SIZE BL_RAM_SIZE +# define BL32_BASE BL32_SRAM_BASE +# define BL32_LIMIT BL32_SRAM_LIMIT +#elif RPI3_BL32_RAM_LOCATION_ID == SEC_DRAM_ID +# define BL32_MEM_BASE SEC_DRAM0_BASE +# define BL32_MEM_SIZE SEC_DRAM0_SIZE +# define BL32_BASE BL32_DRAM_BASE +# define BL32_LIMIT BL32_DRAM_LIMIT +#else +# error "Unsupported RPI3_BL32_RAM_LOCATION_ID value" +#endif +#define BL32_SIZE (BL32_LIMIT - BL32_BASE) + +#ifdef SPD_none +#undef BL32_BASE +#endif /* SPD_none */ + +/* + * Other memory-related defines. + */ +#define ADDR_SPACE_SIZE (ULL(1) << 32) + +#define MAX_MMAP_REGIONS U(8) +#define MAX_XLAT_TABLES U(4) + +#define MAX_IO_DEVICES U(3) +#define MAX_IO_HANDLES U(4) + +/* + * Serial-related constants. + */ +#define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE +#define PLAT_RPI3_UART_CLK_IN_HZ RPI3_MINI_UART_CLK_IN_HZ +#define PLAT_RPI3_UART_BAUDRATE ULL(115200) + +/* + * System counter + */ +#define SYS_COUNTER_FREQ_IN_TICKS ULL(19200000) + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk new file mode 100644 index 0000000..821f801 --- /dev/null +++ b/plat/rpi3/platform.mk @@ -0,0 +1,113 @@ +# +# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_INCLUDES := -Iinclude/common/tbbr \ + -Iinclude/plat/arm/common/ \ + -Iinclude/plat/arm/common/aarch64/ \ + -Iplat/rpi3/include + +PLAT_BL_COMMON_SOURCES := drivers/console/aarch64/console.S \ + drivers/ti/uart/aarch64/16550_console.S \ + plat/rpi3/rpi3_common.c + +BL1_SOURCES += drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + lib/cpus/aarch64/cortex_a53.S \ + plat/common/aarch64/platform_mp_stack.S \ + plat/rpi3/aarch64/plat_helpers.S \ + plat/rpi3/rpi3_bl1_setup.c \ + plat/rpi3/rpi3_io_storage.c + +BL2_SOURCES += common/desc_image_load.c \ + drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + plat/common/aarch64/platform_mp_stack.S \ + plat/rpi3/aarch64/plat_helpers.S \ + plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \ + plat/rpi3/rpi3_bl2_setup.c \ + plat/rpi3/rpi3_image_load.c \ + plat/rpi3/rpi3_io_storage.c + +BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ + plat/common/aarch64/plat_psci_common.c \ + plat/rpi3/aarch64/plat_helpers.S \ + plat/rpi3/rpi3_bl31_setup.c \ + plat/rpi3/rpi3_pm.c \ + plat/rpi3/rpi3_topology.c + +# Translation tables library +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} + +# Tune compiler for Cortex-A53 +ifeq ($(notdir $(CC)),armclang) + TF_CFLAGS_aarch64 += -mcpu=cortex-a53 +else ifneq ($(findstring clang,$(notdir $(CC))),) + TF_CFLAGS_aarch64 += -mcpu=cortex-a53 +else + TF_CFLAGS_aarch64 += -mtune=cortex-a53 +endif + +# Build config flags +# ------------------ + +# Enable all errata workarounds for Cortex-A53 +ERRATA_A53_826319 := 1 +ERRATA_A53_835769 := 1 +ERRATA_A53_836870 := 1 +ERRATA_A53_843419 := 1 +ERRATA_A53_855873 := 1 + +# Disable the PSCI platform compatibility layer by default +ENABLE_PLAT_COMPAT := 0 + +# Enable reset to BL31 by default +RESET_TO_BL31 := 1 + +# Have different sections for code and rodata +SEPARATE_CODE_AND_RODATA := 1 + +# Use Coherent memory +USE_COHERENT_MEM := 1 + +# Enable new version of image loading +LOAD_IMAGE_V2 := 1 + +# Platform build flags +# -------------------- + +# BL33 images are in AArch64 by default +RPI3_BL33_IN_AARCH32 := 0 + +# BL32 location +RPI3_BL32_RAM_LOCATION := tdram +ifeq (${RPI3_BL32_RAM_LOCATION}, tsram) + RPI3_BL32_RAM_LOCATION_ID = SEC_SRAM_ID +else ifeq (${RPI3_BL32_RAM_LOCATION}, tdram) + RPI3_BL32_RAM_LOCATION_ID = SEC_DRAM_ID +else + $(error "Unsupported RPI3_BL32_RAM_LOCATION value") +endif + +# Process platform flags +# ---------------------- + +$(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID)) +$(eval $(call add_define,RPI3_BL33_IN_AARCH32)) + +# Verify build config +# ------------------- + +ifneq (${LOAD_IMAGE_V2}, 1) + $(error Error: rpi3 needs LOAD_IMAGE_V2=1) +endif + +ifeq (${ARCH},aarch32) + $(error Error: AArch32 not supported on rpi3) +endif diff --git a/plat/rpi3/rpi3_bl1_setup.c b/plat/rpi3/rpi3_bl1_setup.c new file mode 100644 index 0000000..11c0f4a --- /dev/null +++ b/plat/rpi3/rpi3_bl1_setup.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../../bl1/bl1_private.h" +#include "rpi3_private.h" + +/* Data structure which holds the extents of the trusted SRAM for BL1 */ +static meminfo_t bl1_tzram_layout; + +meminfo_t *bl1_plat_sec_mem_layout(void) +{ + return &bl1_tzram_layout; +} + +/******************************************************************************* + * Perform any BL1 specific platform actions. + ******************************************************************************/ +void bl1_early_platform_setup(void) +{ + /* Initialize the console to provide early debug support */ + console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ, + PLAT_RPI3_UART_BAUDRATE); + + /* Allow BL1 to see the whole Trusted RAM */ + bl1_tzram_layout.total_base = BL_RAM_BASE; + bl1_tzram_layout.total_size = BL_RAM_SIZE; +} + +/****************************************************************************** + * Perform the very early platform specific architecture setup. This only + * does basic initialization. Later architectural setup (bl1_arch_setup()) + * does not do anything platform specific. + *****************************************************************************/ +void bl1_plat_arch_setup(void) +{ + rpi3_setup_page_tables(bl1_tzram_layout.total_base, + bl1_tzram_layout.total_size, + BL_CODE_BASE, BL1_CODE_END, + BL1_RO_DATA_BASE, BL1_RO_DATA_END +#if USE_COHERENT_MEM + , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END +#endif + ); + + enable_mmu_el3(0); +} + +void bl1_platform_setup(void) +{ + /* Initialise the IO layer and register platform IO devices */ + plat_rpi3_io_setup(); +} diff --git a/plat/rpi3/rpi3_bl2_setup.c b/plat/rpi3/rpi3_bl2_setup.c new file mode 100644 index 0000000..1fd822e --- /dev/null +++ b/plat/rpi3/rpi3_bl2_setup.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpi3_private.h" + +/* Data structure which holds the extents of the trusted SRAM for BL2 */ +static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); + +/******************************************************************************* + * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 + * in x0. This memory layout is sitting at the base of the free trusted SRAM. + * Copy it to a safe location before its reclaimed by later BL2 functionality. + ******************************************************************************/ +void bl2_early_platform_setup(meminfo_t *mem_layout) +{ + /* Initialize the console to provide early debug support */ + console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ, + PLAT_RPI3_UART_BAUDRATE); + + /* Setup the BL2 memory layout */ + bl2_tzram_layout = *mem_layout; + + plat_rpi3_io_setup(); +} + +void bl2_platform_setup(void) +{ + /* + * This is where a TrustZone address space controller and other + * security related peripherals, would be configured. + */ +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. + ******************************************************************************/ +void bl2_plat_arch_setup(void) +{ + rpi3_setup_page_tables(bl2_tzram_layout.total_base, + bl2_tzram_layout.total_size, + BL_CODE_BASE, BL_CODE_END, + BL_RO_DATA_BASE, BL_RO_DATA_END +#if USE_COHERENT_MEM + , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END +#endif + ); + + enable_mmu_el1(0); +} + +/******************************************************************************* + * This function can be used by the platforms to update/use image + * information for given `image_id`. + ******************************************************************************/ +int bl2_plat_handle_post_image_load(unsigned int image_id) +{ + int err = 0; + bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); + + assert(bl_mem_params != NULL); + + switch (image_id) { + case BL32_IMAGE_ID: + bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl32_entry(); + break; + + case BL33_IMAGE_ID: + /* BL33 expects to receive the primary CPU MPID (through r0) */ + bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); + bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl33_entry(); + break; + + } + + return err; +} diff --git a/plat/rpi3/rpi3_bl31_setup.c b/plat/rpi3/rpi3_bl31_setup.c new file mode 100644 index 0000000..3913356 --- /dev/null +++ b/plat/rpi3/rpi3_bl31_setup.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rpi3_private.h" + +#define BL31_END (uintptr_t)(&__BL31_END__) + +/* + * Placeholder variables for copying the arguments that have been passed to + * BL31 from BL2. + */ +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + entry_point_info_t *next_image_info; + + assert(sec_state_is_valid(type) != 0); + + next_image_info = (type == NON_SECURE) + ? &bl33_image_ep_info : &bl32_image_ep_info; + + /* None of the images can have 0x0 as the entrypoint. */ + if (next_image_info->pc) { + return next_image_info; + } else { + return NULL; + } +} + +/******************************************************************************* + * Perform any BL31 early platform setup. Here is an opportunity to copy + * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before + * they are lost (potentially). This needs to be done before the MMU is + * initialized so that the memory layout can be used while creating page + * tables. BL2 has flushed this information to memory, so we are guaranteed + * to pick up good data. + ******************************************************************************/ +void bl31_early_platform_setup(void *from_bl2, + void *plat_params_from_bl2) +{ + /* Initialize the console to provide early debug support */ + console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ, + PLAT_RPI3_UART_BAUDRATE); + +#if RESET_TO_BL31 + + /* There are no parameters from BL2 if BL31 is a reset vector */ + assert(from_bl2 == NULL); + assert(plat_params_from_bl2 == NULL); + +#ifdef BL32_BASE + /* Populate entry point information for BL32 */ + SET_PARAM_HEAD(&bl32_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = rpi3_get_spsr_for_bl32_entry(); +#endif /* BL32_BASE */ + + /* Populate entry point information for BL33 */ + SET_PARAM_HEAD(&bl33_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + + bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + +#else /* RESET_TO_BL31 */ + + /* + * In debug builds, we pass a special value in 'plat_params_from_bl2' + * to verify platform parameters from BL2 to BL31. + * In release builds, it's not used. + */ + assert(((uintptr_t)plat_params_from_bl2) == RPI3_BL31_PLAT_PARAM_VAL); + + /* + * Check params passed from BL2 should not be NULL, + */ + bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; + + assert(params_from_bl2 != NULL); + assert(params_from_bl2->h.type == PARAM_BL_PARAMS); + assert(params_from_bl2->h.version >= VERSION_2); + + bl_params_node_t *bl_params = params_from_bl2->head; + + /* + * Copy BL33 and BL32 (if present), entry point information. + * They are stored in Secure RAM, in BL2's address space. + */ + while (bl_params) { + if (bl_params->image_id == BL32_IMAGE_ID) { + bl32_image_ep_info = *bl_params->ep_info; + } + + if (bl_params->image_id == BL33_IMAGE_ID) { + bl33_image_ep_info = *bl_params->ep_info; + } + + bl_params = bl_params->next_params_info; + } + + if (bl33_image_ep_info.pc == 0) { + panic(); + } + +#endif /* RESET_TO_BL31 */ +} + +void bl31_plat_arch_setup(void) +{ + rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, + BL_CODE_BASE, BL_CODE_END, + BL_RO_DATA_BASE, BL_RO_DATA_END +#if USE_COHERENT_MEM + , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END +#endif + ); + + enable_mmu_el3(0); +} + +void bl31_platform_setup(void) +{ +#if RESET_TO_BL31 + /* + * Do initial security configuration to allow DRAM/device access + * (if earlier BL has not already done so). + */ +#endif /* RESET_TO_BL31 */ + + return; +} + +void bl31_plat_runtime_setup(void) +{ + /* Initialize the runtime console */ + console_init(PLAT_RPI3_UART_BASE, PLAT_RPI3_UART_CLK_IN_HZ, + PLAT_RPI3_UART_BAUDRATE); +} diff --git a/plat/rpi3/rpi3_common.c b/plat/rpi3/rpi3_common.c new file mode 100644 index 0000000..97dce09 --- /dev/null +++ b/plat/rpi3/rpi3_common.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "rpi3_hw.h" +#include "rpi3_private.h" + +#define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ + DEVICE0_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_SHARED_RAM MAP_REGION_FLAT(SHARED_RAM_BASE, \ + SHARED_RAM_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE) + +#define MAP_NS_DRAM0 MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE, \ + MT_MEMORY | MT_RW | MT_NS) + +#define MAP_FIP MAP_REGION_FLAT(PLAT_RPI3_FIP_BASE, \ + PLAT_RPI3_FIP_MAX_SIZE, \ + MT_MEMORY | MT_RO | MT_NS) + +#define MAP_BL32_MEM MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE, \ + MT_MEMORY | MT_RW | MT_SECURE) + +/* + * Table of regions for various BL stages to map using the MMU. + */ +#ifdef IMAGE_BL1 +static const mmap_region_t plat_rpi3_mmap[] = { + MAP_SHARED_RAM, + MAP_DEVICE0, + MAP_FIP, + {0} +}; +#endif + +#ifdef IMAGE_BL2 +static const mmap_region_t plat_rpi3_mmap[] = { + MAP_SHARED_RAM, + MAP_DEVICE0, + MAP_FIP, + MAP_NS_DRAM0, +#ifdef BL32_BASE + MAP_BL32_MEM, +#endif + {0} +}; +#endif + +#ifdef IMAGE_BL31 +static const mmap_region_t plat_rpi3_mmap[] = { + MAP_SHARED_RAM, + MAP_DEVICE0, +#ifdef BL32_BASE + MAP_BL32_MEM, +#endif + {0} +}; +#endif + +/******************************************************************************* + * Function that sets up the translation tables. + ******************************************************************************/ +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 +#if USE_COHERENT_MEM + , uintptr_t coh_start, uintptr_t coh_limit +#endif + ) +{ + /* + * Map the Trusted SRAM with appropriate memory attributes. + * Subsequent mappings will adjust the attributes for specific regions. + */ + VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n", + (void *) total_base, (void *) (total_base + total_size)); + mmap_add_region(total_base, total_base, + total_size, + MT_MEMORY | MT_RW | MT_SECURE); + + /* Re-map the code section */ + VERBOSE("Code region: %p - %p\n", + (void *) code_start, (void *) code_limit); + mmap_add_region(code_start, code_start, + code_limit - code_start, + MT_CODE | MT_SECURE); + + /* Re-map the read-only data section */ + VERBOSE("Read-only data region: %p - %p\n", + (void *) rodata_start, (void *) rodata_limit); + mmap_add_region(rodata_start, rodata_start, + rodata_limit - rodata_start, + MT_RO_DATA | MT_SECURE); + +#if USE_COHERENT_MEM + /* Re-map the coherent memory region */ + VERBOSE("Coherent region: %p - %p\n", + (void *) coh_start, (void *) coh_limit); + mmap_add_region(coh_start, coh_start, + coh_limit - coh_start, + MT_DEVICE | MT_RW | MT_SECURE); +#endif + + mmap_add(plat_rpi3_mmap); + + init_xlat_tables(); +} + +/******************************************************************************* + * Return entrypoint of BL33. + ******************************************************************************/ +uintptr_t plat_get_ns_image_entrypoint(void) +{ +#ifdef PRELOADED_BL33_BASE + return PRELOADED_BL33_BASE; +#else + return PLAT_RPI3_NS_IMAGE_OFFSET; +#endif +} + +/******************************************************************************* + * Gets SPSR for BL32 entry + ******************************************************************************/ +uint32_t rpi3_get_spsr_for_bl32_entry(void) +{ + /* + * The Secure Payload Dispatcher service is responsible for + * setting the SPSR prior to entry into the BL32 image. + */ + return 0; +} + +/******************************************************************************* + * Gets SPSR for BL33 entry + ******************************************************************************/ +uint32_t rpi3_get_spsr_for_bl33_entry(void) +{ +#if RPI3_BL33_IN_AARCH32 + INFO("BL33 will boot in Non-secure AArch32 Hypervisor mode\n"); + return SPSR_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS); +#else + return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); +#endif +} + +unsigned int plat_get_syscnt_freq2(void) +{ + return SYS_COUNTER_FREQ_IN_TICKS; +} + +uint32_t plat_ic_get_pending_interrupt_type(void) +{ + return INTR_TYPE_INVAL; +} diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h new file mode 100644 index 0000000..70272e0 --- /dev/null +++ b/plat/rpi3/rpi3_hw.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __RPI3_HW__ +#define __RPI3_HW__ + +#include + +/* + * Peripherals + */ + +#define RPI3_IO_BASE ULL(0x3F000000) +#define RPI3_IO_SIZE ULL(0x01000000) + +/* + * Serial port (called 'Mini UART' in the BCM docucmentation). + */ +#define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) +#define RPI3_MINI_UART_BASE (RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET) +#define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000) + +/* + * Power management, reset controller, watchdog. + */ +#define RPI3_IO_PM_OFFSET ULL(0x00100000) +#define RPI3_PM_BASE (RPI3_IO_BASE + RPI3_IO_PM_OFFSET) +/* Registers on top of RPI3_PM_BASE. */ +#define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) +#define RPI3_PM_WDOG_OFFSET ULL(0x00000024) +/* Watchdog constants */ +#define RPI3_PM_PASSWORD ULL(0x5A000000) +#define RPI3_PM_RSTC_WRCFG_MASK ULL(0x00000030) +#define RPI3_PM_RSTC_WRCFG_FULL_RESET ULL(0x00000020) + +/* + * Local interrupt controller + */ +#define RPI3_INTC_BASE_ADDRESS ULL(0x40000000) +/* Registers on top of RPI3_INTC_BASE_ADDRESS */ +#define RPI3_INTC_CONTROL_OFFSET ULL(0x00000000) +#define RPI3_INTC_PRESCALER_OFFSET ULL(0x00000008) +#define RPI3_INTC_MBOX_CONTROL_OFFSET ULL(0x00000050) +#define RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ ULL(0x00000080) +#define RPI3_INTC_PENDING_FIQ_OFFSET ULL(0x00000070) +#define RPI3_INTC_PENDING_FIQ_MBOX3 ULL(0x00000080) + +#endif /* __RPI3_HW__ */ diff --git a/plat/rpi3/rpi3_image_load.c b/plat/rpi3/rpi3_image_load.c new file mode 100644 index 0000000..fad9e4f --- /dev/null +++ b/plat/rpi3/rpi3_image_load.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include + +/******************************************************************************* + * This function flushes the data structures so that they are visible + * in memory for the next BL image. + ******************************************************************************/ +void plat_flush_next_bl_params(void) +{ + flush_bl_params_desc(); +} + +/******************************************************************************* + * This function returns the list of loadable images. + ******************************************************************************/ +bl_load_info_t *plat_get_bl_image_load_info(void) +{ + return get_bl_load_info_from_mem_params_desc(); +} + +/******************************************************************************* + * This function returns the list of executable images. + ******************************************************************************/ +bl_params_t *plat_get_next_bl_params(void) +{ + return get_next_bl_params_from_mem_params_desc(); +} diff --git a/plat/rpi3/rpi3_io_storage.c b/plat/rpi3/rpi3_io_storage.c new file mode 100644 index 0000000..7ac45ef --- /dev/null +++ b/plat/rpi3/rpi3_io_storage.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Semihosting filenames */ +#define BL2_IMAGE_NAME "bl2.bin" +#define BL31_IMAGE_NAME "bl31.bin" +#define BL32_IMAGE_NAME "bl32.bin" +#define BL33_IMAGE_NAME "bl33.bin" + +#if TRUSTED_BOARD_BOOT +#define BL2_CERT_NAME "bl2.crt" +#define TRUSTED_KEY_CERT_NAME "trusted_key.crt" +#define BL31_KEY_CERT_NAME "bl31_key.crt" +#define BL32_KEY_CERT_NAME "bl32_key.crt" +#define BL33_KEY_CERT_NAME "bl33_key.crt" +#define BL31_CERT_NAME "bl31.crt" +#define BL32_CERT_NAME "bl32.crt" +#define BL33_CERT_NAME "bl33.crt" +#endif /* TRUSTED_BOARD_BOOT */ + +/* IO devices */ +static const io_dev_connector_t *fip_dev_con; +static uintptr_t fip_dev_handle; +static const io_dev_connector_t *memmap_dev_con; +static uintptr_t memmap_dev_handle; + +static const io_block_spec_t fip_block_spec = { + .offset = PLAT_RPI3_FIP_BASE, + .length = PLAT_RPI3_FIP_MAX_SIZE +}; + +static const io_uuid_spec_t bl2_uuid_spec = { + .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, +}; + +static const io_uuid_spec_t bl31_uuid_spec = { + .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, +}; + +static const io_uuid_spec_t bl32_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32, +}; + +static const io_uuid_spec_t bl33_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, +}; + +#if TRUSTED_BOARD_BOOT +static const io_uuid_spec_t bl2_cert_uuid_spec = { + .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2_CERT, +}; + +static const io_uuid_spec_t trusted_key_cert_uuid_spec = { + .uuid = UUID_TRUSTED_KEY_CERT, +}; + +static const io_uuid_spec_t bl31_key_cert_uuid_spec = { + .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_KEY_CERT, +}; + +static const io_uuid_spec_t bl32_key_cert_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32_KEY_CERT, +}; + +static const io_uuid_spec_t bl33_key_cert_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_KEY_CERT, +}; + +static const io_uuid_spec_t bl31_cert_uuid_spec = { + .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31_CERT, +}; + +static const io_uuid_spec_t bl32_cert_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32_CERT, +}; + +static const io_uuid_spec_t bl33_cert_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33_CERT, +}; +#endif /* TRUSTED_BOARD_BOOT */ + +static int open_fip(const uintptr_t spec); +static int open_memmap(const uintptr_t spec); + +struct plat_io_policy { + uintptr_t *dev_handle; + uintptr_t image_spec; + int (*check)(const uintptr_t spec); +}; + +/* By default, load images from the FIP */ +static const struct plat_io_policy policies[] = { + [FIP_IMAGE_ID] = { + &memmap_dev_handle, + (uintptr_t)&fip_block_spec, + open_memmap + }, + [BL2_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl2_uuid_spec, + open_fip + }, + [BL31_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl31_uuid_spec, + open_fip + }, + [BL32_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_uuid_spec, + open_fip + }, + [BL33_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl33_uuid_spec, + open_fip + }, +#if TRUSTED_BOARD_BOOT + [BL2_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl2_cert_uuid_spec, + open_fip + }, + [TRUSTED_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&trusted_key_cert_uuid_spec, + open_fip + }, + [BL31_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl31_key_cert_uuid_spec, + open_fip + }, + [BL32_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_key_cert_uuid_spec, + open_fip + }, + [BL33_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl33_key_cert_uuid_spec, + open_fip + }, + [BL31_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl31_cert_uuid_spec, + open_fip + }, + [BL32_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_cert_uuid_spec, + open_fip + }, + [BL33_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&bl33_cert_uuid_spec, + open_fip + }, +#endif /* TRUSTED_BOARD_BOOT */ +}; + +static int open_fip(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + /* See if a Firmware Image Package is available */ + result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); + if (result == 0) { + result = io_open(fip_dev_handle, spec, &local_image_handle); + if (result == 0) { + VERBOSE("Using FIP\n"); + io_close(local_image_handle); + } + } + return result; +} + +static int open_memmap(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); + if (result == 0) { + result = io_open(memmap_dev_handle, spec, &local_image_handle); + if (result == 0) { + VERBOSE("Using Memmap\n"); + io_close(local_image_handle); + } + } + return result; +} + +void plat_rpi3_io_setup(void) +{ + int io_result; + + io_result = register_io_dev_fip(&fip_dev_con); + assert(io_result == 0); + + io_result = register_io_dev_memmap(&memmap_dev_con); + assert(io_result == 0); + + /* Open connections to devices and cache the handles */ + io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, + &fip_dev_handle); + assert(io_result == 0); + + io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, + &memmap_dev_handle); + assert(io_result == 0); + + /* Ignore improbable errors in release builds */ + (void)io_result; +} + +/* + * Return an IO device handle and specification which can be used to access + * an image. Use this to enforce platform load policy + */ +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + int result; + const struct plat_io_policy *policy; + + assert(image_id < ARRAY_SIZE(policies)); + + policy = &policies[image_id]; + result = policy->check(policy->image_spec); + if (result == 0) { + *image_spec = policy->image_spec; + *dev_handle = *(policy->dev_handle); + } + + return result; +} diff --git a/plat/rpi3/rpi3_pm.c b/plat/rpi3/rpi3_pm.c new file mode 100644 index 0000000..1d067fb --- /dev/null +++ b/plat/rpi3/rpi3_pm.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rpi3_hw.h" + +/* + * The secure entry point to be used on warm reset. + */ +static uintptr_t secure_entrypoint; + +/* Make composite power state parameter till power level 0 */ +#if PSCI_EXTENDED_STATE_ID + +#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ + (((lvl0_state) << PSTATE_ID_SHIFT) | \ + ((type) << PSTATE_TYPE_SHIFT)) + +#else + +#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ + (((lvl0_state) << PSTATE_ID_SHIFT) | \ + ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ + ((type) << PSTATE_TYPE_SHIFT)) + +#endif /* PSCI_EXTENDED_STATE_ID */ + +#define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ + (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ + rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) + +/* + * The table storing the valid idle power states. Ensure that the + * array entries are populated in ascending order of state-id to + * enable us to use binary search during power state validation. + * The table must be terminated by a NULL entry. + */ +static const unsigned int rpi3_pm_idle_states[] = { + /* State-id - 0x01 */ + rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, + MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), + /* State-id - 0x02 */ + rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, + MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), + /* State-id - 0x22 */ + rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF, + MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN), + 0, +}; + +/******************************************************************************* + * Platform handler called to check the validity of the power state + * parameter. The power state parameter has to be a composite power state. + ******************************************************************************/ +static int rpi3_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + unsigned int state_id; + int i; + + assert(req_state != 0); + + /* + * Currently we are using a linear search for finding the matching + * entry in the idle power state array. This can be made a binary + * search if the number of entries justify the additional complexity. + */ + for (i = 0; rpi3_pm_idle_states[i] != 0; i++) { + if (power_state == rpi3_pm_idle_states[i]) { + break; + } + } + + /* Return error if entry not found in the idle state array */ + if (!rpi3_pm_idle_states[i]) { + return PSCI_E_INVALID_PARAMS; + } + + i = 0; + state_id = psci_get_pstate_id(power_state); + + /* Parse the State ID and populate the state info parameter */ + while (state_id) { + req_state->pwr_domain_state[i++] = state_id & + PLAT_LOCAL_PSTATE_MASK; + state_id >>= PLAT_LOCAL_PSTATE_WIDTH; + } + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Platform handler called when a CPU is about to enter standby. + ******************************************************************************/ +static void rpi3_cpu_standby(plat_local_state_t cpu_state) +{ + assert(cpu_state == PLAT_LOCAL_STATE_RET); + + /* + * Enter standby state. + * dsb is good practice before using wfi to enter low power states + */ + dsb(); + wfi(); +} + +/******************************************************************************* + * Platform handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + ******************************************************************************/ +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; + + assert(pos < PLATFORM_CORE_COUNT); + + hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO; + + /* Make sure that the write has completed */ + dsb(); + isb(); + + sev(); + + return rc; +} + +/******************************************************************************* + * Platform handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + ******************************************************************************/ +void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); +} + +/******************************************************************************* + * Platform handler to reboot the system + ******************************************************************************/ +#define RESET_TIMEOUT 10 + +static void __dead2 rpi3_system_reset(void) +{ + /* Setup watchdog for reset */ + + static const uintptr_t base = RPI3_PM_BASE; + uint32_t rstc; + + INFO("rpi3: PSCI System Reset: invoking watchdog reset\n"); + + console_flush(); + + rstc = mmio_read_32(base + RPI3_PM_RSTC_OFFSET); + rstc &= ~RPI3_PM_RSTC_WRCFG_MASK; + rstc |= RPI3_PM_RSTC_WRCFG_FULL_RESET; + + dmbst(); + + /* + * Watchdog timer = Timer clock / 16 + * Password (31:16) | Value (11:0) + */ + mmio_write_32(base + RPI3_PM_WDOG_OFFSET, + RPI3_PM_PASSWORD | RESET_TIMEOUT); + mmio_write_32(base + RPI3_PM_RSTC_OFFSET, + RPI3_PM_PASSWORD | rstc); + + for (;;) { + wfi(); + } +} + +/******************************************************************************* + * Platform handlers and setup function. + ******************************************************************************/ +static const plat_psci_ops_t plat_rpi3_psci_pm_ops = { + .cpu_standby = rpi3_cpu_standby, + .pwr_domain_on = rpi3_pwr_domain_on, + .pwr_domain_on_finish = rpi3_pwr_domain_on_finish, + .system_reset = rpi3_system_reset, + .validate_power_state = rpi3_validate_power_state, +}; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + uintptr_t *mailbox = (void *)PLAT_RPI3_TRUSTED_MAILBOX_BASE; + + *mailbox = sec_entrypoint; + secure_entrypoint = (uintptr_t)sec_entrypoint; + *psci_ops = &plat_rpi3_psci_pm_ops; + + return 0; +} diff --git a/plat/rpi3/rpi3_private.h b/plat/rpi3/rpi3_private.h new file mode 100644 index 0000000..01c4055 --- /dev/null +++ b/plat/rpi3/rpi3_private.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __RPI3_PRIVATE_H__ +#define __RPI3_PRIVATE_H__ + +#include + +/******************************************************************************* + * Function and variable prototypes + ******************************************************************************/ + +/* Utility functions */ +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 +#if USE_COHERENT_MEM + , uintptr_t coh_start, uintptr_t coh_limit +#endif + ); + +/* Optional functions required in the Raspberry Pi 3 port */ +unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); + +/* BL2 utility functions */ +uint32_t rpi3_get_spsr_for_bl32_entry(void); +uint32_t rpi3_get_spsr_for_bl33_entry(void); + +/* IO storage utility functions */ +void plat_rpi3_io_setup(void); + +#endif /*__RPI3_PRIVATE_H__ */ diff --git a/plat/rpi3/rpi3_topology.c b/plat/rpi3/rpi3_topology.c new file mode 100644 index 0000000..0e03ec3 --- /dev/null +++ b/plat/rpi3/rpi3_topology.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include "rpi3_private.h" + +/* The power domain tree descriptor */ +static unsigned char power_domain_tree_desc[] = { + /* Number of root nodes */ + PLATFORM_CLUSTER_COUNT, + /* Number of children for the first node */ + PLATFORM_CLUSTER0_CORE_COUNT, +}; + +/******************************************************************************* + * This function returns the ARM default topology tree information. + ******************************************************************************/ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return power_domain_tree_desc; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + ******************************************************************************/ +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster_id, cpu_id; + + mpidr &= MPIDR_AFFINITY_MASK; + if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) { + return -1; + } + + cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + + if (cluster_id >= PLATFORM_CLUSTER_COUNT) { + return -1; + } + + if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) { + return -1; + } + + return plat_rpi3_calc_core_pos(mpidr); +}