X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fcore%2Froot.c;h=72bcc7d7f2a308ead763df3626594c8d9f5a5d16;hb=43519c4da700a7df66dd48dd031e8a51bab1dde2;hp=12d046051fdb3af8065adcd18d5bc017d6dc25b9;hpb=e536ab8849b2b4f6d68bbc8e1d1f9bc033db06bd;p=u-boot diff --git a/drivers/core/root.c b/drivers/core/root.c index 12d046051f..72bcc7d7f2 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 @@ -23,6 +25,10 @@ DECLARE_GLOBAL_DATA_PTR; +struct root_priv { + fdt_addr_t translation_offset; /* optional translation offset */ +}; + static const struct driver_info root_info = { .name = "root_driver", }; @@ -37,6 +43,31 @@ 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(); + struct root_priv *priv = dev_get_priv(root); + + return priv->translation_offset; +} + +void dm_set_translation_offset(fdt_addr_t offs) +{ + struct udevice *root = dm_root(); + struct root_priv *priv = dev_get_priv(root); + + priv->translation_offset = offs; +} + #if defined(CONFIG_NEEDS_MANUAL_RELOC) void fix_drivers(void) { @@ -59,6 +90,8 @@ void fix_drivers(void) entry->unbind += gd->reloc_off; if (entry->ofdata_to_platdata) entry->ofdata_to_platdata += gd->reloc_off; + if (entry->child_post_bind) + entry->child_post_bind += gd->reloc_off; if (entry->child_pre_probe) entry->child_pre_probe += gd->reloc_off; if (entry->child_post_remove) @@ -81,10 +114,16 @@ void fix_uclass(void) entry->post_bind += gd->reloc_off; if (entry->pre_unbind) entry->pre_unbind += gd->reloc_off; + if (entry->pre_probe) + entry->pre_probe += gd->reloc_off; if (entry->post_probe) entry->post_probe += gd->reloc_off; if (entry->pre_remove) entry->pre_remove += gd->reloc_off; + if (entry->child_post_bind) + entry->child_post_bind += gd->reloc_off; + if (entry->child_pre_probe) + entry->child_pre_probe += gd->reloc_off; if (entry->init) entry->init += gd->reloc_off; if (entry->destroy) @@ -94,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; @@ -109,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; -#ifdef CONFIG_OF_CONTROL - DM_ROOT_NON_CONST->of_offset = 0; +#if CONFIG_IS_ENABLED(OF_CONTROL) +# 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) @@ -126,12 +185,21 @@ int dm_init(void) int dm_uninit(void) { - device_remove(dm_root()); + device_remove(dm_root(), DM_REMOVE_NORMAL); device_unbind(dm_root()); 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; @@ -145,25 +213,82 @@ int dm_scan_platdata(bool pre_reloc_only) return ret; } -#ifdef CONFIG_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) { + if (pre_reloc_only && + !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) + continue; + if (!of_device_is_available(np)) { + pr_debug(" - ignoring disabled device\n"); + continue; + } + err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); + 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)) { + /* "chosen" node isn't a device itself but may contain some: */ + if (!strcmp(fdt_get_name(blob, offset, NULL), "chosen")) { + pr_debug("parsing subnodes of \"chosen\"\n"); + + err = dm_scan_fdt_node(parent, blob, offset, + pre_reloc_only); + if (err && !ret) + ret = err; + continue; + } + if (pre_reloc_only && - !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) + !dm_fdt_pre_reloc(blob, offset)) 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); - if (err && !ret) + err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); + if (err && !ret) { ret = err; + debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), + ret); + } } if (ret) @@ -172,12 +297,69 @@ 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 +int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only) +{ + int ret; + ofnode node; + + ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); + if (ret) { + debug("dm_scan_fdt() failed: %d\n", ret); + return ret; + } + + /* bind fixed-clock */ + node = ofnode_path("/clocks"); + /* if no DT "clocks" node, no need to go further */ + if (!ofnode_valid(node)) + return ret; + +#if CONFIG_IS_ENABLED(OF_LIVE) + if (of_live_active()) + ret = dm_scan_fdt_live(gd->dm_root, node.np, pre_reloc_only); + else +#endif + ret = dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node.of_offset, + pre_reloc_only); + if (ret) + debug("dm_scan_fdt_node() failed: %d\n", ret); + + return ret; +} + __weak int dm_scan_other(bool pre_reloc_only) { return 0; @@ -187,7 +369,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; @@ -198,10 +380,10 @@ int dm_init_and_scan(bool pre_reloc_only) return ret; } - if (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; } } @@ -217,6 +399,7 @@ int dm_init_and_scan(bool pre_reloc_only) U_BOOT_DRIVER(root_driver) = { .name = "root_driver", .id = UCLASS_ROOT, + .priv_auto_alloc_size = sizeof(struct root_priv), }; /* This is the root uclass */