2 #include "../port/lib.h"
7 #include "../port/pci.h"
10 #include "../port/error.h"
13 GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
14 GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
15 GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
17 GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
19 GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
20 GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
22 GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
23 GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
25 GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
26 GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
28 GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
29 GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
30 GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
33 GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
34 GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
35 GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
37 GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
38 GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
40 GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
49 GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
54 GICC_CTLR = 0x000/4, /* RW, CPU Interace Control Register */
55 GICC_PMR = 0x004/4, /* RW, Interrupt Priority Mask Register */
56 GICC_BPR = 0x008/4, /* RW, Binary Point Register */
57 GICC_IAR = 0x00C/4, /* RO, Interrupt Acknowledge Register */
58 GICC_EOIR = 0x010/4, /* WO, End of Interrupt Register */
59 GICC_RPR = 0x014/4, /* RO, Running Priority Register */
60 GICC_HPPIR = 0x018/4, /* RO, Highest Priority Pending Interrupt Register */
61 GICC_ABPR = 0x01C/4, /* RW, Aliased Binary Point Register */
62 GICC_AIAR = 0x020/4, /* RO, Aliased Interrupt Acknowledge Register */
63 GICC_AEOIR = 0x024/4, /* WO, Aliased End of Interrupt Register */
64 GICC_AHPPIR = 0x028/4, /* RO, Aliased Highest Priority Pending Interrupt Register */
65 GICC_APR0 = 0x0D0/4, /* RW, Active Priority Register */
66 GICC_NSAPR0 = 0x0E0/4, /* RW, Non-Secure Active Priority Register */
67 GICC_IIDR = 0x0FC/4, /* RO, CPU Interface Identification Register */
68 GICC_DIR = 0x1000/4, /* WO, Deactivate Interrupt Register */
70 GICH_HCR = 0x000/4, /* RW, Hypervisor Control Register */
71 GICH_VTR = 0x004/4, /* RO, VGIC Type Register */
72 GICH_VMCR = 0x008/4, /* RW, Virtual Machine Control Register */
73 GICH_MISR = 0x010/4, /* RO, Maintenance Interrupt Status Register */
74 GICH_EISR0 = 0x020/4, /* RO, End of Interrupt Status Register */
75 GICH_ELSR0 = 0x030/4, /* RO, Empty List Register Status Register */
76 GICH_APR0 = 0x0F0/4, /* RW, Active Priority Register */
77 GICH_LR0 = 0x100/4, /* RW, List Registers (0x100-0x10C) */
79 GICV_CTLR = 0x000/4, /* RW, Virtual Machine Control Register */
80 GICV_PMR = 0x004/4, /* RW, VM Priority Mask Register */
81 GICV_BPR = 0x008/4, /* RW, VM Binary Point Register */
82 GICV_IAR = 0x00C/4, /* RO, VM Interrupt Acknowledge Register */
83 GICV_EOIR = 0x010/4, /* WO, VM End of Interrupt Register */
84 GICV_RPR = 0x014/4, /* RO, VM Running Priority Register */
85 GICV_HPPIR = 0x018/4, /* RO, VM Highest Piority Pending Interrupt Register */
86 GICV_ABPR = 0x01C/4, /* RW, VM Aliased Binary Point Register */
87 GICV_AIAR = 0x020/4, /* RO, VM Aliased Interrupt Acknowledge Register */
88 GICV_AEOIR = 0x024/4, /* WO, VM Aliased End of Interrupt Register */
89 GICV_AHPPIR = 0x028/4, /* RO, VM Aliaed Highest Piority Pending Interrupt Register */
90 GICV_APR0 = 0x0D0/4, /* RW, VM Active Priority Register */
91 GICV_IIDR = 0x0FC/4, /* RO, VM CPU Interface Identification Register */
92 GICV_DIR = 0x1000/4, /* WO, VM Deactivate Interrupt Register */
95 typedef struct Vctl Vctl;
98 void (*f)(Ureg*, void*);
104 static Lock vctllock;
105 static Vctl *vctl[MAXMACH][32], *vfiq;
106 static u32int *cregs, *dregs;
109 intrcpushutdown(void)
111 if(cregs == nil || dregs == nil){
114 pa = sysrd(CBAR_EL1);
115 va = ARMLOCAL + (pa - soc.armlocal);
116 dregs = (u32int*)(va + 0x1000);
117 cregs = (u32int*)(va + 0x2000);
120 /* disable cpu interface */
121 cregs[GICC_CTLR] &= ~1;
132 /* disable distributor */
133 dregs[GICD_CTLR] &= ~1;
136 /* clear all interrupts */
137 n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
138 for(i = 0; i < n; i += 32){
139 dregs[GICD_ISENABLER0 + (i/32)] = -1;
141 dregs[GICD_ICENABLER0 + (i/32)] = -1;
144 for(i = 0; i < n; i += 4){
145 dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
146 dregs[GICD_TARGETSR0 + (i/4)] = 0;
148 for(i = 32; i < n; i += 16)
149 dregs[GICD_ICFGR0 + (i/16)] = 0;
154 * called by trap to handle irq interrupts.
155 * returns true iff a clock interrupt, thus maybe reschedule.
165 intid = cregs[GICC_IAR] & 0xFFFFFF;
166 if((intid & ~3) == 1020)
167 return 0; // spurious
169 for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
170 if(v->intid == intid){
174 if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
178 cregs[GICC_EOIR] = intid;
183 * called direct from lexception.s to handle fiq interrupt.
192 intid = cregs[GICC_IAR] & 0xFFFFFF;
193 if((intid & ~3) == 1020)
196 if(v != nil && v->intid == intid && m->machno == 0){
201 cregs[GICC_EOIR] = intid;
205 intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
211 if(BUSTYPE(tbdf) == BusPCI){
212 pciintrenable(tbdf, f, a);
215 if(tbdf != BUSUNKNOWN)
234 print("irqenable: missing documentation for local irq %d\n", irq);
241 else if(irq >= IRQbasic)
242 intid += IRQgic-64-32-8-IRQbasic;
248 if((v = xalloc(sizeof(Vctl))) == nil)
249 panic("irqenable: no mem");
260 v->next = vctl[cpu][intid%32];
261 vctl[cpu][intid%32] = v;
264 /* enable cpu interface */
265 cregs[GICC_PMR] = 0xFF;
268 cregs[GICC_CTLR] |= 1;
271 cregs[GICC_EOIR] = intid;
273 /* enable distributor */
274 dregs[GICD_CTLR] |= 1;
278 dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
279 dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
283 dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
290 intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
292 if(BUSTYPE(tbdf) == BusPCI){
293 pciintrdisable(tbdf, f, a);