682 lines
25 KiB
C
682 lines
25 KiB
C
|
#include <machine/gic.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*)DIST_BASE_ADDR;
|
||
|
gic.gic_rdist = (void*)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);
|
||
|
}
|