refactor(gicv3): clarify redistributor base address usage with USE_GIC_DRIVER=3

The GICv3 driver has 2 methods of discovering the redistributors:
a) via setting gicr_base - done at boot and assumes all GICR frames are
   contiguous. This is the original method.

b) via gicv3_rdistif_probe() - called from platform code and requires
   gicr_base == 0. It relaxes the requirement for frames to be
   contiguous, like in a multichip configuration, and defers the
   discovery to core bringup. This was introduced later.

Configurations possible with option a) are also possible with option b)
with only slightly different behaviour. USE_GIC_DRIVER=3 inherited
option b) from plat_gicv3_base.c and as such option a) is unusable.
However, it is unclear from code how this should be used. Clarify this
by requiring platforms initialise with gic_set_gicr_frames() and
adding relevant comments.

Also rename plat_arm_override_gicr_frames() to gic_set_gicr_frames() as
this is not plat arm specific and a part of the generic GIC driver.

Change-Id: I61d77211f8e65dc54cf9904069b500d26a06b5a5
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 6d3fea1..23de63f 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -1336,7 +1336,9 @@
  - ``2``: use the GICv2 driver
 
  - ``3``: use the GICv3 driver. See the next section on how to further configure
-   it. Use this option for GICv4 implementations.
+   it. Use this option for GICv4 implementations. Requires calling
+   ``gic_set_gicr_frames()``.
+
  - ``5``: use the EXPERIMENTAL GICv5 driver. Requires ``ENABLE_FEAT_GCIE=1``.
 
  For GIC driver versions other than ``1``, deciding when to save and restore GIC
diff --git a/drivers/arm/gic/v3/gicv3_base.c b/drivers/arm/gic/v3/gicv3_base.c
index 1a65758..20b2ea8 100644
--- a/drivers/arm/gic/v3/gicv3_base.c
+++ b/drivers/arm/gic/v3/gicv3_base.c
@@ -22,14 +22,8 @@
 /* The GICv3 driver only needs to be initialized in EL3 */
 uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
 
-/* Default GICR base address to be used for GICR probe. */
-static const uintptr_t gicr_base_addrs[2] = {
-	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
-	0U			/* Zero Termination */
-};
-
 /* List of zero terminated GICR frame addresses which CPUs will probe */
-static const uintptr_t *gicr_frames = gicr_base_addrs;
+static const uintptr_t *gicr_frames = NULL;
 
 static const interrupt_prop_t arm_interrupt_props[] = {
 #ifdef PLAT_ARM_G1S_IRQ_PROPS
@@ -78,6 +72,8 @@
 
 gicv3_driver_data_t gic_data __unused = {
 	.gicd_base = PLAT_ARM_GICD_BASE,
+	/* unused for USE_GIC_DRIVER=3. Use gic_set_gicr_frames(), passing a ptr
+	 * to an array with 2 values - the frame's base and a NULL pointer */
 	.gicr_base = 0U,
 	.interrupt_props = arm_interrupt_props,
 	.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
@@ -87,12 +83,12 @@
 };
 
 /*
- * By default, gicr_frames will be pointing to gicr_base_addrs. If
- * the platform supports a non-contiguous GICR frames (GICR frames located
- * at uneven offset), plat_arm_override_gicr_frames function can be used by
- * such platform to override the gicr_frames.
+ * Initialises the gicr_frames array. It contains a NULL terminated list of
+ * non-contiguous blocks of GICR frames (located at uneven offsets). Most
+ * platforms will have one such block, except multichip configurations, which
+ * will usually have multiple.
  */
-void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames)
+void gic_set_gicr_frames(const uintptr_t *plat_gicr_frames)
 {
 	assert(plat_gicr_frames != NULL);
 	gicr_frames = plat_gicr_frames;
@@ -130,18 +126,21 @@
  *****************************************************************************/
 void gic_pcpu_init(unsigned int cpu_idx)
 {
-	int result;
-	const uintptr_t *plat_gicr_frames = gicr_frames;
+	/* to guard against an empty array */
+	int result = -1;
+
+	/* did the paltform initialise the array with gic_set_gicr_frames() */
+	assert(gicr_frames != NULL);
 
 	do {
-		result = gicv3_rdistif_probe(*plat_gicr_frames);
+		result = gicv3_rdistif_probe(*gicr_frames);
 
 		/* If the probe is successful, no need to proceed further */
 		if (result == 0)
 			break;
 
-		plat_gicr_frames++;
-	} while (*plat_gicr_frames != 0U);
+		gicr_frames++;
+	} while (*gicr_frames != 0U);
 
 	if (result == -1) {
 		ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 0573f3b..39a9bc2 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -376,7 +376,7 @@
 /*
  * Optional functions in ARM standard platforms
  */
-void plat_arm_override_gicr_frames(const uintptr_t *plat_gicr_frames);
+void gic_set_gicr_frames(const uintptr_t *plat_gicr_frames);
 int arm_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
 	unsigned int *flags);
 int arm_get_rotpk_info_regs(void **key_ptr, unsigned int *key_len,
diff --git a/plat/arm/board/fvp/fvp_gicv3.c b/plat/arm/board/fvp/fvp_gicv3.c
index 4167229..9071f41 100644
--- a/plat/arm/board/fvp/fvp_gicv3.c
+++ b/plat/arm/board/fvp/fvp_gicv3.c
@@ -96,6 +96,6 @@
 	gic_data.interrupt_props = fvp_interrupt_props;
 	gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props);
 #endif
-	plat_arm_override_gicr_frames(fvp_gicr_base_addrs);
+	gic_set_gicr_frames(fvp_gicr_base_addrs);
 #endif /* !(BL2_AT_EL3 || RESET_TO_BL31 || RESET_TO_SP_MIN || RESET_TO_BL2) */
 }
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index d8d60ef..9300c14 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -124,7 +124,7 @@
 
 void n1sdp_bl31_multichip_setup(void)
 {
-	plat_arm_override_gicr_frames(n1sdp_multichip_gicr_frames);
+	gic_set_gicr_frames(n1sdp_multichip_gicr_frames);
 	gic600_multichip_init(&n1sdp_multichip_data);
 }
 
diff --git a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
index cf820b8..1f02c77 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -174,7 +174,7 @@
 			}
 		}
 
-		plat_arm_override_gicr_frames(
+		gic_set_gicr_frames(
 			rdn2mc_multichip_gicr_frames);
 		gic600_multichip_init(&rdn2mc_multichip_data);
 	}
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
index e32e761..a9c957e 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -171,7 +171,7 @@
 			}
 		}
 
-		plat_arm_override_gicr_frames(
+		gic_set_gicr_frames(
 			rdv3mc_multichip_gicr_frames);
 		gic600_multichip_init(&rdv3mc_multichip_data);
 	}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 353efac..c38418e 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -28,6 +28,13 @@
 struct transfer_list_header *secure_tl;
 struct transfer_list_header *ns_tl __unused;
 
+#if USE_GIC_DRIVER == 3
+const uintptr_t gicr_base_addrs[2] = {
+	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
+	0U			/* Zero Termination */
+};
+#endif
+
 /*
  * Placeholder variables for copying the arguments that have been passed to
  * BL31 from BL2.
@@ -427,6 +434,10 @@
 #if USE_DEBUGFS
 	debugfs_init();
 #endif /* USE_DEBUGFS */
+
+#if USE_GIC_DRIVER == 3
+	gic_set_gicr_frames(gicr_base_addrs);
+#endif
 }
 
 /*******************************************************************************
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
index 2b52a76..f9a884e 100644
--- a/plat/arm/common/sp_min/arm_sp_min_setup.c
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -21,6 +21,13 @@
 
 static entry_point_info_t bl33_image_ep_info;
 
+#if USE_GIC_DRIVER == 3
+static const uintptr_t gicr_base_addrs[2] = {
+	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
+	0U			/* Zero Termination */
+};
+#endif
+
 /* Weak definitions may be overridden in specific ARM standard platform */
 #pragma weak sp_min_platform_setup
 #pragma weak sp_min_plat_arch_setup
@@ -206,6 +213,9 @@
 	/* Initialize the GIC driver, cpu and distributor interfaces */
 	unsigned int core_pos = plat_my_core_pos();
 
+#if USE_GIC_DRIVER == 3
+	gic_set_gicr_frames(gicr_base_addrs);
+#endif
 	gic_init(core_pos);
 	gic_pcpu_init(core_pos);
 	gic_cpuif_enable(core_pos);
diff --git a/plat/xilinx/versal_net/bl31_versal_net_setup.c b/plat/xilinx/versal_net/bl31_versal_net_setup.c
index 907deee..089f9b1 100644
--- a/plat/xilinx/versal_net/bl31_versal_net_setup.c
+++ b/plat/xilinx/versal_net/bl31_versal_net_setup.c
@@ -30,6 +30,11 @@
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
 
+static const uintptr_t gicr_base_addrs[2] = {
+	PLAT_ARM_GICR_BASE,	/* GICR Base address of the primary CPU */
+	0U			/* Zero Termination */
+};
+
 /*
  * Return a pointer to the 'entry_point_info' structure of the next image for
  * the security state specified. BL33 corresponds to the non-secure image type
@@ -242,6 +247,8 @@
 void bl31_platform_setup(void)
 {
 	prepare_dtb();
+
+	gic_set_gicr_frames(gicr_base_addrs);
 }
 
 void bl31_plat_runtime_setup(void)