[PATCH rtems-libbsd 02/14] mpc85xx: Import from FreeBSD
Christian Mauderer
christian.mauderer at embedded-brains.de
Tue Jan 23 09:09:03 UTC 2024
From: Sebastian Huber <sebastian.huber at embedded-brains.de>
---
freebsd/sys/dev/ofw/ofwpci.c | 677 +++++++++++++
freebsd/sys/dev/ofw/ofwpci.h | 87 ++
freebsd/sys/dev/pci/pci_subr.c | 388 +++++++
freebsd/sys/powerpc/include/machine/hid.h | 224 ++++
freebsd/sys/powerpc/include/machine/pio.h | 306 ++++++
.../sys/powerpc/include/machine/platformvar.h | 91 ++
freebsd/sys/powerpc/mpc85xx/mpc85xx.c | 361 +++++++
freebsd/sys/powerpc/mpc85xx/mpc85xx.h | 177 ++++
freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c | 959 ++++++++++++++++++
.../sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c | 111 ++
.../sys/powerpc/mpc85xx/platform_mpc85xx.c | 710 +++++++++++++
freebsd/sys/powerpc/ofw/ofw_pcib_pci.c | 178 ++++
12 files changed, 4269 insertions(+)
create mode 100644 freebsd/sys/dev/ofw/ofwpci.c
create mode 100644 freebsd/sys/dev/ofw/ofwpci.h
create mode 100644 freebsd/sys/dev/pci/pci_subr.c
create mode 100644 freebsd/sys/powerpc/include/machine/hid.h
create mode 100644 freebsd/sys/powerpc/include/machine/pio.h
create mode 100644 freebsd/sys/powerpc/include/machine/platformvar.h
create mode 100644 freebsd/sys/powerpc/mpc85xx/mpc85xx.c
create mode 100644 freebsd/sys/powerpc/mpc85xx/mpc85xx.h
create mode 100644 freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c
create mode 100644 freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c
create mode 100644 freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c
create mode 100644 freebsd/sys/powerpc/ofw/ofw_pcib_pci.c
diff --git a/freebsd/sys/dev/ofw/ofwpci.c b/freebsd/sys/dev/ofw/ofwpci.c
new file mode 100644
index 00000000..d576cb67
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofwpci.c
@@ -0,0 +1,677 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <rtems/bsd/local/pcib_if.h>
+
+/*
+ * If it is necessary to set another value of this for
+ * some platforms it should be set at fdt.h file
+ */
+#ifndef PCI_MAP_INTR
+#define PCI_MAP_INTR 4
+#endif
+
+#define PCI_INTR_PINS 4
+
+/*
+ * bus interface.
+ */
+static struct resource * ofw_pci_alloc_resource(device_t, device_t,
+ int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
+static int ofw_pci_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_adjust_resource(device_t, device_t, int,
+ struct resource *, rman_res_t, rman_res_t);
+
+#ifdef __powerpc__
+static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
+#endif
+
+/*
+ * pcib interface
+ */
+static int ofw_pci_maxslots(device_t);
+
+/*
+ * ofw_bus interface
+ */
+static phandle_t ofw_pci_get_node(device_t, device_t);
+
+/*
+ * local methods
+ */
+static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
+static struct rman *ofw_pci_get_rman(struct ofw_pci_softc *, int, u_int);
+
+/*
+ * Driver methods.
+ */
+static device_method_t ofw_pci_methods[] = {
+
+ /* Device interface */
+ DEVMETHOD(device_attach, ofw_pci_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ofw_pci_write_ivar),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, ofw_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ofw_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, ofw_pci_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
+#ifdef __powerpc__
+ DEVMETHOD(bus_get_bus_tag, ofw_pci_bus_get_bus_tag),
+#endif
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, ofw_pci_maxslots),
+ DEVMETHOD(pcib_route_interrupt, ofw_pci_route_interrupt),
+ DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
+
+int
+ofw_pci_init(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ phandle_t node;
+ u_int32_t busrange[2];
+ struct ofw_pci_range *rp;
+ int i, error;
+ struct ofw_pci_cell_info *cell_info;
+
+ node = ofw_bus_get_node(dev);
+ sc = device_get_softc(dev);
+ sc->sc_initialized = 1;
+ sc->sc_range = NULL;
+ sc->sc_pci_domain = device_get_unit(dev);
+
+ cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ sc->sc_cell_info = cell_info;
+
+ if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
+ busrange[0] = 0;
+
+ sc->sc_dev = dev;
+ sc->sc_node = node;
+ sc->sc_bus = busrange[0];
+
+ if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
+ phandle_t c;
+ int n, i;
+
+ sc->sc_nrange = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_nranges(c, cell_info);
+ if (n > 0)
+ sc->sc_nrange += n;
+ }
+ if (sc->sc_nrange == 0) {
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ i = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
+ if (n > 0)
+ i += n;
+ }
+ KASSERT(i == sc->sc_nrange, ("range count mismatch"));
+ } else {
+ sc->sc_nrange = ofw_pci_nranges(node, cell_info);
+ if (sc->sc_nrange <= 0) {
+ device_printf(dev, "could not getranges\n");
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ ofw_pci_fill_ranges(node, sc->sc_range);
+ }
+
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "PCI I/O Ports";
+ error = rman_init(&sc->sc_io_rman);
+ if (error != 0) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory";
+ error = rman_init(&sc->sc_mem_rman);
+ if (error != 0) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ sc->sc_pmem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory";
+ error = rman_init(&sc->sc_pmem_rman);
+ if (error != 0) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ for (i = 0; i < sc->sc_nrange; i++) {
+ error = 0;
+ rp = sc->sc_range + i;
+
+ if (sc->sc_range_mask & ((uint64_t)1 << i))
+ continue;
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_CONFIG:
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ error = rman_manage_region(&sc->sc_io_rman, rp->pci,
+ rp->pci + rp->size - 1);
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
+ sc->sc_have_pmem = 1;
+ error = rman_manage_region(&sc->sc_pmem_rman,
+ rp->pci, rp->pci + rp->size - 1);
+ } else {
+ error = rman_manage_region(&sc->sc_mem_rman,
+ rp->pci, rp->pci + rp->size - 1);
+ }
+ break;
+ }
+
+ if (error != 0) {
+ device_printf(dev,
+ "rman_manage_region(%x, %#jx, %#jx) failed. "
+ "error = %d\n", rp->pci_hi &
+ OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
+ rp->pci + rp->size - 1, error);
+ goto out;
+ }
+ }
+
+ ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
+ return (0);
+
+out:
+ free(cell_info, M_DEVBUF);
+ free(sc->sc_range, M_DEVBUF);
+ rman_fini(&sc->sc_io_rman);
+ rman_fini(&sc->sc_mem_rman);
+ rman_fini(&sc->sc_pmem_rman);
+
+ return (error);
+}
+
+int
+ofw_pci_attach(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ if (!sc->sc_initialized) {
+ error = ofw_pci_init(dev);
+ if (error != 0)
+ return (error);
+ }
+
+ device_add_child(dev, "pci", -1);
+ return (bus_generic_attach(dev));
+}
+
+static int
+ofw_pci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+int
+ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
+{
+ struct ofw_pci_softc *sc;
+ struct ofw_pci_register reg;
+ uint32_t pintr, mintr[PCI_MAP_INTR];
+ int intrcells;
+ phandle_t iparent;
+
+ sc = device_get_softc(bus);
+ pintr = pin;
+
+ /* Fabricate imap information in case this isn't an OFW device */
+ bzero(®, sizeof(reg));
+ reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
+ (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
+ (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
+
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
+ &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr),
+ mintr, sizeof(mintr), &iparent);
+ if (intrcells != 0) {
+ pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
+ return (pintr);
+ }
+
+ /*
+ * Maybe it's a real interrupt, not an intpin
+ */
+ if (pin > PCI_INTR_PINS)
+ return (pin);
+
+ device_printf(bus, "could not route pin %d for device %d.%d\n",
+ pin, pci_get_slot(dev), pci_get_function(dev));
+ return (PCI_INVALID_IRQ);
+}
+
+int
+ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = sc->sc_pci_domain;
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_bus;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_bus = value;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
+{
+ ssize_t nbase_ranges;
+
+ if (info == NULL)
+ return (-1);
+
+ info->host_address_cells = 1;
+ info->size_cells = 2;
+ info->pci_address_cell = 3;
+
+ OF_getencprop(OF_parent(node), "#address-cells",
+ &(info->host_address_cells), sizeof(info->host_address_cells));
+ OF_getencprop(node, "#address-cells",
+ &(info->pci_address_cell), sizeof(info->pci_address_cell));
+ OF_getencprop(node, "#size-cells", &(info->size_cells),
+ sizeof(info->size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+
+ return (nbase_ranges / sizeof(cell_t) /
+ (info->pci_address_cell + info->host_address_cells +
+ info->size_cells));
+}
+
+static struct resource *
+ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct ofw_pci_softc *sc;
+ struct resource *rv;
+ struct rman *rm;
+ int needactivate;
+
+
+ needactivate = flags & RF_ACTIVE;
+ flags &= ~RF_ACTIVE;
+
+ sc = device_get_softc(bus);
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS) {
+ return (pci_domain_alloc_bus(sc->sc_pci_domain, child, rid,
+ start, end, count, flags | needactivate));
+ }
+#endif
+
+ rm = ofw_pci_get_rman(sc, type, flags);
+ if (rm == NULL) {
+ return (bus_generic_alloc_resource(bus, child, type, rid,
+ start, end, count, flags | needactivate));
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL) {
+ device_printf(bus, "failed to reserve resource for %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv) != 0) {
+ device_printf(bus,
+ "failed to activate resource for %s\n",
+ device_get_nameunit(child));
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct ofw_pci_softc *sc;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(bus);
+
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS)
+ return (pci_domain_release_bus(sc->sc_pci_domain, child, rid,
+ res));
+#endif
+
+ rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
+ if (rm == NULL) {
+ return (bus_generic_release_resource(bus, child, type, rid,
+ res));
+ }
+ KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
+
+ if (rman_get_flags(res) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type, rid, res);
+ if (error != 0)
+ return (error);
+ }
+ return (rman_release_resource(res));
+}
+
+static int
+ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct ofw_pci_softc *sc;
+ bus_space_handle_t handle;
+ bus_space_tag_t tag;
+ struct ofw_pci_range *rp;
+ vm_paddr_t start;
+ int space;
+ int rv;
+
+ sc = device_get_softc(bus);
+
+ if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
+ return (bus_generic_activate_resource(bus, child, type, rid,
+ res));
+ }
+
+ start = (vm_paddr_t)rman_get_start(res);
+
+ /*
+ * Map this through the ranges list
+ */
+ for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
+ rp->pci_hi != 0; rp++) {
+ if (start < rp->pci || start >= rp->pci + rp->size)
+ continue;
+
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ space = SYS_RES_IOPORT;
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ space = SYS_RES_MEMORY;
+ break;
+ default:
+ space = -1;
+ }
+
+ if (type == space) {
+ start += (rp->host - rp->pci);
+ break;
+ }
+ }
+
+ if (bootverbose)
+ printf("ofw_pci mapdev: start %jx, len %jd\n",
+ (rman_res_t)start, rman_get_size(res));
+
+ tag = BUS_GET_BUS_TAG(child, child);
+ if (tag == NULL)
+ return (ENOMEM);
+
+ rman_set_bustag(res, tag);
+ rv = bus_space_map(tag, start,
+ rman_get_size(res), 0, &handle);
+ if (rv != 0)
+ return (ENOMEM);
+
+ rman_set_bushandle(res, handle);
+ rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
+
+ return (rman_activate_resource(res));
+}
+
+#ifdef __powerpc__
+static bus_space_tag_t
+ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
+{
+
+ return (&bs_le_tag);
+}
+#endif
+
+static int
+ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+ vm_size_t psize;
+
+ if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
+ return (bus_generic_deactivate_resource(bus, child, type, rid,
+ res));
+ }
+
+ psize = rman_get_size(res);
+ pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
+
+ return (rman_deactivate_resource(res));
+}
+
+static int
+ofw_pci_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *res, rman_res_t start, rman_res_t end)
+{
+ struct rman *rm;
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+#if defined(NEW_PCIB) && defined(PCI_RES_BUS)
+ if (type == PCI_RES_BUS)
+ return (pci_domain_adjust_bus(sc->sc_pci_domain, child, res,
+ start, end));
+#endif
+
+ rm = ofw_pci_get_rman(sc, type, rman_get_flags(res));
+ if (rm == NULL) {
+ return (bus_generic_adjust_resource(bus, child, type, res,
+ start, end));
+ }
+ KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
+ KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
+ ("active resources cannot be adjusted"));
+
+ return (rman_adjust_resource(res, start, end));
+}
+
+static phandle_t
+ofw_pci_get_node(device_t bus, device_t dev)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+ /* We only have one child, the PCI bus, which needs our own node. */
+
+ return (sc->sc_node);
+}
+
+static int
+ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
+{
+ int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int nranges;
+ int i, j, k;
+
+ OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
+ sizeof(host_address_cells));
+ OF_getencprop(node, "#address-cells", &pci_address_cells,
+ sizeof(pci_address_cells));
+ OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+ nranges = nbase_ranges / sizeof(cell_t) /
+ (pci_address_cells + host_address_cells + size_cells);
+
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < nranges; i++) {
+ ranges[i].pci_hi = base_ranges[j++];
+ ranges[i].pci = 0;
+ for (k = 0; k < pci_address_cells - 1; k++) {
+ ranges[i].pci <<= 32;
+ ranges[i].pci |= base_ranges[j++];
+ }
+ ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ ranges[i].host <<= 32;
+ ranges[i].host |= base_ranges[j++];
+ }
+ ranges[i].size = 0;
+ for (k = 0; k < size_cells; k++) {
+ ranges[i].size <<= 32;
+ ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (nranges);
+}
+
+static struct rman *
+ofw_pci_get_rman(struct ofw_pci_softc *sc, int type, u_int flags)
+{
+
+ switch (type) {
+ case SYS_RES_IOPORT:
+ return (&sc->sc_io_rman);
+ case SYS_RES_MEMORY:
+ if (sc->sc_have_pmem && (flags & RF_PREFETCHABLE))
+ return (&sc->sc_pmem_rman);
+ else
+ return (&sc->sc_mem_rman);
+ default:
+ break;
+ }
+
+ return (NULL);
+}
diff --git a/freebsd/sys/dev/ofw/ofwpci.h b/freebsd/sys/dev/ofw/ofwpci.h
new file mode 100644
index 00000000..3257fe68
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofwpci.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_OFW_OFWPCI_H_
+#define _DEV_OFW_OFWPCI_H_
+
+/*
+ * Export class definition for inheritance purposes
+ */
+DECLARE_CLASS(ofw_pci_driver);
+
+struct ofw_pci_cell_info {
+ pcell_t host_address_cells;
+ pcell_t pci_address_cell;
+ pcell_t size_cells;
+ };
+
+struct ofw_pci_range {
+ uint32_t pci_hi;
+ uint64_t pci;
+ uint64_t host;
+ uint64_t size;
+};
+
+/*
+ * Quirks for some adapters
+ */
+enum {
+ OFW_PCI_QUIRK_RANGES_ON_CHILDREN = 1,
+};
+
+struct ofw_pci_softc {
+ device_t sc_dev;
+ phandle_t sc_node;
+ int sc_bus;
+ int sc_initialized;
+ int sc_quirks;
+ int sc_have_pmem;
+
+ struct ofw_pci_range *sc_range;
+ int sc_nrange;
+ uint64_t sc_range_mask;
+ struct ofw_pci_cell_info *sc_cell_info;
+
+ struct rman sc_io_rman;
+ struct rman sc_mem_rman;
+ struct rman sc_pmem_rman;
+ bus_space_tag_t sc_memt;
+ bus_dma_tag_t sc_dmat;
+ int sc_pci_domain;
+
+ struct ofw_bus_iinfo sc_pci_iinfo;
+};
+
+int ofw_pci_init(device_t);
+int ofw_pci_attach(device_t);
+int ofw_pci_read_ivar(device_t, device_t, int, uintptr_t *);
+int ofw_pci_write_ivar(device_t, device_t, int, uintptr_t);
+int ofw_pci_route_interrupt(device_t, device_t, int);
+int ofw_pci_nranges(phandle_t, struct ofw_pci_cell_info *);
+
+#endif /* _DEV_OFW_OFWPCI_H_ */
diff --git a/freebsd/sys/dev/pci/pci_subr.c b/freebsd/sys/dev/pci/pci_subr.c
new file mode 100644
index 00000000..1b0fac29
--- /dev/null
+++ b/freebsd/sys/dev/pci/pci_subr.c
@@ -0,0 +1,388 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2011 Hudson River Trading LLC
+ * Written by: John H. Baldwin <jhb at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Support APIs for Host to PCI bridge drivers and drivers that
+ * provide PCI domains.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/systm.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+
+/*
+ * Try to read the bus number of a host-PCI bridge using appropriate config
+ * registers.
+ */
+int
+host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func,
+ uint8_t *busnum)
+{
+ uint32_t id;
+
+ id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4);
+ if (id == 0xffffffff)
+ return (0);
+
+ switch (id) {
+ case 0x12258086:
+ /* Intel 824?? */
+ /* XXX This is a guess */
+ /* *busnum = read_config(bus, slot, func, 0x41, 1); */
+ *busnum = bus;
+ break;
+ case 0x84c48086:
+ /* Intel 82454KX/GX (Orion) */
+ *busnum = read_config(bus, slot, func, 0x4a, 1);
+ break;
+ case 0x84ca8086:
+ /*
+ * For the 450nx chipset, there is a whole bundle of
+ * things pretending to be host bridges. The MIOC will
+ * be seen first and isn't really a pci bridge (the
+ * actual buses are attached to the PXB's). We need to
+ * read the registers of the MIOC to figure out the
+ * bus numbers for the PXB channels.
+ *
+ * Since the MIOC doesn't have a pci bus attached, we
+ * pretend it wasn't there.
+ */
+ return (0);
+ case 0x84cb8086:
+ switch (slot) {
+ case 0x12:
+ /* Intel 82454NX PXB#0, Bus#A */
+ *busnum = read_config(bus, 0x10, func, 0xd0, 1);
+ break;
+ case 0x13:
+ /* Intel 82454NX PXB#0, Bus#B */
+ *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1;
+ break;
+ case 0x14:
+ /* Intel 82454NX PXB#1, Bus#A */
+ *busnum = read_config(bus, 0x10, func, 0xd3, 1);
+ break;
+ case 0x15:
+ /* Intel 82454NX PXB#1, Bus#B */
+ *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1;
+ break;
+ }
+ break;
+
+ /* ServerWorks -- vendor 0x1166 */
+ case 0x00051166:
+ case 0x00061166:
+ case 0x00081166:
+ case 0x00091166:
+ case 0x00101166:
+ case 0x00111166:
+ case 0x00171166:
+ case 0x01011166:
+ case 0x010f1014:
+ case 0x01101166:
+ case 0x02011166:
+ case 0x02251166:
+ case 0x03021014:
+ *busnum = read_config(bus, slot, func, 0x44, 1);
+ break;
+
+ /* Compaq/HP -- vendor 0x0e11 */
+ case 0x60100e11:
+ *busnum = read_config(bus, slot, func, 0xc8, 1);
+ break;
+ default:
+ /* Don't know how to read bus number. */
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef NEW_PCIB
+/*
+ * Return a pointer to a pretty name for a PCI device. If the device
+ * has a driver attached, the device's name is used, otherwise a name
+ * is generated from the device's PCI address.
+ */
+const char *
+pcib_child_name(device_t child)
+{
+ static char buf[64];
+
+ if (device_get_nameunit(child) != NULL)
+ return (device_get_nameunit(child));
+ snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child),
+ pci_get_bus(child), pci_get_slot(child), pci_get_function(child));
+ return (buf);
+}
+
+/*
+ * Some Host-PCI bridge drivers know which resource ranges they can
+ * decode and should only allocate subranges to child PCI devices.
+ * This API provides a way to manage this. The bridge driver should
+ * initialize this structure during attach and call
+ * pcib_host_res_decodes() on each resource range it decodes. It can
+ * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper
+ * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This
+ * API assumes that resources for any decoded ranges can be safely
+ * allocated from the parent via bus_generic_alloc_resource().
+ */
+int
+pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr)
+{
+
+ hr->hr_pcib = pcib;
+ resource_list_init(&hr->hr_rl);
+ return (0);
+}
+
+int
+pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr)
+{
+
+ resource_list_free(&hr->hr_rl);
+ return (0);
+}
+
+int
+pcib_host_res_decodes(struct pcib_host_resources *hr, int type, rman_res_t start,
+ rman_res_t end, u_int flags)
+{
+ struct resource_list_entry *rle;
+ int rid;
+
+ if (bootverbose)
+ device_printf(hr->hr_pcib, "decoding %d %srange %#jx-%#jx\n",
+ type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
+ end);
+ rid = resource_list_add_next(&hr->hr_rl, type, start, end,
+ end - start + 1);
+ if (flags & RF_PREFETCHABLE) {
+ KASSERT(type == SYS_RES_MEMORY,
+ ("only memory is prefetchable"));
+ rle = resource_list_find(&hr->hr_rl, type, rid);
+ rle->flags = RLE_PREFETCH;
+ }
+ return (0);
+}
+
+struct resource *
+pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type,
+ int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct resource_list_entry *rle;
+ struct resource *r;
+ rman_res_t new_start, new_end;
+
+ if (flags & RF_PREFETCHABLE)
+ KASSERT(type == SYS_RES_MEMORY,
+ ("only memory is prefetchable"));
+
+ rle = resource_list_find(&hr->hr_rl, type, 0);
+ if (rle == NULL) {
+ /*
+ * No decoding ranges for this resource type, just pass
+ * the request up to the parent.
+ */
+ return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
+ start, end, count, flags));
+ }
+
+restart:
+ /* Try to allocate from each decoded range. */
+ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
+ if (rle->type != type)
+ continue;
+ if (((flags & RF_PREFETCHABLE) != 0) !=
+ ((rle->flags & RLE_PREFETCH) != 0))
+ continue;
+ new_start = ummax(start, rle->start);
+ new_end = ummin(end, rle->end);
+ if (new_start > new_end ||
+ new_start + count - 1 > new_end ||
+ new_start + count < new_start)
+ continue;
+ r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid,
+ new_start, new_end, count, flags);
+ if (r != NULL) {
+ if (bootverbose)
+ device_printf(hr->hr_pcib,
+ "allocated type %d (%#jx-%#jx) for rid %x of %s\n",
+ type, rman_get_start(r), rman_get_end(r),
+ *rid, pcib_child_name(dev));
+ return (r);
+ }
+ }
+
+ /*
+ * If we failed to find a prefetch range for a memory
+ * resource, try again without prefetch.
+ */
+ if (flags & RF_PREFETCHABLE) {
+ flags &= ~RF_PREFETCHABLE;
+ rle = resource_list_find(&hr->hr_rl, type, 0);
+ goto restart;
+ }
+ return (NULL);
+}
+
+int
+pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type,
+ struct resource *r, rman_res_t start, rman_res_t end)
+{
+ struct resource_list_entry *rle;
+
+ rle = resource_list_find(&hr->hr_rl, type, 0);
+ if (rle == NULL) {
+ /*
+ * No decoding ranges for this resource type, just pass
+ * the request up to the parent.
+ */
+ return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r,
+ start, end));
+ }
+
+ /* Only allow adjustments that stay within a decoded range. */
+ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) {
+ if (rle->start <= start && rle->end >= end)
+ return (bus_generic_adjust_resource(hr->hr_pcib, dev,
+ type, r, start, end));
+ }
+ return (ERANGE);
+}
+
+#ifdef PCI_RES_BUS
+struct pci_domain {
+ int pd_domain;
+ struct rman pd_bus_rman;
+ TAILQ_ENTRY(pci_domain) pd_link;
+};
+
+static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains);
+
+/*
+ * Each PCI domain maintains its own resource manager for PCI bus
+ * numbers in that domain. Domain objects are created on first use.
+ * Host to PCI bridge drivers and PCI-PCI bridge drivers should
+ * allocate their bus ranges from their domain.
+ */
+static struct pci_domain *
+pci_find_domain(int domain)
+{
+ struct pci_domain *d;
+ char buf[64];
+ int error;
+
+ TAILQ_FOREACH(d, &domains, pd_link) {
+ if (d->pd_domain == domain)
+ return (d);
+ }
+
+ snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain);
+ d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO);
+ d->pd_domain = domain;
+ d->pd_bus_rman.rm_start = 0;
+ d->pd_bus_rman.rm_end = PCI_BUSMAX;
+ d->pd_bus_rman.rm_type = RMAN_ARRAY;
+ strcpy((char *)(d + 1), buf);
+ d->pd_bus_rman.rm_descr = (char *)(d + 1);
+ error = rman_init(&d->pd_bus_rman);
+ if (error == 0)
+ error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX);
+ if (error)
+ panic("Failed to initialize PCI domain %d rman", domain);
+ TAILQ_INSERT_TAIL(&domains, d, pd_link);
+ return (d);
+}
+
+struct resource *
+pci_domain_alloc_bus(int domain, device_t dev, int *rid, rman_res_t start,
+ rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct pci_domain *d;
+ struct resource *res;
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (NULL);
+ d = pci_find_domain(domain);
+ res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags,
+ dev);
+ if (res == NULL)
+ return (NULL);
+
+ rman_set_rid(res, *rid);
+ return (res);
+}
+
+int
+pci_domain_adjust_bus(int domain, device_t dev, struct resource *r,
+ rman_res_t start, rman_res_t end)
+{
+#ifdef INVARIANTS
+ struct pci_domain *d;
+#endif
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (EINVAL);
+#ifdef INVARIANTS
+ d = pci_find_domain(domain);
+ KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+ return (rman_adjust_resource(r, start, end));
+}
+
+int
+pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r)
+{
+#ifdef INVARIANTS
+ struct pci_domain *d;
+#endif
+
+ if (domain < 0 || domain > PCI_DOMAINMAX)
+ return (EINVAL);
+#ifdef INVARIANTS
+ d = pci_find_domain(domain);
+ KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource"));
+#endif
+ return (rman_release_resource(r));
+}
+#endif /* PCI_RES_BUS */
+
+#endif /* NEW_PCIB */
diff --git a/freebsd/sys/powerpc/include/machine/hid.h b/freebsd/sys/powerpc/include/machine/hid.h
new file mode 100644
index 00000000..1b038111
--- /dev/null
+++ b/freebsd/sys/powerpc/include/machine/hid.h
@@ -0,0 +1,224 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $NetBSD: hid.h,v 1.2 2001/08/22 21:05:25 matt Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _POWERPC_HID_H_
+#define _POWERPC_HID_H_
+
+/* Hardware Implementation Dependent registers for the PowerPC */
+#define HID0_RADIX 0x0080000000000000 /* Enable Radix page tables (POWER9) */
+
+#define HID0_EMCP 0x80000000 /* Enable machine check pin */
+#define HID0_DBP 0x40000000 /* Disable 60x bus parity generation */
+#define HID0_EBA 0x20000000 /* Enable 60x bus address parity checking */
+#define HID0_EBD 0x10000000 /* Enable 60x bus data parity checking */
+#define HID0_BCLK 0x08000000 /* CLK_OUT clock type selection */
+#define HID0_EICE 0x04000000 /* Enable ICE output */
+#define HID0_ECLK 0x02000000 /* CLK_OUT clock type selection */
+#define HID0_PAR 0x01000000 /* Disable precharge of ARTRY */
+#define HID0_STEN 0x01000000 /* Software table search enable (7450) */
+#define HID0_DEEPNAP 0x01000000 /* Enable deep nap mode (970) */
+#define HID0_HBATEN 0x00800000 /* High BAT enable (74[45][578]) */
+#define HID0_DOZE 0x00800000 /* Enable doze mode */
+#define HID0_NAP 0x00400000 /* Enable nap mode */
+#define HID0_SLEEP 0x00200000 /* Enable sleep mode */
+#define HID0_DPM 0x00100000 /* Enable Dynamic power management */
+#define HID0_RISEG 0x00080000 /* Read I-SEG */
+#define HID0_TG 0x00040000 /* Timebase Granularity (OEA64) */
+#define HID0_BHTCLR 0x00040000 /* Clear branch history table (7450) */
+#define HID0_EIEC 0x00040000 /* Enable internal error checking */
+#define HID0_XAEN 0x00020000 /* Enable eXtended Addressing (7450) */
+#define HID0_NHR 0x00010000 /* Not hard reset */
+#define HID0_ICE 0x00008000 /* Enable i-cache */
+#define HID0_DCE 0x00004000 /* Enable d-cache */
+#define HID0_ILOCK 0x00002000 /* i-cache lock */
+#define HID0_DLOCK 0x00001000 /* d-cache lock */
+#define HID0_ICFI 0x00000800 /* i-cache flush invalidate */
+#define HID0_DCFI 0x00000400 /* d-cache flush invalidate */
+#define HID0_SPD 0x00000200 /* Disable speculative cache access */
+#define HID0_XBSEN 0x00000100 /* Extended BAT block-size enable (7457) */
+#define HID0_IFEM 0x00000100 /* Enable M-bit for I-fetch */
+#define HID0_XBSEN 0x00000100 /* Extended BAT block size enable (7455+)*/
+#define HID0_SGE 0x00000080 /* Enable store gathering */
+#define HID0_DCFA 0x00000040 /* Data cache flush assist */
+#define HID0_BTIC 0x00000020 /* Enable BTIC */
+#define HID0_LRSTK 0x00000010 /* Link register stack enable (7450) */
+#define HID0_ABE 0x00000008 /* Enable address broadcast */
+#define HID0_FOLD 0x00000008 /* Branch folding enable (7450) */
+#define HID0_BHT 0x00000004 /* Enable branch history table */
+#define HID0_NOPTI 0x00000001 /* No-op the dcbt(st) */
+
+#define HID0_AIM_TBEN 0x04000000 /* Time base enable (7450) */
+
+#define HID0_E500_TBEN 0x00004000 /* Time Base and decr. enable */
+#define HID0_E500_SEL_TBCLK 0x00002000 /* Select Time Base clock */
+#define HID0_E500_MAS7UPDEN 0x00000080 /* Enable MAS7 update (e500v2) */
+
+#define HID0_E500MC_L2MMU_MHD 0x40000000 /* L2MMU Multiple Hit Detection */
+
+#define HID0_BITMASK \
+ "\20" \
+ "\040EMCP\037DBP\036EBA\035EBD\034BCLK\033EICE\032ECLK\031PAR" \
+ "\030DOZE\027NAP\026SLEEP\025DPM\024RISEG\023EIEC\022res\021NHR" \
+ "\020ICE\017DCE\016ILOCK\015DLOCK\014ICFI\013DCFI\012SPD\011IFEM" \
+ "\010SGE\007DCFA\006BTIC\005FBIOB\004ABE\003BHT\002NOPDST\001NOPTI"
+
+#define HID0_7450_BITMASK \
+ "\20" \
+ "\040EMCP\037b1\036b2\035b3\034b4\033TBEN\032b6\031STEN" \
+ "\030HBATEN\027NAP\026SLEEP\025DPM\024b12\023BHTCLR\022XAEN\021NHR" \
+ "\020ICE\017DCE\016ILOCK\015DLOCK\014ICFI\013DCFI\012SPD\011XBSEN" \
+ "\010SGE\007b25\006BTIC\005LRSTK\004FOLD\003BHT\002NOPDST\001NOPTI"
+
+#define HID0_E500_BITMASK \
+ "\20" \
+ "\040EMCP\037b1\036b2\035b3\034b4\033b5\032b6\031b7" \
+ "\030DOZE\027NAP\026SLEEP\025b11\024b12\023b13\022b14\021b15" \
+ "\020b16\017TBEN\016SEL_TBCLK\015b19\014b20\013b21\012b22\011b23" \
+ "\010EN_MAS7_UPDATE\007DCFA\006b26\005b27\004b28\003b29\002b30\001NOPTI"
+
+#define HID0_970_BITMASK \
+ "\20" \
+ "\040ONEPPC\037SINGLE\036ISYNCSC\035SERGP\031DEEPNAP\030DOZE" \
+ "\027NAP\025DPM\023TG\022HANGDETECT\021NHR\020INORDER" \
+ "\016TBCTRL\015TBEN\012CIABREN\011HDICEEN\001ENATTN"
+
+#define HID0_E500MC_BITMASK \
+ "\20" \
+ "\040EMCP\037EN_L2MMU_MHD\036b2\035b3\034b4\033b5\032b6\031b7" \
+ "\030b8\027b9\026b10\025b11\024b12\023b13\022b14\021b15" \
+ "\020b16\017b17\016b18\015b19\014b20\013b21\012b22\011b23" \
+ "\010EN_MAS7_UPDATE\007DCFA\006b26\005CIGLSO\004b28\003b29\002b30\001NOPTI"
+
+#define HID0_E5500_BITMASK \
+ "\20" \
+ "\040EMCP\037EN_L2MMU_MHD\036b2\035b3\034b4\033b5\032b6\031b7" \
+ "\030b8\027b9\026b10\025b11\024b12\023b13\022b14\021b15" \
+ "\020b16\017b17\016b18\015b19\014b20\013b21\012b22\011b23" \
+ "\010b24\007DCFA\006b26\005CIGLSO\004b28\003b29\002b30\001NOPTI"
+
+/*
+ * HID0 bit definitions per cpu model
+ *
+ * bit 603 604 750 7400 7410 7450 7457 e500
+ * 0 EMCP EMCP EMCP EMCP EMCP - - EMCP
+ * 1 - ECP DBP - - - - -
+ * 2 EBA EBA EBA EBA EDA - - -
+ * 3 EBD EBD EBD EBD EBD - - -
+ * 4 SBCLK - BCLK BCKL BCLK - - -
+ * 5 EICE - - - - TBEN TBEN -
+ * 6 ECLK - ECLK ECLK ECLK - - -
+ * 7 PAR PAR PAR PAR PAR STEN STEN -
+ * 8 DOZE - DOZE DOZE DOZE - HBATEN DOZE
+ * 9 NAP - NAP NAP NAP NAP NAP NAP
+ * 10 SLEEP - SLEEP SLEEP SLEEP SLEEP SLEEP SLEEP
+ * 11 DPM - DPM DPM DPM DPM DPM -
+ * 12 RISEG - - RISEG - - - -
+ * 13 - - - EIEC EIEC BHTCLR BHTCLR -
+ * 14 - - - - - XAEN XAEN -
+ * 15 - NHR NHR NHR NHR NHR NHR -
+ * 16 ICE ICE ICE ICE ICE ICE ICE -
+ * 17 DCE DCE DCE DCE DCE DCE DCE TBEN
+ * 18 ILOCK ILOCK ILOCK ILOCK ILOCK ILOCK ILOCK SEL_TBCLK
+ * 19 DLOCK DLOCK DLOCK DLOCK DLOCK DLOCK DLOCK -
+ * 20 ICFI ICFI ICFI ICFI ICFI ICFI ICFI -
+ * 21 DCFI DCFI DCFI DCFI DCFI DCFI DCFI -
+ * 22 - - SPD SPD SPG SPD SPD -
+ * 23 - - IFEM IFTT IFTT - XBSEN -
+ * 24 - SIE SGE SGE SGE SGE SGE EN_MAS7_UPDATE
+ * 25 - - DCFA DCFA DCFA - - DCFA
+ * 26 - - BTIC BTIC BTIC BTIC BTIC -
+ * 27 FBIOB - - - - LRSTK LRSTK -
+ * 28 - - ABE - - FOLD FOLD -
+ * 29 - BHT BHT BHT BHT BHT BHT -
+ * 30 - - - NOPDST NOPDST NOPDST NOPDST -
+ * 31 NOOPTI - NOOPTI NOPTI NOPTI NOPTI NOPTI NOPTI
+ *
+ * bit e500mc e5500
+ * 0 EMCP EMCP
+ * 1 EN_L2MMU_MHD EN_L2MMU_MHD
+ * 2 - -
+ * 3 - -
+ * 4 - -
+ * 5 - -
+ * 6 - -
+ * 7 - -
+ * 8 - -
+ * 9 - -
+ * 10 - -
+ * 11 - -
+ * 12 - -
+ * 13 - -
+ * 14 - -
+ * 15 - -
+ * 16 - -
+ * 17 - -
+ * 18 - -
+ * 19 - -
+ * 20 - -
+ * 21 - -
+ * 22 - -
+ * 23 - -
+ * 24 EN_MAS7_UPDATE -
+ * 25 DCFA DCFA
+ * 26 - -
+ * 27 CIGLSO CIGLSO
+ * 28 - -
+ * 29 - -
+ * 30 - -
+ * 31 NOPTI NOPTI
+ *
+ * 604: ECP = Enable cache parity checking
+ * 604: SIE = Serial instruction execution disable
+ * 7450: TBEN = Time Base Enable
+ * 7450: STEN = Software table lookup enable
+ * 7450: BHTCLR = Branch history clear
+ * 7450: XAEN = Extended Addressing Enabled
+ * 7450: LRSTK = Link Register Stack Enable
+ * 7450: FOLD = Branch folding enable
+ * 7457: HBATEN = High BAT Enable
+ * 7457: XBSEN = Extended BAT Block Size Enable
+ */
+
+#define HID1_E500_ABE 0x00001000 /* Address broadcast enable */
+#define HID1_E500_ASTME 0x00002000 /* Address bus streaming mode enable */
+#define HID1_E500_RFXE 0x00020000 /* Read fault exception enable */
+
+#define HID0_E500_DEFAULT_SET (HID0_EMCP | HID0_E500_TBEN | \
+ HID0_E500_MAS7UPDEN)
+#define HID1_E500_DEFAULT_SET (HID1_E500_ABE | HID1_E500_ASTME)
+#define HID0_E500MC_DEFAULT_SET (HID0_EMCP | HID0_E500MC_L2MMU_MHD | \
+ HID0_E500_MAS7UPDEN)
+#define HID0_E5500_DEFAULT_SET (HID0_EMCP | HID0_E500MC_L2MMU_MHD)
+
+#define HID5_970_DCBZ_SIZE_HI 0x00000080UL /* dcbz does a 32-byte store */
+#define HID4_970_DISABLE_LG_PG 0x00000004ULL /* disables large pages */
+
+#endif /* _POWERPC_HID_H_ */
diff --git a/freebsd/sys/powerpc/include/machine/pio.h b/freebsd/sys/powerpc/include/machine/pio.h
new file mode 100644
index 00000000..a4d9b327
--- /dev/null
+++ b/freebsd/sys/powerpc/include/machine/pio.h
@@ -0,0 +1,306 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1997 Per Fogelstrom, Opsycon AB and RTMX Inc, USA.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed under OpenBSD by
+ * Per Fogelstrom Opsycon AB for RTMX Inc, North Carolina, USA.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $NetBSD: pio.h,v 1.1 1998/05/15 10:15:54 tsubai Exp $
+ * $OpenBSD: pio.h,v 1.1 1997/10/13 10:53:47 pefo Exp $
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_PIO_H_
+#define _MACHINE_PIO_H_
+/*
+ * I/O macros.
+ */
+
+/*
+ * Use sync so that bus space operations cannot sneak out the bottom of
+ * mutex-protected sections (mutex release does not guarantee completion of
+ * accesses to caching-inhibited memory on some systems)
+ */
+#define powerpc_iomb() __asm __volatile("sync" : : : "memory")
+
+static __inline void
+__outb(volatile u_int8_t *a, u_int8_t v)
+{
+ *a = v;
+ powerpc_iomb();
+}
+
+static __inline void
+__outw(volatile u_int16_t *a, u_int16_t v)
+{
+ *a = v;
+ powerpc_iomb();
+}
+
+static __inline void
+__outl(volatile u_int32_t *a, u_int32_t v)
+{
+ *a = v;
+ powerpc_iomb();
+}
+
+static __inline void
+__outll(volatile u_int64_t *a, u_int64_t v)
+{
+ *a = v;
+ powerpc_iomb();
+}
+
+static __inline void
+__outwrb(volatile u_int16_t *a, u_int16_t v)
+{
+ __asm__ volatile("sthbrx %0, 0, %1" :: "r"(v), "r"(a));
+ powerpc_iomb();
+}
+
+static __inline void
+__outlrb(volatile u_int32_t *a, u_int32_t v)
+{
+ __asm__ volatile("stwbrx %0, 0, %1" :: "r"(v), "r"(a));
+ powerpc_iomb();
+}
+
+static __inline u_int8_t
+__inb(volatile u_int8_t *a)
+{
+ u_int8_t _v_;
+
+ _v_ = *a;
+ powerpc_iomb();
+ return _v_;
+}
+
+static __inline u_int16_t
+__inw(volatile u_int16_t *a)
+{
+ u_int16_t _v_;
+
+ _v_ = *a;
+ powerpc_iomb();
+ return _v_;
+}
+
+static __inline u_int32_t
+__inl(volatile u_int32_t *a)
+{
+ u_int32_t _v_;
+
+ _v_ = *a;
+ powerpc_iomb();
+ return _v_;
+}
+
+static __inline u_int64_t
+__inll(volatile u_int64_t *a)
+{
+ u_int64_t _v_;
+
+ _v_ = *a;
+ powerpc_iomb();
+ return _v_;
+}
+
+static __inline u_int16_t
+__inwrb(volatile u_int16_t *a)
+{
+ u_int16_t _v_;
+
+ __asm__ volatile("lhbrx %0, 0, %1" : "=r"(_v_) : "r"(a));
+ powerpc_iomb();
+ return _v_;
+}
+
+static __inline u_int32_t
+__inlrb(volatile u_int32_t *a)
+{
+ u_int32_t _v_;
+
+ __asm__ volatile("lwbrx %0, 0, %1" : "=r"(_v_) : "r"(a));
+ powerpc_iomb();
+ return _v_;
+}
+
+#define outb(a,v) (__outb((volatile u_int8_t *)(a), v))
+#define out8(a,v) outb(a,v)
+#define outw(a,v) (__outw((volatile u_int16_t *)(a), v))
+#define out16(a,v) outw(a,v)
+#define outl(a,v) (__outl((volatile u_int32_t *)(a), v))
+#define out32(a,v) outl(a,v)
+#define outll(a,v) (__outll((volatile u_int64_t *)(a), v))
+#define out64(a,v) outll(a,v)
+#define inb(a) (__inb((volatile u_int8_t *)(a)))
+#define in8(a) inb(a)
+#define inw(a) (__inw((volatile u_int16_t *)(a)))
+#define in16(a) inw(a)
+#define inl(a) (__inl((volatile u_int32_t *)(a)))
+#define in32(a) inl(a)
+#define inll(a) (__inll((volatile u_int64_t *)(a)))
+#define in64(a) inll(a)
+
+#define out8rb(a,v) outb(a,v)
+#define outwrb(a,v) (__outwrb((volatile u_int16_t *)(a), v))
+#define out16rb(a,v) outwrb(a,v)
+#define outlrb(a,v) (__outlrb((volatile u_int32_t *)(a), v))
+#define out32rb(a,v) outlrb(a,v)
+#define in8rb(a) inb(a)
+#define inwrb(a) (__inwrb((volatile u_int16_t *)(a)))
+#define in16rb(a) inwrb(a)
+#define inlrb(a) (__inlrb((volatile u_int32_t *)(a)))
+#define in32rb(a) inlrb(a)
+
+
+static __inline void
+__outsb(volatile u_int8_t *a, const u_int8_t *s, size_t c)
+{
+ while (c--)
+ *a = *s++;
+ powerpc_iomb();
+}
+
+static __inline void
+__outsw(volatile u_int16_t *a, const u_int16_t *s, size_t c)
+{
+ while (c--)
+ *a = *s++;
+ powerpc_iomb();
+}
+
+static __inline void
+__outsl(volatile u_int32_t *a, const u_int32_t *s, size_t c)
+{
+ while (c--)
+ *a = *s++;
+ powerpc_iomb();
+}
+
+static __inline void
+__outsll(volatile u_int64_t *a, const u_int64_t *s, size_t c)
+{
+ while (c--)
+ *a = *s++;
+ powerpc_iomb();
+}
+
+static __inline void
+__outswrb(volatile u_int16_t *a, const u_int16_t *s, size_t c)
+{
+ while (c--)
+ __asm__ volatile("sthbrx %0, 0, %1" :: "r"(*s++), "r"(a));
+ powerpc_iomb();
+}
+
+static __inline void
+__outslrb(volatile u_int32_t *a, const u_int32_t *s, size_t c)
+{
+ while (c--)
+ __asm__ volatile("stwbrx %0, 0, %1" :: "r"(*s++), "r"(a));
+ powerpc_iomb();
+}
+
+static __inline void
+__insb(volatile u_int8_t *a, u_int8_t *d, size_t c)
+{
+ while (c--)
+ *d++ = *a;
+ powerpc_iomb();
+}
+
+static __inline void
+__insw(volatile u_int16_t *a, u_int16_t *d, size_t c)
+{
+ while (c--)
+ *d++ = *a;
+ powerpc_iomb();
+}
+
+static __inline void
+__insl(volatile u_int32_t *a, u_int32_t *d, size_t c)
+{
+ while (c--)
+ *d++ = *a;
+ powerpc_iomb();
+}
+
+static __inline void
+__insll(volatile u_int64_t *a, u_int64_t *d, size_t c)
+{
+ while (c--)
+ *d++ = *a;
+ powerpc_iomb();
+}
+
+static __inline void
+__inswrb(volatile u_int16_t *a, u_int16_t *d, size_t c)
+{
+ while (c--)
+ __asm__ volatile("lhbrx %0, 0, %1" : "=r"(*d++) : "r"(a));
+ powerpc_iomb();
+}
+
+static __inline void
+__inslrb(volatile u_int32_t *a, u_int32_t *d, size_t c)
+{
+ while (c--)
+ __asm__ volatile("lwbrx %0, 0, %1" : "=r"(*d++) : "r"(a));
+ powerpc_iomb();
+}
+
+#define outsb(a,s,c) (__outsb((volatile u_int8_t *)(a), s, c))
+#define outs8(a,s,c) outsb(a,s,c)
+#define outsw(a,s,c) (__outsw((volatile u_int16_t *)(a), s, c))
+#define outs16(a,s,c) outsw(a,s,c)
+#define outsl(a,s,c) (__outsl((volatile u_int32_t *)(a), s, c))
+#define outs32(a,s,c) outsl(a,s,c)
+#define outsll(a,s,c) (__outsll((volatile u_int64_t *)(a), s, c))
+#define outs64(a,s,c) outsll(a,s,c)
+#define insb(a,d,c) (__insb((volatile u_int8_t *)(a), d, c))
+#define ins8(a,d,c) insb(a,d,c)
+#define insw(a,d,c) (__insw((volatile u_int16_t *)(a), d, c))
+#define ins16(a,d,c) insw(a,d,c)
+#define insl(a,d,c) (__insl((volatile u_int32_t *)(a), d, c))
+#define ins32(a,d,c) insl(a,d,c)
+#define insll(a,d,c) (__insll((volatile u_int64_t *)(a), d, c))
+#define ins64(a,d,c) insll(a,d,c)
+
+#define outs8rb(a,s,c) outsb(a,s,c)
+#define outswrb(a,s,c) (__outswrb((volatile u_int16_t *)(a), s, c))
+#define outs16rb(a,s,c) outswrb(a,s,c)
+#define outslrb(a,s,c) (__outslrb((volatile u_int32_t *)(a), s, c))
+#define outs32rb(a,s,c) outslrb(a,s,c)
+#define ins8rb(a,d,c) insb(a,d,c)
+#define inswrb(a,d,c) (__inswrb((volatile u_int16_t *)(a), d, c))
+#define ins16rb(a,d,c) inswrb(a,d,c)
+#define inslrb(a,d,c) (__inslrb((volatile u_int32_t *)(a), d, c))
+#define ins32rb(a,d,c) inslrb(a,d,c)
+
+#endif /*_MACHINE_PIO_H_*/
diff --git a/freebsd/sys/powerpc/include/machine/platformvar.h b/freebsd/sys/powerpc/include/machine/platformvar.h
new file mode 100644
index 00000000..d5928e72
--- /dev/null
+++ b/freebsd/sys/powerpc/include/machine/platformvar.h
@@ -0,0 +1,91 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2005 Peter Grehan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MACHINE_PLATFORMVAR_H_
+#define _MACHINE_PLATFORMVAR_H_
+
+/*
+ * A PowerPC platform implementation is declared with a kernel object and
+ * an associated method table, similar to a device driver.
+ *
+ * e.g.
+ *
+ * static platform_method_t chrp_methods[] = {
+ * PLATFORMMETHOD(platform_probe, chrp_probe),
+ * PLATFORMMETHOD(platform_mem_regions, ofw_mem_regions),
+ * ...
+ * PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu),
+ * { 0, 0 }
+ * };
+ *
+ * static platform_def_t chrp_platform = {
+ * "chrp",
+ * chrp_methods,
+ * sizeof(chrp_platform_softc), // or 0 if no softc
+ * };
+ *
+ * PLATFORM_DEF(chrp_platform);
+ */
+
+#include <sys/kobj.h>
+
+struct platform_kobj {
+ /*
+ * A platform instance is a kernel object
+ */
+ KOBJ_FIELDS;
+
+ /*
+ * Utility elements that an instance may use
+ */
+ struct mtx platform_mtx; /* available for instance use */
+ void *platform_iptr; /* instance data pointer */
+
+ /*
+ * Opaque data that can be overlaid with an instance-private
+ * structure. Platform code can test that this is large enough at
+ * compile time with a sizeof() test againt it's softc. There
+ * is also a run-time test when the platform kernel object is
+ * registered.
+ */
+#define PLATFORM_OPAQUESZ 64
+ u_int platform_opaque[PLATFORM_OPAQUESZ];
+};
+
+typedef struct platform_kobj *platform_t;
+typedef struct kobj_class platform_def_t;
+#define platform_method_t kobj_method_t
+
+#define PLATFORMMETHOD KOBJMETHOD
+#define PLATFORMMETHOD_END KOBJMETHOD_END
+
+#define PLATFORM_DEF(name) DATA_SET(platform_set, name)
+
+#endif /* _MACHINE_PLATFORMVAR_H_ */
diff --git a/freebsd/sys/powerpc/mpc85xx/mpc85xx.c b/freebsd/sys/powerpc/mpc85xx/mpc85xx.c
new file mode 100644
index 00000000..4c4b4c2f
--- /dev/null
+++ b/freebsd/sys/powerpc/mpc85xx/mpc85xx.c
@@ -0,0 +1,361 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2008 Semihalf, Rafal Jaworowski
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/local/opt_platform.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/reboot.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#ifndef __rtems__
+#include <machine/machdep.h>
+#endif /* __rtems__ */
+#include <machine/pio.h>
+#include <machine/spr.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+
+/*
+ * MPC85xx system specific routines
+ */
+
+uint32_t
+ccsr_read4(uintptr_t addr)
+{
+ volatile uint32_t *ptr = (void *)addr;
+
+ return (*ptr);
+}
+
+void
+ccsr_write4(uintptr_t addr, uint32_t val)
+{
+ volatile uint32_t *ptr = (void *)addr;
+
+ *ptr = val;
+ powerpc_iomb();
+}
+
+int
+law_getmax(void)
+{
+ uint32_t ver;
+ int law_max;
+
+ ver = SVR_VER(mfspr(SPR_SVR));
+ switch (ver) {
+ case SVR_MPC8555:
+ case SVR_MPC8555E:
+ law_max = 8;
+ break;
+ case SVR_MPC8533:
+ case SVR_MPC8533E:
+ case SVR_MPC8548:
+ case SVR_MPC8548E:
+ law_max = 10;
+ break;
+ case SVR_P5020:
+ case SVR_P5020E:
+ case SVR_P5021:
+ case SVR_P5021E:
+ case SVR_P5040:
+ case SVR_P5040E:
+ law_max = 32;
+ break;
+ default:
+ law_max = 8;
+ }
+
+ return (law_max);
+}
+
+static inline void
+law_write(uint32_t n, uint64_t bar, uint32_t sr)
+{
+
+ if (mpc85xx_is_qoriq()) {
+ ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32);
+ ccsr_write4(OCP85XX_LAWBARL(n), bar);
+ ccsr_write4(OCP85XX_LAWSR_QORIQ(n), sr);
+ ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
+ } else {
+ ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12);
+ ccsr_write4(OCP85XX_LAWSR_85XX(n), sr);
+ ccsr_read4(OCP85XX_LAWSR_85XX(n));
+ }
+
+ /*
+ * The last write to LAWAR should be followed by a read
+ * of LAWAR before any device try to use any of windows.
+ * What more the read of LAWAR should be followed by isync
+ * instruction.
+ */
+
+ isync();
+}
+
+static inline void
+law_read(uint32_t n, uint64_t *bar, uint32_t *sr)
+{
+
+ if (mpc85xx_is_qoriq()) {
+ *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 |
+ ccsr_read4(OCP85XX_LAWBARL(n));
+ *sr = ccsr_read4(OCP85XX_LAWSR_QORIQ(n));
+ } else {
+ *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12;
+ *sr = ccsr_read4(OCP85XX_LAWSR_85XX(n));
+ }
+}
+
+static int
+law_find_free(void)
+{
+ uint32_t i,sr;
+ uint64_t bar;
+ int law_max;
+
+ law_max = law_getmax();
+ /* Find free LAW */
+ for (i = 0; i < law_max; i++) {
+ law_read(i, &bar, &sr);
+ if ((sr & 0x80000000) == 0)
+ break;
+ }
+
+ return (i);
+}
+
+#define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | \
+ (flsl(size + (size - 1)) - 2))
+
+int
+law_enable(int trgt, uint64_t bar, uint32_t size)
+{
+ uint64_t bar_tmp;
+ uint32_t sr, sr_tmp;
+ int i, law_max;
+
+ if (size == 0)
+ return (0);
+
+ law_max = law_getmax();
+ sr = _LAW_SR(trgt, size);
+
+ /* Bail if already programmed. */
+ for (i = 0; i < law_max; i++) {
+ law_read(i, &bar_tmp, &sr_tmp);
+ if (sr == sr_tmp && bar == bar_tmp)
+ return (0);
+ }
+
+ /* Find an unused access window. */
+ i = law_find_free();
+
+ if (i == law_max)
+ return (ENOSPC);
+
+ law_write(i, bar, sr);
+ return (0);
+}
+
+int
+law_disable(int trgt, uint64_t bar, uint32_t size)
+{
+ uint64_t bar_tmp;
+ uint32_t sr, sr_tmp;
+ int i, law_max;
+
+ law_max = law_getmax();
+ sr = _LAW_SR(trgt, size);
+
+ /* Find and disable requested LAW. */
+ for (i = 0; i < law_max; i++) {
+ law_read(i, &bar_tmp, &sr_tmp);
+ if (sr == sr_tmp && bar == bar_tmp) {
+ law_write(i, 0, 0);
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+int
+law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io)
+{
+ u_long start;
+ uint32_t ver;
+ int trgt, rv;
+
+ ver = SVR_VER(mfspr(SPR_SVR));
+
+ start = rman_get_start(res) & 0xf000;
+
+ rv = 0;
+ trgt = -1;
+ switch (start) {
+ case 0x0000:
+ case 0x8000:
+ trgt = 0;
+ break;
+ case 0x1000:
+ case 0x9000:
+ trgt = 1;
+ break;
+ case 0x2000:
+ case 0xa000:
+ if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
+ trgt = 3;
+ else
+ trgt = 2;
+ break;
+ case 0x3000:
+ case 0xb000:
+ if (ver == SVR_MPC8548E || ver == SVR_MPC8548)
+ rv = EINVAL;
+ else
+ trgt = 3;
+ break;
+ default:
+ rv = ENXIO;
+ }
+ if (rv == 0) {
+ *trgt_mem = trgt;
+ *trgt_io = trgt;
+ }
+ return (rv);
+}
+
+static void
+l3cache_inval(void)
+{
+
+ /* Flash invalidate the CPC and clear all the locks */
+ ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI |
+ OCP85XX_CPC_CSR0_LFC);
+ while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI |
+ OCP85XX_CPC_CSR0_LFC))
+ ;
+}
+
+static void
+l3cache_enable(void)
+{
+
+ ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE |
+ OCP85XX_CPC_CSR0_PE);
+ /* Read back to sync write */
+ ccsr_read4(OCP85XX_CPC_CSR0);
+}
+
+void
+mpc85xx_enable_l3_cache(void)
+{
+ uint32_t csr, size, ver;
+
+ /* Enable L3 CoreNet Platform Cache (CPC) */
+ ver = SVR_VER(mfspr(SPR_SVR));
+ if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 ||
+ ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) {
+ csr = ccsr_read4(OCP85XX_CPC_CSR0);
+ if ((csr & OCP85XX_CPC_CSR0_CE) == 0) {
+ l3cache_inval();
+ l3cache_enable();
+ }
+
+ csr = ccsr_read4(OCP85XX_CPC_CSR0);
+ if ((boothowto & RB_VERBOSE) != 0 ||
+ (csr & OCP85XX_CPC_CSR0_CE) == 0) {
+ size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0));
+ printf("L3 Corenet Platform Cache: %d KB %sabled\n",
+ size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ?
+ "dis" : "en");
+ }
+ }
+}
+
+int
+mpc85xx_is_qoriq(void)
+{
+ uint16_t pvr = mfpvr() >> 16;
+
+ /* QorIQ register set is only in e500mc and derivative core based SoCs. */
+ if (pvr == FSL_E500mc || pvr == FSL_E5500 || pvr == FSL_E6500)
+ return (1);
+
+ return (0);
+}
+
+uint32_t
+mpc85xx_get_platform_clock(void)
+{
+ phandle_t soc;
+ static uint32_t freq;
+
+ if (freq != 0)
+ return (freq);
+
+ soc = OF_finddevice("/soc");
+
+ /* freq isn't modified on error. */
+ OF_getencprop(soc, "bus-frequency", (void *)&freq, sizeof(freq));
+
+ return (freq);
+}
+
+uint32_t
+mpc85xx_get_system_clock(void)
+{
+ uint32_t freq;
+
+ freq = mpc85xx_get_platform_clock();
+
+ return (freq / 2);
+}
diff --git a/freebsd/sys/powerpc/mpc85xx/mpc85xx.h b/freebsd/sys/powerpc/mpc85xx/mpc85xx.h
new file mode 100644
index 00000000..1a0be6cb
--- /dev/null
+++ b/freebsd/sys/powerpc/mpc85xx/mpc85xx.h
@@ -0,0 +1,177 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2008 Semihalf, Rafal Jaworowski
+ * Copyright 2006 by Juniper Networks.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPC85XX_H_
+#define _MPC85XX_H_
+
+#include <machine/platformvar.h>
+
+/*
+ * Configuration control and status registers
+ */
+extern vm_offset_t ccsrbar_va;
+extern vm_paddr_t ccsrbar_pa;
+extern vm_size_t ccsrbar_size;
+#define CCSRBAR_VA ccsrbar_va
+#define OCP85XX_CCSRBAR (CCSRBAR_VA + 0x0)
+#define OCP85XX_BPTR (CCSRBAR_VA + 0x20)
+
+#define OCP85XX_BSTRH (CCSRBAR_VA + 0x20)
+#define OCP85XX_BSTRL (CCSRBAR_VA + 0x24)
+#define OCP85XX_BSTAR (CCSRBAR_VA + 0x28)
+
+#define OCP85XX_COREDISR (CCSRBAR_VA + 0xE0094)
+#define OCP85XX_BRR (CCSRBAR_VA + 0xE00E4)
+
+/*
+ * Run Control and Power Management registers
+ */
+#define CCSR_CTBENR (CCSRBAR_VA + 0xE2084)
+#define CCSR_CTBCKSELR (CCSRBAR_VA + 0xE208C)
+#define CCSR_CTBCHLTCR (CCSRBAR_VA + 0xE2094)
+
+/*
+ * DDR Memory controller.
+ */
+#define OCP85XX_DDR1_CS0_CONFIG (CCSRBAR_VA + 0x8080)
+
+/*
+ * E500 Coherency Module registers
+ */
+#define OCP85XX_EEBPCR (CCSRBAR_VA + 0x1010)
+
+/*
+ * Local access registers
+ */
+/* Write order: OCP_LAWBARH -> OCP_LAWBARL -> OCP_LAWSR */
+#define OCP85XX_LAWBARH(n) (CCSRBAR_VA + 0xc00 + 0x10 * (n))
+#define OCP85XX_LAWBARL(n) (CCSRBAR_VA + 0xc04 + 0x10 * (n))
+#define OCP85XX_LAWSR_QORIQ(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n))
+#define OCP85XX_LAWBAR(n) (CCSRBAR_VA + 0xc08 + 0x10 * (n))
+#define OCP85XX_LAWSR_85XX(n) (CCSRBAR_VA + 0xc10 + 0x10 * (n))
+#define OCP85XX_LAWSR(n) (mpc85xx_is_qoriq() ? OCP85XX_LAWSR_QORIQ(n) : \
+ OCP85XX_LAWSR_85XX(n))
+
+/* Attribute register */
+#define OCP85XX_ENA_MASK 0x80000000
+#define OCP85XX_DIS_MASK 0x7fffffff
+
+#define OCP85XX_TGTIF_LBC_QORIQ 0x1f
+#define OCP85XX_TGTIF_RAM_INTL_QORIQ 0x14
+#define OCP85XX_TGTIF_RAM1_QORIQ 0x10
+#define OCP85XX_TGTIF_RAM2_QORIQ 0x11
+#define OCP85XX_TGTIF_BMAN 0x18
+#define OCP85XX_TGTIF_DCSR 0x1D
+#define OCP85XX_TGTIF_QMAN 0x3C
+#define OCP85XX_TRGT_SHIFT_QORIQ 20
+
+#define OCP85XX_TGTIF_LBC_85XX 0x04
+#define OCP85XX_TGTIF_RAM_INTL_85XX 0x0b
+#define OCP85XX_TGTIF_RIO_85XX 0x0c
+#define OCP85XX_TGTIF_RAM1_85XX 0x0f
+#define OCP85XX_TGTIF_RAM2_85XX 0x16
+
+#define OCP85XX_TGTIF_LBC \
+ (mpc85xx_is_qoriq() ? OCP85XX_TGTIF_LBC_QORIQ : OCP85XX_TGTIF_LBC_85XX)
+#define OCP85XX_TGTIF_RAM_INTL \
+ (mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM_INTL_QORIQ : OCP85XX_TGTIF_RAM_INTL_85XX)
+#define OCP85XX_TGTIF_RIO \
+ (mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RIO_QORIQ : OCP85XX_TGTIF_RIO_85XX)
+#define OCP85XX_TGTIF_RAM1 \
+ (mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM1_QORIQ : OCP85XX_TGTIF_RAM1_85XX)
+#define OCP85XX_TGTIF_RAM2 \
+ (mpc85xx_is_qoriq() ? OCP85XX_TGTIF_RAM2_QORIQ : OCP85XX_TGTIF_RAM2_85XX)
+
+/*
+ * L2 cache registers
+ */
+#define OCP85XX_L2CTL (CCSRBAR_VA + 0x20000)
+
+/*
+ * L3 CoreNet platform cache (CPC) registers
+ */
+#define OCP85XX_CPC_CSR0 (CCSRBAR_VA + 0x10000)
+#define OCP85XX_CPC_CSR0_CE 0x80000000
+#define OCP85XX_CPC_CSR0_PE 0x40000000
+#define OCP85XX_CPC_CSR0_FI 0x00200000
+#define OCP85XX_CPC_CSR0_WT 0x00080000
+#define OCP85XX_CPC_CSR0_FL 0x00000800
+#define OCP85XX_CPC_CSR0_LFC 0x00000400
+#define OCP85XX_CPC_CFG0 (CCSRBAR_VA + 0x10008)
+#define OCP85XX_CPC_CFG_SZ_MASK 0x00003fff
+#define OCP85XX_CPC_CFG0_SZ_K(x) (((x) & OCP85XX_CPC_CFG_SZ_MASK) << 6)
+
+/*
+ * Power-On Reset configuration
+ */
+#define OCP85XX_PORDEVSR (CCSRBAR_VA + 0xe000c)
+#define OCP85XX_PORDEVSR_IO_SEL 0x00780000
+#define OCP85XX_PORDEVSR_IO_SEL_SHIFT 19
+
+#define OCP85XX_PORDEVSR2 (CCSRBAR_VA + 0xe0014)
+
+/*
+ * Status Registers.
+ */
+#define OCP85XX_RSTCR (CCSRBAR_VA + 0xe00b0)
+
+#define OCP85XX_CLKDVDR (CCSRBAR_VA + 0xe0800)
+#define OCP85XX_CLKDVDR_PXCKEN 0x80000000
+#define OCP85XX_CLKDVDR_SSICKEN 0x20000000
+#define OCP85XX_CLKDVDR_PXCKINV 0x10000000
+#define OCP85XX_CLKDVDR_PXCLK_MASK 0x00FF0000
+#define OCP85XX_CLKDVDR_SSICLK_MASK 0x000000FF
+
+/*
+ * Run Control/Power Management Registers.
+ */
+#define OCP85XX_RCPM_CDOZSR (CCSRBAR_VA + 0xe2004)
+#define OCP85XX_RCPM_CDOZCR (CCSRBAR_VA + 0xe200c)
+
+/*
+ * Prototypes.
+ */
+uint32_t ccsr_read4(uintptr_t addr);
+void ccsr_write4(uintptr_t addr, uint32_t val);
+int law_enable(int trgt, uint64_t bar, uint32_t size);
+int law_disable(int trgt, uint64_t bar, uint32_t size);
+int law_getmax(void);
+int law_pci_target(struct resource *, int *, int *);
+
+DECLARE_CLASS(mpc85xx_platform);
+int mpc85xx_attach(platform_t);
+
+void mpc85xx_enable_l3_cache(void);
+int mpc85xx_is_qoriq(void);
+uint32_t mpc85xx_get_platform_clock(void);
+uint32_t mpc85xx_get_system_clock(void);
+
+#endif /* _MPC85XX_H_ */
diff --git a/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c b/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c
new file mode 100644
index 00000000..f615fafa
--- /dev/null
+++ b/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx.c
@@ -0,0 +1,959 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2006-2007 by Juniper Networks.
+ * Copyright 2008 Semihalf.
+ * Copyright 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Semihalf
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ktr.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/rman.h>
+#include <sys/endian.h>
+#include <sys/vmem.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include <rtems/bsd/local/ofw_bus_if.h>
+#include <rtems/bsd/local/pcib_if.h>
+#include <rtems/bsd/local/pic_if.h>
+
+#include <machine/resource.h>
+#include <machine/bus.h>
+#include <machine/intr_machdep.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+#define REG_CFG_ADDR 0x0000
+#define CONFIG_ACCESS_ENABLE 0x80000000
+
+#define REG_CFG_DATA 0x0004
+#define REG_INT_ACK 0x0008
+
+#define REG_PEX_IP_BLK_REV1 0x0bf8
+#define IP_MJ_M 0x0000ff00
+#define IP_MJ_S 8
+#define IP_MN_M 0x000000ff
+#define IP_MN_S 0
+
+#define REG_POTAR(n) (0x0c00 + 0x20 * (n))
+#define REG_POTEAR(n) (0x0c04 + 0x20 * (n))
+#define REG_POWBAR(n) (0x0c08 + 0x20 * (n))
+#define REG_POWAR(n) (0x0c10 + 0x20 * (n))
+
+#define REG_PITAR(n) (0x0e00 - 0x20 * (n))
+#define REG_PIWBAR(n) (0x0e08 - 0x20 * (n))
+#define REG_PIWBEAR(n) (0x0e0c - 0x20 * (n))
+#define REG_PIWAR(n) (0x0e10 - 0x20 * (n))
+#define PIWAR_EN 0x80000000
+#define PIWAR_PF 0x40000000
+#define PIWAR_TRGT_M 0x00f00000
+#define PIWAR_TRGT_S 20
+#define PIWAR_TRGT_CCSR 0xe
+#define PIWAR_TRGT_LOCAL 0xf
+
+#define REG_PEX_MES_DR 0x0020
+#define REG_PEX_MES_IER 0x0028
+#define REG_PEX_ERR_DR 0x0e00
+#define REG_PEX_ERR_EN 0x0e08
+
+#define REG_PEX_ERR_DR 0x0e00
+#define REG_PEX_ERR_DR_ME 0x80000000
+#define REG_PEX_ERR_DR_PCT 0x800000
+#define REG_PEX_ERR_DR_PAT 0x400000
+#define REG_PEX_ERR_DR_PCAC 0x200000
+#define REG_PEX_ERR_DR_PNM 0x100000
+#define REG_PEX_ERR_DR_CDNSC 0x80000
+#define REG_PEX_ERR_DR_CRSNC 0x40000
+#define REG_PEX_ERR_DR_ICCA 0x20000
+#define REG_PEX_ERR_DR_IACA 0x10000
+#define REG_PEX_ERR_DR_CRST 0x8000
+#define REG_PEX_ERR_DR_MIS 0x4000
+#define REG_PEX_ERR_DR_IOIS 0x2000
+#define REG_PEX_ERR_DR_CIS 0x1000
+#define REG_PEX_ERR_DR_CIEP 0x800
+#define REG_PEX_ERR_DR_IOIEP 0x400
+#define REG_PEX_ERR_DR_OAC 0x200
+#define REG_PEX_ERR_DR_IOIA 0x100
+#define REG_PEX_ERR_DR_IMBA 0x80
+#define REG_PEX_ERR_DR_IIOBA 0x40
+#define REG_PEX_ERR_DR_LDDE 0x20
+#define REG_PEX_ERR_EN 0x0e08
+
+#define PCIR_LTSSM 0x404
+#define LTSSM_STAT_L0 0x16
+
+#define DEVFN(b, s, f) ((b << 16) | (s << 8) | f)
+
+#define FSL_NUM_MSIS 256 /* 8 registers of 32 bits (8 hardware IRQs) */
+
+struct fsl_pcib_softc {
+ struct ofw_pci_softc pci_sc;
+ device_t sc_dev;
+ struct mtx sc_cfg_mtx;
+ int sc_ip_maj;
+ int sc_ip_min;
+
+ int sc_iomem_target;
+ bus_addr_t sc_iomem_start, sc_iomem_end;
+ int sc_ioport_target;
+ bus_addr_t sc_ioport_start, sc_ioport_end;
+
+ struct resource *sc_res;
+ bus_space_handle_t sc_bsh;
+ bus_space_tag_t sc_bst;
+ int sc_rid;
+
+ struct resource *sc_irq_res;
+ void *sc_ih;
+
+ int sc_busnr;
+ int sc_pcie;
+ uint8_t sc_pcie_capreg; /* PCI-E Capability Reg Set */
+};
+
+struct fsl_pcib_err_dr {
+ const char *msg;
+ uint32_t err_dr_mask;
+};
+
+struct fsl_msi_map {
+ SLIST_ENTRY(fsl_msi_map) slist;
+ uint32_t irq_base;
+ bus_addr_t target;
+};
+
+SLIST_HEAD(msi_head, fsl_msi_map) fsl_msis = SLIST_HEAD_INITIALIZER(msi_head);
+
+static const struct fsl_pcib_err_dr pci_err[] = {
+ {"ME", REG_PEX_ERR_DR_ME},
+ {"PCT", REG_PEX_ERR_DR_PCT},
+ {"PAT", REG_PEX_ERR_DR_PAT},
+ {"PCAC", REG_PEX_ERR_DR_PCAC},
+ {"PNM", REG_PEX_ERR_DR_PNM},
+ {"CDNSC", REG_PEX_ERR_DR_CDNSC},
+ {"CRSNC", REG_PEX_ERR_DR_CRSNC},
+ {"ICCA", REG_PEX_ERR_DR_ICCA},
+ {"IACA", REG_PEX_ERR_DR_IACA},
+ {"CRST", REG_PEX_ERR_DR_CRST},
+ {"MIS", REG_PEX_ERR_DR_MIS},
+ {"IOIS", REG_PEX_ERR_DR_IOIS},
+ {"CIS", REG_PEX_ERR_DR_CIS},
+ {"CIEP", REG_PEX_ERR_DR_CIEP},
+ {"IOIEP", REG_PEX_ERR_DR_IOIEP},
+ {"OAC", REG_PEX_ERR_DR_OAC},
+ {"IOIA", REG_PEX_ERR_DR_IOIA},
+ {"IMBA", REG_PEX_ERR_DR_IMBA},
+ {"IIOBA", REG_PEX_ERR_DR_IIOBA},
+ {"LDDE", REG_PEX_ERR_DR_LDDE}
+};
+
+/* Local forward declerations. */
+static uint32_t fsl_pcib_cfgread(struct fsl_pcib_softc *, u_int, u_int, u_int,
+ u_int, int);
+static void fsl_pcib_cfgwrite(struct fsl_pcib_softc *, u_int, u_int, u_int,
+ u_int, uint32_t, int);
+static int fsl_pcib_decode_win(phandle_t, struct fsl_pcib_softc *);
+static void fsl_pcib_err_init(device_t);
+static void fsl_pcib_inbound(struct fsl_pcib_softc *, int, int, uint64_t,
+ uint64_t, uint64_t);
+static void fsl_pcib_outbound(struct fsl_pcib_softc *, int, int, uint64_t,
+ uint64_t, uint64_t);
+
+/* Forward declerations. */
+static int fsl_pcib_attach(device_t);
+static int fsl_pcib_detach(device_t);
+static int fsl_pcib_probe(device_t);
+
+static int fsl_pcib_maxslots(device_t);
+static uint32_t fsl_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
+static void fsl_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
+ uint32_t, int);
+static int fsl_pcib_alloc_msi(device_t dev, device_t child,
+ int count, int maxcount, int *irqs);
+static int fsl_pcib_release_msi(device_t dev, device_t child,
+ int count, int *irqs);
+static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq);
+static int fsl_pcib_release_msix(device_t dev, device_t child, int irq);
+static int fsl_pcib_map_msi(device_t dev, device_t child,
+ int irq, uint64_t *addr, uint32_t *data);
+
+static vmem_t *msi_vmem; /* Global MSI vmem, holds all MSI ranges. */
+
+/*
+ * Bus interface definitions.
+ */
+static device_method_t fsl_pcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, fsl_pcib_probe),
+ DEVMETHOD(device_attach, fsl_pcib_attach),
+ DEVMETHOD(device_detach, fsl_pcib_detach),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, fsl_pcib_maxslots),
+ DEVMETHOD(pcib_read_config, fsl_pcib_read_config),
+ DEVMETHOD(pcib_write_config, fsl_pcib_write_config),
+ DEVMETHOD(pcib_alloc_msi, fsl_pcib_alloc_msi),
+ DEVMETHOD(pcib_release_msi, fsl_pcib_release_msi),
+ DEVMETHOD(pcib_alloc_msix, fsl_pcib_alloc_msix),
+ DEVMETHOD(pcib_release_msix, fsl_pcib_release_msix),
+ DEVMETHOD(pcib_map_msi, fsl_pcib_map_msi),
+
+ DEVMETHOD_END
+};
+
+static devclass_t fsl_pcib_devclass;
+
+DEFINE_CLASS_1(pcib, fsl_pcib_driver, fsl_pcib_methods,
+ sizeof(struct fsl_pcib_softc), ofw_pci_driver);
+EARLY_DRIVER_MODULE(pcib, ofwbus, fsl_pcib_driver, fsl_pcib_devclass, 0, 0,
+ BUS_PASS_BUS);
+
+static void
+fsl_pcib_err_intr(void *v)
+{
+ struct fsl_pcib_softc *sc;
+ device_t dev;
+ uint32_t err_reg, clear_reg;
+ uint8_t i;
+
+ dev = (device_t)v;
+ sc = device_get_softc(dev);
+
+ clear_reg = 0;
+ err_reg = bus_space_read_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR);
+
+ /* Check which one error occurred */
+ for (i = 0; i < sizeof(pci_err)/sizeof(struct fsl_pcib_err_dr); i++) {
+ if (err_reg & pci_err[i].err_dr_mask) {
+ device_printf(dev, "PCI %d: report %s error\n",
+ device_get_unit(dev), pci_err[i].msg);
+ clear_reg |= pci_err[i].err_dr_mask;
+ }
+ }
+
+ /* Clear pending errors */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR, clear_reg);
+}
+
+static int
+fsl_pcib_probe(device_t dev)
+{
+
+ if (ofw_bus_get_type(dev) == NULL ||
+ strcmp(ofw_bus_get_type(dev), "pci") != 0)
+ return (ENXIO);
+
+ if (!(ofw_bus_is_compatible(dev, "fsl,mpc8540-pci") ||
+ ofw_bus_is_compatible(dev, "fsl,mpc8540-pcie") ||
+ ofw_bus_is_compatible(dev, "fsl,mpc8548-pcie") ||
+ ofw_bus_is_compatible(dev, "fsl,p5020-pcie") ||
+ ofw_bus_is_compatible(dev, "fsl,qoriq-pcie-v2.2") ||
+ ofw_bus_is_compatible(dev, "fsl,qoriq-pcie")))
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale Integrated PCI/PCI-E Controller");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fsl_pcib_attach(device_t dev)
+{
+ struct fsl_pcib_softc *sc;
+ phandle_t node;
+ uint32_t cfgreg, brctl, ipreg;
+ int error, rid;
+ uint8_t ltssm, capptr;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ sc->sc_rid = 0;
+ sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
+ RF_ACTIVE);
+ if (sc->sc_res == NULL) {
+ device_printf(dev, "could not map I/O memory\n");
+ return (ENXIO);
+ }
+ sc->sc_bst = rman_get_bustag(sc->sc_res);
+ sc->sc_bsh = rman_get_bushandle(sc->sc_res);
+ sc->sc_busnr = 0;
+
+ ipreg = bus_read_4(sc->sc_res, REG_PEX_IP_BLK_REV1);
+ sc->sc_ip_min = (ipreg & IP_MN_M) >> IP_MN_S;
+ sc->sc_ip_maj = (ipreg & IP_MJ_M) >> IP_MJ_S;
+ mtx_init(&sc->sc_cfg_mtx, "pcicfg", NULL, MTX_SPIN);
+
+ cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2);
+ if (cfgreg != 0x1057 && cfgreg != 0x1957)
+ goto err;
+
+ capptr = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_CAP_PTR, 1);
+ while (capptr != 0) {
+ cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, capptr, 2);
+ switch (cfgreg & 0xff) {
+ case PCIY_PCIX:
+ break;
+ case PCIY_EXPRESS:
+ sc->sc_pcie = 1;
+ sc->sc_pcie_capreg = capptr;
+ break;
+ }
+ capptr = (cfgreg >> 8) & 0xff;
+ }
+
+ node = ofw_bus_get_node(dev);
+
+ /*
+ * Initialize generic OF PCI interface (ranges, etc.)
+ */
+
+ error = ofw_pci_init(dev);
+ if (error)
+ return (error);
+
+ /*
+ * Configure decode windows for PCI(E) access.
+ */
+ if (fsl_pcib_decode_win(node, sc) != 0)
+ goto err;
+
+ cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_COMMAND, 2);
+ cfgreg |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
+ PCIM_CMD_PORTEN;
+ fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_COMMAND, cfgreg, 2);
+
+ /* Reset the bus. Needed for Radeon video cards. */
+ brctl = fsl_pcib_read_config(sc->sc_dev, 0, 0, 0,
+ PCIR_BRIDGECTL_1, 1);
+ brctl |= PCIB_BCR_SECBUS_RESET;
+ fsl_pcib_write_config(sc->sc_dev, 0, 0, 0,
+ PCIR_BRIDGECTL_1, brctl, 1);
+ DELAY(100000);
+ brctl &= ~PCIB_BCR_SECBUS_RESET;
+ fsl_pcib_write_config(sc->sc_dev, 0, 0, 0,
+ PCIR_BRIDGECTL_1, brctl, 1);
+ DELAY(100000);
+
+ if (sc->sc_pcie) {
+ ltssm = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_LTSSM, 1);
+ if (ltssm < LTSSM_STAT_L0) {
+ if (bootverbose)
+ printf("PCI %d: no PCIE link, skipping\n",
+ device_get_unit(dev));
+ return (0);
+ }
+ }
+
+ /* Allocate irq */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (sc->sc_irq_res == NULL) {
+ error = fsl_pcib_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "Detach of the driver failed with error %d\n",
+ error);
+ }
+ return (ENXIO);
+ }
+
+ /* Setup interrupt handler */
+ error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, fsl_pcib_err_intr, dev, &sc->sc_ih);
+ if (error != 0) {
+ device_printf(dev, "Could not setup irq, %d\n", error);
+ sc->sc_ih = NULL;
+ error = fsl_pcib_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "Detach of the driver failed with error %d\n",
+ error);
+ }
+ return (ENXIO);
+ }
+
+ fsl_pcib_err_init(dev);
+
+ return (ofw_pci_attach(dev));
+
+err:
+ return (ENXIO);
+}
+
+static uint32_t
+fsl_pcib_cfgread(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
+ u_int reg, int bytes)
+{
+ uint32_t addr, data;
+
+ addr = CONFIG_ACCESS_ENABLE;
+ addr |= (bus & 0xff) << 16;
+ addr |= (slot & 0x1f) << 11;
+ addr |= (func & 0x7) << 8;
+ addr |= reg & 0xfc;
+ if (sc->sc_pcie)
+ addr |= (reg & 0xf00) << 16;
+
+ mtx_lock_spin(&sc->sc_cfg_mtx);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
+
+ switch (bytes) {
+ case 1:
+ data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA + (reg & 3));
+ break;
+ case 2:
+ data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA + (reg & 2)));
+ break;
+ case 4:
+ data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA));
+ break;
+ default:
+ data = ~0;
+ break;
+ }
+ mtx_unlock_spin(&sc->sc_cfg_mtx);
+ return (data);
+}
+
+static void
+fsl_pcib_cfgwrite(struct fsl_pcib_softc *sc, u_int bus, u_int slot, u_int func,
+ u_int reg, uint32_t data, int bytes)
+{
+ uint32_t addr;
+
+ addr = CONFIG_ACCESS_ENABLE;
+ addr |= (bus & 0xff) << 16;
+ addr |= (slot & 0x1f) << 11;
+ addr |= (func & 0x7) << 8;
+ addr |= reg & 0xfc;
+ if (sc->sc_pcie)
+ addr |= (reg & 0xf00) << 16;
+
+ mtx_lock_spin(&sc->sc_cfg_mtx);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_CFG_ADDR, addr);
+
+ switch (bytes) {
+ case 1:
+ bus_space_write_1(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA + (reg & 3), data);
+ break;
+ case 2:
+ bus_space_write_2(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA + (reg & 2), htole16(data));
+ break;
+ case 4:
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+ REG_CFG_DATA, htole32(data));
+ break;
+ }
+ mtx_unlock_spin(&sc->sc_cfg_mtx);
+}
+
+#if 0
+static void
+dump(struct fsl_pcib_softc *sc)
+{
+ unsigned int i;
+
+#define RD(o) bus_space_read_4(sc->sc_bst, sc->sc_bsh, o)
+ for (i = 0; i < 5; i++) {
+ printf("POTAR%u =0x%08x\n", i, RD(REG_POTAR(i)));
+ printf("POTEAR%u =0x%08x\n", i, RD(REG_POTEAR(i)));
+ printf("POWBAR%u =0x%08x\n", i, RD(REG_POWBAR(i)));
+ printf("POWAR%u =0x%08x\n", i, RD(REG_POWAR(i)));
+ }
+ printf("\n");
+ for (i = 1; i < 4; i++) {
+ printf("PITAR%u =0x%08x\n", i, RD(REG_PITAR(i)));
+ printf("PIWBAR%u =0x%08x\n", i, RD(REG_PIWBAR(i)));
+ printf("PIWBEAR%u=0x%08x\n", i, RD(REG_PIWBEAR(i)));
+ printf("PIWAR%u =0x%08x\n", i, RD(REG_PIWAR(i)));
+ }
+ printf("\n");
+#undef RD
+
+ for (i = 0; i < 0x48; i += 4) {
+ printf("cfg%02x=0x%08x\n", i, fsl_pcib_cfgread(sc, 0, 0, 0,
+ i, 4));
+ }
+}
+#endif
+
+static int
+fsl_pcib_maxslots(device_t dev)
+{
+ struct fsl_pcib_softc *sc = device_get_softc(dev);
+
+ return ((sc->sc_pcie) ? 0 : PCI_SLOTMAX);
+}
+
+static uint32_t
+fsl_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
+ u_int reg, int bytes)
+{
+ struct fsl_pcib_softc *sc = device_get_softc(dev);
+ u_int devfn;
+
+ if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
+ return (~0);
+ devfn = DEVFN(bus, slot, func);
+
+ return (fsl_pcib_cfgread(sc, bus, slot, func, reg, bytes));
+}
+
+static void
+fsl_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
+ u_int reg, uint32_t val, int bytes)
+{
+ struct fsl_pcib_softc *sc = device_get_softc(dev);
+
+ if (bus == sc->sc_busnr && !sc->sc_pcie && slot < 10)
+ return;
+ fsl_pcib_cfgwrite(sc, bus, slot, func, reg, val, bytes);
+}
+
+static void
+fsl_pcib_inbound(struct fsl_pcib_softc *sc, int wnd, int tgt, uint64_t start,
+ uint64_t size, uint64_t pci_start)
+{
+ uint32_t attr, bar, tar;
+
+ KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__));
+
+ attr = PIWAR_EN;
+
+ switch (tgt) {
+ case -1:
+ attr &= ~PIWAR_EN;
+ break;
+ case PIWAR_TRGT_LOCAL:
+ attr |= (ffsl(size) - 2);
+ default:
+ attr |= (tgt << PIWAR_TRGT_S);
+ break;
+ }
+ tar = start >> 12;
+ bar = pci_start >> 12;
+
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PITAR(wnd), tar);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBEAR(wnd), 0);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWBAR(wnd), bar);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PIWAR(wnd), attr);
+}
+
+static void
+fsl_pcib_outbound(struct fsl_pcib_softc *sc, int wnd, int res, uint64_t start,
+ uint64_t size, uint64_t pci_start)
+{
+ uint32_t attr, bar, tar;
+
+ switch (res) {
+ case SYS_RES_MEMORY:
+ attr = 0x80044000 | (ffsll(size) - 2);
+ break;
+ case SYS_RES_IOPORT:
+ attr = 0x80088000 | (ffsll(size) - 2);
+ break;
+ default:
+ attr = 0x0004401f;
+ break;
+ }
+ bar = start >> 12;
+ tar = pci_start >> 12;
+
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTAR(wnd), tar);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POTEAR(wnd), 0);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWBAR(wnd), bar);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_POWAR(wnd), attr);
+}
+
+
+static void
+fsl_pcib_err_init(device_t dev)
+{
+ struct fsl_pcib_softc *sc;
+ uint16_t sec_stat, dsr;
+ uint32_t dcr, err_en;
+
+ sc = device_get_softc(dev);
+
+ sec_stat = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_SECSTAT_1, 2);
+ if (sec_stat)
+ fsl_pcib_cfgwrite(sc, 0, 0, 0, PCIR_SECSTAT_1, 0xffff, 2);
+ if (sc->sc_pcie) {
+ /* Clear error bits */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_IER,
+ 0xffffffff);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_MES_DR,
+ 0xffffffff);
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_DR,
+ 0xffffffff);
+
+ dsr = fsl_pcib_cfgread(sc, 0, 0, 0,
+ sc->sc_pcie_capreg + PCIER_DEVICE_STA, 2);
+ if (dsr)
+ fsl_pcib_cfgwrite(sc, 0, 0, 0,
+ sc->sc_pcie_capreg + PCIER_DEVICE_STA,
+ 0xffff, 2);
+
+ /* Enable all errors reporting */
+ err_en = 0x00bfff00;
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, REG_PEX_ERR_EN,
+ err_en);
+
+ /* Enable error reporting: URR, FER, NFER */
+ dcr = fsl_pcib_cfgread(sc, 0, 0, 0,
+ sc->sc_pcie_capreg + PCIER_DEVICE_CTL, 4);
+ dcr |= PCIEM_CTL_URR_ENABLE | PCIEM_CTL_FER_ENABLE |
+ PCIEM_CTL_NFER_ENABLE;
+ fsl_pcib_cfgwrite(sc, 0, 0, 0,
+ sc->sc_pcie_capreg + PCIER_DEVICE_CTL, dcr, 4);
+ }
+}
+
+static int
+fsl_pcib_detach(device_t dev)
+{
+ struct fsl_pcib_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ mtx_destroy(&sc->sc_cfg_mtx);
+
+ return (bus_generic_detach(dev));
+}
+
+static int
+fsl_pcib_decode_win(phandle_t node, struct fsl_pcib_softc *sc)
+{
+ device_t dev;
+ int error, i, trgt;
+
+ dev = sc->sc_dev;
+
+ fsl_pcib_outbound(sc, 0, -1, 0, 0, 0);
+
+ /*
+ * Configure LAW decode windows.
+ */
+ error = law_pci_target(sc->sc_res, &sc->sc_iomem_target,
+ &sc->sc_ioport_target);
+ if (error != 0) {
+ device_printf(dev, "could not retrieve PCI LAW target info\n");
+ return (error);
+ }
+
+ for (i = 0; i < sc->pci_sc.sc_nrange; i++) {
+ switch (sc->pci_sc.sc_range[i].pci_hi &
+ OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_CONFIG:
+ continue;
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ trgt = sc->sc_ioport_target;
+ fsl_pcib_outbound(sc, 2, SYS_RES_IOPORT,
+ sc->pci_sc.sc_range[i].host,
+ sc->pci_sc.sc_range[i].size,
+ sc->pci_sc.sc_range[i].pci);
+ sc->sc_ioport_start = sc->pci_sc.sc_range[i].pci;
+ sc->sc_ioport_end = sc->pci_sc.sc_range[i].pci +
+ sc->pci_sc.sc_range[i].size - 1;
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ trgt = sc->sc_iomem_target;
+ fsl_pcib_outbound(sc, 1, SYS_RES_MEMORY,
+ sc->pci_sc.sc_range[i].host,
+ sc->pci_sc.sc_range[i].size,
+ sc->pci_sc.sc_range[i].pci);
+ sc->sc_iomem_start = sc->pci_sc.sc_range[i].pci;
+ sc->sc_iomem_end = sc->pci_sc.sc_range[i].pci +
+ sc->pci_sc.sc_range[i].size - 1;
+ break;
+ default:
+ panic("Unknown range type %#x\n",
+ sc->pci_sc.sc_range[i].pci_hi &
+ OFW_PCI_PHYS_HI_SPACEMASK);
+ }
+ error = law_enable(trgt, sc->pci_sc.sc_range[i].host,
+ sc->pci_sc.sc_range[i].size);
+ if (error != 0) {
+ device_printf(dev, "could not program LAW for range "
+ "%d\n", i);
+ return (error);
+ }
+ }
+
+ /*
+ * Set outbout and inbound windows.
+ */
+ fsl_pcib_outbound(sc, 3, -1, 0, 0, 0);
+ fsl_pcib_outbound(sc, 4, -1, 0, 0, 0);
+
+ fsl_pcib_inbound(sc, 1, -1, 0, 0, 0);
+ fsl_pcib_inbound(sc, 2, -1, 0, 0, 0);
+ fsl_pcib_inbound(sc, 3, PIWAR_TRGT_LOCAL, 0,
+ ptoa(Maxmem), 0);
+
+ /* Direct-map the CCSR for MSIs. */
+ /* Freescale PCIe 2.x has a dedicated MSI window. */
+ /* inbound window 8 makes it hit 0xD00 offset, the MSI window. */
+ if (sc->sc_ip_maj >= 2)
+ fsl_pcib_inbound(sc, 8, PIWAR_TRGT_CCSR, ccsrbar_pa,
+ ccsrbar_size, ccsrbar_pa);
+ else
+ fsl_pcib_inbound(sc, 1, PIWAR_TRGT_CCSR, ccsrbar_pa,
+ ccsrbar_size, ccsrbar_pa);
+
+ return (0);
+}
+
+static int fsl_pcib_alloc_msi(device_t dev, device_t child,
+ int count, int maxcount, int *irqs)
+{
+ struct fsl_pcib_softc *sc;
+ vmem_addr_t start;
+ int err, i;
+
+ sc = device_get_softc(dev);
+ if (msi_vmem == NULL)
+ return (ENODEV);
+
+ err = vmem_xalloc(msi_vmem, count, powerof2(count), 0, 0,
+ VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_WAITOK, &start);
+
+ if (err)
+ return (err);
+
+ for (i = 0; i < count; i++)
+ irqs[i] = start + i;
+
+ return (0);
+}
+
+static int fsl_pcib_release_msi(device_t dev, device_t child,
+ int count, int *irqs)
+{
+ if (msi_vmem == NULL)
+ return (ENODEV);
+
+ vmem_xfree(msi_vmem, irqs[0], count);
+ return (0);
+}
+
+static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq)
+{
+ return (fsl_pcib_alloc_msi(dev, child, 1, 1, irq));
+}
+
+static int fsl_pcib_release_msix(device_t dev, device_t child, int irq)
+{
+ return (fsl_pcib_release_msi(dev, child, 1, &irq));
+}
+
+static int fsl_pcib_map_msi(device_t dev, device_t child,
+ int irq, uint64_t *addr, uint32_t *data)
+{
+ struct fsl_msi_map *mp;
+
+ SLIST_FOREACH(mp, &fsl_msis, slist) {
+ if (irq >= mp->irq_base && irq < mp->irq_base + FSL_NUM_MSIS)
+ break;
+ }
+
+ if (mp == NULL)
+ return (ENODEV);
+
+ *data = (irq & 255);
+ *addr = ccsrbar_pa + mp->target;
+
+ return (0);
+}
+
+
+/*
+ * Linux device trees put the msi@<x> as children of the SoC, with ranges based
+ * on the CCSR. Since rman doesn't permit overlapping or sub-ranges between
+ * devices (bus_space_subregion(9) could do it, but let's not touch the PIC
+ * driver just to allocate a subregion for a sibling driver). This driver will
+ * use ccsr_write() and ccsr_read() instead.
+ */
+
+#define FSL_NUM_IRQS 8
+#define FSL_NUM_MSI_PER_IRQ 32
+#define FSL_MSI_TARGET 0x140
+
+struct fsl_msi_softc {
+ vm_offset_t sc_base;
+ vm_offset_t sc_target;
+ int sc_msi_base_irq;
+ struct fsl_msi_map sc_map;
+ struct fsl_msi_irq {
+ /* This struct gets passed as the filter private data. */
+ struct fsl_msi_softc *sc_ptr; /* Pointer back to softc. */
+ struct resource *res;
+ int irq;
+ void *cookie;
+ int vectors[FSL_NUM_MSI_PER_IRQ];
+ vm_offset_t reg;
+ } sc_msi_irq[FSL_NUM_IRQS];
+};
+
+static int
+fsl_msi_intr_filter(void *priv)
+{
+ struct fsl_msi_irq *data = priv;
+ uint32_t reg;
+ int i;
+
+ reg = ccsr_read4(ccsrbar_va + data->reg);
+ i = 0;
+ while (reg != 0) {
+ if (reg & 1)
+ powerpc_dispatch_intr(data->vectors[i], NULL);
+ reg >>= 1;
+ i++;
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static int
+fsl_msi_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "fsl,mpic-msi"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale MSI");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fsl_msi_attach(device_t dev)
+{
+ struct fsl_msi_softc *sc;
+ struct fsl_msi_irq *irq;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ if (msi_vmem == NULL)
+ msi_vmem = vmem_create("MPIC MSI", 0, 0, 1, 0, M_BESTFIT | M_WAITOK);
+
+ /* Manually play with resource entries. */
+ sc->sc_base = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
+ sc->sc_map.target = bus_get_resource_start(dev, SYS_RES_MEMORY, 1);
+
+ if (sc->sc_map.target == 0)
+ sc->sc_map.target = sc->sc_base + FSL_MSI_TARGET;
+
+ for (i = 0; i < FSL_NUM_IRQS; i++) {
+ irq = &sc->sc_msi_irq[i];
+ irq->irq = i;
+ irq->reg = sc->sc_base + 16 * i;
+ irq->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &irq->irq, RF_ACTIVE);
+ bus_setup_intr(dev, irq->res, INTR_TYPE_MISC | INTR_MPSAFE,
+ fsl_msi_intr_filter, NULL, irq, &irq->cookie);
+ }
+ sc->sc_map.irq_base = powerpc_register_pic(dev, ofw_bus_get_node(dev),
+ FSL_NUM_MSIS, 0, 0);
+
+ /* Let vmem and the IRQ subsystem work their magic for allocations. */
+ vmem_add(msi_vmem, sc->sc_map.irq_base, FSL_NUM_MSIS, M_WAITOK);
+
+ SLIST_INSERT_HEAD(&fsl_msis, &sc->sc_map, slist);
+
+ return (0);
+}
+
+static void
+fsl_msi_enable(device_t dev, u_int irq, u_int vector, void **priv)
+{
+ struct fsl_msi_softc *sc;
+ struct fsl_msi_irq *irqd;
+
+ sc = device_get_softc(dev);
+
+ irqd = &sc->sc_msi_irq[irq / FSL_NUM_MSI_PER_IRQ];
+ irqd->vectors[irq % FSL_NUM_MSI_PER_IRQ] = vector;
+}
+
+static device_method_t fsl_msi_methods[] = {
+ DEVMETHOD(device_probe, fsl_msi_probe),
+ DEVMETHOD(device_attach, fsl_msi_attach),
+
+ DEVMETHOD(pic_enable, fsl_msi_enable),
+ DEVMETHOD_END
+};
+
+static devclass_t fsl_msi_devclass;
+
+static driver_t fsl_msi_driver = {
+ "fsl_msi",
+ fsl_msi_methods,
+ sizeof(struct fsl_msi_softc)
+};
+
+EARLY_DRIVER_MODULE(fsl_msi, simplebus, fsl_msi_driver, fsl_msi_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + 1);
diff --git a/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c b/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c
new file mode 100644
index 00000000..74a580f5
--- /dev/null
+++ b/freebsd/sys/powerpc/mpc85xx/pci_mpc85xx_pcib.c
@@ -0,0 +1,111 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright 2015 Justin Hibbits
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From: FreeBSD: src/sys/powerpc/mpc85xx/pci_ocp.c,v 1.9 2010/03/23 23:46:28 marcel
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ktr.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/endian.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include <machine/intr_machdep.h>
+
+#include <rtems/bsd/local/pcib_if.h>
+
+DECLARE_CLASS(ofw_pcib_pci_driver);
+
+struct fsl_pcib_softc {
+ /*
+ * This is here so that we can use pci bridge methods, too - the
+ * generic routines only need the dev, secbus and subbus members
+ * filled.
+ *
+ * XXX: This should be extracted from ofw_pcib_pci.c, and shared in a
+ * header.
+ */
+ struct pcib_softc ops_pcib_sc;
+ phandle_t ops_node;
+ struct ofw_bus_iinfo ops_iinfo;
+};
+
+static int
+fsl_pcib_rc_probe(device_t dev)
+{
+
+ if (pci_get_vendor(dev) != 0x1957)
+ return (ENXIO);
+ if (pci_get_progif(dev) != 0)
+ return (ENXIO);
+ if (pci_get_class(dev) != PCIC_PROCESSOR)
+ return (ENXIO);
+ if (pci_get_subclass(dev) != PCIS_PROCESSOR_POWERPC)
+ return (ENXIO);
+
+ device_set_desc(dev, "MPC85xx Root Complex bridge");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static device_method_t fsl_pcib_rc_methods[] = {
+ DEVMETHOD(device_probe, fsl_pcib_rc_probe),
+ DEVMETHOD_END
+};
+
+static devclass_t fsl_pcib_rc_devclass;
+DEFINE_CLASS_1(pcib, fsl_pcib_rc_driver, fsl_pcib_rc_methods,
+ sizeof(struct fsl_pcib_softc), ofw_pcib_pci_driver);
+EARLY_DRIVER_MODULE(rcpcib, pci, fsl_pcib_rc_driver, fsl_pcib_rc_devclass, 0, 0,
+ BUS_PASS_BUS);
diff --git a/freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c b/freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c
new file mode 100644
index 00000000..1d806970
--- /dev/null
+++ b/freebsd/sys/powerpc/mpc85xx/platform_mpc85xx.c
@@ -0,0 +1,710 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008-2012 Semihalf.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rtems/bsd/local/opt_platform.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/hid.h>
+#include <machine/_inttypes.h>
+#include <machine/machdep.h>
+#include <machine/md_var.h>
+#include <machine/platform.h>
+#include <machine/platformvar.h>
+#include <machine/smp.h>
+#include <machine/spr.h>
+#include <machine/vmparam.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <powerpc/mpc85xx/mpc85xx.h>
+
+#include <rtems/bsd/local/platform_if.h>
+
+#ifdef SMP
+extern void *ap_pcpu;
+extern vm_paddr_t kernload; /* Kernel physical load address */
+extern uint8_t __boot_page[]; /* Boot page body */
+extern uint32_t bp_kernload;
+extern vm_offset_t __startkernel;
+
+struct cpu_release {
+ uint32_t entry_h;
+ uint32_t entry_l;
+ uint32_t r3_h;
+ uint32_t r3_l;
+ uint32_t reserved;
+ uint32_t pir;
+};
+#endif
+
+extern uint32_t *bootinfo;
+vm_paddr_t ccsrbar_pa;
+vm_offset_t ccsrbar_va;
+vm_size_t ccsrbar_size;
+
+static int cpu, maxcpu;
+
+static device_t rcpm_dev;
+static void dummy_freeze(device_t, bool);
+
+static void (*freeze_timebase)(device_t, bool) = dummy_freeze;
+
+static int mpc85xx_probe(platform_t);
+static void mpc85xx_mem_regions(platform_t, struct mem_region *phys,
+ int *physsz, struct mem_region *avail, int *availsz);
+static u_long mpc85xx_timebase_freq(platform_t, struct cpuref *cpuref);
+static int mpc85xx_smp_first_cpu(platform_t, struct cpuref *cpuref);
+static int mpc85xx_smp_next_cpu(platform_t, struct cpuref *cpuref);
+static int mpc85xx_smp_get_bsp(platform_t, struct cpuref *cpuref);
+static int mpc85xx_smp_start_cpu(platform_t, struct pcpu *cpu);
+static void mpc85xx_smp_timebase_sync(platform_t, u_long tb, int ap);
+
+static void mpc85xx_reset(platform_t);
+
+static platform_method_t mpc85xx_methods[] = {
+ PLATFORMMETHOD(platform_probe, mpc85xx_probe),
+ PLATFORMMETHOD(platform_attach, mpc85xx_attach),
+ PLATFORMMETHOD(platform_mem_regions, mpc85xx_mem_regions),
+ PLATFORMMETHOD(platform_timebase_freq, mpc85xx_timebase_freq),
+
+ PLATFORMMETHOD(platform_smp_first_cpu, mpc85xx_smp_first_cpu),
+ PLATFORMMETHOD(platform_smp_next_cpu, mpc85xx_smp_next_cpu),
+ PLATFORMMETHOD(platform_smp_get_bsp, mpc85xx_smp_get_bsp),
+ PLATFORMMETHOD(platform_smp_start_cpu, mpc85xx_smp_start_cpu),
+ PLATFORMMETHOD(platform_smp_timebase_sync, mpc85xx_smp_timebase_sync),
+
+ PLATFORMMETHOD(platform_reset, mpc85xx_reset),
+
+ PLATFORMMETHOD_END
+};
+
+DEFINE_CLASS_0(mpc85xx, mpc85xx_platform, mpc85xx_methods, 0);
+
+PLATFORM_DEF(mpc85xx_platform);
+
+static int
+mpc85xx_probe(platform_t plat)
+{
+ u_int pvr = (mfpvr() >> 16) & 0xFFFF;
+
+ switch (pvr) {
+ case FSL_E500v1:
+ case FSL_E500v2:
+ case FSL_E500mc:
+ case FSL_E5500:
+ case FSL_E6500:
+ return (BUS_PROBE_DEFAULT);
+ }
+ return (ENXIO);
+}
+
+int
+mpc85xx_attach(platform_t plat)
+{
+ phandle_t cpus, child, ccsr;
+ const char *soc_name_guesses[] = {"/soc", "soc", NULL};
+ const char **name;
+ pcell_t ranges[6], acells, pacells, scells;
+ uint64_t ccsrbar, ccsrsize;
+ int i;
+
+ if ((cpus = OF_finddevice("/cpus")) != -1) {
+ for (maxcpu = 0, child = OF_child(cpus); child != 0;
+ child = OF_peer(child), maxcpu++)
+ ;
+ } else
+ maxcpu = 1;
+
+ /*
+ * Locate CCSR region. Irritatingly, there is no way to find it
+ * unless you already know where it is. Try to infer its location
+ * from the device tree.
+ */
+
+ ccsr = -1;
+ for (name = soc_name_guesses; *name != NULL && ccsr == -1; name++)
+ ccsr = OF_finddevice(*name);
+ if (ccsr == -1) {
+ char type[64];
+
+ /* That didn't work. Search for devices of type "soc" */
+ child = OF_child(OF_peer(0));
+ for (OF_child(child); child != 0; child = OF_peer(child)) {
+ if (OF_getprop(child, "device_type", type, sizeof(type))
+ <= 0)
+ continue;
+
+ if (strcmp(type, "soc") == 0) {
+ ccsr = child;
+ break;
+ }
+ }
+ }
+
+ if (ccsr == -1)
+ panic("Could not locate CCSR window!");
+
+ OF_getprop(ccsr, "#size-cells", &scells, sizeof(scells));
+ OF_getprop(ccsr, "#address-cells", &acells, sizeof(acells));
+ OF_searchprop(OF_parent(ccsr), "#address-cells", &pacells,
+ sizeof(pacells));
+ OF_getprop(ccsr, "ranges", ranges, sizeof(ranges));
+ ccsrbar = ccsrsize = 0;
+ for (i = acells; i < acells + pacells; i++) {
+ ccsrbar <<= 32;
+ ccsrbar |= ranges[i];
+ }
+ for (i = acells + pacells; i < acells + pacells + scells; i++) {
+ ccsrsize <<= 32;
+ ccsrsize |= ranges[i];
+ }
+ ccsrbar_va = pmap_early_io_map(ccsrbar, ccsrsize);
+ ccsrbar_pa = ccsrbar;
+ ccsrbar_size = ccsrsize;
+
+ mpc85xx_enable_l3_cache();
+
+ return (0);
+}
+
+void
+mpc85xx_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+ struct mem_region *avail, int *availsz)
+{
+
+ ofw_mem_regions(phys, physsz, avail, availsz);
+}
+
+static u_long
+mpc85xx_timebase_freq(platform_t plat, struct cpuref *cpuref)
+{
+ u_long ticks;
+ phandle_t cpus, child;
+ pcell_t freq;
+
+ if (bootinfo != NULL) {
+ if (bootinfo[0] == 1) {
+ /* Backward compatibility. See 8-STABLE. */
+ ticks = bootinfo[3] >> 3;
+ } else {
+ /* Compatibility with Juniper's loader. */
+ ticks = bootinfo[5] >> 3;
+ }
+ } else
+ ticks = 0;
+
+ if ((cpus = OF_finddevice("/cpus")) == -1)
+ goto out;
+
+ if ((child = OF_child(cpus)) == 0)
+ goto out;
+
+ switch (OF_getproplen(child, "timebase-frequency")) {
+ case 4:
+ {
+ uint32_t tbase;
+ OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
+ ticks = tbase;
+ return (ticks);
+ }
+ case 8:
+ {
+ uint64_t tbase;
+ OF_getprop(child, "timebase-frequency", &tbase, sizeof(tbase));
+ ticks = tbase;
+ return (ticks);
+ }
+ default:
+ break;
+ }
+
+ freq = 0;
+ if (OF_getprop(child, "bus-frequency", (void *)&freq,
+ sizeof(freq)) <= 0)
+ goto out;
+
+ if (freq == 0)
+ goto out;
+
+ /*
+ * Time Base and Decrementer are updated every 8 CCB bus clocks.
+ * HID0[SEL_TBCLK] = 0
+ */
+ if (mpc85xx_is_qoriq())
+ ticks = freq / 32;
+ else
+ ticks = freq / 8;
+
+out:
+ if (ticks <= 0)
+ panic("Unable to determine timebase frequency!");
+
+ return (ticks);
+}
+
+static int
+mpc85xx_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
+{
+
+ cpu = 0;
+ cpuref->cr_cpuid = cpu;
+ cpuref->cr_hwref = cpuref->cr_cpuid;
+ if (bootverbose)
+ printf("powerpc_smp_first_cpu: cpuid %d\n", cpuref->cr_cpuid);
+ cpu++;
+
+ return (0);
+}
+
+static int
+mpc85xx_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
+{
+
+ if (cpu >= maxcpu)
+ return (ENOENT);
+
+ cpuref->cr_cpuid = cpu++;
+ cpuref->cr_hwref = cpuref->cr_cpuid;
+ if (bootverbose)
+ printf("powerpc_smp_next_cpu: cpuid %d\n", cpuref->cr_cpuid);
+
+ return (0);
+}
+
+static int
+mpc85xx_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
+{
+
+ cpuref->cr_cpuid = mfspr(SPR_PIR);
+ cpuref->cr_hwref = cpuref->cr_cpuid;
+
+ return (0);
+}
+
+#ifdef SMP
+static int
+mpc85xx_smp_start_cpu_epapr(platform_t plat, struct pcpu *pc)
+{
+ vm_paddr_t rel_pa, bptr;
+ volatile struct cpu_release *rel;
+ vm_offset_t rel_va, rel_page;
+ phandle_t node;
+ int i;
+
+ /* If we're calling this, the node already exists. */
+ node = OF_finddevice("/cpus");
+ for (i = 0, node = OF_child(node); i < pc->pc_cpuid;
+ i++, node = OF_peer(node))
+ ;
+ if (OF_getencprop(node, "cpu-release-addr", (pcell_t *)&rel_pa,
+ sizeof(rel_pa)) == -1) {
+ return (ENOENT);
+ }
+
+ rel_page = kva_alloc(PAGE_SIZE);
+ if (rel_page == 0)
+ return (ENOMEM);
+
+ critical_enter();
+ rel_va = rel_page + (rel_pa & PAGE_MASK);
+ pmap_kenter(rel_page, rel_pa & ~PAGE_MASK);
+ rel = (struct cpu_release *)rel_va;
+ bptr = pmap_kextract((uintptr_t)__boot_page);
+ cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+ rel->pir = pc->pc_cpuid; __asm __volatile("sync");
+ rel->entry_h = (bptr >> 32);
+ rel->entry_l = bptr; __asm __volatile("sync");
+ cpu_flush_dcache(__DEVOLATILE(struct cpu_release *,rel), sizeof(*rel));
+ if (bootverbose)
+ printf("Waking up CPU %d via CPU release page %p\n",
+ pc->pc_cpuid, rel);
+ critical_exit();
+ pmap_kremove(rel_page);
+ kva_free(rel_page, PAGE_SIZE);
+
+ return (0);
+}
+#endif
+
+static int
+mpc85xx_smp_start_cpu(platform_t plat, struct pcpu *pc)
+{
+#ifdef SMP
+ vm_paddr_t bptr;
+ uint32_t reg;
+ int timeout;
+ uintptr_t brr;
+ int cpuid;
+ int epapr_boot = 0;
+ uint32_t tgt;
+
+ if (mpc85xx_is_qoriq()) {
+ reg = ccsr_read4(OCP85XX_COREDISR);
+ cpuid = pc->pc_cpuid;
+
+ if ((reg & (1 << cpuid)) != 0) {
+ printf("%s: CPU %d is disabled!\n", __func__, pc->pc_cpuid);
+ return (-1);
+ }
+
+ brr = OCP85XX_BRR;
+ } else {
+ brr = OCP85XX_EEBPCR;
+ cpuid = pc->pc_cpuid + 24;
+ }
+ bp_kernload = kernload;
+ /*
+ * bp_kernload is in the boot page. Sync the cache because ePAPR
+ * booting has the other core(s) already running.
+ */
+ cpu_flush_dcache(&bp_kernload, sizeof(bp_kernload));
+
+ ap_pcpu = pc;
+ __asm __volatile("msync; isync");
+
+ /* First try the ePAPR way. */
+ if (mpc85xx_smp_start_cpu_epapr(plat, pc) == 0) {
+ epapr_boot = 1;
+ goto spin_wait;
+ }
+
+ reg = ccsr_read4(brr);
+ if ((reg & (1 << cpuid)) != 0) {
+ printf("SMP: CPU %d already out of hold-off state!\n",
+ pc->pc_cpuid);
+ return (ENXIO);
+ }
+
+ /* Flush caches to have our changes hit DRAM. */
+ cpu_flush_dcache(__boot_page, 4096);
+
+ bptr = pmap_kextract((uintptr_t)__boot_page);
+ KASSERT((bptr & 0xfff) == 0,
+ ("%s: boot page is not aligned (%#jx)", __func__, (uintmax_t)bptr));
+ if (mpc85xx_is_qoriq()) {
+ /*
+ * Read DDR controller configuration to select proper BPTR target ID.
+ *
+ * On P5020 bit 29 of DDR1_CS0_CONFIG enables DDR controllers
+ * interleaving. If this bit is set, we have to use
+ * OCP85XX_TGTIF_RAM_INTL as BPTR target ID. On other QorIQ DPAA SoCs,
+ * this bit is reserved and always 0.
+ */
+
+ reg = ccsr_read4(OCP85XX_DDR1_CS0_CONFIG);
+ if (reg & (1 << 29))
+ tgt = OCP85XX_TGTIF_RAM_INTL;
+ else
+ tgt = OCP85XX_TGTIF_RAM1;
+
+ /*
+ * Set BSTR to the physical address of the boot page
+ */
+ ccsr_write4(OCP85XX_BSTRH, bptr >> 32);
+ ccsr_write4(OCP85XX_BSTRL, bptr);
+ ccsr_write4(OCP85XX_BSTAR, OCP85XX_ENA_MASK |
+ (tgt << OCP85XX_TRGT_SHIFT_QORIQ) | (ffsl(PAGE_SIZE) - 2));
+
+ /* Read back OCP85XX_BSTAR to synchronize write */
+ ccsr_read4(OCP85XX_BSTAR);
+
+ /*
+ * Enable and configure time base on new CPU.
+ */
+
+ /* Set TB clock source to platform clock / 32 */
+ reg = ccsr_read4(CCSR_CTBCKSELR);
+ ccsr_write4(CCSR_CTBCKSELR, reg & ~(1 << pc->pc_cpuid));
+
+ /* Enable TB */
+ reg = ccsr_read4(CCSR_CTBENR);
+ ccsr_write4(CCSR_CTBENR, reg | (1 << pc->pc_cpuid));
+ } else {
+ /*
+ * Set BPTR to the physical address of the boot page
+ */
+ bptr = (bptr >> 12) | 0x80000000u;
+ ccsr_write4(OCP85XX_BPTR, bptr);
+ __asm __volatile("isync; msync");
+ }
+
+ /*
+ * Release AP from hold-off state
+ */
+ reg = ccsr_read4(brr);
+ ccsr_write4(brr, reg | (1 << cpuid));
+ __asm __volatile("isync; msync");
+
+spin_wait:
+ timeout = 500;
+ while (!pc->pc_awake && timeout--)
+ DELAY(1000); /* wait 1ms */
+
+ /*
+ * Disable boot page translation so that the 4K page at the default
+ * address (= 0xfffff000) isn't permanently remapped and thus not
+ * usable otherwise.
+ */
+ if (!epapr_boot) {
+ if (mpc85xx_is_qoriq())
+ ccsr_write4(OCP85XX_BSTAR, 0);
+ else
+ ccsr_write4(OCP85XX_BPTR, 0);
+ __asm __volatile("isync; msync");
+ }
+
+ if (!pc->pc_awake)
+ panic("SMP: CPU %d didn't wake up.\n", pc->pc_cpuid);
+ return ((pc->pc_awake) ? 0 : EBUSY);
+#else
+ /* No SMP support */
+ return (ENXIO);
+#endif
+}
+
+static void
+mpc85xx_reset(platform_t plat)
+{
+
+ /*
+ * Try the dedicated reset register first.
+ * If the SoC doesn't have one, we'll fall
+ * back to using the debug control register.
+ */
+ ccsr_write4(OCP85XX_RSTCR, 2);
+
+ /* Clear DBCR0, disables debug interrupts and events. */
+ mtspr(SPR_DBCR0, 0);
+ __asm __volatile("isync");
+
+ /* Enable Debug Interrupts in MSR. */
+ mtmsr(mfmsr() | PSL_DE);
+
+ /* Enable debug interrupts and issue reset. */
+ mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | DBCR0_RST_SYSTEM);
+
+ printf("Reset failed...\n");
+ while (1)
+ ;
+}
+
+static void
+mpc85xx_smp_timebase_sync(platform_t plat, u_long tb, int ap)
+{
+ static volatile bool tb_ready;
+ static volatile int cpu_done;
+
+ if (ap) {
+ /* APs. Hold off until we get a stable timebase. */
+ while (!tb_ready)
+ atomic_thread_fence_seq_cst();
+ mttb(tb);
+ atomic_add_int(&cpu_done, 1);
+ while (cpu_done < mp_ncpus)
+ atomic_thread_fence_seq_cst();
+ } else {
+ /* BSP */
+ freeze_timebase(rcpm_dev, true);
+ tb_ready = true;
+ mttb(tb);
+ atomic_add_int(&cpu_done, 1);
+ while (cpu_done < mp_ncpus)
+ atomic_thread_fence_seq_cst();
+ freeze_timebase(rcpm_dev, false);
+ }
+}
+
+/* Fallback freeze. In case no real handler is found in the device tree. */
+static void
+dummy_freeze(device_t dev, bool freeze)
+{
+ /* Nothing to do here, move along. */
+}
+
+
+/* QorIQ Run control/power management timebase management. */
+
+#define RCPM_CTBENR 0x00000084
+struct mpc85xx_rcpm_softc {
+ struct resource *sc_mem;
+};
+
+static void
+mpc85xx_rcpm_freeze_timebase(device_t dev, bool freeze)
+{
+ struct mpc85xx_rcpm_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ if (freeze)
+ bus_write_4(sc->sc_mem, RCPM_CTBENR, 0);
+ else
+ bus_write_4(sc->sc_mem, RCPM_CTBENR, (1 << maxcpu) - 1);
+}
+
+static int
+mpc85xx_rcpm_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "fsl,qoriq-rcpm-1.0"))
+ return (ENXIO);
+
+ device_set_desc(dev, "QorIQ Run control and power management");
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+mpc85xx_rcpm_attach(device_t dev)
+{
+ struct mpc85xx_rcpm_softc *sc;
+ int rid;
+
+ sc = device_get_softc(dev);
+ freeze_timebase = mpc85xx_rcpm_freeze_timebase;
+ rcpm_dev = dev;
+
+ rid = 0;
+ sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ return (0);
+}
+
+static device_method_t mpc85xx_rcpm_methods[] = {
+ DEVMETHOD(device_probe, mpc85xx_rcpm_probe),
+ DEVMETHOD(device_attach, mpc85xx_rcpm_attach),
+ DEVMETHOD_END
+};
+
+static devclass_t mpc85xx_rcpm_devclass;
+
+static driver_t mpc85xx_rcpm_driver = {
+ "rcpm",
+ mpc85xx_rcpm_methods,
+ sizeof(struct mpc85xx_rcpm_softc)
+};
+
+EARLY_DRIVER_MODULE(mpc85xx_rcpm, simplebus, mpc85xx_rcpm_driver,
+ mpc85xx_rcpm_devclass, 0, 0, BUS_PASS_BUS);
+
+
+/* "Global utilities" power management/Timebase management. */
+
+#define GUTS_DEVDISR 0x00000070
+#define DEVDISR_TB0 0x00004000
+#define DEVDISR_TB1 0x00001000
+
+struct mpc85xx_guts_softc {
+ struct resource *sc_mem;
+};
+
+static void
+mpc85xx_guts_freeze_timebase(device_t dev, bool freeze)
+{
+ struct mpc85xx_guts_softc *sc;
+ uint32_t devdisr;
+
+ sc = device_get_softc(dev);
+
+ devdisr = bus_read_4(sc->sc_mem, GUTS_DEVDISR);
+ if (freeze)
+ bus_write_4(sc->sc_mem, GUTS_DEVDISR,
+ devdisr | (DEVDISR_TB0 | DEVDISR_TB1));
+ else
+ bus_write_4(sc->sc_mem, GUTS_DEVDISR,
+ devdisr & ~(DEVDISR_TB0 | DEVDISR_TB1));
+}
+
+static int
+mpc85xx_guts_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "fsl,mpc8572-guts") &&
+ !ofw_bus_is_compatible(dev, "fsl,p1020-guts") &&
+ !ofw_bus_is_compatible(dev, "fsl,p1021-guts") &&
+ !ofw_bus_is_compatible(dev, "fsl,p1022-guts") &&
+ !ofw_bus_is_compatible(dev, "fsl,p1023-guts") &&
+ !ofw_bus_is_compatible(dev, "fsl,p2020-guts"))
+ return (ENXIO);
+
+ device_set_desc(dev, "MPC85xx Global Utilities");
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+mpc85xx_guts_attach(device_t dev)
+{
+ struct mpc85xx_rcpm_softc *sc;
+ int rid;
+
+ sc = device_get_softc(dev);
+ freeze_timebase = mpc85xx_guts_freeze_timebase;
+ rcpm_dev = dev;
+
+ rid = 0;
+ sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ return (0);
+}
+
+static device_method_t mpc85xx_guts_methods[] = {
+ DEVMETHOD(device_probe, mpc85xx_guts_probe),
+ DEVMETHOD(device_attach, mpc85xx_guts_attach),
+ DEVMETHOD_END
+};
+
+static driver_t mpc85xx_guts_driver = {
+ "guts",
+ mpc85xx_guts_methods,
+ sizeof(struct mpc85xx_guts_softc)
+};
+
+static devclass_t mpc85xx_guts_devclass;
+
+EARLY_DRIVER_MODULE(mpc85xx_guts, simplebus, mpc85xx_guts_driver,
+ mpc85xx_guts_devclass, 0, 0, BUS_PASS_BUS);
diff --git a/freebsd/sys/powerpc/ofw/ofw_pcib_pci.c b/freebsd/sys/powerpc/ofw/ofw_pcib_pci.c
new file mode 100644
index 00000000..26dd52ba
--- /dev/null
+++ b/freebsd/sys/powerpc/ofw/ofw_pcib_pci.c
@@ -0,0 +1,178 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2000 Michael Smith
+ * Copyright (c) 2000 BSDi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcib_private.h>
+
+#include <machine/intr_machdep.h>
+
+#include <rtems/bsd/local/pcib_if.h>
+
+static int ofw_pcib_pci_probe(device_t bus);
+static int ofw_pcib_pci_attach(device_t bus);
+static phandle_t ofw_pcib_pci_get_node(device_t bus, device_t dev);
+static int ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev,
+ int intpin);
+
+static device_method_t ofw_pcib_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_pcib_pci_probe),
+ DEVMETHOD(device_attach, ofw_pcib_pci_attach),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_route_interrupt, ofw_pcib_pci_route_interrupt),
+ DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, ofw_pcib_pci_get_node),
+
+ DEVMETHOD_END
+};
+
+static devclass_t pcib_devclass;
+
+struct ofw_pcib_softc {
+ /*
+ * This is here so that we can use pci bridge methods, too - the
+ * generic routines only need the dev, secbus and subbus members
+ * filled.
+ */
+ struct pcib_softc ops_pcib_sc;
+ phandle_t ops_node;
+ struct ofw_bus_iinfo ops_iinfo;
+};
+
+DEFINE_CLASS_1(pcib, ofw_pcib_pci_driver, ofw_pcib_pci_methods,
+ sizeof(struct ofw_pcib_softc), pcib_driver);
+EARLY_DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_pci_driver, pcib_devclass, 0, 0,
+ BUS_PASS_BUS);
+
+static int
+ofw_pcib_pci_probe(device_t dev)
+{
+
+ if ((pci_get_class(dev) != PCIC_BRIDGE) ||
+ (pci_get_subclass(dev) != PCIS_BRIDGE_PCI)) {
+ return (ENXIO);
+ }
+
+ if (ofw_bus_get_node(dev) == -1)
+ return (ENXIO);
+
+ device_set_desc(dev, "OFW PCI-PCI bridge");
+ return (0);
+}
+
+static int
+ofw_pcib_pci_attach(device_t dev)
+{
+ struct ofw_pcib_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->ops_pcib_sc.dev = dev;
+ sc->ops_node = ofw_bus_get_node(dev);
+
+ ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo,
+ sizeof(cell_t));
+
+ pcib_attach_common(dev);
+ return (pcib_attach_child(dev));
+}
+
+static phandle_t
+ofw_pcib_pci_get_node(device_t bridge, device_t dev)
+{
+ /* We have only one child, the PCI bus, so pass it our node */
+
+ return (ofw_bus_get_node(bridge));
+}
+
+static int
+ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
+{
+ struct ofw_pcib_softc *sc;
+ struct ofw_bus_iinfo *ii;
+ struct ofw_pci_register reg;
+ cell_t pintr, mintr[2];
+ int intrcells;
+ phandle_t iparent;
+
+ sc = device_get_softc(bridge);
+ ii = &sc->ops_iinfo;
+ if (ii->opi_imapsz > 0) {
+ pintr = intpin;
+
+ /* Fabricate imap information if this isn't an OFW device */
+ bzero(®, sizeof(reg));
+ reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
+ (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
+ (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
+
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, ®,
+ sizeof(reg), &pintr, sizeof(pintr), mintr, sizeof(mintr),
+ &iparent);
+ if (intrcells) {
+ /*
+ * If we've found a mapping, return it and don't map
+ * it again on higher levels - that causes problems
+ * in some cases, and never seems to be required.
+ */
+ mintr[0] = ofw_bus_map_intr(dev, iparent, intrcells,
+ mintr);
+ return (mintr[0]);
+ }
+ } else if (intpin >= 1 && intpin <= 4) {
+ /*
+ * When an interrupt map is missing, we need to do the
+ * standard PCI swizzle and continue mapping at the parent.
+ */
+ return (pcib_route_interrupt(bridge, dev, intpin));
+ }
+ return (PCIB_ROUTE_INTERRUPT(device_get_parent(device_get_parent(
+ bridge)), bridge, intpin));
+}
+
--
2.35.3
More information about the devel
mailing list