[rtems-libbsd commit] FDT(4): Import from FreeBSD

Sebastian Huber sebh at rtems.org
Wed Mar 8 12:13:26 UTC 2017


Module:    rtems-libbsd
Branch:    master
Commit:    f0dd0c506a706542e1a6b1c3e78e6c9809d31085
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=f0dd0c506a706542e1a6b1c3e78e6c9809d31085

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Mar  2 16:28:14 2017 +0100

FDT(4): Import from FreeBSD

---

 freebsd/sys/dev/fdt/fdt_common.c   | 744 +++++++++++++++++++++++++++++
 freebsd/sys/dev/fdt/fdt_common.h   | 107 +++++
 freebsd/sys/dev/fdt/simplebus.c    | 431 +++++++++++++++++
 freebsd/sys/dev/fdt/simplebus.h    |  64 +++
 freebsd/sys/dev/ofw/ofw_bus.h      |  79 +++
 freebsd/sys/dev/ofw/ofw_bus_subr.c | 953 +++++++++++++++++++++++++++++++++++++
 freebsd/sys/dev/ofw/ofw_bus_subr.h | 145 ++++++
 freebsd/sys/dev/ofw/ofw_fdt.c      | 490 +++++++++++++++++++
 freebsd/sys/dev/ofw/ofw_pci.h      | 103 ++++
 freebsd/sys/dev/ofw/ofw_subr.c     | 246 ++++++++++
 freebsd/sys/dev/ofw/ofw_subr.h     |  51 ++
 freebsd/sys/dev/ofw/ofwbus.c       | 297 ++++++++++++
 freebsd/sys/dev/ofw/ofwvar.h       |  89 ++++
 freebsd/sys/dev/ofw/openfirm.c     | 807 +++++++++++++++++++++++++++++++
 freebsd/sys/dev/tsec/if_tsec_fdt.c | 390 +++++++++++++++
 freebsd/sys/sys/slicer.h           |  52 ++
 16 files changed, 5048 insertions(+)

diff --git a/freebsd/sys/dev/fdt/fdt_common.c b/freebsd/sys/dev/fdt/fdt_common.c
new file mode 100644
index 0000000..efbef9d
--- /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 *)®
+	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 0000000..81ce4bf
--- /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 0000000..d981d06
--- /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 0000000..caccf16
--- /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 */
diff --git a/freebsd/sys/dev/ofw/ofw_bus.h b/freebsd/sys/dev/ofw/ofw_bus.h
new file mode 100644
index 0000000..dff9a2b
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_bus.h
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2001, 2003 by Thomas Moestl <tmm at FreeBSD.org>
+ * Copyright (c) 2004 by Marius Strobl <marius 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 ``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_OFW_BUS_H_
+#define	_DEV_OFW_OFW_BUS_H_
+
+#include <sys/bus.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <rtems/bsd/local/ofw_bus_if.h>
+
+static __inline const char *
+ofw_bus_get_compat(device_t dev)
+{
+
+	return (OFW_BUS_GET_COMPAT(device_get_parent(dev), dev));
+}
+
+static __inline const char *
+ofw_bus_get_model(device_t dev)
+{
+
+	return (OFW_BUS_GET_MODEL(device_get_parent(dev), dev));
+}
+
+static __inline const char *
+ofw_bus_get_name(device_t dev)
+{
+
+	return (OFW_BUS_GET_NAME(device_get_parent(dev), dev));
+}
+
+static __inline phandle_t
+ofw_bus_get_node(device_t dev)
+{
+
+	return (OFW_BUS_GET_NODE(device_get_parent(dev), dev));
+}
+
+static __inline const char *
+ofw_bus_get_type(device_t dev)
+{
+
+	return (OFW_BUS_GET_TYPE(device_get_parent(dev), dev));
+}
+
+static __inline int
+ofw_bus_map_intr(device_t dev, phandle_t iparent, int icells, pcell_t *intr)
+{
+	return (OFW_BUS_MAP_INTR(dev, dev, iparent, icells, intr));
+}
+
+#endif /* !_DEV_OFW_OFW_BUS_H_ */
diff --git a/freebsd/sys/dev/ofw/ofw_bus_subr.c b/freebsd/sys/dev/ofw/ofw_bus_subr.c
new file mode 100644
index 0000000..79852af
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_bus_subr.c
@@ -0,0 +1,953 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm at FreeBSD.org>.
+ * Copyright (c) 2005 Marius Strobl <marius 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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/local/opt_platform.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <rtems/bsd/sys/errno.h>
+#include <sys/libkern.h>
+
+#include <machine/resource.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>
+
+#define	OFW_COMPAT_LEN	255
+
+int
+ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
+{
+
+	if (obd == NULL)
+		return (ENOMEM);
+	/* The 'name' property is considered mandatory. */
+	if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1)
+		return (EINVAL);
+	OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat);
+	OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type);
+	OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model);
+	OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status);
+	obd->obd_node = node;
+	return (0);
+}
+
+void
+ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
+{
+
+	if (obd == NULL)
+		return;
+	if (obd->obd_compat != NULL)
+		free(obd->obd_compat, M_OFWPROP);
+	if (obd->obd_model != NULL)
+		free(obd->obd_model, M_OFWPROP);
+	if (obd->obd_name != NULL)
+		free(obd->obd_name, M_OFWPROP);
+	if (obd->obd_type != NULL)
+		free(obd->obd_type, M_OFWPROP);
+	if (obd->obd_status != NULL)
+		free(obd->obd_status, M_OFWPROP);
+}
+
+int
+ofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf,
+    size_t buflen)
+{
+
+	if (ofw_bus_get_name(child) != NULL) {
+		strlcat(buf, "name=", buflen);
+		strlcat(buf, ofw_bus_get_name(child), buflen);
+	}
+
+	if (ofw_bus_get_compat(child) != NULL) {
+		strlcat(buf, " compat=", buflen);
+		strlcat(buf, ofw_bus_get_compat(child), buflen);
+	}
+	return (0);
+};
+
+const char *
+ofw_bus_gen_get_compat(device_t bus, device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(bus, dev);
+	if (obd == NULL)
+		return (NULL);
+	return (obd->obd_compat);
+}
+
+const char *
+ofw_bus_gen_get_model(device_t bus, device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(bus, dev);
+	if (obd == NULL)
+		return (NULL);
+	return (obd->obd_model);
+}
+
+const char *
+ofw_bus_gen_get_name(device_t bus, device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(bus, dev);
+	if (obd == NULL)
+		return (NULL);
+	return (obd->obd_name);
+}
+
+phandle_t
+ofw_bus_gen_get_node(device_t bus, device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(bus, dev);
+	if (obd == NULL)
+		return (0);
+	return (obd->obd_node);
+}
+
+const char *
+ofw_bus_gen_get_type(device_t bus, device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(bus, dev);
+	if (obd == NULL)
+		return (NULL);
+	return (obd->obd_type);
+}
+
+const char *
+ofw_bus_get_status(device_t dev)
+{
+	const struct ofw_bus_devinfo *obd;
+
+	obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev);
+	if (obd == NULL)
+		return (NULL);
+
+	return (obd->obd_status);
+}
+
+int
+ofw_bus_status_okay(device_t dev)
+{
+	const char *status;
+
+	status = ofw_bus_get_status(dev);
+	if (status == NULL || strcmp(status, "okay") == 0 ||
+	    strcmp(status, "ok") == 0)
+		return (1);
+	
+	return (0);
+}
+
+static int
+ofw_bus_node_is_compatible_int(const char *compat, int len,
+    const char *onecompat)
+{
+	int onelen, l, ret;
+
+	onelen = strlen(onecompat);
+
+	ret = 0;
+	while (len > 0) {
+		if (strlen(compat) == onelen &&
+		    strncasecmp(compat, onecompat, onelen) == 0) {
+			/* Found it. */
+			ret = 1;
+			break;
+		}
+
+		/* Slide to the next sub-string. */
+		l = strlen(compat) + 1;
+		compat += l;
+		len -= l;
+	}
+
+	return (ret);
+}
+
+int
+ofw_bus_node_is_compatible(phandle_t node, const char *compatstr)
+{
+	char compat[OFW_COMPAT_LEN];
+	int len, rv;
+
+	if ((len = OF_getproplen(node, "compatible")) <= 0)
+		return (0);
+
+	bzero(compat, OFW_COMPAT_LEN);
+
+	if (OF_getprop(node, "compatible", compat, OFW_COMPAT_LEN) < 0)
+		return (0);
+
+	rv = ofw_bus_node_is_compatible_int(compat, len, compatstr);
+
+	return (rv);
+}
+
+int
+ofw_bus_is_compatible(device_t dev, const char *onecompat)
+{
+	phandle_t node;
+	const char *compat;
+	int len;
+
+	if ((compat = ofw_bus_get_compat(dev)) == NULL)
+		return (0);
+
+	if ((node = ofw_bus_get_node(dev)) == -1)
+		return (0);
+
+	/* Get total 'compatible' prop len */
+	if ((len = OF_getproplen(node, "compatible")) <= 0)
+		return (0);
+
+	return (ofw_bus_node_is_compatible_int(compat, len, onecompat));
+}
+
+int
+ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
+{
+	const char *compat;
+	size_t len;
+
+	if ((compat = ofw_bus_get_compat(dev)) == NULL)
+		return (0);
+
+	len = strlen(compatible);
+	if (strlen(compat) == len &&
+	    strncasecmp(compat, compatible, len) == 0)
+		return (1);
+
+	return (0);
+}
+
+const struct ofw_compat_data *
+ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat)
+{
+
+	if (compat == NULL)
+		return NULL;
+
+	for (; compat->ocd_str != NULL; ++compat) {
+		if (ofw_bus_is_compatible(dev, compat->ocd_str))
+			break;
+	}
+
+	return (compat);
+}
+
+int
+ofw_bus_has_prop(device_t dev, const char *propname)
+{
+	phandle_t node;
+
+	if ((node = ofw_bus_get_node(dev)) == -1)
+		return (0);
+
+	return (OF_hasprop(node, propname));
+}
+
+void
+ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
+{
+	pcell_t addrc;
+	int msksz;
+
+	if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
+		addrc = 2;
+	ii->opi_addrc = addrc * sizeof(pcell_t);
+
+	ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1,
+	    (void **)&ii->opi_imap);
+	if (ii->opi_imapsz > 0) {
+		msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1,
+		    (void **)&ii->opi_imapmsk);
+		/*
+		 * Failure to get the mask is ignored; a full mask is used
+		 * then.  We barf on bad mask sizes, however.
+		 */
+		if (msksz != -1 && msksz != ii->opi_addrc + intrsz)
+			panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
+			    "property!");
+	}
+}
+
+int
+ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
+    int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
+    phandle_t *iparent)
+{
+	uint8_t maskbuf[regsz + pintrsz];
+	int rv;
+
+	if (ii->opi_imapsz <= 0)
+		return (0);
+	KASSERT(regsz >= ii->opi_addrc,
+	    ("ofw_bus_lookup_imap: register size too small: %d < %d",
+		regsz, ii->opi_addrc));
+	if (node != -1) {
+		rv = OF_getencprop(node, "reg", reg, regsz);
+		if (rv < regsz)
+			panic("ofw_bus_lookup_imap: cannot get reg property");
+	}
+	return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
+	    ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
+	    mintrsz, iparent));
+}
+
+/*
+ * Map an interrupt using the firmware reg, interrupt-map and
+ * interrupt-map-mask properties.
+ * The interrupt property to be mapped must be of size intrsz, and pointed to
+ * by intr.  The regs property of the node for which the mapping is done must
+ * be passed as regs. This property is an array of register specifications;
+ * the size of the address part of such a specification must be passed as
+ * physsz.  Only the first element of the property is used.
+ * imap and imapsz hold the interrupt mask and it's size.
+ * imapmsk is a pointer to the interrupt-map-mask property, which must have
+ * a size of physsz + intrsz; it may be NULL, in which case a full mask is
+ * assumed.
+ * maskbuf must point to a buffer of length physsz + intrsz.
+ * The interrupt is returned in result, which must point to a buffer of length
+ * rintrsz (which gives the expected size of the mapped interrupt).
+ * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
+ */
+int
+ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
+    void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
+    int rintrsz, phandle_t *iparent)
+{
+	phandle_t parent;
+	uint8_t *ref = maskbuf;
+	uint8_t *uiintr = intr;
+	uint8_t *uiregs = regs;
+	uint8_t *uiimapmsk = imapmsk;
+	uint8_t *mptr;
+	pcell_t paddrsz;
+	pcell_t pintrsz;
+	int i, rsz, tsz;
+
+	rsz = -1;
+	if (imapmsk != NULL) {
+		for (i = 0; i < physsz; i++)
+			ref[i] = uiregs[i] & uiimapmsk[i];
+		for (i = 0; i < intrsz; i++)
+			ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
+	} else {
+		bcopy(regs, ref, physsz);
+		bcopy(intr, ref + physsz, intrsz);
+	}
+
+	mptr = imap;
+	i = imapsz;
+	paddrsz = 0;
+	while (i > 0) {
+		bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
+#ifndef OFW_IMAP_NO_IPARENT_ADDR_CELLS
+		/*
+		 * Find if we need to read the parent address data.
+		 * CHRP-derived OF bindings, including ePAPR-compliant FDTs,
+		 * use this as an optional part of the specifier.
+		 */
+		if (OF_getencprop(OF_node_from_xref(parent),
+		    "#address-cells", &paddrsz, sizeof(paddrsz)) == -1)
+			paddrsz = 0;	/* default */
+		paddrsz *= sizeof(pcell_t);
+#endif
+
+		if (OF_searchencprop(OF_node_from_xref(parent),
+		    "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
+			pintrsz = 1;	/* default */
+		pintrsz *= sizeof(pcell_t);
+
+		/* Compute the map stride size. */
+		tsz = physsz + intrsz + sizeof(phandle_t) + paddrsz + pintrsz;
+		KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
+
+		if (bcmp(ref, mptr, physsz + intrsz) == 0) {
+			bcopy(mptr + physsz + intrsz + sizeof(parent) + paddrsz,
+			    result, MIN(rintrsz, pintrsz));
+
+			if (iparent != NULL)
+				*iparent = parent;
+			return (pintrsz/sizeof(pcell_t));
+		}
+		mptr += tsz;
+		i -= tsz;
+	}
+	return (0);
+}
+
+int
+ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent,
+    uint32_t *msi_rid)
+{
+	pcell_t *map, mask, msi_base, rid_base, rid_length;
+	ssize_t len;
+	uint32_t masked_rid, rid;
+	int err, i;
+
+	/* TODO: This should be OF_searchprop_alloc if we had it */
+	len = OF_getencprop_alloc(node, "msi-map", sizeof(*map), (void **)&map);
+	if (len < 0) {
+		if (msi_parent != NULL) {
+			*msi_parent = 0;
+			OF_getencprop(node, "msi-parent", msi_parent,
+			    sizeof(*msi_parent));
+		}
+		if (msi_rid != NULL)
+			*msi_rid = pci_rid;
+		return (0);
+	}
+
+	err = ENOENT;
+	rid = 0;
+	mask = 0xffffffff;
+	OF_getencprop(node, "msi-map-mask", &mask, sizeof(mask));
+
+	masked_rid = pci_rid & mask;
+	for (i = 0; i < len; i += 4) {
+		rid_base = map[i + 0];
+		rid_length = map[i + 3];
+
+		if (masked_rid < rid_base ||
+		    masked_rid >= (rid_base + rid_length))
+			continue;
+
+		msi_base = map[i + 2];
+
+		if (msi_parent != NULL)
+			*msi_parent = map[i + 1];
+		if (msi_rid != NULL)
+			*msi_rid = masked_rid - rid_base + msi_base;
+		err = 0;
+		break;
+	}
+
+	free(map, M_OFWPROP);
+
+	return (err);
+}
+
+int
+ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
+    struct resource_list *rl)
+{
+	uint64_t phys, size;
+	ssize_t i, j, rid, nreg, ret;
+	uint32_t *reg;
+	char *name;
+
+	/*
+	 * This may be just redundant when having ofw_bus_devinfo
+	 * but makes this routine independent of it.
+	 */
+	ret = OF_getprop_alloc(node, "name", sizeof(*name), (void **)&name);
+	if (ret == -1)
+		name = NULL;
+
+	ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
+	nreg = (ret == -1) ? 0 : ret;
+
+	if (nreg % (acells + scells) != 0) {
+		if (bootverbose)
+			device_printf(dev, "Malformed reg property on <%s>\n",
+			    (name == NULL) ? "unknown" : name);
+		nreg = 0;
+	}
+
+	for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) {
+		phys = size = 0;
+		for (j = 0; j < acells; j++) {
+			phys <<= 32;
+			phys |= reg[i + j];
+		}
+		for (j = 0; j < scells; j++) {
+			size <<= 32;
+			size |= reg[i + acells + j];
+		}
+		/* Skip the dummy reg property of glue devices like ssm(4). */
+		if (size != 0)
+			resource_list_add(rl, SYS_RES_MEMORY, rid,
+			    phys, phys + size - 1, size);
+	}
+	free(name, M_OFWPROP);
+	free(reg, M_OFWPROP);
+
+	return (0);
+}
+
+/*
+ * Get interrupt parent for given node.
+ * Returns 0 if interrupt parent doesn't exist.
+ */
+phandle_t
+ofw_bus_find_iparent(phandle_t node)
+{
+	phandle_t iparent;
+
+	if (OF_searchencprop(node, "interrupt-parent", &iparent,
+		    sizeof(iparent)) == -1) {
+		for (iparent = node; iparent != 0;
+		    iparent = OF_parent(iparent)) {
+			if (OF_hasprop(iparent, "interrupt-controller"))
+				break;
+		}
+		iparent = OF_xref_from_node(iparent);
+	}
+	return (iparent);
+}
+
+int
+ofw_bus_intr_to_rl(device_t dev, phandle_t node,
+    struct resource_list *rl, int *rlen)
+{
+	phandle_t iparent;
+	uint32_t icells, *intr;
+	int err, i, irqnum, nintr, rid;
+	boolean_t extended;
+
+	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
+	    (void **)&intr);
+	if (nintr > 0) {
+		iparent = ofw_bus_find_iparent(node);
+		if (iparent == 0) {
+			device_printf(dev, "No interrupt-parent found, "
+			    "assuming direct parent\n");
+			iparent = OF_parent(node);
+			iparent = OF_xref_from_node(iparent);
+		}
+		if (OF_searchencprop(OF_node_from_xref(iparent), 
+		    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+			device_printf(dev, "Missing #interrupt-cells "
+			    "property, assuming <1>\n");
+			icells = 1;
+		}
+		if (icells < 1 || icells > nintr) {
+			device_printf(dev, "Invalid #interrupt-cells property "
+			    "value <%d>, assuming <1>\n", icells);
+			icells = 1;
+		}
+		extended = false;
+	} else {
+		nintr = OF_getencprop_alloc(node, "interrupts-extended",
+		    sizeof(*intr), (void **)&intr);
+		if (nintr <= 0)
+			return (0);
+		extended = true;
+	}
+	err = 0;
+	rid = 0;
+	for (i = 0; i < nintr; i += icells) {
+		if (extended) {
+			iparent = intr[i++];
+			if (OF_searchencprop(OF_node_from_xref(iparent), 
+			    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+				device_printf(dev, "Missing #interrupt-cells "
+				    "property\n");
+				err = ENOENT;
+				break;
+			}
+			if (icells < 1 || (i + icells) > nintr) {
+				device_printf(dev, "Invalid #interrupt-cells "
+				    "property value <%d>\n", icells);
+				err = ERANGE;
+				break;
+			}
+		}
+		irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
+		resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
+	}
+	if (rlen != NULL)
+		*rlen = rid;
+	free(intr, M_OFWPROP);
+	return (err);
+}
+
+int
+ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid,
+    phandle_t *producer, int *ncells, pcell_t **cells)
+{
+	phandle_t iparent;
+	uint32_t icells, *intr;
+	int err, i, nintr, rid;
+	boolean_t extended;
+
+	nintr = OF_getencprop_alloc(node, "interrupts",  sizeof(*intr),
+	    (void **)&intr);
+	if (nintr > 0) {
+		iparent = ofw_bus_find_iparent(node);
+		if (iparent == 0) {
+			device_printf(dev, "No interrupt-parent found, "
+			    "assuming direct parent\n");
+			iparent = OF_parent(node);
+			iparent = OF_xref_from_node(iparent);
+		}
+		if (OF_searchencprop(OF_node_from_xref(iparent),
+		    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+			device_printf(dev, "Missing #interrupt-cells "
+			    "property, assuming <1>\n");
+			icells = 1;
+		}
+		if (icells < 1 || icells > nintr) {
+			device_printf(dev, "Invalid #interrupt-cells property "
+			    "value <%d>, assuming <1>\n", icells);
+			icells = 1;
+		}
+		extended = false;
+	} else {
+		nintr = OF_getencprop_alloc(node, "interrupts-extended",
+		    sizeof(*intr), (void **)&intr);
+		if (nintr <= 0)
+			return (ESRCH);
+		extended = true;
+	}
+	err = ESRCH;
+	rid = 0;
+	for (i = 0; i < nintr; i += icells, rid++) {
+		if (extended) {
+			iparent = intr[i++];
+			if (OF_searchencprop(OF_node_from_xref(iparent),
+			    "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+				device_printf(dev, "Missing #interrupt-cells "
+				    "property\n");
+				err = ENOENT;
+				break;
+			}
+			if (icells < 1 || (i + icells) > nintr) {
+				device_printf(dev, "Invalid #interrupt-cells "
+				    "property value <%d>\n", icells);
+				err = ERANGE;
+				break;
+			}
+		}
+		if (rid == wanted_rid) {
+			*cells = malloc(icells * sizeof(**cells), M_OFWPROP,
+			    M_WAITOK);
+			*producer = iparent;
+			*ncells= icells;
+			memcpy(*cells, intr + i, icells * sizeof(**cells));
+			err = 0;
+			break;
+		}
+	}
+	free(intr, M_OFWPROP);
+	return (err);
+}
+
+phandle_t
+ofw_bus_find_child(phandle_t start, const char *child_name)
+{
+	char *name;
+	int ret;
+	phandle_t child;
+
+	for (child = OF_child(start); child != 0; child = OF_peer(child)) {
+		ret = OF_getprop_alloc(child, "name", sizeof(*name), (void **)&name);
+		if (ret == -1)
+			continue;
+		if (strcmp(name, child_name) == 0) {
+			free(name, M_OFWPROP);
+			return (child);
+		}
+
+		free(name, M_OFWPROP);
+	}
+
+	return (0);
+}
+
+phandle_t
+ofw_bus_find_compatible(phandle_t node, const char *onecompat)
+{
+	phandle_t child, ret;
+	void *compat;
+	int len;
+
+	/*
+	 * Traverse all children of 'start' node, and find first with
+	 * matching 'compatible' property.
+	 */
+	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+		len = OF_getprop_alloc(child, "compatible", 1, &compat);
+		if (len >= 0) {
+			ret = ofw_bus_node_is_compatible_int(compat, len,
+			    onecompat);
+			free(compat, M_OFWPROP);
+			if (ret != 0)
+				return (child);
+		}
+
+		ret = ofw_bus_find_compatible(child, onecompat);
+		if (ret != 0)
+			return (ret);
+	}
+	return (0);
+}
+
+/**
+ * @brief Return child of bus whose phandle is node
+ *
+ * A direct child of @p will be returned if it its phandle in the
+ * OFW tree is @p node. Otherwise, NULL is returned.
+ *
+ * @param bus		The bus to examine
+ * @param node		The phandle_t to look for.
+ */
+device_t
+ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node)
+{
+	device_t *children, retval, child;
+	int nkid, i;
+
+	/*
+	 * Nothing can match the flag value for no node.
+	 */
+	if (node == -1)
+		return (NULL);
+
+	/*
+	 * Search the children for a match. We microoptimize
+	 * a bit by not using ofw_bus_get since we already know
+	 * the parent. We do not recurse.
+	 */
+	if (device_get_children(bus, &children, &nkid) != 0)
+		return (NULL);
+	retval = NULL;
+	for (i = 0; i < nkid; i++) {
+		child = children[i];
+		if (OFW_BUS_GET_NODE(bus, child) == node) {
+			retval = child;
+			break;
+		}
+	}
+	free(children, M_TEMP);
+
+	return (retval);
+}
+
+/*
+ * Parse property that contain list of xrefs and values
+ * (like standard "clocks" and "resets" properties)
+ * Input arguments:
+ *  node - consumers device node
+ *  list_name  - name of parsed list - "clocks"
+ *  cells_name - name of size property - "#clock-cells"
+ *  idx - the index of the requested list entry, or, if -1, an indication
+ *        to return the number of entries in the parsed list.
+ * Output arguments:
+ *  producer - handle of producer
+ *  ncells   - number of cells in result or the number of items in the list when
+ *             idx == -1.
+ *  cells    - array of decoded cells
+ */
+static int
+ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name,
+    const char *cells_name, int idx, phandle_t *producer, int *ncells,
+    pcell_t **cells)
+{
+	phandle_t pnode;
+	phandle_t *elems;
+	uint32_t  pcells;
+	int rv, i, j, nelems, cnt;
+
+	elems = NULL;
+	nelems = OF_getencprop_alloc(node, list_name,  sizeof(*elems),
+	    (void **)&elems);
+	if (nelems <= 0)
+		return (ENOENT);
+	rv = (idx == -1) ? 0 : ENOENT;
+	for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) {
+		pnode = elems[i++];
+		if (OF_getencprop(OF_node_from_xref(pnode),
+		    cells_name, &pcells, sizeof(pcells)) == -1) {
+			printf("Missing %s property\n", cells_name);
+			rv = ENOENT;
+			break;
+		}
+
+		if ((i + pcells) > nelems) {
+			printf("Invalid %s property value <%d>\n", cells_name,
+			    pcells);
+			rv = ERANGE;
+			break;
+		}
+		if (cnt == idx) {
+			*cells= malloc(pcells * sizeof(**cells), M_OFWPROP,
+			    M_WAITOK);
+			*producer = pnode;
+			*ncells = pcells;
+			for (j = 0; j < pcells; j++)
+				(*cells)[j] = elems[i + j];
+			rv = 0;
+			break;
+		}
+	}
+	if (elems != NULL)
+		free(elems, M_OFWPROP);
+	if (idx == -1 && rv == 0)
+		*ncells = cnt;
+	return (rv);
+}
+
+/*
+ * Parse property that contain list of xrefs and values
+ * (like standard "clocks" and "resets" properties)
+ * Input arguments:
+ *  node - consumers device node
+ *  list_name  - name of parsed list - "clocks"
+ *  cells_name - name of size property - "#clock-cells"
+ *  idx - the index of the requested list entry (>= 0)
+ * Output arguments:
+ *  producer - handle of producer
+ *  ncells   - number of cells in result
+ *  cells    - array of decoded cells
+ */
+int
+ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
+    const char *cells_name, int idx, phandle_t *producer, int *ncells,
+    pcell_t **cells)
+{
+
+	KASSERT(idx >= 0,
+	    ("ofw_bus_parse_xref_list_alloc: negative index supplied"));
+
+	return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
+		    idx, producer, ncells, cells));
+}
+
+/*
+ * Parse property that contain list of xrefs and values
+ * (like standard "clocks" and "resets" properties)
+ * and determine the number of items in the list
+ * Input arguments:
+ *  node - consumers device node
+ *  list_name  - name of parsed list - "clocks"
+ *  cells_name - name of size property - "#clock-cells"
+ * Output arguments:
+ *  count - number of items in list
+ */
+int
+ofw_bus_parse_xref_list_get_length(phandle_t node, const char *list_name,
+    const char *cells_name, int *count)
+{
+
+	return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
+		    -1, NULL, count, NULL));
+}
+
+/*
+ * Find index of string in string list property (case sensitive).
+ */
+int
+ofw_bus_find_string_index(phandle_t node, const char *list_name,
+    const char *name, int *idx)
+{
+	char *elems;
+	int rv, i, cnt, nelems;
+
+	elems = NULL;
+	nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems);
+	if (nelems <= 0)
+		return (ENOENT);
+
+	rv = ENOENT;
+	for (i = 0, cnt = 0; i < nelems; cnt++) {
+		if (strcmp(elems + i, name) == 0) {
+			*idx = cnt;
+			rv = 0;
+			break;
+		}
+		i += strlen(elems + i) + 1;
+	}
+
+	if (elems != NULL)
+		free(elems, M_OFWPROP);
+	return (rv);
+}
+
+/*
+ * Create zero terminated array of strings from string list property.
+ */
+int
+ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
+   const char ***out_array)
+{
+	char *elems, *tptr;
+	const char **array;
+	int i, cnt, nelems, len;
+
+	elems = NULL;
+	nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems);
+	if (nelems <= 0)
+		return (nelems);
+
+	/* Count number of strings. */
+	for (i = 0, cnt = 0; i < nelems; cnt++)
+		i += strlen(elems + i) + 1;
+
+	/* Allocate space for arrays and all strings. */
+	array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP,
+	    M_WAITOK);
+
+	/* Get address of first string. */
+	tptr = (char *)(array + cnt + 1);
+
+	/* Copy strings. */
+	memcpy(tptr, elems, nelems);
+	free(elems, M_OFWPROP);
+
+	/* Fill string pointers. */
+	for (i = 0, cnt = 0; i < nelems; cnt++) {
+		len = strlen(tptr) + 1;
+		array[cnt] = tptr;
+		i += len;
+		tptr += len;
+	}
+	array[cnt] = 0;
+	*out_array = array;
+
+	return (cnt);
+}
diff --git a/freebsd/sys/dev/ofw/ofw_bus_subr.h b/freebsd/sys/dev/ofw/ofw_bus_subr.h
new file mode 100644
index 0000000..30f299a
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_bus_subr.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2005 Marius Strobl <marius 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,
+ *    without modification, immediately at the beginning of the file.
+ * 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_OFW_BUS_SUBR_H_
+#define	_DEV_OFW_OFW_BUS_SUBR_H_
+
+#include <sys/bus.h>
+#ifdef INTRNG
+#include <sys/intr.h>
+#endif
+#include <dev/ofw/openfirm.h>
+
+#include <rtems/bsd/local/ofw_bus_if.h>
+
+#define	ORIP_NOINT	-1
+#define	ORIR_NOTFOUND	0xffffffff
+
+struct ofw_bus_iinfo {
+	uint8_t			*opi_imap;
+	uint8_t			*opi_imapmsk;
+	int			opi_imapsz;
+	pcell_t			opi_addrc;
+};
+
+struct ofw_compat_data {
+	const char	*ocd_str;
+	uintptr_t	 ocd_data;
+};
+
+#ifdef INTRNG
+struct intr_map_data_fdt {
+	struct intr_map_data	hdr;
+	phandle_t		iparent;
+	u_int			ncells;
+	pcell_t			cells[];
+};
+#endif
+
+#define SIMPLEBUS_PNP_DESCR "Z:compat;P:private;"
+#define SIMPLEBUS_PNP_INFO(t) \
+	MODULE_PNP_INFO(SIMPLEBUS_PNP_DESCR, simplebus, t, t, sizeof(t[0]), sizeof(t) / sizeof(t[0]));
+
+/* Generic implementation of ofw_bus_if.m methods and helper routines */
+int	ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *, phandle_t);
+void	ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *);
+
+ofw_bus_get_compat_t	ofw_bus_gen_get_compat;
+ofw_bus_get_model_t	ofw_bus_gen_get_model;
+ofw_bus_get_name_t	ofw_bus_gen_get_name;
+ofw_bus_get_node_t	ofw_bus_gen_get_node;
+ofw_bus_get_type_t	ofw_bus_gen_get_type;
+
+/* Helper method to report interesting OF properties in pnpinfo */
+bus_child_pnpinfo_str_t	ofw_bus_gen_child_pnpinfo_str;
+
+/* Routines for processing firmware interrupt maps */
+void	ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int);
+int	ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int,
+	    void *, int, void *, int, phandle_t *);
+int	ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *,
+	    void *, void *, int, phandle_t *);
+
+/* Routines for processing msi maps */
+int ofw_bus_msimap(phandle_t, uint16_t, phandle_t *, uint32_t *);
+
+/* Routines for parsing device-tree data into resource lists. */
+int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t,
+    struct resource_list *);
+int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *, int *);
+int ofw_bus_intr_by_rid(device_t, phandle_t, int, phandle_t *, int *,
+    pcell_t **);
+
+/* Helper to get device status property */
+const char *ofw_bus_get_status(device_t dev);
+int ofw_bus_status_okay(device_t dev);
+
+/* Helper to get node's interrupt parent */
+phandle_t ofw_bus_find_iparent(phandle_t);
+
+/* Helper routine for checking compat prop */
+int ofw_bus_is_compatible(device_t, const char *);
+int ofw_bus_is_compatible_strict(device_t, const char *);
+int ofw_bus_node_is_compatible(phandle_t, const char *);
+
+/* 
+ * Helper routine to search a list of compat properties.  The table is
+ * terminated by an entry with a NULL compat-string pointer; a pointer to that
+ * table entry is returned if none of the compat strings match for the device,
+ * giving you control over the not-found value.  Will not return NULL unless the
+ * provided table pointer is NULL.
+ */
+const struct ofw_compat_data *
+    ofw_bus_search_compatible(device_t, const struct ofw_compat_data *);
+
+/* Helper routine for checking existence of a prop */
+int ofw_bus_has_prop(device_t, const char *);
+
+/* Helper to search for a child with a given compat prop */
+phandle_t ofw_bus_find_compatible(phandle_t, const char *);
+
+/* Helper to search for a child with a given name */
+phandle_t ofw_bus_find_child(phandle_t, const char *);
+
+/* Helper routine to find a device_t child matching a given phandle_t */
+device_t ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node);
+
+/* Helper routines for parsing lists  */
+int ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
+    const char *cells_name, int idx, phandle_t *producer, int *ncells,
+    pcell_t **cells);
+int ofw_bus_parse_xref_list_get_length(phandle_t node, const char *list_name,
+    const char *cells_name, int *count);
+int ofw_bus_find_string_index(phandle_t node, const char *list_name,
+    const char *name, int *idx);
+int ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
+    const char ***array);
+
+#endif /* !_DEV_OFW_OFW_BUS_SUBR_H_ */
diff --git a/freebsd/sys/dev/ofw/ofw_fdt.c b/freebsd/sys/dev/ofw/ofw_fdt.c
new file mode 100644
index 0000000..6bdaf89
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_fdt.c
@@ -0,0 +1,490 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <contrib/libfdt/libfdt.h>
+
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofwvar.h>
+#include <dev/ofw/openfirm.h>
+
+#include <rtems/bsd/local/ofw_if.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#if defined(__arm__)
+#if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) || \
+    defined(SOC_MV_DISCOVERY) || defined(SOC_MV_DOVE) || \
+    defined(SOC_MV_FREY) || defined(SOC_MV_KIRKWOOD) || \
+    defined(SOC_MV_LOKIPLUS) || defined(SOC_MV_ORION)
+#define FDT_MARVELL
+#endif
+#endif
+
+static int ofw_fdt_init(ofw_t, void *);
+static phandle_t ofw_fdt_peer(ofw_t, phandle_t);
+static phandle_t ofw_fdt_child(ofw_t, phandle_t);
+static phandle_t ofw_fdt_parent(ofw_t, phandle_t);
+static phandle_t ofw_fdt_instance_to_package(ofw_t, ihandle_t);
+static ssize_t ofw_fdt_getproplen(ofw_t, phandle_t, const char *);
+static ssize_t ofw_fdt_getprop(ofw_t, phandle_t, const char *, void *, size_t);
+static int ofw_fdt_nextprop(ofw_t, phandle_t, const char *, char *, size_t);
+static int ofw_fdt_setprop(ofw_t, phandle_t, const char *, const void *,
+    size_t);
+static ssize_t ofw_fdt_canon(ofw_t, const char *, char *, size_t);
+static phandle_t ofw_fdt_finddevice(ofw_t, const char *);
+static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t);
+static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t);
+static int ofw_fdt_interpret(ofw_t, const char *, int, cell_t *);
+
+static ofw_method_t ofw_fdt_methods[] = {
+	OFWMETHOD(ofw_init,			ofw_fdt_init),
+	OFWMETHOD(ofw_peer,			ofw_fdt_peer),
+	OFWMETHOD(ofw_child,			ofw_fdt_child),
+	OFWMETHOD(ofw_parent,			ofw_fdt_parent),
+	OFWMETHOD(ofw_instance_to_package,	ofw_fdt_instance_to_package),
+	OFWMETHOD(ofw_getproplen,		ofw_fdt_getproplen),
+	OFWMETHOD(ofw_getprop,			ofw_fdt_getprop),
+	OFWMETHOD(ofw_nextprop,			ofw_fdt_nextprop),
+	OFWMETHOD(ofw_setprop,			ofw_fdt_setprop),
+	OFWMETHOD(ofw_canon,			ofw_fdt_canon),
+	OFWMETHOD(ofw_finddevice,		ofw_fdt_finddevice),
+	OFWMETHOD(ofw_instance_to_path,		ofw_fdt_instance_to_path),
+	OFWMETHOD(ofw_package_to_path,		ofw_fdt_package_to_path),
+	OFWMETHOD(ofw_interpret,		ofw_fdt_interpret),
+	{ 0, 0 }
+};
+
+static ofw_def_t ofw_fdt = {
+	OFW_FDT,
+	ofw_fdt_methods,
+	0
+};
+OFW_DEF(ofw_fdt);
+
+static void *fdtp = NULL;
+
+static int
+sysctl_handle_dtb(SYSCTL_HANDLER_ARGS)
+{
+
+        return (sysctl_handle_opaque(oidp, fdtp, fdt_totalsize(fdtp), req));
+}
+
+static void
+sysctl_register_fdt_oid(void *arg)
+{
+
+	/* If there is no FDT registered, skip adding the sysctl */
+	if (fdtp == NULL)
+		return;
+
+	SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_fdt), OID_AUTO, "dtb",
+	    CTLTYPE_OPAQUE | CTLFLAG_RD, NULL, 0, sysctl_handle_dtb, "",
+	    "Device Tree Blob");
+}
+SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, 0);
+
+static int
+ofw_fdt_init(ofw_t ofw, void *data)
+{
+	int err;
+
+	/* Check FDT blob integrity */
+	if ((err = fdt_check_header(data)) != 0)
+		return (err);
+
+	fdtp = data;
+	return (0);
+}
+
+/*
+ * Device tree functions.
+ *
+ * We use the offset from fdtp to the node as the 'phandle' in OF interface.
+ *
+ * phandle is a u32 value, therefore we cannot use the pointer to node as
+ * phandle in 64 bit. We also do not use the usual fdt offset as phandle,
+ * as it can be 0, and the OF interface has special meaning for phandle 0.
+ */
+
+static phandle_t
+fdt_offset_phandle(int offset)
+{
+	if (offset < 0)
+		return (0);
+	return ((phandle_t)offset + fdt_off_dt_struct(fdtp));
+}
+
+static int
+fdt_phandle_offset(phandle_t p)
+{
+	int pint = (int)p;
+	int dtoff = fdt_off_dt_struct(fdtp);
+
+	if (pint < dtoff)
+		return (-1);
+	return (pint - dtoff);
+}
+
+/* Return the next sibling of this node or 0. */
+static phandle_t
+ofw_fdt_peer(ofw_t ofw, phandle_t node)
+{
+	int depth, offset;
+
+	if (node == 0) {
+		/* Find root node */
+		offset = fdt_path_offset(fdtp, "/");
+
+		return (fdt_offset_phandle(offset));
+	}
+
+	offset = fdt_phandle_offset(node);
+	if (offset < 0)
+		return (0);
+
+	for (depth = 1, offset = fdt_next_node(fdtp, offset, &depth);
+	    offset >= 0;
+	    offset = fdt_next_node(fdtp, offset, &depth)) {
+		if (depth < 0)
+			return (0);
+		if (depth == 1)
+			return (fdt_offset_phandle(offset));
+	}
+
+	return (0);
+}
+
+/* Return the first child of this node or 0. */
+static phandle_t
+ofw_fdt_child(ofw_t ofw, phandle_t node)
+{
+	int depth, offset;
+
+	offset = fdt_phandle_offset(node);
+	if (offset < 0)
+		return (0);
+
+	for (depth = 0, offset = fdt_next_node(fdtp, offset, &depth);
+	    (offset >= 0) && (depth > 0);
+	    offset = fdt_next_node(fdtp, offset, &depth)) {
+		if (depth < 0)
+			return (0);
+		if (depth == 1)
+			return (fdt_offset_phandle(offset));
+	}
+
+	return (0);
+}
+
+/* Return the parent of this node or 0. */
+static phandle_t
+ofw_fdt_parent(ofw_t ofw, phandle_t node)
+{
+	int offset, paroffset;
+
+	offset = fdt_phandle_offset(node);
+	if (offset < 0)
+		return (0);
+
+	paroffset = fdt_parent_offset(fdtp, offset);
+	return (fdt_offset_phandle(paroffset));
+}
+
+/* Return the package handle that corresponds to an instance handle. */
+static phandle_t
+ofw_fdt_instance_to_package(ofw_t ofw, ihandle_t instance)
+{
+
+	/* Where real OF uses ihandles in the tree, FDT uses xref phandles */
+	return (OF_node_from_xref(instance));
+}
+
+/* Get the length of a property of a package. */
+static ssize_t
+ofw_fdt_getproplen(ofw_t ofw, phandle_t package, const char *propname)
+{
+	const struct fdt_property *prop;
+	int offset, len;
+
+	offset = fdt_phandle_offset(package);
+	if (offset < 0)
+		return (-1);
+
+	len = -1;
+	prop = fdt_get_property(fdtp, offset, propname, &len);
+
+	if (prop == NULL && strcmp(propname, "name") == 0) {
+		/* Emulate the 'name' property */
+		fdt_get_name(fdtp, offset, &len);
+		return (len + 1);
+	}
+
+	if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
+		if (strcmp(propname, "fdtbootcpu") == 0)
+			return (sizeof(cell_t));
+		if (strcmp(propname, "fdtmemreserv") == 0)
+			return (sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp));
+	}
+
+	if (prop == NULL)
+		return (-1);
+
+	return (len);
+}
+
+/* Get the value of a property of a package. */
+static ssize_t
+ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf,
+    size_t buflen)
+{
+	const void *prop;
+	const char *name;
+	int len, offset;
+	uint32_t cpuid;
+
+	offset = fdt_phandle_offset(package);
+	if (offset < 0)
+		return (-1);
+
+	prop = fdt_getprop(fdtp, offset, propname, &len);
+
+	if (prop == NULL && strcmp(propname, "name") == 0) {
+		/* Emulate the 'name' property */
+		name = fdt_get_name(fdtp, offset, &len);
+		strncpy(buf, name, buflen);
+		if (len + 1 > buflen)
+			len = buflen;
+		return (len + 1);
+	}
+
+	if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) {
+		if (strcmp(propname, "fdtbootcpu") == 0) {
+			cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp));
+			len = sizeof(cpuid);
+			prop = &cpuid;
+		}
+		if (strcmp(propname, "fdtmemreserv") == 0) {
+			prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp);
+			len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp);
+		}
+	}
+
+	if (prop == NULL)
+		return (-1);
+
+	if (len > buflen)
+		len = buflen;
+	bcopy(prop, buf, len);
+	return (len);
+}
+
+/*
+ * Get the next property of a package. Return values:
+ *  -1: package or previous property does not exist
+ *   0: no more properties
+ *   1: success
+ */
+static int
+ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf,
+    size_t size)
+{
+	const struct fdt_property *prop;
+	const char *name;
+	int offset;
+
+	offset = fdt_phandle_offset(package);
+	if (offset < 0)
+		return (-1);
+
+	/* Find the first prop in the node */
+	offset = fdt_first_property_offset(fdtp, offset);
+	if (offset < 0)
+		return (0); /* No properties */
+
+	if (previous != NULL) {
+		while (offset >= 0) {
+			prop = fdt_get_property_by_offset(fdtp, offset, NULL);
+			if (prop == NULL)
+				return (-1); /* Internal error */
+
+			offset = fdt_next_property_offset(fdtp, offset);
+			if (offset < 0)
+				return (0); /* No more properties */
+
+			/* Check if the last one was the one we wanted */
+			name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
+			if (strcmp(name, previous) == 0)
+				break;
+		}
+	}
+
+	prop = fdt_get_property_by_offset(fdtp, offset, &offset);
+	if (prop == NULL)
+		return (-1); /* Internal error */
+
+	strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size);
+
+	return (1);
+}
+
+/* Set the value of a property of a package. */
+static int
+ofw_fdt_setprop(ofw_t ofw, phandle_t package, const char *propname,
+    const void *buf, size_t len)
+{
+	int offset;
+
+	offset = fdt_phandle_offset(package);
+	if (offset < 0)
+		return (-1);
+
+	return (fdt_setprop_inplace(fdtp, offset, propname, buf, len));
+}
+
+/* Convert a device specifier to a fully qualified pathname. */
+static ssize_t
+ofw_fdt_canon(ofw_t ofw, const char *device, char *buf, size_t len)
+{
+
+	return (-1);
+}
+
+/* Return a package handle for the specified device. */
+static phandle_t
+ofw_fdt_finddevice(ofw_t ofw, const char *device)
+{
+	int offset;
+
+	offset = fdt_path_offset(fdtp, device);
+	if (offset < 0)
+		return (-1);
+	return (fdt_offset_phandle(offset));
+}
+
+/* Return the fully qualified pathname corresponding to an instance. */
+static ssize_t
+ofw_fdt_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len)
+{
+	phandle_t phandle;
+
+	phandle = OF_instance_to_package(instance);
+	if (phandle == -1)
+		return (-1);
+
+	return (OF_package_to_path(phandle, buf, len));
+}
+
+/* Return the fully qualified pathname corresponding to a package. */
+static ssize_t
+ofw_fdt_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len)
+{
+
+	return (-1);
+}
+
+#if defined(FDT_MARVELL) || defined(__powerpc__)
+static int
+ofw_fdt_fixup(ofw_t ofw)
+{
+#define FDT_MODEL_LEN	80
+	char model[FDT_MODEL_LEN];
+	phandle_t root;
+	ssize_t len;
+	int i;
+
+	if ((root = ofw_fdt_finddevice(ofw, "/")) == -1)
+		return (ENODEV);
+
+	if ((len = ofw_fdt_getproplen(ofw, root, "model")) <= 0)
+		return (0);
+
+	bzero(model, FDT_MODEL_LEN);
+	if (ofw_fdt_getprop(ofw, root, "model", model, FDT_MODEL_LEN) <= 0)
+		return (0);
+
+	/*
+	 * Search fixup table and call handler if appropriate.
+	 */
+	for (i = 0; fdt_fixup_table[i].model != NULL; i++) {
+		if (strncmp(model, fdt_fixup_table[i].model,
+		    FDT_MODEL_LEN) != 0)
+			continue;
+
+		if (fdt_fixup_table[i].handler != NULL)
+			(*fdt_fixup_table[i].handler)(root);
+	}
+
+	return (0);
+}
+#endif
+
+static int
+ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, cell_t *retvals)
+{
+#if defined(FDT_MARVELL) || defined(__powerpc__)
+	int rv;
+
+	/*
+	 * Note: FDT does not have the possibility to 'interpret' commands,
+	 * but we abuse the interface a bit to use it for doing non-standard
+	 * operations on the device tree blob.
+	 *
+	 * Currently the only supported 'command' is to trigger performing
+	 * fixups.
+	 */
+	if (strncmp("perform-fixup", cmd, 13) != 0)
+		return (0);
+
+	rv = ofw_fdt_fixup(ofw);
+	if (nret > 0)
+		retvals[0] = rv;
+
+	return (rv);
+#else
+	return (0);
+#endif
+}
diff --git a/freebsd/sys/dev/ofw/ofw_pci.h b/freebsd/sys/dev/ofw/ofw_pci.h
new file mode 100644
index 0000000..eb60c5b
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_pci.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ *
+ *	from: NetBSD: ofw_pci.h,v 1.5 2003/10/22 09:04:39 mjl Exp
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_OFW_OFW_PCI_H_
+#define	_DEV_OFW_OFW_PCI_H_
+
+/*
+ * PCI Bus Binding to:
+ *
+ * IEEE Std 1275-1994
+ * Standard for Boot (Initialization Configuration) Firmware
+ *
+ * Revision 2.1
+ */
+
+/*
+ * Section 2.2.1. Physical Address Formats
+ *
+ * A PCI physical address is represented by 3 address cells:
+ *
+ *	phys.hi cell:	npt000ss bbbbbbbb dddddfff rrrrrrrr
+ *	phys.mid cell:	hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh
+ *	phys.lo cell:	llllllll llllllll llllllll llllllll
+ *
+ *	n	nonrelocatable
+ *	p	prefetchable
+ *	t	aliased below 1MB (memory) or 64k (i/o)
+ *	ss	space code
+ *	b	bus number
+ *	d	device number
+ *	f	function number
+ *	r	register number
+ *	h	high 32-bits of PCI address
+ *	l	low 32-bits of PCI address
+ */
+
+#define	OFW_PCI_PHYS_HI_NONRELOCATABLE	0x80000000
+#define	OFW_PCI_PHYS_HI_PREFETCHABLE	0x40000000
+#define	OFW_PCI_PHYS_HI_ALIASED		0x20000000
+#define	OFW_PCI_PHYS_HI_SPACEMASK	0x03000000
+#define	OFW_PCI_PHYS_HI_BUSMASK		0x00ff0000
+#define	OFW_PCI_PHYS_HI_BUSSHIFT	16
+#define	OFW_PCI_PHYS_HI_DEVICEMASK	0x0000f800
+#define	OFW_PCI_PHYS_HI_DEVICESHIFT	11
+#define	OFW_PCI_PHYS_HI_FUNCTIONMASK	0x00000700
+#define	OFW_PCI_PHYS_HI_FUNCTIONSHIFT	8
+#define	OFW_PCI_PHYS_HI_REGISTERMASK	0x000000ff
+
+#define	OFW_PCI_PHYS_HI_SPACE_CONFIG	0x00000000
+#define	OFW_PCI_PHYS_HI_SPACE_IO	0x01000000
+#define	OFW_PCI_PHYS_HI_SPACE_MEM32	0x02000000
+#define	OFW_PCI_PHYS_HI_SPACE_MEM64	0x03000000
+
+#define OFW_PCI_PHYS_HI_BUS(hi) \
+	(((hi) & OFW_PCI_PHYS_HI_BUSMASK) >> OFW_PCI_PHYS_HI_BUSSHIFT)
+#define OFW_PCI_PHYS_HI_DEVICE(hi) \
+	(((hi) & OFW_PCI_PHYS_HI_DEVICEMASK) >> OFW_PCI_PHYS_HI_DEVICESHIFT)
+#define OFW_PCI_PHYS_HI_FUNCTION(hi) \
+	(((hi) & OFW_PCI_PHYS_HI_FUNCTIONMASK) >> OFW_PCI_PHYS_HI_FUNCTIONSHIFT)
+
+/*
+ * This has the 3 32bit cell values, plus 2 more to make up a 64-bit size.
+ */
+struct ofw_pci_register {
+	u_int32_t	phys_hi;
+	u_int32_t	phys_mid;
+	u_int32_t	phys_lo;
+	u_int32_t	size_hi;
+	u_int32_t	size_lo;
+};
+
+#endif /* _DEV_OFW_OFW_PCI_H_ */
diff --git a/freebsd/sys/dev/ofw/ofw_subr.c b/freebsd/sys/dev/ofw/ofw_subr.c
new file mode 100644
index 0000000..391d25c
--- /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 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.
+ *
+ * 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);
+}
diff --git a/freebsd/sys/dev/ofw/ofw_subr.h b/freebsd/sys/dev/ofw/ofw_subr.h
new file mode 100644
index 0000000..ed29142
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_subr.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2015 Ian Lepore <ian 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_DEV_OFW_OFW_SUBR_H_
+#define	_DEV_OFW_OFW_SUBR_H_
+
+/*
+ * Translate an address from the Nth tuple of a device node's reg properties to
+ * a physical memory address, by applying the range mappings from all ancestors.
+ * This assumes that all ancestor ranges are simple numerical offsets for which
+ * addition and subtraction operations will perform the required mapping (the
+ * bit-options in the high word of standard PCI properties are also handled).
+ * After the call, *pci_hi (if non-NULL) contains the phys.hi cell of the
+ * device's parent PCI bus, or OFW_PADDR_NOT_PCI if no PCI bus is involved.
+ *
+ * This is intended to be a helper function called by the platform-specific
+ * implementation of OF_decode_addr(), and not for direct use by device drivers.
+ */
+#define	OFW_PADDR_NOT_PCI	(~0)
+
+int ofw_reg_to_paddr(phandle_t _dev, int _regno, bus_addr_t *_paddr,
+    bus_size_t *_size, pcell_t *_pci_hi);
+
+int ofw_parse_bootargs(void);
+
+#endif
diff --git a/freebsd/sys/dev/ofw/ofwbus.c b/freebsd/sys/dev/ofw/ofwbus.c
new file mode 100644
index 0000000..58ec284
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofwbus.c
@@ -0,0 +1,297 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright 1998 Massachusetts Institute of Technology
+ * Copyright 2001 by Thomas Moestl <tmm at FreeBSD.org>.
+ * Copyright 2006 by Marius Strobl <marius at FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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/i386/i386/nexus.c,v 1.43 2001/02/09
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+#ifdef INTRNG
+#include <sys/intr.h>
+#endif
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/fdt/simplebus.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+/*
+ * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that
+ * hang from the Open Firmware root node and adds them as devices to this bus
+ * (except some special nodes which are excluded) so that drivers can be
+ * attached to them.
+ *
+ */
+
+struct ofwbus_softc {
+	struct simplebus_softc simplebus_sc;
+	struct rman	sc_intr_rman;
+	struct rman	sc_mem_rman;
+};
+
+#ifndef __aarch64__
+static device_identify_t ofwbus_identify;
+#endif
+static device_probe_t ofwbus_probe;
+static device_attach_t ofwbus_attach;
+static bus_alloc_resource_t ofwbus_alloc_resource;
+static bus_adjust_resource_t ofwbus_adjust_resource;
+static bus_release_resource_t ofwbus_release_resource;
+
+static device_method_t ofwbus_methods[] = {
+	/* Device interface */
+#ifndef __aarch64__
+	DEVMETHOD(device_identify,	ofwbus_identify),
+#endif
+	DEVMETHOD(device_probe,		ofwbus_probe),
+	DEVMETHOD(device_attach,	ofwbus_attach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_alloc_resource,	ofwbus_alloc_resource),
+	DEVMETHOD(bus_adjust_resource,	ofwbus_adjust_resource),
+	DEVMETHOD(bus_release_resource,	ofwbus_release_resource),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods,
+    sizeof(struct ofwbus_softc), simplebus_driver);
+static devclass_t ofwbus_devclass;
+EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0,
+    BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofwbus, 1);
+
+#ifndef __aarch64__
+static void
+ofwbus_identify(driver_t *driver, device_t parent)
+{
+
+	/* Check if Open Firmware has been instantiated */
+	if (OF_peer(0) == 0)
+		return;
+
+	if (device_find_child(parent, "ofwbus", -1) == NULL)
+		BUS_ADD_CHILD(parent, 0, "ofwbus", -1);
+}
+#endif
+
+static int
+ofwbus_probe(device_t dev)
+{
+
+#ifdef __aarch64__
+	if (OF_peer(0) == 0)
+		return (ENXIO);
+#endif
+
+	device_set_desc(dev, "Open Firmware Device Tree");
+	return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+ofwbus_attach(device_t dev)
+{
+	struct ofwbus_softc *sc;
+	phandle_t node;
+	struct ofw_bus_devinfo obd;
+
+	sc = device_get_softc(dev);
+
+	node = OF_peer(0);
+
+	/*
+	 * If no Open Firmware, bail early
+	 */
+	if (node == -1)
+		return (ENXIO);
+
+	/*
+	 * ofwbus bus starts on unamed node in FDT, so we cannot make
+	 * ofw_bus_devinfo from it. Pass node to simplebus_init directly.
+	 */
+	simplebus_init(dev, node);
+	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
+	sc->sc_intr_rman.rm_descr = "Interrupts";
+	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+	sc->sc_mem_rman.rm_descr = "Device Memory";
+	if (rman_init(&sc->sc_intr_rman) != 0 ||
+	    rman_init(&sc->sc_mem_rman) != 0 ||
+	    rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 ||
+	    rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0)
+		panic("%s: failed to set up rmans.", __func__);
+
+	/*
+	 * Allow devices to identify.
+	 */
+	bus_generic_probe(dev);
+
+	/*
+	 * Now walk the OFW tree and attach top-level devices.
+	 */
+	for (node = OF_child(node); node > 0; node = OF_peer(node)) {
+		if (ofw_bus_gen_setup_devinfo(&obd, node) != 0)
+			continue;
+		simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+	}
+	return (bus_generic_attach(dev));
+}
+
+static struct resource *
+ofwbus_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 ofwbus_softc *sc;
+	struct rman *rm;
+	struct resource *rv;
+	struct resource_list_entry *rle;
+	int isdefault, passthrough;
+
+	isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
+	passthrough = (device_get_parent(child) != bus);
+	sc = device_get_softc(bus);
+	rle = NULL;
+	if (!passthrough && isdefault) {
+		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
+		    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;
+		count = ummax(count, rle->count);
+		end = ummax(rle->end, start + count - 1);
+	}
+
+	switch (type) {
+	case SYS_RES_IRQ:
+		rm = &sc->sc_intr_rman;
+		break;
+	case SYS_RES_MEMORY:
+		rm = &sc->sc_mem_rman;
+		break;
+	default:
+		return (NULL);
+	}
+
+	rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+	    child);
+	if (rv == NULL)
+		return (NULL);
+	rman_set_rid(rv, *rid);
+
+	if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
+	    *rid, rv) != 0) {
+		rman_release_resource(rv);
+		return (NULL);
+	}
+
+	if (!passthrough && rle != NULL) {
+		rle->res = rv;
+		rle->start = rman_get_start(rv);
+		rle->end = rman_get_end(rv);
+		rle->count = rle->end - rle->start + 1;
+	}
+
+	return (rv);
+}
+
+static int
+ofwbus_adjust_resource(device_t bus, device_t child __unused, int type,
+    struct resource *r, rman_res_t start, rman_res_t end)
+{
+	struct ofwbus_softc *sc;
+	struct rman *rm;
+	device_t ofwbus;
+
+	ofwbus = bus;
+	while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0)
+		ofwbus = device_get_parent(ofwbus);
+	sc = device_get_softc(ofwbus);
+	switch (type) {
+	case SYS_RES_IRQ:
+		rm = &sc->sc_intr_rman;
+		break;
+	case SYS_RES_MEMORY:
+		rm = &sc->sc_mem_rman;
+		break;
+	default:
+		return (EINVAL);
+	}
+	if (rm == NULL)
+		return (ENXIO);
+	if (rman_is_region_manager(r, rm) == 0)
+		return (EINVAL);
+	return (rman_adjust_resource(r, start, end));
+}
+
+static int
+ofwbus_release_resource(device_t bus, device_t child, int type,
+    int rid, struct resource *r)
+{
+	struct resource_list_entry *rle;
+	int passthrough;
+	int error;
+
+	passthrough = (device_get_parent(child) != bus);
+	if (!passthrough) {
+		/* Clean resource list entry */
+		rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child),
+		    type, rid);
+		if (rle != NULL)
+			rle->res = NULL;
+	}
+
+	if ((rman_get_flags(r) & RF_ACTIVE) != 0) {
+		error = bus_deactivate_resource(child, type, rid, r);
+		if (error)
+			return (error);
+	}
+	return (rman_release_resource(r));
+}
diff --git a/freebsd/sys/dev/ofw/ofwvar.h b/freebsd/sys/dev/ofw/ofwvar.h
new file mode 100644
index 0000000..ddaa3db
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofwvar.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2005 Peter Grehan
+ * Copyright (c) 2008 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_OFWVAR_H_
+#define	_DEV_OFW_OFWVAR_H_
+
+/*
+ * An Open Firmware client implementation is declared with a kernel object and
+ * an associated method table, similar to a device driver.
+ *
+ * e.g.
+ *
+ * static ofw_method_t fdt_methods[] = {
+ *	OFWMETHOD(ofw_init,		fdt_init),
+ *	OFWMETHOD(ofw_finddevice,	fdt_finddevice),
+ *  ...
+ *	OFWMETHOD(ofw_nextprop,		fdt_nextprop),
+ *	{ 0, 0 }
+ * };
+ *
+ * static ofw_def_t ofw_fdt = {
+ *	"ofw_fdt",
+ *	fdt_methods,
+ *	sizeof(fdt_softc),	// or 0 if no softc
+ * };
+ *
+ * OFW_DEF(ofw_fdt);
+ */
+
+#include <sys/kobj.h>
+
+struct ofw_kobj {
+	/*
+	 * An OFW instance is a kernel object.
+	 */
+	KOBJ_FIELDS;
+
+	/*
+	 * Utility elements that an instance may use
+	 */
+	struct mtx	ofw_mtx;	/* available for instance use */
+	void		*ofw_iptr;	/* instance data pointer */
+
+	/*
+	 * Opaque data that can be overlaid with an instance-private
+	 * structure.  OFW 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 MMU kernel object is
+	 * registered.
+	 */
+#define	OFW_OPAQUESZ	64
+	u_int		ofw_opaque[OFW_OPAQUESZ];
+};
+
+typedef struct ofw_kobj		*ofw_t;
+typedef struct kobj_class	ofw_def_t;
+
+#define	ofw_method_t	kobj_method_t
+#define	OFWMETHOD	KOBJMETHOD
+
+#define	OFW_DEF(name)	DATA_SET(ofw_set, name)
+
+#endif /* _DEV_OFW_OFWVAR_H_ */
diff --git a/freebsd/sys/dev/ofw/openfirm.c b/freebsd/sys/dev/ofw/openfirm.c
new file mode 100644
index 0000000..6c6cd87
--- /dev/null
+++ b/freebsd/sys/dev/ofw/openfirm.c
@@ -0,0 +1,807 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*	$NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $	*/
+
+/*-
+ * Copyright (C) 1995, 1996 Wolfgang Solfrank.
+ * Copyright (C) 1995, 1996 TooLs GmbH.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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.
+ */
+/*-
+ * Copyright (C) 2000 Benno Rice.
+ * 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 Benno Rice ``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 TOOLS GMBH 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 <rtems/bsd/sys/param.h>
+#include <sys/kernel.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+
+#include <machine/stdarg.h>
+
+#include <dev/ofw/ofwvar.h>
+#include <dev/ofw/openfirm.h>
+
+#include <rtems/bsd/local/ofw_if.h>
+
+static void OF_putchar(int c, void *arg);
+
+MALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties");
+
+static ihandle_t stdout;
+
+static ofw_def_t	*ofw_def_impl = NULL;
+static ofw_t		ofw_obj;
+static struct ofw_kobj	ofw_kernel_obj;
+static struct kobj_ops	ofw_kernel_kops;
+
+struct xrefinfo {
+	phandle_t	xref;
+	phandle_t 	node;
+	device_t  	dev;
+	SLIST_ENTRY(xrefinfo) next_entry;
+};
+
+static SLIST_HEAD(, xrefinfo) xreflist = SLIST_HEAD_INITIALIZER(xreflist);
+static struct mtx xreflist_lock;
+static boolean_t xref_init_done;
+
+#define	FIND_BY_XREF	0
+#define	FIND_BY_NODE	1
+#define	FIND_BY_DEV	2
+
+/*
+ * xref-phandle-device lookup helper routines.
+ *
+ * As soon as we are able to use malloc(), walk the node tree and build a list
+ * of info that cross-references node handles, xref handles, and device_t
+ * instances.  This list exists primarily to allow association of a device_t
+ * with an xref handle, but it is also used to speed up translation between xref
+ * and node handles.  Before malloc() is available we have to recursively search
+ * the node tree each time we want to translate between a node and xref handle.
+ * Afterwards we can do the translations by searching this much shorter list.
+ */
+static void
+xrefinfo_create(phandle_t node)
+{
+	struct xrefinfo * xi;
+	phandle_t child, xref;
+
+	/*
+	 * Recursively descend from parent, looking for nodes with a property
+	 * named either "phandle", "ibm,phandle", or "linux,phandle".  For each
+	 * such node found create an entry in the xreflist.
+	 */
+	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+		xrefinfo_create(child);
+		if (OF_getencprop(child, "phandle", &xref, sizeof(xref)) ==
+		    -1 && OF_getencprop(child, "ibm,phandle", &xref,
+		    sizeof(xref)) == -1 && OF_getencprop(child,
+		    "linux,phandle", &xref, sizeof(xref)) == -1)
+			continue;
+		xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK | M_ZERO);
+		xi->node = child;
+		xi->xref = xref;
+		SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
+	}
+}
+
+static void
+xrefinfo_init(void *unsed)
+{
+
+	/*
+	 * There is no locking during this init because it runs much earlier
+	 * than any of the clients/consumers of the xref list data, but we do
+	 * initialize the mutex that will be used for access later.
+	 */
+	mtx_init(&xreflist_lock, "OF xreflist lock", NULL, MTX_DEF);
+	xrefinfo_create(OF_peer(0));
+	xref_init_done = true;
+}
+SYSINIT(xrefinfo, SI_SUB_KMEM, SI_ORDER_ANY, xrefinfo_init, NULL);
+
+static struct xrefinfo *
+xrefinfo_find(uintptr_t key, int find_by)
+{
+	struct xrefinfo *rv, *xi;
+
+	rv = NULL;
+	mtx_lock(&xreflist_lock);
+	SLIST_FOREACH(xi, &xreflist, next_entry) {
+		if ((find_by == FIND_BY_XREF && (phandle_t)key == xi->xref) ||
+		    (find_by == FIND_BY_NODE && (phandle_t)key == xi->node) ||
+		    (find_by == FIND_BY_DEV && key == (uintptr_t)xi->dev)) {
+			rv = xi;
+			break;
+		}
+	}
+	mtx_unlock(&xreflist_lock);
+	return (rv);
+}
+
+static struct xrefinfo *
+xrefinfo_add(phandle_t node, phandle_t xref, device_t dev)
+{
+	struct xrefinfo *xi;
+
+	xi = malloc(sizeof(*xi), M_OFWPROP, M_WAITOK);
+	xi->node = node;
+	xi->xref = xref;
+	xi->dev  = dev;
+	mtx_lock(&xreflist_lock);
+	SLIST_INSERT_HEAD(&xreflist, xi, next_entry);
+	mtx_unlock(&xreflist_lock);
+	return (xi);
+}
+
+/*
+ * OFW install routines.  Highest priority wins, equal priority also
+ * overrides allowing last-set to win.
+ */
+SET_DECLARE(ofw_set, ofw_def_t);
+
+boolean_t
+OF_install(char *name, int prio)
+{
+	ofw_def_t *ofwp, **ofwpp;
+	static int curr_prio = 0;
+
+	/*
+	 * Try and locate the OFW kobj corresponding to the name.
+	 */
+	SET_FOREACH(ofwpp, ofw_set) {
+		ofwp = *ofwpp;
+
+		if (ofwp->name &&
+		    !strcmp(ofwp->name, name) &&
+		    prio >= curr_prio) {
+			curr_prio = prio;
+			ofw_def_impl = ofwp;
+			return (TRUE);
+		}
+	}
+
+	return (FALSE);
+}
+
+/* Initializer */
+int
+OF_init(void *cookie)
+{
+	phandle_t chosen;
+	int rv;
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	ofw_obj = &ofw_kernel_obj;
+	/*
+	 * Take care of compiling the selected class, and
+	 * then statically initialize the OFW object.
+	 */
+	kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops);
+	kobj_init_static((kobj_t)ofw_obj, ofw_def_impl);
+
+	rv = OFW_INIT(ofw_obj, cookie);
+
+	if ((chosen = OF_finddevice("/chosen")) != -1)
+		if (OF_getencprop(chosen, "stdout", &stdout,
+		    sizeof(stdout)) == -1)
+			stdout = -1;
+
+	return (rv);
+}
+
+static void
+OF_putchar(int c, void *arg __unused)
+{
+	char cbuf;
+
+	if (c == '\n') {
+		cbuf = '\r';
+		OF_write(stdout, &cbuf, 1);
+	}
+
+	cbuf = c;
+	OF_write(stdout, &cbuf, 1);
+}
+
+void
+OF_printf(const char *fmt, ...)
+{
+	va_list	va;
+
+	va_start(va, fmt);
+	(void)kvprintf(fmt, OF_putchar, NULL, 10, va);
+	va_end(va);
+}
+
+/*
+ * Generic functions
+ */
+
+/* Test to see if a service exists. */
+int
+OF_test(const char *name)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_TEST(ofw_obj, name));
+}
+
+int
+OF_interpret(const char *cmd, int nreturns, ...)
+{
+	va_list ap;
+	cell_t slots[16];
+	int i = 0;
+	int status;
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots);
+	if (status == -1)
+		return (status);
+
+	va_start(ap, nreturns);
+	while (i < nreturns)
+		*va_arg(ap, cell_t *) = slots[i++];
+	va_end(ap);
+
+	return (status);
+}
+
+/*
+ * Device tree functions
+ */
+
+/* Return the next sibling of this node or 0. */
+phandle_t
+OF_peer(phandle_t node)
+{
+
+	if (ofw_def_impl == NULL)
+		return (0);
+
+	return (OFW_PEER(ofw_obj, node));
+}
+
+/* Return the first child of this node or 0. */
+phandle_t
+OF_child(phandle_t node)
+{
+
+	if (ofw_def_impl == NULL)
+		return (0);
+
+	return (OFW_CHILD(ofw_obj, node));
+}
+
+/* Return the parent of this node or 0. */
+phandle_t
+OF_parent(phandle_t node)
+{
+
+	if (ofw_def_impl == NULL)
+		return (0);
+
+	return (OFW_PARENT(ofw_obj, node));
+}
+
+/* Return the package handle that corresponds to an instance handle. */
+phandle_t
+OF_instance_to_package(ihandle_t instance)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance));
+}
+
+/* Get the length of a property of a package. */
+ssize_t
+OF_getproplen(phandle_t package, const char *propname)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_GETPROPLEN(ofw_obj, package, propname));
+}
+
+/* Check existence of a property of a package. */
+int
+OF_hasprop(phandle_t package, const char *propname)
+{
+
+	return (OF_getproplen(package, propname) >= 0 ? 1 : 0);
+}
+
+/* Get the value of a property of a package. */
+ssize_t
+OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen));
+}
+
+ssize_t
+OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
+{
+	ssize_t retval;
+	int i;
+
+	KASSERT(len % 4 == 0, ("Need a multiple of 4 bytes"));
+
+	retval = OF_getprop(node, propname, buf, len);
+	if (retval <= 0)
+		return (retval);
+
+	for (i = 0; i < len/4; i++)
+		buf[i] = be32toh(buf[i]);
+
+	return (retval);
+}
+
+/*
+ * Recursively search the node and its parent for the given property, working
+ * downward from the node to the device tree root.  Returns the value of the
+ * first match.
+ */
+ssize_t
+OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len)
+{
+	ssize_t rv;
+
+	for (; node != 0; node = OF_parent(node))
+		if ((rv = OF_getprop(node, propname, buf, len)) != -1)
+			return (rv);
+	return (-1);
+}
+
+ssize_t
+OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len)
+{
+	ssize_t rv;
+
+	for (; node != 0; node = OF_parent(node))
+		if ((rv = OF_getencprop(node, propname, buf, len)) != -1)
+			return (rv);
+	return (-1);
+}
+
+/*
+ * Store the value of a property of a package into newly allocated memory
+ * (using the M_OFWPROP malloc pool and M_WAITOK).  elsz is the size of a
+ * single element, the number of elements is return in number.
+ */
+ssize_t
+OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf)
+{
+	int len;
+
+	*buf = NULL;
+	if ((len = OF_getproplen(package, propname)) == -1 ||
+	    len % elsz != 0)
+		return (-1);
+
+	*buf = malloc(len, M_OFWPROP, M_WAITOK);
+	if (OF_getprop(package, propname, *buf, len) == -1) {
+		free(*buf, M_OFWPROP);
+		*buf = NULL;
+		return (-1);
+	}
+	return (len / elsz);
+}
+
+ssize_t
+OF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf)
+{
+	ssize_t retval;
+	pcell_t *cell;
+	int i;
+
+	retval = OF_getprop_alloc(package, name, elsz, buf);
+	if (retval == -1)
+		return (-1);
+ 	if (retval * elsz % 4 != 0) {
+		free(*buf, M_OFWPROP);
+		*buf = NULL;
+		return (-1);
+	}
+
+	cell = *buf;
+	for (i = 0; i < retval * elsz / 4; i++)
+		cell[i] = be32toh(cell[i]);
+
+	return (retval);
+}
+
+/* Free buffer allocated by OF_getencprop_alloc or OF_getprop_alloc */
+void OF_prop_free(void *buf)
+{
+
+	free(buf, M_OFWPROP);
+}
+
+/* Get the next property of a package. */
+int
+OF_nextprop(phandle_t package, const char *previous, char *buf, size_t size)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size));
+}
+
+/* Set the value of a property of a package. */
+int
+OF_setprop(phandle_t package, const char *propname, const void *buf, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_SETPROP(ofw_obj, package, propname, buf,len));
+}
+
+/* Convert a device specifier to a fully qualified pathname. */
+ssize_t
+OF_canon(const char *device, char *buf, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_CANON(ofw_obj, device, buf, len));
+}
+
+/* Return a package handle for the specified device. */
+phandle_t
+OF_finddevice(const char *device)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_FINDDEVICE(ofw_obj, device));
+}
+
+/* Return the fully qualified pathname corresponding to an instance. */
+ssize_t
+OF_instance_to_path(ihandle_t instance, char *buf, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len));
+}
+
+/* Return the fully qualified pathname corresponding to a package. */
+ssize_t
+OF_package_to_path(phandle_t package, char *buf, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len));
+}
+
+/* Look up effective phandle (see FDT/PAPR spec) */
+static phandle_t
+OF_child_xref_phandle(phandle_t parent, phandle_t xref)
+{
+	phandle_t child, rxref;
+
+	/*
+	 * Recursively descend from parent, looking for a node with a property
+	 * named either "phandle", "ibm,phandle", or "linux,phandle" that
+	 * matches the xref we are looking for.
+	 */
+
+	for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
+		rxref = OF_child_xref_phandle(child, xref);
+		if (rxref != -1)
+			return (rxref);
+
+		if (OF_getencprop(child, "phandle", &rxref, sizeof(rxref)) ==
+		    -1 && OF_getencprop(child, "ibm,phandle", &rxref,
+		    sizeof(rxref)) == -1 && OF_getencprop(child,
+		    "linux,phandle", &rxref, sizeof(rxref)) == -1)
+			continue;
+
+		if (rxref == xref)
+			return (child);
+	}
+
+	return (-1);
+}
+
+phandle_t
+OF_node_from_xref(phandle_t xref)
+{
+	struct xrefinfo *xi;
+	phandle_t node;
+
+	if (xref_init_done) {
+		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
+			return (xref);
+		return (xi->node);
+	}
+
+	if ((node = OF_child_xref_phandle(OF_peer(0), xref)) == -1)
+		return (xref);
+	return (node);
+}
+
+phandle_t
+OF_xref_from_node(phandle_t node)
+{
+	struct xrefinfo *xi;
+	phandle_t xref;
+
+	if (xref_init_done) {
+		if ((xi = xrefinfo_find(node, FIND_BY_NODE)) == NULL)
+			return (node);
+		return (xi->xref);
+	}
+
+	if (OF_getencprop(node, "phandle", &xref, sizeof(xref)) == -1 &&
+	    OF_getencprop(node, "ibm,phandle", &xref, sizeof(xref)) == -1 &&
+	    OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1)
+		return (node);
+	return (xref);
+}
+
+device_t
+OF_device_from_xref(phandle_t xref)
+{
+	struct xrefinfo *xi;
+
+	if (xref_init_done) {
+		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
+			return (NULL);
+		return (xi->dev);
+	}
+	panic("Attempt to find device before xreflist_init");
+}
+
+phandle_t
+OF_xref_from_device(device_t dev)
+{
+	struct xrefinfo *xi;
+
+	if (xref_init_done) {
+		if ((xi = xrefinfo_find((uintptr_t)dev, FIND_BY_DEV)) == NULL)
+			return (0);
+		return (xi->xref);
+	}
+	panic("Attempt to find xref before xreflist_init");
+}
+
+int
+OF_device_register_xref(phandle_t xref, device_t dev)
+{
+	struct xrefinfo *xi;
+
+	/*
+	 * If the given xref handle doesn't already exist in the list then we
+	 * add a list entry.  In theory this can only happen on a system where
+	 * nodes don't contain phandle properties and xref and node handles are
+	 * synonymous, so the xref handle is added as the node handle as well.
+	 */
+	if (xref_init_done) {
+		if ((xi = xrefinfo_find(xref, FIND_BY_XREF)) == NULL)
+			xrefinfo_add(xref, xref, dev);
+		else 
+			xi->dev = dev;
+		return (0);
+	}
+	panic("Attempt to register device before xreflist_init");
+}
+
+/*  Call the method in the scope of a given instance. */
+int
+OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns,
+    ...)
+{
+	va_list ap;
+	cell_t args_n_results[12];
+	int n, status;
+
+	if (nargs > 6 || ofw_def_impl == NULL)
+		return (-1);
+	va_start(ap, nreturns);
+	for (n = 0; n < nargs; n++)
+		args_n_results[n] = va_arg(ap, cell_t);
+
+	status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns,
+	    args_n_results);
+	if (status != 0)
+		return (status);
+
+	for (; n < nargs + nreturns; n++)
+		*va_arg(ap, cell_t *) = args_n_results[n];
+	va_end(ap);
+	return (0);
+}
+
+/*
+ * Device I/O functions
+ */
+
+/* Open an instance for a device. */
+ihandle_t
+OF_open(const char *device)
+{
+
+	if (ofw_def_impl == NULL)
+		return (0);
+
+	return (OFW_OPEN(ofw_obj, device));
+}
+
+/* Close an instance. */
+void
+OF_close(ihandle_t instance)
+{
+
+	if (ofw_def_impl == NULL)
+		return;
+
+	OFW_CLOSE(ofw_obj, instance);
+}
+
+/* Read from an instance. */
+ssize_t
+OF_read(ihandle_t instance, void *addr, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_READ(ofw_obj, instance, addr, len));
+}
+
+/* Write to an instance. */
+ssize_t
+OF_write(ihandle_t instance, const void *addr, size_t len)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_WRITE(ofw_obj, instance, addr, len));
+}
+
+/* Seek to a position. */
+int
+OF_seek(ihandle_t instance, uint64_t pos)
+{
+
+	if (ofw_def_impl == NULL)
+		return (-1);
+
+	return (OFW_SEEK(ofw_obj, instance, pos));
+}
+
+/*
+ * Memory functions
+ */
+
+/* Claim an area of memory. */
+void *
+OF_claim(void *virt, size_t size, u_int align)
+{
+
+	if (ofw_def_impl == NULL)
+		return ((void *)-1);
+
+	return (OFW_CLAIM(ofw_obj, virt, size, align));
+}
+
+/* Release an area of memory. */
+void
+OF_release(void *virt, size_t size)
+{
+
+	if (ofw_def_impl == NULL)
+		return;
+
+	OFW_RELEASE(ofw_obj, virt, size);
+}
+
+/*
+ * Control transfer functions
+ */
+
+/* Suspend and drop back to the Open Firmware interface. */
+void
+OF_enter()
+{
+
+	if (ofw_def_impl == NULL)
+		return;
+
+	OFW_ENTER(ofw_obj);
+}
+
+/* Shut down and drop back to the Open Firmware interface. */
+void
+OF_exit()
+{
+
+	if (ofw_def_impl == NULL)
+		panic("OF_exit: Open Firmware not available");
+
+	/* Should not return */
+	OFW_EXIT(ofw_obj);
+
+	for (;;)			/* just in case */
+		;
+}
diff --git a/freebsd/sys/dev/tsec/if_tsec_fdt.c b/freebsd/sys/dev/tsec/if_tsec_fdt.c
new file mode 100644
index 0000000..1ae47b9
--- /dev/null
+++ b/freebsd/sys/dev/tsec/if_tsec_fdt.c
@@ -0,0 +1,390 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski
+ * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski
+ * 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.
+ *
+ * From: FreeBSD: head/sys/dev/tsec/if_tsec_ocp.c 188712 2009-02-17 14:59:47Z raj
+ */
+
+/*
+ * FDT 'simple-bus' attachment for Freescale TSEC controller.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/tsec/if_tsec.h>
+#include <dev/tsec/if_tsecreg.h>
+
+#include <rtems/bsd/local/miibus_if.h>
+
+#define	TSEC_RID_TXIRQ	0
+#define	TSEC_RID_RXIRQ	1
+#define	TSEC_RID_ERRIRQ	2
+
+static int tsec_fdt_probe(device_t dev);
+static int tsec_fdt_attach(device_t dev);
+static int tsec_fdt_detach(device_t dev);
+static int tsec_setup_intr(struct tsec_softc *sc, struct resource **ires,
+    void **ihand, int *irid, driver_intr_t handler, const char *iname);
+static void tsec_release_intr(struct tsec_softc *sc, struct resource *ires,
+    void *ihand, int irid, const char *iname);
+
+static device_method_t tsec_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		tsec_fdt_probe),
+	DEVMETHOD(device_attach,	tsec_fdt_attach),
+	DEVMETHOD(device_detach,	tsec_fdt_detach),
+
+	DEVMETHOD(device_shutdown,	tsec_shutdown),
+	DEVMETHOD(device_suspend,	tsec_suspend),
+	DEVMETHOD(device_resume,	tsec_resume),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	tsec_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	tsec_miibus_writereg),
+	DEVMETHOD(miibus_statchg,	tsec_miibus_statchg),
+
+	DEVMETHOD_END
+};
+
+static driver_t tsec_fdt_driver = {
+	"tsec",
+	tsec_methods,
+	sizeof(struct tsec_softc),
+};
+
+DRIVER_MODULE(tsec, simplebus, tsec_fdt_driver, tsec_devclass, 0, 0);
+
+static int
+tsec_fdt_probe(device_t dev)
+{
+	struct tsec_softc *sc;
+	uint32_t id;
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_get_type(dev) == NULL ||
+	    strcmp(ofw_bus_get_type(dev), "network") != 0)
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "gianfar") &&
+	    !ofw_bus_is_compatible(dev, "fsl,etsec2"))
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+
+	/*
+	 * Device trees with "fsl,etsec2" compatible nodes don't have a reg
+	 * property, as it's been relegated to the queue-group children.
+	 */
+	if (ofw_bus_is_compatible(dev, "fsl,etsec2"))
+		sc->is_etsec = 1;
+	else {
+		sc->sc_rrid = 0;
+		sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
+		    RF_ACTIVE);
+		if (sc->sc_rres == NULL)
+			return (ENXIO);
+
+		sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
+		sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
+
+		/* Check if we are eTSEC (enhanced TSEC) */
+		id = TSEC_READ(sc, TSEC_REG_ID);
+		sc->is_etsec = ((id >> 16) == TSEC_ETSEC_ID) ? 1 : 0;
+		id |= TSEC_READ(sc, TSEC_REG_ID2);
+
+		bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
+
+		if (id == 0) {
+			device_printf(dev, "could not identify TSEC type\n");
+			return (ENXIO);
+		}
+	}
+
+	if (sc->is_etsec)
+		device_set_desc(dev, "Enhanced Three-Speed Ethernet Controller");
+	else
+		device_set_desc(dev, "Three-Speed Ethernet Controller");
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tsec_fdt_attach(device_t dev)
+{
+	struct tsec_softc *sc;
+	struct resource_list *rl;
+	phandle_t child, mdio, phy;
+	int acells, scells;
+	int error = 0;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	sc->node = ofw_bus_get_node(dev);
+
+	if (fdt_addrsize_cells(sc->node, &acells, &scells) != 0) {
+		acells = 1;
+		scells = 1;
+	}
+	if (ofw_bus_is_compatible(dev, "fsl,etsec2")) {
+		rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
+
+		/*
+		 * TODO: Add all children resources to the list.  Will be
+		 * required to support multigroup mode.
+		 */
+		child = OF_child(sc->node);
+		ofw_bus_reg_to_rl(dev, child, acells, scells, rl);
+		ofw_bus_intr_to_rl(dev, child, rl, NULL);
+	}
+
+	/* Get phy address from fdt */
+	if (OF_getencprop(sc->node, "phy-handle", &phy, sizeof(phy)) <= 0) {
+		device_printf(dev, "PHY not found in device tree");
+		return (ENXIO);
+	}
+
+	phy = OF_node_from_xref(phy);
+	mdio = OF_parent(phy);
+	OF_decode_addr(mdio, 0, &sc->phy_bst, &sc->phy_bsh, NULL);
+	OF_getencprop(phy, "reg", &sc->phyaddr, sizeof(sc->phyaddr));
+
+	/*
+	 * etsec2 MDIO nodes are given the MDIO module base address, so we need
+	 * to add the MII offset to get the PHY registers.
+	 */
+	if (ofw_bus_node_is_compatible(mdio, "fsl,etsec2-mdio"))
+		sc->phy_regoff = TSEC_REG_MIIBASE;
+
+	/* Init timer */
+	callout_init(&sc->tsec_callout, 1);
+
+	/* Init locks */
+	mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock",
+	    MTX_DEF);
+	mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock",
+	    MTX_DEF);
+	mtx_init(&sc->ic_lock, device_get_nameunit(dev), "TSEC IC lock",
+	    MTX_DEF);
+
+	/* Allocate IO memory for TSEC registers */
+	sc->sc_rrid = 0;
+	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
+	    RF_ACTIVE);
+	if (sc->sc_rres == NULL) {
+		device_printf(dev, "could not allocate IO memory range!\n");
+		goto fail1;
+	}
+	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
+	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
+
+	/* TSEC attach */
+	if (tsec_attach(sc) != 0) {
+		device_printf(dev, "could not be configured\n");
+		goto fail2;
+	}
+
+	/* Set up interrupts (TX/RX/ERR) */
+	sc->sc_transmit_irid = TSEC_RID_TXIRQ;
+	error = tsec_setup_intr(sc, &sc->sc_transmit_ires,
+	    &sc->sc_transmit_ihand, &sc->sc_transmit_irid,
+	    tsec_transmit_intr, "TX");
+	if (error)
+		goto fail2;
+
+	sc->sc_receive_irid = TSEC_RID_RXIRQ;
+	error = tsec_setup_intr(sc, &sc->sc_receive_ires,
+	    &sc->sc_receive_ihand, &sc->sc_receive_irid,
+	    tsec_receive_intr, "RX");
+	if (error)
+		goto fail3;
+
+	sc->sc_error_irid = TSEC_RID_ERRIRQ;
+	error = tsec_setup_intr(sc, &sc->sc_error_ires,
+	    &sc->sc_error_ihand, &sc->sc_error_irid,
+	    tsec_error_intr, "ERR");
+	if (error)
+		goto fail4;
+
+	return (0);
+
+fail4:
+	tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
+	    sc->sc_receive_irid, "RX");
+fail3:
+	tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
+	    sc->sc_transmit_irid, "TX");
+fail2:
+	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
+fail1:
+	mtx_destroy(&sc->receive_lock);
+	mtx_destroy(&sc->transmit_lock);
+	return (ENXIO);
+}
+
+static int
+tsec_setup_intr(struct tsec_softc *sc, struct resource **ires, void **ihand,
+    int *irid, driver_intr_t handler, const char *iname)
+{
+	int error;
+
+	*ires = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, irid, RF_ACTIVE);
+	if (*ires == NULL) {
+		device_printf(sc->dev, "could not allocate %s IRQ\n", iname);
+		return (ENXIO);
+	}
+	error = bus_setup_intr(sc->dev, *ires, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, handler, sc, ihand);
+	if (error) {
+		device_printf(sc->dev, "failed to set up %s IRQ\n", iname);
+		if (bus_release_resource(sc->dev, SYS_RES_IRQ, *irid, *ires))
+			device_printf(sc->dev, "could not release %s IRQ\n", iname);
+		*ires = NULL;
+		return (error);
+	}
+	return (0);
+}
+
+static void
+tsec_release_intr(struct tsec_softc *sc, struct resource *ires, void *ihand,
+    int irid, const char *iname)
+{
+	int error;
+
+	if (ires == NULL)
+		return;
+
+	error = bus_teardown_intr(sc->dev, ires, ihand);
+	if (error)
+		device_printf(sc->dev, "bus_teardown_intr() failed for %s intr"
+		    ", error %d\n", iname, error);
+
+	error = bus_release_resource(sc->dev, SYS_RES_IRQ, irid, ires);
+	if (error)
+		device_printf(sc->dev, "bus_release_resource() failed for %s "
+		    "intr, error %d\n", iname, error);
+}
+
+static int
+tsec_fdt_detach(device_t dev)
+{
+	struct tsec_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	/* Wait for stopping watchdog */
+	callout_drain(&sc->tsec_callout);
+
+	/* Stop and release all interrupts */
+	tsec_release_intr(sc, sc->sc_transmit_ires, sc->sc_transmit_ihand,
+	    sc->sc_transmit_irid, "TX");
+	tsec_release_intr(sc, sc->sc_receive_ires, sc->sc_receive_ihand,
+	    sc->sc_receive_irid, "RX");
+	tsec_release_intr(sc, sc->sc_error_ires, sc->sc_error_ihand,
+	    sc->sc_error_irid, "ERR");
+
+	/* TSEC detach */
+	tsec_detach(sc);
+
+	/* Free IO memory handler */
+	if (sc->sc_rres) {
+		error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid,
+		    sc->sc_rres);
+		if (error)
+			device_printf(dev, "bus_release_resource() failed for"
+			    " IO memory, error %d\n", error);
+	}
+
+	/* Destroy locks */
+	mtx_destroy(&sc->receive_lock);
+	mtx_destroy(&sc->transmit_lock);
+	mtx_destroy(&sc->ic_lock);
+	return (0);
+}
+
+void
+tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr)
+{
+	union {
+		uint32_t reg[2];
+		uint8_t addr[6];
+	} hw;
+	int i;
+
+	hw.reg[0] = hw.reg[1] = 0;
+
+	/* Retrieve the hardware address from the device tree. */
+	i = OF_getprop(sc->node, "local-mac-address", (void *)hw.addr, 6);
+	if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) {
+		bcopy(hw.addr, addr, 6);
+		return;
+	}
+
+	/* Also try the mac-address property, which is second-best */
+	i = OF_getprop(sc->node, "mac-address", (void *)hw.addr, 6);
+	if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) {
+		bcopy(hw.addr, addr, 6);
+		return;
+	}
+
+	/*
+	 * Fall back -- use the currently programmed address in the hope that
+	 * it was set be firmware...
+	 */
+	hw.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1);
+	hw.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2);
+	for (i = 0; i < 6; i++)
+		addr[5-i] = hw.addr[i];
+}
diff --git a/freebsd/sys/sys/slicer.h b/freebsd/sys/sys/slicer.h
new file mode 100644
index 0000000..9bf8748
--- /dev/null
+++ b/freebsd/sys/sys/slicer.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 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 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 _FLASH_SLICER_H_
+#define _FLASH_SLICER_H_
+
+#include <sys/types.h>
+
+#define FLASH_SLICES_MAX_NUM		8
+#define FLASH_SLICES_MAX_NAME_LEN	(32 + 1)
+
+#define	FLASH_SLICES_FLAG_NONE		0
+#define	FLASH_SLICES_FLAG_RO		1	/* Read only */
+
+struct flash_slice {
+	off_t		base;
+	off_t		size;
+	char		*label;
+	unsigned int	flags;
+};
+
+#ifdef _KERNEL
+int fdt_flash_fill_slices(device_t, struct flash_slice *, int *) __weak_symbol;
+void flash_register_slicer(int (*)(device_t, struct flash_slice *, int *));
+#endif /* _KERNEL */
+
+#endif /* _FLASH_SLICER_H_ */




More information about the vc mailing list