Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F149656330
D4217.1790655933.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D4217.1790655933.diff
View Options
Index: sys/dev/fdt/simplebus.h
===================================================================
--- sys/dev/fdt/simplebus.h
+++ sys/dev/fdt/simplebus.h
@@ -61,4 +61,6 @@
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);
+int simplebus_get_base_addr(phandle_t node, u_long start, u_long size,
+ u_long *phys_addr);
#endif /* _FDT_SIMPLEBUS_H */
Index: sys/dev/fdt/simplebus.c
===================================================================
--- sys/dev/fdt/simplebus.c
+++ sys/dev/fdt/simplebus.c
@@ -39,6 +39,7 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/fdt/simplebus.h>
+#include <dev/fdt/fdt_common.h>
/*
* Bus interface.
@@ -421,3 +422,108 @@
rv += bus_print_child_footer(bus, child);
return (rv);
}
+
+/* Limit size of stack buffers */
+#define MAX_RANGES 8
+#define MAX_CELLS_PER_RANGE 6
+
+/* Calculate absolute physical base address of a device node */
+int
+simplebus_get_base_addr(phandle_t node, u_long start, u_long size,
+ u_long *phys_addr)
+{
+ struct simplebus_range ranges[MAX_RANGES];
+ cell_t base_ranges[MAX_CELLS_PER_RANGE * MAX_RANGES];
+ ssize_t nbase_ranges, rv;
+ int i, j, k, nranges;
+ pcell_t addr_cells, host_address_cells, size_cells;
+ u_long end;
+
+ end = start + size - 1;
+ /* Get parent bus of the node */
+ node = OF_parent(node);
+
+ /* Work from the immediate parent of the device node up to the root node
+ * translating the base address through 'ranges' properties of every
+ * simple-bus parent, the same way simplebus_alloc_resource() does it.
+ */
+ for (; node != 0; node = OF_parent(node)) {
+ if (!fdt_is_compatible(node, "simple-bus"))
+ continue;
+
+ rv = OF_getencprop(node, "#address-cells", &addr_cells,
+ sizeof(addr_cells));
+ if (rv <= 0)
+ addr_cells = 2; /* Default size used by simplebus */
+
+ rv = OF_getencprop(OF_parent(node), "#address-cells",
+ &host_address_cells, sizeof(host_address_cells));
+ if (rv <= 0)
+ host_address_cells = 2; /* Default size */
+
+ rv = OF_getencprop(node, "#size-cells", &size_cells,
+ sizeof(size_cells));
+ if (rv <= 0)
+ size_cells = 1; /* Default size */
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges < 0)
+ return (-1);
+
+ if (nbase_ranges == 0) {
+ /* Empty ranges; property means 1:1 mapping */
+ continue;
+ }
+
+ nranges = nbase_ranges / sizeof(cell_t) /
+ (addr_cells + host_address_cells + size_cells);
+
+ if (nranges == 0 || (nranges > MAX_RANGES))
+ return (-1);
+
+ /* Copy ranges data into local buffer */
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ /* Parse bus and host addresses along with sizes */
+ for (i = 0, j = 0; i < nranges; i++) {
+ ranges[i].bus = 0;
+ for (k = 0; k < addr_cells; k++) {
+ ranges[i].bus <<= 32;
+ ranges[i].bus |= base_ranges[j++];
+ }
+ ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ ranges[i].host <<= 32;
+ ranges[i].host |= base_ranges[j++];
+ }
+ ranges[i].size = 0;
+ for (k = 0; k < size_cells; k++) {
+ ranges[i].size <<= 32;
+ ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ /* Remap through ranges property */
+ for (i = 0; i < nranges; i++) {
+ if (start >= ranges[i].bus && end <
+ (ranges[i].bus + ranges[i].size)) {
+ /* Found matching range entry */
+ start -= ranges[i].bus;
+ start += ranges[i].host;
+ end -= ranges[i].bus;
+ end += ranges[i].host;
+ break;
+ }
+ }
+
+ if (i == nranges) {
+ /* Could not find corresponding range entry */
+ printf("%s: address space translation error\n",
+ __func__);
+ return (-1);
+ }
+ }
+
+ *phys_addr = start;
+ return (0);
+}
Index: sys/dev/uart/uart_cpu_fdt.c
===================================================================
--- sys/dev/uart/uart_cpu_fdt.c
+++ sys/dev/uart/uart_cpu_fdt.c
@@ -47,6 +47,7 @@
#endif
#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/simplebus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/uart/uart.h>
@@ -215,13 +216,20 @@
di->bas.bst = uart_bus_space_mem;
err = fdt_regsize(node, &start, &size);
- if (err)
+ if (err != 0)
return (ENXIO);
- err = fdt_get_range(OF_parent(node), 0, &pbase, &psize);
- if (err)
- pbase = 0;
- start += pbase;
+ if (fdt_is_compatible(OF_parent(node), "simple-bus")) {
+ /* Get the physical base address of UART registers */
+ if (simplebus_get_base_addr(node, start, size, &start))
+ return (ENXIO);
+ } else {
+ err = fdt_get_range(OF_parent(node), 0, &pbase, &psize);
+ if (err != 0)
+ pbase = 0;
+
+ start += pbase;
+ }
return (bus_space_map(di->bas.bst, start, size, 0, &di->bas.bsh));
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 29, 4:25 AM (21 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29998792
Default Alt Text
D4217.1790655933.diff (4 KB)
Attached To
Mode
D4217: Remap UART physical address through simple-bus ranges
Attached
Detach File
Event Timeline
Log In to Comment