fdt-dummy1 = "/translation-test@8000/dev@1,100";
fdt-dummy2 = "/translation-test@8000/dev@2,200";
fdt-dummy3 = "/translation-test@8000/noxlatebus@3,300/dev@42";
+ fdt-dummy4 = "/translation-test@8000/xlatebus@4,400/devs/dev@19";
usb0 = &usb_0;
usb1 = &usb_1;
usb2 = &usb_2;
1 0x100 0x9000 0x1000
2 0x200 0xA000 0x1000
3 0x300 0xB000 0x1000
+ 4 0x400 0xC000 0x1000
>;
dma-ranges = <0 0x000 0x10000000 0x1000
reg = <0x42>;
};
};
+
+ xlatebus@4,400 {
+ compatible = "sandbox,zero-size-cells-bus";
+ reg = <4 0x400 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 4 0x400 0x1000>;
+
+ devs {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dev@19 {
+ compatible = "denx,u-boot-fdt-dummy";
+ reg = <0x19>;
+ };
+ };
+ };
+
};
osd {
#include <exports.h>
#include <fdtdec.h>
+DECLARE_GLOBAL_DATA_PTR;
+
/**
* fdt_getprop_u32_default_node - Return a node's property or a default
*
/* Max address size we deal with */
#define OF_MAX_ADDR_CELLS 4
#define OF_BAD_ADDR FDT_ADDR_T_NONE
-#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
- (ns) > 0)
+#define OF_CHECK_COUNTS(na, ns) (((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) && \
+ ((ns) > 0 || gd_size_cells_0()))
/* Debug utility */
#ifdef DEBUG
used for the address translation. This function is faster and
smaller in size than fdt_translate_address().
+config OF_TRANSLATE_ZERO_SIZE_CELLS
+ bool "Enable translation for zero size cells"
+ depends on OF_TRANSLATE
+ default n
+ help
+ The routine used to translate an FDT address into a physical CPU
+ address was developed by IBM. It considers that crossing any level
+ with #size-cells = <0> makes translation impossible, even if it is
+ not the way it was specified.
+ Enabling this option makes translation possible even in the case
+ of crossing levels with #size-cells = <0>.
+
config SPL_OF_TRANSLATE
bool "Translate addresses using fdt_translate_address in SPL"
depends on SPL_DM && SPL_OF_CONTROL
reg += index * (na + ns);
- if (ns) {
+ if (ns || gd_size_cells_0()) {
/*
* Use the full-fledged translate function for complex
* bus setups.
/* Max address size we deal with */
#define OF_MAX_ADDR_CELLS 4
#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
-#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
+#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && \
+ ((ns) > 0 || gd_size_cells_0()))
static struct of_bus *of_match_bus(struct device_node *np);
}
EXPORT_SYMBOL(of_get_address);
-static int of_empty_ranges_quirk(const struct device_node *np)
-{
- return false;
-}
-
static int of_translate_one(const struct device_node *parent,
struct of_bus *bus, struct of_bus *pbus,
__be32 *addr, int na, int ns, int pna,
* As far as we know, this damage only exists on Apple machines, so
* This code is only enabled on powerpc. --gcl
*/
+
ranges = of_get_property(parent, rprop, &rlen);
- if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
- debug("no ranges; cannot translate\n");
- return 1;
- }
if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
ns = of_n_size_cells(ofnode_to_np(node));
- if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE) &&
+ (ns > 0 || gd_size_cells_0())) {
return of_translate_address(ofnode_to_np(node), prop_val);
} else {
na = of_n_addr_cells(ofnode_to_np(node));
ns = of_n_size_cells(np);
*sizep = of_read_number(prop + na, ns);
- if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
+ if (CONFIG_IS_ENABLED(OF_TRANSLATE) &&
+ (ns > 0 || gd_size_cells_0())) {
return of_translate_address(np, prop);
+ }
else
return of_read_number(prop, na);
} else {
{
int ret;
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS))
+ gd->dm_flags |= GD_DM_FLG_SIZE_CELLS_0;
+
if (gd->dm_root) {
dm_warn("Virtual root driver already exists!\n");
return -EINVAL;
struct global_data *new_gd;
#ifdef CONFIG_DM
+ /**
+ * @dm_flags: additional flags for Driver Model
+ *
+ * See &enum gd_dm_flags
+ */
+ unsigned long dm_flags;
/**
* @dm_root: root instance for Driver Model
*/
#define gd_acpi_ctx() NULL
#endif
+#if CONFIG_IS_ENABLED(DM)
+#define gd_size_cells_0() (gd->dm_flags & GD_DM_FLG_SIZE_CELLS_0)
+#else
+#define gd_size_cells_0() (0)
+#endif
+
/**
* enum gd_flags - global data flags
*
GD_FLG_SMP_READY = 0x40000,
};
+/**
+ * enum gd_dm_flags - global data flags for Driver Model
+ *
+ * See field dm_flags of &struct global_data.
+ */
+enum gd_dm_flags {
+ /**
+ * @GD_DM_FLG_SIZE_CELLS_0: Enable #size-cells=<0> translation
+ */
+ GD_DM_FLG_SIZE_CELLS_0 = 0x00001,
+};
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_GENERIC_GBL_DATA_H */
#include <common.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <errno.h>
#include <fdtdec.h>
#include <log.h>
.id = UCLASS_TEST_DUMMY,
};
+static int zero_size_cells_bus_bind(struct udevice *dev)
+{
+ ofnode child;
+ int err;
+
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ if (ofnode_get_property(child, "compatible", NULL))
+ continue;
+
+ err = device_bind_driver_to_node(dev,
+ "zero_size_cells_bus_child_drv",
+ "zero_size_cells_bus_child",
+ child, NULL);
+ if (err) {
+ dev_err(dev, "%s: failed to bind %s\n", __func__,
+ ofnode_get_name(child));
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static const struct udevice_id zero_size_cells_bus_ids[] = {
+ { .compatible = "sandbox,zero-size-cells-bus" },
+ { }
+};
+
+U_BOOT_DRIVER(zero_size_cells_bus) = {
+ .name = "zero_size_cells_bus_drv",
+ .id = UCLASS_TEST_DUMMY,
+ .of_match = zero_size_cells_bus_ids,
+ .bind = zero_size_cells_bus_bind,
+};
+
+static int zero_size_cells_bus_child_bind(struct udevice *dev)
+{
+ ofnode child;
+ int err;
+
+ ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+ err = lists_bind_fdt(dev, child, NULL, false);
+ if (err) {
+ dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
+ __func__, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(zero_size_cells_bus_child_drv) = {
+ .name = "zero_size_cells_bus_child_drv",
+ .id = UCLASS_TEST_DUMMY,
+ .bind = zero_size_cells_bus_child_bind,
+};
+
static int dm_test_fdt_translation(struct unit_test_state *uts)
{
struct udevice *dev;
/* No translation for busses with #size-cells == 0 */
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 3, &dev));
ut_asserteq_str("dev@42", dev->name);
+ /* No translation for busses with #size-cells == 0 */
ut_asserteq(0x42, dev_read_addr(dev));
+ /* Translation for busses with #size-cells == 0 */
+ gd->dm_flags |= GD_DM_FLG_SIZE_CELLS_0;
+ ut_asserteq(0x8042, dev_read_addr(dev));
+ ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 4, &dev));
+ ut_asserteq_str("dev@19", dev->name);
+ ut_asserteq(0xc019, dev_read_addr(dev));
+ gd->dm_flags &= ~GD_DM_FLG_SIZE_CELLS_0;
+
/* dma address translation */
ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, &dev));
dma_addr[0] = cpu_to_be32(0);