svn commit: r235526 - in user/jceel/soc2012_armv6/sys: arm/ti
dev/fdt dev/uart
Jakub Wojciech Klama
jceel at FreeBSD.org
Wed May 16 22:21:58 UTC 2012
Author: jceel
Date: Wed May 16 22:21:57 2012
New Revision: 235526
URL: http://svn.freebsd.org/changeset/base/235526
Log:
Rewrite FDT bus ranges calculation:
- bus ranges from DTS files are correctly read and used for translation
of device register addresses. this includes empty "ranges;" property
as well as encoded ranges tuples.
- simplebuses can be freely nested (except for system console UART which
should be placed in toplevel simplebus)
- base addresses in resources (rman) are now physical. translation or
mapping to virtual address is done via bus_space_map() and can be
accessed via rman_get_bushandle().
- ti_mmchs driver is corrected to use physical registers base address
from rman instead of using vtophys().
Modified:
user/jceel/soc2012_armv6/sys/arm/ti/ti_mmchs.c
user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.c
user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.h
user/jceel/soc2012_armv6/sys/dev/fdt/fdtbus.c
user/jceel/soc2012_armv6/sys/dev/fdt/simplebus.c
user/jceel/soc2012_armv6/sys/dev/uart/uart_bus_fdt.c
Directory Properties:
user/jceel/soc2012_armv6/ (props changed)
Modified: user/jceel/soc2012_armv6/sys/arm/ti/ti_mmchs.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/arm/ti/ti_mmchs.c Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/arm/ti/ti_mmchs.c Wed May 16 22:21:57 2012 (r235526)
@@ -1630,7 +1630,7 @@ ti_mmchs_activate(device_t dev)
panic("Unknown OMAP device\n");
/* Get the physical address of the MMC data register, needed for DMA */
- addr = vtophys(rman_get_start(sc->sc_mem_res));
+ addr = rman_get_start(sc->sc_mem_res);
sc->sc_data_reg_paddr = addr + sc->sc_reg_off + MMCHS_DATA;
/* Set the initial power state to off */
Modified: user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.c Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.c Wed May 16 22:21:57 2012 (r235526)
@@ -64,12 +64,30 @@ vm_offset_t fdt_immr_va;
vm_offset_t fdt_immr_size;
int
-fdt_get_range(phandle_t node, int range_id, u_long *base, u_long *size)
+fdt_immr_addr(vm_offset_t immr_va)
{
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);
/*
@@ -82,14 +100,6 @@ fdt_get_range(phandle_t node, int range_
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);
@@ -102,48 +112,81 @@ fdt_get_range(phandle_t node, int range_
addr_cells, size_cells)) {
return (ERANGE);
}
- *base = 0;
- *size = 0;
- rangesptr = &ranges[range_id];
+ base = 0;
+ size = 0;
+ rangesptr = &ranges[0];
- *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);
+
+ fdt_immr_pa = base;
+ fdt_immr_va = immr_va;
+ fdt_immr_size = size;
+
return (0);
}
int
-fdt_immr_addr(vm_offset_t immr_va)
+fdt_read_ranges(phandle_t node, struct fdt_range **ranges, int addr_cells,
+ int par_addr_cells, int size_cells)
{
- 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_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);
+ static pcell_t data[128];
+ pcell_t *ptr;
+ int i, len, tuple_size, ranges_count;
+
+ len = OF_getprop(node, "ranges", (void *)&data, sizeof data);
+ tuple_size = addr_cells + par_addr_cells + size_cells;
+ ranges_count = len != 0 ? len / tuple_size / sizeof(pcell_t) : 1;
+
+ debugf("tuple_size=%d ranges_count=%d\n", tuple_size, ranges_count);
+
+ ptr = data;
+
+ if (*ranges == NULL)
+ *ranges = malloc(sizeof(struct fdt_range) * ranges_count,
+ M_TEMP, M_WAITOK | M_ZERO);
+
+ /* empty ranges case */
+ if (len == 0) {
+ (*ranges)[0].base = 0l;
+ (*ranges)[0].parent = 0l;
+ (*ranges)[0].size = ~0l;
+ return (1);
+ }
-moveon:
- if ((r = fdt_get_range(node, 0, &base, &size)) == 0) {
- fdt_immr_pa = base;
- fdt_immr_va = immr_va;
- fdt_immr_size = size;
+ for (i = 0; i < ranges_count; i++) {
+ (*ranges)[i].base = fdt_data_get((void *)ptr, addr_cells);
+ ptr += addr_cells;
+ (*ranges)[i].parent = fdt_data_get((void *)ptr, par_addr_cells);
+ ptr += par_addr_cells;
+ (*ranges)[i].size = fdt_data_get((void *)ptr, size_cells);
+ ptr += size_cells;
+
+ debugf("new range: base=%lx parent=%lx size=%lx\n",
+ (*ranges)[i].base, (*ranges[i]).parent,
+ (*ranges)[i].size);
+ }
+
+ return (ranges_count);
+}
+
+__inline u_long
+fdt_ranges_lookup(struct fdt_range *ranges, int nranges, u_long addr,
+ u_long size)
+{
+ int n;
+
+ for (n = 0; n < nranges; n++) {
+ if (ranges[n].base <= addr && (ranges[n].base +
+ ranges[n].size >= addr + size - 1)) {
+ return ranges[n].parent;
+ }
}
- return (r);
+ return 0;
}
/*
@@ -419,19 +462,17 @@ fdt_regsize(phandle_t node, u_long *base
}
int
-fdt_reg_to_rl(phandle_t node, struct resource_list *rl)
+fdt_reg_to_rl(phandle_t node, struct resource_list *rl,
+ struct fdt_range *ranges, int ranges_count)
{
- u_long start, end, count;
+ u_long start, end, count, parent;
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 **)®);
@@ -453,15 +494,22 @@ fdt_reg_to_rl(phandle_t node, struct res
reg += addr_cells + size_cells;
/* Calculate address range relative to base. */
- 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;
+ parent = 0;
+
+ if (ranges == NULL)
+ goto moveon;
+
+ parent = fdt_ranges_lookup(ranges, ranges_count, start, count);
+
+moveon:
+
+ start = parent + start;
+ end = start + count - 1;
- debugf("reg addr start = %lx, end = %lx, count = %lx\n", vaddr,
+ debugf("reg addr start = %lx, end = %lx, count = %lx\n", start,
end, count);
- resource_list_add(rl, SYS_RES_MEMORY, i, vaddr, end,
+ resource_list_add(rl, SYS_RES_MEMORY, i, start, end,
count);
}
rv = 0;
Modified: user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.h
==============================================================================
--- user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.h Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/dev/fdt/fdt_common.h Wed May 16 22:21:57 2012 (r235526)
@@ -40,6 +40,12 @@
#define DI_MAX_INTR_NUM 8
+struct fdt_range {
+ u_long base;
+ u_long parent;
+ u_long size;
+};
+
struct fdt_pci_range {
u_long base_pci;
u_long base_parent;
@@ -90,8 +96,11 @@ 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_read_ranges(phandle_t node, struct fdt_range **ranges, int addr_cells,
+ int par_addr_cells, int size_cels);
+u_long fdt_ranges_lookup(struct fdt_range *ranges, int nranges, u_long addr,
+ u_long size);
int fdt_regsize(phandle_t, u_long *, u_long *);
int fdt_intr_decode(phandle_t, pcell_t *, int *, int *, int *);
int fdt_intr_to_rl(phandle_t, struct resource_list *, struct fdt_sense_level *);
@@ -107,7 +116,7 @@ int fdt_pci_ranges_decode(phandle_t, str
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 *);
+int fdt_reg_to_rl(phandle_t, struct resource_list *, struct fdt_range *, int);
int fdt_pm(phandle_t);
#endif /* _FDT_COMMON_H_ */
Modified: user/jceel/soc2012_armv6/sys/dev/fdt/fdtbus.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/dev/fdt/fdtbus.c Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/dev/fdt/fdtbus.c Wed May 16 22:21:57 2012 (r235526)
@@ -290,7 +290,7 @@ newbus_device_create(device_t dev_par, p
resource_list_init(&di->di_res);
- if (fdt_reg_to_rl(node, &di->di_res)) {
+ if (fdt_reg_to_rl(node, &di->di_res, NULL, 0)) {
device_printf(child, "could not process 'reg' property\n");
newbus_device_destroy(child);
child = NULL;
@@ -378,9 +378,7 @@ newbus_pci_create(device_t dev_par, phan
}
/* Calculate address range relative to base. */
- par_base &= 0x000ffffful;
- start &= 0x000ffffful;
- start += par_base + fdt_immr_va;
+ start += par_base;
if (count == 0)
count = par_size;
end = start + count - 1;
@@ -487,6 +485,7 @@ fdtbus_alloc_resource(device_t bus, devi
struct rman *rm;
struct fdtbus_devinfo *di;
struct resource_list_entry *rle;
+ bus_space_handle_t bsh;
int needactivate;
/*
@@ -541,8 +540,16 @@ fdtbus_alloc_resource(device_t bus, devi
if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) {
/* XXX endianess should be set based on SOC node */
+ if (bus_space_map(fdtbus_bs_tag, rman_get_start(res),
+ rman_get_size(res), 0, &bsh))
+ printf("cannot map memory on 0x%lx\n",
+ rman_get_start(res));
+
rman_set_bustag(res, fdtbus_bs_tag);
- rman_set_bushandle(res, rman_get_start(res));
+ rman_set_bushandle(res, bsh);
+
+ debugf("%s: virtual register space: 0x%lx\n",
+ device_get_name(child), bsh);
}
if (needactivate)
Modified: user/jceel/soc2012_armv6/sys/dev/fdt/simplebus.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/dev/fdt/simplebus.c Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/dev/fdt/simplebus.c Wed May 16 22:21:57 2012 (r235526)
@@ -59,8 +59,10 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_SIMPLEBUS, "simplebus", "simplebus devices information");
struct simplebus_softc {
- int sc_addr_cells;
- int sc_size_cells;
+ int sc_addr_cells;
+ int sc_size_cells;
+ struct fdt_range * sc_ranges;
+ int sc_ranges_count;
};
struct simplebus_devinfo {
@@ -129,6 +131,7 @@ static driver_t simplebus_driver = {
devclass_t simplebus_devclass;
DRIVER_MODULE(simplebus, fdtbus, simplebus_driver, simplebus_devclass, 0, 0);
+DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass, 0, 0);
static int
simplebus_probe(device_t dev)
@@ -146,11 +149,48 @@ static int
simplebus_attach(device_t dev)
{
device_t dev_child;
+ device_t parent;
struct simplebus_devinfo *di;
struct simplebus_softc *sc;
+ struct simplebus_softc *parent_sc;
phandle_t dt_node, dt_child;
+ int i, par_addr_cells;
sc = device_get_softc(dev);
+ dt_node = ofw_bus_get_node(dev);
+
+ if ((fdt_addrsize_cells(dt_node, &sc->sc_addr_cells, &sc->sc_size_cells)) != 0)
+ return (ENXIO);
+
+ /*
+ * Process 'ranges' property
+ */
+ par_addr_cells = fdt_parent_addr_cells(dt_node);
+ if (par_addr_cells > 2)
+ return (ERANGE);
+
+ sc->sc_ranges_count = fdt_read_ranges(dt_node, &sc->sc_ranges,
+ sc->sc_addr_cells, par_addr_cells, sc->sc_size_cells);
+ if (sc->sc_ranges_count <= 0)
+ device_printf(dev, "WARNING: could not read bus ranges.");
+
+ /*
+ * Check if we're nested. If so, look up parent simplebus
+ * ranges and merge it with ours.
+ */
+ parent = device_get_parent(dev);
+
+ if (device_get_devclass(parent) == simplebus_devclass) {
+ parent_sc = device_get_softc(parent);
+ for (i = 0; i < sc->sc_ranges_count; i++) {
+ sc->sc_ranges[i].parent += fdt_ranges_lookup(
+ parent_sc->sc_ranges,
+ parent_sc->sc_ranges_count,
+ sc->sc_ranges[i].parent,
+ sc->sc_ranges[i].size);
+ }
+ }
+
/*
* Walk simple-bus and add direct subordinates as our children.
@@ -175,7 +215,9 @@ simplebus_attach(device_t dev)
}
resource_list_init(&di->di_res);
- if (fdt_reg_to_rl(dt_child, &di->di_res)) {
+
+ if (fdt_reg_to_rl(dt_child, &di->di_res, sc->sc_ranges,
+ sc->sc_ranges_count)) {
device_printf(dev,
"%s: could not process 'reg' "
"property\n", di->di_ofw.obd_name);
Modified: user/jceel/soc2012_armv6/sys/dev/uart/uart_bus_fdt.c
==============================================================================
--- user/jceel/soc2012_armv6/sys/dev/uart/uart_bus_fdt.c Wed May 16 22:19:22 2012 (r235525)
+++ user/jceel/soc2012_armv6/sys/dev/uart/uart_bus_fdt.c Wed May 16 22:21:57 2012 (r235526)
@@ -137,10 +137,13 @@ uart_cpu_getdev(int devtype, struct uart
{
char buf[64];
struct uart_class *class;
- phandle_t node, chosen;
+ phandle_t node, parent, chosen;
pcell_t shift, br, rclk;
- u_long start, size, pbase, psize;
- int err;
+ u_long start, size;
+ struct fdt_range ranges[8];
+ struct fdt_range *rptr = ranges;
+ int err, addr_cells, par_addr_cells, size_cells;
+ int nranges;
uart_bus_space_mem = fdtbus_bs_tag;
uart_bus_space_io = NULL;
@@ -168,6 +171,21 @@ uart_cpu_getdev(int devtype, struct uart
if (OF_finddevice(buf) != node)
/* Only stdin == stdout is supported. */
return (ENXIO);
+
+ /*
+ * Retrieve UART device parent bus
+ */
+ if ((parent = OF_parent(node)) <= 0)
+ return (ENXIO);
+ if (fdt_addrsize_cells(parent, &addr_cells, &size_cells))
+ return (ENXIO);
+ if ((par_addr_cells = fdt_parent_addr_cells(parent)) > 2)
+ return (ENXIO);
+ nranges = fdt_read_ranges(parent, &rptr, addr_cells,
+ par_addr_cells, size_cells);
+ if (nranges <= 0)
+ return (ENXIO);
+
/*
* Retrieve serial attributes.
*/
@@ -203,8 +221,11 @@ uart_cpu_getdev(int devtype, struct uart
if (err)
return (ENXIO);
- fdt_get_range(OF_parent(node), 0, &pbase, &psize);
- start += pbase;
+ /*
+ * XXX this will not work with uart sitting on
+ * simplebus nested in other simplebus.
+ */
+ start += fdt_ranges_lookup(ranges, nranges, start, size);
return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh));
}
More information about the svn-src-user
mailing list