summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arch/arm64/conf/GENERIC3
-rw-r--r--sys/arch/arm64/conf/RAMDISK3
-rw-r--r--sys/dev/fdt/files.fdt6
-rw-r--r--sys/dev/fdt/mvgicp.c176
-rw-r--r--sys/dev/fdt/mvicu.c214
5 files changed, 333 insertions, 69 deletions
diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC
index e11bec9fee6..b85e1099412 100644
--- a/sys/arch/arm64/conf/GENERIC
+++ b/sys/arch/arm64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.95 2019/01/23 09:58:08 phessler Exp $
+# $OpenBSD: GENERIC,v 1.96 2019/02/03 14:03:36 patrick Exp $
#
# GENERIC machine description file
#
@@ -143,6 +143,7 @@ hitemp* at fdt?
# Marvell SoCs
mvclock* at fdt? early 1
+mvgicp* at fdt? early 1
mvicu* at fdt? early 1
mvpinctrl* at fdt? early 1
mvgpio* at fdt?
diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK
index 4a02114faa1..201a5f0fcb2 100644
--- a/sys/arch/arm64/conf/RAMDISK
+++ b/sys/arch/arm64/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.80 2019/01/29 22:14:32 patrick Exp $
+# $OpenBSD: RAMDISK,v 1.81 2019/02/03 14:03:36 patrick Exp $
#
# GENERIC machine description file
#
@@ -139,6 +139,7 @@ hireset* at fdt? early 1
# Marvell SoCs
mvclock* at fdt? early 1
+mvgicp* at fdt? early 1
mvicu* at fdt? early 1
mvpinctrl* at fdt? early 1
mvgpio* at fdt?
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt
index be0e2686e94..f90efcdf446 100644
--- a/sys/dev/fdt/files.fdt
+++ b/sys/dev/fdt/files.fdt
@@ -1,4 +1,4 @@
-# $OpenBSD: files.fdt,v 1.76 2019/01/11 08:02:19 patrick Exp $
+# $OpenBSD: files.fdt,v 1.77 2019/02/03 14:03:36 patrick Exp $
#
# Config file and device description for machine-independent FDT code.
# Included by ports that need it.
@@ -190,6 +190,10 @@ device mvclock
attach mvclock at fdt
file dev/fdt/mvclock.c mvclock
+device mvgicp
+attach mvgicp at fdt
+file dev/fdt/mvgicp.c mvgicp
+
device mvgpio
attach mvgpio at fdt
file dev/fdt/mvgpio.c mvgpio
diff --git a/sys/dev/fdt/mvgicp.c b/sys/dev/fdt/mvgicp.c
new file mode 100644
index 00000000000..42bd7f98e70
--- /dev/null
+++ b/sys/dev/fdt/mvgicp.c
@@ -0,0 +1,176 @@
+/* $OpenBSD: mvgicp.c,v 1.1 2019/02/03 14:03:36 patrick Exp $ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_misc.h>
+#include <dev/ofw/fdt.h>
+
+struct mvgicp_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ paddr_t sc_addr;
+
+ uint32_t sc_spi_ranges[4];
+ void **sc_spi;
+ uint32_t sc_nspi;
+
+ struct interrupt_controller sc_ic;
+ struct interrupt_controller *sc_parent_ic;
+};
+
+int mvgicp_match(struct device *, void *, void *);
+void mvgicp_attach(struct device *, struct device *, void *);
+
+void * mvgicp_intr_establish(void *, uint64_t *, uint64_t *,
+ int, int (*)(void *), void *, char *);
+void mvgicp_intr_disestablish(void *);
+
+struct cfattach mvgicp_ca = {
+ sizeof(struct mvgicp_softc), mvgicp_match, mvgicp_attach
+};
+
+struct cfdriver mvgicp_cd = {
+ NULL, "mvgicp", DV_DULL
+};
+
+int
+mvgicp_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "marvell,ap806-gicp");
+}
+
+void
+mvgicp_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mvgicp_softc *sc = (struct mvgicp_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ struct interrupt_controller *ic;
+ uint32_t phandle;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no registers\n");
+ return;
+ }
+
+ OF_getpropintarray(faa->fa_node, "marvell,spi-ranges",
+ sc->sc_spi_ranges, sizeof(sc->sc_spi_ranges));
+ sc->sc_nspi = sc->sc_spi_ranges[1] + sc->sc_spi_ranges[3];
+ sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(void *),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ 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)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ /* 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;
+ }
+
+ extern uint32_t fdt_intr_get_parent(int);
+ phandle = fdt_intr_get_parent(faa->fa_node);
+ extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
+ LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
+ if (ic->ic_phandle == phandle)
+ break;
+ }
+ sc->sc_parent_ic = ic;
+
+ sc->sc_ic.ic_node = faa->fa_node;
+ sc->sc_ic.ic_cookie = sc;
+ sc->sc_ic.ic_establish_msi = mvgicp_intr_establish;
+ sc->sc_ic.ic_disestablish = mvgicp_intr_disestablish;
+ fdt_intr_register(&sc->sc_ic);
+
+ printf("\n");
+}
+
+void *
+mvgicp_intr_establish(void *self, uint64_t *addr, uint64_t *data,
+ int level, int (*func)(void *), void *arg, char *name)
+{
+ struct mvgicp_softc *sc = (struct mvgicp_softc *)self;
+ struct interrupt_controller *ic = sc->sc_parent_ic;
+ uint32_t interrupt[3];
+ uint32_t flags;
+ void *cookie;
+ int i, spi;
+
+ if (ic == NULL)
+ return NULL;
+
+ for (i = 0; i < sc->sc_nspi; i++) {
+ if (sc->sc_spi[i] == NULL) {
+ spi = i;
+ break;
+ }
+ }
+ if (i == sc->sc_nspi)
+ return NULL;
+
+ flags = *data;
+
+ *addr = sc->sc_addr;
+ *data = spi;
+
+ /* Convert to GIC interrupt source. */
+ for (i = 0; i < nitems(sc->sc_spi_ranges); i += 2) {
+ if (spi < sc->sc_spi_ranges[i + 1]) {
+ spi += sc->sc_spi_ranges[i];
+ break;
+ }
+ spi -= sc->sc_spi_ranges[i + 1];
+ }
+ if (i == nitems(sc->sc_spi_ranges))
+ return NULL;
+
+ interrupt[0] = 0;
+ interrupt[1] = spi - 32;
+ interrupt[2] = flags;
+ cookie = ic->ic_establish(ic->ic_cookie, interrupt, level,
+ func, arg, name);
+ if (cookie == NULL)
+ return NULL;
+
+ sc->sc_spi[*data] = cookie;
+ return &sc->sc_spi[*data];
+}
+
+void
+mvgicp_intr_disestablish(void *cookie)
+{
+ fdt_intr_disestablish(*(void **)cookie);
+ *(void **)cookie = NULL;
+}
diff --git a/sys/dev/fdt/mvicu.c b/sys/dev/fdt/mvicu.c
index 46baffb370a..f4b6b3bfb8f 100644
--- a/sys/dev/fdt/mvicu.c
+++ b/sys/dev/fdt/mvicu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mvicu.c,v 1.3 2018/08/06 10:52:30 patrick Exp $ */
+/* $OpenBSD: mvicu.c,v 1.4 2019/02/03 14:03:36 patrick Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -18,6 +18,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/malloc.h>
#include <machine/intr.h>
#include <machine/bus.h>
@@ -31,26 +32,53 @@
#define ICU_SETSPI_NSR_AH 0x14
#define ICU_CLRSPI_NSR_AL 0x18
#define ICU_CLRSPI_NSR_AH 0x1c
+#define ICU_SET_SEI_AL 0x50
+#define ICU_SET_SEI_AH 0x54
+#define ICU_CLR_SEI_AL 0x58
+#define ICU_CLR_SEI_AH 0x5c
#define ICU_INT_CFG(x) (0x100 + (x) * 4)
#define ICU_INT_ENABLE (1 << 24)
#define ICU_INT_EDGE (1 << 28)
#define ICU_INT_GROUP_SHIFT 29
#define ICU_INT_MASK 0x3ff
+#define GICP_SETSPI_NSR 0x00
+#define GICP_CLRSPI_NSR 0x08
+
+/* Devices */
+#define ICU_DEVICE_SATA0 109
+#define ICU_DEVICE_SATA1 107
+#define ICU_DEVICE_NIRQ 207
+
+/* Groups. */
+#define ICU_GRP_NSR 0x0
+#define ICU_GRP_SR 0x1
+#define ICU_GRP_SEI 0x4
+#define ICU_GRP_REI 0x5
+
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+struct mvicu_softc;
+struct mvicu_subnode {
+ struct mvicu_softc *sn_sc;
+ int sn_group;
+ struct interrupt_controller sn_ic;
+ struct interrupt_controller *sn_parent_ic;
+};
+
struct mvicu_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
- uint32_t sc_spi_ranges[4];
+ uint64_t sc_nsr_addr;
+ uint64_t sc_sei_addr;
- struct interrupt_controller sc_ic;
- struct interrupt_controller *sc_parent_ic;
+ int sc_legacy;
+ struct mvicu_subnode *sc_nodes;
};
int mvicu_match(struct device *, void *, void *);
@@ -64,6 +92,7 @@ struct cfdriver mvicu_cd = {
NULL, "mvicu", DV_DULL
};
+void mvicu_register(struct mvicu_softc *, int, int);
void *mvicu_intr_establish(void *, int *, int, int (*)(void *),
void *, char *);
void mvicu_intr_disestablish(void *);
@@ -81,25 +110,13 @@ mvicu_attach(struct device *parent, struct device *self, void *aux)
{
struct mvicu_softc *sc = (struct mvicu_softc *)self;
struct fdt_attach_args *faa = aux;
- struct interrupt_controller *ic;
- bus_addr_t low, high, setspi_addr, clrspi_addr;
- uint32_t phandle;
- int node;
+ int i, node, nchildren;
if (faa->fa_nreg < 1) {
printf(": no registers\n");
return;
}
- phandle = OF_getpropint(faa->fa_node, "msi-parent", 0);
- node = OF_getnodebyphandle(phandle);
- if (node == 0) {
- printf(": GICP not found\n");
- return;
- }
- OF_getpropintarray(node, "marvell,spi-ranges", sc->sc_spi_ranges,
- sizeof(sc->sc_spi_ranges));
-
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)) {
@@ -107,76 +124,141 @@ mvicu_attach(struct device *parent, struct device *self, void *aux)
return;
}
- /*
- * This driver assumes that the ICU has been configured by the
- * firmware. Do some (minimal) checks to verify that has
- * indeed been done.
- */
- low = HREAD4(sc, ICU_SETSPI_NSR_AL);
- high = HREAD4(sc, ICU_SETSPI_NSR_AH);
- setspi_addr = (high << 32) | low;
- low = HREAD4(sc, ICU_CLRSPI_NSR_AL);
- high = HREAD4(sc, ICU_CLRSPI_NSR_AH);
- clrspi_addr = (high << 32) | low;
- if (setspi_addr == 0 || clrspi_addr == 0) {
- printf(": not configured by firmware\n");
- return;
+ printf("\n");
+
+ if (OF_child(faa->fa_node) == 0) {
+ sc->sc_legacy = 1;
+ sc->sc_nodes = mallocarray(1, sizeof(*sc->sc_nodes),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+ mvicu_register(sc, faa->fa_node, 0);
+ } else {
+ for (node = OF_child(faa->fa_node), nchildren = 0;
+ node; node = OF_peer(node))
+ nchildren++;
+ sc->sc_nodes = mallocarray(nchildren, sizeof(*sc->sc_nodes),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+ for (node = OF_child(faa->fa_node), i = 0; node;
+ node = OF_peer(node))
+ mvicu_register(sc, node, i++);
}
+}
- printf("\n");
+void
+mvicu_register(struct mvicu_softc *sc, int node, int idx)
+{
+ struct mvicu_subnode *sn = &sc->sc_nodes[idx];
+ struct interrupt_controller *ic;
+ uint32_t phandle = 0;
+ uint32_t group;
+ int i;
+
+ sn->sn_group = -1;
+ if (OF_is_compatible(node, "marvell,cp110-icu") ||
+ OF_is_compatible(node, "marvell,cp110-icu-nsr"))
+ sn->sn_group = ICU_GRP_NSR;
+ if (OF_is_compatible(node, "marvell,cp110-icu-sei"))
+ sn->sn_group = ICU_GRP_SEI;
+
+ for (i = 0; i < ICU_DEVICE_NIRQ; i++) {
+ group = HREAD4(sc, ICU_INT_CFG(i)) >> ICU_INT_GROUP_SHIFT;
+ if ((sn->sn_group == ICU_GRP_NSR && group == ICU_GRP_NSR) ||
+ (sn->sn_group == ICU_GRP_SEI && group == ICU_GRP_SEI))
+ HWRITE4(sc, ICU_INT_CFG(i), 0);
+ }
+
+ sn->sn_sc = sc;
+ sn->sn_ic.ic_node = node;
+ sn->sn_ic.ic_cookie = sn;
+ sn->sn_ic.ic_establish = mvicu_intr_establish;
+ sn->sn_ic.ic_disestablish = mvicu_intr_disestablish;
+
+ while (node && !phandle) {
+ phandle = OF_getpropint(node, "msi-parent", 0);
+ node = OF_parent(node);
+ }
+ if (phandle == 0)
+ return;
- extern uint32_t fdt_intr_get_parent(int);
- phandle = fdt_intr_get_parent(node);
extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
if (ic->ic_phandle == phandle)
break;
}
- sc->sc_parent_ic = ic;
+ if (ic == NULL)
+ return;
- sc->sc_ic.ic_node = faa->fa_node;
- sc->sc_ic.ic_cookie = sc;
- sc->sc_ic.ic_establish = mvicu_intr_establish;
- sc->sc_ic.ic_disestablish = mvicu_intr_disestablish;
- fdt_intr_register(&sc->sc_ic);
+ sn->sn_parent_ic = ic;
+ fdt_intr_register(&sn->sn_ic);
}
void *
mvicu_intr_establish(void *cookie, int *cell, int level,
int (*func)(void *), void *arg, char *name)
{
- struct mvicu_softc *sc = cookie;
- struct interrupt_controller *ic = sc->sc_parent_ic;
- uint32_t group = cell[0];
- uint32_t idx = cell[1];
- uint32_t interrupt[3];
- uint32_t reg;
- int i;
+ struct mvicu_subnode *sn = cookie;
+ struct mvicu_softc *sc = sn->sn_sc;
+ struct interrupt_controller *ic = sn->sn_parent_ic;
+ uint32_t idx, flags;
+ uint64_t addr, data;
+ int edge = 0;
- if (ic == NULL)
+ if (sc->sc_legacy) {
+ if (cell[0] != ICU_GRP_NSR)
+ return NULL;
+ idx = cell[1];
+ flags = cell[2];
+ edge = ((flags & 0xf) == 0x1);
+ } else if (sn->sn_group == ICU_GRP_NSR) {
+ idx = cell[0];
+ flags = cell[1];
+ edge = ((flags & 0xf) == 0x1);
+ } else if (sn->sn_group == ICU_GRP_SEI) {
+ idx = cell[0];
+ flags = cell[1];
+ edge = 1;
+ } else {
return NULL;
+ }
- reg = HREAD4(sc, ICU_INT_CFG(idx));
- if ((reg & ICU_INT_ENABLE) == 0 ||
- (reg >> ICU_INT_GROUP_SHIFT) != group)
+ data = flags;
+ cookie = ic->ic_establish_msi(ic->ic_cookie, &addr, &data,
+ level, func, arg, name);
+ if (cookie == NULL)
return NULL;
- /* Convert to GIC interrupt source. */
- idx = reg & ICU_INT_MASK;
- for (i = 0; i < nitems(sc->sc_spi_ranges); i += 2) {
- if (idx < sc->sc_spi_ranges[i + 1]) {
- idx += sc->sc_spi_ranges[i];
- break;
- }
- idx -= sc->sc_spi_ranges[i];
+ if (sn->sn_group == ICU_GRP_NSR && !sc->sc_nsr_addr) {
+ sc->sc_nsr_addr = addr;
+ HWRITE4(sc, ICU_SETSPI_NSR_AL,
+ (addr + GICP_SETSPI_NSR) & 0xffffffff);
+ HWRITE4(sc, ICU_SETSPI_NSR_AH,
+ (addr + GICP_SETSPI_NSR) >> 32);
+ HWRITE4(sc, ICU_CLRSPI_NSR_AL,
+ (addr + GICP_CLRSPI_NSR) & 0xffffffff);
+ HWRITE4(sc, ICU_CLRSPI_NSR_AH,
+ (addr + GICP_CLRSPI_NSR) >> 32);
}
- if (i == nitems(sc->sc_spi_ranges))
- return NULL;
- interrupt[0] = 0;
- interrupt[1] = idx - 32;
- interrupt[2] = cell[2];
- return ic->ic_establish(ic->ic_cookie, interrupt, level,
- func, arg, name);
+
+ if (sn->sn_group == ICU_GRP_SEI && !sc->sc_sei_addr) {
+ sc->sc_sei_addr = addr;
+ HWRITE4(sc, ICU_SET_SEI_AL, addr & 0xffffffff);
+ HWRITE4(sc, ICU_SET_SEI_AH, addr >> 32);
+ }
+
+ /* Configure ICU. */
+ HWRITE4(sc, ICU_INT_CFG(idx), data | ICU_INT_ENABLE |
+ (sn->sn_group << ICU_INT_GROUP_SHIFT) | (edge ? ICU_INT_EDGE : 0));
+
+ /* Need to configure interrupt for both SATA ports. */
+ if (idx == ICU_DEVICE_SATA0 || idx == ICU_DEVICE_SATA1) {
+ HWRITE4(sc, ICU_INT_CFG(ICU_DEVICE_SATA0), data |
+ ICU_INT_ENABLE | (sn->sn_group << ICU_INT_GROUP_SHIFT) |
+ (edge ? ICU_INT_EDGE : 0));
+ HWRITE4(sc, ICU_INT_CFG(ICU_DEVICE_SATA1), data |
+ ICU_INT_ENABLE | (sn->sn_group << ICU_INT_GROUP_SHIFT) |
+ (edge ? ICU_INT_EDGE : 0));
+ }
+
+ return cookie;
}
void