changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: bcm64: add gic interrupt controller driver for raspberry pi 4

changeset 7314: 5afd2605d0f3
parent 7313: db3e8d004b27
child 7315: 6e8b95bccec4
author: cinap_lenrek@felloff.net
date: Thu, 25 Jul 2019 09:02:47 +0200
files: sys/src/9/bcm64/gic.c sys/src/9/bcm64/sysreg.h
description: bcm64: add gic interrupt controller driver for raspberry pi 4
     1.1new file mode 100644
     1.2--- /dev/null
     1.3+++ b/sys/src/9/bcm64/gic.c
     1.4@@ -0,0 +1,295 @@
     1.5+#include "u.h"
     1.6+#include "../port/lib.h"
     1.7+#include "mem.h"
     1.8+#include "dat.h"
     1.9+#include "fns.h"
    1.10+#include "io.h"
    1.11+#include "ureg.h"
    1.12+#include "sysreg.h"
    1.13+#include "../port/error.h"
    1.14+
    1.15+enum {
    1.16+	GICD_CTLR	= 0x000/4,	/* RW, Distributor Control Register */
    1.17+	GICD_TYPER	= 0x004/4,	/* RO, Interrupt Controller Type */
    1.18+	GICD_IIDR	= 0x008/4,	/* RO, Distributor Implementer Identification Register */
    1.19+
    1.20+	GICD_IGROUPR0	= 0x080/4,	/* RW, Interrupt Group Registers (0x80-0xBC) */
    1.21+
    1.22+	GICD_ISENABLER0	= 0x100/4,	/* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
    1.23+	GICD_ICENABLER0	= 0x180/4,	/* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
    1.24+
    1.25+	GICD_ISPENDR0	= 0x200/4,	/* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
    1.26+	GICD_ICPENDR0	= 0x280/4,	/* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
    1.27+
    1.28+	GICD_ISACTIVER0	= 0x300/4,	/* RW, Interrupt Set-Active Registers (0x300-0x33C) */
    1.29+	GICD_ICACTIVER0 = 0x380/4,	/* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
    1.30+
    1.31+	GICD_IPRIORITYR0= 0x400/4,	/* RW, Interrupt Priority Registers (0x400-0x5FC) */
    1.32+	GICD_TARGETSR0	= 0x800/4,	/* RW, Interrupt Target Registers (0x800-0x9FC) */
    1.33+	GICD_ICFGR0	= 0xC00/4,	/* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
    1.34+
    1.35+	GICD_ISR0	= 0xD00/4,
    1.36+	GICD_PPISR	= GICD_ISR0,	/* RO, Private Peripheral Interrupt Status Register */
    1.37+	GICD_SPISR0	= GICD_ISR0+1,	/* RO, Shared Peripheral Interrupt Status Register */
    1.38+	GICD_SGIR	= 0xF00/4,	/* WO, Software Generated Interrupt Register */
    1.39+
    1.40+	GICD_CPENDSGIR0	= 0xF10/4,	/* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
    1.41+	GICD_SPENDSGIR0	= 0xF20/4,	/* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
    1.42+
    1.43+	GICD_PIDR4	= 0xFD0/4,	/* RO, Perpheral ID Registers */
    1.44+	GICD_PIDR5	= 0xFD4/4,
    1.45+	GICD_PIDR6	= 0xFD8/4,
    1.46+	GICD_PIDR7	= 0xFDC/4,
    1.47+	GICD_PIDR0	= 0xFE0/4,
    1.48+	GICD_PIDR1	= 0xFE4/4,
    1.49+	GICD_PIDR2	= 0xFE8/4,
    1.50+	GICD_PIDR3	= 0xFEC/4,
    1.51+
    1.52+	GICD_CIDR0	= 0xFF0/4,	/* RO, Component ID Registers */
    1.53+	GICD_CIDR1	= 0xFF4/4,
    1.54+	GICD_CIDR2	= 0xFF8/4,
    1.55+	GICD_CIDR3	= 0xFFC/4,
    1.56+
    1.57+	GICC_CTLR	= 0x000/4,	/* RW, CPU Interace Control Register */
    1.58+	GICC_PMR	= 0x004/4,	/* RW, Interrupt Priority Mask Register */
    1.59+	GICC_BPR	= 0x008/4,	/* RW, Binary Point Register */
    1.60+	GICC_IAR	= 0x00C/4,	/* RO, Interrupt Acknowledge Register */
    1.61+	GICC_EOIR	= 0x010/4,	/* WO, End of Interrupt Register */
    1.62+	GICC_RPR	= 0x014/4,	/* RO, Running Priority Register */
    1.63+	GICC_HPPIR	= 0x018/4,	/* RO, Highest Priority Pending Interrupt Register */
    1.64+	GICC_ABPR	= 0x01C/4,	/* RW, Aliased Binary Point Register */
    1.65+	GICC_AIAR	= 0x020/4,	/* RO, Aliased Interrupt Acknowledge Register */
    1.66+	GICC_AEOIR	= 0x024/4,	/* WO, Aliased End of Interrupt Register */
    1.67+	GICC_AHPPIR	= 0x028/4,	/* RO, Aliased Highest Priority Pending Interrupt Register */
    1.68+	GICC_APR0	= 0x0D0/4,	/* RW, Active Priority Register */
    1.69+	GICC_NSAPR0	= 0x0E0/4,	/* RW, Non-Secure Active Priority Register */
    1.70+	GICC_IIDR	= 0x0FC/4,	/* RO, CPU Interface Identification Register */
    1.71+	GICC_DIR	= 0x1000/4,	/* WO, Deactivate Interrupt Register */
    1.72+
    1.73+	GICH_HCR	= 0x000/4,	/* RW, Hypervisor Control Register */
    1.74+	GICH_VTR	= 0x004/4,	/* RO, VGIC Type Register */
    1.75+	GICH_VMCR	= 0x008/4,	/* RW, Virtual Machine Control Register */
    1.76+	GICH_MISR	= 0x010/4,	/* RO, Maintenance Interrupt Status Register */
    1.77+	GICH_EISR0	= 0x020/4,	/* RO, End of Interrupt Status Register */
    1.78+	GICH_ELSR0	= 0x030/4,	/* RO, Empty List Register Status Register */
    1.79+	GICH_APR0	= 0x0F0/4,	/* RW, Active Priority Register */
    1.80+	GICH_LR0	= 0x100/4,	/* RW, List Registers (0x100-0x10C) */
    1.81+
    1.82+	GICV_CTLR	= 0x000/4,	/* RW, Virtual Machine Control Register */
    1.83+	GICV_PMR	= 0x004/4,	/* RW, VM Priority Mask Register */
    1.84+	GICV_BPR	= 0x008/4,	/* RW, VM Binary Point Register */
    1.85+	GICV_IAR	= 0x00C/4,	/* RO, VM Interrupt Acknowledge Register */
    1.86+	GICV_EOIR	= 0x010/4,	/* WO, VM End of Interrupt Register */
    1.87+	GICV_RPR	= 0x014/4,	/* RO, VM Running Priority Register */
    1.88+	GICV_HPPIR	= 0x018/4,	/* RO, VM Highest Piority Pending Interrupt Register */
    1.89+	GICV_ABPR	= 0x01C/4,	/* RW, VM Aliased Binary Point Register */
    1.90+	GICV_AIAR	= 0x020/4,	/* RO, VM Aliased Interrupt Acknowledge Register */
    1.91+	GICV_AEOIR	= 0x024/4,	/* WO, VM Aliased End of Interrupt Register */
    1.92+	GICV_AHPPIR	= 0x028/4,	/* RO, VM Aliaed Highest Piority Pending Interrupt Register */
    1.93+	GICV_APR0	= 0x0D0/4,	/* RW, VM Active Priority Register */
    1.94+	GICV_IIDR	= 0x0FC/4,	/* RO, VM CPU Interface Identification Register */
    1.95+	GICV_DIR	= 0x1000/4,	/* WO, VM Deactivate Interrupt Register */
    1.96+};
    1.97+
    1.98+typedef struct Vctl Vctl;
    1.99+struct Vctl {
   1.100+	Vctl	*next;
   1.101+	void	(*f)(Ureg*, void*);
   1.102+	void	*a;
   1.103+	int	irq;
   1.104+	u32int	intid;
   1.105+};
   1.106+
   1.107+static Lock vctllock;
   1.108+static Vctl *vctl[MAXMACH][32], *vfiq;
   1.109+static u32int *cregs, *dregs;
   1.110+
   1.111+void
   1.112+intrcpushutdown(void)
   1.113+{
   1.114+	if(cregs == nil || dregs == nil){
   1.115+		uintptr va, pa;
   1.116+
   1.117+		pa = sysrd(CBAR_EL1);
   1.118+		va = ARMLOCAL + (pa - soc.armlocal);
   1.119+		dregs = (u32int*)(va + 0x1000);
   1.120+		cregs = (u32int*)(va + 0x2000);
   1.121+	}
   1.122+
   1.123+	/* disable cpu interface */
   1.124+	cregs[GICC_CTLR] &= ~1;
   1.125+	coherence();
   1.126+}
   1.127+
   1.128+void
   1.129+intrsoff(void)
   1.130+{
   1.131+	int i, n;
   1.132+
   1.133+	intrcpushutdown();
   1.134+
   1.135+	/* disable distributor */
   1.136+	dregs[GICD_CTLR] &= ~1;
   1.137+	coherence();
   1.138+
   1.139+	/* clear all interrupts */
   1.140+	n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
   1.141+	for(i = 0; i < n; i += 32){
   1.142+		dregs[GICD_ISENABLER0 + (i/32)] = -1;
   1.143+		coherence();
   1.144+		dregs[GICD_ICENABLER0 + (i/32)] = -1;
   1.145+		coherence();
   1.146+	}
   1.147+	for(i = 0; i < n; i += 4){
   1.148+		dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
   1.149+		dregs[GICD_TARGETSR0 + (i/4)] = 0;
   1.150+	}
   1.151+	for(i = 32; i < n; i += 16)
   1.152+		dregs[GICD_ICFGR0 + (i/16)] = 0;
   1.153+	coherence();
   1.154+}
   1.155+
   1.156+/*
   1.157+ *  called by trap to handle irq interrupts.
   1.158+ *  returns true iff a clock interrupt, thus maybe reschedule.
   1.159+ */
   1.160+int
   1.161+irq(Ureg* ureg)
   1.162+{
   1.163+	Vctl *v;
   1.164+	int clockintr;
   1.165+	u32int intid;
   1.166+
   1.167+	m->intr++;
   1.168+	intid = cregs[GICC_IAR] & 0xFFFFFF;
   1.169+	if((intid & ~3) == 1020)
   1.170+		return 0; // spurious
   1.171+	clockintr = 0;
   1.172+	for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
   1.173+		if(v->intid == intid){
   1.174+			coherence();
   1.175+			v->f(ureg, v->a);
   1.176+			coherence();
   1.177+			if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
   1.178+				clockintr = 1;
   1.179+		}
   1.180+	coherence();
   1.181+	cregs[GICC_EOIR] = intid;
   1.182+	return clockintr;
   1.183+}
   1.184+
   1.185+/*
   1.186+ * called direct from lexception.s to handle fiq interrupt.
   1.187+ */
   1.188+void
   1.189+fiq(Ureg *ureg)
   1.190+{
   1.191+	Vctl *v;
   1.192+	u32int intid;
   1.193+
   1.194+	m->intr++;
   1.195+	intid = cregs[GICC_IAR] & 0xFFFFFF;
   1.196+	if((intid & ~3) == 1020)
   1.197+		return;	// spurious
   1.198+	v = vfiq;
   1.199+	if(v != nil && v->intid == intid && m->machno == 0){
   1.200+		coherence();
   1.201+		v->f(ureg, v->a);
   1.202+		coherence();
   1.203+	}
   1.204+	cregs[GICC_EOIR] = intid;
   1.205+}
   1.206+
   1.207+void
   1.208+intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
   1.209+{
   1.210+	Vctl *v;
   1.211+	u32int intid;
   1.212+	int cpu, prio;
   1.213+
   1.214+	if(BUSTYPE(tbdf) == BusPCI){
   1.215+		pciintrenable(tbdf, f, a);
   1.216+		return;
   1.217+	}
   1.218+	if(tbdf != BUSUNKNOWN)
   1.219+		return;
   1.220+
   1.221+	cpu = 0;
   1.222+	prio = 0x80;
   1.223+	intid = irq;
   1.224+	switch(irq){
   1.225+	case IRQcntps:
   1.226+		intid = 16 + 13;
   1.227+		break;
   1.228+	case IRQcntpns:
   1.229+		intid = 16 + 14;
   1.230+		break;
   1.231+
   1.232+	case IRQmbox0:
   1.233+	case IRQmbox1:
   1.234+	case IRQmbox2:
   1.235+	case IRQmbox3:
   1.236+	case IRQlocaltmr:
   1.237+		print("irqenable: missing documentation for local irq %d\n", irq);
   1.238+		return;
   1.239+
   1.240+	default:
   1.241+		if(irq < IRQgic){
   1.242+			if(irq < 64)
   1.243+				intid += IRQgic-64;
   1.244+			else if(irq >= IRQbasic)
   1.245+				intid += IRQgic-64-32-8-IRQbasic;
   1.246+		}
   1.247+	}
   1.248+	if(intid < 32)
   1.249+		cpu = m->machno;
   1.250+
   1.251+	if((v = xalloc(sizeof(Vctl))) == nil)
   1.252+		panic("irqenable: no mem");
   1.253+	v->irq = irq;
   1.254+	v->intid = intid;
   1.255+	v->f = f;
   1.256+	v->a = a;
   1.257+
   1.258+	lock(&vctllock);
   1.259+	if(irq == IRQfiq){
   1.260+		vfiq = v;
   1.261+		prio = 0;
   1.262+	}else{
   1.263+		v->next = vctl[cpu][intid%32];
   1.264+		vctl[cpu][intid%32] = v;
   1.265+	}
   1.266+
   1.267+	/* enable cpu interface */
   1.268+	cregs[GICC_PMR] = 0xFF;
   1.269+	coherence();
   1.270+
   1.271+	cregs[GICC_CTLR] |= 1;
   1.272+	coherence();
   1.273+
   1.274+	cregs[GICC_EOIR] = intid;
   1.275+
   1.276+	/* enable distributor */
   1.277+	dregs[GICD_CTLR] |= 1;
   1.278+	coherence();
   1.279+
   1.280+	/* setup */
   1.281+	dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
   1.282+	dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
   1.283+	coherence();
   1.284+
   1.285+	/* turn on */
   1.286+	dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
   1.287+	coherence();
   1.288+
   1.289+	unlock(&vctllock);
   1.290+}
   1.291+
   1.292+void
   1.293+intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
   1.294+{
   1.295+	if(BUSTYPE(tbdf) == BusPCI){
   1.296+		pciintrdisable(tbdf, f, a);
   1.297+		return;
   1.298+	}
   1.299+}
     2.1--- a/sys/src/9/bcm64/sysreg.h
     2.2+++ b/sys/src/9/bcm64/sysreg.h
     2.3@@ -1,6 +1,15 @@
     2.4 #define MIDR_EL1			SYSREG(3,0,0,0,0)
     2.5 #define MPIDR_EL1			SYSREG(3,0,0,0,5)
     2.6+#define ID_AA64AFR0_EL1			SYSREG(3,0,0,5,4)
     2.7+#define ID_AA64AFR1_EL1			SYSREG(3,0,0,5,5)
     2.8+#define ID_AA64DFR0_EL1			SYSREG(3,0,0,5,0)
     2.9+#define ID_AA64DFR1_EL1			SYSREG(3,0,0,5,1)
    2.10+#define ID_AA64ISAR0_EL1		SYSREG(3,0,0,6,0)
    2.11+#define ID_AA64ISAR1_EL1		SYSREG(3,0,0,6,1)
    2.12 #define ID_AA64MMFR0_EL1		SYSREG(3,0,0,7,0)
    2.13+#define ID_AA64MMFR1_EL1		SYSREG(3,0,0,7,1)
    2.14+#define ID_AA64PFR0_EL1			SYSREG(3,0,0,4,0)
    2.15+#define ID_AA64PFR1_EL1			SYSREG(3,0,0,4,1)
    2.16 #define SCTLR_EL1			SYSREG(3,0,1,0,0)
    2.17 #define CPACR_EL1			SYSREG(3,0,1,0,2)
    2.18 #define MAIR_EL1			SYSREG(3,0,10,2,0)
    2.19@@ -35,6 +44,7 @@
    2.20 #define ACTLR_EL2			SYSREG(3,4,1,0,1)
    2.21 #define CPUACTLR_EL1			SYSREG(3,1,15,2,0)
    2.22 #define CPUECTLR_EL1			SYSREG(3,1,15,2,1)
    2.23+#define CBAR_EL1			SYSREG(3,1,15,3,0)
    2.24 
    2.25 /* l.s redefines this for the assembler */
    2.26 #define SYSREG(op0,op1,Cn,Cm,op2)	((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5)