diff options
author | Alexei Fedorov <Alexei.Fedorov@arm.com> | 2020-04-06 16:27:54 +0100 |
---|---|---|
committer | Alexei Fedorov <Alexei.Fedorov@arm.com> | 2020-04-06 16:27:54 +0100 |
commit | 8f3ad7661400c1cf23276f8ffff905102c54329a (patch) | |
tree | 92318678d279d68e21ede6d2fce5e4680e7eb4d0 /drivers/arm/gic/v3/gicv3_helpers.c | |
parent | 37d56d3829f86ee5808b5f4a5a6b4dbdbb1bab67 (diff) | |
download | trusted-firmware-a-8f3ad7661400c1cf23276f8ffff905102c54329a.tar.gz |
TF-A GICv3 driver: Add extended PPI and SPI range
This patch provides support for GICv3.1 extended PPI and SPI
range. The option is enabled by setting to 1 and passing
`GIC_EXT_INTID` build flag to gicv3.mk makefile.
This option defaults to 0 with no extended range support.
Change-Id: I7d09086fe22ea531c5df51a8a1efd8928458d394
Signed-off-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
Diffstat (limited to 'drivers/arm/gic/v3/gicv3_helpers.c')
-rw-r--r-- | drivers/arm/gic/v3/gicv3_helpers.c | 207 |
1 files changed, 135 insertions, 72 deletions
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index d5aaf96966..09fa6786e1 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -31,8 +31,8 @@ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 0 */ - while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U) - ; + while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U) { + } } /****************************************************************************** @@ -45,11 +45,10 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base) gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 1 */ - while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) - ; + while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) { + } } - /******************************************************************************* * This function probes the Redistributor frames when the driver is initialised * and saves their base addresses. These base addresses are used later to @@ -84,47 +83,78 @@ void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, TYPER_PROC_NUM_MASK; } - if (proc_num < rdistif_num) + if (proc_num < rdistif_num) { rdistif_base_addrs[proc_num] = rdistif_base; + } rdistif_base += (1U << GICR_PCPUBASE_SHIFT); } while ((typer_val & TYPER_LAST_BIT) == 0U); } /******************************************************************************* - * Helper function to configure the default attributes of SPIs. + * Helper function to configure the default attributes of (E)SPIs. ******************************************************************************/ void gicv3_spis_config_defaults(uintptr_t gicd_base) { - unsigned int index, num_ints; + unsigned int i, num_ints; +#if GIC_EXT_INTID + unsigned int num_eints; +#endif + unsigned int typer_reg = gicd_read_typer(gicd_base); + + /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */ + num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5; + + /* Treat all (E)SPIs as G1NS by default. We do 32 at a time. */ + for (i = MIN_SPI_ID; i < num_ints; i += (1U << IGROUPR_SHIFT)) { + gicd_write_igroupr(gicd_base, i, ~0U); + } - num_ints = gicd_read_typer(gicd_base); - num_ints &= TYPER_IT_LINES_NO_MASK; - num_ints = (num_ints + 1U) << 5; +#if GIC_EXT_INTID + /* Check if extended SPI range is implemented */ + if ((typer_reg & TYPER_ESPI) != 0U) { + /* + * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095 + */ + num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) & + TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID - 1; - /* - * Treat all SPIs as G1NS by default. The number of interrupts is - * calculated as 32 * (IT_LINES + 1). We do 32 at a time. - */ - for (index = MIN_SPI_ID; index < num_ints; index += 32U) - gicd_write_igroupr(gicd_base, index, ~0U); + for (i = MIN_ESPI_ID; i < num_eints; + i += (1U << IGROUPR_SHIFT)) { + gicd_write_igroupr(gicd_base, i, ~0U); + } + } else { + num_eints = 0U; + } +#endif - /* Setup the default SPI priorities doing four at a time */ - for (index = MIN_SPI_ID; index < num_ints; index += 4U) - gicd_write_ipriorityr(gicd_base, - index, - GICD_IPRIORITYR_DEF_VAL); + /* Setup the default (E)SPI priorities doing four at a time */ + for (i = MIN_SPI_ID; i < num_ints; i += (1U << IPRIORITYR_SHIFT)) { + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + } +#if GIC_EXT_INTID + for (i = MIN_ESPI_ID; i < num_eints; + i += (1U << IPRIORITYR_SHIFT)) { + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + } +#endif /* - * Treat all SPIs as level triggered by default, write 16 at - * a time + * Treat all (E)SPIs as level triggered by default, write 16 at a time */ - for (index = MIN_SPI_ID; index < num_ints; index += 16U) - gicd_write_icfgr(gicd_base, index, 0U); + for (i = MIN_SPI_ID; i < num_ints; i += (1U << ICFGR_SHIFT)) { + gicd_write_icfgr(gicd_base, i, 0U); + } + +#if GIC_EXT_INTID + for (i = MIN_ESPI_ID; i < num_eints; i += (1U << ICFGR_SHIFT)) { + gicd_write_icfgr(gicd_base, i, 0U); + } +#endif } /******************************************************************************* - * Helper function to configure properties of secure SPIs + * Helper function to configure properties of secure (E)SPIs ******************************************************************************/ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, @@ -136,80 +166,108 @@ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ - if (interrupt_props_num > 0U) + if (interrupt_props_num > 0U) { assert(interrupt_props != NULL); + } for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; - if (current_prop->intr_num < MIN_SPI_ID) + unsigned int intr_num = current_prop->intr_num; + + /* Skip SGI, (E)PPI and LPI interrupts */ + if (!IS_SPI(intr_num)) { continue; + } /* Configure this interrupt as a secure interrupt */ - gicd_clr_igroupr(gicd_base, current_prop->intr_num); + gicd_clr_igroupr(gicd_base, 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); + gicd_set_igrpmodr(gicd_base, intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { - gicd_clr_igrpmodr(gicd_base, current_prop->intr_num); + gicd_clr_igrpmodr(gicd_base, intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set interrupt configuration */ - gicd_set_icfgr(gicd_base, current_prop->intr_num, - current_prop->intr_cfg); + gicd_set_icfgr(gicd_base, 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); + gicd_set_ipriorityr(gicd_base, intr_num, + current_prop->intr_pri); - /* Target SPIs to the primary CPU */ + /* Target (E)SPIs to the primary CPU */ gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0U); - gicd_write_irouter(gicd_base, current_prop->intr_num, - gic_affinity_val); + gicd_write_irouter(gicd_base, intr_num, + gic_affinity_val); /* Enable this interrupt */ - gicd_set_isenabler(gicd_base, current_prop->intr_num); + gicd_set_isenabler(gicd_base, intr_num); } return ctlr_enable; } /******************************************************************************* - * Helper function to configure the default attributes of SPIs. + * Helper function to configure the default attributes of (E)SPIs ******************************************************************************/ void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base) { - unsigned int index; - + unsigned int i, ppi_regs_num, regs_num; + +#if GIC_EXT_INTID + /* Calculate number of PPI registers */ + ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >> + TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1; + /* All other values except PPInum [0-2] are reserved */ + if (ppi_regs_num > 3U) { + ppi_regs_num = 1U; + } +#else + ppi_regs_num = 1U; +#endif /* - * 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 + * Disable all SGIs (imp. def.)/(E)PPIs before configuring them. + * This is a more scalable approach as it avoids clearing + * the enable bits in the GICD_CTLR. */ - gicr_write_icenabler0(gicr_base, ~0U); + for (i = 0U; i < ppi_regs_num; ++i) { + gicr_write_icenabler(gicr_base, i, ~0U); + } + + /* Wait for pending writes to GICR_ICENABLER */ gicr_wait_for_pending_write(gicr_base); - /* Treat all SGIs/PPIs as G1NS by default. */ - gicr_write_igroupr0(gicr_base, ~0U); + /* 32 interrupt IDs per GICR_IGROUPR register */ + for (i = 0U; i < ppi_regs_num; ++i) { + /* Treat all SGIs/(E)PPIs as G1NS by default */ + gicr_write_igroupr(gicr_base, i, ~0U); + } - /* Setup the default PPI/SGI priorities doing four at a time */ - for (index = 0U; index < MIN_SPI_ID; index += 4U) - gicr_write_ipriorityr(gicr_base, - index, - GICD_IPRIORITYR_DEF_VAL); + /* 4 interrupt IDs per GICR_IPRIORITYR register */ + regs_num = ppi_regs_num << 3; + for (i = 0U; i < regs_num; ++i) { + /* Setup the default (E)PPI/SGI priorities doing 4 at a time */ + gicr_write_ipriorityr(gicr_base, i, GICD_IPRIORITYR_DEF_VAL); + } - /* Configure all PPIs as level triggered by default */ - gicr_write_icfgr1(gicr_base, 0U); + /* 16 interrupt IDs per GICR_ICFGR register */ + regs_num = ppi_regs_num << 1; + for (i = (MIN_PPI_ID >> ICFGR_SHIFT); i < regs_num; ++i) { + /* Configure all (E)PPIs as level triggered by default */ + gicr_write_icfgr(gicr_base, i, 0U); + } } /******************************************************************************* - * Helper function to configure properties of secure G0 and G1S PPIs and SGIs. + * Helper function to configure properties of secure G0 and G1S (E)PPIs and SGIs ******************************************************************************/ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, const interrupt_prop_t *interrupt_props, @@ -220,45 +278,50 @@ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ - if (interrupt_props_num > 0U) + if (interrupt_props_num > 0U) { assert(interrupt_props != NULL); + } for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; - if (current_prop->intr_num >= MIN_SPI_ID) + unsigned int intr_num = current_prop->intr_num; + + /* Skip (E)SPI interrupt */ + if (!IS_SGI_PPI(intr_num)) { continue; + } /* Configure this interrupt as a secure interrupt */ - gicr_clr_igroupr0(gicr_base, current_prop->intr_num); + gicr_clr_igroupr(gicr_base, intr_num); /* Configure this interrupt as G0 or a G1S interrupt */ assert((current_prop->intr_grp == INTR_GROUP0) || - (current_prop->intr_grp == INTR_GROUP1S)); + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) { - gicr_set_igrpmodr0(gicr_base, current_prop->intr_num); + gicr_set_igrpmodr(gicr_base, intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { - gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num); + gicr_clr_igrpmodr(gicr_base, intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set the priority of this interrupt */ - gicr_set_ipriorityr(gicr_base, current_prop->intr_num, - current_prop->intr_pri); + gicr_set_ipriorityr(gicr_base, intr_num, + current_prop->intr_pri); /* - * Set interrupt configuration for PPIs. Configuration for SGIs - * are ignored. + * Set interrupt configuration for (E)PPIs. + * Configurations for SGIs 0-15 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, + if (intr_num >= MIN_PPI_ID) { + gicr_set_icfgr(gicr_base, intr_num, current_prop->intr_cfg); } /* Enable this interrupt */ - gicr_set_isenabler0(gicr_base, current_prop->intr_num); + gicr_set_isenabler(gicr_base, intr_num); } return ctlr_enable; |