Browse Source

drivers: gicv3: Add Support for Extended SPI

Added support to gicv3 driver to utilize the
extended SPI MMIO registers introduced in
GICv3.1 for the extended SPI range.

Documentation for the Extended Shared
Peripheral Interrupts extension can be found
in the ARM General Interrupt Controller
Architecture Specification:

https://developer.arm.com/documentation/ihi0069/latest/

Signed-off-by: Adam Openshaw <quic_adamo@quicinc.com>
pull/88391/head
Adam Openshaw 7 months ago committed by Benjamin Cabé
parent
commit
1146574b67
  1. 26
      drivers/interrupt_controller/intc_gic_common_priv.h
  2. 101
      drivers/interrupt_controller/intc_gicv3.c
  3. 4
      drivers/interrupt_controller/intc_gicv3_priv.h
  4. 57
      include/zephyr/drivers/interrupt_controller/gic.h

26
drivers/interrupt_controller/intc_gic_common_priv.h

@ -21,6 +21,20 @@ @@ -21,6 +21,20 @@
#define GIC_DIST_IGROUPMODR 0x0d00
#define GIC_DIST_SGIR 0x0f00
/* GICv3.1 Support for Extended SPI Range */
#define GIC_ESPI_START 4096
#define GIC_ESPI_END 5119
#define GIC_DIST_IGROUPRnE 0x1000
#define GIC_DIST_ISENABLERnE 0x1200
#define GIC_DIST_ICENABLERnE 0x1400
#define GIC_DIST_ISPENDRnE 0x1600
#define GIC_DIST_ICPENDRnE 0x1800
#define GIC_DIST_ISACTIVERnE 0x1a00
#define GIC_DIST_ICACTIVERnE 0x1c00
#define GIC_DIST_IPRIORITYRnE 0x2000
#define GIC_DIST_ICFGRnE 0x3000
#define GIC_DIST_IGROUPMODRnE 0x3400
/* GICD GICR common access macros */
#define IGROUPR(base, n) (base + GIC_DIST_IGROUPR + (n) * 4)
#define ISENABLER(base, n) (base + GIC_DIST_ISENABLER + (n) * 4)
@ -32,6 +46,16 @@ @@ -32,6 +46,16 @@
#define ICFGR(base, n) (base + GIC_DIST_ICFGR + (n) * 4)
#define IGROUPMODR(base, n) (base + GIC_DIST_IGROUPMODR + (n) * 4)
/* GICD Extended SPI (GICv3.1) common access macros */
#define IGROUPRnE(base, n) (base + GIC_DIST_IGROUPRnE + (n) * 4)
#define ISENABLERnE(base, n) (base + GIC_DIST_ISENABLERnE + (n) * 4)
#define ICENABLERnE(base, n) (base + GIC_DIST_ICENABLERnE + (n) * 4)
#define ISPENDRnE(base, n) (base + GIC_DIST_ISPENDRnE + (n) * 4)
#define ICPENDRnE(base, n) (base + GIC_DIST_ICPENDRnE + (n) * 4)
#define IPRIORITYRnE(base, n) (base + GIC_DIST_IPRIORITYRnE + n)
#define ICFGRnE(base, n) (base + GIC_DIST_ICFGRnE + (n) * 4)
#define IGROUPMODRnE(base, n) (base + GIC_DIST_IGROUPMODRnE + (n) * 4)
/*
* selects redistributor SGI_base for current core for PPI and SGI
* selects distributor base for SPI
@ -40,8 +64,10 @@ @@ -40,8 +64,10 @@
#if CONFIG_GIC_VER <= 2
#define GET_DIST_BASE(intid) GIC_DIST_BASE
#define GIC_IS_ESPI(intid) 0
#else
#define GET_DIST_BASE(intid) \
((intid < GIC_SPI_INT_BASE) ? (gic_get_rdist() + GICR_SGI_BASE_OFF) : GIC_DIST_BASE)
#define GIC_IS_ESPI(intid) ((intid >= GIC_ESPI_START) && (intid <= GIC_ESPI_END))
#endif
#endif /* ZEPHYR_INCLUDE_DRIVERS_INTC_GIC_COMMON_PRIV_H */

101
drivers/interrupt_controller/intc_gicv3.c

@ -139,7 +139,13 @@ static bool arm_gic_lpi_is_enabled(unsigned int intid) @@ -139,7 +139,13 @@ static bool arm_gic_lpi_is_enabled(unsigned int intid)
#if defined(CONFIG_ARMV8_A_NS) || defined(CONFIG_GIC_SINGLE_SECURITY_STATE)
static inline void arm_gic_write_irouter(uint64_t val, unsigned int intid)
{
mem_addr_t addr = IROUTER(GET_DIST_BASE(intid), intid);
mem_addr_t addr;
if (GIC_IS_ESPI(intid)) {
addr = IROUTERnE(GET_DIST_BASE(intid), intid - GIC_ESPI_START);
} else {
addr = IROUTER(GET_DIST_BASE(intid), intid);
}
#ifdef CONFIG_ARM
sys_write32((uint32_t)val, addr);
@ -159,30 +165,46 @@ void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio, uint32_t fl @@ -159,30 +165,46 @@ void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio, uint32_t fl
}
#endif
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
uint32_t shift;
uint32_t val;
mem_addr_t base = GET_DIST_BASE(intid);
/* Disable the interrupt */
if (GIC_IS_ESPI(intid)) {
sys_write32(mask, ICENABLERnE(base, idx));
} else {
sys_write32(mask, ICENABLER(base, idx));
}
gic_wait_rwp(intid);
/* PRIORITYR registers provide byte access */
if (GIC_IS_ESPI(intid)) {
sys_write8(prio & GIC_PRI_MASK, IPRIORITYRnE(base, intid - GIC_ESPI_START));
} else {
sys_write8(prio & GIC_PRI_MASK, IPRIORITYR(base, intid));
}
/* Interrupt type config */
if (!GIC_IS_SGI(intid)) {
idx = intid / GIC_NUM_CFG_PER_REG;
idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_CFG_PER_REG)
: (intid / GIC_NUM_CFG_PER_REG);
shift = (intid & (GIC_NUM_CFG_PER_REG - 1)) * 2;
val = sys_read32(ICFGR(base, idx));
val = GIC_IS_ESPI(intid) ? sys_read32(ICFGRnE(base, idx))
: sys_read32(ICFGR(base, idx));
val &= ~(GICD_ICFGR_MASK << shift);
if (flags & IRQ_TYPE_EDGE) {
val |= (GICD_ICFGR_TYPE << shift);
}
if (GIC_IS_ESPI(intid)) {
sys_write32(val, ICFGRnE(base, idx));
} else {
sys_write32(val, ICFGR(base, idx));
}
}
}
void arm_gic_irq_enable(unsigned int intid)
@ -194,7 +216,8 @@ void arm_gic_irq_enable(unsigned int intid) @@ -194,7 +216,8 @@ void arm_gic_irq_enable(unsigned int intid)
}
#endif
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
#if defined(CONFIG_ARMV8_A_NS) || defined(CONFIG_GIC_SINGLE_SECURITY_STATE)
/*
@ -202,12 +225,16 @@ void arm_gic_irq_enable(unsigned int intid) @@ -202,12 +225,16 @@ void arm_gic_irq_enable(unsigned int intid)
* is set to '1') and for GIC single security state (GICD_CTRL.ARE is set to '1'),
* so need to set SPI's affinity, now set it to be the PE on which it is enabled.
*/
if (GIC_IS_SPI(intid)) {
if (GIC_IS_SPI(intid) || GIC_IS_ESPI(intid)) {
arm_gic_write_irouter(MPIDR_TO_CORE(GET_MPIDR()), intid);
}
#endif
if (GIC_IS_ESPI(intid)) {
sys_write32(mask, ISENABLERnE(GET_DIST_BASE(intid), idx));
} else {
sys_write32(mask, ISENABLER(GET_DIST_BASE(intid), idx));
}
}
void arm_gic_irq_disable(unsigned int intid)
@ -219,9 +246,15 @@ void arm_gic_irq_disable(unsigned int intid) @@ -219,9 +246,15 @@ void arm_gic_irq_disable(unsigned int intid)
}
#endif
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
if (GIC_IS_ESPI(intid)) {
sys_write32(mask, ICENABLERnE(GET_DIST_BASE(intid), idx));
} else {
sys_write32(mask, ICENABLER(GET_DIST_BASE(intid), idx));
}
/* poll to ensure write is complete */
gic_wait_rwp(intid);
}
@ -234,10 +267,12 @@ bool arm_gic_irq_is_enabled(unsigned int intid) @@ -234,10 +267,12 @@ bool arm_gic_irq_is_enabled(unsigned int intid)
}
#endif
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
uint32_t val;
val = sys_read32(ISENABLER(GET_DIST_BASE(intid), idx));
val = GIC_IS_ESPI(intid) ? sys_read32(ISENABLERnE(GET_DIST_BASE(intid), idx))
: sys_read32(ISENABLER(GET_DIST_BASE(intid), idx));
return (val & mask) != 0;
}
@ -245,10 +280,12 @@ bool arm_gic_irq_is_enabled(unsigned int intid) @@ -245,10 +280,12 @@ bool arm_gic_irq_is_enabled(unsigned int intid)
bool arm_gic_irq_is_pending(unsigned int intid)
{
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
uint32_t val;
val = sys_read32(ISPENDR(GET_DIST_BASE(intid), idx));
val = GIC_IS_ESPI(intid) ? sys_read32(ISPENDRnE(GET_DIST_BASE(intid), idx))
: sys_read32(ISPENDR(GET_DIST_BASE(intid), idx));
return (val & mask) != 0;
}
@ -256,17 +293,27 @@ bool arm_gic_irq_is_pending(unsigned int intid) @@ -256,17 +293,27 @@ bool arm_gic_irq_is_pending(unsigned int intid)
void arm_gic_irq_set_pending(unsigned int intid)
{
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
if (GIC_IS_ESPI(intid)) {
sys_write32(mask, ISPENDRnE(GET_DIST_BASE(intid), idx));
} else {
sys_write32(mask, ISPENDR(GET_DIST_BASE(intid), idx));
}
}
void arm_gic_irq_clear_pending(unsigned int intid)
{
uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1));
uint32_t idx = intid / GIC_NUM_INTR_PER_REG;
uint32_t idx = GIC_IS_ESPI(intid) ? ((intid - GIC_ESPI_START) / GIC_NUM_INTR_PER_REG)
: (intid / GIC_NUM_INTR_PER_REG);
if (GIC_IS_ESPI(intid)) {
sys_write32(mask, ICPENDRnE(GET_DIST_BASE(intid), idx));
} else {
sys_write32(mask, ICPENDR(GET_DIST_BASE(intid), idx));
}
}
unsigned int arm_gic_get_active(void)
@ -463,7 +510,7 @@ static void gicv3_cpuif_init(void) @@ -463,7 +510,7 @@ static void gicv3_cpuif_init(void)
*/
static void gicv3_dist_init(void)
{
unsigned int num_ints;
unsigned int num_ints, num_espi;
unsigned int intid;
unsigned int idx;
mem_addr_t base = GIC_DIST_BASE;
@ -480,6 +527,7 @@ static void gicv3_dist_init(void) @@ -480,6 +527,7 @@ static void gicv3_dist_init(void)
#endif
num_ints = sys_read32(GICD_TYPER);
num_espi = (num_ints & GICD_TYPER_ESPI_MASK) ? ((num_ints >> 27) + 1) * 32 : 0;
num_ints &= GICD_TYPER_ITLINESNUM_MASK;
num_ints = (num_ints + 1) << 5;
@ -509,6 +557,20 @@ static void gicv3_dist_init(void) @@ -509,6 +557,20 @@ static void gicv3_dist_init(void)
sys_write32(IGROUPR_VAL, IGROUPR(base, idx));
sys_write32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODR(base, idx));
}
/*
* Default configuration of all ESPIs
*/
for (intid = 0; intid < num_espi; intid += GIC_NUM_INTR_PER_REG) {
idx = intid / GIC_NUM_INTR_PER_REG;
/* Disable interrupt */
sys_write32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICENABLERnE(base, idx));
/* Clear pending */
sys_write32(BIT64_MASK(GIC_NUM_INTR_PER_REG), ICPENDRnE(base, idx));
sys_write32(IGROUPR_VAL, IGROUPRnE(base, idx));
sys_write32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODRnE(base, idx));
}
/* wait for rwp on GICD */
gic_wait_rwp(GIC_SPI_INT_BASE);
@ -517,12 +579,23 @@ static void gicv3_dist_init(void) @@ -517,12 +579,23 @@ static void gicv3_dist_init(void)
sys_write32(GIC_INT_DEF_PRI_X4, IPRIORITYR(base, intid));
}
/* Configure default priorities for all ESPIs. */
for (intid = 0; intid < num_espi; intid += GIC_NUM_PRI_PER_REG) {
sys_write32(GIC_INT_DEF_PRI_X4, IPRIORITYRnE(base, intid));
}
/* Configure all SPIs as active low, level triggered by default */
for (intid = GIC_SPI_INT_BASE; intid < num_ints; intid += GIC_NUM_CFG_PER_REG) {
idx = intid / GIC_NUM_CFG_PER_REG;
sys_write32(0, ICFGR(base, idx));
}
/* Configure all ESPIs as active low, level triggered by default */
for (intid = 0; intid < num_espi; intid += GIC_NUM_CFG_PER_REG) {
idx = intid / GIC_NUM_CFG_PER_REG;
sys_write32(0, ICFGRnE(base, idx));
}
#ifdef CONFIG_ARMV8_A_NS
/* Enable distributor with ARE */
sys_write32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS), GICD_CTLR);

4
drivers/interrupt_controller/intc_gicv3_priv.h

@ -108,6 +108,10 @@ @@ -108,6 +108,10 @@
#define GIC_DIST_IROUTER 0x6000
#define IROUTER(base, n) (base + GIC_DIST_IROUTER + (n) * 8)
/* GITCD_IROUTERnE for GICv3.1 Extended SPI Range */
#define GIC_DIST_IROUTERnE 0x8000
#define IROUTERnE(base, n) (base + GIC_DIST_IROUTERnE + (n) * 8)
/*
* ITS registers, offsets from ITS_base
*/

57
include/zephyr/drivers/interrupt_controller/gic.h

@ -55,6 +55,12 @@ @@ -55,6 +55,12 @@
*/
#define GICD_IGROUPRn (GIC_DIST_BASE + 0x80)
/*
* 0x1000 Interrupt Group Registers for Extended SPI Range
* v3.1 GICD_IGROUPRnE
*/
#define GICD_IGROUPRnE (GIC_DIST_BASE + 0x1000)
/*
* 0x100 Interrupt Set-Enable Registers
* v1 ICDISERn
@ -62,6 +68,12 @@ @@ -62,6 +68,12 @@
*/
#define GICD_ISENABLERn (GIC_DIST_BASE + 0x100)
/*
* 0x1200 Interrupt Set-Enable Registers for Extended SPI Range
* v3.1 GICD_ISENABLERnE
*/
#define GICD_ISENABLERnE (GIC_DIST_BASE + 0x1200)
/*
* 0x180 Interrupt Clear-Enable Registers
* v1 ICDICERn
@ -69,6 +81,12 @@ @@ -69,6 +81,12 @@
*/
#define GICD_ICENABLERn (GIC_DIST_BASE + 0x180)
/*
* 0x1400 Interrupt Clear-Enable Registers for Extended SPI Range
* v3.1 GICD_ICENABLERnE
*/
#define GICD_ICENABLERnE (GIC_DIST_BASE + 0x1400)
/*
* 0x200 Interrupt Set-Pending Registers
* v1 ICDISPRn
@ -76,6 +94,12 @@ @@ -76,6 +94,12 @@
*/
#define GICD_ISPENDRn (GIC_DIST_BASE + 0x200)
/*
* 1600 Interrupt Set-Pending Registers for Extended SPI Range
* v3.1 GICD_ISPENDRnE
*/
#define GICD_ISPENDRnE (GIC_DIST_BASE + 0x1600)
/*
* 0x280 Interrupt Clear-Pending Registers
* v1 ICDICPRn
@ -83,6 +107,12 @@ @@ -83,6 +107,12 @@
*/
#define GICD_ICPENDRn (GIC_DIST_BASE + 0x280)
/*
* 0x1800 Interrupt Clear-Pending Registers for Extended SPI Range
* v3.1 GICD_ICPENDRnE
*/
#define GICD_ICPENDRnE (GIC_DIST_BASE + 0x1800)
/*
* 0x300 Interrupt Set-Active Registers
* v1 ICDABRn
@ -90,12 +120,24 @@ @@ -90,12 +120,24 @@
*/
#define GICD_ISACTIVERn (GIC_DIST_BASE + 0x300)
/*
* 0x1A00 Interrupt Set-Active Registers for Extended SPI Range
* v3.1 GICD_ISACTIVERnE
*/
#define GICD_ISACTIVERnE (GIC_DIST_BASE + 0x1A00)
#if CONFIG_GIC_VER >= 2
/*
* 0x380 Interrupt Clear-Active Registers
* v2/v3 GICD_ICACTIVERn
*/
#define GICD_ICACTIVERn (GIC_DIST_BASE + 0x380)
/*
* 0x1C00 Interrupt Clear-Active Registers for Extended SPI Range
* v3.1 GICD_ICACTIVERnE
*/
#define GICD_ICACTIVERnE (GIC_DIST_BASE + 0x1C00)
#endif
/*
@ -105,6 +147,12 @@ @@ -105,6 +147,12 @@
*/
#define GICD_IPRIORITYRn (GIC_DIST_BASE + 0x400)
/*
* 0x2000 Interrupt Priority Registers for Extended SPI Range
* v3.1 GICD_IPRIORITYRnE
*/
#define GICD_IPRIORITYRnE (GIC_DIST_BASE + 0x2000)
/*
* 0x800 Interrupt Processor Targets Registers
* v1 ICDIPTRn
@ -119,6 +167,12 @@ @@ -119,6 +167,12 @@
*/
#define GICD_ICFGRn (GIC_DIST_BASE + 0xc00)
/*
* 0x3000 Interrupt Configuration Registers for Extended SPI Range
* v3.1 GICD_ICFGRnE
*/
#define GICD_ICFGRnE (GIC_DIST_BASE + 0x3000)
/*
* 0xF00 Software Generated Interrupt Register
* v1 ICDSGIR
@ -213,6 +267,9 @@ @@ -213,6 +267,9 @@
/* GICD_TYPER.ITLinesNumber 0:4 */
#define GICD_TYPER_ITLINESNUM_MASK 0x1f
/* GICD_TYPER.ESPI [8] */
#define GICD_TYPER_ESPI_MASK BIT(8)
/* GICD_TYPER.IDbits */
#define GICD_TYPER_IDBITS(typer) ((((typer) >> 19) & 0x1f) + 1)

Loading…
Cancel
Save