diff --git a/bl32/tsp/tsp-fvp.mk b/bl32/tsp/tsp-fvp.mk index b1d0afe..21864d6 100644 --- a/bl32/tsp/tsp-fvp.mk +++ b/bl32/tsp/tsp-fvp.mk @@ -31,7 +31,7 @@ # TSP source files specific to FVP platform BL32_SOURCES += drivers/arm/gic/gic_v2.c \ plat/common/aarch64/platform_mp_stack.S \ - plat/fvp/aarch64/plat_common.c \ - plat/fvp/aarch64/plat_helpers.S \ - plat/fvp/bl32_plat_setup.c \ - plat/fvp/plat_gic.c + plat/fvp/aarch64/fvp_common.c \ + plat/fvp/aarch64/fvp_helpers.S \ + plat/fvp/bl32_fvp_setup.c \ + plat/fvp/fvp_gic.c diff --git a/plat/fvp/aarch64/fvp_common.c b/plat/fvp/aarch64/fvp_common.c new file mode 100644 index 0000000..acfb752 --- /dev/null +++ b/plat/fvp/aarch64/fvp_common.c @@ -0,0 +1,310 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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]; + +/******************************************************************************* + * Macro generating the code for the function enabling the MMU in the given + * exception level, assuming that the pagetables have already been created. + * + * _el: Exception level at which the function will run + * _tcr_extra: Extra bits to set in the TCR register. This mask will + * be OR'ed with the default TCR value. + * _tlbi_fct: Function to invalidate the TLBs at the current + * exception level + ******************************************************************************/ +#define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct) \ + void enable_mmu_el##_el(void) \ + { \ + uint64_t mair, tcr, ttbr; \ + uint32_t sctlr; \ + \ + assert(IS_IN_EL(_el)); \ + assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0); \ + \ + /* Set attributes in the right indices of the MAIR */ \ + mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); \ + mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, \ + ATTR_IWBWA_OWBWA_NTR_INDEX); \ + write_mair_el##_el(mair); \ + \ + /* Invalidate TLBs at the current exception level */ \ + _tlbi_fct(); \ + \ + /* Set TCR bits as well. */ \ + /* Inner & outer WBWA & shareable + T0SZ = 32 */ \ + tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | \ + TCR_RGN_INNER_WBA | TCR_T0SZ_4GB; \ + tcr |= _tcr_extra; \ + write_tcr_el##_el(tcr); \ + \ + /* Set TTBR bits as well */ \ + ttbr = (uint64_t) l1_xlation_table; \ + write_ttbr0_el##_el(ttbr); \ + \ + /* Ensure all translation table writes have drained */ \ + /* into memory, the TLB invalidation is complete, */ \ + /* and translation register writes are committed */ \ + /* before enabling the MMU */ \ + dsb(); \ + isb(); \ + \ + sctlr = read_sctlr_el##_el(); \ + sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT | SCTLR_I_BIT; \ + sctlr |= SCTLR_A_BIT | SCTLR_C_BIT; \ + write_sctlr_el##_el(sctlr); \ + \ + /* Ensure the MMU enable takes effect immediately */ \ + isb(); \ + } + +/* Define EL1 and EL3 variants of the function enabling the MMU */ +DEFINE_ENABLE_MMU_EL(1, 0, tlbivmalle1) +DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1, tlbialle3) + +/* + * 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 +#include +#include +#include +#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/aarch64/plat_common.c b/plat/fvp/aarch64/plat_common.c deleted file mode 100644 index f0a06d8..0000000 --- a/plat/fvp/aarch64/plat_common.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 platform_config[CONFIG_LIMIT]; - -/******************************************************************************* - * Macro generating the code for the function enabling the MMU in the given - * exception level, assuming that the pagetables have already been created. - * - * _el: Exception level at which the function will run - * _tcr_extra: Extra bits to set in the TCR register. This mask will - * be OR'ed with the default TCR value. - * _tlbi_fct: Function to invalidate the TLBs at the current - * exception level - ******************************************************************************/ -#define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct) \ - void enable_mmu_el##_el(void) \ - { \ - uint64_t mair, tcr, ttbr; \ - uint32_t sctlr; \ - \ - assert(IS_IN_EL(_el)); \ - assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0); \ - \ - /* Set attributes in the right indices of the MAIR */ \ - mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); \ - mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, \ - ATTR_IWBWA_OWBWA_NTR_INDEX); \ - write_mair_el##_el(mair); \ - \ - /* Invalidate TLBs at the current exception level */ \ - _tlbi_fct(); \ - \ - /* Set TCR bits as well. */ \ - /* Inner & outer WBWA & shareable + T0SZ = 32 */ \ - tcr = TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | \ - TCR_RGN_INNER_WBA | TCR_T0SZ_4GB; \ - tcr |= _tcr_extra; \ - write_tcr_el##_el(tcr); \ - \ - /* Set TTBR bits as well */ \ - ttbr = (uint64_t) l1_xlation_table; \ - write_ttbr0_el##_el(ttbr); \ - \ - /* Ensure all translation table writes have drained */ \ - /* into memory, the TLB invalidation is complete, */ \ - /* and translation register writes are committed */ \ - /* before enabling the MMU */ \ - dsb(); \ - isb(); \ - \ - sctlr = read_sctlr_el##_el(); \ - sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT | SCTLR_I_BIT; \ - sctlr |= SCTLR_A_BIT | SCTLR_C_BIT; \ - write_sctlr_el##_el(sctlr); \ - \ - /* Ensure the MMU enable takes effect immediately */ \ - isb(); \ - } - -/* Define EL1 and EL3 variants of the function enabling the MMU */ -DEFINE_ENABLE_MMU_EL(1, 0, tlbivmalle1) -DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1, tlbialle3) - -/* - * 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 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 platform_get_cfgvar(unsigned int var_id) -{ - assert(var_id < CONFIG_LIMIT); - return platform_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 platform_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: - platform_config[CONFIG_GICD_ADDR] = VE_GICD_BASE; - platform_config[CONFIG_GICC_ADDR] = VE_GICC_BASE; - platform_config[CONFIG_GICH_ADDR] = VE_GICH_BASE; - platform_config[CONFIG_GICV_ADDR] = VE_GICV_BASE; - break; - case BLD_GIC_A53A57_MMAP: - platform_config[CONFIG_GICD_ADDR] = BASE_GICD_BASE; - platform_config[CONFIG_GICC_ADDR] = BASE_GICC_BASE; - platform_config[CONFIG_GICH_ADDR] = BASE_GICH_BASE; - platform_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: - platform_config[CONFIG_MAX_AFF0] = 4; - platform_config[CONFIG_MAX_AFF1] = 1; - platform_config[CONFIG_CPU_SETUP] = 0; - platform_config[CONFIG_BASE_MMAP] = 0; - platform_config[CONFIG_HAS_CCI] = 0; - platform_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)) - platform_config[CONFIG_CPU_SETUP] = 1; - else - platform_config[CONFIG_CPU_SETUP] = 0; - - platform_config[CONFIG_MAX_AFF0] = 4; - platform_config[CONFIG_MAX_AFF1] = 2; - platform_config[CONFIG_BASE_MMAP] = 1; - platform_config[CONFIG_HAS_CCI] = 1; - platform_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 = platform_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/plat_helpers.S b/plat/fvp/aarch64/plat_helpers.S deleted file mode 100644 index fbb2fce..0000000 --- a/plat/fvp/aarch64/plat_helpers.S +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 -#include -#include -#include -#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 platform_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 - platform_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 +#include +#include +#include +#include +#include +#include +#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/bl1_plat_setup.c b/plat/fvp/bl1_plat_setup.c deleted file mode 100644 index 34e74e2..0000000 --- a/plat/fvp/bl1_plat_setup.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#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 */ - platform_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 */ - 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(); - - 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..e18cf7d --- /dev/null +++ b/plat/fvp/bl2_fvp_setup.c @@ -0,0 +1,295 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#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) +{ + 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/bl2_plat_setup.c b/plat/fvp/bl2_plat_setup.c deleted file mode 100644 index 2cfb8bc..0000000 --- a/plat/fvp/bl2_plat_setup.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#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) -{ - 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 */ - platform_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. - */ - plat_security_setup(); - - /* Initialise the IO layer and register platform IO devices */ - 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() -{ - 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..d867fba --- /dev/null +++ b/plat/fvp/bl31_fvp_setup.c @@ -0,0 +1,256 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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_get_next_image_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; +#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/bl31_plat_setup.c b/plat/fvp/bl31_plat_setup.c deleted file mode 100644 index d1e16bd..0000000 --- a/plat/fvp/bl31_plat_setup.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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_get_next_image_info(uint32_t type) -{ - entry_point_info_t *next_image_info; - -#if RESET_TO_BL31 - - if (type == NON_SECURE) - plat_get_entry_point_info(NON_SECURE, &bl33_entrypoint_info); - else - plat_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 */ - platform_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. - */ - plat_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; -#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. */ - plat_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 - - 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 plat_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 +#include +#include +#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/bl32_plat_setup.c b/plat/fvp/bl32_plat_setup.c deleted file mode 100644 index b583349..0000000 --- a/plat/fvp/bl32_plat_setup.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 -#include -#include -#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 */ - platform_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() -{ - 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/fvp_gic.c b/plat/fvp/fvp_gic.c new file mode 100644 index 0000000..fed2fca --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 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 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 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 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 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 +#include +#include +#include +#include +#include +#include +#include /* For FOPEN_MODE_... */ +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#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 index 04e8b81..2331bb7 100644 --- a/plat/fvp/fvp_private.h +++ b/plat/fvp/fvp_private.h @@ -63,23 +63,23 @@ /******************************************************************************* * Function and variable prototypes ******************************************************************************/ -void configure_mmu_el1(unsigned long total_base, - unsigned long total_size, - unsigned long, - unsigned long, - unsigned long, - unsigned long); -void configure_mmu_el3(unsigned long total_base, - unsigned long total_size, - unsigned long, - unsigned long, - unsigned long, - unsigned long); -unsigned long platform_get_cfgvar(unsigned int); -int platform_config_setup(void); +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 plat_get_entry_point_info(unsigned long target_security, +void fvp_get_entry_point_info(unsigned long target_security, struct entry_point_info *target_entry_info); #endif void fvp_cci_setup(void); @@ -91,13 +91,13 @@ void gic_setup(void); /* Declarations for fvp_topology.c */ -int plat_setup_topology(void); +int fvp_setup_topology(void); -/* Declarations for plat_io_storage.c */ -void io_setup(void); +/* Declarations for fvp_io_storage.c */ +void fvp_io_setup(void); -/* Declarations for plat_security.c */ -void plat_security_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); 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 +#include +#include +#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 +#include +/* TODO: Reusing psci error codes & state information. Get our own! */ +#include +#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 index 1fa50fd..bdd402d 100644 --- a/plat/fvp/include/plat_macros.S +++ b/plat/fvp/include/plat_macros.S @@ -44,7 +44,7 @@ */ .macro plat_print_gic_regs mov x0, #CONFIG_GICC_ADDR - bl platform_get_cfgvar + bl fvp_get_cfgvar /* gic base address is now in x0 */ ldr w1, [x0, #GICC_IAR] ldr w2, [x0, #GICD_CTLR] diff --git a/plat/fvp/plat_gic.c b/plat/fvp/plat_gic.c deleted file mode 100644 index 6b29723..0000000 --- a/plat/fvp/plat_gic.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 = platform_get_cfgvar(CONFIG_GICD_ADDR); - gicc_base = platform_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 = platform_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 ic_get_pending_interrupt_type() -{ - uint32_t id, gicc_base; - - gicc_base = platform_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 ic_get_pending_interrupt_id() -{ - uint32_t id, gicc_base; - - gicc_base = platform_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 ic_acknowledge_interrupt() -{ - return gicc_read_IAR(platform_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 ic_end_of_interrupt(uint32_t id) -{ - gicc_write_EOIR(platform_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 ic_get_interrupt_type(uint32_t id) -{ - uint32_t group; - - group = gicd_get_igroupr(platform_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/plat_io_storage.c b/plat/fvp/plat_io_storage.c deleted file mode 100644 index baa98ff..0000000 --- a/plat/fvp/plat_io_storage.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include /* For FOPEN_MODE_... */ -#include -#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 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/plat_pm.c b/plat/fvp/plat_pm.c deleted file mode 100644 index ad4ce79..0000000 --- a/plat/fvp/plat_pm.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#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 = platform_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 = platform_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 = platform_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 = platform_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 = platform_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 = platform_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 = platform_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 = platform_get_cfgvar(CONFIG_GICD_ADDR); - gicc_base = platform_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/plat_security.c b/plat/fvp/plat_security.c deleted file mode 100644 index 976f75e..0000000 --- a/plat/fvp/plat_security.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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 -#include -#include -#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 plat_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 (!platform_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/plat_topology.c b/plat/fvp/plat_topology.c deleted file mode 100644 index f06b4f7..0000000 --- a/plat/fvp/plat_topology.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * 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 -#include -/* TODO: Reusing psci error codes & state information. Get our own! */ -#include -#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 plat_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/platform.mk b/plat/fvp/platform.mk index f1d6f87..105cdfa 100644 --- a/plat/fvp/platform.mk +++ b/plat/fvp/platform.mk @@ -51,40 +51,40 @@ drivers/io/io_memmap.c \ drivers/io/io_semihosting.c \ lib/mmio.c \ - lib/aarch64/sysreg_helpers.S \ + lib/aarch64/sysreg_helpers.S \ lib/aarch64/xlat_tables.c \ lib/semihosting/semihosting.c \ lib/semihosting/aarch64/semihosting_call.S \ - plat/fvp/plat_io_storage.c + plat/fvp/fvp_io_storage.c BL1_SOURCES += drivers/arm/cci400/cci400.c \ plat/common/aarch64/platform_up_stack.S \ - plat/fvp/bl1_plat_setup.c \ - plat/fvp/aarch64/plat_common.c \ - plat/fvp/aarch64/plat_helpers.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_plat_setup.c \ - plat/fvp/plat_security.c \ - plat/fvp/aarch64/plat_common.c + 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_plat_setup.c \ - plat/fvp/plat_gic.c \ - plat/fvp/plat_pm.c \ - plat/fvp/plat_topology.c \ - plat/fvp/aarch64/plat_helpers.S \ - plat/fvp/aarch64/plat_common.c \ + 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/plat_security.c +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