summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/arm64/conf/files.arm648
-rw-r--r--sys/arch/arm64/dev/ampintc.c128
2 files changed, 129 insertions, 7 deletions
diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64
index 89a54d8f0d6..e2370431497 100644
--- a/sys/arch/arm64/conf/files.arm64
+++ b/sys/arch/arm64/conf/files.arm64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.10 2017/02/24 10:13:13 patrick Exp $
+# $OpenBSD: files.arm64,v 1.11 2017/02/25 17:04:19 patrick Exp $
maxpartitions 16
maxusers 2 8 64
@@ -115,9 +115,11 @@ device pluart
attach pluart at fdt
file arch/arm64/dev/pluart.c pluart
-device ampintc
+device ampintc: fdt
attach ampintc at fdt
-file arch/arm64/dev/ampintc.c ampintc
+device ampintcmsi
+attach ampintcmsi at fdt
+file arch/arm64/dev/ampintc.c ampintc | ampintcmsi
device agtimer
attach agtimer at fdt
diff --git a/sys/arch/arm64/dev/ampintc.c b/sys/arch/arm64/dev/ampintc.c
index 5a2e127608b..11953200981 100644
--- a/sys/arch/arm64/dev/ampintc.c
+++ b/sys/arch/arm64/dev/ampintc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ampintc.c,v 1.6 2017/02/25 13:19:57 patrick Exp $ */
+/* $OpenBSD: ampintc.c,v 1.7 2017/02/25 17:04:19 patrick Exp $ */
/*
* Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org>
*
@@ -27,12 +27,16 @@
#include <sys/device.h>
#include <sys/evcount.h>
+#include <uvm/uvm_extern.h>
+
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/fdt.h>
#include <dev/ofw/openfirm.h>
+#include <arm64/dev/simplebusvar.h>
+
/* registers */
#define ICD_DCR 0x000
#define ICD_DCR_ES 0x00000001
@@ -129,7 +133,7 @@
#define IRQ_DISABLE 0
struct ampintc_softc {
- struct device sc_dev;
+ struct simplebus_softc sc_sbus;
struct intrq *sc_ampintc_handler;
int sc_nintr;
bus_space_tag_t sc_iot;
@@ -240,7 +244,7 @@ ampintc_attach(struct device *parent, struct device *self, void *aux)
ICD_ICTR) & ICD_ICTR_ITL_M);
nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
sc->sc_nintr = nintr;
- printf(" nirq %d\n", nintr);
+ printf(" nirq %d", nintr);
/* Disable all interrupts, clear all pending */
for (i = 0; i < nintr/32; i++) {
@@ -288,6 +292,9 @@ ampintc_attach(struct device *parent, struct device *self, void *aux)
sc->sc_ic.ic_establish = ampintc_intr_establish_fdt;
sc->sc_ic.ic_disestablish = ampintc_intr_disestablish;
arm_intr_register_fdt(&sc->sc_ic);
+
+ /* attach GICv2M frame controller */
+ simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
}
void
@@ -558,7 +565,7 @@ ampintc_intr_establish_fdt(void *cookie, int *cell, int level,
else if (cell[0] == 1)
irq += 16;
else
- panic("%s: bogus interrupt type", sc->sc_dev.dv_xname);
+ panic("%s: bogus interrupt type", sc->sc_sbus.sc_dev.dv_xname);
/* SPIs are only active-high level or low-to-high edge */
if (cell[2] & 0x3)
@@ -640,3 +647,116 @@ ampintc_intr_string(void *cookie)
snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq);
return irqstr;
}
+
+/*
+ * GICv2m frame controller for MSI interrupts.
+ */
+#define GICV2M_TYPER 0x008
+#define GICV2M_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff)
+#define GICV2M_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff)
+#define GICV2M_SETSPI_NS 0x040
+
+int ampintc_msi_match(struct device *, void *, void *);
+void ampintc_msi_attach(struct device *, struct device *, void *);
+void *ampintc_intr_establish_msi(void *, uint64_t *, uint64_t *,
+ int , int (*)(void *), void *, char *);
+void ampintc_intr_disestablish_msi(void *);
+
+struct ampintc_msi_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ paddr_t sc_addr;
+ int sc_bspi;
+ int sc_nspi;
+ void **sc_spi;
+ struct interrupt_controller sc_ic;
+};
+
+struct cfattach ampintcmsi_ca = {
+ sizeof (struct ampintc_msi_softc), ampintc_msi_match, ampintc_msi_attach
+};
+
+struct cfdriver ampintcmsi_cd = {
+ NULL, "ampintcmsi", DV_DULL
+};
+
+int
+ampintc_msi_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "arm,gic-v2m-frame");
+}
+
+void
+ampintc_msi_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ uint32_t typer;
+
+ sc->sc_iot = faa->fa_iot;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sc->sc_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ /* XXX: Hack to retrieve the physical address (from a CPU PoV). */
+ if (!pmap_extract(pmap_kernel(), sc->sc_ioh, &sc->sc_addr)) {
+ printf(": cannot retrieve msi addr\n");
+ return;
+ }
+
+ typer = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GICV2M_TYPER);
+ sc->sc_bspi = GICV2M_TYPER_SPI_BASE(typer);
+ sc->sc_nspi = GICV2M_TYPER_SPI_COUNT(typer);
+
+ sc->sc_bspi = OF_getpropint(faa->fa_node,
+ "arm,msi-base-spi", sc->sc_bspi);
+ sc->sc_nspi = OF_getpropint(faa->fa_node,
+ "arm,msi-num-spis", sc->sc_nspi);
+
+ printf(": nspi %d\n", sc->sc_nspi);
+
+ sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(int), M_DEVBUF,
+ M_WAITOK|M_ZERO);
+
+ sc->sc_ic.ic_node = faa->fa_node;
+ sc->sc_ic.ic_cookie = sc;
+ sc->sc_ic.ic_establish_msi = ampintc_intr_establish_msi;
+ sc->sc_ic.ic_disestablish = ampintc_intr_disestablish_msi;
+ arm_intr_register_fdt(&sc->sc_ic);
+}
+
+void *
+ampintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data,
+ int level, int (*func)(void *), void *arg, char *name)
+{
+ struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
+ void *cookie;
+ int i;
+
+ for (i = 0; i < sc->sc_nspi; i++) {
+ if (sc->sc_spi[i] != NULL)
+ continue;
+
+ cookie = ampintc_intr_establish_ext(sc->sc_bspi + i,
+ IST_EDGE_RISING, level, func, arg, name);
+ if (cookie == NULL)
+ return NULL;
+
+ *addr = sc->sc_addr + GICV2M_SETSPI_NS;
+ *data = sc->sc_bspi + i + 32;
+ sc->sc_spi[i] = cookie;
+ return &sc->sc_spi[i];
+ }
+
+ return NULL;
+}
+
+void
+ampintc_intr_disestablish_msi(void *cookie)
+{
+ ampintc_intr_disestablish(*(void **)cookie);
+ *(void **)cookie = NULL;
+}