diff options
author | ian <ian@FreeBSD.org> | 2015-12-21 18:07:32 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2015-12-21 18:07:32 +0000 |
commit | f2c27d05283dc9a5c359331976911732b48ec7b6 (patch) | |
tree | d71ce8ea746db2371af40f1155e7fe871d285138 /sys/powerpc | |
parent | 5e0b3f1167b3511ce001af9ce6d5ffec64fbef24 (diff) | |
download | FreeBSD-src-f2c27d05283dc9a5c359331976911732b48ec7b6.zip FreeBSD-src-f2c27d05283dc9a5c359331976911732b48ec7b6.tar.gz |
Implement OF_decode_addr() for arm. Move most of powerpc's implementation
into a new function that other platforms can share.
This creates a new ofw_reg_to_paddr() function (in a new ofw_subr.c file)
that contains most of the existing ppc implementation, mostly unchanged.
The ppc code now calls the new MI code from the MD code, then creates a
ppc-specific bus_space mapping from the results. The new arm implementation
does the same in an arm-specific way.
This also moves the declaration of OF_decode_addr() from ofw_machdep.h to
openfirm.h, except on sparc64 which uses a different function signature.
This will help all FDT platforms to set up early console access using
OF_decode_addr().
Diffstat (limited to 'sys/powerpc')
-rw-r--r-- | sys/powerpc/include/ofw_machdep.h | 1 | ||||
-rw-r--r-- | sys/powerpc/ofw/ofw_machdep.c | 140 |
2 files changed, 17 insertions, 124 deletions
diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index 0ee75f4..8376e1a 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -37,7 +37,6 @@ typedef uint32_t cell_t; -int OF_decode_addr(phandle_t, int, bus_space_tag_t *, bus_space_handle_t *); void OF_getetheraddr(device_t dev, u_char *addr); void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)); diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index d085af9..5594d84 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> #include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_subr.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -565,135 +566,28 @@ OF_getetheraddr(device_t dev, u_char *addr) * register in the address space of its parent and recursively walk * the device tree upward this way. */ -static void -OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip) -{ - char type[64]; - uint32_t addr, size; - int pci, res; - - res = OF_getencprop(node, "#address-cells", &addr, sizeof(addr)); - if (res == -1) - addr = 2; - res = OF_getencprop(node, "#size-cells", &size, sizeof(size)); - if (res == -1) - size = 1; - pci = 0; - if (addr == 3 && size == 2) { - res = OF_getprop(node, "device_type", type, sizeof(type)); - if (res != -1) { - type[sizeof(type) - 1] = '\0'; - pci = (strcmp(type, "pci") == 0) ? 1 : 0; - } - } - if (addrp != NULL) - *addrp = addr; - if (sizep != NULL) - *sizep = size; - if (pcip != NULL) - *pcip = pci; -} - int OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag, bus_space_handle_t *handle) { - uint32_t cell[32]; - bus_addr_t addr, raddr, baddr; - bus_size_t size, rsize; - uint32_t c, nbridge, naddr, nsize; - phandle_t bridge, parent; - u_int spc, rspc, prefetch; - int pci, pcib, res; - - /* Sanity checking. */ - if (dev == 0) - return (EINVAL); - bridge = OF_parent(dev); - if (bridge == 0) - return (EINVAL); - if (regno < 0) - return (EINVAL); - if (tag == NULL || handle == NULL) - return (EINVAL); - - /* Assume big-endian unless we find a PCI device */ - *tag = &bs_be_tag; - - /* Get the requested register. */ - OF_get_addr_props(bridge, &naddr, &nsize, &pci); - if (pci) + bus_addr_t addr; + bus_size_t size; + pcell_t pci_hi; + int flags, res; + + res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi); + if (res < 0) + return (res); + + if (pci_hi == OFW_PADDR_NOT_PCI) { + *tag = &bs_be_tag; + flags = 0; + } else { *tag = &bs_le_tag; - res = OF_getencprop(dev, (pci) ? "assigned-addresses" : "reg", - cell, sizeof(cell)); - if (res == -1) - return (ENXIO); - if (res % sizeof(cell[0])) - return (ENXIO); - res /= sizeof(cell[0]); - regno *= naddr + nsize; - if (regno + naddr + nsize > res) - return (EINVAL); - spc = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK : ~0; - prefetch = (pci) ? cell[regno] & OFW_PCI_PHYS_HI_PREFETCHABLE : 0; - addr = 0; - for (c = 0; c < naddr; c++) - addr = ((uint64_t)addr << 32) | cell[regno++]; - size = 0; - for (c = 0; c < nsize; c++) - size = ((uint64_t)size << 32) | cell[regno++]; - - /* - * Map the address range in the bridge's decoding window as given - * by the "ranges" property. If a node doesn't have such property - * then no mapping is done. - */ - parent = OF_parent(bridge); - while (parent != 0) { - OF_get_addr_props(parent, &nbridge, NULL, &pcib); - if (pcib) - *tag = &bs_le_tag; - res = OF_getencprop(bridge, "ranges", cell, sizeof(cell)); - if (res == -1) - goto next; - if (res % sizeof(cell[0])) - return (ENXIO); - res /= sizeof(cell[0]); - regno = 0; - while (regno < res) { - rspc = (pci) - ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK - : ~0; - if (rspc != spc) { - regno += naddr + nbridge + nsize; - continue; - } - raddr = 0; - for (c = 0; c < naddr; c++) - raddr = ((uint64_t)raddr << 32) | cell[regno++]; - rspc = (pcib) - ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK - : ~0; - baddr = 0; - for (c = 0; c < nbridge; c++) - baddr = ((uint64_t)baddr << 32) | cell[regno++]; - rsize = 0; - for (c = 0; c < nsize; c++) - rsize = ((uint64_t)rsize << 32) | cell[regno++]; - if (addr < raddr || addr >= raddr + rsize) - continue; - addr = addr - raddr + baddr; - if (rspc != ~0) - spc = rspc; - } - - next: - bridge = parent; - parent = OF_parent(bridge); - OF_get_addr_props(bridge, &naddr, &nsize, &pci); + flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? + BUS_SPACE_MAP_PREFETCHABLE: 0; } - return (bus_space_map(*tag, addr, size, - prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle)); + return (bus_space_map(*tag, addr, size, flags, handle)); } |