diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-03-02 16:28:14 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-03-08 09:00:03 +0100 |
commit | f0dd0c506a706542e1a6b1c3e78e6c9809d31085 (patch) | |
tree | 7b0707ca37cc697da33ee43deb267f6cd9f20d8a /freebsd/sys/dev/ofw/ofw_subr.c | |
parent | media01: Add cpuinfo command (diff) | |
download | rtems-libbsd-f0dd0c506a706542e1a6b1c3e78e6c9809d31085.tar.bz2 |
FDT(4): Import from FreeBSD
Diffstat (limited to 'freebsd/sys/dev/ofw/ofw_subr.c')
-rw-r--r-- | freebsd/sys/dev/ofw/ofw_subr.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/freebsd/sys/dev/ofw/ofw_subr.c b/freebsd/sys/dev/ofw/ofw_subr.c new file mode 100644 index 00000000..391d25c4 --- /dev/null +++ b/freebsd/sys/dev/ofw/ofw_subr.c @@ -0,0 +1,246 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * Copyright (c) 2015 Ian Lepore <ian@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. + * + * The initial ofw_reg_to_paddr() implementation has been copied from powerpc + * ofw_machdep.c OF_decode_addr(). It was added by Marcel Moolenaar, who did not + * assert copyright with the addition but still deserves credit for the work. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <rtems/bsd/sys/param.h> +#include <sys/bus.h> +#include <sys/libkern.h> +#include <sys/reboot.h> +#include <sys/rman.h> + +#include <machine/bus.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pci.h> +#include <dev/ofw/ofw_subr.h> + +static void +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 +ofw_reg_to_paddr(phandle_t dev, int regno, bus_addr_t *paddr, + bus_size_t *psize, pcell_t *ppci_hi) +{ + pcell_t cell[32], pci_hi; + uint64_t addr, raddr, baddr; + uint64_t size, rsize; + uint32_t c, nbridge, naddr, nsize; + phandle_t bridge, parent; + u_int spc, rspc; + 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 (paddr == NULL || psize == NULL) + return (EINVAL); + + get_addr_props(bridge, &naddr, &nsize, &pci); + 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); + pci_hi = pci ? cell[regno] : OFW_PADDR_NOT_PCI; + spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK; + 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 + * or the property is empty, we assume an identity mapping. The + * standard says a missing property indicates no possible mapping. + * This code is more liberal since the intended use is to get a + * console running early, and a printf to warn of malformed data + * is probably futile before the console is fully set up. + */ + parent = OF_parent(bridge); + while (parent != 0) { + get_addr_props(parent, &nbridge, NULL, &pcib); + res = OF_getencprop(bridge, "ranges", cell, sizeof(cell)); + if (res < 1) + goto next; + if (res % sizeof(cell[0])) + return (ENXIO); + /* Capture pci_hi if we just transitioned onto a PCI bus. */ + if (pcib && pci_hi == OFW_PADDR_NOT_PCI) { + pci_hi = cell[0]; + spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK; + } + res /= sizeof(cell[0]); + regno = 0; + while (regno < res) { + rspc = (pci ? cell[regno] : OFW_PADDR_NOT_PCI) & + OFW_PCI_PHYS_HI_SPACEMASK; + 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 + : OFW_PADDR_NOT_PCI; + 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 != OFW_PADDR_NOT_PCI) + spc = rspc; + } + next: + bridge = parent; + parent = OF_parent(bridge); + get_addr_props(bridge, &naddr, &nsize, &pci); + } + + KASSERT(addr <= BUS_SPACE_MAXADDR, + ("Bus sddress is too large: %jx", (uintmax_t)addr)); + KASSERT(size <= BUS_SPACE_MAXSIZE, + ("Bus size is too large: %jx", (uintmax_t)size)); + + *paddr = addr; + *psize = size; + if (ppci_hi != NULL) + *ppci_hi = pci_hi; + + return (0); +} + +/* Parse cmd line args as env - copied from xlp_machdep. */ +/* XXX-BZ this should really be centrally provided for all (boot) code. */ +static void +_parse_bootargs(char *cmdline) +{ + char *n, *v; + + while ((v = strsep(&cmdline, " \n")) != NULL) { + if (*v == '\0') + continue; + if (*v == '-') { + while (*v != '\0') { + v++; + switch (*v) { + case 'a': boothowto |= RB_ASKNAME; break; + /* Someone should simulate that ;-) */ + case 'C': boothowto |= RB_CDROM; break; + case 'd': boothowto |= RB_KDB; break; + case 'D': boothowto |= RB_MULTIPLE; break; + case 'm': boothowto |= RB_MUTE; break; + case 'g': boothowto |= RB_GDB; break; + case 'h': boothowto |= RB_SERIAL; break; + case 'p': boothowto |= RB_PAUSE; break; + case 'r': boothowto |= RB_DFLTROOT; break; + case 's': boothowto |= RB_SINGLE; break; + case 'v': boothowto |= RB_VERBOSE; break; + } + } + } else { + n = strsep(&v, "="); + if (v == NULL) + kern_setenv(n, "1"); + else + kern_setenv(n, v); + } + } +} + +/* + * This is intended to be called early on, right after the OF system is + * initialized, so pmap may not be up yet. + */ +int +ofw_parse_bootargs(void) +{ + phandle_t chosen; + char buf[2048]; /* early stack supposedly big enough */ + int err; + + chosen = OF_finddevice("/chosen"); + if (chosen <= 0) + return (chosen); + + if ((err = OF_getprop(chosen, "bootargs", buf, sizeof(buf))) != -1) { + _parse_bootargs(buf); + return (0); + } + + return (err); +} |