• U_BOOT_DRIVER简析


    1、board_init_f和board_init_r(uboot/common/board_r.c、board_f.c)

    board_init_f调用init_sequence_f[]中数组元素表示的函数接口。board_init_r调用init_sequence_r[]中数组元素表示的函数接口。

    board_init_f是uboot重定位前的流程,它包括一些基础模块的初始化和重定位相关的准备工作。board_init_r是uboot重定位后需要执行的流程,它包含基础模块、硬件驱动以及板级特性等的初始化,并最终通过run_main_loop启动os会进入命令行窗口。

    2、U_BOOT_DRIVER

    新版u-boot都支持设备树,和linux一样,u-boot这里也建立了一个驱动模型。比如, of_match来匹配,probe来识别等。

    定义一个U_BOOT_DRIVER:

    U_BOOT_DRIVER(mtk_eth) = {
    	.name = "mtk-eth",
    	.id = UCLASS_ETH,
    	.of_match = mtk_eth_ids,
    	.of_to_plat = mtk_eth_of_to_plat,
    	.plat_auto	= sizeof(struct eth_pdata),
    	.probe = mtk_eth_probe,
    	.remove = mtk_eth_remove,
    	.ops = &mtk_eth_ops,
    	.priv_auto	= sizeof(struct mtk_eth_priv),
    	.flags = DM_FLAG_ALLOC_PRIV_DMA,
    };
    //其中:
    /* Declare a new U-Boot driver */
    #define U_BOOT_DRIVER(__name)						\
    	ll_entry_declare(struct driver, __name, driver)
    
    #define ll_entry_declare(_type, _name, _list)				\
    	_type _u_boot_list_2_##_list##_2_##_name __aligned(4)		\
    			__attribute__((unused,				\
    			section(".u_boot_list_2_"#_list"_2_"#_name)))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用U_BOOT_DRIVER宏都会指向u_boot_list_2_xx段,展开后,相当于定义了一个struct driver类型的变量

    对于struct driver结构体来看:

    struct driver {
    	char *name;
    	enum uclass_id id;
    	const struct udevice_id *of_match;
    	int (*bind)(struct udevice *dev);
    	int (*probe)(struct udevice *dev);
    	int (*remove)(struct udevice *dev);
    	int (*unbind)(struct udevice *dev);
    	int (*ofdata_to_platdata)(struct udevice *dev);
    	int (*child_post_bind)(struct udevice *dev);
    	int (*child_pre_probe)(struct udevice *dev);
    	int (*child_post_remove)(struct udevice *dev);
    	int priv_auto_alloc_size;
    	int platdata_auto_alloc_size;
    	int per_child_auto_alloc_size;
    	int per_child_platdata_auto_alloc_size;
    	const void *ops;	/* driver-specific operations */
    	uint32_t flags;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    看起来和linux确实很像。 再回来看链接脚本arch/arm/cpu/u-boot.lds

    . = ALIGN(4);
            .u_boot_list : {
                    KEEP(*(SORT(.u_boot_list*)));
            }
    
    • 1
    • 2
    • 3
    • 4

    设备驱动模型调用流程:

    init_sequence_f[]             // comman/board_f.c
        initf_dm
            dm_init_and_scan
                dm_init
                dm_scan_platdata
                dm_scan_fdt
                dm_scan_other
            dm_timer_init
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    int dm_init(void)
    {
    	int ret;
        if (gd->dm_root) {
            dm_warn("Virtual root driver already exists!\n");
            return -EINVAL;
        }
        INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
    
        ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
        if (ret)
            return ret;
    
        ret = device_probe(DM_ROOT_NON_CONST);
        if (ret)
            return ret;
    
        return 0;
    }
    
    // device_bind_by_name里面根据名字绑定
    
    int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
    			const struct driver_info *info, struct udevice **devp)
    {
    
        lists_driver_lookup_name(info->name);
         
        ...
        return device_bind_common(parent, drv, info->name,
    }
    //其中device_bind_common是核心,其与uclass建立关系,里面调用uclass_bind_device
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在初始化里面主要调用dm_scan_platdata来解析设备树信息并保存

    int dm_scan_platdata(bool pre_reloc_only)
    {
    	int ret;
        ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
        if (ret == -ENOENT) {
            dm_warn("Some drivers were not found\n");
            ret = 0;
        }
    
        return ret;
    }
    
    int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
    {
    	struct driver_info *info =
    		ll_entry_start(struct driver_info, driver_info);
    	const int n_ents = ll_entry_count(struct driver_info, driver_info);
    	struct driver_info *entry;
    	struct udevice *dev;
    	int result = 0;
    	int ret;
        for (entry = info; entry != info + n_ents; entry++) {     // 扫描
            ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
            if (ret && ret != -EPERM) {
                dm_warn("No match for driver '%s'\n", entry->name);
                if (!result || ret != -ENOENT)
                    result = ret;
            }
        }
    
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    然后再调用dm_scan_fdt_node分解子节点。
    参考链接:https://blog.csdn.net/qq_21353001/article/details/91337650

  • 相关阅读:
    ELK单机版部署踩坑及与Springboot整合
    一文读懂 Spring Bean 的生命周期
    基础测试干了4年,自学了自动化(太片面),突然接到被裁员消息
    ElasticSearch集群搭建
    Java基础知识篇之类的基本概念
    易语言实现植物大战僵尸新手cheat体验
    安全队列和曲线拟合
    Linux - nm命令
    矩阵乘法和激活函数
    学习笔记-ThinkPHP5之任意方法调用RCE(六)
  • 原文地址:https://blog.csdn.net/qq_37935909/article/details/127689277