summaryrefslogtreecommitdiffstats
path: root/sys/arm/mv/mv_pci.c
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-01-05 22:36:34 +0000
committerian <ian@FreeBSD.org>2014-01-05 22:36:34 +0000
commit420aa503c6704f4bb0c18541b7c7c193388555e1 (patch)
treee83eb08af479512a00f04c4a944ab592618fc11b /sys/arm/mv/mv_pci.c
parent6f9ebfa0c3159b8dd19fa1a837691a7deaaa3842 (diff)
downloadFreeBSD-src-420aa503c6704f4bb0c18541b7c7c193388555e1.zip
FreeBSD-src-420aa503c6704f4bb0c18541b7c7c193388555e1.tar.gz
Remove dev/fdt/fdt_pci.c, which was code specific to Marvell ARM SoCs,
related to setting up static device mappings. Since it was only used by arm/mv/mv_pci.c, it's now just static functions within that file, plus one public function that gets called only from arm/mv/mv_machdep.c.
Diffstat (limited to 'sys/arm/mv/mv_pci.c')
-rw-r--r--sys/arm/mv/mv_pci.c172
1 files changed, 170 insertions, 2 deletions
diff --git a/sys/arm/mv/mv_pci.c b/sys/arm/mv/mv_pci.c
index 597e1b6..4660e5c 100644
--- a/sys/arm/mv/mv_pci.c
+++ b/sys/arm/mv/mv_pci.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include "ofw_bus_if.h"
#include "pcib_if.h"
+#include <machine/devmap.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -83,6 +84,172 @@ __FBSDID("$FreeBSD$");
#define debugf(fmt, args...)
#endif
+/*
+ * Code and data related to fdt-based PCI configuration.
+ *
+ * This stuff used to be in dev/fdt/fdt_pci.c and fdt_common.h, but it was
+ * always Marvell-specific so that was deleted and the code now lives here.
+ */
+
+struct mv_pci_range {
+ u_long base_pci;
+ u_long base_parent;
+ u_long len;
+};
+
+#define FDT_RANGES_CELLS ((3 + 3 + 2) * 2)
+
+static void
+mv_pci_range_dump(struct mv_pci_range *range)
+{
+#ifdef DEBUG
+ printf("\n");
+ printf(" base_pci = 0x%08lx\n", range->base_pci);
+ printf(" base_par = 0x%08lx\n", range->base_parent);
+ printf(" len = 0x%08lx\n", range->len);
+#endif
+}
+
+static int
+mv_pci_ranges_decode(phandle_t node, struct mv_pci_range *io_space,
+ struct mv_pci_range *mem_space)
+{
+ pcell_t ranges[FDT_RANGES_CELLS];
+ struct mv_pci_range *pci_space;
+ pcell_t addr_cells, size_cells, par_addr_cells;
+ pcell_t *rangesptr;
+ pcell_t cell0, cell1, cell2;
+ int tuple_size, tuples, i, rv, offset_cells, len;
+
+ /*
+ * Retrieve 'ranges' property.
+ */
+ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+ return (EINVAL);
+ if (addr_cells != 3 || size_cells != 2)
+ return (ERANGE);
+
+ par_addr_cells = fdt_parent_addr_cells(node);
+ if (par_addr_cells > 3)
+ return (ERANGE);
+
+ len = OF_getproplen(node, "ranges");
+ if (len > sizeof(ranges))
+ return (ENOMEM);
+
+ if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
+ return (EINVAL);
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
+ size_cells);
+ tuples = len / tuple_size;
+
+ /*
+ * Initialize the ranges so that we don't have to worry about
+ * having them all defined in the FDT. In particular, it is
+ * perfectly fine not to want I/O space on PCI busses.
+ */
+ bzero(io_space, sizeof(*io_space));
+ bzero(mem_space, sizeof(*mem_space));
+
+ rangesptr = &ranges[0];
+ offset_cells = 0;
+ for (i = 0; i < tuples; i++) {
+ cell0 = fdt_data_get((void *)rangesptr, 1);
+ rangesptr++;
+ cell1 = fdt_data_get((void *)rangesptr, 1);
+ rangesptr++;
+ cell2 = fdt_data_get((void *)rangesptr, 1);
+ rangesptr++;
+
+ if (cell0 & 0x02000000) {
+ pci_space = mem_space;
+ } else if (cell0 & 0x01000000) {
+ pci_space = io_space;
+ } else {
+ rv = ERANGE;
+ goto out;
+ }
+
+ if (par_addr_cells == 3) {
+ /*
+ * This is a PCI subnode 'ranges'. Skip cell0 and
+ * cell1 of this entry and only use cell2.
+ */
+ offset_cells = 2;
+ rangesptr += offset_cells;
+ }
+
+ if (fdt_data_verify((void *)rangesptr, par_addr_cells -
+ offset_cells)) {
+ rv = ERANGE;
+ goto out;
+ }
+ pci_space->base_parent = fdt_data_get((void *)rangesptr,
+ par_addr_cells - offset_cells);
+ rangesptr += par_addr_cells - offset_cells;
+
+ if (fdt_data_verify((void *)rangesptr, size_cells)) {
+ rv = ERANGE;
+ goto out;
+ }
+ pci_space->len = fdt_data_get((void *)rangesptr, size_cells);
+ rangesptr += size_cells;
+
+ pci_space->base_pci = cell2;
+ }
+ rv = 0;
+out:
+ return (rv);
+}
+
+static int
+mv_pci_ranges(phandle_t node, struct mv_pci_range *io_space,
+ struct mv_pci_range *mem_space)
+{
+ int err;
+
+ debugf("Processing PCI node: %x\n", node);
+ if ((err = mv_pci_ranges_decode(node, io_space, mem_space)) != 0) {
+ debugf("could not decode parent PCI node 'ranges'\n");
+ return (err);
+ }
+
+ debugf("Post fixup dump:\n");
+ mv_pci_range_dump(io_space);
+ mv_pci_range_dump(mem_space);
+ return (0);
+}
+
+int
+mv_pci_devmap(phandle_t node, struct arm_devmap_entry *devmap, vm_offset_t io_va,
+ vm_offset_t mem_va)
+{
+ struct mv_pci_range io_space, mem_space;
+ int error;
+
+ if ((error = mv_pci_ranges_decode(node, &io_space, &mem_space)) != 0)
+ return (error);
+
+ devmap->pd_va = (io_va ? io_va : io_space.base_parent);
+ devmap->pd_pa = io_space.base_parent;
+ devmap->pd_size = io_space.len;
+ devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ devmap->pd_cache = PTE_NOCACHE;
+ devmap++;
+
+ devmap->pd_va = (mem_va ? mem_va : mem_space.base_parent);
+ devmap->pd_pa = mem_space.base_parent;
+ devmap->pd_size = mem_space.len;
+ devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ devmap->pd_cache = PTE_NOCACHE;
+ return (0);
+}
+
+/*
+ * Code and data related to the Marvell pcib driver.
+ */
+
#define PCI_CFG_ENA (1U << 31)
#define PCI_CFG_BUS(bus) (((bus) & 0xff) << 16)
#define PCI_CFG_DEV(dev) (((dev) & 0x1f) << 11)
@@ -912,13 +1079,13 @@ mv_pcib_route_interrupt(device_t bus, device_t dev, int pin)
static int
mv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc)
{
- struct fdt_pci_range io_space, mem_space;
+ struct mv_pci_range io_space, mem_space;
device_t dev;
int error;
dev = sc->sc_dev;
- if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
+ if ((error = mv_pci_ranges(node, &io_space, &mem_space)) != 0) {
device_printf(dev, "could not retrieve 'ranges' data\n");
return (error);
}
@@ -1026,3 +1193,4 @@ mv_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
return (0);
}
#endif
+
OpenPOWER on IntegriCloud