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_name(const char *name)
 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 && !strcmp(uc_drv->name, name))
 191                        return i;
 192        }
 193
 194        return UCLASS_INVALID;
 195}
 196
 197int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
 198{
 199        struct udevice *iter;
 200        struct uclass *uc = dev->uclass;
 201        int i = 0;
 202
 203        if (list_empty(&uc->dev_head))
 204                return -ENODEV;
 205
 206        uclass_foreach_dev(iter, uc) {
 207                if (iter == dev) {
 208                        if (ucp)
 209                                *ucp = uc;
 210                        return i;
 211                }
 212                i++;
 213        }
 214
 215        return -ENODEV;
 216}
 217
 218int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 219{
 220        struct uclass *uc;
 221        struct udevice *dev;
 222        int ret;
 223
 224        *devp = NULL;
 225        ret = uclass_get(id, &uc);
 226        if (ret)
 227                return ret;
 228        if (list_empty(&uc->dev_head))
 229                return -ENODEV;
 230
 231        uclass_foreach_dev(dev, uc) {
 232                if (!index--) {
 233                        *devp = dev;
 234                        return 0;
 235                }
 236        }
 237
 238        return -ENODEV;
 239}
 240
 241int uclass_find_first_device(enum uclass_id id, struct udevice **devp)
 242{
 243        struct uclass *uc;
 244        int ret;
 245
 246        *devp = NULL;
 247        ret = uclass_get(id, &uc);
 248        if (ret)
 249                return ret;
 250        if (list_empty(&uc->dev_head))
 251                return 0;
 252
 253        *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
 254
 255        return 0;
 256}
 257
 258int uclass_find_next_device(struct udevice **devp)
 259{
 260        struct udevice *dev = *devp;
 261
 262        *devp = NULL;
 263        if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
 264                return 0;
 265
 266        *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node);
 267
 268        return 0;
 269}
 270
 271int uclass_find_device_by_name(enum uclass_id id, const char *name,
 272                               struct udevice **devp)
 273{
 274        struct uclass *uc;
 275        struct udevice *dev;
 276        int ret;
 277
 278        *devp = NULL;
 279        if (!name)
 280                return -EINVAL;
 281        ret = uclass_get(id, &uc);
 282        if (ret)
 283                return ret;
 284
 285        uclass_foreach_dev(dev, uc) {
 286                if (!strcmp(dev->name, name)) {
 287                        *devp = dev;
 288                        return 0;
 289                }
 290        }
 291
 292        return -ENODEV;
 293}
 294
 295int uclass_find_next_free_seq(struct uclass *uc)
 296{
 297        struct udevice *dev;
 298        int max = -1;
 299
 300        /* If using aliases, start with the highest alias value */
 301        if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
 302            (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS))
 303                max = dev_read_alias_highest_id(uc->uc_drv->name);
 304
 305        /* Avoid conflict with existing devices */
 306        list_for_each_entry(dev, &uc->dev_head, uclass_node) {
 307                if (dev->seq_ > max)
 308                        max = dev->seq_;
 309        }
 310        /*
 311         * At this point, max will be -1 if there are no existing aliases or
 312         * devices
 313         */
 314
 315        return max + 1;
 316}
 317
 318int uclass_find_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 319{
 320        struct uclass *uc;
 321        struct udevice *dev;
 322        int ret;
 323
 324        *devp = NULL;
 325        log_debug("%d\n", seq);
 326        if (seq == -1)
 327                return -ENODEV;
 328        ret = uclass_get(id, &uc);
 329        if (ret)
 330                return ret;
 331
 332        uclass_foreach_dev(dev, uc) {
 333                log_debug("   - %d '%s'\n", dev->seq_, dev->name);
 334                if (dev->seq_ == seq) {
 335                        *devp = dev;
 336                        log_debug("   - found\n");
 337                        return 0;
 338                }
 339        }
 340        log_debug("   - not found\n");
 341
 342        return -ENODEV;
 343}
 344
 345int uclass_find_device_by_of_offset(enum uclass_id id, int node,
 346                                    struct udevice **devp)
 347{
 348        struct uclass *uc;
 349        struct udevice *dev;
 350        int ret;
 351
 352        *devp = NULL;
 353        if (node < 0)
 354                return -ENODEV;
 355        ret = uclass_get(id, &uc);
 356        if (ret)
 357                return ret;
 358
 359        uclass_foreach_dev(dev, uc) {
 360                if (dev_of_offset(dev) == node) {
 361                        *devp = dev;
 362                        return 0;
 363                }
 364        }
 365
 366        return -ENODEV;
 367}
 368
 369int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
 370                                 struct udevice **devp)
 371{
 372        struct uclass *uc;
 373        struct udevice *dev;
 374        int ret;
 375
 376        log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
 377        *devp = NULL;
 378        if (!ofnode_valid(node))
 379                return -ENODEV;
 380        ret = uclass_get(id, &uc);
 381        if (ret)
 382                return ret;
 383
 384        uclass_foreach_dev(dev, uc) {
 385                log(LOGC_DM, LOGL_DEBUG_CONTENT, "      - checking %s\n",
 386                    dev->name);
 387                if (ofnode_equal(dev_ofnode(dev), node)) {
 388                        *devp = dev;
 389                        goto done;
 390                }
 391        }
 392        ret = -ENODEV;
 393
 394done:
 395        log(LOGC_DM, LOGL_DEBUG, "   - result for %s: %s (ret=%d)\n",
 396            ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret);
 397        return ret;
 398}
 399
 400#if CONFIG_IS_ENABLED(OF_REAL)
 401int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
 402                                  const char *name, struct udevice **devp)
 403{
 404        struct udevice *dev;
 405        struct uclass *uc;
 406        int find_phandle;
 407        int ret;
 408
 409        *devp = NULL;
 410        find_phandle = dev_read_u32_default(parent, name, -1);
 411        if (find_phandle <= 0)
 412                return -ENOENT;
 413        ret = uclass_get(id, &uc);
 414        if (ret)
 415                return ret;
 416
 417        uclass_foreach_dev(dev, uc) {
 418                uint phandle;
 419
 420                phandle = dev_read_phandle(dev);
 421
 422                if (phandle == find_phandle) {
 423                        *devp = dev;
 424                        return 0;
 425                }
 426        }
 427
 428        return -ENODEV;
 429}
 430#endif
 431
 432int uclass_get_device_by_driver(enum uclass_id id,
 433                                const struct driver *find_drv,
 434                                struct udevice **devp)
 435{
 436        struct udevice *dev;
 437        struct uclass *uc;
 438        int ret;
 439
 440        ret = uclass_get(id, &uc);
 441        if (ret)
 442                return ret;
 443
 444        uclass_foreach_dev(dev, uc) {
 445                if (dev->driver == find_drv)
 446                        return uclass_get_device_tail(dev, 0, devp);
 447        }
 448
 449        return -ENODEV;
 450}
 451
 452int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp)
 453{
 454        if (ret)
 455                return ret;
 456
 457        assert(dev);
 458        ret = device_probe(dev);
 459        if (ret)
 460                return ret;
 461
 462        *devp = dev;
 463
 464        return 0;
 465}
 466
 467int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
 468{
 469        struct udevice *dev;
 470        int ret;
 471
 472        *devp = NULL;
 473        ret = uclass_find_device(id, index, &dev);
 474        return uclass_get_device_tail(dev, ret, devp);
 475}
 476
 477int uclass_get_device_by_name(enum uclass_id id, const char *name,
 478                              struct udevice **devp)
 479{
 480        struct udevice *dev;
 481        int ret;
 482
 483        *devp = NULL;
 484        ret = uclass_find_device_by_name(id, name, &dev);
 485        return uclass_get_device_tail(dev, ret, devp);
 486}
 487
 488int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 489{
 490        struct udevice *dev;
 491        int ret;
 492
 493        *devp = NULL;
 494        ret = uclass_find_device_by_seq(id, seq, &dev);
 495
 496        return uclass_get_device_tail(dev, ret, devp);
 497}
 498
 499int uclass_get_device_by_of_offset(enum uclass_id id, int node,
 500                                   struct udevice **devp)
 501{
 502        struct udevice *dev;
 503        int ret;
 504
 505        *devp = NULL;
 506        ret = uclass_find_device_by_of_offset(id, node, &dev);
 507        return uclass_get_device_tail(dev, ret, devp);
 508}
 509
 510int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
 511                                struct udevice **devp)
 512{
 513        struct udevice *dev;
 514        int ret;
 515
 516        log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
 517        *devp = NULL;
 518        ret = uclass_find_device_by_ofnode(id, node, &dev);
 519        log(LOGC_DM, LOGL_DEBUG, "   - result for %s: %s (ret=%d)\n",
 520            ofnode_get_name(node), dev ? dev->name : "(none)", ret);
 521
 522        return uclass_get_device_tail(dev, ret, devp);
 523}
 524
 525#if CONFIG_IS_ENABLED(OF_CONTROL)
 526int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
 527                                    struct udevice **devp)
 528{
 529        struct udevice *dev;
 530        struct uclass *uc;
 531        int ret;
 532
 533        *devp = NULL;
 534        ret = uclass_get(id, &uc);
 535        if (ret)
 536                return ret;
 537
 538        uclass_foreach_dev(dev, uc) {
 539                uint phandle;
 540
 541                phandle = dev_read_phandle(dev);
 542
 543                if (phandle == phandle_id) {
 544                        *devp = dev;
 545                        return uclass_get_device_tail(dev, ret, devp);
 546                }
 547        }
 548
 549        return -ENODEV;
 550}
 551
 552int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
 553                                 const char *name, struct udevice **devp)
 554{
 555        struct udevice *dev;
 556        int ret;
 557
 558        *devp = NULL;
 559        ret = uclass_find_device_by_phandle(id, parent, name, &dev);
 560        return uclass_get_device_tail(dev, ret, devp);
 561}
 562#endif
 563
 564int uclass_first_device(enum uclass_id id, struct udevice **devp)
 565{
 566        struct udevice *dev;
 567        int ret;
 568
 569        *devp = NULL;
 570        ret = uclass_find_first_device(id, &dev);
 571        if (!dev)
 572                return 0;
 573        return uclass_get_device_tail(dev, ret, devp);
 574}
 575
 576int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
 577{
 578        int ret;
 579
 580        ret = uclass_first_device(id, devp);
 581        if (ret)
 582                return ret;
 583        else if (!*devp)
 584                return -ENODEV;
 585
 586        return 0;
 587}
 588
 589int uclass_next_device(struct udevice **devp)
 590{
 591        struct udevice *dev = *devp;
 592        int ret;
 593
 594        *devp = NULL;
 595        ret = uclass_find_next_device(&dev);
 596        if (!dev)
 597                return 0;
 598        return uclass_get_device_tail(dev, ret, devp);
 599}
 600
 601int uclass_next_device_err(struct udevice **devp)
 602{
 603        int ret;
 604
 605        ret = uclass_next_device(devp);
 606        if (ret)
 607                return ret;
 608        else if (!*devp)
 609                return -ENODEV;
 610
 611        return 0;
 612}
 613
 614int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
 615{
 616        int ret;
 617
 618        *devp = NULL;
 619        ret = uclass_find_first_device(id, devp);
 620        if (ret)
 621                return ret;
 622        if (!*devp)
 623                return 0;
 624
 625        return device_probe(*devp);
 626}
 627
 628int uclass_next_device_check(struct udevice **devp)
 629{
 630        int ret;
 631
 632        ret = uclass_find_next_device(devp);
 633        if (ret)
 634                return ret;
 635        if (!*devp)
 636                return 0;
 637
 638        return device_probe(*devp);
 639}
 640
 641int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
 642                                struct udevice **devp)
 643{
 644        struct udevice *dev;
 645        struct uclass *uc;
 646
 647        uclass_id_foreach_dev(id, dev, uc) {
 648                if (dev_get_driver_data(dev) == driver_data) {
 649                        *devp = dev;
 650
 651                        return device_probe(dev);
 652                }
 653        }
 654
 655        return -ENODEV;
 656}
 657
 658int uclass_bind_device(struct udevice *dev)
 659{
 660        struct uclass *uc;
 661        int ret;
 662
 663        uc = dev->uclass;
 664        list_add_tail(&dev->uclass_node, &uc->dev_head);
 665
 666        if (dev->parent) {
 667                struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
 668
 669                if (uc_drv->child_post_bind) {
 670                        ret = uc_drv->child_post_bind(dev);
 671                        if (ret)
 672                                goto err;
 673                }
 674        }
 675
 676        return 0;
 677err:
 678        /* There is no need to undo the parent's post_bind call */
 679        list_del(&dev->uclass_node);
 680
 681        return ret;
 682}
 683
 684#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 685int uclass_unbind_device(struct udevice *dev)
 686{
 687        struct uclass *uc;
 688        int ret;
 689
 690        uc = dev->uclass;
 691        if (uc->uc_drv->pre_unbind) {
 692                ret = uc->uc_drv->pre_unbind(dev);
 693                if (ret)
 694                        return ret;
 695        }
 696
 697        list_del(&dev->uclass_node);
 698        return 0;
 699}
 700#endif
 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                ret = uc_drv->child_pre_probe(dev);
 719                if (ret)
 720                        return ret;
 721        }
 722
 723        return 0;
 724}
 725
 726int uclass_post_probe_device(struct udevice *dev)
 727{
 728        struct uclass_driver *uc_drv;
 729        int ret;
 730
 731        if (dev->parent) {
 732                uc_drv = dev->parent->uclass->uc_drv;
 733                if (uc_drv->child_post_probe) {
 734                        ret = uc_drv->child_post_probe(dev);
 735                        if (ret)
 736                                return ret;
 737                }
 738        }
 739
 740        uc_drv = dev->uclass->uc_drv;
 741        if (uc_drv->post_probe) {
 742                ret = uc_drv->post_probe(dev);
 743                if (ret)
 744                        return ret;
 745        }
 746
 747        return 0;
 748}
 749
 750#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
 751int uclass_pre_remove_device(struct udevice *dev)
 752{
 753        struct uclass *uc;
 754        int ret;
 755
 756        uc = dev->uclass;
 757        if (uc->uc_drv->pre_remove) {
 758                ret = uc->uc_drv->pre_remove(dev);
 759                if (ret)
 760                        return ret;
 761        }
 762
 763        return 0;
 764}
 765#endif
 766
 767int uclass_probe_all(enum uclass_id id)
 768{
 769        struct udevice *dev;
 770        int ret;
 771
 772        ret = uclass_first_device(id, &dev);
 773        if (ret || !dev)
 774                return ret;
 775
 776        /* Scanning uclass to probe all devices */
 777        while (dev) {
 778                ret = uclass_next_device(&dev);
 779                if (ret)
 780                        return ret;
 781        }
 782
 783        return 0;
 784}
 785
 786UCLASS_DRIVER(nop) = {
 787        .id             = UCLASS_NOP,
 788        .name           = "nop",
 789};
 790