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