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> 146a6d8fbeSSimon Glass #include <libfdt.h> 156494d708SSimon Glass #include <dm/device.h> 166494d708SSimon Glass #include <dm/device-internal.h> 176494d708SSimon Glass #include <dm/lists.h> 18*19c8205eSSimon Glass #include <dm/of.h> 19*19c8205eSSimon Glass #include <dm/of_access.h> 206494d708SSimon Glass #include <dm/platdata.h> 21*19c8205eSSimon 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 153*19c8205eSSimon 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) 173*19c8205eSSimon Glass # if CONFIG_IS_ENABLED(OF_LIVE) 174*19c8205eSSimon Glass if (of_live) 175*19c8205eSSimon Glass DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root); 176*19c8205eSSimon Glass else 177*19c8205eSSimon 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 217*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 218*19c8205eSSimon Glass static int dm_scan_fdt_live(struct udevice *parent, 219*19c8205eSSimon Glass const struct device_node *node_parent, 220*19c8205eSSimon Glass bool pre_reloc_only) 221*19c8205eSSimon Glass { 222*19c8205eSSimon Glass struct device_node *np; 223*19c8205eSSimon Glass int ret = 0, err; 224*19c8205eSSimon Glass 225*19c8205eSSimon Glass for (np = node_parent->child; np; np = np->sibling) { 226*19c8205eSSimon Glass if (pre_reloc_only && 227*19c8205eSSimon Glass !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) 228*19c8205eSSimon Glass continue; 229*19c8205eSSimon Glass if (!of_device_is_available(np)) { 230*19c8205eSSimon Glass dm_dbg(" - ignoring disabled device\n"); 231*19c8205eSSimon Glass continue; 232*19c8205eSSimon Glass } 233*19c8205eSSimon Glass err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); 234*19c8205eSSimon Glass if (err && !ret) { 235*19c8205eSSimon Glass ret = err; 236*19c8205eSSimon Glass debug("%s: ret=%d\n", np->name, ret); 237*19c8205eSSimon Glass } 238*19c8205eSSimon Glass } 239*19c8205eSSimon Glass 240*19c8205eSSimon Glass if (ret) 241*19c8205eSSimon Glass dm_warn("Some drivers failed to bind\n"); 242*19c8205eSSimon Glass 243*19c8205eSSimon Glass return ret; 244*19c8205eSSimon Glass } 245*19c8205eSSimon Glass #endif /* CONFIG_IS_ENABLED(OF_LIVE) */ 246*19c8205eSSimon 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)) { 27394f7afdfSSimon Glass dm_dbg(" - 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 { 292*19c8205eSSimon Glass if (!dev_of_valid(dev)) 293cc7f66f7SSimon Glass return 0; 294cc7f66f7SSimon Glass 295*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 296*19c8205eSSimon Glass if (of_live_active()) 297*19c8205eSSimon Glass return dm_scan_fdt_live(dev, dev_np(dev), 298*19c8205eSSimon Glass gd->flags & GD_FLG_RELOC ? false : true); 299*19c8205eSSimon Glass else 300*19c8205eSSimon 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 { 307*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE) 308*19c8205eSSimon Glass if (of_live_active()) 309*19c8205eSSimon Glass return dm_scan_fdt_live(gd->dm_root, gd->of_root, 310*19c8205eSSimon Glass pre_reloc_only); 311*19c8205eSSimon Glass else 312*19c8205eSSimon Glass #endif 3131ca7e206SSimon Glass return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); 3141ca7e206SSimon Glass } 3156494d708SSimon Glass #endif 3166494d708SSimon Glass 317bb58503dSSimon Glass __weak int dm_scan_other(bool pre_reloc_only) 318bb58503dSSimon Glass { 319bb58503dSSimon Glass return 0; 320bb58503dSSimon Glass } 321bb58503dSSimon Glass 322ab7cd627SSimon Glass int dm_init_and_scan(bool pre_reloc_only) 323ab7cd627SSimon Glass { 324ab7cd627SSimon Glass int ret; 325ab7cd627SSimon Glass 326*19c8205eSSimon Glass ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE)); 327ab7cd627SSimon Glass if (ret) { 328ab7cd627SSimon Glass debug("dm_init() failed: %d\n", ret); 329ab7cd627SSimon Glass return ret; 330ab7cd627SSimon Glass } 331ab7cd627SSimon Glass ret = dm_scan_platdata(pre_reloc_only); 332ab7cd627SSimon Glass if (ret) { 333ab7cd627SSimon Glass debug("dm_scan_platdata() failed: %d\n", ret); 334ab7cd627SSimon Glass return ret; 335ab7cd627SSimon Glass } 336b2b0d3e7SSimon Glass 33729629eb8SSimon Glass if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { 338ab7cd627SSimon Glass ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); 339ab7cd627SSimon Glass if (ret) { 340ab7cd627SSimon Glass debug("dm_scan_fdt() failed: %d\n", ret); 341ab7cd627SSimon Glass return ret; 342ab7cd627SSimon Glass } 343b2b0d3e7SSimon Glass } 344b2b0d3e7SSimon Glass 345bb58503dSSimon Glass ret = dm_scan_other(pre_reloc_only); 346bb58503dSSimon Glass if (ret) 347bb58503dSSimon Glass return ret; 348ab7cd627SSimon Glass 349ab7cd627SSimon Glass return 0; 350ab7cd627SSimon Glass } 351ab7cd627SSimon Glass 3526494d708SSimon Glass /* This is the root driver - all drivers are children of this */ 3536494d708SSimon Glass U_BOOT_DRIVER(root_driver) = { 3546494d708SSimon Glass .name = "root_driver", 3556494d708SSimon Glass .id = UCLASS_ROOT, 35666eaea6cSStefan Roese .priv_auto_alloc_size = sizeof(struct root_priv), 3576494d708SSimon Glass }; 3586494d708SSimon Glass 3596494d708SSimon Glass /* This is the root uclass */ 3606494d708SSimon Glass UCLASS_DRIVER(root) = { 3616494d708SSimon Glass .name = "root", 3626494d708SSimon Glass .id = UCLASS_ROOT, 3636494d708SSimon Glass }; 364