16494d708SSimon Glass /* 26494d708SSimon Glass * Copyright (c) 2013 Google, Inc 36494d708SSimon Glass * 46494d708SSimon Glass * (C) Copyright 2012 56494d708SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com> 66494d708SSimon Glass * 76494d708SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 86494d708SSimon Glass */ 96494d708SSimon Glass 106494d708SSimon Glass #include <common.h> 116494d708SSimon Glass #include <errno.h> 1294f7afdfSSimon Glass #include <fdtdec.h> 136494d708SSimon Glass #include <malloc.h> 14*0e00a84cSMasahiro Yamada #include <linux/libfdt.h> 156494d708SSimon Glass #include <dm/device.h> 166494d708SSimon Glass #include <dm/device-internal.h> 176494d708SSimon Glass #include <dm/lists.h> 1819c8205eSSimon Glass #include <dm/of.h> 1919c8205eSSimon Glass #include <dm/of_access.h> 206494d708SSimon Glass #include <dm/platdata.h> 2119c8205eSSimon Glass #include <dm/read.h> 22fd536d81SJeroen Hofstee #include <dm/root.h> 236494d708SSimon Glass #include <dm/uclass.h> 246494d708SSimon Glass #include <dm/util.h> 256494d708SSimon Glass #include <linux/list.h> 266494d708SSimon Glass 276494d708SSimon Glass DECLARE_GLOBAL_DATA_PTR; 286494d708SSimon Glass 2966eaea6cSStefan Roese struct root_priv { 3066eaea6cSStefan Roese fdt_addr_t translation_offset; /* optional translation offset */ 3166eaea6cSStefan Roese }; 3266eaea6cSStefan Roese 336494d708SSimon Glass static const struct driver_info root_info = { 346494d708SSimon Glass .name = "root_driver", 356494d708SSimon Glass }; 366494d708SSimon Glass 3754c5d08aSHeiko Schocher struct udevice *dm_root(void) 386494d708SSimon Glass { 396494d708SSimon Glass if (!gd->dm_root) { 406494d708SSimon Glass dm_warn("Virtual root driver does not exist!\n"); 416494d708SSimon Glass return NULL; 426494d708SSimon Glass } 436494d708SSimon Glass 446494d708SSimon Glass return gd->dm_root; 456494d708SSimon Glass } 466494d708SSimon Glass 472f11cd91SSimon Glass void dm_fixup_for_gd_move(struct global_data *new_gd) 482f11cd91SSimon Glass { 492f11cd91SSimon Glass /* The sentinel node has moved, so update things that point to it */ 50b0d9512aSLokesh Vutla if (gd->dm_root) { 512f11cd91SSimon Glass new_gd->uclass_root.next->prev = &new_gd->uclass_root; 522f11cd91SSimon Glass new_gd->uclass_root.prev->next = &new_gd->uclass_root; 532f11cd91SSimon Glass } 54b0d9512aSLokesh Vutla } 552f11cd91SSimon Glass 5666eaea6cSStefan Roese fdt_addr_t dm_get_translation_offset(void) 5766eaea6cSStefan Roese { 5866eaea6cSStefan Roese struct udevice *root = dm_root(); 5966eaea6cSStefan Roese struct root_priv *priv = dev_get_priv(root); 6066eaea6cSStefan Roese 6166eaea6cSStefan Roese return priv->translation_offset; 6266eaea6cSStefan Roese } 6366eaea6cSStefan Roese 6466eaea6cSStefan Roese void dm_set_translation_offset(fdt_addr_t offs) 6566eaea6cSStefan Roese { 6666eaea6cSStefan Roese struct udevice *root = dm_root(); 6766eaea6cSStefan Roese struct root_priv *priv = dev_get_priv(root); 6866eaea6cSStefan Roese 6966eaea6cSStefan Roese priv->translation_offset = offs; 7066eaea6cSStefan Roese } 7166eaea6cSStefan Roese 72484fdf5bSMichal Simek #if defined(CONFIG_NEEDS_MANUAL_RELOC) 73484fdf5bSMichal Simek void fix_drivers(void) 74484fdf5bSMichal Simek { 75484fdf5bSMichal Simek struct driver *drv = 76484fdf5bSMichal Simek ll_entry_start(struct driver, driver); 77484fdf5bSMichal Simek const int n_ents = ll_entry_count(struct driver, driver); 78484fdf5bSMichal Simek struct driver *entry; 79484fdf5bSMichal Simek 80484fdf5bSMichal Simek for (entry = drv; entry != drv + n_ents; entry++) { 81484fdf5bSMichal Simek if (entry->of_match) 82484fdf5bSMichal Simek entry->of_match = (const struct udevice_id *) 83484fdf5bSMichal Simek ((u32)entry->of_match + gd->reloc_off); 84484fdf5bSMichal Simek if (entry->bind) 85484fdf5bSMichal Simek entry->bind += gd->reloc_off; 86484fdf5bSMichal Simek if (entry->probe) 87484fdf5bSMichal Simek entry->probe += gd->reloc_off; 88484fdf5bSMichal Simek if (entry->remove) 89484fdf5bSMichal Simek entry->remove += gd->reloc_off; 90484fdf5bSMichal Simek if (entry->unbind) 91484fdf5bSMichal Simek entry->unbind += gd->reloc_off; 92484fdf5bSMichal Simek if (entry->ofdata_to_platdata) 93484fdf5bSMichal Simek entry->ofdata_to_platdata += gd->reloc_off; 9431e1029aSMichal Simek if (entry->child_post_bind) 9531e1029aSMichal Simek entry->child_post_bind += gd->reloc_off; 96484fdf5bSMichal Simek if (entry->child_pre_probe) 97484fdf5bSMichal Simek entry->child_pre_probe += gd->reloc_off; 98484fdf5bSMichal Simek if (entry->child_post_remove) 99484fdf5bSMichal Simek entry->child_post_remove += gd->reloc_off; 100484fdf5bSMichal Simek /* OPS are fixed in every uclass post_probe function */ 101484fdf5bSMichal Simek if (entry->ops) 102484fdf5bSMichal Simek entry->ops += gd->reloc_off; 103484fdf5bSMichal Simek } 104484fdf5bSMichal Simek } 105484fdf5bSMichal Simek 106484fdf5bSMichal Simek void fix_uclass(void) 107484fdf5bSMichal Simek { 108484fdf5bSMichal Simek struct uclass_driver *uclass = 109484fdf5bSMichal Simek ll_entry_start(struct uclass_driver, uclass); 110484fdf5bSMichal Simek const int n_ents = ll_entry_count(struct uclass_driver, uclass); 111484fdf5bSMichal Simek struct uclass_driver *entry; 112484fdf5bSMichal Simek 113484fdf5bSMichal Simek for (entry = uclass; entry != uclass + n_ents; entry++) { 114484fdf5bSMichal Simek if (entry->post_bind) 115484fdf5bSMichal Simek entry->post_bind += gd->reloc_off; 116484fdf5bSMichal Simek if (entry->pre_unbind) 117484fdf5bSMichal Simek entry->pre_unbind += gd->reloc_off; 11831e1029aSMichal Simek if (entry->pre_probe) 11931e1029aSMichal Simek entry->pre_probe += gd->reloc_off; 120484fdf5bSMichal Simek if (entry->post_probe) 121484fdf5bSMichal Simek entry->post_probe += gd->reloc_off; 122484fdf5bSMichal Simek if (entry->pre_remove) 123484fdf5bSMichal Simek entry->pre_remove += gd->reloc_off; 12431e1029aSMichal Simek if (entry->child_post_bind) 12531e1029aSMichal Simek entry->child_post_bind += gd->reloc_off; 12631e1029aSMichal Simek if (entry->child_pre_probe) 12731e1029aSMichal Simek entry->child_pre_probe += gd->reloc_off; 128484fdf5bSMichal Simek if (entry->init) 129484fdf5bSMichal Simek entry->init += gd->reloc_off; 130484fdf5bSMichal Simek if (entry->destroy) 131484fdf5bSMichal Simek entry->destroy += gd->reloc_off; 132484fdf5bSMichal Simek /* FIXME maybe also need to fix these ops */ 133484fdf5bSMichal Simek if (entry->ops) 134484fdf5bSMichal Simek entry->ops += gd->reloc_off; 135484fdf5bSMichal Simek } 136484fdf5bSMichal Simek } 1375aeedebcSAngelo Dureghello 1385aeedebcSAngelo Dureghello void fix_devices(void) 1395aeedebcSAngelo Dureghello { 1405aeedebcSAngelo Dureghello struct driver_info *dev = 1415aeedebcSAngelo Dureghello ll_entry_start(struct driver_info, driver_info); 1425aeedebcSAngelo Dureghello const int n_ents = ll_entry_count(struct driver_info, driver_info); 1435aeedebcSAngelo Dureghello struct driver_info *entry; 1445aeedebcSAngelo Dureghello 1455aeedebcSAngelo Dureghello for (entry = dev; entry != dev + n_ents; entry++) { 1465aeedebcSAngelo Dureghello if (entry->platdata) 1475aeedebcSAngelo Dureghello entry->platdata += gd->reloc_off; 1485aeedebcSAngelo Dureghello } 1495aeedebcSAngelo Dureghello } 1505aeedebcSAngelo Dureghello 151484fdf5bSMichal Simek #endif 152484fdf5bSMichal Simek 15319c8205eSSimon Glass int dm_init(bool of_live) 1546494d708SSimon Glass { 1556494d708SSimon Glass int ret; 1566494d708SSimon Glass 1576494d708SSimon Glass if (gd->dm_root) { 1586494d708SSimon Glass dm_warn("Virtual root driver already exists!\n"); 1596494d708SSimon Glass return -EINVAL; 1606494d708SSimon Glass } 16189876a55SSimon Glass INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); 1626494d708SSimon Glass 163484fdf5bSMichal Simek #if defined(CONFIG_NEEDS_MANUAL_RELOC) 164484fdf5bSMichal Simek fix_drivers(); 165484fdf5bSMichal Simek fix_uclass(); 1665aeedebcSAngelo Dureghello fix_devices(); 167484fdf5bSMichal Simek #endif 168484fdf5bSMichal Simek 16900606d7eSSimon Glass ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); 1706494d708SSimon Glass if (ret) 1716494d708SSimon Glass return ret; 1720f925822SMasahiro Yamada #if CONFIG_IS_ENABLED(OF_CONTROL) 17319c8205eSSimon Glass # if CONFIG_IS_ENABLED(OF_LIVE) 17419c8205eSSimon Glass if (of_live) 17519c8205eSSimon Glass DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); 17619c8205eSSimon Glass else 17719c8205eSSimon Glass #endif 1784984de2bSSimon Glass DM_ROOT_NON_CONST->node = offset_to_ofnode(0); 1792f3b95dbSSimon Glass #endif 1807497812dSSimon Glass ret = device_probe(DM_ROOT_NON_CONST); 1817497812dSSimon Glass if (ret) 1827497812dSSimon Glass return ret; 1836494d708SSimon Glass 1846494d708SSimon Glass return 0; 1856494d708SSimon Glass } 1866494d708SSimon Glass 1879adbd7a1SSimon Glass int dm_uninit(void) 1889adbd7a1SSimon Glass { 189706865afSStefan Roese device_remove(dm_root(), DM_REMOVE_NORMAL); 1909adbd7a1SSimon Glass device_unbind(dm_root()); 1919adbd7a1SSimon Glass 1929adbd7a1SSimon Glass return 0; 1939adbd7a1SSimon Glass } 1949adbd7a1SSimon Glass 195bc85aa40SStefan Roese #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) 196bc85aa40SStefan Roese int dm_remove_devices_flags(uint flags) 197bc85aa40SStefan Roese { 198bc85aa40SStefan Roese device_remove(dm_root(), flags); 199bc85aa40SStefan Roese 200bc85aa40SStefan Roese return 0; 201bc85aa40SStefan Roese } 202bc85aa40SStefan Roese #endif 203bc85aa40SStefan Roese 20400606d7eSSimon Glass int dm_scan_platdata(bool pre_reloc_only) 2056494d708SSimon Glass { 2066494d708SSimon Glass int ret; 2076494d708SSimon Glass 20800606d7eSSimon Glass ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only); 2096494d708SSimon Glass if (ret == -ENOENT) { 2106494d708SSimon Glass dm_warn("Some drivers were not found\n"); 2116494d708SSimon Glass ret = 0; 2126494d708SSimon Glass } 2136494d708SSimon Glass 214cbf86d71SMasahiro Yamada return ret; 2156494d708SSimon Glass } 2166494d708SSimon Glass 21719c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 21819c8205eSSimon Glass static int dm_scan_fdt_live(struct udevice *parent, 21919c8205eSSimon Glass const struct device_node *node_parent, 22019c8205eSSimon Glass bool pre_reloc_only) 22119c8205eSSimon Glass { 22219c8205eSSimon Glass struct device_node *np; 22319c8205eSSimon Glass int ret = 0, err; 22419c8205eSSimon Glass 22519c8205eSSimon Glass for (np = node_parent->child; np; np = np->sibling) { 22619c8205eSSimon Glass if (pre_reloc_only && 22719c8205eSSimon Glass !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) 22819c8205eSSimon Glass continue; 22919c8205eSSimon Glass if (!of_device_is_available(np)) { 230d42197e4SMasahiro Yamada pr_debug(" - ignoring disabled device\n"); 23119c8205eSSimon Glass continue; 23219c8205eSSimon Glass } 23319c8205eSSimon Glass err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); 23419c8205eSSimon Glass if (err && !ret) { 23519c8205eSSimon Glass ret = err; 23619c8205eSSimon Glass debug("%s: ret=%d\n", np->name, ret); 23719c8205eSSimon Glass } 23819c8205eSSimon Glass } 23919c8205eSSimon Glass 24019c8205eSSimon Glass if (ret) 24119c8205eSSimon Glass dm_warn("Some drivers failed to bind\n"); 24219c8205eSSimon Glass 24319c8205eSSimon Glass return ret; 24419c8205eSSimon Glass } 24519c8205eSSimon Glass #endif /* CONFIG_IS_ENABLED(OF_LIVE) */ 24619c8205eSSimon Glass 24729629eb8SSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 248a771a04fSSimon Glass /** 249a771a04fSSimon Glass * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node 250a771a04fSSimon Glass * 251a771a04fSSimon Glass * This scans the subnodes of a device tree node and and creates a driver 252a771a04fSSimon Glass * for each one. 253a771a04fSSimon Glass * 254a771a04fSSimon Glass * @parent: Parent device for the devices that will be created 255a771a04fSSimon Glass * @blob: Pointer to device tree blob 256a771a04fSSimon Glass * @offset: Offset of node to scan 257a771a04fSSimon Glass * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC 258a771a04fSSimon Glass * flag. If false bind all drivers. 259a771a04fSSimon Glass * @return 0 if OK, -ve on error 260a771a04fSSimon Glass */ 261a771a04fSSimon Glass static int dm_scan_fdt_node(struct udevice *parent, const void *blob, 262a771a04fSSimon Glass int offset, bool pre_reloc_only) 2636494d708SSimon Glass { 2646494d708SSimon Glass int ret = 0, err; 2656494d708SSimon Glass 2661ca7e206SSimon Glass for (offset = fdt_first_subnode(blob, offset); 2671ca7e206SSimon Glass offset > 0; 2681ca7e206SSimon Glass offset = fdt_next_subnode(blob, offset)) { 26900606d7eSSimon Glass if (pre_reloc_only && 27027326c7eSHeiko Stübner !dm_fdt_pre_reloc(blob, offset)) 27100606d7eSSimon Glass continue; 27294f7afdfSSimon Glass if (!fdtdec_get_is_enabled(blob, offset)) { 273d42197e4SMasahiro Yamada pr_debug(" - ignoring disabled device\n"); 27494f7afdfSSimon Glass continue; 27594f7afdfSSimon Glass } 276f5b5719cSSimon Glass err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); 277bc7b2f43SSimon Glass if (err && !ret) { 2786494d708SSimon Glass ret = err; 279bc7b2f43SSimon Glass debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), 280bc7b2f43SSimon Glass ret); 281bc7b2f43SSimon Glass } 2826494d708SSimon Glass } 2836494d708SSimon Glass 2846494d708SSimon Glass if (ret) 2856494d708SSimon Glass dm_warn("Some drivers failed to bind\n"); 2866494d708SSimon Glass 2876494d708SSimon Glass return ret; 2886494d708SSimon Glass } 2891ca7e206SSimon Glass 290cc7f66f7SSimon Glass int dm_scan_fdt_dev(struct udevice *dev) 291cc7f66f7SSimon Glass { 29219c8205eSSimon Glass if (!dev_of_valid(dev)) 293cc7f66f7SSimon Glass return 0; 294cc7f66f7SSimon Glass 29519c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 29619c8205eSSimon Glass if (of_live_active()) 29719c8205eSSimon Glass return dm_scan_fdt_live(dev, dev_np(dev), 29819c8205eSSimon Glass gd->flags & GD_FLG_RELOC ? false : true); 29919c8205eSSimon Glass else 30019c8205eSSimon Glass #endif 301e160f7d4SSimon Glass return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev), 302cc7f66f7SSimon Glass gd->flags & GD_FLG_RELOC ? false : true); 303cc7f66f7SSimon Glass } 304cc7f66f7SSimon Glass 3051ca7e206SSimon Glass int dm_scan_fdt(const void *blob, bool pre_reloc_only) 3061ca7e206SSimon Glass { 30719c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 30819c8205eSSimon Glass if (of_live_active()) 30919c8205eSSimon Glass return dm_scan_fdt_live(gd->dm_root, gd->of_root, 31019c8205eSSimon Glass pre_reloc_only); 31119c8205eSSimon Glass else 31219c8205eSSimon Glass #endif 3131ca7e206SSimon Glass return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); 3141ca7e206SSimon Glass } 31546fb92f0SPatrice Chotard #else 31646fb92f0SPatrice Chotard static int dm_scan_fdt_node(struct udevice *parent, const void *blob, 31746fb92f0SPatrice Chotard int offset, bool pre_reloc_only) 31846fb92f0SPatrice Chotard { 31946fb92f0SPatrice Chotard return 0; 32046fb92f0SPatrice Chotard } 3216494d708SSimon Glass #endif 3226494d708SSimon Glass 32346fb92f0SPatrice Chotard int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only) 32446fb92f0SPatrice Chotard { 32546fb92f0SPatrice Chotard int node, ret; 32646fb92f0SPatrice Chotard 32746fb92f0SPatrice Chotard ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); 32846fb92f0SPatrice Chotard if (ret) { 32946fb92f0SPatrice Chotard debug("dm_scan_fdt() failed: %d\n", ret); 33046fb92f0SPatrice Chotard return ret; 33146fb92f0SPatrice Chotard } 33246fb92f0SPatrice Chotard 33346fb92f0SPatrice Chotard /* bind fixed-clock */ 33446fb92f0SPatrice Chotard node = ofnode_to_offset(ofnode_path("/clocks")); 33546fb92f0SPatrice Chotard /* if no DT "clocks" node, no need to go further */ 33646fb92f0SPatrice Chotard if (node < 0) 33746fb92f0SPatrice Chotard return ret; 33846fb92f0SPatrice Chotard 33946fb92f0SPatrice Chotard ret = dm_scan_fdt_node(gd->dm_root, gd->fdt_blob, node, 34046fb92f0SPatrice Chotard pre_reloc_only); 34146fb92f0SPatrice Chotard if (ret) 34246fb92f0SPatrice Chotard debug("dm_scan_fdt_node() failed: %d\n", ret); 34346fb92f0SPatrice Chotard 34446fb92f0SPatrice Chotard return ret; 34546fb92f0SPatrice Chotard } 34646fb92f0SPatrice Chotard 347bb58503dSSimon Glass __weak int dm_scan_other(bool pre_reloc_only) 348bb58503dSSimon Glass { 349bb58503dSSimon Glass return 0; 350bb58503dSSimon Glass } 351bb58503dSSimon Glass 352ab7cd627SSimon Glass int dm_init_and_scan(bool pre_reloc_only) 353ab7cd627SSimon Glass { 354ab7cd627SSimon Glass int ret; 355ab7cd627SSimon Glass 35619c8205eSSimon Glass ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); 357ab7cd627SSimon Glass if (ret) { 358ab7cd627SSimon Glass debug("dm_init() failed: %d\n", ret); 359ab7cd627SSimon Glass return ret; 360ab7cd627SSimon Glass } 361ab7cd627SSimon Glass ret = dm_scan_platdata(pre_reloc_only); 362ab7cd627SSimon Glass if (ret) { 363ab7cd627SSimon Glass debug("dm_scan_platdata() failed: %d\n", ret); 364ab7cd627SSimon Glass return ret; 365ab7cd627SSimon Glass } 366b2b0d3e7SSimon Glass 36729629eb8SSimon Glass if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { 36846fb92f0SPatrice Chotard ret = dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only); 369ab7cd627SSimon Glass if (ret) { 37046fb92f0SPatrice Chotard debug("dm_extended_scan_dt() failed: %d\n", ret); 371ab7cd627SSimon Glass return ret; 372ab7cd627SSimon Glass } 373b2b0d3e7SSimon Glass } 374b2b0d3e7SSimon Glass 375bb58503dSSimon Glass ret = dm_scan_other(pre_reloc_only); 376bb58503dSSimon Glass if (ret) 377bb58503dSSimon Glass return ret; 378ab7cd627SSimon Glass 379ab7cd627SSimon Glass return 0; 380ab7cd627SSimon Glass } 381ab7cd627SSimon Glass 3826494d708SSimon Glass /* This is the root driver - all drivers are children of this */ 3836494d708SSimon Glass U_BOOT_DRIVER(root_driver) = { 3846494d708SSimon Glass .name = "root_driver", 3856494d708SSimon Glass .id = UCLASS_ROOT, 38666eaea6cSStefan Roese .priv_auto_alloc_size = sizeof(struct root_priv), 3876494d708SSimon Glass }; 3886494d708SSimon Glass 3896494d708SSimon Glass /* This is the root uclass */ 3906494d708SSimon Glass UCLASS_DRIVER(root) = { 3916494d708SSimon Glass .name = "root", 3926494d708SSimon Glass .id = UCLASS_ROOT, 3936494d708SSimon Glass }; 394