From dcc1816c91a63e959330d3a05bb085d0c77fb69a Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Sun, 4 May 2014 19:02:52 +0100 Subject: [PATCH] Introduce platform api to access an ARM GIC This patch introduces a set of functions which allow generic firmware code e.g. the interrupt management framework to access the platform interrupt controller. APIs for finding the type and id of the highest pending interrupt, acknowledging and EOIing an interrupt and finding the security state of an interrupt have been added. It is assumed that the platform interrupt controller implements the v2.0 of the ARM GIC architecture specification. Support for v3.0 of the specification for managing interrupts in EL3 and the platform port will be added in the future. Change-Id: Ib3a01c2cf3e3ab27806930f1be79db2b29f91bcf --- include/drivers/arm/gic_v2.h | 7 +++ plat/fvp/plat_gic.c | 94 +++++++++++++++++++++++++++++++++--- plat/fvp/platform.h | 9 +++- 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/include/drivers/arm/gic_v2.h b/include/drivers/arm/gic_v2.h index 91c3f11e..e8196763 100644 --- a/include/drivers/arm/gic_v2.h +++ b/include/drivers/arm/gic_v2.h @@ -43,6 +43,7 @@ #define GIC_LOWEST_SEC_PRIORITY 127 #define GIC_HIGHEST_NS_PRIORITY 128 #define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */ +#define GIC_SPURIOUS_INTERRUPT 1023 #define ENABLE_GRP0 (1 << 0) #define ENABLE_GRP1 (1 << 1) @@ -88,6 +89,7 @@ #define GICC_EOIR 0x10 #define GICC_RPR 0x14 #define GICC_HPPIR 0x18 +#define GICC_AHPPIR 0x28 #define GICC_IIDR 0xFC #define GICC_DIR 0x1000 #define GICC_PRIODROP GICC_EOIR @@ -247,6 +249,11 @@ static inline unsigned int gicc_read_hppir(unsigned int base) return mmio_read_32(base + GICC_HPPIR); } +static inline unsigned int gicc_read_ahppir(unsigned int base) +{ + return mmio_read_32(base + GICC_AHPPIR); +} + static inline unsigned int gicc_read_dir(unsigned int base) { return mmio_read_32(base + GICC_DIR); diff --git a/plat/fvp/plat_gic.c b/plat/fvp/plat_gic.c index dd409f56..7dec404f 100644 --- a/plat/fvp/plat_gic.c +++ b/plat/fvp/plat_gic.c @@ -38,12 +38,6 @@ #include #include - -/******************************************************************************* - * 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 @@ -322,3 +316,91 @@ uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) #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 814fb776..9b85b23f 100644 --- a/plat/fvp/platform.h +++ b/plat/fvp/platform.h @@ -425,7 +425,12 @@ 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); @@ -433,7 +438,7 @@ 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); -- 2.30.2