summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/fdt
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-03-02 16:28:14 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-03-08 09:00:03 +0100
commitf0dd0c506a706542e1a6b1c3e78e6c9809d31085 (patch)
tree7b0707ca37cc697da33ee43deb267f6cd9f20d8a /freebsd/sys/dev/fdt
parentmedia01: Add cpuinfo command (diff)
downloadrtems-libbsd-f0dd0c506a706542e1a6b1c3e78e6c9809d31085.tar.bz2
FDT(4): Import from FreeBSD
Diffstat (limited to 'freebsd/sys/dev/fdt')
-rw-r--r--freebsd/sys/dev/fdt/fdt_common.c744
-rw-r--r--freebsd/sys/dev/fdt/fdt_common.h107
-rw-r--r--freebsd/sys/dev/fdt/simplebus.c431
-rw-r--r--freebsd/sys/dev/fdt/simplebus.h64
4 files changed, 1346 insertions, 0 deletions
diff --git a/freebsd/sys/dev/fdt/fdt_common.c b/freebsd/sys/dev/fdt/fdt_common.c
new file mode 100644
index 00000000..efbef9de
--- /dev/null
+++ b/freebsd/sys/dev/fdt/fdt_common.c
@@ -0,0 +1,744 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2009-2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under sponsorship from
+ * the FreeBSD Foundation.
+ * This software was 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.
+ *
+ * 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 <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/sysctl.h>
+
+#include <machine/resource.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 <rtems/bsd/local/ofw_bus_if.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
+ printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define FDT_COMPAT_LEN 255
+#define FDT_TYPE_LEN 64
+
+#define FDT_REG_CELLS 4
+
+SYSCTL_NODE(_hw, OID_AUTO, fdt, CTLFLAG_RD, 0, "Flattened Device Tree");
+
+vm_paddr_t fdt_immr_pa;
+vm_offset_t fdt_immr_va;
+vm_offset_t fdt_immr_size;
+
+struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head);
+
+static int fdt_is_compatible(phandle_t, const char *);
+
+static int
+fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base,
+ u_long *size)
+{
+ pcell_t ranges[32], *rangesptr;
+ pcell_t addr_cells, size_cells, par_addr_cells;
+ u_long bus_addr, par_bus_addr, pbase, psize;
+ int err, i, len, tuple_size, tuples;
+
+ if (node == 0) {
+ *base = 0;
+ *size = ULONG_MAX;
+ return (0);
+ }
+
+ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+ return (ENXIO);
+ /*
+ * Process 'ranges' property.
+ */
+ par_addr_cells = fdt_parent_addr_cells(node);
+ if (par_addr_cells > 2) {
+ return (ERANGE);
+ }
+
+ len = OF_getproplen(node, "ranges");
+ if (len < 0)
+ return (-1);
+ if (len > sizeof(ranges))
+ return (ENOMEM);
+ if (len == 0) {
+ return (fdt_get_range_by_busaddr(OF_parent(node), addr,
+ base, size));
+ }
+
+ if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
+ return (EINVAL);
+
+ tuple_size = addr_cells + par_addr_cells + size_cells;
+ tuples = len / (tuple_size * sizeof(cell_t));
+
+ if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2)
+ return (ERANGE);
+
+ *base = 0;
+ *size = 0;
+
+ for (i = 0; i < tuples; i++) {
+ rangesptr = &ranges[i * tuple_size];
+
+ bus_addr = fdt_data_get((void *)rangesptr, addr_cells);
+ if (bus_addr != addr)
+ continue;
+ rangesptr += addr_cells;
+
+ par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
+ rangesptr += par_addr_cells;
+
+ err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+ &pbase, &psize);
+ if (err > 0)
+ return (err);
+ if (err == 0)
+ *base = pbase;
+ else
+ *base = par_bus_addr;
+
+ *size = fdt_data_get((void *)rangesptr, size_cells);
+
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+int
+fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
+{
+ pcell_t ranges[6], *rangesptr;
+ pcell_t addr_cells, size_cells, par_addr_cells;
+ u_long par_bus_addr, pbase, psize;
+ int err, len, tuple_size, tuples;
+
+ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+ return (ENXIO);
+ /*
+ * Process 'ranges' property.
+ */
+ par_addr_cells = fdt_parent_addr_cells(node);
+ if (par_addr_cells > 2)
+ return (ERANGE);
+
+ len = OF_getproplen(node, "ranges");
+ if (len > sizeof(ranges))
+ return (ENOMEM);
+ if (len == 0) {
+ *base = 0;
+ *size = ULONG_MAX;
+ return (0);
+ }
+
+ if (!(range_id < len))
+ return (ERANGE);
+
+ 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;
+
+ if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2)
+ return (ERANGE);
+
+ *base = 0;
+ *size = 0;
+ rangesptr = &ranges[range_id];
+
+ *base = fdt_data_get((void *)rangesptr, addr_cells);
+ rangesptr += addr_cells;
+
+ par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
+ rangesptr += par_addr_cells;
+
+ err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+ &pbase, &psize);
+ if (err == 0)
+ *base += pbase;
+ else
+ *base += par_bus_addr;
+
+ *size = fdt_data_get((void *)rangesptr, size_cells);
+ return (0);
+}
+
+int
+fdt_immr_addr(vm_offset_t immr_va)
+{
+ phandle_t node;
+ u_long base, size;
+ int r;
+
+ /*
+ * Try to access the SOC node directly i.e. through /aliases/.
+ */
+ if ((node = OF_finddevice("soc")) != 0)
+ if (fdt_is_compatible(node, "simple-bus"))
+ goto moveon;
+ /*
+ * Find the node the long way.
+ */
+ if ((node = OF_finddevice("/")) == 0)
+ return (ENXIO);
+
+ if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0)
+ return (ENXIO);
+
+moveon:
+ if ((r = fdt_get_range(node, 0, &base, &size)) == 0) {
+ fdt_immr_pa = base;
+ fdt_immr_va = immr_va;
+ fdt_immr_size = size;
+ }
+
+ return (r);
+}
+
+/*
+ * This routine is an early-usage version of the ofw_bus_is_compatible() when
+ * the ofw_bus I/F is not available (like early console routines and similar).
+ * Note the buffer has to be on the stack since malloc() is usually not
+ * available in such cases either.
+ */
+static int
+fdt_is_compatible(phandle_t node, const char *compatstr)
+{
+ char buf[FDT_COMPAT_LEN];
+ char *compat;
+ int len, onelen, l, rv;
+
+ if ((len = OF_getproplen(node, "compatible")) <= 0)
+ return (0);
+
+ compat = (char *)&buf;
+ bzero(compat, FDT_COMPAT_LEN);
+
+ if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
+ return (0);
+
+ onelen = strlen(compatstr);
+ rv = 0;
+ while (len > 0) {
+ if (strncasecmp(compat, compatstr, onelen) == 0) {
+ /* Found it. */
+ rv = 1;
+ break;
+ }
+ /* Slide to the next sub-string. */
+ l = strlen(compat) + 1;
+ compat += l;
+ len -= l;
+ }
+
+ return (rv);
+}
+
+int
+fdt_is_compatible_strict(phandle_t node, const char *compatible)
+{
+ char compat[FDT_COMPAT_LEN];
+
+ if (OF_getproplen(node, "compatible") <= 0)
+ return (0);
+
+ if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
+ return (0);
+
+ if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
+ /* This fits. */
+ return (1);
+
+ return (0);
+}
+
+phandle_t
+fdt_find_compatible(phandle_t start, const char *compat, int strict)
+{
+ phandle_t child;
+
+ /*
+ * Traverse all children of 'start' node, and find first with
+ * matching 'compatible' property.
+ */
+ for (child = OF_child(start); child != 0; child = OF_peer(child))
+ if (fdt_is_compatible(child, compat)) {
+ if (strict)
+ if (!fdt_is_compatible_strict(child, compat))
+ continue;
+ return (child);
+ }
+ return (0);
+}
+
+phandle_t
+fdt_depth_search_compatible(phandle_t start, const char *compat, int strict)
+{
+ phandle_t child, node;
+
+ /*
+ * Depth-search all descendants of 'start' node, and find first with
+ * matching 'compatible' property.
+ */
+ for (node = OF_child(start); node != 0; node = OF_peer(node)) {
+ if (fdt_is_compatible(node, compat) &&
+ (strict == 0 || fdt_is_compatible_strict(node, compat))) {
+ return (node);
+ }
+ child = fdt_depth_search_compatible(node, compat, strict);
+ if (child != 0)
+ return (child);
+ }
+ return (0);
+}
+
+int
+fdt_is_enabled(phandle_t node)
+{
+ char *stat;
+ int ena, len;
+
+ len = OF_getprop_alloc(node, "status", sizeof(char),
+ (void **)&stat);
+
+ if (len <= 0)
+ /* It is OK if no 'status' property. */
+ return (1);
+
+ /* Anything other than 'okay' means disabled. */
+ ena = 0;
+ if (strncmp((char *)stat, "okay", len) == 0)
+ ena = 1;
+
+ OF_prop_free(stat);
+ return (ena);
+}
+
+int
+fdt_is_type(phandle_t node, const char *typestr)
+{
+ char type[FDT_TYPE_LEN];
+
+ if (OF_getproplen(node, "device_type") <= 0)
+ return (0);
+
+ if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0)
+ return (0);
+
+ if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0)
+ /* This fits. */
+ return (1);
+
+ return (0);
+}
+
+int
+fdt_parent_addr_cells(phandle_t node)
+{
+ pcell_t addr_cells;
+
+ /* Find out #address-cells of the superior bus. */
+ if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
+ sizeof(addr_cells)) <= 0)
+ return (2);
+
+ return ((int)fdt32_to_cpu(addr_cells));
+}
+
+int
+fdt_pm_is_enabled(phandle_t node)
+{
+ int ret;
+
+ ret = 1;
+
+#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+ ret = fdt_pm(node);
+#endif
+ return (ret);
+}
+
+u_long
+fdt_data_get(void *data, int cells)
+{
+
+ if (cells == 1)
+ return (fdt32_to_cpu(*((uint32_t *)data)));
+
+ return (fdt64_to_cpu(*((uint64_t *)data)));
+}
+
+int
+fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells)
+{
+ pcell_t cell;
+ int cell_size;
+
+ /*
+ * Retrieve #{address,size}-cells.
+ */
+ cell_size = sizeof(cell);
+ if (OF_getencprop(node, "#address-cells", &cell, cell_size) < cell_size)
+ *addr_cells = 2;
+ *addr_cells = (int)cell;
+
+ if (OF_getencprop(node, "#size-cells", &cell, cell_size) < cell_size)
+ cell = 1;
+ *size_cells = (int)cell;
+
+ if (*addr_cells > 3 || *size_cells > 2)
+ return (ERANGE);
+ return (0);
+}
+
+int
+fdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start,
+ u_long *count)
+{
+
+ /* Address portion. */
+ if (addr_cells > 2)
+ return (ERANGE);
+
+ *start = fdt_data_get((void *)data, addr_cells);
+ data += addr_cells;
+
+ /* Size portion. */
+ if (size_cells > 2)
+ return (ERANGE);
+
+ *count = fdt_data_get((void *)data, size_cells);
+ return (0);
+}
+
+int
+fdt_regsize(phandle_t node, u_long *base, u_long *size)
+{
+ pcell_t reg[4];
+ int addr_cells, len, size_cells;
+
+ if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
+ return (ENXIO);
+
+ if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
+ return (ENOMEM);
+
+ len = OF_getprop(node, "reg", &reg, sizeof(reg));
+ if (len <= 0)
+ return (EINVAL);
+
+ *base = fdt_data_get(&reg[0], addr_cells);
+ *size = fdt_data_get(&reg[addr_cells], size_cells);
+ return (0);
+}
+
+int
+fdt_reg_to_rl(phandle_t node, struct resource_list *rl)
+{
+ u_long end, count, start;
+ pcell_t *reg, *regptr;
+ pcell_t addr_cells, size_cells;
+ int tuple_size, tuples;
+ int i, rv;
+ long busaddr, bussize;
+
+ if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
+ return (ENXIO);
+ if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) {
+ busaddr = 0;
+ bussize = 0;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+ tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
+ debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
+ debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
+ if (tuples <= 0)
+ /* No 'reg' property in this node. */
+ return (0);
+
+ regptr = reg;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(reg, addr_cells, size_cells, &start,
+ &count);
+ if (rv != 0) {
+ resource_list_free(rl);
+ goto out;
+ }
+ reg += addr_cells + size_cells;
+
+ /* Calculate address range relative to base. */
+ start += busaddr;
+ end = start + count - 1;
+
+ debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
+ end, count);
+
+ resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
+ count);
+ }
+ rv = 0;
+
+out:
+ OF_prop_free(regptr);
+ return (rv);
+}
+
+int
+fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
+{
+ phandle_t phy_node;
+ pcell_t phy_handle, phy_reg;
+ uint32_t i;
+ device_t parent, child;
+
+ if (OF_getencprop(node, "phy-handle", (void *)&phy_handle,
+ sizeof(phy_handle)) <= 0)
+ return (ENXIO);
+
+ phy_node = OF_node_from_xref(phy_handle);
+
+ if (OF_getencprop(phy_node, "reg", (void *)&phy_reg,
+ sizeof(phy_reg)) <= 0)
+ return (ENXIO);
+
+ *phy_addr = phy_reg;
+
+ /*
+ * Search for softc used to communicate with phy.
+ */
+
+ /*
+ * Step 1: Search for ancestor of the phy-node with a "phy-handle"
+ * property set.
+ */
+ phy_node = OF_parent(phy_node);
+ while (phy_node != 0) {
+ if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
+ sizeof(phy_handle)) > 0)
+ break;
+ phy_node = OF_parent(phy_node);
+ }
+ if (phy_node == 0)
+ return (ENXIO);
+
+ /*
+ * Step 2: For each device with the same parent and name as ours
+ * compare its node with the one found in step 1, ancestor of phy
+ * node (stored in phy_node).
+ */
+ parent = device_get_parent(dev);
+ i = 0;
+ child = device_find_child(parent, device_get_name(dev), i);
+ while (child != NULL) {
+ if (ofw_bus_get_node(child) == phy_node)
+ break;
+ i++;
+ child = device_find_child(parent, device_get_name(dev), i);
+ }
+ if (child == NULL)
+ return (ENXIO);
+
+ /*
+ * Use softc of the device found.
+ */
+ *phy_sc = (void *)device_get_softc(child);
+
+ return (0);
+}
+
+int
+fdt_get_reserved_regions(struct mem_region *mr, int *mrcnt)
+{
+ pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS];
+ pcell_t *reservep;
+ phandle_t memory, root;
+ uint32_t memory_size;
+ int addr_cells, size_cells;
+ int i, max_size, res_len, rv, tuple_size, tuples;
+
+ max_size = sizeof(reserve);
+ root = OF_finddevice("/");
+ memory = OF_finddevice("/memory");
+ if (memory == -1) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
+ &size_cells)) != 0)
+ goto out;
+
+ if (addr_cells > 2) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+
+ res_len = OF_getproplen(root, "memreserve");
+ if (res_len <= 0 || res_len > sizeof(reserve)) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ memory_size = 0;
+ tuples = res_len / tuple_size;
+ reservep = (pcell_t *)&reserve;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(reservep, addr_cells, size_cells,
+ (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
+
+ if (rv != 0)
+ goto out;
+
+ reservep += addr_cells + size_cells;
+ }
+
+ *mrcnt = i;
+ rv = 0;
+out:
+ return (rv);
+}
+
+int
+fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint64_t *memsize)
+{
+ pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
+ pcell_t *regp;
+ phandle_t memory;
+ uint64_t memory_size;
+ int addr_cells, size_cells;
+ int i, max_size, reg_len, rv, tuple_size, tuples;
+
+ max_size = sizeof(reg);
+ memory = OF_finddevice("/memory");
+ if (memory == -1) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
+ &size_cells)) != 0)
+ goto out;
+
+ if (addr_cells > 2) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+ reg_len = OF_getproplen(memory, "reg");
+ if (reg_len <= 0 || reg_len > sizeof(reg)) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ if (OF_getprop(memory, "reg", reg, reg_len) <= 0) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ memory_size = 0;
+ tuples = reg_len / tuple_size;
+ regp = (pcell_t *)&reg;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(regp, addr_cells, size_cells,
+ (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
+
+ if (rv != 0)
+ goto out;
+
+ regp += addr_cells + size_cells;
+ memory_size += mr[i].mr_size;
+ }
+
+ if (memory_size == 0) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ *mrcnt = i;
+ if (memsize != NULL)
+ *memsize = memory_size;
+ rv = 0;
+out:
+ return (rv);
+}
+
+int
+fdt_get_unit(device_t dev)
+{
+ const char * name;
+
+ name = ofw_bus_get_name(dev);
+ name = strchr(name, '@') + 1;
+
+ return (strtol(name,NULL,0));
+}
+
+int
+fdt_get_chosen_bootargs(char *bootargs, size_t max_size)
+{
+ phandle_t chosen;
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return (ENXIO);
+ if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1)
+ return (ENXIO);
+ return (0);
+}
diff --git a/freebsd/sys/dev/fdt/fdt_common.h b/freebsd/sys/dev/fdt/fdt_common.h
new file mode 100644
index 00000000..81ce4bfa
--- /dev/null
+++ b/freebsd/sys/dev/fdt/fdt_common.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was 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.
+ *
+ * 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 _FDT_COMMON_H_
+#define _FDT_COMMON_H_
+
+#include <sys/sysctl.h>
+#include <sys/slicer.h>
+#include <contrib/libfdt/libfdt_env.h>
+#include <dev/ofw/ofw_bus.h>
+
+#define FDT_MEM_REGIONS 8
+
+#define DI_MAX_INTR_NUM 32
+
+struct fdt_sense_level {
+ enum intr_trigger trig;
+ enum intr_polarity pol;
+};
+
+#if defined(__arm__) && !defined(INTRNG)
+typedef int (*fdt_pic_decode_t)(phandle_t, pcell_t *, int *, int *, int *);
+extern fdt_pic_decode_t fdt_pic_table[];
+#endif
+
+#if defined(__arm__) || defined(__powerpc__)
+typedef void (*fdt_fixup_t)(phandle_t);
+struct fdt_fixup_entry {
+ char *model;
+ fdt_fixup_t handler;
+};
+extern struct fdt_fixup_entry fdt_fixup_table[];
+#endif
+
+extern SLIST_HEAD(fdt_ic_list, fdt_ic) fdt_ic_list_head;
+struct fdt_ic {
+ SLIST_ENTRY(fdt_ic) fdt_ics;
+ ihandle_t iph;
+ device_t dev;
+};
+
+extern vm_paddr_t fdt_immr_pa;
+extern vm_offset_t fdt_immr_va;
+extern vm_offset_t fdt_immr_size;
+
+struct fdt_pm_mask_entry {
+ char *compat;
+ uint32_t mask;
+};
+extern struct fdt_pm_mask_entry fdt_pm_mask_table[];
+
+#if defined(FDT_DTB_STATIC)
+extern u_char fdt_static_dtb;
+#endif
+
+SYSCTL_DECL(_hw_fdt);
+
+int fdt_addrsize_cells(phandle_t, int *, int *);
+u_long fdt_data_get(void *, int);
+int fdt_data_to_res(pcell_t *, int, int, u_long *, u_long *);
+phandle_t fdt_find_compatible(phandle_t, const char *, int);
+phandle_t fdt_depth_search_compatible(phandle_t, const char *, int);
+int fdt_get_mem_regions(struct mem_region *, int *, uint64_t *);
+int fdt_get_reserved_regions(struct mem_region *, int *);
+int fdt_get_phyaddr(phandle_t, device_t, int *, void **);
+int fdt_get_range(phandle_t, int, u_long *, u_long *);
+int fdt_immr_addr(vm_offset_t);
+int fdt_regsize(phandle_t, u_long *, u_long *);
+int fdt_is_compatible_strict(phandle_t, const char *);
+int fdt_is_enabled(phandle_t);
+int fdt_pm_is_enabled(phandle_t);
+int fdt_is_type(phandle_t, const char *);
+int fdt_parent_addr_cells(phandle_t);
+int fdt_reg_to_rl(phandle_t, struct resource_list *);
+int fdt_pm(phandle_t);
+int fdt_get_unit(device_t);
+int fdt_get_chosen_bootargs(char *bootargs, size_t max_size);
+
+#endif /* _FDT_COMMON_H_ */
diff --git a/freebsd/sys/dev/fdt/simplebus.c b/freebsd/sys/dev/fdt/simplebus.c
new file mode 100644
index 00000000..d981d065
--- /dev/null
+++ b/freebsd/sys/dev/fdt/simplebus.c
@@ -0,0 +1,431 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2013 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 <rtems/bsd/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_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/fdt/simplebus.h>
+
+/*
+ * Bus interface.
+ */
+static int simplebus_probe(device_t dev);
+static int simplebus_attach(device_t dev);
+static struct resource *simplebus_alloc_resource(device_t, device_t, int,
+ int *, rman_res_t, rman_res_t, rman_res_t, u_int);
+static void simplebus_probe_nomatch(device_t bus, device_t child);
+static int simplebus_print_child(device_t bus, device_t child);
+static device_t simplebus_add_child(device_t dev, u_int order,
+ const char *name, int unit);
+static struct resource_list *simplebus_get_resource_list(device_t bus,
+ device_t child);
+/*
+ * ofw_bus interface
+ */
+static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus,
+ device_t child);
+
+/*
+ * local methods
+ */
+
+static int simplebus_fill_ranges(phandle_t node,
+ struct simplebus_softc *sc);
+
+/*
+ * Driver methods.
+ */
+static device_method_t simplebus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, simplebus_probe),
+ DEVMETHOD(device_attach, simplebus_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_add_child, simplebus_add_child),
+ DEVMETHOD(bus_print_child, simplebus_print_child),
+ DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch),
+ DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
+ DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
+ DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo),
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(simplebus, simplebus_driver, simplebus_methods,
+ sizeof(struct simplebus_softc));
+
+static devclass_t simplebus_devclass;
+EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, simplebus_devclass,
+ 0, 0, BUS_PASS_BUS);
+EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+
+static int
+simplebus_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ /*
+ * FDT data puts a "simple-bus" compatible string on many things that
+ * have children but aren't really busses in our world. Without a
+ * ranges property we will fail to attach, so just fail to probe too.
+ */
+ if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
+ ofw_bus_has_prop(dev, "ranges")) &&
+ (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
+ "soc") != 0))
+ return (ENXIO);
+
+ device_set_desc(dev, "Flattened device tree simple bus");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+simplebus_attach(device_t dev)
+{
+ struct simplebus_softc *sc;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ simplebus_init(dev, 0);
+ if (simplebus_fill_ranges(sc->node, sc) < 0) {
+ device_printf(dev, "could not get ranges\n");
+ return (ENXIO);
+ }
+
+ /*
+ * In principle, simplebus could have an interrupt map, but ignore that
+ * for now
+ */
+
+ for (node = OF_child(sc->node); node > 0; node = OF_peer(node))
+ simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+ return (bus_generic_attach(dev));
+}
+
+void
+simplebus_init(device_t dev, phandle_t node)
+{
+ struct simplebus_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (node == 0)
+ node = ofw_bus_get_node(dev);
+ sc->dev = dev;
+ sc->node = node;
+
+ /*
+ * Some important numbers
+ */
+ sc->acells = 2;
+ OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells));
+ sc->scells = 1;
+ OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells));
+}
+
+static int
+simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc)
+{
+ int host_address_cells;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int err;
+ int i, j, k;
+
+ err = OF_searchencprop(OF_parent(node), "#address-cells",
+ &host_address_cells, sizeof(host_address_cells));
+ if (err <= 0)
+ return (-1);
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges < 0)
+ return (-1);
+ sc->nranges = nbase_ranges / sizeof(cell_t) /
+ (sc->acells + host_address_cells + sc->scells);
+ if (sc->nranges == 0)
+ return (0);
+
+ sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
+ M_DEVBUF, M_WAITOK);
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < sc->nranges; i++) {
+ sc->ranges[i].bus = 0;
+ for (k = 0; k < sc->acells; k++) {
+ sc->ranges[i].bus <<= 32;
+ sc->ranges[i].bus |= base_ranges[j++];
+ }
+ sc->ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ sc->ranges[i].host <<= 32;
+ sc->ranges[i].host |= base_ranges[j++];
+ }
+ sc->ranges[i].size = 0;
+ for (k = 0; k < sc->scells; k++) {
+ sc->ranges[i].size <<= 32;
+ sc->ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (sc->nranges);
+}
+
+struct simplebus_devinfo *
+simplebus_setup_dinfo(device_t dev, phandle_t node,
+ struct simplebus_devinfo *di)
+{
+ struct simplebus_softc *sc;
+ struct simplebus_devinfo *ndi;
+
+ sc = device_get_softc(dev);
+ if (di == NULL)
+ ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
+ else
+ ndi = di;
+ if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
+ if (di == NULL)
+ free(ndi, M_DEVBUF);
+ return (NULL);
+ }
+
+ resource_list_init(&ndi->rl);
+ ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl);
+ ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL);
+
+ return (ndi);
+}
+
+device_t
+simplebus_add_device(device_t dev, phandle_t node, u_int order,
+ const char *name, int unit, struct simplebus_devinfo *di)
+{
+ struct simplebus_devinfo *ndi;
+ device_t cdev;
+
+ if ((ndi = simplebus_setup_dinfo(dev, node, di)) == NULL)
+ return (NULL);
+ cdev = device_add_child_ordered(dev, order, name, unit);
+ if (cdev == NULL) {
+ device_printf(dev, "<%s>: device_add_child failed\n",
+ ndi->obdinfo.obd_name);
+ resource_list_free(&ndi->rl);
+ ofw_bus_gen_destroy_devinfo(&ndi->obdinfo);
+ if (di == NULL)
+ free(ndi, M_DEVBUF);
+ return (NULL);
+ }
+ device_set_ivars(cdev, ndi);
+
+ return(cdev);
+}
+
+static device_t
+simplebus_add_child(device_t dev, u_int order, const char *name, int unit)
+{
+ device_t cdev;
+ struct simplebus_devinfo *ndi;
+
+ cdev = device_add_child_ordered(dev, order, name, unit);
+ if (cdev == NULL)
+ return (NULL);
+
+ ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
+ ndi->obdinfo.obd_node = -1;
+ resource_list_init(&ndi->rl);
+ device_set_ivars(cdev, ndi);
+
+ return (cdev);
+}
+
+static const struct ofw_bus_devinfo *
+simplebus_get_devinfo(device_t bus __unused, device_t child)
+{
+ struct simplebus_devinfo *ndi;
+
+ ndi = device_get_ivars(child);
+ if (ndi == NULL)
+ return (NULL);
+ return (&ndi->obdinfo);
+}
+
+static struct resource_list *
+simplebus_get_resource_list(device_t bus __unused, device_t child)
+{
+ struct simplebus_devinfo *ndi;
+
+ ndi = device_get_ivars(child);
+ if (ndi == NULL)
+ return (NULL);
+ return (&ndi->rl);
+}
+
+static struct resource *
+simplebus_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 simplebus_softc *sc;
+ struct simplebus_devinfo *di;
+ struct resource_list_entry *rle;
+ int j;
+
+ sc = device_get_softc(bus);
+
+ /*
+ * Request for the default allocation with a given rid: use resource
+ * list stored in the local device info.
+ */
+ if (RMAN_IS_DEFAULT_RANGE(start, end)) {
+ if ((di = device_get_ivars(child)) == NULL)
+ return (NULL);
+
+ if (type == SYS_RES_IOPORT)
+ type = SYS_RES_MEMORY;
+
+ rle = resource_list_find(&di->rl, type, *rid);
+ if (rle == NULL) {
+ if (bootverbose)
+ device_printf(bus, "no default resources for "
+ "rid = %d, type = %d\n", *rid, type);
+ return (NULL);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ if (type == SYS_RES_MEMORY) {
+ /* Remap through ranges property */
+ for (j = 0; j < sc->nranges; j++) {
+ if (start >= sc->ranges[j].bus && end <
+ sc->ranges[j].bus + sc->ranges[j].size) {
+ start -= sc->ranges[j].bus;
+ start += sc->ranges[j].host;
+ end -= sc->ranges[j].bus;
+ end += sc->ranges[j].host;
+ break;
+ }
+ }
+ if (j == sc->nranges && sc->nranges != 0) {
+ if (bootverbose)
+ device_printf(bus, "Could not map resource "
+ "%#jx-%#jx\n", start, end);
+
+ return (NULL);
+ }
+ }
+
+ return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
+ count, flags));
+}
+
+static int
+simplebus_print_res(struct simplebus_devinfo *di)
+{
+ int rv;
+
+ if (di == NULL)
+ return (0);
+ rv = 0;
+ rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd");
+ return (rv);
+}
+
+static void
+simplebus_probe_nomatch(device_t bus, device_t child)
+{
+ const char *name, *type, *compat;
+
+ if (!bootverbose)
+ return;
+
+ compat = ofw_bus_get_compat(child);
+ if (compat == NULL)
+ return;
+ name = ofw_bus_get_name(child);
+ type = ofw_bus_get_type(child);
+
+ device_printf(bus, "<%s>", name != NULL ? name : "unknown");
+ simplebus_print_res(device_get_ivars(child));
+ if (!ofw_bus_status_okay(child))
+ printf(" disabled");
+ if (type)
+ printf(" type %s", type);
+ printf(" compat %s (no driver attached)\n", compat);
+}
+
+static int
+simplebus_print_child(device_t bus, device_t child)
+{
+ int rv;
+
+ rv = bus_print_child_header(bus, child);
+ rv += simplebus_print_res(device_get_ivars(child));
+ if (!ofw_bus_status_okay(child))
+ rv += printf(" disabled");
+ rv += bus_print_child_footer(bus, child);
+ return (rv);
+}
diff --git a/freebsd/sys/dev/fdt/simplebus.h b/freebsd/sys/dev/fdt/simplebus.h
new file mode 100644
index 00000000..caccf162
--- /dev/null
+++ b/freebsd/sys/dev/fdt/simplebus.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2013 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 _FDT_SIMPLEBUS_H
+#define _FDT_SIMPLEBUS_H
+
+#include <dev/ofw/ofw_bus.h>
+
+/* FDT simplebus */
+DECLARE_CLASS(simplebus_driver);
+
+struct simplebus_range {
+ uint64_t bus;
+ uint64_t host;
+ uint64_t size;
+};
+
+/* devinfo and softc */
+struct simplebus_softc {
+ device_t dev;
+ phandle_t node;
+
+ struct simplebus_range *ranges;
+ int nranges;
+
+ pcell_t acells, scells;
+};
+
+struct simplebus_devinfo {
+ struct ofw_bus_devinfo obdinfo;
+ struct resource_list rl;
+};
+
+void simplebus_init(device_t dev, phandle_t node);
+device_t simplebus_add_device(device_t dev, phandle_t node, u_int order,
+ const char *name, int unit, struct simplebus_devinfo *di);
+struct simplebus_devinfo *simplebus_setup_dinfo(device_t dev, phandle_t node,
+ struct simplebus_devinfo *di);
+#endif /* _FDT_SIMPLEBUS_H */