feat(gic): add support for local chip addressing
This patch adds support for Local Chip Addressing (LCA). In a multi-chip
system, enablig LCA allows each GIC Distributor to maintain its own
version of routing table. This feature is activated when the
GICD_CFGID.LCA bit is set to 1.
The existing `gic600_multichip_data` data structure did not account for
the LCA feature. To support LCA:
- `rt_owner_base` is replaced by `base_addrs[]`. This is required
because each GICD in the system needs to be configured independently,
and their base addresses must be passed to the driver.
- `chip_addrs` is changed from 1D to 2D array to store the routing table
for each chip's GICD. The entries in `chip_addrs` are configuration
dependent, as the GIC specification does not enforce this.
On a multi-chip platform with chip count N where LCA is enabled by
default, the `gic600_multichip_data` structure should contain all copies
of the routing table (N*N entries). On platforms where LCA is not
supported, only the first sub-array with N entries is required. The
function signature of `gic600_multichip_init` remains unchanged, but if
the LCA feature is enabled, the driver will expect the routing table
configuration in the described format.
Change-Id: I8830c2cf90db6a0cae78e99914cd32c637284a2b
Signed-off-by: Jerry Wang <Jerry.Wang4@arm.com>
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index 5e44aa9..6e9567e 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -322,12 +322,40 @@
}
/*******************************************************************************
+ * Initialize GIC-600 and GIC-700 Multichip operation in LCA mode by setting up
+ * the routing table first.
+ ******************************************************************************/
+static void gic600_multichip_lca_init(
+ struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i, j;
+ unsigned int rt_owner = multichip_data->rt_owner;
+
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ for (j = 0; j < multichip_data->chip_count; j++) {
+ INFO("RT(LCA): CHIP%u -> CHIP%u 0x%lx\n", i, j,
+ multichip_data->chip_addrs[i][j]);
+ set_gicd_chipr_n(multichip_data->base_addrs[i], j,
+ multichip_data->chip_addrs[i][j],
+ multichip_data->spi_ids[j].spi_id_min,
+ multichip_data->spi_ids[j].spi_id_max);
+ }
+ }
+
+ /* Initialize the GICD which is marked as routing table owner last */
+ set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+ rt_owner);
+}
+
+/*******************************************************************************
* Initialize GIC-600 and GIC-700 Multichip operation.
******************************************************************************/
void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
{
unsigned int i;
- uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
+ unsigned int rt_owner = multichip_data->rt_owner;
+ uint32_t gicd_iidr_val =
+ gicd_read_iidr(multichip_data->base_addrs[rt_owner]);
if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
gic600_multichip_validate_data(multichip_data);
@@ -341,16 +369,16 @@
* Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
* that GIC-600 Multichip configuration is done first.
*/
- if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
- (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
- CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+ if ((gicd_read_ctlr(multichip_data->base_addrs[rt_owner]) &
+ (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
ERROR("GICD_CTLR group interrupts are either enabled or have "
"pending writes.\n");
panic();
}
/* Ensure that the routing table owner is in disconnected state */
- if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
+ if (((read_gicd_chipsr(multichip_data->base_addrs[rt_owner]) &
GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
ERROR("GIC-600 routing table owner is not in disconnected "
@@ -358,25 +386,34 @@
panic();
}
- /* Initialize the GICD which is marked as routing table owner first */
- set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
- multichip_data->rt_owner);
+ /* If LCA is not enabled */
+ if ((read_gicd_cfgid(multichip_data->base_addrs[rt_owner]) &
+ GICD_CFGID_LCA_BIT) == 0) {
+ /*
+ * Initialize the GICD which is marked as routing table
+ * owner first.
+ */
+ set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+ rt_owner);
- set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
- multichip_data->chip_addrs[multichip_data->rt_owner],
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_min,
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_max);
+ set_gicd_chipr_n(multichip_data->base_addrs[rt_owner], rt_owner,
+ multichip_data->chip_addrs[rt_owner][rt_owner],
+ multichip_data->spi_ids[rt_owner].spi_id_min,
+ multichip_data->spi_ids[rt_owner].spi_id_max);
- for (i = 0; i < multichip_data->chip_count; i++) {
- if (i == multichip_data->rt_owner)
- continue;
-
- set_gicd_chipr_n(multichip_data->rt_owner_base, i,
- multichip_data->chip_addrs[i],
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ if (i == rt_owner)
+ continue;
+ set_gicd_chipr_n(
+ multichip_data->base_addrs[rt_owner], i,
+ multichip_data->chip_addrs[rt_owner][i],
multichip_data->spi_ids[i].spi_id_min,
multichip_data->spi_ids[i].spi_id_max);
+ }
+ } else {
+ /* If LCA is enabled */
+ INFO("GIC Local chip addressing is enabled\n");
+ gic600_multichip_lca_init(multichip_data);
}
plat_gic_multichip_data = multichip_data;
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
index fd1cb57..33030b3 100644
--- a/drivers/arm/gic/v3/gic600_multichip_private.h
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2023, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,12 +15,14 @@
#define GICD_CHIPSR U(0xC000)
#define GICD_DCHIPR U(0xC004)
#define GICD_CHIPR U(0xC008)
+#define GICD_CFGID U(0xF000)
/* GIC600 GICD multichip related masks */
#define GICD_CHIPRx_PUP_BIT BIT_64(1)
#define GICD_CHIPRx_SOCKET_STATE BIT_64(0)
#define GICD_DCHIPR_PUP_BIT BIT_32(0)
#define GICD_CHIPSR_RTS_MASK (BIT_32(4) | BIT_32(5))
+#define GICD_CFGID_LCA_BIT BIT_64(21)
/* GIC600 GICD multichip related shifts */
#define GICD_CHIPRx_ADDR_SHIFT 16
@@ -98,6 +100,11 @@
return mmio_read_32(base + GICD_CHIPSR);
}
+static inline uint64_t read_gicd_cfgid(uintptr_t base)
+{
+ return mmio_read_64(base + GICD_CFGID);
+}
+
static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
{
mmio_write_32(base + GICD_DCHIPR, val);
diff --git a/include/drivers/arm/gic600_multichip.h b/include/drivers/arm/gic600_multichip.h
index 978d735..d0f9027 100644
--- a/include/drivers/arm/gic600_multichip.h
+++ b/include/drivers/arm/gic600_multichip.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
* Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -49,10 +49,10 @@
* value of {0, 0, 0} should be passed.
******************************************************************************/
struct gic600_multichip_data {
- uintptr_t rt_owner_base;
+ uintptr_t base_addrs[GIC600_MAX_MULTICHIP];
unsigned int rt_owner;
unsigned int chip_count;
- uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
+ uint64_t chip_addrs[GIC600_MAX_MULTICHIP][GIC600_MAX_MULTICHIP];
multichip_spi_ids_desc_t spi_ids[GIC600_MAX_MULTICHIP];
};
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index 27ea7f7..d8d60ef 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -17,6 +17,8 @@
#include "n1sdp_private.h"
#include <platform_def.h>
+#define RT_OWNER 0
+
/*
* Platform information structure stored in SDS.
* This structure holds information about platform's DDR
@@ -44,12 +46,16 @@
};
static struct gic600_multichip_data n1sdp_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = 1,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- PLAT_ARM_GICD_BASE >> 16
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ PLAT_ARM_GICD_BASE >> 16
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE, 32, 511},
diff --git a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
index ccabe22..5cbdd5f 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
@@ -11,6 +11,8 @@
#include <nrd_plat.h>
+#define RT_OWNER 0
+
#if defined(IMAGE_BL31)
static const mmap_region_t rdn1edge_dynamic_mmap[] = {
NRD_CSS_SHARED_RAM_MMAP(1),
@@ -19,12 +21,17 @@
};
static struct gic600_multichip_data rdn1e1_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE,
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 b1046d6..84be243 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
@@ -13,6 +13,8 @@
#include <nrd_plat.h>
#include <rdn2_ras.h>
+#define RT_OWNER 0
+
#if defined(IMAGE_BL31)
#if (NRD_PLATFORM_VARIANT == 2)
static const mmap_region_t rdn2mc_dynamic_mmap[] = {
@@ -33,20 +35,27 @@
#if (NRD_PLATFORM_VARIANT == 2)
static struct gic600_multichip_data rdn2mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
#if NRD_CHIP_COUNT > 1
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
#endif
#if NRD_CHIP_COUNT > 2
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
#endif
#if NRD_CHIP_COUNT > 3
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
#endif
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE,
diff --git a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
index 5713cb9..0a40762 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
@@ -11,6 +11,8 @@
#include <nrd_plat.h>
+#define RT_OWNER 0
+
#if defined(IMAGE_BL31)
static const mmap_region_t rdv1mc_dynamic_mmap[] = {
NRD_CSS_SHARED_RAM_MMAP(1),
@@ -29,18 +31,25 @@
};
static struct gic600_multichip_data rdv1mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
#if (NRD_CHIP_COUNT > 2)
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
#endif
#if (NRD_CHIP_COUNT > 3)
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
#endif
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE,
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 a5d687e..3b32ecf 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
@@ -15,6 +15,8 @@
#include <nrd_variant.h>
#include <rdv3_rse_comms.h>
+#define RT_OWNER 0
+
#if (NRD_PLATFORM_VARIANT == 2)
static const mmap_region_t rdv3mc_dynamic_mmap[] = {
#if NRD_CHIP_COUNT > 1
@@ -32,20 +34,27 @@
};
static struct gic600_multichip_data rdv3mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
#if NRD_CHIP_COUNT > 1
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
#endif
#if NRD_CHIP_COUNT > 2
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
#endif
#if NRD_CHIP_COUNT > 3
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
#endif
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE, 32, 511},