16494d708SSimon Glass /* 26494d708SSimon Glass * Device manager 36494d708SSimon Glass * 46494d708SSimon Glass * Copyright (c) 2013 Google, Inc 56494d708SSimon Glass * 66494d708SSimon Glass * (C) Copyright 2012 76494d708SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com> 86494d708SSimon Glass * 96494d708SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 106494d708SSimon Glass */ 116494d708SSimon Glass 126494d708SSimon Glass #include <common.h> 135a66a8ffSSimon Glass #include <fdtdec.h> 14ef5cd330SStefan Roese #include <fdt_support.h> 156494d708SSimon Glass #include <malloc.h> 166494d708SSimon Glass #include <dm/device.h> 176494d708SSimon Glass #include <dm/device-internal.h> 186494d708SSimon Glass #include <dm/lists.h> 19d90a5a30SMasahiro Yamada #include <dm/pinctrl.h> 206494d708SSimon Glass #include <dm/platdata.h> 216494d708SSimon Glass #include <dm/uclass.h> 226494d708SSimon Glass #include <dm/uclass-internal.h> 236494d708SSimon Glass #include <dm/util.h> 246494d708SSimon Glass #include <linux/err.h> 256494d708SSimon Glass #include <linux/list.h> 266494d708SSimon Glass 275a66a8ffSSimon Glass DECLARE_GLOBAL_DATA_PTR; 285a66a8ffSSimon Glass 29*daac3bfeSStephen Warren static int device_bind_common(struct udevice *parent, const struct driver *drv, 30*daac3bfeSStephen Warren const char *name, void *platdata, 31*daac3bfeSStephen Warren ulong driver_data, int of_offset, 323479253dSSimon Glass struct udevice **devp) 336494d708SSimon Glass { 3454c5d08aSHeiko Schocher struct udevice *dev; 356494d708SSimon Glass struct uclass *uc; 365eaed880SPrzemyslaw Marczak int size, ret = 0; 376494d708SSimon Glass 38e6cabe4aSMasahiro Yamada if (devp) 396494d708SSimon Glass *devp = NULL; 406494d708SSimon Glass if (!name) 416494d708SSimon Glass return -EINVAL; 426494d708SSimon Glass 436494d708SSimon Glass ret = uclass_get(drv->id, &uc); 443346c876SSimon Glass if (ret) { 453346c876SSimon Glass debug("Missing uclass for driver %s\n", drv->name); 466494d708SSimon Glass return ret; 473346c876SSimon Glass } 486494d708SSimon Glass 4954c5d08aSHeiko Schocher dev = calloc(1, sizeof(struct udevice)); 506494d708SSimon Glass if (!dev) 516494d708SSimon Glass return -ENOMEM; 526494d708SSimon Glass 536494d708SSimon Glass INIT_LIST_HEAD(&dev->sibling_node); 546494d708SSimon Glass INIT_LIST_HEAD(&dev->child_head); 556494d708SSimon Glass INIT_LIST_HEAD(&dev->uclass_node); 56e2282d70SMasahiro Yamada #ifdef CONFIG_DEVRES 57608f26c5SMasahiro Yamada INIT_LIST_HEAD(&dev->devres_head); 58e2282d70SMasahiro Yamada #endif 596494d708SSimon Glass dev->platdata = platdata; 60*daac3bfeSStephen Warren dev->driver_data = driver_data; 616494d708SSimon Glass dev->name = name; 626494d708SSimon Glass dev->of_offset = of_offset; 636494d708SSimon Glass dev->parent = parent; 646494d708SSimon Glass dev->driver = drv; 656494d708SSimon Glass dev->uclass = uc; 665a66a8ffSSimon Glass 675a66a8ffSSimon Glass dev->seq = -1; 6891cbd792SSimon Glass dev->req_seq = -1; 694f627c5aSNathan Rossi if (CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_SEQ_ALIAS)) { 709cc36a2bSSimon Glass /* 7136fa61dcSSimon Glass * Some devices, such as a SPI bus, I2C bus and serial ports 7236fa61dcSSimon Glass * are numbered using aliases. 739cc36a2bSSimon Glass * 749cc36a2bSSimon Glass * This is just a 'requested' sequence, and will be 759cc36a2bSSimon Glass * resolved (and ->seq updated) when the device is probed. 769cc36a2bSSimon Glass */ 779cc36a2bSSimon Glass if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) { 789cc36a2bSSimon Glass if (uc->uc_drv->name && of_offset != -1) { 7936fa61dcSSimon Glass fdtdec_get_alias_seq(gd->fdt_blob, 8036fa61dcSSimon Glass uc->uc_drv->name, of_offset, 8136fa61dcSSimon Glass &dev->req_seq); 829cc36a2bSSimon Glass } 839cc36a2bSSimon Glass } 8436fa61dcSSimon Glass } 8536fa61dcSSimon Glass 86f8a85449SSimon Glass if (!dev->platdata && drv->platdata_auto_alloc_size) { 876494d708SSimon Glass dev->flags |= DM_FLAG_ALLOC_PDATA; 88f8a85449SSimon Glass dev->platdata = calloc(1, drv->platdata_auto_alloc_size); 89f8a85449SSimon Glass if (!dev->platdata) { 90f8a85449SSimon Glass ret = -ENOMEM; 91f8a85449SSimon Glass goto fail_alloc1; 92f8a85449SSimon Glass } 93f8a85449SSimon Glass } 94cdc133bdSSimon Glass 955eaed880SPrzemyslaw Marczak size = uc->uc_drv->per_device_platdata_auto_alloc_size; 965eaed880SPrzemyslaw Marczak if (size) { 975eaed880SPrzemyslaw Marczak dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA; 985eaed880SPrzemyslaw Marczak dev->uclass_platdata = calloc(1, size); 995eaed880SPrzemyslaw Marczak if (!dev->uclass_platdata) { 1005eaed880SPrzemyslaw Marczak ret = -ENOMEM; 1015eaed880SPrzemyslaw Marczak goto fail_alloc2; 1025eaed880SPrzemyslaw Marczak } 1035eaed880SPrzemyslaw Marczak } 1045eaed880SPrzemyslaw Marczak 1055eaed880SPrzemyslaw Marczak if (parent) { 1065eaed880SPrzemyslaw Marczak size = parent->driver->per_child_platdata_auto_alloc_size; 107ba8da9dcSSimon Glass if (!size) { 108ba8da9dcSSimon Glass size = parent->uclass->uc_drv-> 109ba8da9dcSSimon Glass per_child_platdata_auto_alloc_size; 110ba8da9dcSSimon Glass } 111cdc133bdSSimon Glass if (size) { 112cdc133bdSSimon Glass dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA; 113cdc133bdSSimon Glass dev->parent_platdata = calloc(1, size); 114cdc133bdSSimon Glass if (!dev->parent_platdata) { 115cdc133bdSSimon Glass ret = -ENOMEM; 1165eaed880SPrzemyslaw Marczak goto fail_alloc3; 117cdc133bdSSimon Glass } 118cdc133bdSSimon Glass } 119cdc133bdSSimon Glass } 1206494d708SSimon Glass 1216494d708SSimon Glass /* put dev into parent's successor list */ 1226494d708SSimon Glass if (parent) 1236494d708SSimon Glass list_add_tail(&dev->sibling_node, &parent->child_head); 1246494d708SSimon Glass 1256494d708SSimon Glass ret = uclass_bind_device(dev); 1266494d708SSimon Glass if (ret) 12772ebfe86SSimon Glass goto fail_uclass_bind; 1286494d708SSimon Glass 1296494d708SSimon Glass /* if we fail to bind we remove device from successors and free it */ 1306494d708SSimon Glass if (drv->bind) { 1316494d708SSimon Glass ret = drv->bind(dev); 13272ebfe86SSimon Glass if (ret) 1336494d708SSimon Glass goto fail_bind; 1346494d708SSimon Glass } 1350118ce79SSimon Glass if (parent && parent->driver->child_post_bind) { 1360118ce79SSimon Glass ret = parent->driver->child_post_bind(dev); 1370118ce79SSimon Glass if (ret) 1380118ce79SSimon Glass goto fail_child_post_bind; 1390118ce79SSimon Glass } 14020af3c0aSSimon Glass if (uc->uc_drv->post_bind) { 14120af3c0aSSimon Glass ret = uc->uc_drv->post_bind(dev); 14220af3c0aSSimon Glass if (ret) 14320af3c0aSSimon Glass goto fail_uclass_post_bind; 14420af3c0aSSimon Glass } 1450118ce79SSimon Glass 1466494d708SSimon Glass if (parent) 1476494d708SSimon Glass dm_dbg("Bound device %s to %s\n", dev->name, parent->name); 148e6cabe4aSMasahiro Yamada if (devp) 1496494d708SSimon Glass *devp = dev; 1506494d708SSimon Glass 151aed1a4ddSMasahiro Yamada dev->flags |= DM_FLAG_BOUND; 152aed1a4ddSMasahiro Yamada 1536494d708SSimon Glass return 0; 1546494d708SSimon Glass 15520af3c0aSSimon Glass fail_uclass_post_bind: 15620af3c0aSSimon Glass /* There is no child unbind() method, so no clean-up required */ 1570118ce79SSimon Glass fail_child_post_bind: 1580a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { 1590118ce79SSimon Glass if (drv->unbind && drv->unbind(dev)) { 1600118ce79SSimon Glass dm_warn("unbind() method failed on dev '%s' on error path\n", 1610118ce79SSimon Glass dev->name); 1620118ce79SSimon Glass } 1635a87c417SSimon Glass } 1640118ce79SSimon Glass 1656494d708SSimon Glass fail_bind: 1660a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { 16772ebfe86SSimon Glass if (uclass_unbind_device(dev)) { 16872ebfe86SSimon Glass dm_warn("Failed to unbind dev '%s' on error path\n", 16972ebfe86SSimon Glass dev->name); 17072ebfe86SSimon Glass } 1715a87c417SSimon Glass } 17272ebfe86SSimon Glass fail_uclass_bind: 1730a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { 1746494d708SSimon Glass list_del(&dev->sibling_node); 175cdc133bdSSimon Glass if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { 176cdc133bdSSimon Glass free(dev->parent_platdata); 177cdc133bdSSimon Glass dev->parent_platdata = NULL; 178cdc133bdSSimon Glass } 1795a87c417SSimon Glass } 1805eaed880SPrzemyslaw Marczak fail_alloc3: 1815eaed880SPrzemyslaw Marczak if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) { 1825eaed880SPrzemyslaw Marczak free(dev->uclass_platdata); 1835eaed880SPrzemyslaw Marczak dev->uclass_platdata = NULL; 1845eaed880SPrzemyslaw Marczak } 185cdc133bdSSimon Glass fail_alloc2: 186f8a85449SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 187f8a85449SSimon Glass free(dev->platdata); 188f8a85449SSimon Glass dev->platdata = NULL; 189f8a85449SSimon Glass } 190f8a85449SSimon Glass fail_alloc1: 191608f26c5SMasahiro Yamada devres_release_all(dev); 192608f26c5SMasahiro Yamada 1936494d708SSimon Glass free(dev); 19472ebfe86SSimon Glass 1956494d708SSimon Glass return ret; 1966494d708SSimon Glass } 1976494d708SSimon Glass 198*daac3bfeSStephen Warren int device_bind_with_driver_data(struct udevice *parent, 199*daac3bfeSStephen Warren const struct driver *drv, const char *name, 200*daac3bfeSStephen Warren ulong driver_data, int of_offset, 201*daac3bfeSStephen Warren struct udevice **devp) 202*daac3bfeSStephen Warren { 203*daac3bfeSStephen Warren return device_bind_common(parent, drv, name, NULL, driver_data, 204*daac3bfeSStephen Warren of_offset, devp); 205*daac3bfeSStephen Warren } 206*daac3bfeSStephen Warren 207*daac3bfeSStephen Warren int device_bind(struct udevice *parent, const struct driver *drv, 208*daac3bfeSStephen Warren const char *name, void *platdata, int of_offset, 209*daac3bfeSStephen Warren struct udevice **devp) 210*daac3bfeSStephen Warren { 211*daac3bfeSStephen Warren return device_bind_common(parent, drv, name, platdata, 0, of_offset, 212*daac3bfeSStephen Warren devp); 213*daac3bfeSStephen Warren } 214*daac3bfeSStephen Warren 21500606d7eSSimon Glass int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, 21600606d7eSSimon Glass const struct driver_info *info, struct udevice **devp) 2176494d708SSimon Glass { 2186494d708SSimon Glass struct driver *drv; 2196494d708SSimon Glass 2206494d708SSimon Glass drv = lists_driver_lookup_name(info->name); 2216494d708SSimon Glass if (!drv) 2226494d708SSimon Glass return -ENOENT; 22300606d7eSSimon Glass if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) 22400606d7eSSimon Glass return -EPERM; 2256494d708SSimon Glass 2266494d708SSimon Glass return device_bind(parent, drv, info->name, (void *)info->platdata, 2276494d708SSimon Glass -1, devp); 2286494d708SSimon Glass } 2296494d708SSimon Glass 2302c03c463SSimon Glass static void *alloc_priv(int size, uint flags) 2312c03c463SSimon Glass { 2322c03c463SSimon Glass void *priv; 2332c03c463SSimon Glass 2342c03c463SSimon Glass if (flags & DM_FLAG_ALLOC_PRIV_DMA) { 2352c03c463SSimon Glass priv = memalign(ARCH_DMA_MINALIGN, size); 2362c03c463SSimon Glass if (priv) 2372c03c463SSimon Glass memset(priv, '\0', size); 2382c03c463SSimon Glass } else { 2392c03c463SSimon Glass priv = calloc(1, size); 2402c03c463SSimon Glass } 2412c03c463SSimon Glass 2422c03c463SSimon Glass return priv; 2432c03c463SSimon Glass } 2442c03c463SSimon Glass 245c6db965fSSimon Glass int device_probe(struct udevice *dev) 2466494d708SSimon Glass { 2473479253dSSimon Glass const struct driver *drv; 2486494d708SSimon Glass int size = 0; 2496494d708SSimon Glass int ret; 2505a66a8ffSSimon Glass int seq; 2516494d708SSimon Glass 2526494d708SSimon Glass if (!dev) 2536494d708SSimon Glass return -EINVAL; 2546494d708SSimon Glass 2556494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 2566494d708SSimon Glass return 0; 2576494d708SSimon Glass 2586494d708SSimon Glass drv = dev->driver; 2596494d708SSimon Glass assert(drv); 2606494d708SSimon Glass 261cdeb2ba9SBin Meng /* Allocate private data if requested and not reentered */ 262cdeb2ba9SBin Meng if (drv->priv_auto_alloc_size && !dev->priv) { 2632c03c463SSimon Glass dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags); 2646494d708SSimon Glass if (!dev->priv) { 2656494d708SSimon Glass ret = -ENOMEM; 2666494d708SSimon Glass goto fail; 2676494d708SSimon Glass } 2686494d708SSimon Glass } 269cdeb2ba9SBin Meng /* Allocate private data if requested and not reentered */ 2706494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 271cdeb2ba9SBin Meng if (size && !dev->uclass_priv) { 2726494d708SSimon Glass dev->uclass_priv = calloc(1, size); 2736494d708SSimon Glass if (!dev->uclass_priv) { 2746494d708SSimon Glass ret = -ENOMEM; 2756494d708SSimon Glass goto fail; 2766494d708SSimon Glass } 2776494d708SSimon Glass } 2786494d708SSimon Glass 2796494d708SSimon Glass /* Ensure all parents are probed */ 2806494d708SSimon Glass if (dev->parent) { 281e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 282dac8db2cSSimon Glass if (!size) { 283dac8db2cSSimon Glass size = dev->parent->uclass->uc_drv-> 284dac8db2cSSimon Glass per_child_auto_alloc_size; 285dac8db2cSSimon Glass } 286cdeb2ba9SBin Meng if (size && !dev->parent_priv) { 2872c03c463SSimon Glass dev->parent_priv = alloc_priv(size, drv->flags); 288e59f458dSSimon Glass if (!dev->parent_priv) { 289e59f458dSSimon Glass ret = -ENOMEM; 290e59f458dSSimon Glass goto fail; 291e59f458dSSimon Glass } 292e59f458dSSimon Glass } 293e59f458dSSimon Glass 2946494d708SSimon Glass ret = device_probe(dev->parent); 2956494d708SSimon Glass if (ret) 2966494d708SSimon Glass goto fail; 297cdeb2ba9SBin Meng 298cdeb2ba9SBin Meng /* 299cdeb2ba9SBin Meng * The device might have already been probed during 300cdeb2ba9SBin Meng * the call to device_probe() on its parent device 301cdeb2ba9SBin Meng * (e.g. PCI bridge devices). Test the flags again 302cdeb2ba9SBin Meng * so that we don't mess up the device. 303cdeb2ba9SBin Meng */ 304cdeb2ba9SBin Meng if (dev->flags & DM_FLAG_ACTIVATED) 305cdeb2ba9SBin Meng return 0; 3066494d708SSimon Glass } 3076494d708SSimon Glass 3085a66a8ffSSimon Glass seq = uclass_resolve_seq(dev); 3095a66a8ffSSimon Glass if (seq < 0) { 3105a66a8ffSSimon Glass ret = seq; 3115a66a8ffSSimon Glass goto fail; 3125a66a8ffSSimon Glass } 3135a66a8ffSSimon Glass dev->seq = seq; 3145a66a8ffSSimon Glass 315206d4d2bSSimon Glass dev->flags |= DM_FLAG_ACTIVATED; 316206d4d2bSSimon Glass 31784d26e29SSimon Glass /* 31884d26e29SSimon Glass * Process pinctrl for everything except the root device, and 3190379597eSSimon Glass * continue regardless of the result of pinctrl. Don't process pinctrl 3200379597eSSimon Glass * settings for pinctrl devices since the device may not yet be 3210379597eSSimon Glass * probed. 32284d26e29SSimon Glass */ 3230379597eSSimon Glass if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) 324d90a5a30SMasahiro Yamada pinctrl_select_state(dev, "default"); 325d90a5a30SMasahiro Yamada 32602c07b37SSimon Glass ret = uclass_pre_probe_device(dev); 32783c7e434SSimon Glass if (ret) 32883c7e434SSimon Glass goto fail; 32983c7e434SSimon Glass 330a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_pre_probe) { 331a327dee0SSimon Glass ret = dev->parent->driver->child_pre_probe(dev); 332a327dee0SSimon Glass if (ret) 333a327dee0SSimon Glass goto fail; 334a327dee0SSimon Glass } 335a327dee0SSimon Glass 3366494d708SSimon Glass if (drv->ofdata_to_platdata && dev->of_offset >= 0) { 3376494d708SSimon Glass ret = drv->ofdata_to_platdata(dev); 3386494d708SSimon Glass if (ret) 3396494d708SSimon Glass goto fail; 3406494d708SSimon Glass } 3416494d708SSimon Glass 3426494d708SSimon Glass if (drv->probe) { 3436494d708SSimon Glass ret = drv->probe(dev); 34402eeb1bbSSimon Glass if (ret) { 34502eeb1bbSSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3466494d708SSimon Glass goto fail; 3476494d708SSimon Glass } 34802eeb1bbSSimon Glass } 3496494d708SSimon Glass 3506494d708SSimon Glass ret = uclass_post_probe_device(dev); 351206d4d2bSSimon Glass if (ret) 3526494d708SSimon Glass goto fail_uclass; 3536494d708SSimon Glass 354c3ab9853SPeng Fan if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) 355c3ab9853SPeng Fan pinctrl_select_state(dev, "default"); 356c3ab9853SPeng Fan 3576494d708SSimon Glass return 0; 3586494d708SSimon Glass fail_uclass: 3596494d708SSimon Glass if (device_remove(dev)) { 3606494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove on error path\n", 3616494d708SSimon Glass __func__, dev->name); 3626494d708SSimon Glass } 3636494d708SSimon Glass fail: 364206d4d2bSSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 365206d4d2bSSimon Glass 3665a66a8ffSSimon Glass dev->seq = -1; 3676494d708SSimon Glass device_free(dev); 3686494d708SSimon Glass 3696494d708SSimon Glass return ret; 3706494d708SSimon Glass } 3716494d708SSimon Glass 37254c5d08aSHeiko Schocher void *dev_get_platdata(struct udevice *dev) 3736494d708SSimon Glass { 3746494d708SSimon Glass if (!dev) { 375964d153cSSimon Glass dm_warn("%s: null device\n", __func__); 3766494d708SSimon Glass return NULL; 3776494d708SSimon Glass } 3786494d708SSimon Glass 3796494d708SSimon Glass return dev->platdata; 3806494d708SSimon Glass } 3816494d708SSimon Glass 382cdc133bdSSimon Glass void *dev_get_parent_platdata(struct udevice *dev) 383cdc133bdSSimon Glass { 384cdc133bdSSimon Glass if (!dev) { 38536d7cc17SSimon Glass dm_warn("%s: null device\n", __func__); 386cdc133bdSSimon Glass return NULL; 387cdc133bdSSimon Glass } 388cdc133bdSSimon Glass 389cdc133bdSSimon Glass return dev->parent_platdata; 390cdc133bdSSimon Glass } 391cdc133bdSSimon Glass 3925eaed880SPrzemyslaw Marczak void *dev_get_uclass_platdata(struct udevice *dev) 3935eaed880SPrzemyslaw Marczak { 3945eaed880SPrzemyslaw Marczak if (!dev) { 39536d7cc17SSimon Glass dm_warn("%s: null device\n", __func__); 3965eaed880SPrzemyslaw Marczak return NULL; 3975eaed880SPrzemyslaw Marczak } 3985eaed880SPrzemyslaw Marczak 3995eaed880SPrzemyslaw Marczak return dev->uclass_platdata; 4005eaed880SPrzemyslaw Marczak } 4015eaed880SPrzemyslaw Marczak 40254c5d08aSHeiko Schocher void *dev_get_priv(struct udevice *dev) 4036494d708SSimon Glass { 4046494d708SSimon Glass if (!dev) { 405964d153cSSimon Glass dm_warn("%s: null device\n", __func__); 4066494d708SSimon Glass return NULL; 4076494d708SSimon Glass } 4086494d708SSimon Glass 4096494d708SSimon Glass return dev->priv; 4106494d708SSimon Glass } 411997c87bbSSimon Glass 412e564f054SSimon Glass void *dev_get_uclass_priv(struct udevice *dev) 413e564f054SSimon Glass { 414e564f054SSimon Glass if (!dev) { 415e564f054SSimon Glass dm_warn("%s: null device\n", __func__); 416e564f054SSimon Glass return NULL; 417e564f054SSimon Glass } 418e564f054SSimon Glass 419e564f054SSimon Glass return dev->uclass_priv; 420e564f054SSimon Glass } 421e564f054SSimon Glass 422bcbe3d15SSimon Glass void *dev_get_parent_priv(struct udevice *dev) 423e59f458dSSimon Glass { 424e59f458dSSimon Glass if (!dev) { 425964d153cSSimon Glass dm_warn("%s: null device\n", __func__); 426e59f458dSSimon Glass return NULL; 427e59f458dSSimon Glass } 428e59f458dSSimon Glass 429e59f458dSSimon Glass return dev->parent_priv; 430e59f458dSSimon Glass } 431e59f458dSSimon Glass 432997c87bbSSimon Glass static int device_get_device_tail(struct udevice *dev, int ret, 433997c87bbSSimon Glass struct udevice **devp) 434997c87bbSSimon Glass { 435997c87bbSSimon Glass if (ret) 436997c87bbSSimon Glass return ret; 437997c87bbSSimon Glass 438997c87bbSSimon Glass ret = device_probe(dev); 439997c87bbSSimon Glass if (ret) 440997c87bbSSimon Glass return ret; 441997c87bbSSimon Glass 442997c87bbSSimon Glass *devp = dev; 443997c87bbSSimon Glass 444997c87bbSSimon Glass return 0; 445997c87bbSSimon Glass } 446997c87bbSSimon Glass 447997c87bbSSimon Glass int device_get_child(struct udevice *parent, int index, struct udevice **devp) 448997c87bbSSimon Glass { 449997c87bbSSimon Glass struct udevice *dev; 450997c87bbSSimon Glass 451997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 452997c87bbSSimon Glass if (!index--) 453997c87bbSSimon Glass return device_get_device_tail(dev, 0, devp); 454997c87bbSSimon Glass } 455997c87bbSSimon Glass 456997c87bbSSimon Glass return -ENODEV; 457997c87bbSSimon Glass } 458997c87bbSSimon Glass 459997c87bbSSimon Glass int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, 460997c87bbSSimon Glass bool find_req_seq, struct udevice **devp) 461997c87bbSSimon Glass { 462997c87bbSSimon Glass struct udevice *dev; 463997c87bbSSimon Glass 464997c87bbSSimon Glass *devp = NULL; 465997c87bbSSimon Glass if (seq_or_req_seq == -1) 466997c87bbSSimon Glass return -ENODEV; 467997c87bbSSimon Glass 468997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 469997c87bbSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) == 470997c87bbSSimon Glass seq_or_req_seq) { 471997c87bbSSimon Glass *devp = dev; 472997c87bbSSimon Glass return 0; 473997c87bbSSimon Glass } 474997c87bbSSimon Glass } 475997c87bbSSimon Glass 476997c87bbSSimon Glass return -ENODEV; 477997c87bbSSimon Glass } 478997c87bbSSimon Glass 479997c87bbSSimon Glass int device_get_child_by_seq(struct udevice *parent, int seq, 480997c87bbSSimon Glass struct udevice **devp) 481997c87bbSSimon Glass { 482997c87bbSSimon Glass struct udevice *dev; 483997c87bbSSimon Glass int ret; 484997c87bbSSimon Glass 485997c87bbSSimon Glass *devp = NULL; 486997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, false, &dev); 487997c87bbSSimon Glass if (ret == -ENODEV) { 488997c87bbSSimon Glass /* 489997c87bbSSimon Glass * We didn't find it in probed devices. See if there is one 490997c87bbSSimon Glass * that will request this seq if probed. 491997c87bbSSimon Glass */ 492997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, true, &dev); 493997c87bbSSimon Glass } 494997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 495997c87bbSSimon Glass } 496997c87bbSSimon Glass 497997c87bbSSimon Glass int device_find_child_by_of_offset(struct udevice *parent, int of_offset, 498997c87bbSSimon Glass struct udevice **devp) 499997c87bbSSimon Glass { 500997c87bbSSimon Glass struct udevice *dev; 501997c87bbSSimon Glass 502997c87bbSSimon Glass *devp = NULL; 503997c87bbSSimon Glass 504997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 505997c87bbSSimon Glass if (dev->of_offset == of_offset) { 506997c87bbSSimon Glass *devp = dev; 507997c87bbSSimon Glass return 0; 508997c87bbSSimon Glass } 509997c87bbSSimon Glass } 510997c87bbSSimon Glass 511997c87bbSSimon Glass return -ENODEV; 512997c87bbSSimon Glass } 513997c87bbSSimon Glass 514132f9bfcSSimon Glass int device_get_child_by_of_offset(struct udevice *parent, int node, 515997c87bbSSimon Glass struct udevice **devp) 516997c87bbSSimon Glass { 517997c87bbSSimon Glass struct udevice *dev; 518997c87bbSSimon Glass int ret; 519997c87bbSSimon Glass 520997c87bbSSimon Glass *devp = NULL; 521132f9bfcSSimon Glass ret = device_find_child_by_of_offset(parent, node, &dev); 522997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 523997c87bbSSimon Glass } 524a8981d4fSSimon Glass 5252693047aSSimon Glass static struct udevice *_device_find_global_by_of_offset(struct udevice *parent, 5262693047aSSimon Glass int of_offset) 5272693047aSSimon Glass { 5282693047aSSimon Glass struct udevice *dev, *found; 5292693047aSSimon Glass 5302693047aSSimon Glass if (parent->of_offset == of_offset) 5312693047aSSimon Glass return parent; 5322693047aSSimon Glass 5332693047aSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 5342693047aSSimon Glass found = _device_find_global_by_of_offset(dev, of_offset); 5352693047aSSimon Glass if (found) 5362693047aSSimon Glass return found; 5372693047aSSimon Glass } 5382693047aSSimon Glass 5392693047aSSimon Glass return NULL; 5402693047aSSimon Glass } 5412693047aSSimon Glass 5422693047aSSimon Glass int device_get_global_by_of_offset(int of_offset, struct udevice **devp) 5432693047aSSimon Glass { 5442693047aSSimon Glass struct udevice *dev; 5452693047aSSimon Glass 5462693047aSSimon Glass dev = _device_find_global_by_of_offset(gd->dm_root, of_offset); 5472693047aSSimon Glass return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); 5482693047aSSimon Glass } 5492693047aSSimon Glass 550a8981d4fSSimon Glass int device_find_first_child(struct udevice *parent, struct udevice **devp) 551a8981d4fSSimon Glass { 552a8981d4fSSimon Glass if (list_empty(&parent->child_head)) { 553a8981d4fSSimon Glass *devp = NULL; 554a8981d4fSSimon Glass } else { 555a8981d4fSSimon Glass *devp = list_first_entry(&parent->child_head, struct udevice, 556a8981d4fSSimon Glass sibling_node); 557a8981d4fSSimon Glass } 558a8981d4fSSimon Glass 559a8981d4fSSimon Glass return 0; 560a8981d4fSSimon Glass } 561a8981d4fSSimon Glass 562a8981d4fSSimon Glass int device_find_next_child(struct udevice **devp) 563a8981d4fSSimon Glass { 564a8981d4fSSimon Glass struct udevice *dev = *devp; 565a8981d4fSSimon Glass struct udevice *parent = dev->parent; 566a8981d4fSSimon Glass 567a8981d4fSSimon Glass if (list_is_last(&dev->sibling_node, &parent->child_head)) { 568a8981d4fSSimon Glass *devp = NULL; 569a8981d4fSSimon Glass } else { 570a8981d4fSSimon Glass *devp = list_entry(dev->sibling_node.next, struct udevice, 571a8981d4fSSimon Glass sibling_node); 572a8981d4fSSimon Glass } 573a8981d4fSSimon Glass 574a8981d4fSSimon Glass return 0; 575a8981d4fSSimon Glass } 5762ef249b4SSimon Glass 577479728cbSSimon Glass struct udevice *dev_get_parent(struct udevice *child) 578479728cbSSimon Glass { 579479728cbSSimon Glass return child->parent; 580479728cbSSimon Glass } 581479728cbSSimon Glass 58239de8433SSimon Glass ulong dev_get_driver_data(struct udevice *dev) 5832ef249b4SSimon Glass { 58439de8433SSimon Glass return dev->driver_data; 5852ef249b4SSimon Glass } 586b3670531SSimon Glass 587cc73d37bSPrzemyslaw Marczak const void *dev_get_driver_ops(struct udevice *dev) 588cc73d37bSPrzemyslaw Marczak { 589cc73d37bSPrzemyslaw Marczak if (!dev || !dev->driver->ops) 590cc73d37bSPrzemyslaw Marczak return NULL; 591cc73d37bSPrzemyslaw Marczak 592cc73d37bSPrzemyslaw Marczak return dev->driver->ops; 593cc73d37bSPrzemyslaw Marczak } 594cc73d37bSPrzemyslaw Marczak 595b3670531SSimon Glass enum uclass_id device_get_uclass_id(struct udevice *dev) 596b3670531SSimon Glass { 597b3670531SSimon Glass return dev->uclass->uc_drv->id; 598b3670531SSimon Glass } 599c9cac3f8SPeng Fan 600f9c370dcSPrzemyslaw Marczak const char *dev_get_uclass_name(struct udevice *dev) 601f9c370dcSPrzemyslaw Marczak { 602f9c370dcSPrzemyslaw Marczak if (!dev) 603f9c370dcSPrzemyslaw Marczak return NULL; 604f9c370dcSPrzemyslaw Marczak 605f9c370dcSPrzemyslaw Marczak return dev->uclass->uc_drv->name; 606f9c370dcSPrzemyslaw Marczak } 607f9c370dcSPrzemyslaw Marczak 60869b41388SMugunthan V N fdt_addr_t dev_get_addr_index(struct udevice *dev, int index) 609f3301771SSimon Glass { 6100f925822SMasahiro Yamada #if CONFIG_IS_ENABLED(OF_CONTROL) 611f3301771SSimon Glass fdt_addr_t addr; 612f3301771SSimon Glass 613ef5cd330SStefan Roese if (CONFIG_IS_ENABLED(OF_TRANSLATE)) { 614ef5cd330SStefan Roese const fdt32_t *reg; 61569b41388SMugunthan V N int len = 0; 61669b41388SMugunthan V N int na, ns; 617ef5cd330SStefan Roese 61869b41388SMugunthan V N na = fdt_address_cells(gd->fdt_blob, dev->parent->of_offset); 61969b41388SMugunthan V N if (na < 1) { 62069b41388SMugunthan V N debug("bad #address-cells\n"); 621ef5cd330SStefan Roese return FDT_ADDR_T_NONE; 62269b41388SMugunthan V N } 62369b41388SMugunthan V N 62469b41388SMugunthan V N ns = fdt_size_cells(gd->fdt_blob, dev->parent->of_offset); 62569b41388SMugunthan V N if (ns < 0) { 62669b41388SMugunthan V N debug("bad #size-cells\n"); 62769b41388SMugunthan V N return FDT_ADDR_T_NONE; 62869b41388SMugunthan V N } 62969b41388SMugunthan V N 63069b41388SMugunthan V N reg = fdt_getprop(gd->fdt_blob, dev->of_offset, "reg", &len); 63169b41388SMugunthan V N if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) { 63269b41388SMugunthan V N debug("Req index out of range\n"); 63369b41388SMugunthan V N return FDT_ADDR_T_NONE; 63469b41388SMugunthan V N } 63569b41388SMugunthan V N 63669b41388SMugunthan V N reg += index * (na + ns); 637ef5cd330SStefan Roese 638ef5cd330SStefan Roese /* 639ef5cd330SStefan Roese * Use the full-fledged translate function for complex 640ef5cd330SStefan Roese * bus setups. 641ef5cd330SStefan Roese */ 64266eaea6cSStefan Roese addr = fdt_translate_address((void *)gd->fdt_blob, 643ef5cd330SStefan Roese dev->of_offset, reg); 64466eaea6cSStefan Roese } else { 645ef5cd330SStefan Roese /* 646ef5cd330SStefan Roese * Use the "simple" translate function for less complex 647ef5cd330SStefan Roese * bus setups. 648ef5cd330SStefan Roese */ 64902464e38SStephen Warren addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, 65002464e38SStephen Warren dev->parent->of_offset, 65102464e38SStephen Warren dev->of_offset, "reg", 65269b41388SMugunthan V N index, NULL); 653628d792cSMarek Vasut if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) { 65466eaea6cSStefan Roese if (device_get_uclass_id(dev->parent) == 65566eaea6cSStefan Roese UCLASS_SIMPLE_BUS) 656f3301771SSimon Glass addr = simple_bus_translate(dev->parent, addr); 657c9cac3f8SPeng Fan } 65866eaea6cSStefan Roese } 65966eaea6cSStefan Roese 66066eaea6cSStefan Roese /* 66166eaea6cSStefan Roese * Some platforms need a special address translation. Those 66266eaea6cSStefan Roese * platforms (e.g. mvebu in SPL) can configure a translation 66366eaea6cSStefan Roese * offset in the DM by calling dm_set_translation_offset() that 66466eaea6cSStefan Roese * will get added to all addresses returned by dev_get_addr(). 66566eaea6cSStefan Roese */ 66666eaea6cSStefan Roese addr += dm_get_translation_offset(); 667f3301771SSimon Glass 668f3301771SSimon Glass return addr; 669c9cac3f8SPeng Fan #else 670c9cac3f8SPeng Fan return FDT_ADDR_T_NONE; 671c9cac3f8SPeng Fan #endif 672f3301771SSimon Glass } 673c5785673SSimon Glass 67443c4d44eSStephen Warren fdt_addr_t dev_get_addr_name(struct udevice *dev, const char *name) 67543c4d44eSStephen Warren { 67643c4d44eSStephen Warren #if CONFIG_IS_ENABLED(OF_CONTROL) 67743c4d44eSStephen Warren int index; 67843c4d44eSStephen Warren 67935732098SStephen Warren index = fdt_find_string(gd->fdt_blob, dev->of_offset, "reg-names", 68035732098SStephen Warren name); 68143c4d44eSStephen Warren if (index < 0) 68243c4d44eSStephen Warren return index; 68343c4d44eSStephen Warren 68443c4d44eSStephen Warren return dev_get_addr_index(dev, index); 68543c4d44eSStephen Warren #else 68643c4d44eSStephen Warren return FDT_ADDR_T_NONE; 68743c4d44eSStephen Warren #endif 68843c4d44eSStephen Warren } 68943c4d44eSStephen Warren 69069b41388SMugunthan V N fdt_addr_t dev_get_addr(struct udevice *dev) 69169b41388SMugunthan V N { 69269b41388SMugunthan V N return dev_get_addr_index(dev, 0); 69369b41388SMugunthan V N } 69469b41388SMugunthan V N 69528027521SStefan Roese void *dev_get_addr_ptr(struct udevice *dev) 69628027521SStefan Roese { 69728027521SStefan Roese return (void *)(uintptr_t)dev_get_addr_index(dev, 0); 69828027521SStefan Roese } 69928027521SStefan Roese 700c5785673SSimon Glass bool device_has_children(struct udevice *dev) 701c5785673SSimon Glass { 702c5785673SSimon Glass return !list_empty(&dev->child_head); 703c5785673SSimon Glass } 704c5785673SSimon Glass 705c5785673SSimon Glass bool device_has_active_children(struct udevice *dev) 706c5785673SSimon Glass { 707c5785673SSimon Glass struct udevice *child; 708c5785673SSimon Glass 709c5785673SSimon Glass for (device_find_first_child(dev, &child); 710c5785673SSimon Glass child; 711c5785673SSimon Glass device_find_next_child(&child)) { 712c5785673SSimon Glass if (device_active(child)) 713c5785673SSimon Glass return true; 714c5785673SSimon Glass } 715c5785673SSimon Glass 716c5785673SSimon Glass return false; 717c5785673SSimon Glass } 718c5785673SSimon Glass 719c5785673SSimon Glass bool device_is_last_sibling(struct udevice *dev) 720c5785673SSimon Glass { 721c5785673SSimon Glass struct udevice *parent = dev->parent; 722c5785673SSimon Glass 723c5785673SSimon Glass if (!parent) 724c5785673SSimon Glass return false; 725c5785673SSimon Glass return list_is_last(&dev->sibling_node, &parent->child_head); 726c5785673SSimon Glass } 727f5c67ea0SSimon Glass 728a2040facSSimon Glass void device_set_name_alloced(struct udevice *dev) 729a2040facSSimon Glass { 730a2040facSSimon Glass dev->flags |= DM_NAME_ALLOCED; 731a2040facSSimon Glass } 732a2040facSSimon Glass 733f5c67ea0SSimon Glass int device_set_name(struct udevice *dev, const char *name) 734f5c67ea0SSimon Glass { 735f5c67ea0SSimon Glass name = strdup(name); 736f5c67ea0SSimon Glass if (!name) 737f5c67ea0SSimon Glass return -ENOMEM; 738f5c67ea0SSimon Glass dev->name = name; 739a2040facSSimon Glass device_set_name_alloced(dev); 740f5c67ea0SSimon Glass 741f5c67ea0SSimon Glass return 0; 742f5c67ea0SSimon Glass } 74373443b9eSMugunthan V N 74473443b9eSMugunthan V N bool of_device_is_compatible(struct udevice *dev, const char *compat) 74573443b9eSMugunthan V N { 74673443b9eSMugunthan V N const void *fdt = gd->fdt_blob; 74773443b9eSMugunthan V N 74873443b9eSMugunthan V N return !fdt_node_check_compatible(fdt, dev->of_offset, compat); 74973443b9eSMugunthan V N } 75073443b9eSMugunthan V N 75173443b9eSMugunthan V N bool of_machine_is_compatible(const char *compat) 75273443b9eSMugunthan V N { 75373443b9eSMugunthan V N const void *fdt = gd->fdt_blob; 75473443b9eSMugunthan V N 75573443b9eSMugunthan V N return !fdt_node_check_compatible(fdt, 0, compat); 75673443b9eSMugunthan V N } 757