diff options
Diffstat (limited to 'plat/fvp')
-rw-r--r-- | plat/fvp/aarch64/fvp_common.c | 251 | ||||
-rw-r--r-- | plat/fvp/aarch64/fvp_helpers.S | 186 | ||||
-rw-r--r-- | plat/fvp/bl1_fvp_setup.c | 152 | ||||
-rw-r--r-- | plat/fvp/bl2_fvp_setup.c | 298 | ||||
-rw-r--r-- | plat/fvp/bl31_fvp_setup.c | 257 | ||||
-rw-r--r-- | plat/fvp/bl32_fvp_setup.c | 101 | ||||
-rw-r--r-- | plat/fvp/drivers/pwrc/fvp_pwrc.c | 107 | ||||
-rw-r--r-- | plat/fvp/drivers/pwrc/fvp_pwrc.h | 77 | ||||
-rw-r--r-- | plat/fvp/fvp_def.h | 237 | ||||
-rw-r--r-- | plat/fvp/fvp_gic.c | 408 | ||||
-rw-r--r-- | plat/fvp/fvp_io_storage.c | 238 | ||||
-rw-r--r-- | plat/fvp/fvp_pm.c | 411 | ||||
-rw-r--r-- | plat/fvp/fvp_private.h | 109 | ||||
-rw-r--r-- | plat/fvp/fvp_security.c | 136 | ||||
-rw-r--r-- | plat/fvp/fvp_topology.c | 240 | ||||
-rw-r--r-- | plat/fvp/include/plat_macros.S | 57 | ||||
-rw-r--r-- | plat/fvp/include/platform_def.h | 180 | ||||
-rw-r--r-- | plat/fvp/platform.mk | 94 |
18 files changed, 3539 insertions, 0 deletions
diff --git a/plat/fvp/aarch64/fvp_common.c b/plat/fvp/aarch64/fvp_common.c new file mode 100644 index 0000000..3a07844 --- /dev/null +++ b/plat/fvp/aarch64/fvp_common.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <cci400.h> +#include <debug.h> +#include <mmio.h> +#include <platform.h> +#include <xlat_tables.h> +#include "../fvp_def.h" + +/******************************************************************************* + * This array holds the characteristics of the differences between the three + * FVP platforms (Base, A53_A57 & Foundation). It will be populated during cold + * boot at each boot stage by the primary before enabling the MMU (to allow cci + * configuration) & used thereafter. Each BL will have its own copy to allow + * independent operation. + ******************************************************************************/ +static unsigned long fvp_config[CONFIG_LIMIT]; + +/* + * Table of regions to map using the MMU. + * This doesn't include TZRAM as the 'mem_layout' argument passed to + * configure_mmu_elx() will give the available subset of that, + */ +const mmap_region_t fvp_mmap[] = { + { TZROM_BASE, TZROM_SIZE, MT_MEMORY | MT_RO | MT_SECURE }, + { TZDRAM_BASE, TZDRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE }, + { FLASH0_BASE, FLASH0_SIZE, MT_MEMORY | MT_RO | MT_SECURE }, + { FLASH1_BASE, FLASH1_SIZE, MT_MEMORY | MT_RO | MT_SECURE }, + { VRAM_BASE, VRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE }, + { DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + { NSRAM_BASE, NSRAM_SIZE, MT_MEMORY | MT_RW | MT_NS }, + { DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, + /* 2nd GB as device for now...*/ + { 0x40000000, 0x40000000, MT_DEVICE | MT_RW | MT_SECURE }, + { DRAM1_BASE, DRAM1_SIZE, MT_MEMORY | MT_RW | MT_NS }, + {0} +}; + +/******************************************************************************* + * Macro generating the code for the function setting up the pagetables as per + * the platform memory map & initialize the mmu, for the given exception level + ******************************************************************************/ +#define DEFINE_CONFIGURE_MMU_EL(_el) \ + void fvp_configure_mmu_el##_el(unsigned long total_base, \ + unsigned long total_size, \ + unsigned long ro_start, \ + unsigned long ro_limit, \ + unsigned long coh_start, \ + unsigned long coh_limit) \ + { \ + mmap_add_region(total_base, \ + total_size, \ + MT_MEMORY | MT_RW | MT_SECURE); \ + mmap_add_region(ro_start, ro_limit - ro_start, \ + MT_MEMORY | MT_RO | MT_SECURE); \ + mmap_add_region(coh_start, coh_limit - coh_start, \ + MT_DEVICE | MT_RW | MT_SECURE); \ + mmap_add(fvp_mmap); \ + init_xlat_tables(); \ + \ + enable_mmu_el##_el(); \ + } + +/* Define EL1 and EL3 variants of the function initialising the MMU */ +DEFINE_CONFIGURE_MMU_EL(1) +DEFINE_CONFIGURE_MMU_EL(3) + +/* Simple routine which returns a configuration variable value */ +unsigned long fvp_get_cfgvar(unsigned int var_id) +{ + assert(var_id < CONFIG_LIMIT); + return fvp_config[var_id]; +} + +/******************************************************************************* + * A single boot loader stack is expected to work on both the Foundation FVP + * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The + * SYS_ID register provides a mechanism for detecting the differences between + * these platforms. This information is stored in a per-BL array to allow the + * code to take the correct path.Per BL platform configuration. + ******************************************************************************/ +int fvp_config_setup(void) +{ + unsigned int rev, hbi, bld, arch, sys_id, midr_pn; + + sys_id = mmio_read_32(VE_SYSREGS_BASE + V2M_SYS_ID); + rev = (sys_id >> SYS_ID_REV_SHIFT) & SYS_ID_REV_MASK; + hbi = (sys_id >> SYS_ID_HBI_SHIFT) & SYS_ID_HBI_MASK; + bld = (sys_id >> SYS_ID_BLD_SHIFT) & SYS_ID_BLD_MASK; + arch = (sys_id >> SYS_ID_ARCH_SHIFT) & SYS_ID_ARCH_MASK; + + if ((rev != REV_FVP) || (arch != ARCH_MODEL)) + panic(); + + /* + * The build field in the SYS_ID tells which variant of the GIC + * memory is implemented by the model. + */ + switch (bld) { + case BLD_GIC_VE_MMAP: + fvp_config[CONFIG_GICD_ADDR] = VE_GICD_BASE; + fvp_config[CONFIG_GICC_ADDR] = VE_GICC_BASE; + fvp_config[CONFIG_GICH_ADDR] = VE_GICH_BASE; + fvp_config[CONFIG_GICV_ADDR] = VE_GICV_BASE; + break; + case BLD_GIC_A53A57_MMAP: + fvp_config[CONFIG_GICD_ADDR] = BASE_GICD_BASE; + fvp_config[CONFIG_GICC_ADDR] = BASE_GICC_BASE; + fvp_config[CONFIG_GICH_ADDR] = BASE_GICH_BASE; + fvp_config[CONFIG_GICV_ADDR] = BASE_GICV_BASE; + break; + default: + assert(0); + } + + /* + * The hbi field in the SYS_ID is 0x020 for the Base FVP & 0x010 + * for the Foundation FVP. + */ + switch (hbi) { + case HBI_FOUNDATION: + fvp_config[CONFIG_MAX_AFF0] = 4; + fvp_config[CONFIG_MAX_AFF1] = 1; + fvp_config[CONFIG_CPU_SETUP] = 0; + fvp_config[CONFIG_BASE_MMAP] = 0; + fvp_config[CONFIG_HAS_CCI] = 0; + fvp_config[CONFIG_HAS_TZC] = 0; + break; + case HBI_FVP_BASE: + midr_pn = (read_midr() >> MIDR_PN_SHIFT) & MIDR_PN_MASK; + if ((midr_pn == MIDR_PN_A57) || (midr_pn == MIDR_PN_A53)) + fvp_config[CONFIG_CPU_SETUP] = 1; + else + fvp_config[CONFIG_CPU_SETUP] = 0; + + fvp_config[CONFIG_MAX_AFF0] = 4; + fvp_config[CONFIG_MAX_AFF1] = 2; + fvp_config[CONFIG_BASE_MMAP] = 1; + fvp_config[CONFIG_HAS_CCI] = 1; + fvp_config[CONFIG_HAS_TZC] = 1; + break; + default: + assert(0); + } + + return 0; +} + +unsigned long plat_get_ns_image_entrypoint(void) +{ + return NS_IMAGE_OFFSET; +} + +uint64_t plat_get_syscnt_freq(void) +{ + uint64_t counter_base_frequency; + + /* Read the frequency from Frequency modes table */ + counter_base_frequency = mmio_read_32(SYS_CNTCTL_BASE + CNTFID_OFF); + + /* The first entry of the frequency modes table must not be 0 */ + assert(counter_base_frequency != 0); + + return counter_base_frequency; +} + +void fvp_cci_setup(void) +{ + unsigned long cci_setup; + + /* + * Enable CCI-400 for this cluster. No need + * for locks as no other cpu is active at the + * moment + */ + cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI); + if (cci_setup) + cci_enable_coherency(read_mpidr()); +} + + +/******************************************************************************* + * Set SPSR and secure state for BL32 image + ******************************************************************************/ +void fvp_set_bl32_ep_info(entry_point_info_t *bl32_ep_info) +{ + SET_SECURITY_STATE(bl32_ep_info->h.attr, SECURE); + /* + * The Secure Payload Dispatcher service is responsible for + * setting the SPSR prior to entry into the BL32 image. + */ + bl32_ep_info->spsr = 0; +} + +/******************************************************************************* + * Set SPSR and secure state for BL33 image + ******************************************************************************/ +void fvp_set_bl33_ep_info(entry_point_info_t *bl33_ep_info) +{ + unsigned long el_status; + unsigned int mode; + + /* Figure out what mode we enter the non-secure world in */ + el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; + el_status &= ID_AA64PFR0_ELX_MASK; + + if (el_status) + mode = MODE_EL2; + else + mode = MODE_EL1; + + /* + * TODO: Consider the possibility of specifying the SPSR in + * the FIP ToC and allowing the platform to have a say as + * well. + */ + bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE); +} diff --git a/plat/fvp/aarch64/fvp_helpers.S b/plat/fvp/aarch64/fvp_helpers.S new file mode 100644 index 0000000..f856f46 --- /dev/null +++ b/plat/fvp/aarch64/fvp_helpers.S @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <asm_macros.S> +#include <bl_common.h> +#include <gic_v2.h> +#include "../drivers/pwrc/fvp_pwrc.h" +#include "../fvp_def.h" + + .globl platform_get_entrypoint + .globl plat_secondary_cold_boot_setup + .globl platform_mem_init + .globl plat_report_exception + + .macro fvp_choose_gicmmap param1, param2, x_tmp, w_tmp, res + ldr \x_tmp, =VE_SYSREGS_BASE + V2M_SYS_ID + ldr \w_tmp, [\x_tmp] + ubfx \w_tmp, \w_tmp, #SYS_ID_BLD_SHIFT, #SYS_ID_BLD_LENGTH + cmp \w_tmp, #BLD_GIC_VE_MMAP + csel \res, \param1, \param2, eq + .endm + + /* ----------------------------------------------------- + * 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. + * TODO: Should we read the PSYS register to make sure + * that the request has gone through. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + /* --------------------------------------------- + * Power down this cpu. + * TODO: Do we need to worry about powering the + * cluster down as well here. That will need + * locks which we won't have unless an elf- + * loader zeroes out the zi section. + * --------------------------------------------- + */ + mrs x0, mpidr_el1 + ldr x1, =PWRC_BASE + str w0, [x1, #PPOFFR_OFF] + + /* --------------------------------------------- + * Deactivate the gic cpu interface as well + * --------------------------------------------- + */ + ldr x0, =VE_GICC_BASE + ldr x1, =BASE_GICC_BASE + fvp_choose_gicmmap x0, x1, x2, w2, x1 + mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1) + orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0) + str w0, [x1, #GICC_CTLR] + + /* --------------------------------------------- + * There is no sane reason to come out of this + * wfi so panic if we do. This cpu will be pow- + * ered on and reset by the cpu_on pm api + * --------------------------------------------- + */ + dsb sy + wfi +cb_panic: + b cb_panic + + + /* ----------------------------------------------------- + * void platform_get_entrypoint (unsigned int mpid); + * + * Main job of this routine is to distinguish between + * a cold and warm boot. + * On a cold boot the secondaries first wait for the + * platform to be initialized after which they are + * hotplugged in. The primary proceeds to perform the + * platform initialization. + * On a warm boot, each cpu jumps to the address in its + * mailbox. + * + * TODO: Not a good idea to save lr in a temp reg + * TODO: PSYSR is a common register and should be + * accessed using locks. Since its not possible + * to use locks immediately after a cold reset + * we are relying on the fact that after a cold + * reset all cpus will read the same WK field + * ----------------------------------------------------- + */ +func platform_get_entrypoint + mov x9, x30 // lr + mov x2, x0 + ldr x1, =PWRC_BASE + str w2, [x1, #PSYSR_OFF] + ldr w2, [x1, #PSYSR_OFF] + ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_MASK + cbnz w2, warm_reset + mov x0, x2 + b exit +warm_reset: + /* --------------------------------------------- + * A per-cpu mailbox is maintained in the tru- + * sted DRAM. Its flushed out of the caches + * after every update using normal memory so + * its safe to read it here with SO attributes + * --------------------------------------------- + */ + ldr x10, =TZDRAM_BASE + MBOX_OFF + bl platform_get_core_pos + lsl x0, x0, #CACHE_WRITEBACK_SHIFT + ldr x0, [x10, x0] + cbz x0, _panic +exit: + ret x9 +_panic: b _panic + + + /* ----------------------------------------------------- + * void platform_mem_init (void); + * + * Zero out the mailbox registers in the TZDRAM. The + * mmu is turned off right now and only the primary can + * ever execute this code. Secondaries will read the + * mailboxes using SO accesses. In short, BL31 will + * update the mailboxes after mapping the tzdram as + * normal memory. It will flush its copy after update. + * BL1 will always read the mailboxes with the MMU off + * ----------------------------------------------------- + */ +func platform_mem_init + ldr x0, =TZDRAM_BASE + MBOX_OFF + mov w1, #PLATFORM_CORE_COUNT +loop: + str xzr, [x0], #CACHE_WRITEBACK_GRANULE + subs w1, w1, #1 + b.gt loop + ret + + /* --------------------------------------------- + * void plat_report_exception(unsigned int type) + * Function to report an unhandled exception + * with platform-specific means. + * On FVP platform, it updates the LEDs + * to indicate where we are + * --------------------------------------------- + */ +func plat_report_exception + mrs x1, CurrentEl + lsr x1, x1, #MODE_EL_SHIFT + lsl x1, x1, #SYS_LED_EL_SHIFT + lsl x0, x0, #SYS_LED_EC_SHIFT + mov x2, #(SECURE << SYS_LED_SS_SHIFT) + orr x0, x0, x2 + orr x0, x0, x1 + mov x1, #VE_SYSREGS_BASE + add x1, x1, #V2M_SYS_LED + str w0, [x1] + ret diff --git a/plat/fvp/bl1_fvp_setup.c b/plat/fvp/bl1_fvp_setup.c new file mode 100644 index 0000000..f758082 --- /dev/null +++ b/plat/fvp/bl1_fvp_setup.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +extern unsigned long __BL1_RAM_START__; +extern unsigned long __BL1_RAM_END__; + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +#define BL1_RAM_BASE (unsigned long)(&__BL1_RAM_START__) +#define BL1_RAM_LIMIT (unsigned long)(&__BL1_RAM_END__) + + +/* 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) +{ + const unsigned long bl1_ram_base = BL1_RAM_BASE; + const unsigned long bl1_ram_limit = BL1_RAM_LIMIT; + const unsigned long tzram_limit = TZRAM_BASE + TZRAM_SIZE; + + /* Initialize the console to provide early debug support */ + console_init(PL011_UART0_BASE); + + /* + * Calculate how much ram is BL1 using & how much remains free. + * This also includes a rudimentary mechanism to detect whether + * the BL1 data is loaded at the top or bottom of memory. + * TODO: add support for discontigous chunks of free ram if + * needed. Might need dynamic memory allocation support + * et al. + */ + bl1_tzram_layout.total_base = TZRAM_BASE; + bl1_tzram_layout.total_size = TZRAM_SIZE; + + if (bl1_ram_limit == tzram_limit) { + /* BL1 has been loaded at the top of memory. */ + bl1_tzram_layout.free_base = TZRAM_BASE; + bl1_tzram_layout.free_size = bl1_ram_base - TZRAM_BASE; + } else { + /* BL1 has been loaded at the bottom of memory. */ + bl1_tzram_layout.free_base = bl1_ram_limit; + bl1_tzram_layout.free_size = + tzram_limit - bl1_ram_limit; + } + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} + +/******************************************************************************* + * Function which will evaluate how much of the trusted ram has been gobbled + * up by BL1 and return the base and size of whats available for loading BL2. + * Its called after coherency and the MMU have been turned on. + ******************************************************************************/ +void bl1_platform_setup(void) +{ + /* Initialise the IO layer and register platform IO devices */ + fvp_io_setup(); +} + + +/******************************************************************************* + * Perform the very early platform specific architecture setup here. At the + * moment this only does basic initialization. Later architectural setup + * (bl1_arch_setup()) does not do anything platform specific. + ******************************************************************************/ +void bl1_plat_arch_setup(void) +{ + fvp_cci_setup(); + + fvp_configure_mmu_el3(bl1_tzram_layout.total_base, + bl1_tzram_layout.total_size, + TZROM_BASE, + TZROM_BASE + TZROM_SIZE, + BL1_COHERENT_RAM_BASE, + BL1_COHERENT_RAM_LIMIT); +} + + +/******************************************************************************* + * Before calling this function BL2 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL2 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl1_plat_set_bl2_ep_info(image_info_t *bl2_image, + entry_point_info_t *bl2_ep) +{ + SET_SECURITY_STATE(bl2_ep->h.attr, SECURE); + bl2_ep->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); +} diff --git a/plat/fvp/bl2_fvp_setup.c b/plat/fvp/bl2_fvp_setup.c new file mode 100644 index 0000000..72580f9 --- /dev/null +++ b/plat/fvp/bl2_fvp_setup.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <console.h> +#include <platform.h> +#include <platform_def.h> +#include <string.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL2_RO_BASE (unsigned long)(&__RO_START__) +#define BL2_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL2_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL2_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +/* Pointer to memory visible to both BL2 and BL31 for passing data */ +extern unsigned char **bl2_el_change_mem_ptr; + +/* Data structure which holds the extents of the trusted SRAM for BL2 */ +static meminfo_t bl2_tzram_layout +__attribute__ ((aligned(PLATFORM_CACHE_LINE_SIZE), + section("tzfw_coherent_mem"))); + +/******************************************************************************* + * Reference to structures which holds the arguments which need to be passed + * to BL31 + ******************************************************************************/ +static bl31_params_t *bl2_to_bl31_params; +static entry_point_info_t *bl31_ep_info; + +meminfo_t *bl2_plat_sec_mem_layout(void) +{ + return &bl2_tzram_layout; +} + +/******************************************************************************* + * This function assigns a pointer to the memory that the platform has kept + * aside to pass platform specific and trusted firmware related information + * to BL31. This memory is allocated by allocating memory to + * bl2_to_bl31_params_mem_t structure which is a superset of all the + * structure whose information is passed to BL31 + * NOTE: This function should be called only once and should be done + * before generating params to BL31 + ******************************************************************************/ +bl31_params_t *bl2_plat_get_bl31_params(void) +{ + bl2_to_bl31_params_mem_t *bl31_params_mem; + +#if TSP_RAM_LOCATION_ID == TSP_IN_TZDRAM + /* + * Ensure that the secure DRAM memory used for passing BL31 arguments + * does not overlap with the BL32_BASE. + */ + assert(BL32_BASE > PARAMS_BASE + sizeof(bl2_to_bl31_params_mem_t)); +#endif + + /* + * Allocate the memory for all the arguments that needs to + * be passed to BL31 + */ + bl31_params_mem = (bl2_to_bl31_params_mem_t *)PARAMS_BASE; + memset((void *)PARAMS_BASE, 0, sizeof(bl2_to_bl31_params_mem_t)); + + /* Assign memory for TF related information */ + bl2_to_bl31_params = &bl31_params_mem->bl31_params; + SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0); + + /* Fill BL31 related information */ + bl31_ep_info = &bl31_params_mem->bl31_ep_info; + bl2_to_bl31_params->bl31_image_info = &bl31_params_mem->bl31_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + + /* Fill BL32 related information if it exists */ + if (BL32_BASE) { + bl2_to_bl31_params->bl32_ep_info = + &bl31_params_mem->bl32_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl32_image_info = + &bl31_params_mem->bl32_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, + PARAM_IMAGE_BINARY, + VERSION_1, 0); + } + + /* Fill BL33 related information */ + bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem->bl33_ep_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info, + PARAM_EP, VERSION_1, 0); + bl2_to_bl31_params->bl33_image_info = &bl31_params_mem->bl33_image_info; + SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY, + VERSION_1, 0); + + return bl2_to_bl31_params; +} + + +/******************************************************************************* + * This function returns a pointer to the shared memory that the platform + * has kept to point to entry point information of BL31 to BL2 + ******************************************************************************/ +struct entry_point_info *bl2_plat_get_bl31_ep_info(void) +{ +#if DEBUG + bl31_ep_info->args.arg1 = FVP_BL31_PLAT_PARAM_VAL; +#endif + return bl31_ep_info; +} + + +/******************************************************************************* + * 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 loaction 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(PL011_UART0_BASE); + + /* Setup the BL2 memory layout */ + bl2_tzram_layout.total_base = mem_layout->total_base; + bl2_tzram_layout.total_size = mem_layout->total_size; + bl2_tzram_layout.free_base = mem_layout->free_base; + bl2_tzram_layout.free_size = mem_layout->free_size; + bl2_tzram_layout.attr = mem_layout->attr; + bl2_tzram_layout.next = 0; + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} + +/******************************************************************************* + * Perform platform specific setup. For now just initialize the memory location + * to use for passing arguments to BL31. + ******************************************************************************/ +void bl2_platform_setup(void) +{ + /* + * Do initial security configuration to allow DRAM/device access. On + * Base FVP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + fvp_security_setup(); + + /* Initialise the IO layer and register platform IO devices */ + fvp_io_setup(); +} + +/* Flush the TF params and the TF plat params */ +void bl2_plat_flush_bl31_params(void) +{ + flush_dcache_range((unsigned long)PARAMS_BASE, \ + sizeof(bl2_to_bl31_params_mem_t)); +} + + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bl2_plat_arch_setup() +{ + fvp_configure_mmu_el1(bl2_tzram_layout.total_base, + bl2_tzram_layout.total_size, + BL2_RO_BASE, + BL2_RO_LIMIT, + BL2_COHERENT_RAM_BASE, + BL2_COHERENT_RAM_LIMIT); +} + +/******************************************************************************* + * Before calling this function BL31 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL31 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl31_ep_info(image_info_t *bl31_image_info, + entry_point_info_t *bl31_ep_info) +{ + SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE); + bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); +} + + +/******************************************************************************* + * Before calling this function BL32 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL32 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl32_ep_info(image_info_t *bl32_image_info, + entry_point_info_t *bl32_ep_info) +{ + fvp_set_bl32_ep_info(bl32_ep_info); +} + +/******************************************************************************* + * Before calling this function BL33 is loaded in memory and its entrypoint + * is set by load_image. This is a placeholder for the platform to change + * the entrypoint of BL33 and set SPSR and security state. + * On FVP we are only setting the security state, entrypoint + ******************************************************************************/ +void bl2_plat_set_bl33_ep_info(image_info_t *image, + entry_point_info_t *bl33_ep_info) +{ + fvp_set_bl33_ep_info(bl33_ep_info); +} + + +/******************************************************************************* + * Populate the extents of memory available for loading BL32 + ******************************************************************************/ +void bl2_plat_get_bl32_meminfo(meminfo_t *bl32_meminfo) +{ + /* + * Populate the extents of memory available for loading BL32. + */ + bl32_meminfo->total_base = BL32_BASE; + bl32_meminfo->free_base = BL32_BASE; + bl32_meminfo->total_size = + (TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE; + bl32_meminfo->free_size = + (TSP_SEC_MEM_BASE + TSP_SEC_MEM_SIZE) - BL32_BASE; + bl32_meminfo->attr = BOT_LOAD; + bl32_meminfo->next = 0; +} + + +/******************************************************************************* + * Populate the extents of memory available for loading BL33 + ******************************************************************************/ +void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo) +{ + bl33_meminfo->total_base = DRAM_BASE; + bl33_meminfo->total_size = DRAM_SIZE - DRAM1_SEC_SIZE; + bl33_meminfo->free_base = DRAM_BASE; + bl33_meminfo->free_size = DRAM_SIZE - DRAM1_SEC_SIZE; + bl33_meminfo->attr = 0; + bl33_meminfo->attr = 0; +} diff --git a/plat/fvp/bl31_fvp_setup.c b/plat/fvp/bl31_fvp_setup.c new file mode 100644 index 0000000..6554ec3 --- /dev/null +++ b/plat/fvp/bl31_fvp_setup.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <bl31.h> +#include <console.h> +#include <mmio.h> +#include <platform.h> +#include <stddef.h> +#include "drivers/pwrc/fvp_pwrc.h" +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL31_RO_BASE (unsigned long)(&__RO_START__) +#define BL31_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols + * refer to page-aligned addresses. + */ +#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + + +#if RESET_TO_BL31 +static entry_point_info_t bl32_entrypoint_info; +static entry_point_info_t bl33_entrypoint_info; +#else +/******************************************************************************* + * Reference to structure which holds the arguments that have been passed to + * BL31 from BL2. + ******************************************************************************/ +static bl31_params_t *bl2_to_bl31_params; +#endif + +/******************************************************************************* + * 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; + +#if RESET_TO_BL31 + + if (type == NON_SECURE) + fvp_get_entry_point_info(NON_SECURE, &bl33_entrypoint_info); + else + fvp_get_entry_point_info(SECURE, &bl32_entrypoint_info); + + next_image_info = (type == NON_SECURE) ? + &bl33_entrypoint_info : + &bl32_entrypoint_info; +#else + next_image_info = (type == NON_SECURE) ? + bl2_to_bl31_params->bl33_ep_info : + bl2_to_bl31_params->bl32_ep_info; +#endif + + + /* None of the images on this platform can have 0x0 as the entrypoint */ + if (next_image_info->pc) + return next_image_info; + else + return NULL; +} + +/******************************************************************************* + * Perform any BL31 specific platform actions. 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. On the FVP + * we know that BL2 has populated the parameters in secure DRAM. So we just use + * the reference passed in 'from_bl2' instead of copying. The 'data' parameter + * is not used since all the information is contained in 'from_bl2'. Also, BL2 + * has flushed this information to memory, so we are guaranteed to pick up good + * data + ******************************************************************************/ +void bl31_early_platform_setup(bl31_params_t *from_bl2, + void *plat_params_from_bl2) +{ + /* Initialize the console to provide early debug support */ + console_init(PL011_UART0_BASE); + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); + +#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); + + + /* + * Do initial security configuration to allow DRAM/device access. On + * Base FVP only DRAM security is programmable (via TrustZone), but + * other platforms might have more programmable security devices + * present. + */ + fvp_security_setup(); +#else + /* Check params passed from BL2 should not be NULL, + * We are not checking plat_params_from_bl2 as NULL as we are not + * using it on FVP + */ + assert(from_bl2 != NULL); + assert(from_bl2->h.type == PARAM_BL31); + assert(from_bl2->h.version >= VERSION_1); + + bl2_to_bl31_params = from_bl2; + assert(((unsigned long)plat_params_from_bl2) == FVP_BL31_PLAT_PARAM_VAL); +#endif +} + +/******************************************************************************* + * Initialize the gic, configure the CLCD and zero out variables needed by the + * secondaries to boot up correctly. + ******************************************************************************/ +void bl31_platform_setup() +{ + unsigned int reg_val; + + /* Initialize the gic cpu and distributor interfaces */ + gic_setup(); + + /* + * TODO: Configure the CLCD before handing control to + * linux. Need to see if a separate driver is needed + * instead. + */ + mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGDATA, 0); + mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGCTRL, + (1ull << 31) | (1 << 30) | (7 << 20) | (0 << 16)); + + /* Enable and initialize the System level generic timer */ + mmio_write_32(SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0) | CNTCR_EN); + + /* Allow access to the System counter timer module */ + reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); + reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); + reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val); + + reg_val = (1 << CNTNSAR_NS_SHIFT(0)) | (1 << CNTNSAR_NS_SHIFT(1)); + mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val); + + /* Intialize the power controller */ + fvp_pwrc_setup(); + + /* Topologies are best known to the platform. */ + fvp_setup_topology(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bl31_plat_arch_setup() +{ +#if RESET_TO_BL31 + fvp_cci_setup(); + +#endif + fvp_configure_mmu_el3(BL31_RO_BASE, + (BL31_COHERENT_RAM_LIMIT - BL31_RO_BASE), + BL31_RO_BASE, + BL31_RO_LIMIT, + BL31_COHERENT_RAM_BASE, + BL31_COHERENT_RAM_LIMIT); +} + +#if RESET_TO_BL31 +/******************************************************************************* + * Generate the entry point info for Non Secure and Secure images + * for transferring control from BL31 + ******************************************************************************/ +void fvp_get_entry_point_info(unsigned long target_security, + entry_point_info_t *target_entry_info) +{ + if (target_security == NON_SECURE) { + SET_PARAM_HEAD(target_entry_info, + PARAM_EP, + VERSION_1, + 0); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + target_entry_info->pc = plat_get_ns_image_entrypoint(); + + fvp_set_bl33_ep_info(target_entry_info); + + } else { + SET_PARAM_HEAD(target_entry_info, + PARAM_EP, + VERSION_1, + 0); + if (BL32_BASE != 0) { + /* Hard coding entry point to the base of the BL32 */ + target_entry_info->pc = BL32_BASE; + fvp_set_bl32_ep_info(target_entry_info); + } + } +} +#endif diff --git a/plat/fvp/bl32_fvp_setup.c b/plat/fvp/bl32_fvp_setup.c new file mode 100644 index 0000000..f8dc3c7 --- /dev/null +++ b/plat/fvp/bl32_fvp_setup.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bl_common.h> +#include <console.h> +#include <platform.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * Declarations of linker defined symbols which will help us find the layout + * of trusted SRAM + ******************************************************************************/ +extern unsigned long __RO_START__; +extern unsigned long __RO_END__; + +extern unsigned long __COHERENT_RAM_START__; +extern unsigned long __COHERENT_RAM_END__; + +/* + * The next 2 constants identify the extents of the code & RO data region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. + */ +#define BL32_RO_BASE (unsigned long)(&__RO_START__) +#define BL32_RO_LIMIT (unsigned long)(&__RO_END__) + +/* + * The next 2 constants identify the extents of the coherent memory region. + * These addresses are used by the MMU setup code and therefore they must be + * page-aligned. It is the responsibility of the linker script to ensure that + * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to + * page-aligned addresses. + */ +#define BL32_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__) +#define BL32_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__) + +/******************************************************************************* + * Initialize the UART + ******************************************************************************/ +void bl32_early_platform_setup(void) +{ + /* + * Initialize a different console than already in use to display + * messages from TSP + */ + console_init(PL011_UART1_BASE); + + /* Initialize the platform config for future decision making */ + fvp_config_setup(); +} + +/******************************************************************************* + * Perform platform specific setup placeholder + ******************************************************************************/ +void bl32_platform_setup() +{ + +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only intializes the MMU + ******************************************************************************/ +void bl32_plat_arch_setup() +{ + fvp_configure_mmu_el1(BL32_RO_BASE, + (BL32_COHERENT_RAM_LIMIT - BL32_RO_BASE), + BL32_RO_BASE, + BL32_RO_LIMIT, + BL32_COHERENT_RAM_BASE, + BL32_COHERENT_RAM_LIMIT); +} diff --git a/plat/fvp/drivers/pwrc/fvp_pwrc.c b/plat/fvp/drivers/pwrc/fvp_pwrc.c new file mode 100644 index 0000000..d1feece --- /dev/null +++ b/plat/fvp/drivers/pwrc/fvp_pwrc.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bakery_lock.h> +#include <mmio.h> +#include "../../fvp_def.h" +#include "fvp_pwrc.h" + +/* + * TODO: Someday there will be a generic power controller api. At the moment + * each platform has its own pwrc so just exporting functions is fine. + */ +static bakery_lock_t pwrc_lock __attribute__ ((section("tzfw_coherent_mem"))); + +unsigned int fvp_pwrc_get_cpu_wkr(unsigned long mpidr) +{ + unsigned int rc = 0; + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr); + rc = PSYSR_WK(mmio_read_32(PWRC_BASE + PSYSR_OFF)); + bakery_lock_release(mpidr, &pwrc_lock); + return rc; +} + +unsigned int fvp_pwrc_read_psysr(unsigned long mpidr) +{ + unsigned int rc = 0; + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr); + rc = mmio_read_32(PWRC_BASE + PSYSR_OFF); + bakery_lock_release(mpidr, &pwrc_lock); + return rc; +} + +void fvp_pwrc_write_pponr(unsigned long mpidr) +{ + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr); + bakery_lock_release(mpidr, &pwrc_lock); +} + +void fvp_pwrc_write_ppoffr(unsigned long mpidr) +{ + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr); + bakery_lock_release(mpidr, &pwrc_lock); +} + +void fvp_pwrc_set_wen(unsigned long mpidr) +{ + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PWKUPR_OFF, + (unsigned int) (PWKUPR_WEN | mpidr)); + bakery_lock_release(mpidr, &pwrc_lock); +} + +void fvp_pwrc_clr_wen(unsigned long mpidr) +{ + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PWKUPR_OFF, + (unsigned int) mpidr); + bakery_lock_release(mpidr, &pwrc_lock); +} + +void fvp_pwrc_write_pcoffr(unsigned long mpidr) +{ + bakery_lock_get(mpidr, &pwrc_lock); + mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr); + bakery_lock_release(mpidr, &pwrc_lock); +} + +/* Nothing else to do here apart from initializing the lock */ +int fvp_pwrc_setup(void) +{ + bakery_lock_init(&pwrc_lock); + return 0; +} + + + diff --git a/plat/fvp/drivers/pwrc/fvp_pwrc.h b/plat/fvp/drivers/pwrc/fvp_pwrc.h new file mode 100644 index 0000000..ad1ea85 --- /dev/null +++ b/plat/fvp/drivers/pwrc/fvp_pwrc.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FVP_PWRC_H__ +#define __FVP_PWRC_H__ + +/* FVP Power controller register offset etc */ +#define PPOFFR_OFF 0x0 +#define PPONR_OFF 0x4 +#define PCOFFR_OFF 0x8 +#define PWKUPR_OFF 0xc +#define PSYSR_OFF 0x10 + +#define PWKUPR_WEN (1ull << 31) + +#define PSYSR_AFF_L2 (1 << 31) +#define PSYSR_AFF_L1 (1 << 30) +#define PSYSR_AFF_L0 (1 << 29) +#define PSYSR_WEN (1 << 28) +#define PSYSR_PC (1 << 27) +#define PSYSR_PP (1 << 26) + +#define PSYSR_WK_SHIFT 24 +#define PSYSR_WK_MASK 0x3 +#define PSYSR_WK(x) (x >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK + +#define WKUP_COLD 0x0 +#define WKUP_RESET 0x1 +#define WKUP_PPONR 0x2 +#define WKUP_GICREQ 0x3 + +#define PSYSR_INVALID 0xffffffff + +#ifndef __ASSEMBLY__ + +/******************************************************************************* + * Function & variable prototypes + ******************************************************************************/ +int fvp_pwrc_setup(void); +void fvp_pwrc_write_pcoffr(unsigned long); +void fvp_pwrc_write_ppoffr(unsigned long); +void fvp_pwrc_write_pponr(unsigned long); +void fvp_pwrc_set_wen(unsigned long); +void fvp_pwrc_clr_wen(unsigned long); +unsigned int fvp_pwrc_read_psysr(unsigned long); +unsigned int fvp_pwrc_get_cpu_wkr(unsigned long); + +#endif /*__ASSEMBLY__*/ + +#endif /* __FVP_PWRC_H__ */ diff --git a/plat/fvp/fvp_def.h b/plat/fvp/fvp_def.h new file mode 100644 index 0000000..04ba611 --- /dev/null +++ b/plat/fvp/fvp_def.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FVP_DEF_H__ +#define __FVP_DEF_H__ + +#include <platform_def.h> /* for TZROM_SIZE */ + + +/* Firmware Image Package */ +#define FIP_IMAGE_NAME "fip.bin" + +/* Constants for accessing platform configuration */ +#define CONFIG_GICD_ADDR 0 +#define CONFIG_GICC_ADDR 1 +#define CONFIG_GICH_ADDR 2 +#define CONFIG_GICV_ADDR 3 +#define CONFIG_MAX_AFF0 4 +#define CONFIG_MAX_AFF1 5 +/* Indicate whether the CPUECTLR SMP bit should be enabled. */ +#define CONFIG_CPU_SETUP 6 +#define CONFIG_BASE_MMAP 7 +/* Indicates whether CCI should be enabled on the platform. */ +#define CONFIG_HAS_CCI 8 +#define CONFIG_HAS_TZC 9 +#define CONFIG_LIMIT 10 + +/******************************************************************************* + * FVP memory map related constants + ******************************************************************************/ + +#define FLASH0_BASE 0x08000000 +#define FLASH0_SIZE TZROM_SIZE + +#define FLASH1_BASE 0x0c000000 +#define FLASH1_SIZE 0x04000000 + +#define PSRAM_BASE 0x14000000 +#define PSRAM_SIZE 0x04000000 + +#define VRAM_BASE 0x18000000 +#define VRAM_SIZE 0x02000000 + +/* Aggregate of all devices in the first GB */ +#define DEVICE0_BASE 0x1a000000 +#define DEVICE0_SIZE 0x12200000 + +#define DEVICE1_BASE 0x2f000000 +#define DEVICE1_SIZE 0x200000 + +#define NSRAM_BASE 0x2e000000 +#define NSRAM_SIZE 0x10000 + +#define MBOX_OFF 0x1000 + +/* Base address where parameters to BL31 are stored */ +#define PARAMS_BASE TZDRAM_BASE + +#define DRAM1_BASE 0x80000000ull +#define DRAM1_SIZE 0x80000000ull +#define DRAM1_END (DRAM1_BASE + DRAM1_SIZE - 1) +#define DRAM1_SEC_SIZE 0x01000000ull + +#define DRAM_BASE DRAM1_BASE +#define DRAM_SIZE DRAM1_SIZE + +#define DRAM2_BASE 0x880000000ull +#define DRAM2_SIZE 0x780000000ull +#define DRAM2_END (DRAM2_BASE + DRAM2_SIZE - 1) + +#define PCIE_EXP_BASE 0x40000000 +#define TZRNG_BASE 0x7fe60000 +#define TZNVCTR_BASE 0x7fe70000 +#define TZROOTKEY_BASE 0x7fe80000 + +/* Memory mapped Generic timer interfaces */ +#define SYS_CNTCTL_BASE 0x2a430000 +#define SYS_CNTREAD_BASE 0x2a800000 +#define SYS_TIMCTL_BASE 0x2a810000 + +/* V2M motherboard system registers & offsets */ +#define VE_SYSREGS_BASE 0x1c010000 +#define V2M_SYS_ID 0x0 +#define V2M_SYS_LED 0x8 +#define V2M_SYS_CFGDATA 0xa0 +#define V2M_SYS_CFGCTRL 0xa4 + +/* Load address of BL33 in the FVP port */ +#define NS_IMAGE_OFFSET (DRAM1_BASE + 0x8000000) /* DRAM + 128MB */ + +/* Special value used to verify platform parameters from BL2 to BL3-1 */ +#define FVP_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL + +/* + * V2M sysled bit definitions. The values written to this + * register are defined in arch.h & runtime_svc.h. Only + * used by the primary cpu to diagnose any cold boot issues. + * + * SYS_LED[0] - Security state (S=0/NS=1) + * SYS_LED[2:1] - Exception Level (EL3-EL0) + * SYS_LED[7:3] - Exception Class (Sync/Async & origin) + * + */ +#define SYS_LED_SS_SHIFT 0x0 +#define SYS_LED_EL_SHIFT 0x1 +#define SYS_LED_EC_SHIFT 0x3 + +#define SYS_LED_SS_MASK 0x1 +#define SYS_LED_EL_MASK 0x3 +#define SYS_LED_EC_MASK 0x1f + +/* V2M sysid register bits */ +#define SYS_ID_REV_SHIFT 27 +#define SYS_ID_HBI_SHIFT 16 +#define SYS_ID_BLD_SHIFT 12 +#define SYS_ID_ARCH_SHIFT 8 +#define SYS_ID_FPGA_SHIFT 0 + +#define SYS_ID_REV_MASK 0xf +#define SYS_ID_HBI_MASK 0xfff +#define SYS_ID_BLD_MASK 0xf +#define SYS_ID_ARCH_MASK 0xf +#define SYS_ID_FPGA_MASK 0xff + +#define SYS_ID_BLD_LENGTH 4 + +#define REV_FVP 0x0 +#define HBI_FVP_BASE 0x020 +#define HBI_FOUNDATION 0x010 + +#define BLD_GIC_VE_MMAP 0x0 +#define BLD_GIC_A53A57_MMAP 0x1 + +#define ARCH_MODEL 0x1 + +/* FVP Power controller base address*/ +#define PWRC_BASE 0x1c100000 + + +/******************************************************************************* + * CCI-400 related constants + ******************************************************************************/ +#define CCI400_BASE 0x2c090000 +#define CCI400_SL_IFACE_CLUSTER0 3 +#define CCI400_SL_IFACE_CLUSTER1 4 +#define CCI400_SL_IFACE_INDEX(mpidr) (mpidr & MPIDR_CLUSTER_MASK ? \ + CCI400_SL_IFACE_CLUSTER1 : \ + CCI400_SL_IFACE_CLUSTER0) + +/******************************************************************************* + * GIC-400 & interrupt handling related constants + ******************************************************************************/ +/* VE compatible GIC memory map */ +#define VE_GICD_BASE 0x2c001000 +#define VE_GICC_BASE 0x2c002000 +#define VE_GICH_BASE 0x2c004000 +#define VE_GICV_BASE 0x2c006000 + +/* Base FVP compatible GIC memory map */ +#define BASE_GICD_BASE 0x2f000000 +#define BASE_GICR_BASE 0x2f100000 +#define BASE_GICC_BASE 0x2c000000 +#define BASE_GICH_BASE 0x2c010000 +#define BASE_GICV_BASE 0x2c02f000 + +#define IRQ_TZ_WDOG 56 +#define IRQ_SEC_PHY_TIMER 29 +#define IRQ_SEC_SGI_0 8 +#define IRQ_SEC_SGI_1 9 +#define IRQ_SEC_SGI_2 10 +#define IRQ_SEC_SGI_3 11 +#define IRQ_SEC_SGI_4 12 +#define IRQ_SEC_SGI_5 13 +#define IRQ_SEC_SGI_6 14 +#define IRQ_SEC_SGI_7 15 +#define IRQ_SEC_SGI_8 16 + +/******************************************************************************* + * PL011 related constants + ******************************************************************************/ +#define PL011_UART0_BASE 0x1c090000 +#define PL011_UART1_BASE 0x1c0a0000 +#define PL011_UART2_BASE 0x1c0b0000 +#define PL011_UART3_BASE 0x1c0c0000 + +/******************************************************************************* + * TrustZone address space controller related constants + ******************************************************************************/ +#define TZC400_BASE 0x2a4a0000 + +/* + * The NSAIDs for this platform as used to program the TZC400. + */ + +/* The FVP has 4 bits of NSAIDs. Used with TZC FAIL_ID (ACE Lite ID width) */ +#define FVP_AID_WIDTH 4 + +/* NSAIDs used by devices in TZC filter 0 on FVP */ +#define FVP_NSAID_DEFAULT 0 +#define FVP_NSAID_PCI 1 +#define FVP_NSAID_VIRTIO 8 /* from FVP v5.6 onwards */ +#define FVP_NSAID_AP 9 /* Application Processors */ +#define FVP_NSAID_VIRTIO_OLD 15 /* until FVP v5.5 */ + +/* NSAIDs used by devices in TZC filter 2 on FVP */ +#define FVP_NSAID_HDLCD0 2 +#define FVP_NSAID_CLCD 7 + + +#endif /* __FVP_DEF_H__ */ diff --git a/plat/fvp/fvp_gic.c b/plat/fvp/fvp_gic.c new file mode 100644 index 0000000..3156da9 --- /dev/null +++ b/plat/fvp/fvp_gic.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> +#include <debug.h> +#include <gic_v2.h> +#include <gic_v3.h> +#include <interrupt_mgmt.h> +#include <platform.h> +#include <stdint.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * This function does some minimal GICv3 configuration. The Firmware itself does + * not fully support GICv3 at this time and relies on GICv2 emulation as + * provided by GICv3. This function allows software (like Linux) in later stages + * to use full GICv3 features. + ******************************************************************************/ +void gicv3_cpuif_setup(void) +{ + unsigned int scr_val, val; + uintptr_t base; + + /* + * When CPUs come out of reset they have their GICR_WAKER.ProcessorSleep + * bit set. In order to allow interrupts to get routed to the CPU we + * need to clear this bit if set and wait for GICR_WAKER.ChildrenAsleep + * to clear (GICv3 Architecture specification 5.4.23). + * GICR_WAKER is NOT banked per CPU, compute the correct base address + * per CPU. + */ + base = gicv3_get_rdist(BASE_GICR_BASE, read_mpidr()); + if (base == (uintptr_t)NULL) { + /* No re-distributor base address. This interface cannot be + * configured. + */ + panic(); + } + + val = gicr_read_waker(base); + + val &= ~WAKER_PS; + gicr_write_waker(base, val); + dsb(); + + /* We need to wait for ChildrenAsleep to clear. */ + val = gicr_read_waker(base); + while (val & WAKER_CA) { + val = gicr_read_waker(base); + } + + /* + * We need to set SCR_EL3.NS in order to see GICv3 non-secure state. + * Restore SCR_EL3.NS again before exit. + */ + scr_val = read_scr(); + write_scr(scr_val | SCR_NS_BIT); + isb(); /* ensure NS=1 takes effect before accessing ICC_SRE_EL2 */ + + /* + * By default EL2 and NS-EL1 software should be able to enable GICv3 + * System register access without any configuration at EL3. But it turns + * out that GICC PMR as set in GICv2 mode does not affect GICv3 mode. So + * we need to set it here again. In order to do that we need to enable + * register access. We leave it enabled as it should be fine and might + * prevent problems with later software trying to access GIC System + * Registers. + */ + val = read_icc_sre_el3(); + write_icc_sre_el3(val | ICC_SRE_EN | ICC_SRE_SRE); + + val = read_icc_sre_el2(); + write_icc_sre_el2(val | ICC_SRE_EN | ICC_SRE_SRE); + + write_icc_pmr_el1(GIC_PRI_MASK); + isb(); /* commite ICC_* changes before setting NS=0 */ + + /* Restore SCR_EL3 */ + write_scr(scr_val); + isb(); /* ensure NS=0 takes effect immediately */ +} + +/******************************************************************************* + * This function does some minimal GICv3 configuration when cores go + * down. + ******************************************************************************/ +void gicv3_cpuif_deactivate(void) +{ + unsigned int val; + uintptr_t base; + + /* + * When taking CPUs down we need to set GICR_WAKER.ProcessorSleep and + * wait for GICR_WAKER.ChildrenAsleep to get set. + * (GICv3 Architecture specification 5.4.23). + * GICR_WAKER is NOT banked per CPU, compute the correct base address + * per CPU. + */ + base = gicv3_get_rdist(BASE_GICR_BASE, read_mpidr()); + if (base == (uintptr_t)NULL) { + /* No re-distributor base address. This interface cannot be + * configured. + */ + panic(); + } + + val = gicr_read_waker(base); + val |= WAKER_PS; + gicr_write_waker(base, val); + dsb(); + + /* We need to wait for ChildrenAsleep to set. */ + val = gicr_read_waker(base); + while ((val & WAKER_CA) == 0) { + val = gicr_read_waker(base); + } +} + + +/******************************************************************************* + * Enable secure interrupts and use FIQs to route them. Disable legacy bypass + * and set the priority mask register to allow all interrupts to trickle in. + ******************************************************************************/ +void gic_cpuif_setup(unsigned int gicc_base) +{ + unsigned int val; + + val = gicc_read_iidr(gicc_base); + + /* + * If GICv3 we need to do a bit of additional setup. We want to + * allow default GICv2 behaviour but allow the next stage to + * enable full gicv3 features. + */ + if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) { + gicv3_cpuif_setup(); + } + + val = ENABLE_GRP0 | FIQ_EN | FIQ_BYP_DIS_GRP0; + val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; + + gicc_write_pmr(gicc_base, GIC_PRI_MASK); + gicc_write_ctlr(gicc_base, val); +} + +/******************************************************************************* + * Place the cpu interface in a state where it can never make a cpu exit wfi as + * as result of an asserted interrupt. This is critical for powering down a cpu + ******************************************************************************/ +void gic_cpuif_deactivate(unsigned int gicc_base) +{ + unsigned int val; + + /* Disable secure, non-secure interrupts and disable their bypass */ + val = gicc_read_ctlr(gicc_base); + val &= ~(ENABLE_GRP0 | ENABLE_GRP1); + val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; + val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; + gicc_write_ctlr(gicc_base, val); + + val = gicc_read_iidr(gicc_base); + + /* + * If GICv3 we need to do a bit of additional setup. Make sure the + * RDIST is put to sleep. + */ + if (((val >> GICC_IIDR_ARCH_SHIFT) & GICC_IIDR_ARCH_MASK) >= 3) { + gicv3_cpuif_deactivate(); + } +} + +/******************************************************************************* + * Per cpu gic distributor setup which will be done by all cpus after a cold + * boot/hotplug. This marks out the secure interrupts & enables them. + ******************************************************************************/ +void gic_pcpu_distif_setup(unsigned int gicd_base) +{ + gicd_write_igroupr(gicd_base, 0, ~0); + + gicd_clr_igroupr(gicd_base, IRQ_SEC_PHY_TIMER); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_0); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_1); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_2); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_3); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_4); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_5); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_6); + gicd_clr_igroupr(gicd_base, IRQ_SEC_SGI_7); + + gicd_set_ipriorityr(gicd_base, IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_ipriorityr(gicd_base, IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY); + + gicd_set_isenabler(gicd_base, IRQ_SEC_PHY_TIMER); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_0); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_1); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_2); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_3); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_4); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_5); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_6); + gicd_set_isenabler(gicd_base, IRQ_SEC_SGI_7); +} + +/******************************************************************************* + * Global gic distributor setup which will be done by the primary cpu after a + * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It + * then enables the secure GIC distributor interface. + ******************************************************************************/ +void gic_distif_setup(unsigned int gicd_base) +{ + unsigned int ctr, num_ints, ctlr; + + /* Disable the distributor before going further */ + ctlr = gicd_read_ctlr(gicd_base); + ctlr &= ~(ENABLE_GRP0 | ENABLE_GRP1); + gicd_write_ctlr(gicd_base, ctlr); + + /* + * Mark out non-secure interrupts. Calculate number of + * IGROUPR registers to consider. Will be equal to the + * number of IT_LINES + */ + num_ints = gicd_read_typer(gicd_base) & IT_LINES_NO_MASK; + num_ints++; + for (ctr = 0; ctr < num_ints; ctr++) + gicd_write_igroupr(gicd_base, ctr << IGROUPR_SHIFT, ~0); + + /* Configure secure interrupts now */ + gicd_clr_igroupr(gicd_base, IRQ_TZ_WDOG); + gicd_set_ipriorityr(gicd_base, IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY); + gicd_set_itargetsr(gicd_base, IRQ_TZ_WDOG, + platform_get_core_pos(read_mpidr())); + gicd_set_isenabler(gicd_base, IRQ_TZ_WDOG); + gic_pcpu_distif_setup(gicd_base); + + gicd_write_ctlr(gicd_base, ctlr | ENABLE_GRP0); +} + +void gic_setup(void) +{ + unsigned int gicd_base, gicc_base; + + gicd_base = fvp_get_cfgvar(CONFIG_GICD_ADDR); + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + + gic_cpuif_setup(gicc_base); + gic_distif_setup(gicd_base); +} + +/******************************************************************************* + * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. + * The interrupt controller knows which pin/line it uses to signal a type of + * interrupt. The platform knows which interrupt controller type is being used + * in a particular security state e.g. with an ARM GIC, normal world could use + * the GICv2 features while the secure world could use GICv3 features and vice + * versa. + * This function is exported by the platform to let the interrupt management + * framework determine for a type of interrupt and security state, which line + * should be used in the SCR_EL3 to control its routing to EL3. The interrupt + * line is represented as the bit position of the IRQ or FIQ bit in the SCR_EL3. + ******************************************************************************/ +uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) +{ + uint32_t gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + + assert(type == INTR_TYPE_S_EL1 || + type == INTR_TYPE_EL3 || + type == INTR_TYPE_NS); + + assert(security_state == NON_SECURE || security_state == SECURE); + + /* + * We ignore the security state parameter under the assumption that + * both normal and secure worlds are using ARM GICv2. This parameter + * will be used when the secure world starts using GICv3. + */ +#if FVP_GIC_ARCH == 2 + return gicv2_interrupt_type_to_line(gicc_base, type); +#else +#error "Invalid GIC architecture version specified for FVP port" +#endif +} + +#if FVP_GIC_ARCH == 2 +/******************************************************************************* + * This function returns the type of the highest priority pending interrupt at + * the GIC cpu interface. INTR_TYPE_INVAL is returned when there is no + * interrupt pending. + ******************************************************************************/ +uint32_t plat_ic_get_pending_interrupt_type() +{ + uint32_t id, gicc_base; + + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + id = gicc_read_hppir(gicc_base); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + if (id < 1022) + return INTR_TYPE_S_EL1; + + if (id == GIC_SPURIOUS_INTERRUPT) + return INTR_TYPE_INVAL; + + return INTR_TYPE_NS; +} + +/******************************************************************************* + * This function returns the id of the highest priority pending interrupt at + * the GIC cpu interface. INTR_ID_UNAVAILABLE is returned when there is no + * interrupt pending. + ******************************************************************************/ +uint32_t plat_ic_get_pending_interrupt_id() +{ + uint32_t id, gicc_base; + + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + id = gicc_read_hppir(gicc_base); + + if (id < 1022) + return id; + + if (id == 1023) + return INTR_ID_UNAVAILABLE; + + /* + * Find out which non-secure interrupt it is under the assumption that + * the GICC_CTLR.AckCtl bit is 0. + */ + return gicc_read_ahppir(gicc_base); +} + +/******************************************************************************* + * This functions reads the GIC cpu interface Interrupt Acknowledge register + * to start handling the pending interrupt. It returns the contents of the IAR. + ******************************************************************************/ +uint32_t plat_ic_acknowledge_interrupt() +{ + return gicc_read_IAR(fvp_get_cfgvar(CONFIG_GICC_ADDR)); +} + +/******************************************************************************* + * This functions writes the GIC cpu interface End Of Interrupt register with + * the passed value to finish handling the active interrupt + ******************************************************************************/ +void plat_ic_end_of_interrupt(uint32_t id) +{ + gicc_write_EOIR(fvp_get_cfgvar(CONFIG_GICC_ADDR), id); + return; +} + +/******************************************************************************* + * This function returns the type of the interrupt id depending upon the group + * this interrupt has been configured under by the interrupt controller i.e. + * group0 or group1. + ******************************************************************************/ +uint32_t plat_ic_get_interrupt_type(uint32_t id) +{ + uint32_t group; + + group = gicd_get_igroupr(fvp_get_cfgvar(CONFIG_GICD_ADDR), id); + + /* Assume that all secure interrupts are S-EL1 interrupts */ + if (group == GRP0) + return INTR_TYPE_S_EL1; + else + return INTR_TYPE_NS; +} + +#else +#error "Invalid GIC architecture version specified for FVP port" +#endif diff --git a/plat/fvp/fvp_io_storage.c b/plat/fvp/fvp_io_storage.c new file mode 100644 index 0000000..c32cca9 --- /dev/null +++ b/plat/fvp/fvp_io_storage.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <debug.h> +#include <io_driver.h> +#include <io_fip.h> +#include <io_memmap.h> +#include <io_storage.h> +#include <io_semihosting.h> +#include <semihosting.h> /* For FOPEN_MODE_... */ +#include <string.h> +#include "fvp_def.h" + +/* IO devices */ +static io_plat_data_t io_data; +static const io_dev_connector_t *sh_dev_con; +static uintptr_t sh_dev_spec; +static uintptr_t sh_init_params; +static uintptr_t sh_dev_handle; +static const io_dev_connector_t *fip_dev_con; +static uintptr_t fip_dev_spec; +static uintptr_t fip_dev_handle; +static const io_dev_connector_t *memmap_dev_con; +static uintptr_t memmap_dev_spec; +static uintptr_t memmap_init_params; +static uintptr_t memmap_dev_handle; + +static const io_block_spec_t fip_block_spec = { + .offset = FLASH0_BASE, + .length = FLASH0_SIZE +}; + +static const io_file_spec_t bl2_file_spec = { + .path = BL2_IMAGE_NAME, + .mode = FOPEN_MODE_RB +}; + +static const io_file_spec_t bl31_file_spec = { + .path = BL31_IMAGE_NAME, + .mode = FOPEN_MODE_RB +}; + +static const io_file_spec_t bl32_file_spec = { + .path = BL32_IMAGE_NAME, + .mode = FOPEN_MODE_RB +}; + +static const io_file_spec_t bl33_file_spec = { + .path = BL33_IMAGE_NAME, + .mode = FOPEN_MODE_RB +}; + +static int open_fip(const uintptr_t spec); +static int open_memmap(const uintptr_t spec); + +struct plat_io_policy { + char *image_name; + uintptr_t *dev_handle; + uintptr_t image_spec; + int (*check)(const uintptr_t spec); +}; + +static const struct plat_io_policy policies[] = { + { + FIP_IMAGE_NAME, + &memmap_dev_handle, + (uintptr_t)&fip_block_spec, + open_memmap + }, { + BL2_IMAGE_NAME, + &fip_dev_handle, + (uintptr_t)&bl2_file_spec, + open_fip + }, { + BL31_IMAGE_NAME, + &fip_dev_handle, + (uintptr_t)&bl31_file_spec, + open_fip + }, { + BL32_IMAGE_NAME, + &fip_dev_handle, + (uintptr_t)&bl32_file_spec, + open_fip + }, { + BL33_IMAGE_NAME, + &fip_dev_handle, + (uintptr_t)&bl33_file_spec, + open_fip + }, { + 0, 0, 0 + } +}; + + +static int open_fip(const uintptr_t spec) +{ + int result = IO_FAIL; + + /* See if a Firmware Image Package is available */ + result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_NAME); + if (result == IO_SUCCESS) { + INFO("Using FIP\n"); + /*TODO: Check image defined in spec is present in FIP. */ + } + return result; +} + + +static int open_memmap(const uintptr_t spec) +{ + int result = IO_FAIL; + uintptr_t local_image_handle; + + result = io_dev_init(memmap_dev_handle, memmap_init_params); + if (result == IO_SUCCESS) { + result = io_open(memmap_dev_handle, spec, &local_image_handle); + if (result == IO_SUCCESS) { + /* INFO("Using Memmap IO\n"); */ + io_close(local_image_handle); + } + } + return result; +} + + +static int open_semihosting(const uintptr_t spec) +{ + int result = IO_FAIL; + uintptr_t local_image_handle; + + /* See if the file exists on semi-hosting.*/ + result = io_dev_init(sh_dev_handle, sh_init_params); + if (result == IO_SUCCESS) { + result = io_open(sh_dev_handle, spec, &local_image_handle); + if (result == IO_SUCCESS) { + INFO("Using Semi-hosting IO\n"); + io_close(local_image_handle); + } + } + return result; +} + +void fvp_io_setup (void) +{ + int io_result = IO_FAIL; + + /* Initialise the IO layer */ + io_init(&io_data); + + /* Register the IO devices on this platform */ + io_result = register_io_dev_sh(&sh_dev_con); + assert(io_result == IO_SUCCESS); + + io_result = register_io_dev_fip(&fip_dev_con); + assert(io_result == IO_SUCCESS); + + io_result = register_io_dev_memmap(&memmap_dev_con); + assert(io_result == IO_SUCCESS); + + /* Open connections to devices and cache the handles */ + io_result = io_dev_open(sh_dev_con, sh_dev_spec, &sh_dev_handle); + assert(io_result == IO_SUCCESS); + + io_result = io_dev_open(fip_dev_con, fip_dev_spec, &fip_dev_handle); + assert(io_result == IO_SUCCESS); + + io_result = io_dev_open(memmap_dev_con, memmap_dev_spec, + &memmap_dev_handle); + assert(io_result == IO_SUCCESS); + + /* 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(const char *image_name, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + int result = IO_FAIL; + const struct plat_io_policy *policy; + + if ((image_name != NULL) && (dev_handle != NULL) && + (image_spec != NULL)) { + policy = policies; + while (policy->image_name != NULL) { + if (strcmp(policy->image_name, image_name) == 0) { + result = policy->check(policy->image_spec); + if (result == IO_SUCCESS) { + *image_spec = policy->image_spec; + *dev_handle = *(policy->dev_handle); + break; + } else { + result = open_semihosting( + policy->image_spec); + if (result == IO_SUCCESS) { + *dev_handle = sh_dev_handle; + *image_spec = + policy->image_spec; + } + } + } + policy++; + } + } else { + result = IO_FAIL; + } + return result; +} diff --git a/plat/fvp/fvp_pm.c b/plat/fvp/fvp_pm.c new file mode 100644 index 0000000..d702643 --- /dev/null +++ b/plat/fvp/fvp_pm.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <assert.h> +#include <bakery_lock.h> +#include <cci400.h> +#include <mmio.h> +#include <platform.h> +#include <platform_def.h> +#include <psci.h> +#include "drivers/pwrc/fvp_pwrc.h" +#include "fvp_def.h" +#include "fvp_private.h" + +/******************************************************************************* + * FVP handler called when an affinity instance is about to enter standby. + ******************************************************************************/ +int fvp_affinst_standby(unsigned int power_state) +{ + unsigned int target_afflvl; + + /* Sanity check the requested state */ + target_afflvl = psci_get_pstate_afflvl(power_state); + + /* + * It's possible to enter standby only on affinity level 0 i.e. a cpu + * on the FVP. Ignore any other affinity level. + */ + if (target_afflvl != MPIDR_AFFLVL0) + return PSCI_E_INVALID_PARAMS; + + /* + * Enter standby state + * dsb is good practice before using wfi to enter low power states + */ + dsb(); + wfi(); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * FVP handler called when an affinity instance is about to be turned on. The + * level and mpidr determine the affinity instance. + ******************************************************************************/ +int fvp_affinst_on(unsigned long mpidr, + unsigned long sec_entrypoint, + unsigned long ns_entrypoint, + unsigned int afflvl, + unsigned int state) +{ + int rc = PSCI_E_SUCCESS; + unsigned long linear_id; + mailbox_t *fvp_mboxes; + unsigned int psysr; + + /* + * It's possible to turn on only affinity level 0 i.e. a cpu + * on the FVP. Ignore any other affinity level. + */ + if (afflvl != MPIDR_AFFLVL0) + goto exit; + + /* + * Ensure that we do not cancel an inflight power off request + * for the target cpu. That would leave it in a zombie wfi. + * Wait for it to power off, program the jump address for the + * target cpu and then program the power controller to turn + * that cpu on + */ + do { + psysr = fvp_pwrc_read_psysr(mpidr); + } while (psysr & PSYSR_AFF_L0); + + linear_id = platform_get_core_pos(mpidr); + fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF); + fvp_mboxes[linear_id].value = sec_entrypoint; + flush_dcache_range((unsigned long) &fvp_mboxes[linear_id], + sizeof(unsigned long)); + + fvp_pwrc_write_pponr(mpidr); + +exit: + return rc; +} + +/******************************************************************************* + * FVP handler called when an affinity instance is about to be turned off. The + * level and mpidr determine the affinity instance. The 'state' arg. allows the + * platform to decide whether the cluster is being turned off and take apt + * actions. + * + * CAUTION: This function is called with coherent stacks so that caches can be + * turned off, flushed and coherency disabled. There is no guarantee that caches + * will remain turned on across calls to this function as each affinity level is + * dealt with. So do not write & read global variables across calls. It will be + * wise to do flush a write to the global to prevent unpredictable results. + ******************************************************************************/ +int fvp_affinst_off(unsigned long mpidr, + unsigned int afflvl, + unsigned int state) +{ + int rc = PSCI_E_SUCCESS; + unsigned int gicc_base, ectlr; + unsigned long cpu_setup, cci_setup; + + switch (afflvl) { + case MPIDR_AFFLVL1: + if (state == PSCI_STATE_OFF) { + /* + * Disable coherency if this cluster is to be + * turned off + */ + cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI); + if (cci_setup) { + cci_disable_coherency(mpidr); + } + + /* + * Program the power controller to turn the + * cluster off + */ + fvp_pwrc_write_pcoffr(mpidr); + + } + break; + + case MPIDR_AFFLVL0: + if (state == PSCI_STATE_OFF) { + + /* + * Take this cpu out of intra-cluster coherency if + * the FVP flavour supports the SMP bit. + */ + cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP); + if (cpu_setup) { + ectlr = read_cpuectlr(); + ectlr &= ~CPUECTLR_SMP_BIT; + write_cpuectlr(ectlr); + } + + /* + * Prevent interrupts from spuriously waking up + * this cpu + */ + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + gic_cpuif_deactivate(gicc_base); + + /* + * Program the power controller to power this + * cpu off + */ + fvp_pwrc_write_ppoffr(mpidr); + } + break; + + default: + assert(0); + } + + return rc; +} + +/******************************************************************************* + * FVP handler called when an affinity instance is about to be suspended. The + * level and mpidr determine the affinity instance. The 'state' arg. allows the + * platform to decide whether the cluster is being turned off and take apt + * actions. + * + * CAUTION: This function is called with coherent stacks so that caches can be + * turned off, flushed and coherency disabled. There is no guarantee that caches + * will remain turned on across calls to this function as each affinity level is + * dealt with. So do not write & read global variables across calls. It will be + * wise to do flush a write to the global to prevent unpredictable results. + ******************************************************************************/ +int fvp_affinst_suspend(unsigned long mpidr, + unsigned long sec_entrypoint, + unsigned long ns_entrypoint, + unsigned int afflvl, + unsigned int state) +{ + int rc = PSCI_E_SUCCESS; + unsigned int gicc_base, ectlr; + unsigned long cpu_setup, cci_setup, linear_id; + mailbox_t *fvp_mboxes; + + switch (afflvl) { + case MPIDR_AFFLVL1: + if (state == PSCI_STATE_OFF) { + /* + * Disable coherency if this cluster is to be + * turned off + */ + cci_setup = fvp_get_cfgvar(CONFIG_HAS_CCI); + if (cci_setup) { + cci_disable_coherency(mpidr); + } + + /* + * Program the power controller to turn the + * cluster off + */ + fvp_pwrc_write_pcoffr(mpidr); + + } + break; + + case MPIDR_AFFLVL0: + if (state == PSCI_STATE_OFF) { + /* + * Take this cpu out of intra-cluster coherency if + * the FVP flavour supports the SMP bit. + */ + cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP); + if (cpu_setup) { + ectlr = read_cpuectlr(); + ectlr &= ~CPUECTLR_SMP_BIT; + write_cpuectlr(ectlr); + } + + /* Program the jump address for the target cpu */ + linear_id = platform_get_core_pos(mpidr); + fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF); + fvp_mboxes[linear_id].value = sec_entrypoint; + flush_dcache_range((unsigned long) &fvp_mboxes[linear_id], + sizeof(unsigned long)); + + /* + * Prevent interrupts from spuriously waking up + * this cpu + */ + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + gic_cpuif_deactivate(gicc_base); + + /* + * Program the power controller to power this + * cpu off and enable wakeup interrupts. + */ + fvp_pwrc_set_wen(mpidr); + fvp_pwrc_write_ppoffr(mpidr); + } + break; + + default: + assert(0); + } + + return rc; +} + +/******************************************************************************* + * FVP handler called when an affinity instance has just been powered on after + * being turned off earlier. The level and mpidr determine the affinity + * instance. The 'state' arg. allows the platform to decide whether the cluster + * was turned off prior to wakeup and do what's necessary to setup it up + * correctly. + ******************************************************************************/ +int fvp_affinst_on_finish(unsigned long mpidr, + unsigned int afflvl, + unsigned int state) +{ + int rc = PSCI_E_SUCCESS; + unsigned long linear_id, cpu_setup; + mailbox_t *fvp_mboxes; + unsigned int gicd_base, gicc_base, reg_val, ectlr; + + switch (afflvl) { + + case MPIDR_AFFLVL1: + /* Enable coherency if this cluster was off */ + if (state == PSCI_STATE_OFF) { + + /* + * This CPU might have woken up whilst the + * cluster was attempting to power down. In + * this case the FVP power controller will + * have a pending cluster power off request + * which needs to be cleared by writing to the + * PPONR register. This prevents the power + * controller from interpreting a subsequent + * entry of this cpu into a simple wfi as a + * power down request. + */ + fvp_pwrc_write_pponr(mpidr); + + fvp_cci_setup(); + } + break; + + case MPIDR_AFFLVL0: + /* + * Ignore the state passed for a cpu. It could only have + * been off if we are here. + */ + + /* + * Turn on intra-cluster coherency if the FVP flavour supports + * it. + */ + cpu_setup = fvp_get_cfgvar(CONFIG_CPU_SETUP); + if (cpu_setup) { + ectlr = read_cpuectlr(); + ectlr |= CPUECTLR_SMP_BIT; + write_cpuectlr(ectlr); + } + + /* + * Clear PWKUPR.WEN bit to ensure interrupts do not interfere + * with a cpu power down unless the bit is set again + */ + fvp_pwrc_clr_wen(mpidr); + + /* Zero the jump address in the mailbox for this cpu */ + fvp_mboxes = (mailbox_t *) (TZDRAM_BASE + MBOX_OFF); + linear_id = platform_get_core_pos(mpidr); + fvp_mboxes[linear_id].value = 0; + flush_dcache_range((unsigned long) &fvp_mboxes[linear_id], + sizeof(unsigned long)); + + gicd_base = fvp_get_cfgvar(CONFIG_GICD_ADDR); + gicc_base = fvp_get_cfgvar(CONFIG_GICC_ADDR); + + /* Enable the gic cpu interface */ + gic_cpuif_setup(gicc_base); + + /* TODO: This setup is needed only after a cold boot */ + gic_pcpu_distif_setup(gicd_base); + + /* Allow access to the System counter timer module */ + reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); + reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); + reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(0), reg_val); + mmio_write_32(SYS_TIMCTL_BASE + CNTACR_BASE(1), reg_val); + + reg_val = (1 << CNTNSAR_NS_SHIFT(0)) | + (1 << CNTNSAR_NS_SHIFT(1)); + mmio_write_32(SYS_TIMCTL_BASE + CNTNSAR, reg_val); + + break; + + default: + assert(0); + } + + return rc; +} + +/******************************************************************************* + * FVP handler called when an affinity instance has just been powered on after + * having been suspended earlier. The level and mpidr determine the affinity + * instance. + * TODO: At the moment we reuse the on finisher and reinitialize the secure + * context. Need to implement a separate suspend finisher. + ******************************************************************************/ +int fvp_affinst_suspend_finish(unsigned long mpidr, + unsigned int afflvl, + unsigned int state) +{ + return fvp_affinst_on_finish(mpidr, afflvl, state); +} + + +/******************************************************************************* + * Export the platform handlers to enable psci to invoke them + ******************************************************************************/ +static const plat_pm_ops_t fvp_plat_pm_ops = { + fvp_affinst_standby, + fvp_affinst_on, + fvp_affinst_off, + fvp_affinst_suspend, + fvp_affinst_on_finish, + fvp_affinst_suspend_finish, +}; + +/******************************************************************************* + * Export the platform specific power ops & initialize the fvp power controller + ******************************************************************************/ +int platform_setup_pm(const plat_pm_ops_t **plat_ops) +{ + *plat_ops = &fvp_plat_pm_ops; + return 0; +} diff --git a/plat/fvp/fvp_private.h b/plat/fvp/fvp_private.h new file mode 100644 index 0000000..2331bb7 --- /dev/null +++ b/plat/fvp/fvp_private.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __FVP_PRIVATE_H__ +#define __FVP_PRIVATE_H__ + +#include <bl_common.h> +#include <platform_def.h> + + +typedef volatile struct mailbox { + unsigned long value + __attribute__((__aligned__(CACHE_WRITEBACK_GRANULE))); +} mailbox_t; + +/******************************************************************************* + * This structure represents the superset of information that is passed to + * BL31 e.g. while passing control to it from BL2 which is bl31_params + * and bl31_plat_params and its elements + ******************************************************************************/ +typedef struct bl2_to_bl31_params_mem { + bl31_params_t bl31_params; + image_info_t bl31_image_info; + image_info_t bl32_image_info; + image_info_t bl33_image_info; + entry_point_info_t bl33_ep_info; + entry_point_info_t bl32_ep_info; + entry_point_info_t bl31_ep_info; +} bl2_to_bl31_params_mem_t; + +/******************************************************************************* + * Forward declarations + ******************************************************************************/ +struct meminfo; + +/******************************************************************************* + * Function and variable prototypes + ******************************************************************************/ +void fvp_configure_mmu_el1(unsigned long total_base, + unsigned long total_size, + unsigned long, + unsigned long, + unsigned long, + unsigned long); +void fvp_configure_mmu_el3(unsigned long total_base, + unsigned long total_size, + unsigned long, + unsigned long, + unsigned long, + unsigned long); +unsigned long fvp_get_cfgvar(unsigned int); +int fvp_config_setup(void); + +#if RESET_TO_BL31 +void fvp_get_entry_point_info(unsigned long target_security, + struct entry_point_info *target_entry_info); +#endif +void fvp_cci_setup(void); + +/* Declarations for fvp_gic.c */ +void gic_cpuif_deactivate(unsigned int); +void gic_cpuif_setup(unsigned int); +void gic_pcpu_distif_setup(unsigned int); +void gic_setup(void); + +/* Declarations for fvp_topology.c */ +int fvp_setup_topology(void); + +/* Declarations for fvp_io_storage.c */ +void fvp_io_setup(void); + +/* Declarations for fvp_security.c */ +void fvp_security_setup(void); + +/* Sets the entrypoint for BL32 */ +void fvp_set_bl32_ep_info(struct entry_point_info *bl32_ep); + +/* Sets the entrypoint for BL33 */ +void fvp_set_bl33_ep_info(struct entry_point_info *bl33_ep); + + +#endif /* __FVP_PRIVATE_H__ */ diff --git a/plat/fvp/fvp_security.c b/plat/fvp/fvp_security.c new file mode 100644 index 0000000..76c4541 --- /dev/null +++ b/plat/fvp/fvp_security.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <debug.h> +#include <tzc400.h> +#include "fvp_def.h" +#include "fvp_private.h" + +/* Used to improve readability for configuring regions. */ +#define FILTER_SHIFT(filter) (1 << filter) + +/* + * For the moment we assume that all security programming is done by the + * primary core. + * TODO: + * Might want to enable interrupt on violations when supported? + */ +void fvp_security_setup(void) +{ + tzc_instance_t controller; + + /* + * The Base FVP has a TrustZone address space controller, the Foundation + * FVP does not. Trying to program the device on the foundation FVP will + * cause an abort. + * + * If the platform had additional peripheral specific security + * configurations, those would be configured here. + */ + + if (!fvp_get_cfgvar(CONFIG_HAS_TZC)) + return; + + /* + * The TrustZone controller controls access to main DRAM. Give + * full NS access for the moment to use with OS. + */ + INFO("Configuring TrustZone Controller\n"); + + /* + * The driver does some error checking and will assert. + * - Provide base address of device on platform. + * - Provide width of ACE-Lite IDs on platform. + */ + controller.base = TZC400_BASE; + controller.aid_width = FVP_AID_WIDTH; + tzc_init(&controller); + + /* + * Currently only filters 0 and 2 are connected on Base FVP. + * Filter 0 : CPU clusters (no access to DRAM by default) + * Filter 1 : not connected + * Filter 2 : LCDs (access to VRAM allowed by default) + * Filter 3 : not connected + * Programming unconnected filters will have no effect at the + * moment. These filter could, however, be connected in future. + * So care should be taken not to configure the unused filters. + */ + + /* Disable all filters before programming. */ + tzc_disable_filters(&controller); + + /* + * Allow only non-secure access to all DRAM to supported devices. + * Give access to the CPUs and Virtio. Some devices + * would normally use the default ID so allow that too. We use + * two regions to cover the blocks of physical memory in the FVPs. + * + * Software executing in the secure state, such as a secure + * boot-loader, can access the DRAM by using the NS attributes in + * the MMU translation tables and descriptors. + */ + + /* Set to cover the first block of DRAM */ + tzc_configure_region(&controller, FILTER_SHIFT(0), 1, + DRAM1_BASE, DRAM1_END - DRAM1_SEC_SIZE, + TZC_REGION_S_NONE, + TZC_REGION_ACCESS_RDWR(FVP_NSAID_DEFAULT) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_PCI) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_AP) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD)); + + /* Set to cover the secure reserved region */ + tzc_configure_region(&controller, FILTER_SHIFT(0), 3, + (DRAM1_END - DRAM1_SEC_SIZE) + 1 , DRAM1_END, + TZC_REGION_S_RDWR, + 0x0); + + /* Set to cover the second block of DRAM */ + tzc_configure_region(&controller, FILTER_SHIFT(0), 2, + DRAM2_BASE, DRAM2_END, TZC_REGION_S_NONE, + TZC_REGION_ACCESS_RDWR(FVP_NSAID_DEFAULT) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_PCI) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_AP) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO) | + TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD)); + + /* + * TODO: Interrupts are not currently supported. The only + * options we have are for access errors to occur quietly or to + * cause an exception. We choose to cause an exception. + */ + tzc_set_action(&controller, TZC_ACTION_ERR); + + /* Enable filters. */ + tzc_enable_filters(&controller); +} diff --git a/plat/fvp/fvp_topology.c b/plat/fvp/fvp_topology.c new file mode 100644 index 0000000..cf21503 --- /dev/null +++ b/plat/fvp/fvp_topology.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <platform_def.h> +/* TODO: Reusing psci error codes & state information. Get our own! */ +#include <psci.h> +#include "drivers/pwrc/fvp_pwrc.h" + +/* We treat '255' as an invalid affinity instance */ +#define AFFINST_INVAL 0xff + +/******************************************************************************* + * We support 3 flavours of the FVP: Foundation, Base AEM & Base Cortex. Each + * flavour has a different topology. The common bit is that there can be a max. + * of 2 clusters (affinity 1) and 4 cpus (affinity 0) per cluster. So we define + * a tree like data structure which caters to these maximum bounds. It simply + * marks the absent affinity level instances as PSCI_AFF_ABSENT e.g. there is no + * cluster 1 on the Foundation FVP. The 'data' field is currently unused. + ******************************************************************************/ +typedef struct affinity_info { + unsigned char sibling; + unsigned char child; + unsigned char state; + unsigned int data; +} affinity_info_t; + +/******************************************************************************* + * The following two data structures store the topology tree for the fvp. There + * is a separate array for each affinity level i.e. cpus and clusters. The child + * and sibling references allow traversal inside and in between the two arrays. + ******************************************************************************/ +static affinity_info_t fvp_aff1_topology_map[PLATFORM_CLUSTER_COUNT]; +static affinity_info_t fvp_aff0_topology_map[PLATFORM_CORE_COUNT]; + +/* Simple global variable to safeguard us from stupidity */ +static unsigned int topology_setup_done; + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform to allow the former to detect the platform + * topology. psci queries the platform to determine how many affinity instances + * are present at a particular level for a given mpidr e.g. consider a dual + * cluster platform where each cluster has 4 cpus. A call to this function with + * (0, 0x100) will return the number of cpus implemented under cluster 1 i.e. 4. + * Similarly a call with (1, 0x100) will return 2 i.e. the number of clusters. + * This is 'cause we are effectively asking how many affinity level 1 instances + * are implemented under affinity level 2 instance 0. + ******************************************************************************/ +unsigned int plat_get_aff_count(unsigned int aff_lvl, + unsigned long mpidr) +{ + unsigned int aff_count = 1, ctr; + unsigned char parent_aff_id; + + assert(topology_setup_done == 1); + + switch (aff_lvl) { + case 3: + case 2: + /* + * Assert if the parent affinity instance is not 0. + * This also takes care of level 3 in an obfuscated way + */ + parent_aff_id = (mpidr >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id == 0); + + /* + * Report that we implement a single instance of + * affinity levels 2 & 3 which are AFF_ABSENT + */ + break; + case 1: + /* Assert if the parent affinity instance is not 0. */ + parent_aff_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id == 0); + + /* Fetch the starting index in the aff1 array */ + for (ctr = 0; + fvp_aff1_topology_map[ctr].sibling != AFFINST_INVAL; + ctr = fvp_aff1_topology_map[ctr].sibling) { + aff_count++; + } + + break; + case 0: + /* Assert if the cluster id is anything apart from 0 or 1 */ + parent_aff_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + assert(parent_aff_id < PLATFORM_CLUSTER_COUNT); + + /* Fetch the starting index in the aff0 array */ + for (ctr = fvp_aff1_topology_map[parent_aff_id].child; + fvp_aff0_topology_map[ctr].sibling != AFFINST_INVAL; + ctr = fvp_aff0_topology_map[ctr].sibling) { + aff_count++; + } + + break; + default: + assert(0); + } + + return aff_count; +} + +/******************************************************************************* + * This function implements a part of the critical interface between the psci + * generic layer and the platform to allow the former to detect the state of a + * affinity instance in the platform topology. psci queries the platform to + * determine whether an affinity instance is present or absent. This caters for + * topologies where an intermediate affinity level instance is missing e.g. + * consider a platform which implements a single cluster with 4 cpus and there + * is another cpu sitting directly on the interconnect along with the cluster. + * The mpidrs of the cluster would range from 0x0-0x3. The mpidr of the single + * cpu would be 0x100 to highlight that it does not belong to cluster 0. Cluster + * 1 is however missing but needs to be accounted to reach this single cpu in + * the topology tree. Hence it will be marked as PSCI_AFF_ABSENT. This is not + * applicable to the FVP but depicted as an example. + ******************************************************************************/ +unsigned int plat_get_aff_state(unsigned int aff_lvl, + unsigned long mpidr) +{ + unsigned int aff_state = PSCI_AFF_ABSENT, idx; + idx = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + + assert(topology_setup_done == 1); + + switch (aff_lvl) { + case 3: + case 2: + /* Report affinity levels 2 & 3 as absent */ + break; + case 1: + aff_state = fvp_aff1_topology_map[idx].state; + break; + case 0: + /* + * First get start index of the aff0 in its array & then add + * to it the affinity id that we want the state of + */ + idx = fvp_aff1_topology_map[idx].child; + idx += (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; + aff_state = fvp_aff0_topology_map[idx].state; + break; + default: + assert(0); + } + + return aff_state; +} + +/******************************************************************************* + * Handy optimization to prevent the psci implementation from traversing through + * affinity levels which are not present while detecting the platform topology. + ******************************************************************************/ +int plat_get_max_afflvl() +{ + return MPIDR_AFFLVL1; +} + +/******************************************************************************* + * This function populates the FVP specific topology information depending upon + * the FVP flavour its running on. We construct all the mpidrs we can handle + * and rely on the PWRC.PSYSR to flag absent cpus when their status is queried. + ******************************************************************************/ +int fvp_setup_topology() +{ + unsigned char aff0, aff1, aff_state, aff0_offset = 0; + unsigned long mpidr; + + topology_setup_done = 0; + + for (aff1 = 0; aff1 < PLATFORM_CLUSTER_COUNT; aff1++) { + + fvp_aff1_topology_map[aff1].child = aff0_offset; + fvp_aff1_topology_map[aff1].sibling = aff1 + 1; + + for (aff0 = 0; aff0 < PLATFORM_MAX_CPUS_PER_CLUSTER; aff0++) { + + mpidr = aff1 << MPIDR_AFF1_SHIFT; + mpidr |= aff0 << MPIDR_AFF0_SHIFT; + + if (fvp_pwrc_read_psysr(mpidr) != PSYSR_INVALID) { + /* + * Presence of even a single aff0 indicates + * presence of parent aff1 on the FVP. + */ + aff_state = PSCI_AFF_PRESENT; + fvp_aff1_topology_map[aff1].state = + PSCI_AFF_PRESENT; + } else { + aff_state = PSCI_AFF_ABSENT; + } + + fvp_aff0_topology_map[aff0_offset].child = AFFINST_INVAL; + fvp_aff0_topology_map[aff0_offset].state = aff_state; + fvp_aff0_topology_map[aff0_offset].sibling = + aff0_offset + 1; + + /* Increment the absolute number of aff0s traversed */ + aff0_offset++; + } + + /* Tie-off the last aff0 sibling to -1 to avoid overflow */ + fvp_aff0_topology_map[aff0_offset - 1].sibling = AFFINST_INVAL; + } + + /* Tie-off the last aff1 sibling to AFFINST_INVAL to avoid overflow */ + fvp_aff1_topology_map[aff1 - 1].sibling = AFFINST_INVAL; + + topology_setup_done = 1; + return 0; +} diff --git a/plat/fvp/include/plat_macros.S b/plat/fvp/include/plat_macros.S new file mode 100644 index 0000000..bdd402d --- /dev/null +++ b/plat/fvp/include/plat_macros.S @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <gic_v2.h> +#include "../fvp_def.h" + +.section .rodata.gic_reg_name, "aS" +gic_regs: .asciz "gic_iar", "gic_ctlr", "" + +/* Currently we have only 2 GIC registers to report */ +#define GIC_REG_SIZE (2 * 8) + /* --------------------------------------------- + * The below macro prints out relevant GIC + * registers whenever an unhandled exception is + * taken in BL31. + * --------------------------------------------- + */ + .macro plat_print_gic_regs + mov x0, #CONFIG_GICC_ADDR + bl fvp_get_cfgvar + /* gic base address is now in x0 */ + ldr w1, [x0, #GICC_IAR] + ldr w2, [x0, #GICD_CTLR] + sub sp, sp, #GIC_REG_SIZE + stp x1, x2, [sp] /* we store the gic registers as 64 bit */ + adr x0, gic_regs + mov x1, sp + bl print_string_value + add sp, sp, #GIC_REG_SIZE + .endm diff --git a/plat/fvp/include/platform_def.h b/plat/fvp/include/platform_def.h new file mode 100644 index 0000000..46a9f24 --- /dev/null +++ b/plat/fvp/include/platform_def.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PLATFORM_DEF_H__ +#define __PLATFORM_DEF_H__ + +#include <arch.h> + + +/******************************************************************************* + * Platform binary types for linking + ******************************************************************************/ +#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" +#define PLATFORM_LINKER_ARCH aarch64 + +/******************************************************************************* + * Generic platform constants + ******************************************************************************/ + +/* Size of cacheable stacks */ +#define PLATFORM_STACK_SIZE 0x800 + +/* Size of coherent stacks for debug and release builds */ +#if DEBUG +#define PCPU_DV_MEM_STACK_SIZE 0x400 +#else +#define PCPU_DV_MEM_STACK_SIZE 0x300 +#endif + +#define FIRMWARE_WELCOME_STR "Booting trusted firmware boot loader stage 1\n\r" + +/* Trusted Boot Firmware BL2 */ +#define BL2_IMAGE_NAME "bl2.bin" + +/* EL3 Runtime Firmware BL31 */ +#define BL31_IMAGE_NAME "bl31.bin" + +/* Secure Payload BL32 (Trusted OS) */ +#define BL32_IMAGE_NAME "bl32.bin" + +/* Non-Trusted Firmware BL33 */ +#define BL33_IMAGE_NAME "bl33.bin" /* e.g. UEFI */ + +#define PLATFORM_CACHE_LINE_SIZE 64 +#define PLATFORM_CLUSTER_COUNT 2ull +#define PLATFORM_CLUSTER0_CORE_COUNT 4 +#define PLATFORM_CLUSTER1_CORE_COUNT 4 +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ + PLATFORM_CLUSTER0_CORE_COUNT) +#define PLATFORM_MAX_CPUS_PER_CLUSTER 4 +#define PRIMARY_CPU 0x0 +#define MAX_IO_DEVICES 3 +#define MAX_IO_HANDLES 4 + +/******************************************************************************* + * Platform memory map related constants + ******************************************************************************/ +#define TZROM_BASE 0x00000000 +#define TZROM_SIZE 0x04000000 + +#define TZRAM_BASE 0x04000000 +#define TZRAM_SIZE 0x40000 + +/* Location of trusted dram on the base fvp */ +#define TZDRAM_BASE 0x06000000 +#define TZDRAM_SIZE 0x02000000 + +/******************************************************************************* + * BL1 specific defines. + * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of + * addresses. + ******************************************************************************/ +#define BL1_RO_BASE TZROM_BASE +#define BL1_RO_LIMIT (TZROM_BASE + TZROM_SIZE) +#define BL1_RW_BASE TZRAM_BASE +#define BL1_RW_LIMIT BL31_BASE + +/******************************************************************************* + * BL2 specific defines. + ******************************************************************************/ +#define BL2_BASE (TZRAM_BASE + TZRAM_SIZE - 0xc000) +#define BL2_LIMIT (TZRAM_BASE + TZRAM_SIZE) + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ +#define BL31_BASE (TZRAM_BASE + 0x6000) +#if TSP_RAM_LOCATION_ID == TSP_IN_TZRAM +#define BL31_LIMIT BL32_BASE +#elif TSP_RAM_LOCATION_ID == TSP_IN_TZDRAM +#define BL31_LIMIT BL2_BASE +#endif + +/******************************************************************************* + * BL32 specific defines. + ******************************************************************************/ +/* + * On FVP, the TSP can execute either from Trusted SRAM or Trusted DRAM. + */ +#define TSP_IN_TZRAM 0 +#define TSP_IN_TZDRAM 1 + +#if TSP_RAM_LOCATION_ID == TSP_IN_TZRAM +# define TSP_SEC_MEM_BASE TZRAM_BASE +# define TSP_SEC_MEM_SIZE TZRAM_SIZE +# define BL32_BASE (TZRAM_BASE + TZRAM_SIZE - 0x1c000) +# define BL32_LIMIT BL2_BASE +#elif TSP_RAM_LOCATION_ID == TSP_IN_TZDRAM +# define TSP_SEC_MEM_BASE TZDRAM_BASE +# define TSP_SEC_MEM_SIZE TZDRAM_SIZE +# define BL32_BASE (TZDRAM_BASE + 0x2000) +# define BL32_LIMIT (TZDRAM_BASE + (1 << 21)) +#else +# error "Unsupported TSP_RAM_LOCATION_ID value" +#endif + +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ +#define ADDR_SPACE_SIZE (1ull << 32) +#define MAX_XLAT_TABLES 3 +#define MAX_MMAP_REGIONS 16 + +/******************************************************************************* + * ID of the secure physical generic timer interrupt. + ******************************************************************************/ +#define IRQ_SEC_PHY_TIMER 29 + +/******************************************************************************* + * CCI-400 related constants + ******************************************************************************/ +#define CCI400_BASE 0x2c090000 +#define CCI400_SL_IFACE_CLUSTER0 3 +#define CCI400_SL_IFACE_CLUSTER1 4 +#define CCI400_SL_IFACE_INDEX(mpidr) (mpidr & MPIDR_CLUSTER_MASK ? \ + CCI400_SL_IFACE_CLUSTER1 : \ + CCI400_SL_IFACE_CLUSTER0) + + +/******************************************************************************* + * Declarations and constants to access the mailboxes safely. Each mailbox is + * 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. Such alignment ensures that two maiboxes do not sit on the same cache + * line at any cache level. They could belong to different cpus/clusters & + * get written while being protected by different locks causing corruption of + * a valid mailbox address. + ******************************************************************************/ +#define CACHE_WRITEBACK_SHIFT 6 +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + + +#endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/fvp/platform.mk b/plat/fvp/platform.mk new file mode 100644 index 0000000..4cc4d1e --- /dev/null +++ b/plat/fvp/platform.mk @@ -0,0 +1,94 @@ +# +# Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# Neither the name of ARM nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +# On FVP, the TSP can execute either from Trusted SRAM or Trusted DRAM. +# Trusted SRAM is the default. +TSP_RAM_LOCATION := tsram + +ifeq (${TSP_RAM_LOCATION}, tsram) + TSP_RAM_LOCATION_ID := TSP_IN_TZRAM +else ifeq (${TSP_RAM_LOCATION}, tdram) + TSP_RAM_LOCATION_ID := TSP_IN_TZDRAM +else + $(error "Unsupported TSP_RAM_LOCATION value") +endif + +# Process TSP_RAM_LOCATION_ID flag +$(eval $(call add_define,TSP_RAM_LOCATION_ID)) + +PLAT_INCLUDES := -Iplat/fvp/include/ + +PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011.c \ + drivers/arm/pl011/pl011_console.c \ + drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_semihosting.c \ + lib/mmio.c \ + lib/aarch64/sysreg_helpers.S \ + lib/aarch64/xlat_tables.c \ + lib/semihosting/semihosting.c \ + lib/semihosting/aarch64/semihosting_call.S \ + plat/common/aarch64/plat_common.c \ + plat/fvp/fvp_io_storage.c + +BL1_SOURCES += drivers/arm/cci400/cci400.c \ + plat/common/aarch64/platform_up_stack.S \ + plat/fvp/bl1_fvp_setup.c \ + plat/fvp/aarch64/fvp_common.c \ + plat/fvp/aarch64/fvp_helpers.S + +BL2_SOURCES += drivers/arm/tzc400/tzc400.c \ + plat/common/aarch64/platform_up_stack.S \ + plat/fvp/bl2_fvp_setup.c \ + plat/fvp/fvp_security.c \ + plat/fvp/aarch64/fvp_common.c + +BL31_SOURCES += drivers/arm/gic/gic_v2.c \ + drivers/arm/gic/gic_v3.c \ + drivers/arm/gic/aarch64/gic_v3_sysregs.S \ + drivers/arm/cci400/cci400.c \ + plat/common/aarch64/platform_mp_stack.S \ + plat/fvp/bl31_fvp_setup.c \ + plat/fvp/fvp_gic.c \ + plat/fvp/fvp_pm.c \ + plat/fvp/fvp_topology.c \ + plat/fvp/aarch64/fvp_helpers.S \ + plat/fvp/aarch64/fvp_common.c \ + plat/fvp/drivers/pwrc/fvp_pwrc.c + +ifeq (${RESET_TO_BL31}, 1) +BL31_SOURCES += drivers/arm/tzc400/tzc400.c \ + plat/fvp/fvp_security.c +endif + +# Flag used by the FVP port to determine the version of ARM GIC architecture +# to use for interrupt management in EL3. +FVP_GIC_ARCH := 2 +$(eval $(call add_define,FVP_GIC_ARCH)) |