summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2017-03-02 16:28:14 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-03-08 09:00:03 +0100
commitf0dd0c506a706542e1a6b1c3e78e6c9809d31085 (patch)
tree7b0707ca37cc697da33ee43deb267f6cd9f20d8a
parentmedia01: Add cpuinfo command (diff)
downloadrtems-libbsd-f0dd0c506a706542e1a6b1c3e78e6c9809d31085.tar.bz2
FDT(4): Import from FreeBSD
-rw-r--r--freebsd/sys/dev/fdt/fdt_common.c744
-rw-r--r--freebsd/sys/dev/fdt/fdt_common.h107
-rw-r--r--freebsd/sys/dev/fdt/simplebus.c431
-rw-r--r--freebsd/sys/dev/fdt/simplebus.h64
-rw-r--r--freebsd/sys/dev/ofw/ofw_bus.h79
-rw-r--r--freebsd/sys/dev/ofw/ofw_bus_subr.c953
-rw-r--r--freebsd/sys/dev/ofw/ofw_bus_subr.h145
-rw-r--r--freebsd/sys/dev/ofw/ofw_fdt.c490
-rw-r--r--freebsd/sys/dev/ofw/ofw_pci.h103
-rw-r--r--freebsd/sys/dev/ofw/ofw_subr.c246
-rw-r--r--freebsd/sys/dev/ofw/ofw_subr.h51
-rw-r--r--freebsd/sys/dev/ofw/ofwbus.c297
-rw-r--r--freebsd/sys/dev/ofw/ofwvar.h89
-rw-r--r--freebsd/sys/dev/ofw/openfirm.c807
-rw-r--r--freebsd/sys/dev/tsec/if_tsec_fdt.c390
-rw-r--r--freebsd/sys/sys/slicer.h52
16 files changed, 5048 insertions, 0 deletions
diff --git a/freebsd/sys/dev/fdt/fdt_common.c b/freebsd/sys/dev/fdt/fdt_common.c
new file mode 100644
index 00000000..efbef9de
--- /dev/null
+++ b/freebsd/sys/dev/fdt/fdt_common.c
@@ -0,0 +1,744 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2009-2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Andrew Turner under sponsorship from
+ * the FreeBSD Foundation.
+ * This software was developed by Semihalf under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/sysctl.h>
+
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <rtems/bsd/local/ofw_bus_if.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
+ printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define FDT_COMPAT_LEN 255
+#define FDT_TYPE_LEN 64
+
+#define FDT_REG_CELLS 4
+
+SYSCTL_NODE(_hw, OID_AUTO, fdt, CTLFLAG_RD, 0, "Flattened Device Tree");
+
+vm_paddr_t fdt_immr_pa;
+vm_offset_t fdt_immr_va;
+vm_offset_t fdt_immr_size;
+
+struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head);
+
+static int fdt_is_compatible(phandle_t, const char *);
+
+static int
+fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base,
+ u_long *size)
+{
+ pcell_t ranges[32], *rangesptr;
+ pcell_t addr_cells, size_cells, par_addr_cells;
+ u_long bus_addr, par_bus_addr, pbase, psize;
+ int err, i, len, tuple_size, tuples;
+
+ if (node == 0) {
+ *base = 0;
+ *size = ULONG_MAX;
+ return (0);
+ }
+
+ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+ return (ENXIO);
+ /*
+ * Process 'ranges' property.
+ */
+ par_addr_cells = fdt_parent_addr_cells(node);
+ if (par_addr_cells > 2) {
+ return (ERANGE);
+ }
+
+ len = OF_getproplen(node, "ranges");
+ if (len < 0)
+ return (-1);
+ if (len > sizeof(ranges))
+ return (ENOMEM);
+ if (len == 0) {
+ return (fdt_get_range_by_busaddr(OF_parent(node), addr,
+ base, size));
+ }
+
+ if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
+ return (EINVAL);
+
+ tuple_size = addr_cells + par_addr_cells + size_cells;
+ tuples = len / (tuple_size * sizeof(cell_t));
+
+ if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2)
+ return (ERANGE);
+
+ *base = 0;
+ *size = 0;
+
+ for (i = 0; i < tuples; i++) {
+ rangesptr = &ranges[i * tuple_size];
+
+ bus_addr = fdt_data_get((void *)rangesptr, addr_cells);
+ if (bus_addr != addr)
+ continue;
+ rangesptr += addr_cells;
+
+ par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
+ rangesptr += par_addr_cells;
+
+ err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+ &pbase, &psize);
+ if (err > 0)
+ return (err);
+ if (err == 0)
+ *base = pbase;
+ else
+ *base = par_bus_addr;
+
+ *size = fdt_data_get((void *)rangesptr, size_cells);
+
+ return (0);
+ }
+
+ return (EINVAL);
+}
+
+int
+fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
+{
+ pcell_t ranges[6], *rangesptr;
+ pcell_t addr_cells, size_cells, par_addr_cells;
+ u_long par_bus_addr, pbase, psize;
+ int err, len, tuple_size, tuples;
+
+ if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
+ return (ENXIO);
+ /*
+ * Process 'ranges' property.
+ */
+ par_addr_cells = fdt_parent_addr_cells(node);
+ if (par_addr_cells > 2)
+ return (ERANGE);
+
+ len = OF_getproplen(node, "ranges");
+ if (len > sizeof(ranges))
+ return (ENOMEM);
+ if (len == 0) {
+ *base = 0;
+ *size = ULONG_MAX;
+ return (0);
+ }
+
+ if (!(range_id < len))
+ return (ERANGE);
+
+ if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
+ return (EINVAL);
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
+ size_cells);
+ tuples = len / tuple_size;
+
+ if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2)
+ return (ERANGE);
+
+ *base = 0;
+ *size = 0;
+ rangesptr = &ranges[range_id];
+
+ *base = fdt_data_get((void *)rangesptr, addr_cells);
+ rangesptr += addr_cells;
+
+ par_bus_addr = fdt_data_get((void *)rangesptr, par_addr_cells);
+ rangesptr += par_addr_cells;
+
+ err = fdt_get_range_by_busaddr(OF_parent(node), par_bus_addr,
+ &pbase, &psize);
+ if (err == 0)
+ *base += pbase;
+ else
+ *base += par_bus_addr;
+
+ *size = fdt_data_get((void *)rangesptr, size_cells);
+ return (0);
+}
+
+int
+fdt_immr_addr(vm_offset_t immr_va)
+{
+ phandle_t node;
+ u_long base, size;
+ int r;
+
+ /*
+ * Try to access the SOC node directly i.e. through /aliases/.
+ */
+ if ((node = OF_finddevice("soc")) != 0)
+ if (fdt_is_compatible(node, "simple-bus"))
+ goto moveon;
+ /*
+ * Find the node the long way.
+ */
+ if ((node = OF_finddevice("/")) == 0)
+ return (ENXIO);
+
+ if ((node = fdt_find_compatible(node, "simple-bus", 0)) == 0)
+ return (ENXIO);
+
+moveon:
+ if ((r = fdt_get_range(node, 0, &base, &size)) == 0) {
+ fdt_immr_pa = base;
+ fdt_immr_va = immr_va;
+ fdt_immr_size = size;
+ }
+
+ return (r);
+}
+
+/*
+ * This routine is an early-usage version of the ofw_bus_is_compatible() when
+ * the ofw_bus I/F is not available (like early console routines and similar).
+ * Note the buffer has to be on the stack since malloc() is usually not
+ * available in such cases either.
+ */
+static int
+fdt_is_compatible(phandle_t node, const char *compatstr)
+{
+ char buf[FDT_COMPAT_LEN];
+ char *compat;
+ int len, onelen, l, rv;
+
+ if ((len = OF_getproplen(node, "compatible")) <= 0)
+ return (0);
+
+ compat = (char *)&buf;
+ bzero(compat, FDT_COMPAT_LEN);
+
+ if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
+ return (0);
+
+ onelen = strlen(compatstr);
+ rv = 0;
+ while (len > 0) {
+ if (strncasecmp(compat, compatstr, onelen) == 0) {
+ /* Found it. */
+ rv = 1;
+ break;
+ }
+ /* Slide to the next sub-string. */
+ l = strlen(compat) + 1;
+ compat += l;
+ len -= l;
+ }
+
+ return (rv);
+}
+
+int
+fdt_is_compatible_strict(phandle_t node, const char *compatible)
+{
+ char compat[FDT_COMPAT_LEN];
+
+ if (OF_getproplen(node, "compatible") <= 0)
+ return (0);
+
+ if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0)
+ return (0);
+
+ if (strncasecmp(compat, compatible, FDT_COMPAT_LEN) == 0)
+ /* This fits. */
+ return (1);
+
+ return (0);
+}
+
+phandle_t
+fdt_find_compatible(phandle_t start, const char *compat, int strict)
+{
+ phandle_t child;
+
+ /*
+ * Traverse all children of 'start' node, and find first with
+ * matching 'compatible' property.
+ */
+ for (child = OF_child(start); child != 0; child = OF_peer(child))
+ if (fdt_is_compatible(child, compat)) {
+ if (strict)
+ if (!fdt_is_compatible_strict(child, compat))
+ continue;
+ return (child);
+ }
+ return (0);
+}
+
+phandle_t
+fdt_depth_search_compatible(phandle_t start, const char *compat, int strict)
+{
+ phandle_t child, node;
+
+ /*
+ * Depth-search all descendants of 'start' node, and find first with
+ * matching 'compatible' property.
+ */
+ for (node = OF_child(start); node != 0; node = OF_peer(node)) {
+ if (fdt_is_compatible(node, compat) &&
+ (strict == 0 || fdt_is_compatible_strict(node, compat))) {
+ return (node);
+ }
+ child = fdt_depth_search_compatible(node, compat, strict);
+ if (child != 0)
+ return (child);
+ }
+ return (0);
+}
+
+int
+fdt_is_enabled(phandle_t node)
+{
+ char *stat;
+ int ena, len;
+
+ len = OF_getprop_alloc(node, "status", sizeof(char),
+ (void **)&stat);
+
+ if (len <= 0)
+ /* It is OK if no 'status' property. */
+ return (1);
+
+ /* Anything other than 'okay' means disabled. */
+ ena = 0;
+ if (strncmp((char *)stat, "okay", len) == 0)
+ ena = 1;
+
+ OF_prop_free(stat);
+ return (ena);
+}
+
+int
+fdt_is_type(phandle_t node, const char *typestr)
+{
+ char type[FDT_TYPE_LEN];
+
+ if (OF_getproplen(node, "device_type") <= 0)
+ return (0);
+
+ if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0)
+ return (0);
+
+ if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0)
+ /* This fits. */
+ return (1);
+
+ return (0);
+}
+
+int
+fdt_parent_addr_cells(phandle_t node)
+{
+ pcell_t addr_cells;
+
+ /* Find out #address-cells of the superior bus. */
+ if (OF_searchprop(OF_parent(node), "#address-cells", &addr_cells,
+ sizeof(addr_cells)) <= 0)
+ return (2);
+
+ return ((int)fdt32_to_cpu(addr_cells));
+}
+
+int
+fdt_pm_is_enabled(phandle_t node)
+{
+ int ret;
+
+ ret = 1;
+
+#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+ ret = fdt_pm(node);
+#endif
+ return (ret);
+}
+
+u_long
+fdt_data_get(void *data, int cells)
+{
+
+ if (cells == 1)
+ return (fdt32_to_cpu(*((uint32_t *)data)));
+
+ return (fdt64_to_cpu(*((uint64_t *)data)));
+}
+
+int
+fdt_addrsize_cells(phandle_t node, int *addr_cells, int *size_cells)
+{
+ pcell_t cell;
+ int cell_size;
+
+ /*
+ * Retrieve #{address,size}-cells.
+ */
+ cell_size = sizeof(cell);
+ if (OF_getencprop(node, "#address-cells", &cell, cell_size) < cell_size)
+ *addr_cells = 2;
+ *addr_cells = (int)cell;
+
+ if (OF_getencprop(node, "#size-cells", &cell, cell_size) < cell_size)
+ cell = 1;
+ *size_cells = (int)cell;
+
+ if (*addr_cells > 3 || *size_cells > 2)
+ return (ERANGE);
+ return (0);
+}
+
+int
+fdt_data_to_res(pcell_t *data, int addr_cells, int size_cells, u_long *start,
+ u_long *count)
+{
+
+ /* Address portion. */
+ if (addr_cells > 2)
+ return (ERANGE);
+
+ *start = fdt_data_get((void *)data, addr_cells);
+ data += addr_cells;
+
+ /* Size portion. */
+ if (size_cells > 2)
+ return (ERANGE);
+
+ *count = fdt_data_get((void *)data, size_cells);
+ return (0);
+}
+
+int
+fdt_regsize(phandle_t node, u_long *base, u_long *size)
+{
+ pcell_t reg[4];
+ int addr_cells, len, size_cells;
+
+ if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells))
+ return (ENXIO);
+
+ if ((sizeof(pcell_t) * (addr_cells + size_cells)) > sizeof(reg))
+ return (ENOMEM);
+
+ len = OF_getprop(node, "reg", &reg, sizeof(reg));
+ if (len <= 0)
+ return (EINVAL);
+
+ *base = fdt_data_get(&reg[0], addr_cells);
+ *size = fdt_data_get(&reg[addr_cells], size_cells);
+ return (0);
+}
+
+int
+fdt_reg_to_rl(phandle_t node, struct resource_list *rl)
+{
+ u_long end, count, start;
+ pcell_t *reg, *regptr;
+ pcell_t addr_cells, size_cells;
+ int tuple_size, tuples;
+ int i, rv;
+ long busaddr, bussize;
+
+ if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
+ return (ENXIO);
+ if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) {
+ busaddr = 0;
+ bussize = 0;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+ tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
+ debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
+ debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
+ if (tuples <= 0)
+ /* No 'reg' property in this node. */
+ return (0);
+
+ regptr = reg;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(reg, addr_cells, size_cells, &start,
+ &count);
+ if (rv != 0) {
+ resource_list_free(rl);
+ goto out;
+ }
+ reg += addr_cells + size_cells;
+
+ /* Calculate address range relative to base. */
+ start += busaddr;
+ end = start + count - 1;
+
+ debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
+ end, count);
+
+ resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
+ count);
+ }
+ rv = 0;
+
+out:
+ OF_prop_free(regptr);
+ return (rv);
+}
+
+int
+fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc)
+{
+ phandle_t phy_node;
+ pcell_t phy_handle, phy_reg;
+ uint32_t i;
+ device_t parent, child;
+
+ if (OF_getencprop(node, "phy-handle", (void *)&phy_handle,
+ sizeof(phy_handle)) <= 0)
+ return (ENXIO);
+
+ phy_node = OF_node_from_xref(phy_handle);
+
+ if (OF_getencprop(phy_node, "reg", (void *)&phy_reg,
+ sizeof(phy_reg)) <= 0)
+ return (ENXIO);
+
+ *phy_addr = phy_reg;
+
+ /*
+ * Search for softc used to communicate with phy.
+ */
+
+ /*
+ * Step 1: Search for ancestor of the phy-node with a "phy-handle"
+ * property set.
+ */
+ phy_node = OF_parent(phy_node);
+ while (phy_node != 0) {
+ if (OF_getprop(phy_node, "phy-handle", (void *)&phy_handle,
+ sizeof(phy_handle)) > 0)
+ break;
+ phy_node = OF_parent(phy_node);
+ }
+ if (phy_node == 0)
+ return (ENXIO);
+
+ /*
+ * Step 2: For each device with the same parent and name as ours
+ * compare its node with the one found in step 1, ancestor of phy
+ * node (stored in phy_node).
+ */
+ parent = device_get_parent(dev);
+ i = 0;
+ child = device_find_child(parent, device_get_name(dev), i);
+ while (child != NULL) {
+ if (ofw_bus_get_node(child) == phy_node)
+ break;
+ i++;
+ child = device_find_child(parent, device_get_name(dev), i);
+ }
+ if (child == NULL)
+ return (ENXIO);
+
+ /*
+ * Use softc of the device found.
+ */
+ *phy_sc = (void *)device_get_softc(child);
+
+ return (0);
+}
+
+int
+fdt_get_reserved_regions(struct mem_region *mr, int *mrcnt)
+{
+ pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS];
+ pcell_t *reservep;
+ phandle_t memory, root;
+ uint32_t memory_size;
+ int addr_cells, size_cells;
+ int i, max_size, res_len, rv, tuple_size, tuples;
+
+ max_size = sizeof(reserve);
+ root = OF_finddevice("/");
+ memory = OF_finddevice("/memory");
+ if (memory == -1) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
+ &size_cells)) != 0)
+ goto out;
+
+ if (addr_cells > 2) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+
+ res_len = OF_getproplen(root, "memreserve");
+ if (res_len <= 0 || res_len > sizeof(reserve)) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ memory_size = 0;
+ tuples = res_len / tuple_size;
+ reservep = (pcell_t *)&reserve;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(reservep, addr_cells, size_cells,
+ (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
+
+ if (rv != 0)
+ goto out;
+
+ reservep += addr_cells + size_cells;
+ }
+
+ *mrcnt = i;
+ rv = 0;
+out:
+ return (rv);
+}
+
+int
+fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint64_t *memsize)
+{
+ pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS];
+ pcell_t *regp;
+ phandle_t memory;
+ uint64_t memory_size;
+ int addr_cells, size_cells;
+ int i, max_size, reg_len, rv, tuple_size, tuples;
+
+ max_size = sizeof(reg);
+ memory = OF_finddevice("/memory");
+ if (memory == -1) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells,
+ &size_cells)) != 0)
+ goto out;
+
+ if (addr_cells > 2) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
+ reg_len = OF_getproplen(memory, "reg");
+ if (reg_len <= 0 || reg_len > sizeof(reg)) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ if (OF_getprop(memory, "reg", reg, reg_len) <= 0) {
+ rv = ENXIO;
+ goto out;
+ }
+
+ memory_size = 0;
+ tuples = reg_len / tuple_size;
+ regp = (pcell_t *)&reg;
+ for (i = 0; i < tuples; i++) {
+
+ rv = fdt_data_to_res(regp, addr_cells, size_cells,
+ (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size);
+
+ if (rv != 0)
+ goto out;
+
+ regp += addr_cells + size_cells;
+ memory_size += mr[i].mr_size;
+ }
+
+ if (memory_size == 0) {
+ rv = ERANGE;
+ goto out;
+ }
+
+ *mrcnt = i;
+ if (memsize != NULL)
+ *memsize = memory_size;
+ rv = 0;
+out:
+ return (rv);
+}
+
+int
+fdt_get_unit(device_t dev)
+{
+ const char * name;
+
+ name = ofw_bus_get_name(dev);
+ name = strchr(name, '@') + 1;
+
+ return (strtol(name,NULL,0));
+}
+
+int
+fdt_get_chosen_bootargs(char *bootargs, size_t max_size)
+{
+ phandle_t chosen;
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return (ENXIO);
+ if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1)
+ return (ENXIO);
+ return (0);
+}
diff --git a/freebsd/sys/dev/fdt/fdt_common.h b/freebsd/sys/dev/fdt/fdt_common.h
new file mode 100644
index 00000000..81ce4bfa
--- /dev/null
+++ b/freebsd/sys/dev/fdt/fdt_common.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2009-2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FDT_COMMON_H_
+#define _FDT_COMMON_H_
+
+#include <sys/sysctl.h>
+#include <sys/slicer.h>
+#include <contrib/libfdt/libfdt_env.h>
+#include <dev/ofw/ofw_bus.h>
+
+#define FDT_MEM_REGIONS 8
+
+#define DI_MAX_INTR_NUM 32
+
+struct fdt_sense_level {
+ enum intr_trigger trig;
+ enum intr_polarity pol;
+};
+
+#if defined(__arm__) && !defined(INTRNG)
+typedef int (*fdt_pic_decode_t)(phandle_t, pcell_t *, int *, int *, int *);
+extern fdt_pic_decode_t fdt_pic_table[];
+#endif
+
+#if defined(__arm__) || defined(__powerpc__)
+typedef void (*fdt_fixup_t)(phandle_t);
+struct fdt_fixup_entry {
+ char *model;
+ fdt_fixup_t handler;
+};
+extern struct fdt_fixup_entry fdt_fixup_table[];
+#endif
+
+extern SLIST_HEAD(fdt_ic_list, fdt_ic) fdt_ic_list_head;
+struct fdt_ic {
+ SLIST_ENTRY(fdt_ic) fdt_ics;
+ ihandle_t iph;
+ device_t dev;
+};
+
+extern vm_paddr_t fdt_immr_pa;
+extern vm_offset_t fdt_immr_va;
+extern vm_offset_t fdt_immr_size;
+
+struct fdt_pm_mask_entry {
+ char *compat;
+ uint32_t mask;
+};
+extern struct fdt_pm_mask_entry fdt_pm_mask_table[];
+
+#if defined(FDT_DTB_STATIC)
+extern u_char fdt_static_dtb;
+#endif
+
+SYSCTL_DECL(_hw_fdt);
+
+int fdt_addrsize_cells(phandle_t, int *, int *);
+u_long fdt_data_get(void *, int);
+int fdt_data_to_res(pcell_t *, int, int, u_long *, u_long *);
+phandle_t fdt_find_compatible(phandle_t, const char *, int);
+phandle_t fdt_depth_search_compatible(phandle_t, const char *, int);
+int fdt_get_mem_regions(struct mem_region *, int *, uint64_t *);
+int fdt_get_reserved_regions(struct mem_region *, int *);
+int fdt_get_phyaddr(phandle_t, device_t, int *, void **);
+int fdt_get_range(phandle_t, int, u_long *, u_long *);
+int fdt_immr_addr(vm_offset_t);
+int fdt_regsize(phandle_t, u_long *, u_long *);
+int fdt_is_compatible_strict(phandle_t, const char *);
+int fdt_is_enabled(phandle_t);
+int fdt_pm_is_enabled(phandle_t);
+int fdt_is_type(phandle_t, const char *);
+int fdt_parent_addr_cells(phandle_t);
+int fdt_reg_to_rl(phandle_t, struct resource_list *);
+int fdt_pm(phandle_t);
+int fdt_get_unit(device_t);
+int fdt_get_chosen_bootargs(char *bootargs, size_t max_size);
+
+#endif /* _FDT_COMMON_H_ */
diff --git a/freebsd/sys/dev/fdt/simplebus.c b/freebsd/sys/dev/fdt/simplebus.c
new file mode 100644
index 00000000..d981d065
--- /dev/null
+++ b/freebsd/sys/dev/fdt/simplebus.c
@@ -0,0 +1,431 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2013 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/fdt/simplebus.h>
+
+/*
+ * Bus interface.
+ */
+static int simplebus_probe(device_t dev);
+static int simplebus_attach(device_t dev);
+static struct resource *simplebus_alloc_resource(device_t, device_t, int,
+ int *, rman_res_t, rman_res_t, rman_res_t, u_int);
+static void simplebus_probe_nomatch(device_t bus, device_t child);
+static int simplebus_print_child(device_t bus, device_t child);
+static device_t simplebus_add_child(device_t dev, u_int order,
+ const char *name, int unit);
+static struct resource_list *simplebus_get_resource_list(device_t bus,
+ device_t child);
+/*
+ * ofw_bus interface
+ */
+static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus,
+ device_t child);
+
+/*
+ * local methods
+ */
+
+static int simplebus_fill_ranges(phandle_t node,
+ struct simplebus_softc *sc);
+
+/*
+ * Driver methods.
+ */
+static device_method_t simplebus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, simplebus_probe),
+ DEVMETHOD(device_attach, simplebus_attach),
+ DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_add_child, simplebus_add_child),
+ DEVMETHOD(bus_print_child, simplebus_print_child),
+ DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch),
+ DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
+ DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
+ DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo),
+ DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
+ DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
+ DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
+ DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
+ DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(simplebus, simplebus_driver, simplebus_methods,
+ sizeof(struct simplebus_softc));
+
+static devclass_t simplebus_devclass;
+EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, simplebus_devclass,
+ 0, 0, BUS_PASS_BUS);
+EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass,
+ 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+
+static int
+simplebus_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ /*
+ * FDT data puts a "simple-bus" compatible string on many things that
+ * have children but aren't really busses in our world. Without a
+ * ranges property we will fail to attach, so just fail to probe too.
+ */
+ if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
+ ofw_bus_has_prop(dev, "ranges")) &&
+ (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
+ "soc") != 0))
+ return (ENXIO);
+
+ device_set_desc(dev, "Flattened device tree simple bus");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+simplebus_attach(device_t dev)
+{
+ struct simplebus_softc *sc;
+ phandle_t node;
+
+ sc = device_get_softc(dev);
+ simplebus_init(dev, 0);
+ if (simplebus_fill_ranges(sc->node, sc) < 0) {
+ device_printf(dev, "could not get ranges\n");
+ return (ENXIO);
+ }
+
+ /*
+ * In principle, simplebus could have an interrupt map, but ignore that
+ * for now
+ */
+
+ for (node = OF_child(sc->node); node > 0; node = OF_peer(node))
+ simplebus_add_device(dev, node, 0, NULL, -1, NULL);
+ return (bus_generic_attach(dev));
+}
+
+void
+simplebus_init(device_t dev, phandle_t node)
+{
+ struct simplebus_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (node == 0)
+ node = ofw_bus_get_node(dev);
+ sc->dev = dev;
+ sc->node = node;
+
+ /*
+ * Some important numbers
+ */
+ sc->acells = 2;
+ OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells));
+ sc->scells = 1;
+ OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells));
+}
+
+static int
+simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc)
+{
+ int host_address_cells;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int err;
+ int i, j, k;
+
+ err = OF_searchencprop(OF_parent(node), "#address-cells",
+ &host_address_cells, sizeof(host_address_cells));
+ if (err <= 0)
+ return (-1);
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges < 0)
+ return (-1);
+ sc->nranges = nbase_ranges / sizeof(cell_t) /
+ (sc->acells + host_address_cells + sc->scells);
+ if (sc->nranges == 0)
+ return (0);
+
+ sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
+ M_DEVBUF, M_WAITOK);
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < sc->nranges; i++) {
+ sc->ranges[i].bus = 0;
+ for (k = 0; k < sc->acells; k++) {
+ sc->ranges[i].bus <<= 32;
+ sc->ranges[i].bus |= base_ranges[j++];
+ }
+ sc->ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ sc->ranges[i].host <<= 32;
+ sc->ranges[i].host |= base_ranges[j++];
+ }
+ sc->ranges[i].size = 0;
+ for (k = 0; k < sc->scells; k++) {
+ sc->ranges[i].size <<= 32;
+ sc->ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (sc->nranges);
+}
+
+struct simplebus_devinfo *
+simplebus_setup_dinfo(device_t dev, phandle_t node,
+ struct simplebus_devinfo *di)
+{
+ struct simplebus_softc *sc;
+ struct simplebus_devinfo *ndi;
+
+ sc = device_get_softc(dev);
+ if (di == NULL)
+ ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
+ else
+ ndi = di;
+ if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) {
+ if (di == NULL)
+ free(ndi, M_DEVBUF);
+ return (NULL);
+ }
+
+ resource_list_init(&ndi->rl);
+ ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl);
+ ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL);
+
+ return (ndi);
+}
+
+device_t
+simplebus_add_device(device_t dev, phandle_t node, u_int order,
+ const char *name, int unit, struct simplebus_devinfo *di)
+{
+ struct simplebus_devinfo *ndi;
+ device_t cdev;
+
+ if ((ndi = simplebus_setup_dinfo(dev, node, di)) == NULL)
+ return (NULL);
+ cdev = device_add_child_ordered(dev, order, name, unit);
+ if (cdev == NULL) {
+ device_printf(dev, "<%s>: device_add_child failed\n",
+ ndi->obdinfo.obd_name);
+ resource_list_free(&ndi->rl);
+ ofw_bus_gen_destroy_devinfo(&ndi->obdinfo);
+ if (di == NULL)
+ free(ndi, M_DEVBUF);
+ return (NULL);
+ }
+ device_set_ivars(cdev, ndi);
+
+ return(cdev);
+}
+
+static device_t
+simplebus_add_child(device_t dev, u_int order, const char *name, int unit)
+{
+ device_t cdev;
+ struct simplebus_devinfo *ndi;
+
+ cdev = device_add_child_ordered(dev, order, name, unit);
+ if (cdev == NULL)
+ return (NULL);
+
+ ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO);
+ ndi->obdinfo.obd_node = -1;
+ resource_list_init(&ndi->rl);
+ device_set_ivars(cdev, ndi);
+
+ return (cdev);
+}
+
+static const struct ofw_bus_devinfo *
+simplebus_get_devinfo(device_t bus __unused, device_t child)
+{
+ struct simplebus_devinfo *ndi;
+
+ ndi = device_get_ivars(child);
+ if (ndi == NULL)
+ return (NULL);
+ return (&ndi->obdinfo);
+}
+
+static struct resource_list *
+simplebus_get_resource_list(device_t bus __unused, device_t child)
+{
+ struct simplebus_devinfo *ndi;
+
+ ndi = device_get_ivars(child);
+ if (ndi == NULL)
+ return (NULL);
+ return (&ndi->rl);
+}
+
+static struct resource *
+simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct simplebus_softc *sc;
+ struct simplebus_devinfo *di;
+ struct resource_list_entry *rle;
+ int j;
+
+ sc = device_get_softc(bus);
+
+ /*
+ * Request for the default allocation with a given rid: use resource
+ * list stored in the local device info.
+ */
+ if (RMAN_IS_DEFAULT_RANGE(start, end)) {
+ if ((di = device_get_ivars(child)) == NULL)
+ return (NULL);
+
+ if (type == SYS_RES_IOPORT)
+ type = SYS_RES_MEMORY;
+
+ rle = resource_list_find(&di->rl, type, *rid);
+ if (rle == NULL) {
+ if (bootverbose)
+ device_printf(bus, "no default resources for "
+ "rid = %d, type = %d\n", *rid, type);
+ return (NULL);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ if (type == SYS_RES_MEMORY) {
+ /* Remap through ranges property */
+ for (j = 0; j < sc->nranges; j++) {
+ if (start >= sc->ranges[j].bus && end <
+ sc->ranges[j].bus + sc->ranges[j].size) {
+ start -= sc->ranges[j].bus;
+ start += sc->ranges[j].host;
+ end -= sc->ranges[j].bus;
+ end += sc->ranges[j].host;
+ break;
+ }
+ }
+ if (j == sc->nranges && sc->nranges != 0) {
+ if (bootverbose)
+ device_printf(bus, "Could not map resource "
+ "%#jx-%#jx\n", start, end);
+
+ return (NULL);
+ }
+ }
+
+ return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
+ count, flags));
+}
+
+static int
+simplebus_print_res(struct simplebus_devinfo *di)
+{
+ int rv;
+
+ if (di == NULL)
+ return (0);
+ rv = 0;
+ rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd");
+ return (rv);
+}
+
+static void
+simplebus_probe_nomatch(device_t bus, device_t child)
+{
+ const char *name, *type, *compat;
+
+ if (!bootverbose)
+ return;
+
+ compat = ofw_bus_get_compat(child);
+ if (compat == NULL)
+ return;
+ name = ofw_bus_get_name(child);
+ type = ofw_bus_get_type(child);
+
+ device_printf(bus, "<%s>", name != NULL ? name : "unknown");
+ simplebus_print_res(device_get_ivars(child));
+ if (!ofw_bus_status_okay(child))
+ printf(" disabled");
+ if (type)
+ printf(" type %s", type);
+ printf(" compat %s (no driver attached)\n", compat);
+}
+
+static int
+simplebus_print_child(device_t bus, device_t child)
+{
+ int rv;
+
+ rv = bus_print_child_header(bus, child);
+ rv += simplebus_print_res(device_get_ivars(child));
+ if (!ofw_bus_status_okay(child))
+ rv += printf(" disabled");
+ rv += bus_print_child_footer(bus, child);
+ return (rv);
+}
diff --git a/freebsd/sys/dev/fdt/simplebus.h b/freebsd/sys/dev/fdt/simplebus.h
new file mode 100644
index 00000000..caccf162
--- /dev/null
+++ b/freebsd/sys/dev/fdt/simplebus.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2013 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FDT_SIMPLEBUS_H
+#define _FDT_SIMPLEBUS_H
+
+#include <dev/ofw/ofw_bus.h>
+
+/* FDT simplebus */
+DECLARE_CLASS(simplebus_driver);
+
+struct simplebus_range {
+ uint64_t bus;
+ uint64_t host;
+ uint64_t size;
+};
+
+/* devinfo and softc */
+struct simplebus_softc {
+ device_t dev;
+ phandle_t node;
+
+ struct simplebus_range *ranges;
+ int nranges;
+
+ pcell_t acells, scells;
+};
+
+struct simplebus_devinfo {
+ struct ofw_bus_devinfo obdinfo;
+ struct resource_list rl;
+};
+
+void simplebus_init(device_t dev, phandle_t node);
+device_t simplebus_add_device(device_t dev, phandle_t node, u_int order,
+ const char *name, int unit, struct simplebus_devinfo *di);
+struct simplebus_devinfo *simplebus_setup_dinfo(device_t dev, phandle_t node,
+ struct simplebus_devinfo *di);
+#endif /* _FDT_SIMPLEBUS_H */
diff --git a/freebsd/sys/dev/ofw/ofw_bus.h b/freebsd/sys/dev/ofw/ofw_bus.h
new file mode 100644
index 00000000..dff9a2b8
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_bus.h
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2001, 2003 by Thomas Moestl <tmm@FreeBSD.org>
+ * Copyright (c) 2004 by Marius Strobl <marius@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 00000000..79852afc
--- /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@FreeBSD.org>.
+ * Copyright (c) 2005 Marius Strobl <marius@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 00000000..30f299a6
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_bus_subr.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2005 Marius Strobl <marius@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 00000000..6bdaf89b
--- /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 00000000..eb60c5ba
--- /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 00000000..391d25c4
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_subr.c
@@ -0,0 +1,246 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2015 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The initial ofw_reg_to_paddr() implementation has been copied from powerpc
+ * ofw_machdep.c OF_decode_addr(). It was added by Marcel Moolenaar, who did not
+ * assert copyright with the addition but still deserves credit for the work.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/bus.h>
+#include <sys/libkern.h>
+#include <sys/reboot.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_subr.h>
+
+static void
+get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
+{
+ char type[64];
+ uint32_t addr, size;
+ int pci, res;
+
+ res = OF_getencprop(node, "#address-cells", &addr, sizeof(addr));
+ if (res == -1)
+ addr = 2;
+ res = OF_getencprop(node, "#size-cells", &size, sizeof(size));
+ if (res == -1)
+ size = 1;
+ pci = 0;
+ if (addr == 3 && size == 2) {
+ res = OF_getprop(node, "device_type", type, sizeof(type));
+ if (res != -1) {
+ type[sizeof(type) - 1] = '\0';
+ pci = (strcmp(type, "pci") == 0) ? 1 : 0;
+ }
+ }
+ if (addrp != NULL)
+ *addrp = addr;
+ if (sizep != NULL)
+ *sizep = size;
+ if (pcip != NULL)
+ *pcip = pci;
+}
+
+int
+ofw_reg_to_paddr(phandle_t dev, int regno, bus_addr_t *paddr,
+ bus_size_t *psize, pcell_t *ppci_hi)
+{
+ pcell_t cell[32], pci_hi;
+ uint64_t addr, raddr, baddr;
+ uint64_t size, rsize;
+ uint32_t c, nbridge, naddr, nsize;
+ phandle_t bridge, parent;
+ u_int spc, rspc;
+ int pci, pcib, res;
+
+ /* Sanity checking. */
+ if (dev == 0)
+ return (EINVAL);
+ bridge = OF_parent(dev);
+ if (bridge == 0)
+ return (EINVAL);
+ if (regno < 0)
+ return (EINVAL);
+ if (paddr == NULL || psize == NULL)
+ return (EINVAL);
+
+ get_addr_props(bridge, &naddr, &nsize, &pci);
+ res = OF_getencprop(dev, (pci) ? "assigned-addresses" : "reg",
+ cell, sizeof(cell));
+ if (res == -1)
+ return (ENXIO);
+ if (res % sizeof(cell[0]))
+ return (ENXIO);
+ res /= sizeof(cell[0]);
+ regno *= naddr + nsize;
+ if (regno + naddr + nsize > res)
+ return (EINVAL);
+ pci_hi = pci ? cell[regno] : OFW_PADDR_NOT_PCI;
+ spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK;
+ addr = 0;
+ for (c = 0; c < naddr; c++)
+ addr = ((uint64_t)addr << 32) | cell[regno++];
+ size = 0;
+ for (c = 0; c < nsize; c++)
+ size = ((uint64_t)size << 32) | cell[regno++];
+ /*
+ * Map the address range in the bridge's decoding window as given
+ * by the "ranges" property. If a node doesn't have such property
+ * or the property is empty, we assume an identity mapping. The
+ * standard says a missing property indicates no possible mapping.
+ * This code is more liberal since the intended use is to get a
+ * console running early, and a printf to warn of malformed data
+ * is probably futile before the console is fully set up.
+ */
+ parent = OF_parent(bridge);
+ while (parent != 0) {
+ get_addr_props(parent, &nbridge, NULL, &pcib);
+ res = OF_getencprop(bridge, "ranges", cell, sizeof(cell));
+ if (res < 1)
+ goto next;
+ if (res % sizeof(cell[0]))
+ return (ENXIO);
+ /* Capture pci_hi if we just transitioned onto a PCI bus. */
+ if (pcib && pci_hi == OFW_PADDR_NOT_PCI) {
+ pci_hi = cell[0];
+ spc = pci_hi & OFW_PCI_PHYS_HI_SPACEMASK;
+ }
+ res /= sizeof(cell[0]);
+ regno = 0;
+ while (regno < res) {
+ rspc = (pci ? cell[regno] : OFW_PADDR_NOT_PCI) &
+ OFW_PCI_PHYS_HI_SPACEMASK;
+ if (rspc != spc) {
+ regno += naddr + nbridge + nsize;
+ continue;
+ }
+ raddr = 0;
+ for (c = 0; c < naddr; c++)
+ raddr = ((uint64_t)raddr << 32) | cell[regno++];
+ rspc = (pcib)
+ ? cell[regno] & OFW_PCI_PHYS_HI_SPACEMASK
+ : OFW_PADDR_NOT_PCI;
+ baddr = 0;
+ for (c = 0; c < nbridge; c++)
+ baddr = ((uint64_t)baddr << 32) | cell[regno++];
+ rsize = 0;
+ for (c = 0; c < nsize; c++)
+ rsize = ((uint64_t)rsize << 32) | cell[regno++];
+ if (addr < raddr || addr >= raddr + rsize)
+ continue;
+ addr = addr - raddr + baddr;
+ if (rspc != OFW_PADDR_NOT_PCI)
+ spc = rspc;
+ }
+ next:
+ bridge = parent;
+ parent = OF_parent(bridge);
+ get_addr_props(bridge, &naddr, &nsize, &pci);
+ }
+
+ KASSERT(addr <= BUS_SPACE_MAXADDR,
+ ("Bus sddress is too large: %jx", (uintmax_t)addr));
+ KASSERT(size <= BUS_SPACE_MAXSIZE,
+ ("Bus size is too large: %jx", (uintmax_t)size));
+
+ *paddr = addr;
+ *psize = size;
+ if (ppci_hi != NULL)
+ *ppci_hi = pci_hi;
+
+ return (0);
+}
+
+/* Parse cmd line args as env - copied from xlp_machdep. */
+/* XXX-BZ this should really be centrally provided for all (boot) code. */
+static void
+_parse_bootargs(char *cmdline)
+{
+ char *n, *v;
+
+ while ((v = strsep(&cmdline, " \n")) != NULL) {
+ if (*v == '\0')
+ continue;
+ if (*v == '-') {
+ while (*v != '\0') {
+ v++;
+ switch (*v) {
+ case 'a': boothowto |= RB_ASKNAME; break;
+ /* Someone should simulate that ;-) */
+ case 'C': boothowto |= RB_CDROM; break;
+ case 'd': boothowto |= RB_KDB; break;
+ case 'D': boothowto |= RB_MULTIPLE; break;
+ case 'm': boothowto |= RB_MUTE; break;
+ case 'g': boothowto |= RB_GDB; break;
+ case 'h': boothowto |= RB_SERIAL; break;
+ case 'p': boothowto |= RB_PAUSE; break;
+ case 'r': boothowto |= RB_DFLTROOT; break;
+ case 's': boothowto |= RB_SINGLE; break;
+ case 'v': boothowto |= RB_VERBOSE; break;
+ }
+ }
+ } else {
+ n = strsep(&v, "=");
+ if (v == NULL)
+ kern_setenv(n, "1");
+ else
+ kern_setenv(n, v);
+ }
+ }
+}
+
+/*
+ * This is intended to be called early on, right after the OF system is
+ * initialized, so pmap may not be up yet.
+ */
+int
+ofw_parse_bootargs(void)
+{
+ phandle_t chosen;
+ char buf[2048]; /* early stack supposedly big enough */
+ int err;
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen <= 0)
+ return (chosen);
+
+ if ((err = OF_getprop(chosen, "bootargs", buf, sizeof(buf))) != -1) {
+ _parse_bootargs(buf);
+ return (0);
+ }
+
+ return (err);
+}
diff --git a/freebsd/sys/dev/ofw/ofw_subr.h b/freebsd/sys/dev/ofw/ofw_subr.h
new file mode 100644
index 00000000..ed29142d
--- /dev/null
+++ b/freebsd/sys/dev/ofw/ofw_subr.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2015 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $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 00000000..58ec2841
--- /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@FreeBSD.org>.
+ * Copyright 2006 by Marius Strobl <marius@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 00000000..ddaa3db0
--- /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 00000000..6c6cd874
--- /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 00000000..1ae47b9c
--- /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 00000000..9bf8748f
--- /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_ */