X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=drivers%2Fcore%2Froot.c;h=e6ec7faf3792c55b428923f71f2d73e46222a94d;hb=83e4c7e9ffa57fe4116967999c223c952a46a78a;hp=13c2713e615391e7ce2fb4194718d6b83f2fdabb;hpb=e6ac28b60be2d670948332197862e314b7977177;p=oweals%2Fu-boot.git diff --git a/drivers/core/root.c b/drivers/core/root.c index 13c2713e61..e6ec7faf37 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -1,21 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2013 Google, Inc * * (C) Copyright 2012 * Pavel Herrmann - * - * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include -#include +#include #include #include #include +#include +#include #include +#include #include #include #include @@ -41,6 +43,15 @@ struct udevice *dm_root(void) return gd->dm_root; } +void dm_fixup_for_gd_move(struct global_data *new_gd) +{ + /* The sentinel node has moved, so update things that point to it */ + if (gd->dm_root) { + new_gd->uclass_root.next->prev = &new_gd->uclass_root; + new_gd->uclass_root.prev->next = &new_gd->uclass_root; + } +} + fdt_addr_t dm_get_translation_offset(void) { struct udevice *root = dm_root(); @@ -122,9 +133,23 @@ void fix_uclass(void) entry->ops += gd->reloc_off; } } + +void fix_devices(void) +{ + struct driver_info *dev = + ll_entry_start(struct driver_info, driver_info); + const int n_ents = ll_entry_count(struct driver_info, driver_info); + struct driver_info *entry; + + for (entry = dev; entry != dev + n_ents; entry++) { + if (entry->platdata) + entry->platdata += gd->reloc_off; + } +} + #endif -int dm_init(void) +int dm_init(bool of_live) { int ret; @@ -137,13 +162,19 @@ int dm_init(void) #if defined(CONFIG_NEEDS_MANUAL_RELOC) fix_drivers(); fix_uclass(); + fix_devices(); #endif ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); if (ret) return ret; #if CONFIG_IS_ENABLED(OF_CONTROL) - DM_ROOT_NON_CONST->of_offset = 0; +# if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live) + DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); + else +#endif + DM_ROOT_NON_CONST->node = offset_to_ofnode(0); #endif ret = device_probe(DM_ROOT_NON_CONST); if (ret) @@ -154,12 +185,22 @@ int dm_init(void) int dm_uninit(void) { - device_remove(dm_root()); + device_remove(dm_root(), DM_REMOVE_NORMAL); device_unbind(dm_root()); + gd->dm_root = NULL; return 0; } +#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) +int dm_remove_devices_flags(uint flags) +{ + device_remove(dm_root(), flags); + + return 0; +} +#endif + int dm_scan_platdata(bool pre_reloc_only) { int ret; @@ -173,27 +214,92 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, - bool pre_reloc_only) +#if CONFIG_IS_ENABLED(OF_LIVE) +static int dm_scan_fdt_live(struct udevice *parent, + const struct device_node *node_parent, + bool pre_reloc_only) +{ + struct device_node *np; + int ret = 0, err; + + for (np = node_parent->child; np; np = np->sibling) { + /* "chosen" node isn't a device itself but may contain some: */ + if (!strcmp(np->name, "chosen")) { + pr_debug("parsing subnodes of \"chosen\"\n"); + + err = dm_scan_fdt_live(parent, np, pre_reloc_only); + if (err && !ret) + ret = err; + continue; + } + + if (!of_device_is_available(np)) { + pr_debug(" - ignoring disabled device\n"); + continue; + } + err = lists_bind_fdt(parent, np_to_ofnode(np), NULL, + pre_reloc_only); + if (err && !ret) { + ret = err; + debug("%s: ret=%d\n", np->name, ret); + } + } + + if (ret) + dm_warn("Some drivers failed to bind\n"); + + return ret; +} +#endif /* CONFIG_IS_ENABLED(OF_LIVE) */ + +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) +/** + * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node + * + * This scans the subnodes of a device tree node and and creates a driver + * for each one. + * + * @parent: Parent device for the devices that will be created + * @blob: Pointer to device tree blob + * @offset: Offset of node to scan + * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC + * flag. If false bind all drivers. + * @return 0 if OK, -ve on error + */ +static int dm_scan_fdt_node(struct udevice *parent, const void *blob, + int offset, bool pre_reloc_only) { int ret = 0, err; for (offset = fdt_first_subnode(blob, offset); offset > 0; offset = fdt_next_subnode(blob, offset)) { - if (pre_reloc_only && - !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) + const char *node_name = fdt_get_name(blob, offset, NULL); + + /* + * The "chosen" and "firmware" nodes aren't devices + * themselves but may contain some: + */ + if (!strcmp(node_name, "chosen") || + !strcmp(node_name, "firmware")) { + pr_debug("parsing subnodes of \"%s\"\n", node_name); + + err = dm_scan_fdt_node(parent, blob, offset, + pre_reloc_only); + if (err && !ret) + ret = err; continue; + } + if (!fdtdec_get_is_enabled(blob, offset)) { - dm_dbg(" - ignoring disabled device\n"); + pr_debug(" - ignoring disabled device\n"); continue; } - err = lists_bind_fdt(parent, blob, offset, NULL); + err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL, + pre_reloc_only); if (err && !ret) { ret = err; - debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), - ret); + debug("%s: ret=%d\n", node_name, ret); } } @@ -203,12 +309,78 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, return ret; } +int dm_scan_fdt_dev(struct udevice *dev) +{ + if (!dev_of_valid(dev)) + return 0; + +#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + return dm_scan_fdt_live(dev, dev_np(dev), + gd->flags & GD_FLG_RELOC ? false : true); + else +#endif + return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), + gd->flags & GD_FLG_RELOC ? false : true); +} + int dm_scan_fdt(const void *blob, bool pre_reloc_only) { +#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + return dm_scan_fdt_live(gd->dm_root, gd->of_root, + pre_reloc_only); + else +#endif return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); } +#else +static int dm_scan_fdt_node(struct udevice *parent, const void *blob, + int offset, bool pre_reloc_only) +{ + return 0; +} #endif +static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only) +{ + ofnode node; + + node = ofnode_path(path); + if (!ofnode_valid(node)) + return 0; + +#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + return dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only); +#endif + return dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset, + pre_reloc_only); +} + +int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only) +{ + int ret; + + ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); + if (ret) { + debug("dm_scan_fdt() failed: %d\n", ret); + return ret; + } + + ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only); + if (ret) { + debug("scan for /clocks failed: %d\n", ret); + return ret; + } + + ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only); + if (ret) + debug("scan for /firmware failed: %d\n", ret); + + return ret; +} + __weak int dm_scan_other(bool pre_reloc_only) { return 0; @@ -218,7 +390,7 @@ int dm_init_and_scan(bool pre_reloc_only) { int ret; - ret = dm_init(); + ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); if (ret) { debug("dm_init() failed: %d\n", ret); return ret; @@ -229,10 +401,10 @@ int dm_init_and_scan(bool pre_reloc_only) return ret; } - if (CONFIG_IS_ENABLED(OF_CONTROL)) { - ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); + if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { + ret = dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only); if (ret) { - debug("dm_scan_fdt() failed: %d\n", ret); + debug("dm_extended_scan_dt() failed: %d\n", ret); return ret; } }