interrupt_controller: gic: Support multiple GIC versions
The current GIC driver implementation only supports the GIC-400, which implements the GICv2 interface. This commit refactors the GIC driver to support multiple GIC versions and adds GICv1 interface support (GICv1 and GICv2 interfaces are very similar). Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
This commit is contained in:
parent
11d0f0a294
commit
2b441732ff
3 changed files with 225 additions and 43 deletions
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_ARCV2_INTERRUPT_UNIT intc_arcv2_irq_unit.c)
|
||||
zephyr_sources_ifdef(CONFIG_GIC intc_gic_400.c)
|
||||
zephyr_sources_ifdef(CONFIG_GIC intc_gic.c)
|
||||
zephyr_sources_ifdef(CONFIG_IOAPIC intc_ioapic.c)
|
||||
zephyr_sources_ifdef(CONFIG_LOAPIC intc_loapic.c intc_system_apic.c)
|
||||
zephyr_sources_ifdef(CONFIG_LOAPIC_SPURIOUS_VECTOR intc_loapic_spurious.S)
|
||||
|
|
|
@ -1,48 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Marvell
|
||||
* Copyright (c) 2018 Lexmark International, Inc.
|
||||
* Copyright (c) 2019 Stephanos Ioannidis <root@stephanos.io>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: This driver currently implements the GICv1 and GICv2 interfaces. The
|
||||
* GICv3 interface is not supported.
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <sw_isr_table.h>
|
||||
#include <irq_nextlevel.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <drivers/interrupt_controller/gic.h>
|
||||
|
||||
#define DT_GIC_DIST_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_0
|
||||
#define DT_GIC_CPU_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_1
|
||||
|
||||
#define GICD_CTRL (DT_GIC_DIST_BASE + 0)
|
||||
#define GICD_TYPER (DT_GIC_DIST_BASE + 0x4)
|
||||
#define GICD_IIDR (DT_GIC_DIST_BASE + 0x8)
|
||||
#define GICD_IGROUPRn (DT_GIC_DIST_BASE + 0x80)
|
||||
#define GICD_ISENABLERn (DT_GIC_DIST_BASE + 0x100)
|
||||
#define GICD_ICENABLERn (DT_GIC_DIST_BASE + 0x180)
|
||||
#define GICD_ISPENDRn (DT_GIC_DIST_BASE + 0x200)
|
||||
#define GICD_ICPENDRn (DT_GIC_DIST_BASE + 0x280)
|
||||
#define GICD_ISACTIVERn (DT_GIC_DIST_BASE + 0x300)
|
||||
#define GICD_ICACTIVERn (DT_GIC_DIST_BASE + 0x380)
|
||||
#define GICD_IPRIORITYRn (DT_GIC_DIST_BASE + 0x400)
|
||||
#define GICD_ITARGETSRn (DT_GIC_DIST_BASE + 0x800)
|
||||
#define GICD_ICFGRn (DT_GIC_DIST_BASE + 0xc00)
|
||||
#define GICD_SGIR (DT_GIC_DIST_BASE + 0xf00)
|
||||
|
||||
#define GICC_CTRL (DT_GIC_CPU_BASE + 0x00)
|
||||
#define GICC_PMR (DT_GIC_CPU_BASE + 0x04)
|
||||
#define GICC_BPR (DT_GIC_CPU_BASE + 0x08)
|
||||
#define GICC_IAR (DT_GIC_CPU_BASE + 0x0c)
|
||||
#define GICC_EOIR (DT_GIC_CPU_BASE + 0x10)
|
||||
|
||||
#define GICC_ENABLE 3
|
||||
#define GICC_DIS_BYPASS_MASK 0x1e0
|
||||
|
||||
#define NO_GIC_INT_PENDING 1023
|
||||
|
||||
#define GIC_SPI_INT_BASE 32
|
||||
|
||||
#define GIC_INT_TYPE_MASK 0x3
|
||||
#define GIC_INT_TYPE_EDGE (1 << 1)
|
||||
#if CONFIG_GIC_VER >= 3
|
||||
#error "GICv3 and above are not supported"
|
||||
#endif
|
||||
|
||||
struct gic_ictl_config {
|
||||
u32_t isr_table_offset;
|
||||
|
@ -61,7 +38,7 @@ static void gic_dist_init(void)
|
|||
* Disable the forwarding of pending interrupts
|
||||
* from the Distributor to the CPU interfaces
|
||||
*/
|
||||
sys_write32(0, GICD_CTRL);
|
||||
sys_write32(0, GICD_CTLR);
|
||||
|
||||
/*
|
||||
* Set all global interrupts to this CPU only.
|
||||
|
@ -88,7 +65,9 @@ static void gic_dist_init(void)
|
|||
* as these enables are banked registers.
|
||||
*/
|
||||
for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
|
||||
#ifndef CONFIG_GIC_V1
|
||||
sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8);
|
||||
#endif
|
||||
sys_write32(0xffffffff, GICD_ICENABLERn + i / 8);
|
||||
}
|
||||
|
||||
|
@ -96,7 +75,7 @@ static void gic_dist_init(void)
|
|||
* Enable the forwarding of pending interrupts
|
||||
* from the Distributor to the CPU interfaces
|
||||
*/
|
||||
sys_write32(1, GICD_CTRL);
|
||||
sys_write32(1, GICD_CTLR);
|
||||
}
|
||||
|
||||
static void gic_cpu_init(void)
|
||||
|
@ -108,7 +87,9 @@ static void gic_cpu_init(void)
|
|||
* Deal with the banked PPI and SGI interrupts - disable all
|
||||
* PPI interrupts, ensure all SGI interrupts are enabled.
|
||||
*/
|
||||
#ifndef CONFIG_GIC_V1
|
||||
sys_write32(0xffffffff, GICD_ICACTIVERn);
|
||||
#endif
|
||||
sys_write32(0xffff0000, GICD_ICENABLERn);
|
||||
sys_write32(0x0000ffff, GICD_ISENABLERn);
|
||||
|
||||
|
@ -123,10 +104,12 @@ static void gic_cpu_init(void)
|
|||
/*
|
||||
* Enable interrupts and signal them using the IRQ signal.
|
||||
*/
|
||||
val = sys_read32(GICC_CTRL);
|
||||
val &= GICC_DIS_BYPASS_MASK;
|
||||
val |= GICC_ENABLE;
|
||||
sys_write32(val, GICC_CTRL);
|
||||
val = sys_read32(GICC_CTLR);
|
||||
#ifndef CONFIG_GIC_V1
|
||||
val &= ~GICC_CTLR_BYPASS_MASK;
|
||||
#endif
|
||||
val |= GICC_CTLR_ENABLE_MASK;
|
||||
sys_write32(val, GICC_CTLR);
|
||||
}
|
||||
|
||||
static void gic_irq_enable(struct device *dev, unsigned int irq)
|
||||
|
@ -168,9 +151,9 @@ static void gic_irq_set_priority(struct device *dev,
|
|||
int_off = (irq % 16) * 2;
|
||||
|
||||
val = sys_read8(GICD_ICFGRn + int_grp);
|
||||
val &= ~(GIC_INT_TYPE_MASK << int_off);
|
||||
val &= ~(GICC_ICFGR_MASK << int_off);
|
||||
if (flags & IRQ_TYPE_EDGE)
|
||||
val |= (GIC_INT_TYPE_EDGE << int_off);
|
||||
val |= (GICC_ICFGR_TYPE << int_off);
|
||||
sys_write8(val, GICD_ICFGRn + int_grp);
|
||||
}
|
||||
|
||||
|
@ -184,7 +167,7 @@ static void gic_isr(void *arg)
|
|||
irq = sys_read32(GICC_IAR);
|
||||
irq &= 0x3ff;
|
||||
|
||||
if (irq == NO_GIC_INT_PENDING) {
|
||||
if (irq == GICC_IAR_SPURIOUS) {
|
||||
printk("gic: Invalid interrupt\n");
|
||||
return;
|
||||
}
|
199
include/drivers/interrupt_controller/gic.h
Normal file
199
include/drivers/interrupt_controller/gic.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Stephanos Ioannidis <root@stephanos.io>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_GIC_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_GIC_H_
|
||||
|
||||
#include <arch/cpu.h>
|
||||
|
||||
/*
|
||||
* GIC Register Interface Base Addresses
|
||||
*/
|
||||
|
||||
#define GIC_DIST_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_0
|
||||
#define GIC_CPU_BASE DT_INST_0_ARM_GIC_BASE_ADDRESS_1
|
||||
|
||||
/*
|
||||
* GIC Distributor Interface
|
||||
*/
|
||||
|
||||
/*
|
||||
* 0x000 Distributor Control Register
|
||||
* v1 ICDDCR
|
||||
* v2/v3 GICD_CTLR
|
||||
*/
|
||||
#define GICD_CTLR (GIC_DIST_BASE + 0x0)
|
||||
|
||||
/*
|
||||
* 0x004 Interrupt Controller Type Register
|
||||
* v1 ICDICTR
|
||||
* v2/v3 GICD_TYPER
|
||||
*/
|
||||
#define GICD_TYPER (GIC_DIST_BASE + 0x4)
|
||||
|
||||
/*
|
||||
* 0x008 Distributor Implementer Identification Register
|
||||
* v1 ICDIIDR
|
||||
* v2/v3 GICD_IIDR
|
||||
*/
|
||||
#define GICD_IIDR (GIC_DIST_BASE + 0x8)
|
||||
|
||||
/*
|
||||
* 0x080 Interrupt Group Registers
|
||||
* v1 ICDISRn
|
||||
* v2/v3 GICD_IGROUPRn
|
||||
*/
|
||||
#define GICD_IGROUPRn (GIC_DIST_BASE + 0x80)
|
||||
|
||||
/*
|
||||
* 0x100 Interrupt Set-Enable Reigsters
|
||||
* v1 ICDISERn
|
||||
* v2/v3 GICD_ISENABLERn
|
||||
*/
|
||||
#define GICD_ISENABLERn (GIC_DIST_BASE + 0x100)
|
||||
|
||||
/*
|
||||
* 0x180 Interrupt Clear-Enable Registers
|
||||
* v1 ICDICERn
|
||||
* v2/v3 GICD_ICENABLERn
|
||||
*/
|
||||
#define GICD_ICENABLERn (GIC_DIST_BASE + 0x180)
|
||||
|
||||
/*
|
||||
* 0x200 Interrupt Set-Pending Registers
|
||||
* v1 ICDISPRn
|
||||
* v2/v3 GICD_ISPENDRn
|
||||
*/
|
||||
#define GICD_ISPENDRn (GIC_DIST_BASE + 0x200)
|
||||
|
||||
/*
|
||||
* 0x280 Interrupt Clear-Pending Registers
|
||||
* v1 ICDICPRn
|
||||
* v2/v3 GICD_ICPENDRn
|
||||
*/
|
||||
#define GICD_ICPENDRn (GIC_DIST_BASE + 0x280)
|
||||
|
||||
/*
|
||||
* 0x300 Interrupt Set-Active Registers
|
||||
* v1 ICDABRn
|
||||
* v2/v3 GICD_ISACTIVERn
|
||||
*/
|
||||
#define GICD_ISACTIVERn (GIC_DIST_BASE + 0x300)
|
||||
|
||||
#if CONFIG_GIC_VER >= 2
|
||||
/*
|
||||
* 0x380 Interrupt Clear-Active Registers
|
||||
* v2/v3 GICD_ICACTIVERn
|
||||
*/
|
||||
#define GICD_ICACTIVERn (GIC_DIST_BASE + 0x380)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 0x400 Interrupt Priority Registers
|
||||
* v1 ICDIPRn
|
||||
* v2/v3 GICD_IPRIORITYRn
|
||||
*/
|
||||
#define GICD_IPRIORITYRn (GIC_DIST_BASE + 0x400)
|
||||
|
||||
/*
|
||||
* 0x800 Interrupt Processor Targets Registers
|
||||
* v1 ICDIPTRn
|
||||
* v2/v3 GICD_ITARGETSRn
|
||||
*/
|
||||
#define GICD_ITARGETSRn (GIC_DIST_BASE + 0x800)
|
||||
|
||||
/*
|
||||
* 0xC00 Interrupt Configuration Registers
|
||||
* v1 ICDICRn
|
||||
* v2/v3 GICD_ICFGRn
|
||||
*/
|
||||
#define GICD_ICFGRn (GIC_DIST_BASE + 0xc00)
|
||||
|
||||
/*
|
||||
* 0xF00 Software Generated Interrupt Register
|
||||
* v1 ICDSGIR
|
||||
* v2/v3 GICD_SGIR
|
||||
*/
|
||||
#define GICD_SGIR (GIC_DIST_BASE + 0xf00)
|
||||
|
||||
/*
|
||||
* GIC CPU Interface
|
||||
*/
|
||||
|
||||
#if CONFIG_GIC_VER <= 2
|
||||
|
||||
/*
|
||||
* 0x0000 CPU Interface Control Register
|
||||
* v1 ICCICR
|
||||
* v2/v3 GICC_CTLR
|
||||
*/
|
||||
#define GICC_CTLR (GIC_CPU_BASE + 0x0)
|
||||
|
||||
/*
|
||||
* 0x0004 Interrupt Priority Mask Register
|
||||
* v1 ICCPMR
|
||||
* v2/v3 GICC_PMR
|
||||
*/
|
||||
#define GICC_PMR (GIC_CPU_BASE + 0x4)
|
||||
|
||||
/*
|
||||
* 0x0008 Binary Point Register
|
||||
* v1 ICCBPR
|
||||
* v2/v3 GICC_BPR
|
||||
*/
|
||||
#define GICC_BPR (GIC_CPU_BASE + 0x8)
|
||||
|
||||
/*
|
||||
* 0x000C Interrupt Acknowledge Register
|
||||
* v1 ICCIAR
|
||||
* v2/v3 GICC_IAR
|
||||
*/
|
||||
#define GICC_IAR (GIC_CPU_BASE + 0xc)
|
||||
|
||||
/*
|
||||
* 0x0010 End of Interrupt Register
|
||||
* v1 ICCEOIR
|
||||
* v2/v3 GICC_EOIR
|
||||
*/
|
||||
#define GICC_EOIR (GIC_CPU_BASE + 0x10)
|
||||
|
||||
|
||||
/*
|
||||
* Helper Constants
|
||||
*/
|
||||
|
||||
#define GIC_SPI_INT_BASE 32
|
||||
|
||||
/* GICC_CTLR */
|
||||
#define GICC_CTLR_ENABLEGRP0 BIT(0)
|
||||
#define GICC_CTLR_ENABLEGRP1 BIT(1)
|
||||
|
||||
#define GICC_CTLR_ENABLE_MASK (GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1)
|
||||
|
||||
#if defined(CONFIG_GIC_V2)
|
||||
|
||||
#define GICC_CTLR_FIQBYPDISGRP0 BIT(5)
|
||||
#define GICC_CTLR_IRQBYPDISGRP0 BIT(6)
|
||||
#define GICC_CTLR_FIQBYPDISGRP1 BIT(7)
|
||||
#define GICC_CTLR_IRQBYPDISGRP1 BIT(8)
|
||||
|
||||
#define GICC_CTLR_BYPASS_MASK (GICC_CTLR_FIQBYPDISGRP0 | \
|
||||
GICC_CTLR_IRQBYPDISGRP1 | \
|
||||
GICC_CTLR_FIQBYPDISGRP1 | \
|
||||
GICC_CTLR_IRQBYPDISGRP1)
|
||||
|
||||
#endif /* CONFIG_GIC_V2 */
|
||||
|
||||
/* GICC_IAR */
|
||||
#define GICC_IAR_SPURIOUS 1023
|
||||
|
||||
/* GICC_ICFGR */
|
||||
#define GICC_ICFGR_MASK BIT_MASK(2)
|
||||
#define GICC_ICFGR_TYPE BIT(1)
|
||||
|
||||
#endif /* CONFIG_GIC_VER <= 2 */
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_GIC_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue