rpi3: Introduce AArch64 Raspberry Pi 3 port

This port can be compiled to boot an AArch64 or AArch32 payload with the
build option `RPI3_BL33_AARCH32`.

Note: This is not a secure port of the Trusted Firmware. This port is
only meant to be a reference implementation to experiment with an
inexpensive board in real hardware.

Change-Id: Ide58114299289bf765ef1366199eb05c46f81903
Co-authored-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
This commit is contained in:
Antonio Nino Diaz 2017-11-06 14:49:04 +00:00
parent 3642ca951b
commit d83c1db15c
16 changed files with 1812 additions and 0 deletions

View File

@ -71,6 +71,15 @@ Files:
- 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 @@ ARMv7 architecture sub-maintainer
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

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2015-2017, 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 "../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

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl_common.h>
#include <desc_image_load.h>
#include <platform.h>
#include <platform_def.h>
/*******************************************************************************
* 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)

View File

@ -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 <arm_macros.S>
#include <platform_def.h>
/* ---------------------------------------------
* 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__ */

View File

@ -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 <arch.h>
#include <common_def.h>
#include <tbbr_img_def.h>
#include <utils_def.h>
#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__ */

113
plat/rpi3/platform.mk Normal file
View File

@ -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

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <bl_common.h>
#include <console.h>
#include <platform_def.h>
#include <xlat_mmu_helpers.h>
#include <xlat_tables_defs.h>
#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();
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <desc_image_load.h>
#include <platform_def.h>
#include <xlat_mmu_helpers.h>
#include <xlat_tables_defs.h>
#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;
}

168
plat/rpi3/rpi3_bl31_setup.c Normal file
View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bl_common.h>
#include <console.h>
#include <platform.h>
#include <platform_def.h>
#include <xlat_mmu_helpers.h>
#include <xlat_tables_defs.h>
#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);
}

166
plat/rpi3/rpi3_common.c Normal file
View File

@ -0,0 +1,166 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <bl_common.h>
#include <debug.h>
#include <interrupt_mgmt.h>
#include <platform_def.h>
#include <xlat_tables_v2.h>
#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;
}

51
plat/rpi3/rpi3_hw.h Normal file
View File

@ -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 <utils_def.h>
/*
* 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__ */

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <bl_common.h>
#include <desc_image_load.h>
#include <platform.h>
#include <platform_def.h>
/*******************************************************************************
* 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();
}

251
plat/rpi3/rpi3_io_storage.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bl_common.h>
#include <debug.h>
#include <firmware_image_package.h>
#include <io_driver.h>
#include <io_fip.h>
#include <io_memmap.h>
#include <platform_def.h>
#include <string.h>
/* 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;
}

209
plat/rpi3/rpi3_pm.c Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <console.h>
#include <debug.h>
#include <mmio.h>
#include <platform_def.h>
#include <platform.h>
#include <psci.h>
#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;
}

35
plat/rpi3/rpi3_private.h Normal file
View File

@ -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 <sys/types.h>
/*******************************************************************************
* 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__ */

56
plat/rpi3/rpi3_topology.c Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <platform_def.h>
#include <sys/types.h>
#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);
}