-/* $OpenBSD: simplebus.c,v 1.6 2016/07/13 20:42:44 patrick Exp $ */
+/* $OpenBSD: simplebus.c,v 1.7 2016/07/18 11:53:32 patrick Exp $ */
/*
* Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
*
void simplebus_attach(struct device *, struct device *, void *);
void simplebus_attach_node(struct device *, int);
+int simplebus_bs_map(void *, bus_addr_t, bus_size_t, int, bus_space_handle_t *);
struct simplebus_softc {
struct device sc_dev;
bus_dma_tag_t sc_dmat;
int sc_acells;
int sc_scells;
+ int sc_pacells;
+ int sc_pscells;
+ struct bus_space sc_bus;
+ int *sc_ranges;
+ int sc_rangeslen;
};
struct cfattach simplebus_ca = {
fa->fa_acells);
sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
fa->fa_scells);
+ sc->sc_pacells = fa->fa_acells;
+ sc->sc_pscells = fa->fa_scells;
if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
name[sizeof(name) - 1] = 0;
printf("\n");
+ memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
+ sc->sc_bus.bs_cookie = sc;
+ sc->sc_bus.bs_map = simplebus_bs_map;
+
+ sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
+ if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
+ sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
+ sc->sc_rangeslen);
+ }
+
/* Scan the whole tree. */
for (node = OF_child(sc->sc_node);
node != 0;
memset(&fa, 0, sizeof(fa));
fa.fa_name = "";
fa.fa_node = node;
- fa.fa_iot = sc->sc_iot;
+ fa.fa_iot = &sc->sc_bus;
fa.fa_dmat = sc->sc_dmat;
fa.fa_acells = sc->sc_acells;
fa.fa_scells = sc->sc_scells;
free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(uint32_t));
free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
}
+
+/*
+ * Translate memory address if needed.
+ */
+int
+simplebus_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flag, bus_space_handle_t *bshp)
+{
+ struct simplebus_softc *sc = (struct simplebus_softc *)t;
+ uint64_t addr, rfrom, rto, rsize;
+ uint32_t *range;
+ int parent, rlen, rone;
+
+ addr = bpa;
+ parent = OF_parent(sc->sc_node);
+ if (parent == 0)
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+
+ if (sc->sc_rangeslen < 0)
+ return EINVAL;
+ if (sc->sc_rangeslen == 0)
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+
+ rlen = sc->sc_rangeslen / sizeof(uint32_t);
+ rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
+
+ /* For each range. */
+ for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
+ /* Extract from and size, so we can see if we fit. */
+ rfrom = range[0];
+ if (sc->sc_acells == 2)
+ rfrom = (rfrom << 32) + range[1];
+ rsize = range[sc->sc_acells + sc->sc_pacells];
+ if (sc->sc_scells == 2)
+ rsize = (rsize << 32) +
+ range[sc->sc_acells + sc->sc_pacells + 1];
+
+ /* Try next, if we're not in the range. */
+ if (addr < rfrom || (addr + size) > (rfrom + rsize))
+ continue;
+
+ /* All good, extract to address and translate. */
+ rto = range[sc->sc_acells];
+ if (sc->sc_pacells == 2)
+ rto = (rto << 32) + range[sc->sc_acells + 1];
+
+ addr -= rfrom;
+ addr += rto;
+
+ return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
+ }
+
+ return ESRCH;
+}