diff options
author | Andrew Thoelke <andrew.thoelke@arm.com> | 2014-05-23 11:00:04 +0100 |
---|---|---|
committer | Andrew Thoelke <andrew.thoelke@arm.com> | 2014-05-23 11:00:04 +0100 |
commit | 8545a8744b541cc6855e3218c4565e76697fb002 (patch) | |
tree | 96fdd4f46996c69897634eabd1e517ab83013f24 /plat | |
parent | 92535302791564e102150072d0e6152f9c4fde87 (diff) | |
parent | a20a81e5b4a19969673f672523b946647f5d545d (diff) |
Merge pull request #102 from achingupta:ag/tf-issues#104-v2
Diffstat (limited to 'plat')
-rw-r--r-- | plat/fvp/bl32_plat_setup.c | 3 | ||||
-rw-r--r-- | plat/fvp/plat_gic.c | 132 | ||||
-rw-r--r-- | plat/fvp/platform.h | 11 | ||||
-rw-r--r-- | plat/fvp/platform.mk | 5 |
4 files changed, 143 insertions, 8 deletions
diff --git a/plat/fvp/bl32_plat_setup.c b/plat/fvp/bl32_plat_setup.c index 8406d313..772e972f 100644 --- a/plat/fvp/bl32_plat_setup.c +++ b/plat/fvp/bl32_plat_setup.c @@ -73,6 +73,9 @@ void bl32_early_platform_setup(void) * messages from TSP */ console_init(PL011_UART1_BASE); + + /* Initialize the platform config for future decision making */ + platform_config_setup(); } /******************************************************************************* diff --git a/plat/fvp/plat_gic.c b/plat/fvp/plat_gic.c index db3c9cf6..7dec404f 100644 --- a/plat/fvp/plat_gic.c +++ b/plat/fvp/plat_gic.c @@ -29,18 +29,15 @@ */ #include <arch_helpers.h> +#include <assert.h> +#include <bl_common.h> #include <debug.h> #include <gic_v2.h> #include <gic_v3.h> +#include <interrupt_mgmt.h> #include <platform.h> #include <stdint.h> - -/******************************************************************************* - * TODO: Revisit if priorities are being set such that no non-secure interrupt - * can have a higher priority than a secure one as recommended in the GICv2 spec - ******************************************************************************/ - /******************************************************************************* * This function does some minimal GICv3 configuration. The Firmware itself does * not fully support GICv3 at this time and relies on GICv2 emulation as @@ -284,3 +281,126 @@ void gic_setup(void) 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/platform.h b/plat/fvp/platform.h index 6ab68629..4c0f38f5 100644 --- a/plat/fvp/platform.h +++ b/plat/fvp/platform.h @@ -452,13 +452,20 @@ extern void plat_get_entry_point_info(unsigned long target_security, extern void fvp_cci_setup(void); -/* Declarations for fvp_gic.c */ +/* Declarations for plat_gic.c */ +extern uint32_t ic_get_pending_interrupt_id(void); +extern uint32_t ic_get_pending_interrupt_type(void); +extern uint32_t ic_acknowledge_interrupt(void); +extern uint32_t ic_get_interrupt_type(uint32_t id); +extern void ic_end_of_interrupt(uint32_t id); extern void gic_cpuif_deactivate(unsigned int); extern void gic_cpuif_setup(unsigned int); extern void gic_pcpu_distif_setup(unsigned int); extern void gic_setup(void); +extern uint32_t plat_interrupt_type_to_line(uint32_t type, + uint32_t security_state); -/* Declarations for fvp_topology.c */ +/* Declarations for plat_topology.c */ extern int plat_setup_topology(void); extern int plat_get_max_afflvl(void); extern unsigned int plat_get_aff_count(unsigned int, unsigned long); diff --git a/plat/fvp/platform.mk b/plat/fvp/platform.mk index 82bafed6..f1d6f878 100644 --- a/plat/fvp/platform.mk +++ b/plat/fvp/platform.mk @@ -86,3 +86,8 @@ ifeq (${RESET_TO_BL31}, 1) BL31_SOURCES += drivers/arm/tzc400/tzc400.c \ plat/fvp/plat_security.c endif + +# Flag used by the FVP port to determine the version of ARM GIC architecture +# to use for interrupt management in EL3. +FVP_GIC_ARCH := 2 +$(eval $(call add_define,FVP_GIC_ARCH)) |