diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 09fa6786e..ff346f9df 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -326,3 +326,33 @@ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, return ctlr_enable; } + +/** + * gicv3_rdistif_get_number_frames() - determine size of GICv3 GICR region + * @gicr_frame: base address of the GICR region to check + * + * This iterates over the GICR_TYPER registers of multiple GICR frames in + * a GICR region, to find the instance which has the LAST bit set. For most + * systems this corresponds to the number of cores handled by a redistributor, + * but there could be disabled cores among them. + * It assumes that each GICR region is fully accessible (till the LAST bit + * marks the end of the region). + * If a platform has multiple GICR regions, this function would need to be + * called multiple times, providing the respective GICR base address each time. + * + * Return: number of valid GICR frames (at least 1, up to PLATFORM_CORE_COUNT) + ******************************************************************************/ +unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame) +{ + uintptr_t rdistif_base = gicr_frame; + unsigned int count; + + for (count = 1; count < PLATFORM_CORE_COUNT; count++) { + if ((gicr_read_typer(rdistif_base) & TYPER_LAST_BIT) != 0U) { + break; + } + rdistif_base += (1U << GICR_PCPUBASE_SHIFT); + } + + return count; +} diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index 18d5b73e2..d8ac4cb33 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -488,6 +488,7 @@ void gicv3_distif_init(void); void gicv3_rdistif_init(unsigned int proc_num); void gicv3_rdistif_on(unsigned int proc_num); void gicv3_rdistif_off(unsigned int proc_num); +unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame); void gicv3_cpuif_enable(unsigned int proc_num); void gicv3_cpuif_disable(unsigned int proc_num); unsigned int gicv3_get_pending_interrupt_type(void);