zoukankan      html  css  js  c++  java
  • 【u-boot】u-boot中initf_dm()函数执行流程(转)

    前部分设备模型初始化

    为了便于阅读,删掉部分代码,只留关键的过程:

    static int initf_dm(void)
    {
        int ret;
        ret = dm_init_and_scan(true);
        if (ret)
            return ret;
        return 0;
    }


    该函数调用了 dm_init_and_scan();并且传入的参数为true,uboot中对该函数的注释如下:

    /**
     * dm_init_and_scan() - Initialise Driver Model structures and scan for devices
     *
     * This function initialises the roots of the driver tree and uclass trees,
     * then scans and binds available devices from platform data and the FDT.
     * This calls dm_init() to set up Driver Model structures.
     *
     * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
     * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
     * @return 0 if OK, -ve on error
     */

    下面看具体的执行过程,删除参数检查等相关代码,如下图:

    int dm_init_and_scan(bool pre_reloc_only)
    {
       ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE));
       ret = dm_scan_platdata(pre_reloc_only);
       ret = dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only);
       ret = dm_scan_other(pre_reloc_only);
    }


    该函数一共调用了四个函数,首先看第一个函数 dm_init(),该函数中涉及到关键的结构体struct global_data,该结构体的具体作用此处不做展开,只看结构体中和DM相关的部分

        struct udevice    *dm_root;    /* Root instance for Driver Model */
        struct udevice    *dm_root_f;    /* Pre-relocation root instance */
        struct list_head uclass_root;    /* Head of core tree */

        #define DM_ROOT_NON_CONST        (((gd_t *)gd)->dm_root)
        #define DM_UCLASS_ROOT_NON_CONST    (((gd_t *)gd)->uclass_root)

    删除参数检查和返回值检查等代码,注释和实现过程如下:

    /**
     * dm_init() - Initialise Driver Model structures
     * This function will initialize roots of driver tree and class tree.
     * This needs to be called before anything uses the DM
     * @of_live:    Enable live device tree
     * @return 0 if OK, -ve on error
     */
    int dm_init(bool of_live)
    {
        int ret;
        if (gd->dm_root) {
            dm_warn("Virtual root driver already exists! ");
            return -EINVAL;
        }
        INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);

        ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);

    #if CONFIG_IS_ENABLED(OF_CONTROL)
            DM_ROOT_NON_CONST->node = offset_to_ofnode(0);
    #endif
        ret = device_probe(DM_ROOT_NON_CONST);
        return 0;
    }

    该函数又调用了device_bind_by_name()函数

    /**
    * device_bind_by_name: Create a device and bind it to a driver
    *
    * This is a helper function used to bind devices which do not use device
    * tree.
    *
    * @parent: Pointer to device's parent
    * @pre_reloc_only: If true, bind the driver only if its DM_FLAG_PRE_RELOC flag
    * is set. If false bind the driver always.
    * @info: Name and platdata for this device
    * @devp: if non-NULL, returns a pointer to the bound device
    * @return 0 if OK, -ve on error
    */
    int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
               const struct driver_info *info, struct udevice **devp)
    {
       struct driver *drv;
       uint platdata_size = 0;

       drv = lists_driver_lookup_name(info->name);
       if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
           return -EPERM;

    #if CONFIG_IS_ENABLED(OF_PLATDATA)
       platdata_size = info->platdata_size;
    #endif
       return device_bind_common(parent, drv, info->name,
               (void *)info->platdata, 0, ofnode_null(), platdata_size,
               devp);
    }

    该函数最终调用了device_bind_common()函数

    static int device_bind_common(struct udevice *parent, const struct driver *drv,
                      const char *name, void *platdata,
                      ulong driver_data, ofnode node,
                      uint of_platdata_size, struct udevice **devp)
    {
        struct udevice *dev;
        struct uclass *uc;
        int size, ret = 0;

        if (devp)
            *devp = NULL;
        if (!name)
            return -EINVAL;

        ret = uclass_get(drv->id, &uc);
        if (ret) {
            debug("Missing uclass for driver %s ", drv->name);
            return ret;
        }

        dev = calloc(1, sizeof(struct udevice));
        if (!dev)
            return -ENOMEM;

        INIT_LIST_HEAD(&dev->sibling_node);
        INIT_LIST_HEAD(&dev->child_head);
        INIT_LIST_HEAD(&dev->uclass_node);
    #ifdef CONFIG_DEVRES
        INIT_LIST_HEAD(&dev->devres_head);
    #endif
        dev->platdata = platdata;
        dev->driver_data = driver_data;
        dev->name = name;
        dev->node = node;
        dev->parent = parent;
        dev->driver = drv;
        dev->uclass = uc;

        dev->seq = -1;
        dev->req_seq = -1;
        if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
            (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
            /*
             * Some devices, such as a SPI bus, I2C bus and serial ports
             * are numbered using aliases.
             *
             * This is just a 'requested' sequence, and will be
             * resolved (and ->seq updated) when the device is probed.
             */
            if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
                if (uc->uc_drv->name && ofnode_valid(node))
                    dev_read_alias_seq(dev, &dev->req_seq);
            } else {
                dev->req_seq = uclass_find_next_free_req_seq(drv->id);
            }
        }

        if (drv->platdata_auto_alloc_size) {
            bool alloc = !platdata;

            if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
                if (of_platdata_size) {
                    dev->flags |= DM_FLAG_OF_PLATDATA;
                    if (of_platdata_size <
                            drv->platdata_auto_alloc_size)
                        alloc = true;
                }
            }
            if (alloc) {
                dev->flags |= DM_FLAG_ALLOC_PDATA;
                dev->platdata = calloc(1,
                               drv->platdata_auto_alloc_size);
                if (!dev->platdata) {
                    ret = -ENOMEM;
                    goto fail_alloc1;
                }
                if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
                    memcpy(dev->platdata, platdata,
                           of_platdata_size);
                }
            }
        }

        size = uc->uc_drv->per_device_platdata_auto_alloc_size;
        if (size) {
            dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
            dev->uclass_platdata = calloc(1, size);
            if (!dev->uclass_platdata) {
                ret = -ENOMEM;
                goto fail_alloc2;
            }
        }

        if (parent) {
            size = parent->driver->per_child_platdata_auto_alloc_size;
            if (!size) {
                size = parent->uclass->uc_drv->
                        per_child_platdata_auto_alloc_size;
            }
            if (size) {
                dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
                dev->parent_platdata = calloc(1, size);
                if (!dev->parent_platdata) {
                    ret = -ENOMEM;
                    goto fail_alloc3;
                }
            }
        }

        /* put dev into parent's successor list */
        if (parent)
            list_add_tail(&dev->sibling_node, &parent->child_head);

        ret = uclass_bind_device(dev);
        if (ret)
            goto fail_uclass_bind;

        /* if we fail to bind we remove device from successors and free it */
        if (drv->bind) {
            ret = drv->bind(dev);
            if (ret)
                goto fail_bind;
        }
        if (parent && parent->driver->child_post_bind) {
            ret = parent->driver->child_post_bind(dev);
            if (ret)
                goto fail_child_post_bind;
        }
        if (uc->uc_drv->post_bind) {
            ret = uc->uc_drv->post_bind(dev);
            if (ret)
                goto fail_uclass_post_bind;
        }

        if (parent)
            pr_debug("Bound device %s to %s ", dev->name, parent->name);
        if (devp)
            *devp = dev;

        dev->flags |= DM_FLAG_BOUND;

        return 0;

    fail_uclass_post_bind:
        /* There is no child unbind() method, so no clean-up required */
    fail_child_post_bind:
        if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
            if (drv->unbind && drv->unbind(dev)) {
                dm_warn("unbind() method failed on dev '%s' on error path ",
                    dev->name);
            }
        }

    fail_bind:
        if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
            if (uclass_unbind_device(dev)) {
                dm_warn("Failed to unbind dev '%s' on error path ",
                    dev->name);
            }
        }
    fail_uclass_bind:
        if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
            list_del(&dev->sibling_node);
            if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
                free(dev->parent_platdata);
                dev->parent_platdata = NULL;
            }
        }
    fail_alloc3:
        if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
            free(dev->uclass_platdata);
            dev->uclass_platdata = NULL;
        }
    fail_alloc2:
        if (dev->flags & DM_FLAG_ALLOC_PDATA) {
            free(dev->platdata);
            dev->platdata = NULL;
        }
    fail_alloc1:
        devres_release_all(dev);

        free(dev);

        return ret;
    }


    在dm_init()函数中,最后执行的是device_probe()函数

    /**
     * device_probe() - Probe a device, activating it
     *
     * Activate a device so that it is ready for use. All its parents are probed
     * first.
     *
     * @dev: Pointer to device to probe
     * @return 0 if OK, -ve on error
     */
    int device_probe(struct udevice *dev)
    {
        struct power_domain pd;
        const struct driver *drv;
        int size = 0;
        int ret;
        int seq;

        if (!dev)
            return -EINVAL;

        if (dev->flags & DM_FLAG_ACTIVATED)
            return 0;

        drv = dev->driver;
        assert(drv);

        /* Allocate private data if requested and not reentered */
        if (drv->priv_auto_alloc_size && !dev->priv) {
            dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
            if (!dev->priv) {
                ret = -ENOMEM;
                goto fail;
            }
        }
        /* Allocate private data if requested and not reentered */
        size = dev->uclass->uc_drv->per_device_auto_alloc_size;
        if (size && !dev->uclass_priv) {
            dev->uclass_priv = alloc_priv(size,
                              dev->uclass->uc_drv->flags);
            if (!dev->uclass_priv) {
                ret = -ENOMEM;
                goto fail;
            }
        }

        /* Ensure all parents are probed */
        if (dev->parent) {
            size = dev->parent->driver->per_child_auto_alloc_size;
            if (!size) {
                size = dev->parent->uclass->uc_drv->
                        per_child_auto_alloc_size;
            }
            if (size && !dev->parent_priv) {
                dev->parent_priv = alloc_priv(size, drv->flags);
                if (!dev->parent_priv) {
                    ret = -ENOMEM;
                    goto fail;
                }
            }

            ret = device_probe(dev->parent);
            if (ret)
                goto fail;

            /*
             * The device might have already been probed during
             * the call to device_probe() on its parent device
             * (e.g. PCI bridge devices). Test the flags again
             * so that we don't mess up the device.
             */
            if (dev->flags & DM_FLAG_ACTIVATED)
                return 0;
        }

        seq = uclass_resolve_seq(dev);
        if (seq < 0) {
            ret = seq;
            goto fail;
        }
        dev->seq = seq;

        dev->flags |= DM_FLAG_ACTIVATED;

        /*
         * Process pinctrl for everything except the root device, and
         * continue regardless of the result of pinctrl. Don't process pinctrl
         * settings for pinctrl devices since the device may not yet be
         * probed.
         */
        if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
            pinctrl_select_state(dev, "default");

        if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
            if (!power_domain_get(dev, &pd))
                power_domain_on(&pd);
        }

        ret = uclass_pre_probe_device(dev);
        if (ret)
            goto fail;

        if (dev->parent && dev->parent->driver->child_pre_probe) {
            ret = dev->parent->driver->child_pre_probe(dev);
            if (ret)
                goto fail;
        }

        if (drv->ofdata_to_platdata && dev_has_of_node(dev)) {
            ret = drv->ofdata_to_platdata(dev);
            if (ret)
                goto fail;
        }

        /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
        ret = clk_set_defaults(dev);
        if (ret)
            goto fail;

        if (drv->probe) {
            ret = drv->probe(dev);
            if (ret) {
                dev->flags &= ~DM_FLAG_ACTIVATED;
                goto fail;
            }
        }

        ret = uclass_post_probe_device(dev);
        if (ret)
            goto fail_uclass;

        if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
            pinctrl_select_state(dev, "default");

        return 0;
    fail_uclass:
        if (device_remove(dev, DM_REMOVE_NORMAL)) {
            dm_warn("%s: Device '%s' failed to remove on error path ",
                __func__, dev->name);
        }
    fail:
        dev->flags &= ~DM_FLAG_ACTIVATED;

        dev->seq = -1;
        device_free(dev);

        return ret;
    }
    ————————————————
    版权声明:本文为CSDN博主「liuduanfei」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/A_orz_/article/details/100117065

  • 相关阅读:
    Java.io.outputstream.PrintStream:打印流
    Codeforces 732F. Tourist Reform (Tarjan缩点)
    退役了
    POJ 3281 Dining (最大流)
    Light oj 1233
    Light oj 1125
    HDU 5521 Meeting (最短路)
    Light oj 1095
    Light oj 1044
    HDU 3549 Flow Problem (dinic模版 && isap模版)
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/12056004.html
Copyright © 2011-2022 走看看