diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/arm/gic/v2/gicv2_helpers.c | 107 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicv2_main.c | 73 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicv2_private.h | 8 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_helpers.c | 111 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 108 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_private.h | 8 |
6 files changed, 356 insertions, 59 deletions
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c index 26930769..0df50fb0 100644 --- a/drivers/arm/gic/v2/gicv2_helpers.c +++ b/drivers/arm/gic/v2/gicv2_helpers.c @@ -9,6 +9,7 @@ #include <assert.h> #include <debug.h> #include <gic_common.h> +#include <interrupt_props.h> #include "../common/gic_common_private.h" #include "gicv2_private.h" @@ -112,6 +113,7 @@ void gicv2_spis_configure_defaults(uintptr_t gicd_base) gicd_write_icfgr(gicd_base, index, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 SPIs. ******************************************************************************/ @@ -145,8 +147,50 @@ void gicv2_secure_spis_configure(uintptr_t gicd_base, } } +#endif /******************************************************************************* + * Helper function to configure properties of secure G0 SPIs. + ******************************************************************************/ +void gicv2_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); + + for (i = 0; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num < MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + gicd_clr_igroupr(gicd_base, prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + + /* Target the secure interrupts to primary CPU */ + gicd_set_itargetsr(gicd_base, prop_desc->intr_num, + gicv2_get_cpuif_id(gicd_base)); + + /* Set interrupt configuration */ + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, prop_desc->intr_num); + } +} + +#if !ERROR_DEPRECATED +/******************************************************************************* * Helper function to configure secure G0 SGIs and PPIs. ******************************************************************************/ void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, @@ -193,3 +237,66 @@ void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, /* Enable the Group 0 SGIs and PPIs */ gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure G0 SGIs and PPIs. + ******************************************************************************/ +void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + uint32_t sec_ppi_sgi_mask = 0; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + assert(interrupt_props_num != 0 ? (uintptr_t) interrupt_props : 1); + + /* + * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a + * more scalable approach as it avoids clearing the enable bits in the + * GICD_CTLR. + */ + gicd_write_icenabler(gicd_base, 0, ~0); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (i = 0; i < MIN_SPI_ID; i += 4) + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + + for (i = 0; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num >= MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + + /* + * Set interrupt configuration for PPIs. Configuration for SGIs + * are ignored. + */ + if ((prop_desc->intr_num >= MIN_PPI_ID) && + (prop_desc->intr_num < MIN_SPI_ID)) { + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + } + + /* We have an SGI or a PPI. They are Group0 at reset */ + sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + } + + /* + * Invert the bitmask to create a mask for non-secure PPIs and SGIs. + * Program the GICD_IGROUPR0 with this bit mask. + */ + gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); + + /* Enable the Group 0 SGIs and PPIs */ + gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); +} diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index 59b66323..25296a63 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -10,6 +10,7 @@ #include <debug.h> #include <gic_common.h> #include <gicv2.h> +#include <interrupt_props.h> #include <spinlock.h> #include "../common/gic_common_private.h" #include "gicv2_private.h" @@ -73,11 +74,21 @@ void gicv2_pcpu_distif_init(void) { assert(driver_data); assert(driver_data->gicd_base); - assert(driver_data->g0_interrupt_array); - gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, - driver_data->g0_interrupt_num, - driver_data->g0_interrupt_array); +#if !ERROR_DEPRECATED + if (driver_data->interrupt_props != NULL) { +#endif + gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base, + driver_data->interrupt_props, + driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(driver_data->g0_interrupt_array); + gicv2_secure_ppi_sgi_setup(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); + } +#endif } /******************************************************************************* @@ -91,7 +102,6 @@ void gicv2_distif_init(void) assert(driver_data); assert(driver_data->gicd_base); - assert(driver_data->g0_interrupt_array); /* Disable the distributor before going further */ ctlr = gicd_read_ctlr(driver_data->gicd_base); @@ -101,10 +111,22 @@ void gicv2_distif_init(void) /* Set the default attribute of all SPIs */ gicv2_spis_configure_defaults(driver_data->gicd_base); - /* Configure the G0 SPIs */ - gicv2_secure_spis_configure(driver_data->gicd_base, - driver_data->g0_interrupt_num, - driver_data->g0_interrupt_array); +#if !ERROR_DEPRECATED + if (driver_data->interrupt_props != NULL) { +#endif + gicv2_secure_spis_configure_props(driver_data->gicd_base, + driver_data->interrupt_props, + driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(driver_data->g0_interrupt_array); + + /* Configure the G0 SPIs */ + gicv2_secure_spis_configure(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array); + } +#endif /* Re-enable the secure SPIs now that they have been configured */ gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); @@ -120,19 +142,26 @@ void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) assert(plat_driver_data->gicd_base); assert(plat_driver_data->gicc_base); - /* - * The platform should provide a list of atleast one type of - * interrupts - */ - assert(plat_driver_data->g0_interrupt_array); - - /* - * If there are no interrupts of a particular type, then the number of - * interrupts of that type should be 0 and vice-versa. - */ - assert(plat_driver_data->g0_interrupt_array ? - plat_driver_data->g0_interrupt_num : - plat_driver_data->g0_interrupt_num == 0); +#if !ERROR_DEPRECATED + if (plat_driver_data->interrupt_props == NULL) { + /* Interrupt properties array size must be 0 */ + assert(plat_driver_data->interrupt_props_num == 0); + + /* The platform should provide a list of secure interrupts */ + assert(plat_driver_data->g0_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the + * number of interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + } +#else + assert(plat_driver_data->interrupt_props != NULL); + assert(plat_driver_data->interrupt_props_num > 0); +#endif /* Ensure that this is a GICv2 system */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h index 70f05976..25600deb 100644 --- a/drivers/arm/gic/v2/gicv2_private.h +++ b/drivers/arm/gic/v2/gicv2_private.h @@ -15,12 +15,20 @@ * Private function prototypes ******************************************************************************/ void gicv2_spis_configure_defaults(uintptr_t gicd_base); +#if !ERROR_DEPRECATED void gicv2_secure_spis_configure(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list); void gicv2_secure_ppi_sgi_setup(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list); +#endif +void gicv2_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); +void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); unsigned int gicv2_get_cpuif_id(uintptr_t base); /******************************************************************************* diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 33dbe2c8..25226956 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -9,6 +9,7 @@ #include <assert.h> #include <debug.h> #include <gic_common.h> +#include <interrupt_props.h> #include "../common/gic_common_private.h" #include "gicv3_private.h" @@ -364,6 +365,7 @@ void gicv3_spis_configure_defaults(uintptr_t gicd_base) gicd_write_icfgr(gicd_base, index, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 and G1S SPIs. ******************************************************************************/ @@ -410,6 +412,63 @@ void gicv3_secure_spis_configure(uintptr_t gicd_base, } } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure SPIs + ******************************************************************************/ +unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *current_prop; + unsigned long long gic_affinity_val; + unsigned int ctlr_enable = 0; + + /* Make sure there's a valid property array */ + assert(interrupt_props != NULL); + assert(interrupt_props_num > 0); + + for (i = 0; i < interrupt_props_num; i++) { + current_prop = &interrupt_props[i]; + + if (current_prop->intr_num < MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + gicd_clr_igroupr(gicd_base, current_prop->intr_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + assert((current_prop->intr_grp == INTR_GROUP0) || + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) { + gicd_set_igrpmodr(gicd_base, current_prop->intr_num); + ctlr_enable |= CTLR_ENABLE_G1S_BIT; + } else { + gicd_clr_igrpmodr(gicd_base, current_prop->intr_num); + ctlr_enable |= CTLR_ENABLE_G0_BIT; + } + + /* Set interrupt configuration */ + gicd_set_icfgr(gicd_base, current_prop->intr_num, + current_prop->intr_cfg); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, current_prop->intr_num, + current_prop->intr_pri); + + /* Target SPIs to the primary CPU */ + gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0); + gicd_write_irouter(gicd_base, current_prop->intr_num, + gic_affinity_val); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, current_prop->intr_num); + } + + return ctlr_enable; +} /******************************************************************************* * Helper function to configure the default attributes of SPIs. @@ -439,6 +498,7 @@ void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base) gicr_write_icfgr1(gicr_base, 0); } +#if !ERROR_DEPRECATED /******************************************************************************* * Helper function to configure secure G0 and G1S SPIs. ******************************************************************************/ @@ -476,3 +536,54 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, } } } +#endif + +/******************************************************************************* + * Helper function to configure properties of secure G0 and G1S PPIs and SGIs. + ******************************************************************************/ +void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *current_prop; + + /* Make sure there's a valid property array */ + assert(interrupt_props != NULL); + assert(interrupt_props_num > 0); + + for (i = 0; i < interrupt_props_num; i++) { + current_prop = &interrupt_props[i]; + + if (current_prop->intr_num >= MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + gicr_clr_igroupr0(gicr_base, current_prop->intr_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + assert((current_prop->intr_grp == INTR_GROUP0) || + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) + gicr_set_igrpmodr0(gicr_base, current_prop->intr_num); + else + gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num); + + /* Set the priority of this interrupt */ + gicr_set_ipriorityr(gicr_base, current_prop->intr_num, + current_prop->intr_pri); + + /* + * Set interrupt configuration for PPIs. Configuration for SGIs + * are ignored. + */ + if ((current_prop->intr_num >= MIN_PPI_ID) && + (current_prop->intr_num < MIN_SPI_ID)) { + gicr_set_icfgr1(gicr_base, current_prop->intr_num, + current_prop->intr_cfg); + } + + /* Enable this interrupt */ + gicr_set_isenabler0(gicr_base, current_prop->intr_num); + } +} diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 0f50f6d7..8c4f5084 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -9,6 +9,7 @@ #include <assert.h> #include <debug.h> #include <gicv3.h> +#include <interrupt_props.h> #include <spinlock.h> #include "gicv3_private.h" @@ -66,23 +67,33 @@ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) assert(IS_IN_EL3()); - /* - * The platform should provide a list of at least one type of - * interrupts - */ - assert(plat_driver_data->g0_interrupt_array || - plat_driver_data->g1s_interrupt_array); - - /* - * If there are no interrupts of a particular type, then the number of - * interrupts of that type should be 0 and vice-versa. - */ - assert(plat_driver_data->g0_interrupt_array ? - plat_driver_data->g0_interrupt_num : - plat_driver_data->g0_interrupt_num == 0); - assert(plat_driver_data->g1s_interrupt_array ? - plat_driver_data->g1s_interrupt_num : - plat_driver_data->g1s_interrupt_num == 0); +#if !ERROR_DEPRECATED + if (plat_driver_data->interrupt_props == NULL) { + /* Interrupt properties array size must be 0 */ + assert(plat_driver_data->interrupt_props_num == 0); + + /* + * The platform should provide a list of at least one type of + * interrupt. + */ + assert(plat_driver_data->g0_interrupt_array || + plat_driver_data->g1s_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the + * number of interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + assert(plat_driver_data->g1s_interrupt_array ? + plat_driver_data->g1s_interrupt_num : + plat_driver_data->g1s_interrupt_num == 0); + } +#else + assert(plat_driver_data->interrupt_props != NULL); + assert(plat_driver_data->interrupt_props_num > 0); +#endif /* Check for system register support */ #ifdef AARCH32 @@ -148,8 +159,6 @@ void gicv3_distif_init(void) assert(gicv3_driver_data); assert(gicv3_driver_data->gicd_base); - assert(gicv3_driver_data->g1s_interrupt_array || - gicv3_driver_data->g0_interrupt_array); assert(IS_IN_EL3()); @@ -171,23 +180,37 @@ void gicv3_distif_init(void) /* Set the default attribute of all SPIs */ gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base); - /* Configure the G1S SPIs */ - if (gicv3_driver_data->g1s_interrupt_array) { - gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, +#if !ERROR_DEPRECATED + if (gicv3_driver_data->interrupt_props != NULL) { +#endif + bitmap = gicv3_secure_spis_configure_props( + gicv3_driver_data->gicd_base, + gicv3_driver_data->interrupt_props, + gicv3_driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(gicv3_driver_data->g1s_interrupt_array || + gicv3_driver_data->g0_interrupt_array); + + /* Configure the G1S SPIs */ + if (gicv3_driver_data->g1s_interrupt_array) { + gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, gicv3_driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_array, INTR_GROUP1S); - bitmap |= CTLR_ENABLE_G1S_BIT; - } + bitmap |= CTLR_ENABLE_G1S_BIT; + } - /* Configure the G0 SPIs */ - if (gicv3_driver_data->g0_interrupt_array) { - gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, + /* Configure the G0 SPIs */ + if (gicv3_driver_data->g0_interrupt_array) { + gicv3_secure_spis_configure(gicv3_driver_data->gicd_base, gicv3_driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_array, INTR_GROUP0); - bitmap |= CTLR_ENABLE_G0_BIT; + bitmap |= CTLR_ENABLE_G0_BIT; + } } +#endif /* Enable the secure SPIs now that they have been configured */ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); @@ -207,8 +230,6 @@ void gicv3_rdistif_init(unsigned int proc_num) assert(gicv3_driver_data->rdistif_base_addrs); assert(gicv3_driver_data->gicd_base); assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT); - assert(gicv3_driver_data->g1s_interrupt_array || - gicv3_driver_data->g0_interrupt_array); assert(IS_IN_EL3()); @@ -220,21 +241,34 @@ void gicv3_rdistif_init(unsigned int proc_num) /* Set the default attribute of all SGIs and PPIs */ gicv3_ppi_sgi_configure_defaults(gicr_base); - /* Configure the G1S SGIs/PPIs */ - if (gicv3_driver_data->g1s_interrupt_array) { - gicv3_secure_ppi_sgi_configure(gicr_base, +#if !ERROR_DEPRECATED + if (gicv3_driver_data->interrupt_props != NULL) { +#endif + gicv3_secure_ppi_sgi_configure_props(gicr_base, + gicv3_driver_data->interrupt_props, + gicv3_driver_data->interrupt_props_num); +#if !ERROR_DEPRECATED + } else { + assert(gicv3_driver_data->g1s_interrupt_array || + gicv3_driver_data->g0_interrupt_array); + + /* Configure the G1S SGIs/PPIs */ + if (gicv3_driver_data->g1s_interrupt_array) { + gicv3_secure_ppi_sgi_configure(gicr_base, gicv3_driver_data->g1s_interrupt_num, gicv3_driver_data->g1s_interrupt_array, INTR_GROUP1S); - } + } - /* Configure the G0 SGIs/PPIs */ - if (gicv3_driver_data->g0_interrupt_array) { - gicv3_secure_ppi_sgi_configure(gicr_base, + /* Configure the G0 SGIs/PPIs */ + if (gicv3_driver_data->g0_interrupt_array) { + gicv3_secure_ppi_sgi_configure(gicr_base, gicv3_driver_data->g0_interrupt_num, gicv3_driver_data->g0_interrupt_array, INTR_GROUP0); + } } +#endif } /******************************************************************************* diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index 43529c5a..a5093d0c 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -85,6 +85,7 @@ void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri); ******************************************************************************/ void gicv3_spis_configure_defaults(uintptr_t gicd_base); void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base); +#if !ERROR_DEPRECATED void gicv3_secure_spis_configure(uintptr_t gicd_base, unsigned int num_ints, const unsigned int *sec_intr_list, @@ -93,6 +94,13 @@ void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, unsigned int num_ints, const unsigned int *sec_intr_list, unsigned int int_grp); +#endif +void gicv3_secure_ppi_sgi_configure_props(uintptr_t gicr_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); +unsigned int gicv3_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num); void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, unsigned int rdistif_num, uintptr_t gicr_base, |