From 6443c4b91a0f792a5fa904b2045b055b9733283a Mon Sep 17 00:00:00 2001
From: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Date: Thu, 15 Jan 2026 19:02:08 +0000
Subject: [PATCH 2/3] gic: refactor implementation of GICv3 to add GICv4
 support

Refactor the definitions of GICv3 to facilitate adding support for
GICv4 by:
* Add macro for registers frame sizes based on GIC versions.
* Add macro for number of frame count for GICR based on GICv3 or GICv4.
* Add single GICR region size definition (GIC_REDIST_REG_SIZE)
  based on GIC version in platform independent include/drivers/gic.h
  along with existing GIC_CPU_REG_SIZE and GIC_DIST_REG_SIZE
  definitions.
* Amend usage of the now platform independent GIC_REDIST_REG_SIZE
  as it no longer includes a multiplication by the number of core on
  the target platform.
* Sort in ascending order the listing of GICR register definitions and
  add comments to denote each definitions sections.
* Add definitions for each GICR frames.
* Ensure that all relevant code sections that compile for CFG_ARM_GICV3
  also compile for CFG_ARM_GICV4.

Upstream-Status: Submitted [https://github.com/OP-TEE/optee_os/pull/7682]
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Reviewed-by: Jerome Forissier <jerome.forissier@arm.com>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
---
 core/arch/arm/arm.mk                          |  6 +-
 core/arch/arm/include/arm32.h                 |  3 +-
 core/arch/arm/include/arm32_macros.S          |  3 +-
 core/arch/arm/kernel/sub.mk                   |  2 +-
 core/arch/arm/plat-corstone1000/main.c        |  9 +--
 .../arm/plat-corstone1000/platform_config.h   | 12 +---
 core/drivers/gic.c                            | 58 +++++++++++--------
 core/include/drivers/gic.h                    | 46 +++++++++++++--
 8 files changed, 90 insertions(+), 49 deletions(-)

diff --git a/core/arch/arm/arm.mk b/core/arch/arm/arm.mk
index 1bf01063e..8d159e625 100644
--- a/core/arch/arm/arm.mk
+++ b/core/arch/arm/arm.mk
@@ -151,8 +151,10 @@ endif
 ifeq ($(CFG_CORE_FFA)-$(CFG_WITH_PAGER),y-y)
 $(error CFG_CORE_FFA and CFG_WITH_PAGER are not compatible)
 endif
+_CFG_ARM_V3_OR_V4 := $(call cfg-one-enabled, CFG_ARM_GICV3 CFG_ARM_GICV4)
+
 ifeq ($(CFG_GIC),y)
-ifeq ($(CFG_ARM_GICV3),y)
+ifeq ($(_CFG_ARM_V3_OR_V4),y)
 $(call force,CFG_CORE_IRQ_IS_NATIVE_INTR,y)
 else
 $(call force,CFG_CORE_IRQ_IS_NATIVE_INTR,n)
@@ -438,7 +440,7 @@ arm32-sysregs-$(arm32-sysreg-txt)-h := arm32_sysreg.h
 arm32-sysregs-$(arm32-sysreg-txt)-s := arm32_sysreg.S
 arm32-sysregs += $(arm32-sysreg-txt)
 
-ifeq ($(CFG_ARM_GICV3),y)
+ifeq ($(_CFG_ARM_V3_OR_V4),y)
 arm32-gicv3-sysreg-txt = core/arch/arm/kernel/arm32_gicv3_sysreg.txt
 arm32-sysregs-$(arm32-gicv3-sysreg-txt)-h := arm32_gicv3_sysreg.h
 arm32-sysregs-$(arm32-gicv3-sysreg-txt)-s := arm32_gicv3_sysreg.S
diff --git a/core/arch/arm/include/arm32.h b/core/arch/arm/include/arm32.h
index ef729d492..195afcacc 100644
--- a/core/arch/arm/include/arm32.h
+++ b/core/arch/arm/include/arm32.h
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2026, Arm Limited
  */
 
 #ifndef __ARM32_H
@@ -165,7 +166,7 @@
 
 #ifndef __ASSEMBLER__
 #include <generated/arm32_sysreg.h>
-#ifdef CFG_ARM_GICV3
+#ifdef _CFG_ARM_V3_OR_V4
 #include <generated/arm32_gicv3_sysreg.h>
 #endif
 
diff --git a/core/arch/arm/include/arm32_macros.S b/core/arch/arm/include/arm32_macros.S
index 95077a075..9db4722dd 100644
--- a/core/arch/arm/include/arm32_macros.S
+++ b/core/arch/arm/include/arm32_macros.S
@@ -1,10 +1,11 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
  * Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2026, Arm Limited
  */
 
 #include <generated/arm32_sysreg.S>
-#ifdef CFG_ARM_GICV3
+#ifdef _CFG_ARM_V3_OR_V4
 #include <generated/arm32_gicv3_sysreg.S>
 #endif
 
diff --git a/core/arch/arm/kernel/sub.mk b/core/arch/arm/kernel/sub.mk
index 40b7a3f92..071f223a5 100644
--- a/core/arch/arm/kernel/sub.mk
+++ b/core/arch/arm/kernel/sub.mk
@@ -69,7 +69,7 @@ asm-defines-y += asm-defines.c
 #     <asm.h> includes <generated/arm32_sysreg.h>
 #                  and <generated/arm32_gicv3_sysreg.h> (optional)
 asm-defines-asm-defines.c-deps += $(out-dir)/core/include/generated/arm32_sysreg.h
-ifeq ($(CFG_ARM_GICV3),y)
+ifeq ($(_CFG_ARM_V3_OR_V4),y)
 asm-defines-asm-defines.c-deps += $(out-dir)/core/include/generated/arm32_gicv3_sysreg.h
 endif
 
diff --git a/core/arch/arm/plat-corstone1000/main.c b/core/arch/arm/plat-corstone1000/main.c
index 376d9c9c6..e1bedddfe 100644
--- a/core/arch/arm/plat-corstone1000/main.c
+++ b/core/arch/arm/plat-corstone1000/main.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: BSD-2-Clause
 /*
- * Copyright (c) 2022, 2025, Arm Limited
+ * Copyright (c) 2022, 2025-2026, Arm Limited
  */
 
 #include <console.h>
@@ -19,15 +19,16 @@ register_ddr(DRAM0_BASE, DRAM0_SIZE);
 register_phys_mem_pgdir(MEM_AREA_IO_SEC, CONSOLE_UART_BASE, PL011_REG_SIZE);
 register_phys_mem_pgdir(MEM_AREA_IO_SEC, GICD_BASE, GIC_DIST_REG_SIZE);
 
-#ifdef CFG_ARM_GICV3
-register_phys_mem_pgdir(MEM_AREA_IO_SEC, GICR_BASE, GIC_REDIST_REG_SIZE);
+#ifdef _CFG_ARM_V3_OR_V4
+register_phys_mem_pgdir(MEM_AREA_IO_SEC, GICR_BASE,
+			GIC_REDIST_REG_SIZE * CFG_TEE_CORE_NB_CORE);
 #else
 register_phys_mem_pgdir(MEM_AREA_IO_SEC, GICC_BASE, GIC_CPU_REG_SIZE);
 #endif
 
 void boot_primary_init_intc(void)
 {
-#ifdef CFG_ARM_GICV3
+#ifdef _CFG_ARM_V3_OR_V4
 	gic_init_v3(0, GICD_BASE, GICR_BASE);
 #else
 	gic_init(GICC_BASE, GICD_BASE);
diff --git a/core/arch/arm/plat-corstone1000/platform_config.h b/core/arch/arm/plat-corstone1000/platform_config.h
index 7a1af3e4c..98dac8ee0 100644
--- a/core/arch/arm/plat-corstone1000/platform_config.h
+++ b/core/arch/arm/plat-corstone1000/platform_config.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: BSD-2-Clause */
 /*
- * Copyright (c) 2022, 2025 Arm Limited
+ * Copyright (c) 2022, 2025-2026 Arm Limited
  */
 
 #ifndef PLATFORM_CONFIG_H
@@ -20,13 +20,7 @@
 #define DRAM0_BASE		0x80000000
 #define DRAM0_SIZE		CFG_DDR_SIZE
 
-#ifdef CFG_ARM_GICV3
-#define GICR_SIZE_PER_CORE	0x20000
-#define GIC_REDIST_REG_SIZE	(GICR_SIZE_PER_CORE * CFG_TEE_CORE_NB_CORE)
-#endif
-
-#ifdef CFG_ARM_GICV3
-/* Corstone-1000 with Cortex-A320 uses GIC-v3 which supports GICR */
+#ifdef _CFG_ARM_V3_OR_V4
 #define GICD_OFFSET		0x00000
 #define GICR_OFFSET		0x40000
 #else
@@ -34,7 +28,7 @@
 #define GICC_OFFSET		0x2F000
 #endif
 
-#ifdef CFG_ARM_GICV3
+#ifdef _CFG_ARM_V3_OR_V4
 #define GICR_BASE		(GIC_BASE + GICR_OFFSET)
 #else
 #define GICC_BASE		(GIC_BASE + GICC_OFFSET)
diff --git a/core/drivers/gic.c b/core/drivers/gic.c
index be0193416..af7783d32 100644
--- a/core/drivers/gic.c
+++ b/core/drivers/gic.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2016-2017, 2023-2024 Linaro Limited
  * Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2026 Arm Limited
  */
 
 #include <arm.h>
@@ -49,7 +50,7 @@
 #define GICD_IGROUPMODR(n)	(0xd00 + (n) * 4)
 #define GICD_SGIR		(0xF00)
 
-#ifdef CFG_ARM_GICV3
+#ifdef _CFG_ARM_V3_OR_V4
 #define GICD_PIDR2		(0xFFE8)
 #else
 /* Called ICPIDR2 in GICv2 specification */
@@ -63,22 +64,29 @@
 #define GICD_CTLR_ARE_NS	BIT32(5)
 
 /* Offsets from gic.gicr_base[core_pos] */
-#define GICR_V3_PCPUBASE_SIZE	(2 * 64 * 1024)
-#define GICR_SGI_BASE_OFFSET	(64 * 1024)
-#define GICR_CTLR		(0x00)
-#define GICR_TYPER		(0x08)
+#define GICR_RD_BASE_OFFSET         (0x0000)
+#define GICR_SGI_BASE_OFFSET        (GICR_RD_BASE_OFFSET + GICR_FRAME_SIZE)
+#define GICR_VLPI_BASE_OFFSET       (GICR_SGI_BASE_OFFSET + GICR_FRAME_SIZE)
+#define GICR_RESERVED_BASE_OFFSET   (GICR_VLPI_BASE_OFFSET + GICR_FRAME_SIZE)
 
+/* GIC physical LPI Redistributor register map */
+#define GICR_CTLR		(GICR_RD_BASE_OFFSET + 0x0000)
+#define GICR_TYPER		(GICR_RD_BASE_OFFSET + 0x0008)
+
+/* GIC SGI and PPI Redistributor register map */
 #define GICR_IGROUPR0		(GICR_SGI_BASE_OFFSET + 0x080)
-#define GICR_IGRPMODR0		(GICR_SGI_BASE_OFFSET + 0xD00)
+#define GICR_ISENABLER0		(GICR_SGI_BASE_OFFSET + 0x100)
 #define GICR_ICENABLER0		(GICR_SGI_BASE_OFFSET + 0x180)
 #define GICR_ICPENDR0		(GICR_SGI_BASE_OFFSET + 0x280)
-#define GICR_ISENABLER0		(GICR_SGI_BASE_OFFSET + 0x100)
+#define GICR_IPRIORITYR(n)	(GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4)
 #define GICR_ICFGR0		(GICR_SGI_BASE_OFFSET + 0xC00)
 #define GICR_ICFGR1		(GICR_SGI_BASE_OFFSET + 0xC04)
-#define GICR_IPRIORITYR(n)	(GICR_SGI_BASE_OFFSET + 0x400 + (n) * 4)
+#define GICR_IGRPMODR0		(GICR_SGI_BASE_OFFSET + 0xD00)
 
+/* GICR_CTLR, Redistributor Control Register bits */
 #define GICR_CTLR_RWP		BIT32(3)
 
+/* GICR_TYPER, Redistributor Type Register bits */
 #define GICR_TYPER_LAST		BIT64(4)
 #define GICR_TYPER_AFF3_SHIFT	56
 #define GICR_TYPER_AFF2_SHIFT	48
@@ -136,7 +144,7 @@
 struct gic_data {
 	vaddr_t gicc_base;
 	vaddr_t gicd_base;
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	vaddr_t gicr_base[CFG_TEE_CORE_NB_CORE];
 #endif
 	size_t max_it;
@@ -174,7 +182,7 @@ DECLARE_KEEP_PAGER(gic_ops);
 
 static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
 {
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	return gd->gicr_base[get_core_pos()];
 #else
 	return 0;
@@ -183,7 +191,7 @@ static vaddr_t __maybe_unused get_gicr_base(struct gic_data *gd __maybe_unused)
 
 static bool affinity_routing_is_enabled(struct gic_data *gd)
 {
-	return IS_ENABLED(CFG_ARM_GICV3) &&
+	return IS_ENABLED2(_CFG_ARM_V3_OR_V4) &&
 	       io_read32(gd->gicd_base + GICD_CTLR) & GICD_CTLR_ARE_S;
 }
 
@@ -198,7 +206,7 @@ static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
 	/*
 	 * Probe which interrupt number is the largest.
 	 */
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	old_ctlr = read_icc_ctlr();
 	write_icc_ctlr(0);
 #else
@@ -222,7 +230,7 @@ static size_t probe_max_it(vaddr_t gicc_base __maybe_unused, vaddr_t gicd_base)
 		}
 	}
 out:
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	write_icc_ctlr(old_ctlr);
 #else
 	io_write32(gicc_base + GICC_CTLR, old_ctlr);
@@ -342,7 +350,7 @@ static void init_gic_per_cpu(struct gic_data *gd)
 	 * Set the priority mask to permit Non-secure interrupts, and to
 	 * allow the Non-secure world to adjust the priority mask itself
 	 */
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	write_icc_pmr(0x80);
 	write_icc_igrpen1(1);
 #else
@@ -359,7 +367,7 @@ void gic_init_per_cpu(void)
 {
 	struct gic_data *gd = &gic_data;
 
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	assert(gd->gicd_base);
 #else
 	assert(gd->gicd_base && gd->gicc_base);
@@ -481,7 +489,7 @@ static int gic_dt_get_irq(const uint32_t *properties, int count, uint32_t *type,
 static void __maybe_unused probe_redist_base_addrs(vaddr_t *gicr_base_addrs,
 						   paddr_t gicr_base_pa)
 {
-	size_t sz = GICR_V3_PCPUBASE_SIZE;
+	size_t sz = GIC_REDIST_REG_SIZE;
 	paddr_t pa = gicr_base_pa;
 	size_t core_pos = 0;
 	uint64_t mt_bit = 0;
@@ -538,7 +546,7 @@ static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
 	vers >>= GICD_PIDR2_ARCHREV_SHIFT;
 	vers &= GICD_PIDR2_ARCHREV_MASK;
 
-	if (IS_ENABLED(CFG_ARM_GICV3)) {
+	if (IS_ENABLED2(_CFG_ARM_V3_OR_V4)) {
 		assert(vers == 4 || vers == 3);
 	} else {
 		assert(vers == 2 || vers == 1);
@@ -551,7 +559,7 @@ static void gic_init_base_addr(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
 	gd->gicc_base = gicc_base;
 	gd->gicd_base = gicd_base;
 	gd->max_it = probe_max_it(gicc_base, gicd_base);
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	if (affinity_routing_is_enabled(gd) && gicr_base_pa)
 		probe_redist_base_addrs(gd->gicr_base, gicr_base_pa);
 #endif
@@ -623,7 +631,7 @@ void gic_init_v3(paddr_t gicc_base_pa, paddr_t gicd_base_pa,
 	/* Set the priority mask to permit Non-secure interrupts, and to
 	 * allow the Non-secure world to adjust the priority mask itself
 	 */
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	write_icc_pmr(0x80);
 	write_icc_igrpen1(1);
 	io_setbits32(gd->gicd_base + GICD_CTLR, GICD_CTLR_ENABLEGRP1S);
@@ -654,7 +662,7 @@ static void gic_it_configure(struct gic_data *gd, size_t it)
 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
 	/* Assign it to group0 */
 	io_clrbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	/* Assign it to group1S */
 	io_setbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
 #endif
@@ -776,7 +784,7 @@ static void assert_cpu_mask_is_valid(uint32_t cpu_mask)
 static void gic_it_raise_sgi(struct gic_data *gd __maybe_unused, size_t it,
 			     uint32_t cpu_mask, bool ns)
 {
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	uint32_t mask_id = it & 0xf;
 	uint64_t mask = SHIFT_U64(mask_id, 24);
 
@@ -841,7 +849,7 @@ static uint32_t gic_read_iar(struct gic_data *gd __maybe_unused)
 {
 	assert(gd == &gic_data);
 
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	return read_icc_iar1();
 #else
 	return io_read32(gd->gicc_base + GICC_IAR);
@@ -852,7 +860,7 @@ static void gic_write_eoir(struct gic_data *gd __maybe_unused, uint32_t eoir)
 {
 	assert(gd == &gic_data);
 
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	write_icc_eoir1(eoir);
 #else
 	io_write32(gd->gicc_base + GICC_EOIR, eoir);
@@ -894,7 +902,7 @@ void gic_dump_state(void)
 	struct gic_data *gd = &gic_data;
 	int i = 0;
 
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	DMSG("GICC_CTLR: %#"PRIx32, read_icc_ctlr());
 #else
 	DMSG("GICC_CTLR: %#"PRIx32, io_read32(gd->gicc_base + GICC_CTLR));
@@ -932,7 +940,7 @@ TEE_Result gic_spi_release_to_ns(size_t it)
 	io_write32(gd->gicd_base + GICD_ICPENDR(idx), mask);
 	/* Assign it to NS Group1 */
 	io_setbits32(gd->gicd_base + GICD_IGROUPR(idx), mask);
-#if defined(CFG_ARM_GICV3)
+#ifdef _CFG_ARM_V3_OR_V4
 	io_clrbits32(gd->gicd_base + GICD_IGROUPMODR(idx), mask);
 #endif
 	mutex_unlock(&gic_mutex);
diff --git a/core/include/drivers/gic.h b/core/include/drivers/gic.h
index 0dfcca7e1..a17dbac0c 100644
--- a/core/include/drivers/gic.h
+++ b/core/include/drivers/gic.h
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2026 Arm Limited
  */
 
 #ifndef __DRIVERS_GIC_H
@@ -9,12 +10,45 @@
 #include <types_ext.h>
 #include <kernel/interrupt.h>
 
-#if defined(CFG_ARM_GICV3)
-#define GIC_DIST_REG_SIZE	0x10000
-#define GIC_CPU_REG_SIZE	0x10000
-#else
-#define GIC_DIST_REG_SIZE	0x1000
-#define GIC_CPU_REG_SIZE	0x1000
+#ifdef _CFG_ARM_V3_OR_V4
+#define GICD_FRAME_SIZE         (64 * 1024)
+#define GICC_FRAME_SIZE         (64 * 1024)
+#define GICR_FRAME_SIZE         (64 * 1024)
+#else /* GICv2 and earlier */
+#define GICD_FRAME_SIZE         (4 * 1024)
+#define GICC_FRAME_SIZE         (4 * 1024)
+#define GICR_FRAME_SIZE         0 /* Unsupported */
+#endif
+
+#define GIC_CPU_REG_SIZE        GICC_FRAME_SIZE
+#define GIC_DIST_REG_SIZE       GICD_FRAME_SIZE
+#ifdef _CFG_ARM_V3_OR_V4
+/*
+ * The frames for each Redistributor are contiguous and are ordered as
+ * follows:
+ * 1. RD_base
+ * 2. SGI_base
+ *
+ * In GICv4, there are two additional 64KB frames:
+ * - A frame to control virtual LPIs. The base address of this frame is
+ *   referred to as VLPI_base.
+ * - A reserved frame.
+ *
+ * The frames for each Redistributor are contiguous and are
+ * ordered as follows:
+ *   1. RD_base
+ *   2. SGI_base
+ *   3. VLPI_base
+ *   4. Reserved
+ */
+#ifdef CFG_ARM_GICV4
+#define GICR_FRAME_COUNT        4
+#else /* CFG_ARM_GICV3 */
+#define GICR_FRAME_COUNT        2
+#endif
+#define GIC_REDIST_REG_SIZE     (GICR_FRAME_COUNT * GICR_FRAME_SIZE)
+#else /* GICv2 and earlier */
+#define GIC_REDIST_REG_SIZE     0 /* Unsupported */
 #endif
 
 #define GIC_PPI_BASE		U(16)
-- 
2.50.1

