uboot/drivers/core/uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2013 Google, Inc
   4 *
   5 * (C) Copyright 2012
   6 * Pavel Herrmann <morpheus.ibis@gmail.com>
   7 */
   8
   9#define LOG_CATEGORY LOGC_DM
  10
  11#include <common.h>
  12#include <dm.h>
  13#include <errno.h>
  14#include <log.h>
  15#include <malloc.h>
  16#include <asm/global_data.h>
  17#include <dm/device.h>
  18#include <dm/device-internal.h>
  19#include <dm/lists.h>
  20#include <dm/uclass.h>
  21#include <dm/uclass-internal.h>
  22#include <dm/util.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26struct uclass *uclass_find(enum uclass_id key)
  27{
  28        struct uclass *uc;
  29
  30        if (!gd->dm_root)
  31                return NULL;
  32        /*
  33         * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
  34         * node to the start of the list, or creating a linear array mapping
  35         * id to node.
  36         */
  37        list_for_each_entry(uc, gd->uclass_root, sibling_node) {
  38                if (uc->uc_drv->id == key)
  39                        return uc;
  40        }
  41
  42        return NULL;
  43}
  44
  45/**
  46 * uclass_add() - Create new uclass in list
  47 * @id: Id number to create
  48 * @ucp: Returns pointer to uclass, or NULL on error
  49 * Return: 0 on success, -ve on error
  50 *
  51 * The new uclass is added to the list. There must be only one uclass for
  52 * each id.
  53 */
  54static int uclass_add(enum uclass_id id, struct uclass **ucp)
  55{
  56        struct uclass_driver *uc_drv;
  57        struct uclass *uc;
  58        int ret;
  59
  60        *ucp = NULL;
  61        uc_drv = lists_uclass_lookup(id);
  62        if (!uc_drv) {
  63                debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
  64                      id);
  65                /*
  66                 * Use a strange error to make this case easier to find. When
  67                 * a uclass is not available it can prevent driver model from
  68                 * starting up and this failure is otherwise hard to debug.
  69                 */
  70                return -EPFNOSUPPORT;
  71        }
  72        uc = calloc(1, sizeof(*uc));
  73        if (!uc)
  74                return -ENOMEM;
  75        if (uc_drv->priv_auto) {
  76                void *ptr;
  77
  78                ptr = calloc(1, uc_drv->priv_auto);
  79                if (!ptr) {
  80                        ret = -ENOMEM;
  81                        goto fail_mem;
  82                }
  83                uclass_set_priv(uc, ptr);
  84        }
  85        uc->uc_drv = uc_drv;
  86        INIT_LIST_HEAD(&uc->sibling_node);
  87        INIT_LIST_HEAD(&uc->dev_head);
  88        list_add(&uc->sibling_node, DM_UCLASS_ROOT_NON_CONST);
  89
  90        if (uc_drv->init) {
  91                ret = uc_drv->init(uc);
  92                if (ret)
  93                        goto fail;
  94        }
  95
  96        *ucp = uc;
  97
  98        return 0;
  99fail:
 100        if (uc_drv->priv_auto) {
 101                free(uclass_get_priv(uc));
 102                uclass_set_priv(uc, NULL);
 103        }
 104        list_del(&uc->sibling_node);
 105fail_mem:
 106        free(uc);
 107
 108        return ret;
 109}
 110
 111int uclass_destroy(struct uclass *uc)
 112{
 113        struct uclass_driver *uc_drv;
 114        struct udevice *dev;
 115        int ret;
 116
 117        /*
 118         * We cannot use list_for_each_entry_safe() here. If a device in this
 119         * uclass has a child device also in this uclass, it will be also be
 120         * unbound (by the recursion in the call to device_unbind() below).
 121         * We can loop until the list is empty.
 122         */
 123        while (!list_empty(&uc->dev_head)) {
 124                dev = list_first_entry(&uc->dev_head, struct udevice,
 125                                       uclass_node);
 126                ret = device_remove(dev, DM_REMOVE_NORMAL | DM_REMOVE_NO_PD);
 127                if (ret)
 128                        return log_msg_ret("remove", ret);
 129                ret = device_unbind(dev);
 130                if (ret)
 131                        return log_msg_ret("unbind", ret);
 132        }
 133
 134        uc_drv = uc->uc_drv;
 135        if (uc_drv->destroy)
 136                uc_drv->destroy(uc);
 137        list_del(&uc->sibling_node);
 138        if (uc_drv->priv_auto)
 139                free(uclass_get_priv(uc));
 140        free(uc);
 141
 142        return 0;
 143}
 144
 145int uclass_get(enum uclass_id id, struct uclass **ucp)
 146{
 147        struct uclass *uc;
 148
 149        /* Immediately fail if driver model is not set up */
 150        if (!gd->uclass_root)
 151                return -EDEADLK;
 152        *ucp = NULL;
 153        uc = uclass_find(id);
 154        if (!uc) {
 155                if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
 156                        return -ENOENT;
 157                return uclass_add(id, ucp);
 158        }
 159        *ucp = uc;
 160
 161        return 0;
 162}
 163
 164const char *uclass_get_name(enum uclass_id id)
 165{
 166        struct uclass *uc;
 167
 168        if (uclass_get(id, &uc))
 169                return NULL;
 170        return uc->uc_drv->name;
 171}
 172
 173void *uclass_get_priv(const struct uclass *uc)
 174{
 175        return uc->priv_;
 176}
 177
 178void uclass_set_priv(struct uclass *uc, void *priv)
 179{
 180        uc->priv_ = priv;
 181}
 182
 183enum uclass_id uclass_get_by_namelen(const char *name, int len)
 184{
 185        int i;
 186
 187        for (i = 0; i < UCLASS_COUNT; i++) {
 188                struct uclass_driver *uc_drv = lists_uclass_lookup(i);
 189
 190                if (uc_drv && !strncmp(uc_drv->name, name, len) &&
 191                    strlen(uc_drv->name) == len)
 192                        return i;
 193        }
 194
 195        return UCLASS_INVALID;
 196}
 197
 198enum uclass_id uclass_get_by_name(const char *name)
 199{
 200        return uclass_get_by_namelen(name, strlen(name));
 201}
 202
 203int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
 204{
 205        struct udevice *iter;
 206        struct uclass *uc = dev->uclass;
 207        int i = 0;
 208
 209        if (list_empty(&uc->dev_head))
 210                return -ENODEV;
 211
 212        uclass_foreach_dev(iter, uc) {
 213                if (iter == dev) {
 214                        if (ucp)
 215                                *ucp = uc;
 216                        return i;
 217                }
 218                i++;
 219        }
 220
 221        return -ENODEV;
 222}
 223
 224int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 225{
 226        struct uclass *uc;
 227        struct udevice *dev;
 228        int ret;
 229
 230        *devp = NULL;
 231        ret = uclass_get(id, &uc);
 232        if (ret)
 233                return ret;
 234        if (list_empty(&uc->dev_head))
 235                return -ENODEV;
 236
 237        uclass_foreach_dev(dev, uc) {
 238                if (!index--) {
 239                        *devp = dev;
 240                        return 0;
 241                }
 242        }
 243
 244        return -ENODEV;
 245}
 246
 247int uclass_find_first_device(enum uclass_id id, struct udevice **devp)
 248{
 249        struct uclass *uc;
 250        int ret;
 251
 252        *devp = NULL;
 253        ret = uclass_get(id, &uc);
 254        if (ret)
 255                return ret;
 256        if (list_empty(&uc->dev_head))
 257                return 0;
 258
 259        *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
 260
 261        return 0;
 262}
 263
 264int uclass_find_next_device(struct udevice **devp)
 265{
 266        struct udevice *dev = *devp;
 267
 268        *devp = NULL;
 269        if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
 270                return 0;
 271
 272        *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node);
 273
 274        return 0;
 275}
 276
 277int uclass_find_device_by_namelen(enum uclass_id id, const char *name, int len,
 278                                  struct udevice **devp)
 279{
 280        struct uclass *uc;
 281        struct udevice *dev;
 282        int ret;
 283
 284        *devp = NULL;
 285        if (!name)
 286                return -EINVAL;
 287        ret = uclass_get(id, &uc);
 288        if (ret)
 289                return ret;
 290
 291        uclass_foreach_dev(dev, uc) {
 292                if (!strncmp(dev->name, name, len) &&
 293                    strlen(dev->name) == len) {
 294                        *devp = dev;
 295                        return 0;
 296                }
 297        }
 298
 299        return -ENODEV;
 300}
 301
 302int uclass_find_device_by_name(enum uclass_id id, const char *name,
 303                               struct udevice **devp)
 304{
 305        return uclass_find_device_by_namelen(id, name, strlen(name), devp);
 306}
 307
 308int uclass_find_next_free_seq(struct uclass *uc)
 309{
 310        struct udevice *dev;
 311        int max = -1;
 312
 313        /* If using aliases, start with the highest alias value */
 314        if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
 315            (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS))
 316                max = dev_read_alias_highest_id(uc->uc_drv->name);
 317
 318        /* Avoid conflict with existing devices */
 319        list_for_each_entry(dev, &uc->dev_head, uclass_node) {
 320                if (dev->seq_ > max)
 321                        max = dev->seq_;
 322        }
 323        /*
 324         * At this point, max will be -1 if there are no existing aliases or
 325         * devices
 326         */
 327
 328        return max + 1;
 329}
 330
 331int uclass_find_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 332{
 333        struct uclass *uc;
 334        struct udevice *dev;
 335        int ret;
 336
 337        *devp = NULL;
 338        log_debug("%d\n", seq);
 339        if (seq == -1)
 340                return -ENODEV;
 341        ret = uclass_get(id, &uc);
 342        if (ret)
 343                return ret;
 344
 345        uclass_foreach_dev(dev, uc) {
 346                log_debug("   - %d '%s'\n", dev->seq_, dev->name);
 347                if (dev->seq_ == seq) {
 348                        *devp = dev;
 349                        log_debug("   - found\n");
 350                        return 0;
 351                }
 352        }
 353        log_debug("   - not found\n");
 354
 355        return -ENODEV;
 356}
 357
 358int uclass_find_device_by_of_offset(enum uclass_id id, int node,
 359                                    struct udevice **devp)
 360{
 361        struct uclass *uc;
 362        struct udevice *dev;
 363        int ret;
 364
 365        *devp = NULL;
 366        if (node < 0)
 367                return -ENODEV;
 368        ret = uclass_get(id, &uc);
 369        if (ret)
 370                return ret;
 371
 372        uclass_foreach_dev(dev, uc) {
 373                if (dev_of_offset(dev) == node) {
 374                        *devp = dev;
 375                        return 0;
 376                }
 377        }
 378
 379        return -ENODEV;
 380}
 381
 382int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
 383                                 struct udevice **devp)
 384{
 385        struct uclass *uc;
 386        struct udevice *dev;
 387        int ret;
 388
 389        log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
 390        *devp = NULL;
 391        if (!ofnode_valid(node))
 392                return -ENODEV;
 393        ret = uclass_get(id, &uc);
 394        if (ret)
 395                return ret;
 396
 397        uclass_foreach_dev(dev, uc) {
 398                log(LOGC_DM, LOGL_DEBUG_CONTENT, "      - checking %s\n",
 399                    dev->name);
 400                if (ofnode_equal(dev_ofnode(dev), node)) {
 401                        *devp = dev;
 402                        goto done;
 403                }
 404        }
 405        ret = -ENODEV;
 406
 407done:
 408        log(LOGC_DM, LOGL_DEBUG, "   - result for %s: %s (ret=%d)\n",
 409            ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret);
 410        return ret;
 411}
 412
 413#if CONFIG_IS_ENABLED(OF_REAL)
 414static int uclass_find_device_by_phandle_id(enum uclass_id id,
 415                                            uint find_phandle,
 416                                            struct udevice **devp)
 417{
 418        struct udevice *dev;
 419        struct uclass *uc;
 420        int ret;
 421
 422        ret = uclass_get(id, &uc);
 423        if (ret)
 424                return ret;
 425
 426        uclass_foreach_dev(dev, uc) {
 427                uint phandle;
 428
 429                phandle = dev_read_phandle(dev);
 430
 431                if (phandle == find_phandle) {
 432                        *devp = dev;
 433                        return 0;
 434                }
 435        }
 436
 437        return -ENODEV;
 438}
 439
 440int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
 441                                  const char *name, struct udevice **devp)
 442{
 443        int find_phandle;
 444
 445        *devp = NULL;
 446        find_phandle = dev_read_u32_default(parent, name, -1);
 447        if (find_phandle <= 0)
 448                return -ENOENT;
 449
 450        return uclass_find_device_by_phandle_id(id, find_phandle, devp);
 451}
 452#endif
 453
 454int uclass_get_device_by_driver(enum uclass_id id,
 455                                const struct driver *find_drv,
 456                                struct udevice **devp)
 457{
 458        struct udevice *dev;
 459        struct uclass *uc;
 460        int ret;
 461
 462        ret = uclass_get(id, &uc);
 463        if (ret)
 464                return ret;
 465
 466        uclass_foreach_dev(dev, uc) {
 467                if (dev->driver == find_drv)
 468                        return uclass_get_device_tail(dev, 0, devp);
 469        }
 470
 471        return -ENODEV;
 472}
 473
 474int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp)
 475{
 476        if (ret)
 477                return ret;
 478
 479        assert(dev);
 480        ret = device_probe(dev);
 481        if (ret)
 482                return ret;
 483
 484        *devp = dev;
 485
 486        return 0;
 487}
 488
 489int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
 490{
 491        struct udevice *dev;
 492        int ret;
 493
 494        *devp = NULL;
 495        ret = uclass_find_device(id, index, &dev);
 496        return uclass_get_device_tail(dev, ret, devp);
 497}
 498
 499int uclass_get_device_by_name(enum uclass_id id, const char *name,
 500                              struct udevice **devp)
 501{
 502        struct udevice *dev;
 503        int ret;
 504
 505        *devp = NULL;
 506        ret = uclass_find_device_by_name(id, name, &dev);
 507        return uclass_get_device_tail(dev, ret, devp);
 508}
 509
 510int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 511{
 512        struct udevice *dev;
 513        int ret;
 514
 515        *devp = NULL;
 516        ret = uclass_find_device_by_seq(id, seq, &dev);
 517
 518        return uclass_get_device_tail(dev, ret, devp);
 519}
 520
 521int uclass_get_device_by_of_offset(enum uclass_id id, int node,
 522                                   struct udevice **devp)
 523{
 524        struct udevice *dev;
 525        int ret;
 526
 527        *devp = NULL;
 528        ret = uclass_find_device_by_of_offset(id, node, &dev);
 529        return uclass_get_device_tail(dev, ret, devp);
 530}
 531
 532int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
 533                                struct udevice **devp)
 534{
 535        struct udevice *dev;
 536        int ret;
 537
 538        log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
 539        *devp = NULL;
 540        ret = uclass_find_device_by_ofnode(id, node, &dev);
 541        log(LOGC_DM, LOGL_DEBUG, "   - result for %s: %s (ret=%d)\n",
 542            ofnode_get_name(node), dev ? dev->name : "(none)", ret);
 543
 544        return uclass_get_device_tail(dev, ret, devp);
 545}
 546
 547#if CONFIG_IS_ENABLED(OF_REAL)
 548int uclass_get_device_by_of_path(enum uclass_id id, const char *path,
 549                                 struct udevice **devp)
 550{
 551        return uclass_get_device_by_ofnode(id, ofnode_path(path), devp);
 552}
 553
 554int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
 555                                    struct udevice **devp)
 556{
 557        struct udevice *dev;
 558        int ret;
 559
 560        *devp = NULL;
 561        ret = uclass_find_device_by_phandle_id(id, phandle_id, &dev);
 562        return uclass_get_device_tail(dev, ret, devp);
 563}
 564
 565int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
 566                                 const char *name, struct udevice **devp)
 567{
 568        struct udevice *dev;
 569        int ret;
 570
 571        *devp = NULL;
 572        ret = uclass_find_device_by_phandle(id, parent, name, &dev);
 573        return uclass_get_device_tail(dev, ret, devp);
 574}
 575#endif
 576
 577/*
 578 * Starting from the given device @dev, return pointer to the first device in
 579 * the uclass that probes successfully in @devp.
 580 */
 581static void _uclass_next_device(struct udevice *dev, struct udevice **devp)
 582{
 583        for (; dev; uclass_find_next_device(&dev)) {
 584                if (!device_probe(dev))
 585                        break;
 586        }
 587        *devp = dev;
 588}
 589
 590void uclass_first_device(enum uclass_id id, struct udevice **devp)
 591{
 592        struct udevice *dev;
 593        int ret;
 594
 595        ret = uclass_find_first_device(id, &dev);
 596        _uclass_next_device(dev, devp);
 597}
 598
 599void uclass_next_device(struct udevice **devp)
 600{
 601        struct udevice *dev = *devp;
 602
 603        uclass_find_next_device(&dev);
 604        _uclass_next_device(dev, devp);
 605}
 606
 607int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
 608{
 609        int ret;
 610
 611        ret = uclass_first_device_check(id, devp);
 612        if (ret)
 613                return ret;
 614        else if (!*devp)
 615                return -ENODEV;
 616
 617        return 0;
 618}
 619
 620int uclass_next_device_err(struct udevice **devp)
 621{
 622        int ret;
 623
 624        ret = uclass_next_device_check(devp);
 625        if (ret)
 626                return ret;
 627        else if (!*devp)
 628                return -ENODEV;
 629
 630        return 0;
 631}
 632
 633int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
 634{
 635        int ret;
 636
 637        *devp = NULL;
 638        ret = uclass_find_first_device(id, devp);
 639        if (ret)
 640                return ret;
 641        if (!*devp)
 642                return 0;
 643
 644        return device_probe(*devp);
 645}
 646
 647int uclass_next_device_check(struct udevice **devp)
 648{
 649        int ret;
 650
 651        ret = uclass_find_next_device(devp);
 652        if (ret)
 653                return ret;
 654        if (!*devp)
 655                return 0;
 656
 657        return device_probe(*devp);
 658}
 659
 660int uclass_get_count(void)
 661{
 662        const struct uclass *uc;
 663        int count = 0;
 664
 665        if (gd->dm_root) {
 666                list_for_each_entry(uc, gd->uclass_root, sibling_node)
 667                        count++;
 668        }
 669
 670        return count;
 671}
 672
 673int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
 674                                struct udevice **devp)
 675{
 676        struct udevice *dev;
 677        struct uclass *uc;
 678
 679        uclass_id_foreach_dev(id, dev, uc) {
 680                if (dev_get_driver_data(dev) == driver_data) {
 681                        *devp = dev;
 682
 683                        return device_probe(dev);
 684                }
 685        }
 686
 687        return -ENODEV;
 688}
 689
 690int uclass_bind_device(struct udevice *dev)
 691{
 692        struct uclass *uc;
 693        int ret;
 694
 695        uc = dev->uclass;
 696        list_add_tail(&dev->uclass_node, &uc->dev_head);
 697
 698        if (dev->parent) {
 699                struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
 700
 701                if (uc_drv->child_post_bind) {
 702                        ret = uc_drv->child_post_bind(dev);
 703                        if (ret)
 704                                goto err;
 705                }
 706        }
 707
 708        return 0;
 709err:
 710        /* There is no need to undo the parent's post_bind call */
 711        list_del(&dev->uclass_node);
 712
 713        return ret;
 714}
 715
 716#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 717int uclass_pre_unbind_device(struct udevice *dev)
 718{
 719        struct uclass *uc;
 720        int ret;
 721
 722        uc = dev->uclass;
 723        if (uc->uc_drv->pre_unbind) {
 724                ret = uc->uc_drv->pre_unbind(dev);
 725                if (ret)
 726                        return ret;
 727        }
 728
 729        return 0;
 730}
 731
 732int uclass_unbind_device(struct udevice *dev)
 733{
 734        list_del(&dev->uclass_node);
 735
 736        return 0;
 737}
 738#endif
 739
 740int uclass_pre_probe_device(struct udevice *dev)
 741{
 742        struct uclass_driver *uc_drv;
 743        int ret;
 744
 745        uc_drv = dev->uclass->uc_drv;
 746        if (uc_drv->pre_probe) {
 747                ret = uc_drv->pre_probe(dev);
 748                if (ret)
 749                        return ret;
 750        }
 751
 752        if (!dev->parent)
 753                return 0;
 754        uc_drv = dev->parent->uclass->uc_drv;
 755        if (uc_drv->child_pre_probe) {
 756                ret = uc_drv->child_pre_probe(dev);
 757                if (ret)
 758                        return ret;
 759        }
 760
 761        return 0;
 762}
 763
 764int uclass_post_probe_device(struct udevice *dev)
 765{
 766        struct uclass_driver *uc_drv;
 767        int ret;
 768
 769        if (dev->parent) {
 770                uc_drv = dev->parent->uclass->uc_drv;
 771                if (uc_drv->child_post_probe) {
 772                        ret = uc_drv->child_post_probe(dev);
 773                        if (ret)
 774                                return ret;
 775                }
 776        }
 777
 778        uc_drv = dev->uclass->uc_drv;
 779        if (uc_drv->post_probe) {
 780                ret = uc_drv->post_probe(dev);
 781                if (ret)
 782                        return ret;
 783        }
 784
 785        return 0;
 786}
 787
 788#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 789int uclass_pre_remove_device(struct udevice *dev)
 790{
 791        struct uclass *uc;
 792        int ret;
 793
 794        uc = dev->uclass;
 795        if (uc->uc_drv->pre_remove) {
 796                ret = uc->uc_drv->pre_remove(dev);
 797                if (ret)
 798                        return ret;
 799        }
 800
 801        return 0;
 802}
 803#endif
 804
 805int uclass_probe_all(enum uclass_id id)
 806{
 807        struct udevice *dev;
 808        int ret, err;
 809
 810        err = uclass_first_device_check(id, &dev);
 811
 812        /* Scanning uclass to probe all devices */
 813        while (dev) {
 814                ret = uclass_next_device_check(&dev);
 815                if (ret)
 816                        err = ret;
 817        }
 818
 819        return err;
 820}
 821
 822int uclass_id_count(enum uclass_id id)
 823{
 824        struct udevice *dev;
 825        struct uclass *uc;
 826        int count = 0;
 827
 828        uclass_id_foreach_dev(id, dev, uc)
 829                count++;
 830
 831        return count;
 832}
 833
 834UCLASS_DRIVER(nop) = {
 835        .id             = UCLASS_NOP,
 836        .name           = "nop",
 837};
 838