metal-cos/sys/arm64/gic.c
2024-09-26 04:07:50 +08:00

683 lines
25 KiB
C

#include <machine/gic.h>
#include "include/pmap.h"
#include "sys/cdefs.h"
#include "errno.h"
#include <sys/kassert.h>
#define DIST_BASE_ADDR (0x2c000000)
#define REDIST_BASE_ADDR (0x2c010000)
struct GICv3_dist_if
{
volatile uint32_t GICD_CTLR; // +0x0000 - RW - Distributor Control Register
const volatile uint32_t GICD_TYPER; // +0x0004 - RO - Interrupt Controller Type Register
const volatile uint32_t GICD_IIDR; // +0x0008 - RO - Distributor Implementer Identification Register
const volatile uint32_t padding0; // +0x000C - RESERVED
volatile uint32_t GICD_STATUSR; // +0x0010 - RW - Status register
const volatile uint32_t padding1[3]; // +0x0014 - RESERVED
volatile uint32_t IMP_DEF[8]; // +0x0020 - RW - Implementation defined registers
volatile uint32_t GICD_SETSPI_NSR; // +0x0040 - WO - Non-secure Set SPI Pending (Used when SPI is signalled using MSI)
const volatile uint32_t padding2; // +0x0044 - RESERVED
volatile uint32_t GICD_CLRSPI_NSR; // +0x0048 - WO - Non-secure Clear SPI Pending (Used when SPI is signalled using MSI)
const volatile uint32_t padding3; // +0x004C - RESERVED
volatile uint32_t GICD_SETSPI_SR; // +0x0050 - WO - Secure Set SPI Pending (Used when SPI is signalled using MSI)
const volatile uint32_t padding4; // +0x0054 - RESERVED
volatile uint32_t GICD_CLRSPI_SR; // +0x0058 - WO - Secure Clear SPI Pending (Used when SPI is signalled using MSI)
const volatile uint32_t padding5[3]; // +0x005C - RESERVED
volatile uint32_t GICD_SEIR; // +0x0068 - WO - System Error Interrupt Register (Note: This was recently removed from the spec)
const volatile uint32_t padding6[5]; // +0x006C - RESERVED
volatile uint32_t GICD_IGROUPR[32]; // +0x0080 - RW - Interrupt Group Registers (Note: In GICv3, need to look at IGROUPR and IGRPMODR)
volatile uint32_t GICD_ISENABLER[32]; // +0x0100 - RW - Interrupt Set-Enable Registers
volatile uint32_t GICD_ICENABLER[32]; // +0x0180 - RW - Interrupt Clear-Enable Registers
volatile uint32_t GICD_ISPENDR[32]; // +0x0200 - RW - Interrupt Set-Pending Registers
volatile uint32_t GICD_ICPENDR[32]; // +0x0280 - RW - Interrupt Clear-Pending Registers
volatile uint32_t GICD_ISACTIVER[32]; // +0x0300 - RW - Interrupt Set-Active Register
volatile uint32_t GICD_ICACTIVER[32]; // +0x0380 - RW - Interrupt Clear-Active Register
volatile uint8_t GICD_IPRIORITYR[1024]; // +0x0400 - RW - Interrupt Priority Registers
volatile uint32_t GICD_ITARGETSR[256]; // +0x0800 - RW - Interrupt Processor Targets Registers
volatile uint32_t GICD_ICFGR[64]; // +0x0C00 - RW - Interrupt Configuration Registers
volatile uint32_t GICD_GRPMODR[32]; // +0x0D00 - RW - Interrupt Group Modifier (Note: In GICv3, need to look at IGROUPR and IGRPMODR)
const volatile uint32_t padding7[32]; // +0x0D80 - RESERVED
volatile uint32_t GICD_NSACR[64]; // +0x0E00 - RW - Non-secure Access Control Register
volatile uint32_t GICD_SGIR; // +0x0F00 - WO - Software Generated Interrupt Register
const volatile uint32_t padding8[3]; // +0x0F04 - RESERVED
volatile uint32_t GICD_CPENDSGIR[4]; // +0x0F10 - RW - Clear pending for SGIs
volatile uint32_t GICD_SPENDSGIR[4]; // +0x0F20 - RW - Set pending for SGIs
const volatile uint32_t padding9[52]; // +0x0F30 - RESERVED
// GICv3.1 extended SPI range
volatile uint32_t GICD_IGROUPRE[128]; // +0x1000 - RW - Interrupt Group Registers (GICv3.1)
volatile uint32_t GICD_ISENABLERE[128]; // +0x1200 - RW - Interrupt Set-Enable Registers (GICv3.1)
volatile uint32_t GICD_ICENABLERE[128]; // +0x1400 - RW - Interrupt Clear-Enable Registers (GICv3.1)
volatile uint32_t GICD_ISPENDRE[128]; // +0x1600 - RW - Interrupt Set-Pending Registers (GICv3.1)
volatile uint32_t GICD_ICPENDRE[128]; // +0x1800 - RW - Interrupt Clear-Pending Registers (GICv3.1)
volatile uint32_t GICD_ISACTIVERE[128]; // +0x1A00 - RW - Interrupt Set-Active Register (GICv3.1)
volatile uint32_t GICD_ICACTIVERE[128]; // +0x1C00 - RW - Interrupt Clear-Active Register (GICv3.1)
const volatile uint32_t padding10[128]; // +0x1E00 - RESERVED
volatile uint8_t GICD_IPRIORITYRE[4096]; // +0x2000 - RW - Interrupt Priority Registers (GICv3.1)
volatile uint32_t GICD_ICFGRE[256]; // +0x3000 - RW - Interrupt Configuration Registers (GICv3.1)
volatile uint32_t GICD_IGRPMODRE[128]; // +0x3400 - RW - Interrupt Group Modifier (GICv3.1)
volatile uint32_t GICD_NSACRE[256]; // +0x3600 - RW - Non-secure Access Control Register (GICv3.1)
const volatile uint32_t padding11[2432]; // +0x3A00 - RESERVED
// GICv3.0
volatile uint64_t GICD_ROUTER[1024]; // +0x6000 - RW - Controls SPI routing when ARE=1
// GICv3.1
volatile uint64_t GICD_ROUTERE[1024]; // +0x8000 - RW - Controls SPI routing when ARE=1 (GICv3.1)
};
struct GICv3_rdist_lpis_if
{
volatile uint32_t GICR_CTLR; // +0x0000 - RW - Redistributor Control Register
const volatile uint32_t GICR_IIDR; // +0x0004 - RO - Redistributor Implementer Identification Register
const volatile uint64_t GICR_TYPER; // +0x0008 - RO - Redistributor Type Register
volatile uint32_t GICR_STATUSR; // +0x0010 - RW - Redistributor Status register
volatile uint32_t GICR_WAKER; // +0x0014 - RW - Wake Request Registers
const volatile uint32_t GICR_MPAMIDR; // +0x0018 - RO - Reports maximum PARTID and PMG (GICv3.1)
volatile uint32_t GICR_PARTID; // +0x001C - RW - Set PARTID and PMG used for Redistributor memory accesses (GICv3.1)
const volatile uint32_t padding1[8]; // +0x0020 - RESERVED
volatile uint64_t GICR_SETLPIR; // +0x0040 - WO - Set LPI pending (Note: IMP DEF if ITS present)
volatile uint64_t GICR_CLRLPIR; // +0x0048 - WO - Set LPI pending (Note: IMP DEF if ITS present)
const volatile uint32_t padding2[6]; // +0x0058 - RESERVED
volatile uint32_t GICR_SEIR; // +0x0068 - WO - (Note: This was removed from the spec)
const volatile uint32_t padding3; // +0x006C - RESERVED
volatile uint64_t GICR_PROPBASER; // +0x0070 - RW - Sets location of the LPI configuration table
volatile uint64_t GICR_PENDBASER; // +0x0078 - RW - Sets location of the LPI pending table
const volatile uint32_t padding4[8]; // +0x0080 - RESERVED
volatile uint64_t GICR_INVLPIR; // +0x00A0 - WO - Invalidates cached LPI config (Note: In GICv3.x: IMP DEF if ITS present)
const volatile uint32_t padding5[2]; // +0x00A8 - RESERVED
volatile uint64_t GICR_INVALLR; // +0x00B0 - WO - Invalidates cached LPI config (Note: In GICv3.x: IMP DEF if ITS present)
const volatile uint32_t padding6[2]; // +0x00B8 - RESERVED
volatile uint64_t GICR_SYNCR; // +0x00C0 - WO - Redistributor Sync
const volatile uint32_t padding7[2]; // +0x00C8 - RESERVED
const volatile uint32_t padding8[12]; // +0x00D0 - RESERVED
volatile uint64_t GICR_MOVLPIR; // +0x0100 - WO - IMP DEF
const volatile uint32_t padding9[2]; // +0x0108 - RESERVED
volatile uint64_t GICR_MOVALLR; // +0x0110 - WO - IMP DEF
const volatile uint32_t padding10[2]; // +0x0118 - RESERVED
};
struct GICv3_rdist_sgis_if
{
const volatile uint32_t padding1[32]; // +0x0000 - RESERVED
volatile uint32_t GICR_IGROUPR[3]; // +0x0080 - RW - Interrupt Group Registers (Security Registers in GICv1)
const volatile uint32_t padding2[29]; // +0x008C - RESERVED
volatile uint32_t GICR_ISENABLER[3]; // +0x0100 - RW - Interrupt Set-Enable Registers
const volatile uint32_t padding3[29]; // +0x010C - RESERVED
volatile uint32_t GICR_ICENABLER[3]; // +0x0180 - RW - Interrupt Clear-Enable Registers
const volatile uint32_t padding4[29]; // +0x018C - RESERVED
volatile uint32_t GICR_ISPENDR[3]; // +0x0200 - RW - Interrupt Set-Pending Registers
const volatile uint32_t padding5[29]; // +0x020C - RESERVED
volatile uint32_t GICR_ICPENDR[3]; // +0x0280 - RW - Interrupt Clear-Pending Registers
const volatile uint32_t padding6[29]; // +0x028C - RESERVED
volatile uint32_t GICR_ISACTIVER[3]; // +0x0300 - RW - Interrupt Set-Active Register
const volatile uint32_t padding7[29]; // +0x030C - RESERVED
volatile uint32_t GICR_ICACTIVER[3]; // +0x0380 - RW - Interrupt Clear-Active Register
const volatile uint32_t padding8[29]; // +0x018C - RESERVED
volatile uint8_t GICR_IPRIORITYR[96]; // +0x0400 - RW - Interrupt Priority Registers
const volatile uint32_t padding9[488]; // +0x0460 - RESERVED
volatile uint32_t GICR_ICFGR[6]; // +0x0C00 - RW - Interrupt Configuration Registers
const volatile uint32_t padding10[58]; // +0x0C18 - RESERVED
volatile uint32_t GICR_IGRPMODR[3]; // +0x0D00 - RW - Interrupt Group Modifier Register
const volatile uint32_t padding11[61]; // +0x0D0C - RESERVED
volatile uint32_t GICR_NSACR; // +0x0E00 - RW - Non-secure Access Control Register
};
struct GICv3_rdist_vlpis_if
{
const volatile uint32_t padding1[28]; // +0x0000 - RESERVED
volatile uint64_t GICR_VPROPBASER; // +0x0070 - RW - Sets location of the LPI vPE Configuration table
volatile uint64_t GICR_VPENDBASER; // +0x0078 - RW - Sets location of the LPI Pending table
};
struct GICv3_rdist_res_if
{
const volatile uint32_t padding1[32]; // +0x0000 - RESERVED
};
struct GICv3_rdist_if
{
struct GICv3_rdist_lpis_if lpis __attribute__((aligned (0x10000)));
struct GICv3_rdist_sgis_if sgis __attribute__((aligned (0x10000)));
#ifdef GICV4
struct GICv3_rdist_vlpis_if vlpis __attribute__((aligned (0x10000)));
struct GICv3_rdist_res_if res __attribute__((aligned (0x10000)));
#endif
};
// +0 from ITS_BASE
struct GICv3_its_ctlr_if
{
volatile uint32_t GITS_CTLR; // +0x0000 - RW - ITS Control Register
const volatile uint32_t GITS_IIDR; // +0x0004 - RO - Implementer Identification Register
const volatile uint64_t GITS_TYPER; // +0x0008 - RO - ITS Type register
const volatile uint32_t GITS_MPAMIDR; // +0x0010 - RO - Reports maxmimum PARTID and PMG (GICv3.1)
volatile uint32_t GITS_PARTIDR; // +0x0004 - RW - Sets the PARTID and PMG used for ITS memory accesses (GICv3.1)
const volatile uint32_t GITS_MPIDR; // +0x0018 - RO - ITS affinity, used for shared vPE table
const volatile uint32_t padding5; // +0x001C - RESERVED
volatile uint32_t GITS_IMPDEF[8]; // +0x0020 - RW - IMP DEF registers
const volatile uint32_t padding2[16]; // +0x0040 - RESERVED
volatile uint64_t GITS_CBASER; // +0x0080 - RW - Sets base address of ITS command queue
volatile uint64_t GITS_CWRITER; // +0x0088 - RW - Points to next enrty to add command
volatile uint64_t GITS_CREADR; // +0x0090 - RW - Points to command being processed
const volatile uint32_t padding3[2]; // +0x0098 - RESERVED
const volatile uint32_t padding4[24]; // +0x00A0 - RESERVED
volatile uint64_t GITS_BASER[8]; // +0x0100 - RW - Sets base address of Device and Collection tables
};
// +0x010000 from ITS_BASE
struct GICv3_its_int_if
{
const volatile uint32_t padding1[16]; // +0x0000 - RESERVED
volatile uint32_t GITS_TRANSLATER; // +0x0040 - RW - Written by peripherals to generate LPI
};
// +0x020000 from ITS_BASE
struct GICv3_its_sgi_if
{
const volatile uint32_t padding1[8]; // +0x0000 - RESERVED
volatile uint64_t GITS_SGIR; // +0x0020 - RW - Written by peripherals to generate vSGI (GICv4.1)
};
struct gic {
struct GICv3_dist_if* gic_dist;
struct GICv3_rdist_if* gic_rdist;
unsigned int max_rd;
};
static struct gic gic = {
.gic_dist = NULL,
.gic_rdist = NULL,
.max_rd = 0
};
static void
gic_addr_init(void)
{
uint32_t index = 0;
gic.gic_dist = (void*)DEVPA2VA(DIST_BASE_ADDR);
gic.gic_rdist = (void*)DEVPA2VA(REDIST_BASE_ADDR);
while((gic.gic_rdist[index].lpis.GICR_TYPER & (1<<4)) == 0) // Keep incrementing until GICR_TYPER.Last reports no more RDs in block
{
index++;
}
gic.max_rd = index;
}
static void
gic_enable(void)
{
// First set the ARE bits
gic.gic_dist->GICD_CTLR = (1 << 5) | (1 << 4);
// The split here is because the register layout is different once ARE==1
// Now set the rest of the options, only enable group1NS interrupts
gic.gic_dist->GICD_CTLR = 0b1110010;
// enable all interrupt groups and routing, disable security
// set SRE bits to enable system registers
__asm__ volatile (
"mrs x0, ICC_SRE_EL1;"
"orr x0, x0, #0x1;"
"msr ICC_SRE_EL1, x0;"
:
:
: "x0"
);
}
uint32_t
gic_get_affinity(void)
{
uint64_t aff;
__asm__ volatile (
"MRS x0, MPIDR_EL1;"
"UBFX x1, x0, #32, #8;"
"BFI w0, w1, #24, #8;"
"MOV %0, x0;"
: "=r" (aff)
:
: "x0", "x1"
);
return aff;
}
int
gic_get_redist_id(uint32_t affinity, unsigned int *id)
{
uint32_t index = 0;
// Check that GIC pointers are valid
do {
if ((gic.gic_rdist[index].lpis.GICR_TYPER >> 32) == affinity) {
*id = index;
return 0;
}
index++;
}
while(index <= gic.max_rd);
return EINVAL;
}
static void
gic_wakeup_redist(uint32_t rdid)
{
uint32_t tmp;
// Tell the Redistributor to wake-up by clearing ProcessorSleep bit
tmp = gic.gic_rdist[rdid].lpis.GICR_WAKER;
tmp = tmp & ~0x2;
gic.gic_rdist[rdid].lpis.GICR_WAKER = tmp;
// Poll ChildrenAsleep bit until Redistributor wakes
do
{
tmp = gic.gic_rdist[rdid].lpis.GICR_WAKER;
} while((tmp & 0x4) != 0);
}
static int
gic_is_valid_extspi(uint32_t rd, uint32_t ID)
{
uint32_t max_spi;
// Check Ext SPI implemented
if (((gic.gic_dist->GICD_TYPER >> 8) & 0x1) == 0) {
return 0; // GICD_TYPER.ESPI==0: Extended SPI range not present
} else {
max_spi = ((gic.gic_dist->GICD_TYPER >> 27) & 0x1F); // Get field which reports the number ESPIs in blocks of 32, minus 1
max_spi = (max_spi + 1) * 32; // Convert into number of ESPIs
max_spi = max_spi + 4096; // Range starts at 4096
if (!(ID < max_spi)) {
return 0;
}
}
return 1;
}
static int
gic_is_valid_extppi(uint32_t rd, uint32_t ID)
{
uint32_t max_ppi;
max_ppi = (gic.gic_rdist[rd].lpis.GICR_TYPER >> 27) & 0x1F;
if (max_ppi == 0) {
return 0;
} else if ((max_ppi == 1) && (ID > 1087)) {
return 0; // Extended PPI range implemented, but supplied INTID beyond range
}
return 1;
}
int
gic_disable_intr(uint32_t rd, uint32_t intid)
{
uint32_t bank;
if (rd > gic.max_rd)
return EINVAL;
if (intid < 31) {
// SGI or PPI
intid = intid & 0x1f; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_rdist[rd].sgis.GICR_ICENABLER[0] = intid;
} else if (intid < 1020) {
// SPI
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1f; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_dist->GICD_ICENABLER[bank] = intid;
} else if ((intid > 1055) && (intid < 1120)) {
// Extended PPI
// Check Ext PPI implemented
if (gic_is_valid_extppi(rd, intid) == 0)
return EINVAL;
intid = intid - 1024;
bank = intid/32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_rdist[rd].sgis.GICR_ICENABLER[bank] = intid;
} else if ((intid > 4095) && (intid < 5120)) {
// Extended SPI
// Check Ext SPI implemented
if (gic_is_valid_extspi(rd, intid) == 0)
return EINVAL;
intid = intid - 4096;
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_dist->GICD_ICENABLERE[bank] = intid;
} else {
return EINVAL;
}
return 0;
}
int
gic_enable_intr(uint32_t rdid, uint32_t intid)
{
uint32_t bank;
if (rdid > gic.max_rd) {
return EINVAL;
}
if (intid < 31) {
// SGI or PPI
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[0] = (1 << intid);
} else if (intid < 1020) {
// SPI
bank = intid/32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1f; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_dist->GICD_ISENABLER[bank] = intid;
} else if ((intid > 1055) && (intid < 1120)) {
// Extended PPI
// Check Ext PPI implemented
if (!gic_is_valid_extppi(rdid, intid))
return EINVAL;
intid = intid - 1024;
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_rdist[rdid].sgis.GICR_ISENABLER[bank] = intid;
} else if ((intid > 4095) && (intid < 5120)) {
// Extended SPI
// Check Ext SPI implemented
if (!gic_is_valid_extspi(rdid, intid))
return EINVAL;
intid = intid - 4096;
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
gic.gic_dist->GICD_ISENABLERE[bank] = intid;
} else {
return EINVAL;
}
return 0;
}
void
gic_set_prio_mask(unsigned int mask)
{
uint64_t _mask = mask & 0xFF;
__asm__ volatile (
"mov x0, %0;"
"msr icc_pmr_el1, x0;"
"dsb sy;"
:
: "r" (_mask)
: "x0"
);
}
int
gic_set_intr_prio(uint32_t rdid, uint32_t intid, uint8_t prio)
{
if (rdid > gic.max_rd) {
return EINVAL;
}
if (intid < 31) {
// SGI or PPI
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
} else if (intid < 1020) {
// SPI
gic.gic_dist->GICD_IPRIORITYR[intid] = prio;
} else if ((intid > 1055) && (intid < 1120)) {
// Extended PPI
// Check Ext PPI implemented
if (!gic_is_valid_extppi(rdid, intid))
return EINVAL;
intid = intid - 1024;
gic.gic_rdist[rdid].sgis.GICR_IPRIORITYR[intid] = prio;
} else if ((intid > 4095) && (intid < 5120)) {
// Extended SPI
// Check Ext SPI implemented
if (!gic_is_valid_extspi(rdid, intid))
return EINVAL;
gic.gic_dist->GICD_IPRIORITYRE[(intid-4096)] = prio;
} else {
return EINVAL;
}
return 0;
}
#define GICV3_GROUP0 (0)
#define GICV3_GROUP1_SECURE (1)
#define GICV3_GROUP1_NON_SECURE (2)
static int
gic_calc_group_mod(uint32_t intid, uint32_t sec, uint32_t * _group, uint32_t * _mod)
{
uint32_t group = *_group, mod = *_mod;
switch (sec) {
case GICV3_GROUP0:
group = (group & ~intid);
mod = (mod & ~intid);
break;
case GICV3_GROUP1_SECURE:
group = (group & ~intid);
mod = (mod | intid);
break;
case GICV3_GROUP1_NON_SECURE:
group = (group | intid);
mod = (mod & ~intid);
break;
default:
return EINVAL;
}
*_group = group;
*_mod = mod;
return 0;
}
static int
gic_set_intr_group(uint32_t rdid, uint32_t intid, uint32_t sec)
{
uint32_t bank, group, mod;
if (rdid > gic.max_rd)
return EINVAL;
if (intid < 31) {
// SGI or PPI
intid = intid & 0x1f; // Find which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
// Read current values
group = gic.gic_rdist[rdid].sgis.GICR_IGROUPR[0];
mod = gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[0];
// Update required bits
gic_calc_group_mod(intid, sec, &group, &mod);
// Write modified version back
gic.gic_rdist[rdid].sgis.GICR_IGROUPR[0] = group;
gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[0] = mod;
} else if (intid < 1020) {
// SPI
bank = intid/32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1f; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
group = gic.gic_dist->GICD_IGROUPR[bank];
mod = gic.gic_dist->GICD_GRPMODR[bank];
gic_calc_group_mod(intid, sec, &group, &mod);
gic.gic_dist->GICD_IGROUPR[bank] = group;
gic.gic_dist->GICD_GRPMODR[bank] = mod;
} else if ((intid > 1055) && (intid < 1120)) {
// Extended PPI
// Check Ext PPI implemented
if (!gic_is_valid_extppi(rdid, intid))
return EINVAL;
intid = intid - 1024;
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
// Read current values
group = gic.gic_rdist[rdid].sgis.GICR_IGROUPR[bank];
mod = gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[bank];
// Update required bits
gic_calc_group_mod(intid, sec, &group, &mod);
// Write modified version back
gic.gic_rdist[rdid].sgis.GICR_IGROUPR[bank] = group;
gic.gic_rdist[rdid].sgis.GICR_IGRPMODR[bank] = mod;
} else if ((intid > 4095) && (intid < 5120)) {
// Extended SPI
// Check Ext SPI implemented
if (gic_is_valid_extspi(rdid, intid) == 0)
return EINVAL;
intid = intid - 4096;
bank = intid / 32; // There are 32 IDs per register, need to work out which register to access
intid = intid & 0x1F; // ... and which bit within the register
intid = 1 << intid; // Move a '1' into the correct bit position
// Read current values
group = gic.gic_dist->GICD_IGROUPRE[bank];
mod = gic.gic_dist->GICD_IGRPMODRE[bank];
// Update required bits
gic_calc_group_mod(intid, sec, &group, &mod);
// Write modified version back
gic.gic_dist->GICD_IGROUPRE[bank] = group;
gic.gic_dist->GICD_IGRPMODRE[bank] = mod;
} else
return EINVAL;
return 0;
}
void
gic_send_eoi(int intr)
{
intr = intr & 0xFFFFFF;
__asm__ volatile (
"mov x0, %x0;"
"msr ICC_EOIR1_EL1, x0;"
"dsb sy;"
:
: "r" (intr)
: "x0"
);
}
unsigned int
gic_ack_intr(void)
{
unsigned int ret;
__asm__ volatile (
"mrs x0, ICC_IAR1_EL1;"
"mov %x0, x0;"
: "=r" (ret)
:
: "x0"
);
return ret;
}
int
gic_init(void)
{
int ret;
gic_addr_init();
gic_enable();
unsigned int rd;
// Get the ID of the Redistributor connected to this PE
ret = gic_get_redist_id(gic_get_affinity(), &rd);
if (ret != 0) {
return ret;
}
// Mark this core as being active
gic_wakeup_redist(rd);
// Configure the CPU interface
// This assumes that the SRE bits are already set
// enable group 1 interrupts
__asm__ volatile (
"MRS x0, ICC_IGRPEN1_EL1;"
"ORR w0, w0, #1;"
"MSR ICC_IGRPEN1_EL1, x0;"
"ISB"
:
:
: "x0"
);
gic_set_prio_mask(0xff);
// Non-secure EL1 Physical Timer (INTID 30)
ret = gic_set_intr_prio(rd, 30, 0);
if (ret != 0) {
return ret;
}
ret = gic_set_intr_group(rd, 30, GICV3_GROUP1_NON_SECURE);
if (ret != 0) {
return ret;
}
return gic_enable_intr(rd, 30);
}