summaryrefslogtreecommitdiff
path: root/sys/arch/armv7
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2016-10-21 20:11:37 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2016-10-21 20:11:37 +0000
commit08723bcbe96de74eb689b2d6bb3c69bf921031de (patch)
tree3f54aab38f7972a1158e7b9403db949556673af7 /sys/arch/armv7
parentd1ab121382f4a402ef90287a1903078d78295311 (diff)
Implement a driver for Marvell's Mbus bridge. This is the component
that lets e.g. the CPU access a USB controller or the USB controller access the system's RAM. The bridge needs to be configured for the devices before we can access the controller or a controller our memory. Since it otherwise acts like a simplebus, simply attach simplebus once we are finished. "looks good to me" kettenis@
Diffstat (limited to 'sys/arch/armv7')
-rw-r--r--sys/arch/armv7/conf/GENERIC3
-rw-r--r--sys/arch/armv7/conf/RAMDISK3
-rw-r--r--sys/arch/armv7/marvell/files.marvell6
-rw-r--r--sys/arch/armv7/marvell/mvmbus.c358
-rw-r--r--sys/arch/armv7/marvell/mvmbusvar.h29
5 files changed, 396 insertions, 3 deletions
diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC
index c484c0ba99d..4f0a13346e5 100644
--- a/sys/arch/armv7/conf/GENERIC
+++ b/sys/arch/armv7/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.66 2016/10/09 23:46:23 jsg Exp $
+# $OpenBSD: GENERIC,v 1.67 2016/10/21 20:11:36 patrick Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
@@ -138,6 +138,7 @@ usb* at dwctwo?
mvacc* at fdt? early 1
mvagc* at fdt?
mvsysctrl* at fdt?
+mvmbus* at fdt?
crosec* at iic?
wskbd* at crosec? mux 1
diff --git a/sys/arch/armv7/conf/RAMDISK b/sys/arch/armv7/conf/RAMDISK
index 85530fca867..0848c81e238 100644
--- a/sys/arch/armv7/conf/RAMDISK
+++ b/sys/arch/armv7/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.61 2016/10/09 23:46:23 jsg Exp $
+# $OpenBSD: RAMDISK,v 1.62 2016/10/21 20:11:36 patrick Exp $
machine armv7 arm
@@ -136,6 +136,7 @@ usb* at dwctwo?
mvacc* at fdt? early 1
mvagc* at fdt?
mvsysctrl* at fdt?
+mvmbus* at fdt?
crosec* at iic?
wskbd* at crosec? mux 1
diff --git a/sys/arch/armv7/marvell/files.marvell b/sys/arch/armv7/marvell/files.marvell
index ad6754d19d3..b4195a1b642 100644
--- a/sys/arch/armv7/marvell/files.marvell
+++ b/sys/arch/armv7/marvell/files.marvell
@@ -1,4 +1,4 @@
-# $OpenBSD: files.marvell,v 1.3 2016/10/07 19:10:46 patrick Exp $
+# $OpenBSD: files.marvell,v 1.4 2016/10/21 20:11:36 patrick Exp $
device mvacc
attach mvacc at fdt
@@ -11,3 +11,7 @@ file arch/armv7/marvell/mvagc.c mvagc
device mvsysctrl
attach mvsysctrl at fdt
file arch/armv7/marvell/mvsysctrl.c mvsysctrl
+
+device mvmbus: fdt
+attach mvmbus at fdt
+file arch/armv7/marvell/mvmbus.c mvmbus
diff --git a/sys/arch/armv7/marvell/mvmbus.c b/sys/arch/armv7/marvell/mvmbus.c
new file mode 100644
index 00000000000..ebcaed51450
--- /dev/null
+++ b/sys/arch/armv7/marvell/mvmbus.c
@@ -0,0 +1,358 @@
+/* $OpenBSD: mvmbus.c,v 1.1 2016/10/21 20:11:36 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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 <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/simplebus/simplebusvar.h>
+#include <armv7/marvell/mvmbusvar.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#define MVMBUS_XP_WINDOW(i) (((i) < 8) ? i << 4 : 0x90 + (((i) - 8) << 3))
+
+#define MVMBUS_WINDOW_CTRL 0x0000
+#define MVMBUS_WINDOW_CTRL_ENABLE (1 << 0)
+#define MVMBUS_WINDOW_CTRL_TARGET_MASK 0xf0
+#define MVMBUS_WINDOW_CTRL_TARGET_SHIFT 4
+#define MVMBUS_WINDOW_CTRL_ATTR_MASK 0xff00
+#define MVMBUS_WINDOW_CTRL_ATTR_SHIFT 8
+#define MVMBUS_WINDOW_CTRL_SIZE_MASK 0xffff0000
+#define MVMBUS_WINDOW_CTRL_SIZE_SHIFT 16
+#define MVMBUS_WINDOW_BASE 0x0004
+#define MVMBUS_WINDOW_BASE_LOW 0xffff0000
+#define MVMBUS_WINDOW_BASE_HIGH 0xf
+#define MVMBUS_WINDOW_REMAP_LO 0x0008
+#define MVMBUS_WINDOW_REMAP_LO_LOW 0xffff0000
+#define MVMBUS_WINDOW_REMAP_HI 0x000c
+
+#define MVMBUS_SDRAM_BASE(i) (0x0000 + ((i) << 3))
+#define MVMBUS_SDRAM_BASE_HIGH_MASK 0xf
+#define MVMBUS_SDRAM_BASE_LOW_MASK 0xff000000
+#define MVMBUS_SDRAM_SIZE(i) (0x0004 + ((i) << 3))
+#define MVMBUS_SDRAM_SIZE_ENABLED (1 << 0)
+#define MVMBUS_SDRAM_SIZE_MASK 0xff000000
+
+#define MVMBUS_NO_REMAP 0xffffffff
+
+struct mvmbus_softc {
+ struct simplebus_softc sc_sbus;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_mbus_ioh;
+ bus_space_handle_t sc_sdram_ioh;
+ bus_space_handle_t sc_bridge_ioh;
+
+ int sc_num_wins;
+ int sc_num_remappable_wins;
+
+ struct mbus_dram_info sc_dram_info;
+ struct mbus_window {
+ int enabled;
+ paddr_t base;
+ size_t size;
+ uint8_t target;
+ uint8_t attr;
+ } *sc_windows;
+};
+
+int mvmbus_match(struct device *, void *, void *);
+void mvmbus_attach(struct device *, struct device *, void *);
+
+void mvmbus_parse_ranges(struct mvmbus_softc *, struct fdt_attach_args *);
+void mvmbus_alloc_window(struct mvmbus_softc *, paddr_t, size_t, paddr_t,
+ uint8_t, uint8_t);
+void mvmbus_setup_window(struct mvmbus_softc *, int, paddr_t, size_t,
+ paddr_t, uint8_t, uint8_t);
+void mvmbus_disable_window(struct mvmbus_softc *, int);
+int mvmbus_window_conflicts(struct mvmbus_softc *, paddr_t, size_t);
+int mvmbus_window_is_free(struct mvmbus_softc *, int);
+void mvmbus_parse_dram_info(struct mvmbus_softc *);
+
+struct mbus_dram_info *mvmbus_dram_info;
+
+struct cfattach mvmbus_ca = {
+ sizeof (struct mvmbus_softc), mvmbus_match, mvmbus_attach
+};
+
+struct cfdriver mvmbus_cd = {
+ NULL, "mvmbus", DV_DULL
+};
+
+int
+mvmbus_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ if (OF_is_compatible(faa->fa_node, "marvell,armada370-mbus") ||
+ OF_is_compatible(faa->fa_node, "marvell,armada380-mbus") ||
+ OF_is_compatible(faa->fa_node, "marvell,armadaxp-mbus"))
+ return 10;
+
+ return 0;
+}
+
+void
+mvmbus_attach(struct device *parent, struct device *self, void *args)
+{
+ struct mvmbus_softc *sc = (struct mvmbus_softc *)self;
+ struct fdt_attach_args *faa = args;
+ struct fdt_reg reg;
+ void *mbusc;
+ int i;
+
+ sc->sc_iot = faa->fa_iot;
+
+ /* The registers are in the controller itself, find it. */
+ mbusc = fdt_find_phandle(OF_getpropint(faa->fa_node, "controller", 0));
+ if (mbusc == NULL)
+ panic("%s: cannot find mbus controller", __func__);
+
+ if (fdt_get_reg(mbusc, 0, &reg))
+ panic("%s: could not extract memory data from FDT",
+ __func__);
+
+ if (bus_space_map(sc->sc_iot, reg.addr, reg.size, 0, &sc->sc_mbus_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ if (fdt_get_reg(mbusc, 1, &reg))
+ panic("%s: could not extract memory data from FDT",
+ __func__);
+
+ if (bus_space_map(sc->sc_iot, reg.addr, reg.size, 0, &sc->sc_sdram_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ /* Bridge mapping is optional. */
+ if (fdt_get_reg(mbusc, 2, &reg) == 0)
+ if (bus_space_map(sc->sc_iot, reg.addr, reg.size, 0,
+ &sc->sc_bridge_ioh))
+ sc->sc_bridge_ioh = 0;
+
+ /* TODO: pcie properties */
+
+ /* TODO: support more than the armada 370/380/xp */
+ sc->sc_num_wins = 20;
+ sc->sc_num_remappable_wins = 8;
+
+ sc->sc_windows = mallocarray(sc->sc_num_wins, sizeof(*sc->sc_windows),
+ M_DEVBUF, M_ZERO | M_WAITOK);
+
+ for (i = 0; i < sc->sc_num_wins; i++)
+ mvmbus_disable_window(sc, i);
+
+ mvmbus_parse_dram_info(sc);
+ mvmbus_dram_info = &sc->sc_dram_info;
+
+ mvmbus_parse_ranges(sc, faa);
+
+ /* We are simple-bus compatible, so just attach it. */
+ simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
+}
+
+void
+mvmbus_parse_ranges(struct mvmbus_softc *sc, struct fdt_attach_args *faa)
+{
+ int pac, psc, cac, csc, rlen, rone, *range;
+ uint32_t *ranges;
+ int rangeslen;
+
+ rangeslen = OF_getproplen(faa->fa_node, "ranges");
+ if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)))
+ panic("%s: unsupported ranges format",
+ sc->sc_sbus.sc_dev.dv_xname);
+
+ ranges = malloc(rangeslen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(faa->fa_node, "ranges", ranges, rangeslen);
+
+ cac = OF_getpropint(faa->fa_node, "#address-cells",
+ faa->fa_acells);
+ csc = OF_getpropint(faa->fa_node, "#size-cells",
+ faa->fa_scells);
+ pac = faa->fa_acells;
+ psc = faa->fa_scells;
+
+ /* Must have at least one range. */
+ rone = pac + cac + csc;
+ rlen = rangeslen / sizeof(uint32_t);
+ if (rlen < rone)
+ return;
+
+ /* For each range. */
+ for (range = ranges; rlen >= rone; rlen -= rone, range += rone) {
+ uint32_t window = range[0];
+ if (window & 0xf0000000)
+ continue;
+
+ uint32_t size = range[cac + pac];
+ if (csc == 2)
+ size = range[cac + pac + 1];
+
+ /* All good, extract to address and translate. */
+ uint32_t base = range[cac];
+ if (pac == 2)
+ base = range[cac + 1];
+
+ uint8_t target = (window & 0x0f000000) >> 24;
+ uint8_t attr = (window & 0x00ff0000) >> 16;
+
+ mvmbus_alloc_window(sc, base, size, MVMBUS_NO_REMAP,
+ target, attr);
+ }
+}
+
+int
+mvmbus_window_is_free(struct mvmbus_softc *sc, int window)
+{
+ /*
+ * On Armada XP systems, window 13 is a remappable window. For this
+ * window to work we need to configure the remap register. Since we
+ * don't do this yet, make sure we don't use this window.
+ */
+ if (window == 13)
+ return 1;
+ return !sc->sc_windows[window].enabled;
+}
+
+void
+mvmbus_alloc_window(struct mvmbus_softc *sc, paddr_t base, size_t size,
+ paddr_t remap, uint8_t target, uint8_t attr)
+{
+ int win;
+
+ if (mvmbus_window_conflicts(sc, base, size)) {
+ printf("%s: window conflicts with another window\n",
+ sc->sc_sbus.sc_dev.dv_xname);
+ return;
+ }
+
+ /* If no remap is wanted, use unremappable windows. */
+ if (remap == MVMBUS_NO_REMAP)
+ for (win = sc->sc_num_remappable_wins;
+ win < sc->sc_num_wins; win++)
+ if (mvmbus_window_is_free(sc, win))
+ return mvmbus_setup_window(sc, win, base, size,
+ remap, target, attr);
+
+ for (win = 0; win < sc->sc_num_wins; win++)
+ if (mvmbus_window_is_free(sc, win))
+ return mvmbus_setup_window(sc, win, base, size,
+ remap, target, attr);
+
+ printf("%s: no free window available\n",
+ sc->sc_sbus.sc_dev.dv_xname);
+}
+
+void
+mvmbus_setup_window(struct mvmbus_softc *sc, int window, paddr_t base,
+ size_t size, paddr_t remap, uint8_t target, uint8_t attr)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_BASE,
+ base & MVMBUS_WINDOW_BASE_LOW);
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_CTRL,
+ ((size - 1) & MVMBUS_WINDOW_CTRL_SIZE_MASK) |
+ attr << MVMBUS_WINDOW_CTRL_ATTR_SHIFT |
+ target << MVMBUS_WINDOW_CTRL_TARGET_SHIFT |
+ MVMBUS_WINDOW_CTRL_ENABLE);
+
+ if (window < sc->sc_num_remappable_wins) {
+ if (remap == MVMBUS_NO_REMAP)
+ remap = base;
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_REMAP_LO,
+ remap & MVMBUS_WINDOW_REMAP_LO_LOW);
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_REMAP_HI, 0);
+ }
+
+ sc->sc_windows[window].enabled = 1;
+ sc->sc_windows[window].base = base;
+ sc->sc_windows[window].size = size;
+ sc->sc_windows[window].target = target;
+ sc->sc_windows[window].attr = attr;
+}
+
+void
+mvmbus_disable_window(struct mvmbus_softc *sc, int window)
+{
+ int i;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_BASE, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_CTRL, 0);
+
+ for (i = 0; i < sc->sc_num_remappable_wins; i++) {
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_REMAP_LO, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_mbus_ioh,
+ MVMBUS_XP_WINDOW(window) + MVMBUS_WINDOW_REMAP_HI, 0);
+ }
+
+ sc->sc_windows[window].enabled = 0;
+}
+
+int
+mvmbus_window_conflicts(struct mvmbus_softc *sc, paddr_t base, size_t size)
+{
+ int i;
+
+ for (i = 0; i < sc->sc_num_wins; i++) {
+ if (!sc->sc_windows[i].enabled)
+ continue;
+
+ if (base < (sc->sc_windows[i].base + sc->sc_windows[i].size) &&
+ (base + size) > sc->sc_windows[i].base)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+mvmbus_parse_dram_info(struct mvmbus_softc *sc)
+{
+ int i, cs = 0;
+
+ sc->sc_dram_info.targetid = 0; /* DDR */
+
+ for (i = 0; i < 4; i++) {
+ uint32_t base = bus_space_read_4(sc->sc_iot, sc->sc_sdram_ioh,
+ MVMBUS_SDRAM_BASE(i));
+ uint32_t size = bus_space_read_4(sc->sc_iot, sc->sc_sdram_ioh,
+ MVMBUS_SDRAM_SIZE(i));
+
+ if (!(size & MVMBUS_SDRAM_SIZE_ENABLED))
+ continue;
+
+ if (base & MVMBUS_SDRAM_BASE_HIGH_MASK)
+ continue;
+
+ struct mbus_dram_window *win = &sc->sc_dram_info.cs[cs++];
+ win->index = i;
+ win->attr = 0xf & ~(1 << i); /* XXX: coherency? */
+ win->base = base & MVMBUS_SDRAM_BASE_LOW_MASK;
+ win->size = (size | MVMBUS_SDRAM_SIZE_MASK) + 1;
+ }
+
+ sc->sc_dram_info.numcs = cs;
+}
diff --git a/sys/arch/armv7/marvell/mvmbusvar.h b/sys/arch/armv7/marvell/mvmbusvar.h
new file mode 100644
index 00000000000..59eb1f696c1
--- /dev/null
+++ b/sys/arch/armv7/marvell/mvmbusvar.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: mvmbusvar.h,v 1.1 2016/10/21 20:11:36 patrick Exp $ */
+/*
+ * Copyright (c) 2016 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.
+ */
+
+struct mbus_dram_info {
+ uint8_t targetid;
+ int numcs;
+ struct mbus_dram_window {
+ uint8_t index;
+ uint8_t attr;
+ uint32_t base;
+ uint32_t size;
+ } cs[4];
+};
+
+extern struct mbus_dram_info *mvmbus_dram_info;