summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/fdt/fdt_common.c92
-rw-r--r--sys/dev/fdt/fdt_common.h3
-rw-r--r--sys/dev/fdt/fdtbus.c2
-rw-r--r--sys/dev/fdt/simplebus.c16
-rw-r--r--sys/dev/uart/uart_bus_fdt.c6
5 files changed, 70 insertions, 49 deletions
diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c
index bf18e34..0504c67 100644
--- a/sys/dev/fdt/fdt_common.c
+++ b/sys/dev/fdt/fdt_common.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/bus.h>
+#include <sys/limits.h>
#include <machine/fdt.h>
#include <machine/resource.h>
@@ -63,30 +64,12 @@ vm_offset_t fdt_immr_va;
vm_offset_t fdt_immr_size;
int
-fdt_immr_addr(vm_offset_t immr_va)
+fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
{
pcell_t ranges[6], *rangesptr;
- phandle_t node;
- u_long base, size;
pcell_t addr_cells, size_cells, par_addr_cells;
int len, tuple_size, tuples;
- /*
- * Try to access the SOC node directly i.e. through /aliases/.
- */
- if ((node = OF_finddevice("soc")) != -1)
- if (fdt_is_compatible_strict(node, "simple-bus"))
- goto moveon;
- /*
- * Find the node the long way.
- */
- if ((node = OF_finddevice("/")) == -1)
- return (ENXIO);
-
- if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0)
- return (ENXIO);
-
-moveon:
if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
return (ENXIO);
/*
@@ -99,6 +82,14 @@ moveon:
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);
@@ -111,21 +102,48 @@ moveon:
addr_cells, size_cells)) {
return (ERANGE);
}
- base = 0;
- size = 0;
- rangesptr = &ranges[0];
+ *base = 0;
+ *size = 0;
+ rangesptr = &ranges[range_id];
- base = fdt_data_get((void *)rangesptr, addr_cells);
+ *base = fdt_data_get((void *)rangesptr, addr_cells);
rangesptr += addr_cells;
- base += fdt_data_get((void *)rangesptr, par_addr_cells);
+ *base += fdt_data_get((void *)rangesptr, par_addr_cells);
rangesptr += par_addr_cells;
- size = fdt_data_get((void *)rangesptr, size_cells);
+ *size = fdt_data_get((void *)rangesptr, size_cells);
+ return (0);
+}
- fdt_immr_pa = base;
- fdt_immr_va = immr_va;
- fdt_immr_size = size;
+int
+fdt_immr_addr(vm_offset_t immr_va)
+{
+ phandle_t node;
+ u_long base, size;
+ int r;
- return (0);
+ /*
+ * Try to access the SOC node directly i.e. through /aliases/.
+ */
+ if ((node = OF_finddevice("soc")) != 0)
+ if (fdt_is_compatible_strict(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", 1)) == 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);
}
/*
@@ -401,16 +419,19 @@ fdt_regsize(phandle_t node, u_long *base, u_long *size)
}
int
-fdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base)
+fdt_reg_to_rl(phandle_t node, struct resource_list *rl)
{
u_long start, end, count;
pcell_t *reg, *regptr;
pcell_t addr_cells, size_cells;
int tuple_size, tuples;
int i, rv;
+ long vaddr;
+ long busaddr, bussize;
if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
return (ENXIO);
+ fdt_get_range(OF_parent(node), 0, &busaddr, &bussize);
tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)&reg);
@@ -432,14 +453,15 @@ fdt_reg_to_rl(phandle_t node, struct resource_list *rl, u_long base)
reg += addr_cells + size_cells;
/* Calculate address range relative to base. */
- start &= 0x000ffffful;
- start = base + start;
- end = start + count - 1;
+ start += busaddr;
+ if (bus_space_map(fdtbus_bs_tag, start, count, 0, &vaddr) != 0)
+ panic("Couldn't map the device memory");
+ end = vaddr + count - 1;
- debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
+ debugf("reg addr start = %lx, end = %lx, count = %lx\n", vaddr,
end, count);
- resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
+ resource_list_add(rl, SYS_RES_MEMORY, i, vaddr, end,
count);
}
rv = 0;
diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h
index 7947428..4dea494 100644
--- a/sys/dev/fdt/fdt_common.h
+++ b/sys/dev/fdt/fdt_common.h
@@ -91,6 +91,7 @@ int fdt_data_verify(void *, int);
phandle_t fdt_find_compatible(phandle_t, const char *, int);
int fdt_get_mem_regions(struct mem_region *, int *, uint32_t *);
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_intr_decode(phandle_t, pcell_t *, int *, int *, int *);
@@ -107,7 +108,7 @@ int fdt_pci_ranges_decode(phandle_t, struct fdt_pci_range *,
struct fdt_pci_range *);
int fdt_pci_route_intr(int, int, int, int, struct fdt_pci_intr *, int *);
int fdt_ranges_verify(pcell_t *, int, int, int, int);
-int fdt_reg_to_rl(phandle_t, struct resource_list *, u_long);
+int fdt_reg_to_rl(phandle_t, struct resource_list *);
int fdt_pm(phandle_t);
#endif /* _FDT_COMMON_H_ */
diff --git a/sys/dev/fdt/fdtbus.c b/sys/dev/fdt/fdtbus.c
index a18ae57..2ca7ab5 100644
--- a/sys/dev/fdt/fdtbus.c
+++ b/sys/dev/fdt/fdtbus.c
@@ -289,7 +289,7 @@ newbus_device_create(device_t dev_par, phandle_t node, char *name, char *type,
resource_list_init(&di->di_res);
- if (fdt_reg_to_rl(node, &di->di_res, fdt_immr_va)) {
+ if (fdt_reg_to_rl(node, &di->di_res)) {
device_printf(child, "could not process 'reg' property\n");
newbus_device_destroy(child);
child = NULL;
diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index 0868fb0..db9ade0 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -61,9 +61,6 @@ static MALLOC_DEFINE(M_SIMPLEBUS, "simplebus", "simplebus devices information");
struct simplebus_softc {
int sc_addr_cells;
int sc_size_cells;
- u_long sc_start_pa;
- u_long sc_start_va;
- u_long sc_size;
};
struct simplebus_devinfo {
@@ -155,10 +152,6 @@ simplebus_attach(device_t dev)
sc = device_get_softc(dev);
- sc->sc_start_pa = fdt_immr_pa;
- sc->sc_start_va = fdt_immr_va;
- sc->sc_size = fdt_immr_size;
-
/*
* Walk simple-bus and add direct subordinates as our children.
*/
@@ -182,10 +175,11 @@ simplebus_attach(device_t dev)
}
resource_list_init(&di->di_res);
-
- if (fdt_reg_to_rl(dt_child, &di->di_res, sc->sc_start_va)) {
- device_printf(dev, "%s: could not process 'reg' "
+ if (fdt_reg_to_rl(dt_child, &di->di_res)) {
+ device_printf(dev,
+ "%s: could not process 'reg' "
"property\n", di->di_ofw.obd_name);
+ /* XXX should unmap */
ofw_bus_gen_destroy_devinfo(&di->di_ofw);
free(di, M_SIMPLEBUS);
continue;
@@ -195,6 +189,7 @@ simplebus_attach(device_t dev)
device_printf(dev, "%s: could not process "
"'interrupts' property\n", di->di_ofw.obd_name);
resource_list_free(&di->di_res);
+ /* XXX should unmap */
ofw_bus_gen_destroy_devinfo(&di->di_ofw);
free(di, M_SIMPLEBUS);
continue;
@@ -206,6 +201,7 @@ simplebus_attach(device_t dev)
device_printf(dev, "could not add child: %s\n",
di->di_ofw.obd_name);
resource_list_free(&di->di_res);
+ /* XXX should unmap */
ofw_bus_gen_destroy_devinfo(&di->di_ofw);
free(di, M_SIMPLEBUS);
continue;
diff --git a/sys/dev/uart/uart_bus_fdt.c b/sys/dev/uart/uart_bus_fdt.c
index 8bb62ea..88523b5 100644
--- a/sys/dev/uart/uart_bus_fdt.c
+++ b/sys/dev/uart/uart_bus_fdt.c
@@ -137,7 +137,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
struct uart_class *class;
phandle_t node, chosen;
pcell_t shift, br, rclk;
- u_long start, size;
+ u_long start, size, pbase, psize;
int err;
uart_bus_space_mem = fdtbus_bs_tag;
@@ -197,7 +197,9 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
err = fdt_regsize(node, &start, &size);
if (err)
return (ENXIO);
- start += fdt_immr_va;
+
+ fdt_get_range(OF_parent(node), 0, &pbase, &psize);
+ start += pbase;
return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh));
}
OpenPOWER on IntegriCloud