Commit dcc1816c authored by Achin Gupta's avatar Achin Gupta
Browse files

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
parent e1333f75
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define GIC_LOWEST_SEC_PRIORITY 127 #define GIC_LOWEST_SEC_PRIORITY 127
#define GIC_HIGHEST_NS_PRIORITY 128 #define GIC_HIGHEST_NS_PRIORITY 128
#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */ #define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */
#define GIC_SPURIOUS_INTERRUPT 1023
#define ENABLE_GRP0 (1 << 0) #define ENABLE_GRP0 (1 << 0)
#define ENABLE_GRP1 (1 << 1) #define ENABLE_GRP1 (1 << 1)
...@@ -88,6 +89,7 @@ ...@@ -88,6 +89,7 @@
#define GICC_EOIR 0x10 #define GICC_EOIR 0x10
#define GICC_RPR 0x14 #define GICC_RPR 0x14
#define GICC_HPPIR 0x18 #define GICC_HPPIR 0x18
#define GICC_AHPPIR 0x28
#define GICC_IIDR 0xFC #define GICC_IIDR 0xFC
#define GICC_DIR 0x1000 #define GICC_DIR 0x1000
#define GICC_PRIODROP GICC_EOIR #define GICC_PRIODROP GICC_EOIR
...@@ -247,6 +249,11 @@ static inline unsigned int gicc_read_hppir(unsigned int base) ...@@ -247,6 +249,11 @@ static inline unsigned int gicc_read_hppir(unsigned int base)
return mmio_read_32(base + GICC_HPPIR); 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) static inline unsigned int gicc_read_dir(unsigned int base)
{ {
return mmio_read_32(base + GICC_DIR); return mmio_read_32(base + GICC_DIR);
......
...@@ -38,12 +38,6 @@ ...@@ -38,12 +38,6 @@
#include <platform.h> #include <platform.h>
#include <stdint.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 * This function does some minimal GICv3 configuration. The Firmware itself does
* not fully support GICv3 at this time and relies on GICv2 emulation as * 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) ...@@ -322,3 +316,91 @@ uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
#endif #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
...@@ -425,7 +425,12 @@ extern void plat_get_entry_point_info(unsigned long target_security, ...@@ -425,7 +425,12 @@ extern void plat_get_entry_point_info(unsigned long target_security,
extern void fvp_cci_setup(void); 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_deactivate(unsigned int);
extern void gic_cpuif_setup(unsigned int); extern void gic_cpuif_setup(unsigned int);
extern void gic_pcpu_distif_setup(unsigned int); extern void gic_pcpu_distif_setup(unsigned int);
...@@ -433,7 +438,7 @@ extern void gic_setup(void); ...@@ -433,7 +438,7 @@ extern void gic_setup(void);
extern uint32_t plat_interrupt_type_to_line(uint32_t type, extern uint32_t plat_interrupt_type_to_line(uint32_t type,
uint32_t security_state); uint32_t security_state);
/* Declarations for fvp_topology.c */ /* Declarations for plat_topology.c */
extern int plat_setup_topology(void); extern int plat_setup_topology(void);
extern int plat_get_max_afflvl(void); extern int plat_get_max_afflvl(void);
extern unsigned int plat_get_aff_count(unsigned int, unsigned long); extern unsigned int plat_get_aff_count(unsigned int, unsigned long);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment