diff options
-rw-r--r-- | sys/arch/arm64/conf/files.arm64 | 8 | ||||
-rw-r--r-- | sys/arch/arm64/dev/ampintc.c | 128 |
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; +} |