aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexei Fedorov <Alexei.Fedorov@arm.com>2020-04-06 16:27:54 +0100
committerAlexei Fedorov <Alexei.Fedorov@arm.com>2020-04-06 16:27:54 +0100
commit8f3ad7661400c1cf23276f8ffff905102c54329a (patch)
tree92318678d279d68e21ede6d2fce5e4680e7eb4d0
parent37d56d3829f86ee5808b5f4a5a6b4dbdbb1bab67 (diff)
downloadtrusted-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>
-rw-r--r--docs/getting_started/build-options.rst3
-rw-r--r--drivers/arm/gic/v3/gicdv3_helpers.c226
-rw-r--r--drivers/arm/gic/v3/gicrv3_helpers.c186
-rw-r--r--drivers/arm/gic/v3/gicv3.mk8
-rw-r--r--drivers/arm/gic/v3/gicv3_helpers.c207
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c528
-rw-r--r--drivers/arm/gic/v3/gicv3_private.h268
-rw-r--r--include/drivers/arm/gicv3.h131
8 files changed, 1052 insertions, 505 deletions
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index e1c6c8f80a..38845ff0b6 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -693,6 +693,9 @@ makefile:
functions. This is required for FVP platform which need to simulate GIC save
and restore during SYSTEM_SUSPEND without powering down GIC. Default is 0.
+- ``GIC_EXT_INTID``: When set to ``1``, GICv3 driver will support extended
+ PPI (1056-1119) and SPI (4096-5119) range. This option defaults to 0.
+
Debugging options
-----------------
diff --git a/drivers/arm/gic/v3/gicdv3_helpers.c b/drivers/arm/gic/v3/gicdv3_helpers.c
index 3f5ff45fc8..987be69e7e 100644
--- a/drivers/arm/gic/v3/gicdv3_helpers.c
+++ b/drivers/arm/gic/v3/gicdv3_helpers.c
@@ -9,50 +9,236 @@
#include "gicv3_private.h"
/*******************************************************************************
- * GIC Distributor interface accessors for bit operations
+ * GIC Distributor functions for accessing the GIC registers
+ * corresponding to a single interrupt ID. These functions use bitwise
+ * operations or appropriate register accesses to modify or return
+ * the bit-field corresponding the single interrupt ID.
******************************************************************************/
/*
- * Accessor to read the GIC Distributor IGRPMODR corresponding to the
- * interrupt `id`, 32 interrupt IDs at a time.
+ * Accessors to set the bits corresponding to interrupt ID
+ * in GIC Distributor ICFGR and ICFGRE.
*/
-uint32_t gicd_read_igrpmodr(uintptr_t base, unsigned int id)
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
{
- return GICD_READ(IGRPMODR, base, id);
+ /* Interrupt configuration is a 2-bit field */
+ unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
+
+ /* Clear the field, and insert required configuration */
+ mmio_clrsetbits_32(base + GICD_OFFSET(ICFG, id),
+ (uint32_t)GIC_CFG_MASK << bit_shift,
+ (cfg & GIC_CFG_MASK) << bit_shift);
}
/*
- * Accessor to write the GIC Distributor IGRPMODR corresponding to the
- * interrupt `id`, 32 interrupt IDs at a time.
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGROUPR and IGROUPRE.
*/
-void gicd_write_igrpmodr(uintptr_t base, unsigned int id, uint32_t val)
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
+{
+ return GICD_GET_BIT(IGROUP, base, id);
+}
+
+void gicd_set_igroupr(uintptr_t base, unsigned int id)
+{
+ GICD_SET_BIT(IGROUP, base, id);
+}
+
+void gicd_clr_igroupr(uintptr_t base, unsigned int id)
{
- GICD_WRITE(IGRPMODR, base, id, val);
+ GICD_CLR_BIT(IGROUP, base, id);
}
/*
- * Accessor to get the bit corresponding to interrupt ID
- * in GIC Distributor IGRPMODR.
+ * Accessors to get/set/clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR and IGRPMODRE.
*/
unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
{
- return GICD_GET_BIT(IGRPMODR, base, id);
+ return GICD_GET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICD_SET_BIT(IGRPMOD, base, id);
+}
+
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+ GICD_CLR_BIT(IGRPMOD, base, id);
}
/*
- * Accessor to set the bit corresponding to interrupt ID
- * in GIC Distributor IGRPMODR.
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ICENABLER and ICENABLERE.
*/
-void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+void gicd_set_icenabler(uintptr_t base, unsigned int id)
{
- GICD_SET_BIT(IGRPMODR, base, id);
+ GICD_WRITE_BIT(ICENABLE, base, id);
}
/*
- * Accessor to clear the bit corresponding to interrupt ID
- * in GIC Distributor IGRPMODR.
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ICPENDR and ICPENDRE.
*/
-void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+void gicd_set_icpendr(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ICPEND, base, id);
+}
+
+/*
+ * Accessors to get/set the bit corresponding to interrupt ID
+ * in GIC Distributor ISACTIVER and ISACTIVERE.
+ */
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id)
+{
+ return GICD_GET_BIT(ISACTIVE, base, id);
+}
+
+void gicd_set_isactiver(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISACTIVE, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ISENABLER and ISENABLERE.
+ */
+void gicd_set_isenabler(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISENABLE, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor ISPENDR and ISPENDRE.
+ */
+void gicd_set_ispendr(uintptr_t base, unsigned int id)
+{
+ GICD_WRITE_BIT(ISPEND, base, id);
+}
+
+/*
+ * Accessors to set the bit corresponding to interrupt ID
+ * in GIC Distributor IPRIORITYR and IPRIORITYRE.
+ */
+void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+ GICD_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading/writing entire registers
+ ******************************************************************************/
+
+/*
+ * Accessors to read/write the GIC Distributor ICGFR and ICGFRE
+ * corresponding to the interrupt ID, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ICFG, base, id);
+}
+
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ICFG, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IGROUPR and IGROUPRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IGROUP, base, id);
+}
+
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IGROUP, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IGRPMODR and IGRPMODRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IGRPMOD, base, id);
+}
+
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IGRPMOD, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor IPRIORITYR and IPRIORITYRE
+ * corresponding to the interrupt ID, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(IPRIORITY, base, id);
+}
+
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(IPRIORITY, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISACTIVER and ISACTIVERE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISACTIVE, base, id);
+}
+
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISACTIVE, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISENABLER and ISENABLERE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISENABLE, base, id);
+}
+
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISENABLE, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor ISPENDR and ISPENDRE
+ * corresponding to the interrupt ID, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(ISPEND, base, id);
+}
+
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+ GICD_WRITE(ISPEND, base, id, val);
+}
+
+/*
+ * Accessors to read/write the GIC Distributor NSACR and NSACRE
+ * corresponding to the interrupt ID, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id)
+{
+ return GICD_READ(NSAC, base, id);
+}
+
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val)
{
- GICD_CLR_BIT(IGRPMODR, base, id);
+ GICD_WRITE(NSAC, base, id, val);
}
diff --git a/drivers/arm/gic/v3/gicrv3_helpers.c b/drivers/arm/gic/v3/gicrv3_helpers.c
index 294acda5a2..e46b15e24c 100644
--- a/drivers/arm/gic/v3/gicrv3_helpers.c
+++ b/drivers/arm/gic/v3/gicrv3_helpers.c
@@ -13,203 +13,113 @@
/*******************************************************************************
* GIC Redistributor functions
- * Note: The raw register values correspond to multiple interrupt IDs and
- * the number of interrupt IDs involved depends on the register accessed.
+ * Note: The raw register values correspond to multiple interrupt `id`s and
+ * the number of interrupt `id`s involved depends on the register accessed.
******************************************************************************/
/*
- * Accessor to read the GIC Redistributor IPRIORITYR corresponding to the
- * interrupt `id`, 4 interrupts IDs at a time.
- */
-unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
-{
- unsigned int n = id >> IPRIORITYR_SHIFT;
-
- return mmio_read_32(base + GICR_IPRIORITYR + (n << 2));
-}
-
-/*
- * Accessor to write the GIC Redistributor IPRIORITYR corresponding to the
- * interrupt `id`, 4 interrupts IDs at a time.
- */
-void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
-{
- unsigned int n = id >> IPRIORITYR_SHIFT;
-
- mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val);
-}
-
-/*
- * Accessor to set the byte corresponding to interrupt ID
- * in GIC Redistributor IPRIORITYR.
+ * Accessor to set the byte corresponding to interrupt `id`
+ * in GIC Redistributor IPRIORITYR and IPRIORITYRE.
*/
void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
{
- GICR_WRITE_8(IPRIORITYR, base, id, pri & GIC_PRI_MASK);
+ GICR_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK));
}
/*
- * Accessor to get the bit corresponding to interrupt ID
- * from GIC Redistributor IGROUPR0.
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGROUPR0 and IGROUPRE
*/
-unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id)
+unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igroupr0(base);
-
- return (reg_val >> bit_num) & 0x1U;
+ return GICR_GET_BIT(IGROUP, base, id);
}
-/*
- * Accessor to set the bit corresponding to interrupt ID
- * in GIC Redistributor IGROUPR0.
- */
-void gicr_set_igroupr0(uintptr_t base, unsigned int id)
+void gicr_set_igroupr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igroupr0(base);
-
- gicr_write_igroupr0(base, reg_val | (1U << bit_num));
+ GICR_SET_BIT(IGROUP, base, id);
}
-/*
- * Accessor to clear the bit corresponding to interrupt ID
- * in GIC Redistributor IGROUPR0.
- */
-void gicr_clr_igroupr0(uintptr_t base, unsigned int id)
+void gicr_clr_igroupr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igroupr0(base);
-
- gicr_write_igroupr0(base, reg_val & ~(1U << bit_num));
+ GICR_CLR_BIT(IGROUP, base, id);
}
/*
- * Accessor to get the bit corresponding to interrupt ID
- * from GIC Redistributor IGRPMODR0.
+ * Accessors to get/set/clear the bit corresponding to interrupt `id`
+ * from GIC Redistributor IGRPMODR0 and IGRPMODRE
*/
-unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id)
+unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igrpmodr0(base);
-
- return (reg_val >> bit_num) & 0x1U;
+ return GICR_GET_BIT(IGRPMOD, base, id);
}
-/*
- * Accessor to set the bit corresponding to interrupt ID
- * in GIC Redistributor IGRPMODR0.
- */
-void gicr_set_igrpmodr0(uintptr_t base, unsigned int id)
+void gicr_set_igrpmodr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igrpmodr0(base);
-
- gicr_write_igrpmodr0(base, reg_val | (1U << bit_num));
+ GICR_SET_BIT(IGRPMOD, base, id);
}
-/*
- * Accessor to clear the bit corresponding to interrupt ID
- * in GIC Redistributor IGRPMODR0.
- */
-void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id)
+void gicr_clr_igrpmodr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_igrpmodr0(base);
-
- gicr_write_igrpmodr0(base, reg_val & ~(1U << bit_num));
+ GICR_CLR_BIT(IGRPMOD, base, id);
}
/*
- * Accessor to set the bit corresponding to interrupt ID
- * in GIC Redistributor ISENABLER0.
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISENABLER0 and ISENABLERE
*/
-void gicr_set_isenabler0(uintptr_t base, unsigned int id)
+void gicr_set_isenabler(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U);
-
- gicr_write_isenabler0(base, (1U << bit_num));
+ GICR_WRITE_BIT(ISENABLE, base, id);
}
/*
- * Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
- * ICENABLER0.
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ICENABLER0 and ICENABLERE
*/
-void gicr_set_icenabler0(uintptr_t base, unsigned int id)
+void gicr_set_icenabler(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U);
-
- gicr_write_icenabler0(base, (1U << bit_num));
+ GICR_WRITE_BIT(ICENABLE, base, id);
}
/*
- * Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
- * ISACTIVER0.
+ * Accessor to get the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISACTIVER0 and ISACTIVERE
*/
-unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id)
+unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U);
- unsigned int reg_val = gicr_read_isactiver0(base);
-
- return (reg_val >> bit_num) & 0x1U;
+ return GICR_GET_BIT(ISACTIVE, base, id);
}
/*
- * Accessor to clear the bit corresponding to interrupt ID in GIC Redistributor
- * ICPENDRR0.
+ * Accessor to clear the bit corresponding to interrupt `id`
+ * in GIC Redistributor ICPENDR0 and ICPENDRE
*/
-void gicr_set_icpendr0(uintptr_t base, unsigned int id)
+void gicr_set_icpendr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U);
-
- gicr_write_icpendr0(base, (1U << bit_num));
+ GICR_WRITE_BIT(ICPEND, base, id);
}
/*
- * Accessor to set the bit corresponding to interrupt ID in GIC Redistributor
- * ISPENDR0.
+ * Accessor to write the bit corresponding to interrupt `id`
+ * in GIC Redistributor ISPENDR0 and ISPENDRE
*/
-void gicr_set_ispendr0(uintptr_t base, unsigned int id)
+void gicr_set_ispendr(uintptr_t base, unsigned int id)
{
- unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U);
-
- gicr_write_ispendr0(base, (1U << bit_num));
+ GICR_WRITE_BIT(ISPEND, base, id);
}
/*
- * Accessor to set the bit fields corresponding to interrupt ID
- * in GIC Redistributor ICFGR0.
+ * Accessor to set the bit fields corresponding to interrupt `id`
+ * in GIC Redistributor ICFGR0, ICFGR1 and ICFGRE
*/
-void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg)
+void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
{
/* Interrupt configuration is a 2-bit field */
- unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
- unsigned int bit_shift = bit_num << 1U;
-
- uint32_t reg_val = gicr_read_icfgr0(base);
+ unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U;
/* Clear the field, and insert required configuration */
- reg_val &= ~(GIC_CFG_MASK << bit_shift);
- reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
-
- gicr_write_icfgr0(base, reg_val);
-}
-
-/*
- * Accessor to set the bit fields corresponding to interrupt ID
- * in GIC Redistributor ICFGR1.
- */
-void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg)
-{
- /* Interrupt configuration is a 2-bit field */
- unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
- unsigned int bit_shift = bit_num << 1U;
-
- uint32_t reg_val = gicr_read_icfgr1(base);
-
- /* Clear the field, and insert required configuration */
- reg_val &= ~(GIC_CFG_MASK << bit_shift);
- reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
-
- gicr_write_icfgr1(base, reg_val);
+ mmio_clrsetbits_32(base + GICR_OFFSET(ICFG, id),
+ (uint32_t)GIC_CFG_MASK << bit_shift,
+ (cfg & GIC_CFG_MASK) << bit_shift);
}
diff --git a/drivers/arm/gic/v3/gicv3.mk b/drivers/arm/gic/v3/gicv3.mk
index 164f88eda8..73339d9915 100644
--- a/drivers/arm/gic/v3/gicv3.mk
+++ b/drivers/arm/gic/v3/gicv3.mk
@@ -8,9 +8,9 @@
GICV3_IMPL ?= GIC500
GICV3_IMPL_GIC600_MULTICHIP ?= 0
GICV3_OVERRIDE_DISTIF_PWR_OPS ?= 0
+GIC_EXT_INTID ?= 0
-GICV3_SOURCES += drivers/arm/gic/common/gic_common.c \
- drivers/arm/gic/v3/gicv3_main.c \
+GICV3_SOURCES += drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
drivers/arm/gic/v3/gicdv3_helpers.c \
drivers/arm/gic/v3/gicrv3_helpers.c
@@ -32,3 +32,7 @@ GICV3_SOURCES += drivers/arm/gic/v3/gic500.c
else
$(error "Incorrect GICV3_IMPL value ${GICV3_IMPL}")
endif
+
+# Set support for extended PPI and SPI range
+$(eval $(call assert_boolean,GIC_EXT_INTID))
+$(eval $(call add_define,GIC_EXT_INTID))
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;
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index a672b18f32..aefaa35953 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -31,26 +31,62 @@ static spinlock_t gic_lock;
#pragma weak gicv3_rdistif_off
#pragma weak gicv3_rdistif_on
+/* Check interrupt ID for SGI/(E)PPI and (E)SPIs */
+static bool is_sgi_ppi(unsigned int id);
+
+/*
+ * Helper macros to save and restore GICR and GICD registers
+ * corresponding to their numbers to and from the context
+ */
+#define RESTORE_GICR_REG(base, ctx, name, i) \
+ gicr_write_##name((base), (i), (ctx)->gicr_##name[(i)])
+
+#define SAVE_GICR_REG(base, ctx, name, i) \
+ (ctx)->gicr_##name[(i)] = gicr_read_##name((base), (i))
/* Helper macros to save and restore GICD registers to and from the context */
#define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG) \
do { \
- for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \
- int_id += (1U << REG##_SHIFT)) { \
- gicd_write_##reg(base, int_id, \
- ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ gicd_write_##reg((base), int_id, \
+ (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \
+ REG##R_SHIFT]); \
} \
} while (false)
#define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG) \
do { \
- for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \
- int_id += (1U << REG##_SHIFT)) { \
- ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\
- gicd_read_##reg(base, int_id); \
+ for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \
+ REG##R_SHIFT] = gicd_read_##reg((base), int_id); \
} \
} while (false)
+#if GIC_EXT_INTID
+#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ gicd_write_##reg((base), int_id, \
+ (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - MIN_SPI_ID))\
+ >> REG##R_SHIFT]); \
+ } \
+ } while (false)
+
+#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG) \
+ do { \
+ for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\
+ int_id += (1U << REG##R_SHIFT)) { \
+ (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - MIN_SPI_ID))\
+ >> REG##R_SHIFT] = gicd_read_##reg((base), int_id);\
+ } \
+ } while (false)
+#else
+#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG)
+#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG)
+#endif /* GIC_EXT_INTID */
/*******************************************************************************
* This function initialises the ARM GICv3 driver in EL3 with provided platform
@@ -80,7 +116,7 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
(ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U);
#endif /* !__aarch64__ */
- /* The GIC version should be 3.0 */
+ /* The GIC version should be 3 */
gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
gic_version >>= PIDR2_ARCH_REV_SHIFT;
gic_version &= PIDR2_ARCH_REV_MASK;
@@ -133,7 +169,6 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
INFO("GICv3 with%s legacy support detected."
" ARM GICv3 driver initialized in EL3\n",
(gicv2_compat == 0U) ? "" : "out");
-
}
/*******************************************************************************
@@ -142,7 +177,7 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
******************************************************************************/
void __init gicv3_distif_init(void)
{
- unsigned int bitmap = 0;
+ unsigned int bitmap;
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
@@ -164,7 +199,7 @@ void __init gicv3_distif_init(void)
gicd_set_ctlr(gicv3_driver_data->gicd_base,
CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
- /* Set the default attribute of all SPIs */
+ /* Set the default attribute of all (E)SPIs */
gicv3_spis_config_defaults(gicv3_driver_data->gicd_base);
bitmap = gicv3_secure_spis_config_props(
@@ -172,7 +207,7 @@ void __init gicv3_distif_init(void)
gicv3_driver_data->interrupt_props,
gicv3_driver_data->interrupt_props_num);
- /* Enable the secure SPIs now that they have been configured */
+ /* Enable the secure (E)SPIs now that they have been configured */
gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
}
@@ -184,7 +219,7 @@ void __init gicv3_distif_init(void)
void gicv3_rdistif_init(unsigned int proc_num)
{
uintptr_t gicr_base;
- unsigned int bitmap = 0U;
+ unsigned int bitmap;
uint32_t ctlr;
assert(gicv3_driver_data != NULL);
@@ -203,7 +238,7 @@ void gicv3_rdistif_init(unsigned int proc_num)
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
assert(gicr_base != 0U);
- /* Set the default attribute of all SGIs and PPIs */
+ /* Set the default attribute of all SGIs and (E)PPIs */
gicv3_ppi_sgi_config_defaults(gicr_base);
bitmap = gicv3_secure_ppi_sgi_config_props(gicr_base,
@@ -211,8 +246,9 @@ void gicv3_rdistif_init(unsigned int proc_num)
gicv3_driver_data->interrupt_props_num);
/* Enable interrupt groups as required, if not already */
- if ((ctlr & bitmap) != bitmap)
+ if ((ctlr & bitmap) != bitmap) {
gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
+ }
}
/*******************************************************************************
@@ -220,12 +256,10 @@ void gicv3_rdistif_init(unsigned int proc_num)
******************************************************************************/
void gicv3_rdistif_off(unsigned int proc_num)
{
- return;
}
void gicv3_rdistif_on(unsigned int proc_num)
{
- return;
}
/*******************************************************************************
@@ -342,8 +376,9 @@ unsigned int gicv3_get_pending_interrupt_id(void)
* If the ID is special identifier corresponding to G1S or G1NS
* interrupt, then read the highest pending group 1 interrupt.
*/
- if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID))
+ if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID)) {
return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK;
+ }
return id;
}
@@ -373,8 +408,7 @@ unsigned int gicv3_get_pending_interrupt_type(void)
* INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure
* interrupt.
******************************************************************************/
-unsigned int gicv3_get_interrupt_type(unsigned int id,
- unsigned int proc_num)
+unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num)
{
unsigned int igroup, grpmodr;
uintptr_t gicr_base;
@@ -387,15 +421,19 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
assert(proc_num < gicv3_driver_data->rdistif_num);
/* All LPI interrupts are Group 1 non secure */
- if (id >= MIN_LPI_ID)
+ if (id >= MIN_LPI_ID) {
return INTR_GROUP1NS;
+ }
- if (id < MIN_SPI_ID) {
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
- igroup = gicr_get_igroupr0(gicr_base, id);
- grpmodr = gicr_get_igrpmodr0(gicr_base, id);
+ igroup = gicr_get_igroupr(gicr_base, id);
+ grpmodr = gicr_get_igrpmodr(gicr_base, id);
} else {
+ /* SPIs: 32-1019, ESPIs: 4096-5119 */
assert(gicv3_driver_data->gicd_base != 0U);
igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
@@ -405,12 +443,14 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
* If the IGROUP bit is set, then it is a Group 1 Non secure
* interrupt
*/
- if (igroup != 0U)
+ if (igroup != 0U) {
return INTR_GROUP1NS;
+ }
/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
- if (grpmodr != 0U)
+ if (grpmodr != 0U) {
return INTR_GROUP1S;
+ }
/* Else it is a Group 0 Secure interrupt */
return INTR_GROUP0;
@@ -427,7 +467,8 @@ unsigned int gicv3_get_interrupt_type(unsigned int id,
*
* This function must be invoked after the GIC CPU interface is disabled.
*****************************************************************************/
-void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx)
+void gicv3_its_save_disable(uintptr_t gits_base,
+ gicv3_its_ctx_t * const its_ctx)
{
unsigned int i;
@@ -439,8 +480,7 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx
its_ctx->gits_ctlr = gits_read_ctlr(gits_base);
/* Disable the ITS */
- gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
- (~GITS_CTLR_ENABLED_BIT));
+ gits_write_ctlr(gits_base, its_ctx->gits_ctlr & ~GITS_CTLR_ENABLED_BIT);
/* Wait for quiescent state */
gits_wait_for_quiescent_bit(gits_base);
@@ -448,8 +488,9 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx
its_ctx->gits_cbaser = gits_read_cbaser(gits_base);
its_ctx->gits_cwriter = gits_read_cwriter(gits_base);
- for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+ for (i = 0U; i < ARRAY_SIZE(its_ctx->gits_baser); i++) {
its_ctx->gits_baser[i] = gits_read_baser(gits_base, i);
+ }
}
/*****************************************************************************
@@ -460,7 +501,8 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx
*
* This must be invoked before the GIC CPU interface is enabled.
*****************************************************************************/
-void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx)
+void gicv3_its_restore(uintptr_t gits_base,
+ const gicv3_its_ctx_t * const its_ctx)
{
unsigned int i;
@@ -476,22 +518,23 @@ void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ct
gits_write_cbaser(gits_base, its_ctx->gits_cbaser);
gits_write_cwriter(gits_base, its_ctx->gits_cwriter);
- for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+ for (i = 0U; i < ARRAY_SIZE(its_ctx->gits_baser); i++) {
gits_write_baser(gits_base, i, its_ctx->gits_baser[i]);
+ }
/* Restore the ITS CTLR but leave the ITS disabled */
- gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
- (~GITS_CTLR_ENABLED_BIT));
+ gits_write_ctlr(gits_base, its_ctx->gits_ctlr & ~GITS_CTLR_ENABLED_BIT);
}
/*****************************************************************************
* Function to save the GIC Redistributor register context. This function
* must be invoked after CPU interface disable and prior to Distributor save.
*****************************************************************************/
-void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx)
+void gicv3_rdistif_save(unsigned int proc_num,
+ gicv3_redist_ctx_t * const rdist_ctx)
{
uintptr_t gicr_base;
- unsigned int int_id;
+ unsigned int i, ppi_regs_num, regs_num;
assert(gicv3_driver_data != NULL);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -501,6 +544,17 @@ void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_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
/*
* Wait for any write to GICR_CTLR to complete before trying to save any
* state.
@@ -512,20 +566,28 @@ void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_
rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base);
rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base);
- rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base);
- rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base);
- rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base);
- rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base);
- rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base);
- rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base);
- rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base);
- rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
- for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
- int_id += (1U << IPRIORITYR_SHIFT)) {
- rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] =
- gicr_read_ipriorityr(gicr_base, int_id);
+ /* 32 interrupt IDs per register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ SAVE_GICR_REG(gicr_base, rdist_ctx, igroupr, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, isenabler, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, ispendr, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, isactiver, i);
+ SAVE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i);
}
+ /* 16 interrupt IDs per GICR_ICFGR register */
+ regs_num = ppi_regs_num << 1;
+ for (i = 0U; i < regs_num; ++i) {
+ SAVE_GICR_REG(gicr_base, rdist_ctx, icfgr, i);
+ }
+
+ rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+
+ /* 4 interrupt IDs per GICR_IPRIORITYR register */
+ regs_num = ppi_regs_num << 3;
+ for (i = 0U; i < regs_num; ++i) {
+ SAVE_GICR_REG(gicr_base, rdist_ctx, ipriorityr, i);
+ }
/*
* Call the pre-save hook that implements the IMP DEF sequence that may
@@ -546,7 +608,7 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
const gicv3_redist_ctx_t * const rdist_ctx)
{
uintptr_t gicr_base;
- unsigned int int_id;
+ unsigned int i, ppi_regs_num, regs_num;
assert(gicv3_driver_data != NULL);
assert(proc_num < gicv3_driver_data->rdistif_num);
@@ -556,6 +618,17 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_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
/* Power on redistributor */
gicv3_rdistif_on(proc_num);
@@ -567,11 +640,14 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
gicv3_distif_post_restore(proc_num);
/*
- * 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);
@@ -586,30 +662,44 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
- gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0);
+ /* 32 interrupt IDs per register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, igroupr, i);
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i);
+ }
+
+ /* 4 interrupt IDs per GICR_IPRIORITYR register */
+ regs_num = ppi_regs_num << 3;
+ for (i = 0U; i < regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, ipriorityr, i);
+ }
- for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
- int_id += (1U << IPRIORITYR_SHIFT)) {
- gicr_write_ipriorityr(gicr_base, int_id,
- rdist_ctx->gicr_ipriorityr[
- (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]);
+ /* 16 interrupt IDs per GICR_ICFGR register */
+ regs_num = ppi_regs_num << 1;
+ for (i = 0U; i < regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, icfgr, i);
}
- gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0);
- gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1);
- gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0);
gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
- /* Restore after group and priorities are set */
- gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0);
- gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0);
+ /* Restore after group and priorities are set.
+ * 32 interrupt IDs per register
+ */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, ispendr, i);
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, isactiver, i);
+ }
/*
* Wait for all writes to the Distributor to complete before enabling
- * the SGI and PPIs.
+ * the SGI and (E)PPIs.
*/
gicr_wait_for_upstream_pending_write(gicr_base);
- gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0);
+
+ /* 32 interrupt IDs per GICR_ISENABLER register */
+ for (i = 0U; i < ppi_regs_num; ++i) {
+ RESTORE_GICR_REG(gicr_base, rdist_ctx, isenabler, i);
+ }
/*
* Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case
@@ -627,7 +717,10 @@ void gicv3_rdistif_init_restore(unsigned int proc_num,
*****************************************************************************/
void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
{
- unsigned int num_ints;
+ unsigned int typer_reg, num_ints;
+#if GIC_EXT_INTID
+ unsigned int num_eints;
+#endif
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
@@ -636,14 +729,28 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
uintptr_t gicd_base = gicv3_driver_data->gicd_base;
- num_ints = gicd_read_typer(gicd_base);
- num_ints &= TYPER_IT_LINES_NO_MASK;
- num_ints = (num_ints + 1U) << 5;
+ 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;
/* Filter out special INTIDs 1020-1023 */
- if (num_ints > (MAX_SPI_ID + 1U))
+ if (num_ints > (MAX_SPI_ID + 1U)) {
num_ints = MAX_SPI_ID + 1U;
+ }
+#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;
+ } else {
+ num_eints = 0U;
+ }
+#endif
/* Wait for pending write to complete */
gicd_wait_for_pending_write(gicd_base);
@@ -651,31 +758,58 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
/* Save GICD_IGROUPR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP);
+
+ /* Save GICD_IGROUPRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP);
/* Save GICD_ISENABLER for INT_IDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE);
+
+ /* Save GICD_ISENABLERE for INT_IDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE);
/* Save GICD_ISPENDR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND);
+
+ /* Save GICD_ISPENDRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND);
/* Save GICD_ISACTIVER for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE);
+
+ /* Save GICD_ISACTIVERE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE);
/* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY);
+
+ /* Save GICD_IPRIORITYRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY);
/* Save GICD_ICFGR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG);
+
+ /* Save GICD_ICFGRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG);
/* Save GICD_IGRPMODR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD);
+
+ /* Save GICD_IGRPMODRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD);
/* Save GICD_NSACR for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC);
+
+ /* Save GICD_NSACRE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC);
/* Save GICD_IROUTER for INTIDs 32 - 1019 */
- SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE);
+
+ /* Save GICD_IROUTERE for INTIDs 4096 - 5119 */
+ SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE);
/*
* GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when
@@ -693,7 +827,10 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
*****************************************************************************/
void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
{
- unsigned int num_ints = 0U;
+ unsigned int typer_reg, num_ints;
+#if GIC_EXT_INTID
+ unsigned int num_eints;
+#endif
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
@@ -716,50 +853,90 @@ void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
- num_ints = gicd_read_typer(gicd_base);
- num_ints &= TYPER_IT_LINES_NO_MASK;
- num_ints = (num_ints + 1U) << 5;
+ 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;
/* Filter out special INTIDs 1020-1023 */
- if (num_ints > (MAX_SPI_ID + 1U))
+ if (num_ints > (MAX_SPI_ID + 1U)) {
num_ints = MAX_SPI_ID + 1U;
+ }
+#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;
+ } else {
+ num_eints = 0U;
+ }
+#endif
/* Restore GICD_IGROUPR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP);
+
+ /* Restore GICD_IGROUPRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP);
/* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY);
+
+ /* Restore GICD_IPRIORITYRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY);
/* Restore GICD_ICFGR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG);
+
+ /* Restore GICD_ICFGRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG);
/* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD);
+
+ /* Restore GICD_IGRPMODRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD);
/* Restore GICD_NSACR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC);
+
+ /* Restore GICD_NSACRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC);
/* Restore GICD_IROUTER for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE);
+
+ /* Restore GICD_IROUTERE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE);
/*
- * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are
- * configured.
+ * Restore ISENABLER(E), ISPENDR(E) and ISACTIVER(E) after
+ * the interrupts are configured.
*/
/* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE);
+
+ /* Restore GICD_ISENABLERE for INT_IDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE);
/* Restore GICD_ISPENDR for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND);
+
+ /* Restore GICD_ISPENDRE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND);
/* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */
- RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE);
+
+ /* Restore GICD_ISACTIVERE for INTIDs 4096 - 5119 */
+ RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE);
/* Restore the GICD_CTLR */
gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr);
gicd_wait_for_pending_write(gicd_base);
-
}
/*******************************************************************************
@@ -774,28 +951,25 @@ unsigned int gicv3_get_running_priority(void)
/*******************************************************************************
* This function checks if the interrupt identified by id is active (whether the
* state is either active, or active and pending). The proc_num is used if the
- * interrupt is SGI or PPI and programs the corresponding Redistributor
+ * interrupt is SGI or (E)PPI and programs the corresponding Redistributor
* interface.
******************************************************************************/
unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
{
- unsigned int value;
-
assert(gicv3_driver_data != NULL);
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
- assert(id <= MAX_SPI_ID);
- if (id < MIN_SPI_ID) {
- /* For SGIs and PPIs */
- value = gicr_get_isactiver0(
- gicv3_driver_data->rdistif_base_addrs[proc_num], id);
- } else {
- value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ return gicr_get_isactiver(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
}
- return value;
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+ return gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
}
/*******************************************************************************
@@ -809,19 +983,20 @@ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
- assert(id <= MAX_SPI_ID);
/*
* Ensure that any shared variable updates depending on out of band
* interrupt trigger are observed before enabling interrupt.
*/
dsbishst();
- if (id < MIN_SPI_ID) {
- /* For SGIs and PPIs */
- gicr_set_isenabler0(
- gicv3_driver_data->rdistif_base_addrs[proc_num],
- id);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_isenabler(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
gicd_set_isenabler(gicv3_driver_data->gicd_base, id);
}
}
@@ -837,22 +1012,23 @@ void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
- assert(id <= MAX_SPI_ID);
/*
* Disable interrupt, and ensure that any shared variable updates
* depending on out of band interrupt trigger are observed afterwards.
*/
- if (id < MIN_SPI_ID) {
- /* For SGIs and PPIs */
- gicr_set_icenabler0(
- gicv3_driver_data->rdistif_base_addrs[proc_num],
- id);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_icenabler(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
/* Write to clear enable requires waiting for pending writes */
gicr_wait_for_pending_write(
- gicv3_driver_data->rdistif_base_addrs[proc_num]);
+ gicv3_driver_data->rdistif_base_addrs[proc_num]);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
gicd_set_icenabler(gicv3_driver_data->gicd_base, id);
/* Write to clear enable requires waiting for pending writes */
@@ -875,19 +1051,21 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
assert(gicv3_driver_data->gicd_base != 0U);
assert(proc_num < gicv3_driver_data->rdistif_num);
assert(gicv3_driver_data->rdistif_base_addrs != NULL);
- assert(id <= MAX_SPI_ID);
- if (id < MIN_SPI_ID) {
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
gicr_set_ipriorityr(gicr_base, id, priority);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
}
}
/*******************************************************************************
* This function assigns group for the interrupt identified by id. The proc_num
- * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * is used if the interrupt is SGI or (E)PPI, and programs the corresponding
* Redistributor interface. The group can be any of GICV3_INTR_GROUP*
******************************************************************************/
void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
@@ -919,29 +1097,26 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
break;
}
- if (id < MIN_SPI_ID) {
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
- if (igroup)
- gicr_set_igroupr0(gicr_base, id);
- else
- gicr_clr_igroupr0(gicr_base, id);
-
- if (grpmod)
- gicr_set_igrpmodr0(gicr_base, id);
- else
- gicr_clr_igrpmodr0(gicr_base, id);
+
+ igroup ? gicr_set_igroupr(gicr_base, id) :
+ gicr_clr_igroupr(gicr_base, id);
+ grpmod ? gicr_set_igrpmodr(gicr_base, id) :
+ gicr_clr_igrpmodr(gicr_base, id);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
+
/* Serialize read-modify-write to Distributor registers */
spin_lock(&gic_lock);
- if (igroup)
- gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
- else
- gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
-
- if (grpmod)
- gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
- else
- gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+
+ igroup ? gicd_set_igroupr(gicv3_driver_data->gicd_base, id) :
+ gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+ grpmod ? gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id) :
+ gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+
spin_unlock(&gic_lock);
}
}
@@ -986,7 +1161,7 @@ void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target)
}
/*******************************************************************************
- * This function sets the interrupt routing for the given SPI interrupt id.
+ * This function sets the interrupt routing for the given (E)SPI interrupt id.
* The interrupt routing is specified in routing mode and mpidr.
*
* The routing mode can be either of:
@@ -1005,7 +1180,8 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
assert(gicv3_driver_data->gicd_base != 0U);
assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE));
- assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID));
+
+ assert(IS_SPI(id));
aff = gicd_irouter_val_from_mpidr(mpidr, irm);
gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
@@ -1025,7 +1201,7 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr
/*******************************************************************************
* This function clears the pending status of an interrupt identified by id.
- * The proc_num is used if the interrupt is SGI or PPI, and programs the
+ * The proc_num is used if the interrupt is SGI or (E)PPI, and programs the
* corresponding Redistributor interface.
******************************************************************************/
void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
@@ -1039,13 +1215,17 @@ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
* Clear pending interrupt, and ensure that any shared variable updates
* depending on out of band interrupt trigger are observed afterwards.
*/
- if (id < MIN_SPI_ID) {
- /* For SGIs and PPIs */
- gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
- id);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_icpendr(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
}
+
dsbishst();
}
@@ -1066,11 +1246,14 @@ void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
* interrupt trigger are observed before setting interrupt pending.
*/
dsbishst();
- if (id < MIN_SPI_ID) {
- /* For SGIs and PPIs */
- gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
- id);
+
+ /* Check interrupt ID */
+ if (is_sgi_ppi(id)) {
+ /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */
+ gicr_set_ispendr(
+ gicv3_driver_data->rdistif_base_addrs[proc_num], id);
} else {
+ /* For SPIs: 32-1019 and ESPIs: 4096-5119 */
gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
}
}
@@ -1083,7 +1266,7 @@ unsigned int gicv3_set_pmr(unsigned int mask)
{
unsigned int old_mask;
- old_mask = (uint32_t) read_icc_pmr_el1();
+ old_mask = (unsigned int)read_icc_pmr_el1();
/*
* Order memory updates w.r.t. PMR write, and ensure they're visible
@@ -1130,15 +1313,17 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
mpidr = mpidr_from_gicr_typer(typer_val);
proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr);
} else {
- proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) &
- TYPER_PROC_NUM_MASK;
+ proc_num = (unsigned int)(typer_val >>
+ TYPER_PROC_NUM_SHIFT) & TYPER_PROC_NUM_MASK;
}
if (proc_num == proc_self) {
/* The base address doesn't need to be initialized on
* every warm boot.
*/
- if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U)
+ if (gicv3_driver_data->rdistif_base_addrs[proc_num]
+ != 0U) {
return 0;
+ }
gicv3_driver_data->rdistif_base_addrs[proc_num] =
rdistif_base;
gicr_frame_found = true;
@@ -1147,8 +1332,9 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT);
} while ((typer_val & TYPER_LAST_BIT) == 0U);
- if (!gicr_frame_found)
+ if (!gicr_frame_found) {
return -1;
+ }
/*
* Flush the driver data to ensure coherency. This is
@@ -1164,3 +1350,23 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame)
#endif
return 0; /* Found matching GICR frame */
}
+
+/******************************************************************************
+ * This function checks the interrupt ID and returns true for SGIs and (E)PPIs
+ * and false for (E)SPIs IDs.
+ *****************************************************************************/
+static bool is_sgi_ppi(unsigned int id)
+{
+ /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
+ if (IS_SGI_PPI(id)) {
+ return true;
+ }
+
+ /* SPIs: 32-1019, ESPIs: 4096-5119 */
+ if (IS_SPI(id)) {
+ return false;
+ }
+
+ assert(false);
+ panic();
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index dae01cb1ed..26c8de53ce 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -26,39 +26,59 @@
/* Calculate GIC register bit number corresponding to its interrupt ID */
#define BIT_NUM(REG, id) \
- ((id) & ((1U << REG##_SHIFT) - 1U))
+ ((id) & ((1U << REG##R_SHIFT) - 1U))
-/* Calculate 8-bit GICD register offset corresponding to its interrupt ID */
+/*
+ * Calculate 8, 32 and 64-bit GICD register offset
+ * corresponding to its interrupt ID
+ */
+#if GIC_EXT_INTID
+ /* GICv3.1 */
+#define GICD_OFFSET_8(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (uintptr_t)(id) : \
+ GICD_##REG##RE + (uintptr_t)(id) - MIN_ESPI_ID)
+
+#define GICD_OFFSET(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \
+ GICD_##REG##RE + ((((uintptr_t)(id) - MIN_ESPI_ID) >> \
+ REG##R_SHIFT) << 2))
+
+#define GICD_OFFSET_64(REG, id) \
+ (((id) <= MAX_SPI_ID) ? \
+ GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3) : \
+ GICD_##REG##RE + (((uintptr_t)(id) - MIN_ESPI_ID) << 3))
+
+#else /* GICv3 */
#define GICD_OFFSET_8(REG, id) \
- GICD_##REG + (id)
+ (GICD_##REG##R + (uintptr_t)(id))
-/* Calculate 32-bit GICD register offset corresponding to its interrupt ID */
#define GICD_OFFSET(REG, id) \
- GICD_##REG + (((id) >> REG##_SHIFT) << 2)
+ (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
-/* Calculate 64-bit GICD register offset corresponding to its interrupt ID */
#define GICD_OFFSET_64(REG, id) \
- GICD_##REG + (((id) >> REG##_SHIFT) << 3)
+ (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3))
+#endif /* GIC_EXT_INTID */
-/* Read 32-bit GIC Distributor register corresponding to its interrupt ID */
+/*
+ * Read/Write 8, 32 and 64-bit GIC Distributor register
+ * corresponding to its interrupt ID
+ */
#define GICD_READ(REG, base, id) \
mmio_read_32((base) + GICD_OFFSET(REG, (id)))
-/* Read 64-bit GIC Distributor register corresponding to its interrupt ID */
#define GICD_READ_64(REG, base, id) \
mmio_read_64((base) + GICD_OFFSET_64(REG, (id)))
-/* Write to 64-bit GIC Distributor register corresponding to its interrupt ID */
-#define GICD_WRITE_64(REG, base, id, val) \
- mmio_write_64((base) + GICD_OFFSET_64(REG, (id)), (val))
+#define GICD_WRITE_8(REG, base, id, val) \
+ mmio_write_8((base) + GICD_OFFSET_8(REG, (id)), (val))
-/* Write to 32-bit GIC Distributor register corresponding to its interrupt ID */
-#define GICD_WRITE(REG, base, id, val) \
+#define GICD_WRITE(REG, base, id, val) \
mmio_write_32((base) + GICD_OFFSET(REG, (id)), (val))
-/* Write to 8-bit GIC Distributor register corresponding to its interrupt ID */
-#define GICD_WRITE_8(REG, base, id, val) \
- mmio_write_8((base) + GICD_OFFSET_8(REG, (id)), (val))
+#define GICD_WRITE_64(REG, base, id, val) \
+ mmio_write_64((base) + GICD_OFFSET_64(REG, (id)), (val))
/*
* Bit operations on GIC Distributor register corresponding
@@ -80,19 +100,43 @@
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Write bit in GIC Distributor register */
-#define GICD_WRITE_BIT(REG, base, id) \
+#define GICD_WRITE_BIT(REG, base, id) \
mmio_write_32((base) + GICD_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/*
- * Calculate GICv3 GICR register offset
+ * Calculate 8 and 32-bit GICR register offset
+ * corresponding to its interrupt ID
*/
+#if GIC_EXT_INTID
+ /* GICv3.1 */
+#define GICR_OFFSET_8(REG, id) \
+ (((id) <= MAX_PPI_ID) ? \
+ GICR_##REG##R + (uintptr_t)(id) : \
+ GICR_##REG##R + (uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID))
+
+#define GICR_OFFSET(REG, id) \
+ (((id) <= MAX_PPI_ID) ? \
+ GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \
+ GICR_##REG##R + ((((uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID))\
+ >> REG##R_SHIFT) << 2))
+#else /* GICv3 */
+#define GICR_OFFSET_8(REG, id) \
+ (GICR_##REG##R + (uintptr_t)(id))
+
#define GICR_OFFSET(REG, id) \
- GICR_##REG + (((id) >> REG##_SHIFT) << 2)
+ (GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2))
+#endif
-/* Write to GIC Redistributor register corresponding to its interrupt ID */
-#define GICR_WRITE_8(REG, base, id, val) \
- mmio_write_8((base) + GICR_##REG + (id), (val))
+/* Read/Write GIC Redistributor register corresponding to its interrupt ID */
+#define GICR_READ(REG, base, id) \
+ mmio_read_32((base) + GICR_OFFSET(REG, (id)))
+
+#define GICR_WRITE_8(REG, base, id, val) \
+ mmio_write_8((base) + GICR_OFFSET_8(REG, (id)), (val))
+
+#define GICR_WRITE(REG, base, id, val) \
+ mmio_write((base) + GICR_OFFSET(REG, (id)), (val))
/*
* Bit operations on GIC Redistributor register
@@ -105,7 +149,7 @@
/* Write bit in GIC Redistributor register */
#define GICR_WRITE_BIT(REG, base, id) \
- mmio_write_32((base) + GICR_OFFSET(REG, (id)), \
+ mmio_write_32((base) + GICR_OFFSET(REG, (id)), \
((uint32_t)1 << BIT_NUM(REG, (id))))
/* Set bit in GIC Redistributor register */
@@ -157,10 +201,8 @@ extern const gicv3_driver_data_t *gicv3_driver_data;
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
******************************************************************************/
-uint32_t gicd_read_igrpmodr(uintptr_t base, unsigned int id);
-unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id);
-void gicd_write_igrpmodr(uintptr_t base, unsigned int id, uint32_t val);
-void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id);
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val);
/*******************************************************************************
* Private GICv3 function prototypes for accessing the GIC registers
@@ -169,22 +211,21 @@ void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
* the bit-field corresponding the single interrupt ID.
******************************************************************************/
unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
-unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
-unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
-unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id);
void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
-void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
-void gicr_set_isenabler0(uintptr_t base, unsigned int id);
-void gicr_set_icenabler0(uintptr_t base, unsigned int id);
-void gicr_set_ispendr0(uintptr_t base, unsigned int id);
-void gicr_set_icpendr0(uintptr_t base, unsigned int id);
-void gicr_set_igroupr0(uintptr_t base, unsigned int id);
+void gicr_set_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_set_isenabler(uintptr_t base, unsigned int id);
+void gicr_set_icenabler(uintptr_t base, unsigned int id);
+void gicr_set_ispendr(uintptr_t base, unsigned int id);
+void gicr_set_icpendr(uintptr_t base, unsigned int id);
+void gicr_set_igroupr(uintptr_t base, unsigned int id);
void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
-void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
-void gicr_clr_igroupr0(uintptr_t base, unsigned int id);
+void gicr_clr_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_clr_igroupr(uintptr_t base, unsigned int id);
void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
-void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg);
-void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg);
+void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
/*******************************************************************************
* Private GICv3 helper function prototypes
@@ -208,10 +249,10 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
* GIC Distributor interface accessors
******************************************************************************/
/*
- * Wait for updates to :
+ * Wait for updates to:
* GICD_CTLR[2:0] - the Group Enables
- * GICD_CTLR[5:4] - the ARE bits
- * GICD_ICENABLERn - the clearing of enable state for SPIs
+ * GICD_CTLR[7:4] - the ARE bits, E1NWF bit and DS bit
+ * GICD_ICENABLER<n> - the clearing of enable state for SPIs
*/
static inline void gicd_wait_for_pending_write(uintptr_t gicd_base)
{
@@ -227,7 +268,7 @@ static inline uint32_t gicd_read_pidr2(uintptr_t base)
static inline uint64_t gicd_read_irouter(uintptr_t base, unsigned int id)
{
assert(id >= MIN_SPI_ID);
- return GICD_READ_64(IROUTER, base, id);
+ return GICD_READ_64(IROUTE, base, id);
}
static inline void gicd_write_irouter(uintptr_t base,
@@ -235,7 +276,7 @@ static inline void gicd_write_irouter(uintptr_t base,
uint64_t affinity)
{
assert(id >= MIN_SPI_ID);
- GICD_WRITE_64(IROUTER, base, id, affinity);
+ GICD_WRITE_64(IROUTE, base, id, affinity);
}
static inline void gicd_clr_ctlr(uintptr_t base,
@@ -287,11 +328,12 @@ static inline void gicr_write_waker(uintptr_t base, uint32_t val)
}
/*
- * Wait for updates to :
+ * Wait for updates to:
* GICR_ICENABLER0
* GICR_CTLR.DPG1S
* GICR_CTLR.DPG1NS
* GICR_CTLR.DPG0
+ * GICR_CTLR, which clears EnableLPIs from 1 to 0
*/
static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
{
@@ -314,101 +356,150 @@ void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num);
* Note: The raw register values correspond to multiple interrupt IDs and
* the number of interrupt IDs involved depends on the register accessed.
******************************************************************************/
-static inline unsigned int gicr_read_icenabler0(uintptr_t base)
-{
- return mmio_read_32(base + GICR_ICENABLER0);
-}
-static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val)
+/*
+ * Accessors to read/write GIC Redistributor ICENABLER0 and ICENABLERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_icenabler(uintptr_t base,
+ unsigned int reg_num)
{
- mmio_write_32(base + GICR_ICENABLER0, val);
+ return mmio_read_32(base + GICR_ICENABLER + (reg_num << 2));
}
-static inline unsigned int gicr_read_isenabler0(uintptr_t base)
+static inline void gicr_write_icenabler(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- return mmio_read_32(base + GICR_ISENABLER0);
+ mmio_write_32(base + GICR_ICENABLER + (reg_num << 2), val);
}
-static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+/*
+ * Accessor to read/write GIC Redistributor ICFGR0, ICFGR1 and ICFGRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_icfgr(uintptr_t base, unsigned int reg_num)
{
- mmio_write_32(base + GICR_ICPENDR0, val);
+ return mmio_read_32(base + GICR_ICFGR + (reg_num << 2));
}
-static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
+static inline void gicr_write_icfgr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- mmio_write_32(base + GICR_ISENABLER0, val);
+ mmio_write_32(base + GICR_ICFGR + (reg_num << 2), val);
}
-static inline unsigned int gicr_read_igroupr0(uintptr_t base)
+/*
+ * Accessors to read/write GIC Redistributor IGROUPR0 and IGROUPRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_igroupr(uintptr_t base,
+ unsigned int reg_num)
{
- return mmio_read_32(base + GICR_IGROUPR0);
+ return mmio_read_32(base + GICR_IGROUPR + (reg_num << 2));
}
-static inline unsigned int gicr_read_ispendr0(uintptr_t base)
+static inline void gicr_write_igroupr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- return mmio_read_32(base + GICR_ISPENDR0);
+ mmio_write_32(base + GICR_IGROUPR + (reg_num << 2), val);
}
-static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val)
+/*
+ * Accessors to read/write GIC Redistributor IGRPMODR0 and IGRPMODRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_igrpmodr(uintptr_t base,
+ unsigned int reg_num)
{
- mmio_write_32(base + GICR_ISPENDR0, val);
+ return mmio_read_32(base + GICR_IGRPMODR + (reg_num << 2));
}
-static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
+static inline void gicr_write_igrpmodr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- mmio_write_32(base + GICR_IGROUPR0, val);
+ mmio_write_32(base + GICR_IGRPMODR + (reg_num << 2), val);
}
-static inline unsigned int gicr_read_igrpmodr0(uintptr_t base)
+/*
+ * Accessors to read/write the GIC Redistributor IPRIORITYR(E) register
+ * corresponding to its number, 4 interrupts IDs at a time.
+ */
+static inline unsigned int gicr_read_ipriorityr(uintptr_t base,
+ unsigned int reg_num)
{
- return mmio_read_32(base + GICR_IGRPMODR0);
+ return mmio_read_32(base + GICR_IPRIORITYR + (reg_num << 2));
}
-static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
+static inline void gicr_write_ipriorityr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- mmio_write_32(base + GICR_IGRPMODR0, val);
+ mmio_write_32(base + GICR_IPRIORITYR + (reg_num << 2), val);
}
-static inline unsigned int gicr_read_nsacr(uintptr_t base)
+/*
+ * Accessors to read/write GIC Redistributor ISACTIVER0 and ISACTIVERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_isactiver(uintptr_t base,
+ unsigned int reg_num)
{
- return mmio_read_32(base + GICR_NSACR);
+ return mmio_read_32(base + GICR_ISACTIVER + (reg_num << 2));
}
-static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
+static inline void gicr_write_isactiver(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- mmio_write_32(base + GICR_NSACR, val);
+ mmio_write_32(base + GICR_ISACTIVER + (reg_num << 2), val);
}
-static inline unsigned int gicr_read_isactiver0(uintptr_t base)
+/*
+ * Accessors to read/write GIC Redistributor ISENABLER0 and ISENABLERE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_isenabler(uintptr_t base,
+ unsigned int reg_num)
{
- return mmio_read_32(base + GICR_ISACTIVER0);
+ return mmio_read_32(base + GICR_ISENABLER + (reg_num << 2));
}
-static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val)
+static inline void gicr_write_isenabler(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- mmio_write_32(base + GICR_ISACTIVER0, val);
+ mmio_write_32(base + GICR_ISENABLER + (reg_num << 2), val);
}
-static inline unsigned int gicr_read_icfgr0(uintptr_t base)
+/*
+ * Accessors to read/write GIC Redistributor ISPENDR0 and ISPENDRE
+ * register corresponding to its number
+ */
+static inline unsigned int gicr_read_ispendr(uintptr_t base,
+ unsigned int reg_num)
{
- return mmio_read_32(base + GICR_ICFGR0);
+ return mmio_read_32(base + GICR_ISPENDR + (reg_num << 2));
}
-static inline unsigned int gicr_read_icfgr1(uintptr_t base)
+static inline void gicr_write_ispendr(uintptr_t base, unsigned int reg_num,
+ unsigned int val)
{
- return mmio_read_32(base + GICR_ICFGR1);
+ mmio_write_32(base + GICR_ISPENDR + (reg_num << 2), val);
}
-static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val)
+/*
+ * Accessors to read/write GIC Redistributor NSACR register
+ */
+static inline unsigned int gicr_read_nsacr(uintptr_t base)
{
- mmio_write_32(base + GICR_ICFGR0, val);
+ return mmio_read_32(base + GICR_NSACR);
}
-static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
+static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
{
- mmio_write_32(base + GICR_ICFGR1, val);
+ mmio_write_32(base + GICR_NSACR, val);
}
+/*
+ * Accessors to read/write GIC Redistributor PROPBASER register
+ */
static inline uint64_t gicr_read_propbaser(uintptr_t base)
{
return mmio_read_64(base + GICR_PROPBASER);
@@ -419,6 +510,9 @@ static inline void gicr_write_propbaser(uintptr_t base, uint64_t val)
mmio_write_64(base + GICR_PROPBASER, val);
}
+/*
+ * Accessors to read/write GIC Redistributor PENDBASER register
+ */
static inline uint64_t gicr_read_pendbaser(uintptr_t base)
{
return mmio_read_64(base + GICR_PENDBASER);
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index e6339bcfe6..c29896b4b5 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -8,7 +8,7 @@
#define GICV3_H
/*******************************************************************************
- * GICv3 miscellaneous definitions
+ * GICv3 and 3.1 miscellaneous definitions
******************************************************************************/
/* Interrupt group definitions */
#define INTR_GROUP1S U(0)
@@ -25,20 +25,85 @@
/* GICv3 can only target up to 16 PEs with SGI */
#define GICV3_MAX_SGI_TARGETS U(16)
+/* PPIs INTIDs 16-31 */
+#define MAX_PPI_ID U(31)
+
+#if GIC_EXT_INTID
+
+/* GICv3.1 extended PPIs INTIDs 1056-1119 */
+#define MIN_EPPI_ID U(1056)
+#define MAX_EPPI_ID U(1119)
+
+/* Total number of GICv3.1 EPPIs */
+#define TOTAL_EPPI_INTR_NUM (MAX_EPPI_ID - MIN_EPPI_ID + U(1))
+
+/* Total number of GICv3.1 PPIs and EPPIs */
+#define TOTAL_PRIVATE_INTR_NUM (TOTAL_PCPU_INTR_NUM + TOTAL_EPPI_INTR_NUM)
+
+/* GICv3.1 extended SPIs INTIDs 4096 - 5119 */
+#define MIN_ESPI_ID U(4096)
+#define MAX_ESPI_ID U(5119)
+
+/* Total number of GICv3.1 ESPIs */
+#define TOTAL_ESPI_INTR_NUM (MAX_ESPI_ID - MIN_ESPI_ID + U(1))
+
+/* Total number of GICv3.1 SPIs and ESPIs */
+#define TOTAL_SHARED_INTR_NUM (TOTAL_SPI_INTR_NUM + TOTAL_ESPI_INTR_NUM)
+
+/* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */
+#define IS_SGI_PPI(id) (((id) <= MAX_PPI_ID) || \
+ (((id) >= MIN_EPPI_ID) && \
+ ((id) <= MAX_EPPI_ID)))
+
+/* SPIs: 32-1019, ESPIs: 4096-5119 */
+#define IS_SPI(id) ((((id) >= MIN_SPI_ID) && \
+ ((id) <= MAX_SPI_ID)) || \
+ (((id) >= MIN_ESPI_ID) && \
+ ((id) <= MAX_ESPI_ID)))
+#else /* GICv3 */
+
+/* Total number of GICv3 PPIs */
+#define TOTAL_PRIVATE_INTR_NUM TOTAL_PCPU_INTR_NUM
+
+/* Total number of GICv3 SPIs */
+#define TOTAL_SHARED_INTR_NUM TOTAL_SPI_INTR_NUM
+
+/* SGIs: 0-15, PPIs: 16-31 */
+#define IS_SGI_PPI(id) ((id) <= MAX_PPI_ID)
+
+/* SPIs: 32-1019 */
+#define IS_SPI(id) (((id) >= MIN_SPI_ID) && ((id) <= MAX_SPI_ID))
+
+#endif /* GIC_EXT_INTID */
+
/*******************************************************************************
- * GICv3 specific Distributor interface register offsets and constants.
+ * GICv3 and 3.1 specific Distributor interface register offsets and constants
******************************************************************************/
+#define GICD_TYPER2 U(0x0c)
#define GICD_STATUSR U(0x10)
#define GICD_SETSPI_NSR U(0x40)
#define GICD_CLRSPI_NSR U(0x48)
#define GICD_SETSPI_SR U(0x50)
#define GICD_CLRSPI_SR U(0x58)
#define GICD_IGRPMODR U(0xd00)
+#define GICD_IGROUPRE U(0x1000)
+#define GICD_ISENABLERE U(0x1200)
+#define GICD_ICENABLERE U(0x1400)
+#define GICD_ISPENDRE U(0x1600)
+#define GICD_ICPENDRE U(0x1800)
+#define GICD_ISACTIVERE U(0x1a00)
+#define GICD_ICACTIVERE U(0x1c00)
+#define GICD_IPRIORITYRE U(0x2000)
+#define GICD_ICFGRE U(0x3000)
+#define GICD_IGRPMODRE U(0x3400)
+#define GICD_NSACRE U(0x3600)
/*
- * GICD_IROUTER<n> register is at 0x6000 + 8n, where n is the interrupt id and
- * n >= 32, making the effective offset as 0x6100.
+ * GICD_IROUTER<n> register is at 0x6000 + 8n, where n is the interrupt ID
+ * and n >= 32, making the effective offset as 0x6100
*/
#define GICD_IROUTER U(0x6000)
+#define GICD_IROUTERE U(0x8000)
+
#define GICD_PIDR2_GICV3 U(0xffe8)
#define IGRPMODR_SHIFT 5
@@ -78,14 +143,22 @@
#define NUM_OF_DIST_REGS 30
+/* GICD_TYPER shifts and masks */
+#define TYPER_ESPI U(1 << 8)
+#define TYPER_DVIS U(1 << 18)
+#define TYPER_ESPI_RANGE_MASK U(0x1f)
+#define TYPER_ESPI_RANGE_SHIFT U(27)
+#define TYPER_ESPI_RANGE U(TYPER_ESPI_MASK << TYPER_ESPI_SHIFT)
+
/*******************************************************************************
- * GICv3 Redistributor interface registers & constants
+ * GICv3 and 3.1 Redistributor interface registers & constants
******************************************************************************/
#define GICR_PCPUBASE_SHIFT 0x11
#define GICR_SGIBASE_OFFSET U(65536) /* 64 KB */
#define GICR_CTLR U(0x0)
#define GICR_IIDR U(0x04)
#define GICR_TYPER U(0x08)
+#define GICR_STATUSR U(0x10)
#define GICR_WAKER U(0x14)
#define GICR_PROPBASER U(0x70)
#define GICR_PENDBASER U(0x78)
@@ -102,6 +175,16 @@
#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + U(0xd00))
#define GICR_NSACR (GICR_SGIBASE_OFFSET + U(0xe00))
+#define GICR_IGROUPR GICR_IGROUPR0
+#define GICR_ISENABLER GICR_ISENABLER0
+#define GICR_ICENABLER GICR_ICENABLER0
+#define GICR_ISPENDR GICR_ISPENDR0
+#define GICR_ICPENDR GICR_ICPENDR0
+#define GICR_ISACTIVER GICR_ISACTIVER0
+#define GICR_ICACTIVER GICR_ICACTIVER0
+#define GICR_ICFGR GICR_ICFGR0
+#define GICR_IGRPMODR GICR_IGRPMODR0
+
/* GICR_CTLR bit definitions */
#define GICR_CTLR_UWP_SHIFT 31
#define GICR_CTLR_UWP_MASK U(0x1)
@@ -132,12 +215,13 @@
#define TYPER_LAST_BIT BIT_32(TYPER_LAST_SHIFT)
-#define NUM_OF_REDIST_REGS 30
+#define TYPER_PPI_NUM_SHIFT U(27)
+#define TYPER_PPI_NUM_MASK U(0x1f)
/*******************************************************************************
- * GICv3 CPU interface registers & constants
+ * GICv3 and 3.1 CPU interface registers & constants
******************************************************************************/
-/* ICC_SRE bit definitions*/
+/* ICC_SRE bit definitions */
#define ICC_SRE_EN_BIT BIT_32(3)
#define ICC_SRE_DIB_BIT BIT_32(2)
#define ICC_SRE_DFB_BIT BIT_32(1)
@@ -192,9 +276,8 @@
((_tgt) & SGIR_TGT_MASK))
/*****************************************************************************
- * GICv3 ITS registers and constants
+ * GICv3 and 3.1 ITS registers and constants
*****************************************************************************/
-
#define GITS_CTLR U(0x0)
#define GITS_IIDR U(0x4)
#define GITS_TYPER U(0x8)
@@ -205,8 +288,7 @@
/* GITS_CTLR bit definitions */
#define GITS_CTLR_ENABLED_BIT BIT_32(0)
-#define GITS_CTLR_QUIESCENT_SHIFT 31
-#define GITS_CTLR_QUIESCENT_BIT BIT_32(GITS_CTLR_QUIESCENT_SHIFT)
+#define GITS_CTLR_QUIESCENT_BIT BIT_32(1)
#ifndef __ASSEMBLER__
@@ -224,7 +306,7 @@ static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
}
/*******************************************************************************
- * Helper GICv3 macros for SEL1
+ * Helper GICv3 and 3.1 macros for SEL1
******************************************************************************/
static inline uint32_t gicv3_acknowledge_interrupt_sel1(void)
{
@@ -255,14 +337,14 @@ static inline void gicv3_end_of_interrupt(unsigned int id)
}
/*
- * This macro returns the total number of GICD registers corresponding to
- * the name.
+ * This macro returns the total number of GICD/GICR registers corresponding to
+ * the register name
*/
#define GICD_NUM_REGS(reg_name) \
- DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT))
+ DIV_ROUND_UP_2EVAL(TOTAL_SHARED_INTR_NUM, (1 << reg_name##_SHIFT))
#define GICR_NUM_REGS(reg_name) \
- DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
+ DIV_ROUND_UP_2EVAL(TOTAL_PRIVATE_INTR_NUM, (1 << reg_name##_SHIFT))
/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
#define INT_ID_MASK U(0xffffff)
@@ -325,20 +407,19 @@ typedef struct gicv3_redist_ctx {
/* 32 bits registers */
uint32_t gicr_ctlr;
- uint32_t gicr_igroupr0;
- uint32_t gicr_isenabler0;
- uint32_t gicr_ispendr0;
- uint32_t gicr_isactiver0;
+ uint32_t gicr_igroupr[GICR_NUM_REGS(IGROUPR)];
+ uint32_t gicr_isenabler[GICR_NUM_REGS(ISENABLER)];
+ uint32_t gicr_ispendr[GICR_NUM_REGS(ISPENDR)];
+ uint32_t gicr_isactiver[GICR_NUM_REGS(ISACTIVER)];
uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)];
- uint32_t gicr_icfgr0;
- uint32_t gicr_icfgr1;
- uint32_t gicr_igrpmodr0;
+ uint32_t gicr_icfgr[GICR_NUM_REGS(ICFGR)];
+ uint32_t gicr_igrpmodr[GICR_NUM_REGS(IGRPMODR)];
uint32_t gicr_nsacr;
} gicv3_redist_ctx_t;
typedef struct gicv3_dist_ctx {
/* 64 bits registers */
- uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM];
+ uint64_t gicd_irouter[TOTAL_SHARED_INTR_NUM];
/* 32 bits registers */
uint32_t gicd_ctlr;