设为首页 加入收藏

TOP

uboot的驱动模型理解(一)
2019-09-01 23:09:07 】 浏览:70
Tags:uboot 驱动 模型 理解
uboot的驱动模型,简称dm, 具体细节建议参考./doc/driver-model/README.txt
关于dm的三个概念:
uclass:一组同类型的devices,uclass为同一个group的device,提供一个相同的接口。比如:I2C、GPIO等
driver:上层的接口,英文原文解释是“some code which talks to a peripheral and presents a higher-level
    interface to it.”
device:driver的一个实例,绑定到一个具体的端口或者外设。(driver和device是不是可以类比于程序与进程,进程是程序的一个实例)
 
每一类uclass,需要在代码中用下面的方式来定义,以spi-uclass为例:
 
UCLASS_DRIVER(spi) = {
    .id        = UCLASS_SPI,
    .name        = "spi",
    .flags        = DM_UC_FLAG_SEQ_ALIAS,
    .post_bind    = spi_post_bind,
    .post_probe    = spi_post_probe,
    .child_pre_probe = spi_child_pre_probe,
    .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
    .per_child_auto_alloc_size = sizeof(struct spi_slave),
    .per_child_platdata_auto_alloc_size =
            sizeof(struct dm_spi_slave_platdata),
    .child_post_bind = spi_child_post_bind,
};

 

通过对宏定义UCLASS_DRIVER的展开
/* Declare a new uclass_driver */
#define UCLASS_DRIVER(__name)                        \
    ll_entry_declare(struct uclass_driver, __name, uclass)
 
#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)))
这样我们就能得到一个结构体, struct uclass_driver _u_boot_list_2_uclass_2_spi
并且存在 .u_boot_list_2_uclass_2_spi段。
但是我们如何通过ID UCLASS_SPI来找到对应的uclass结构体呢?
struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
{
// 会根据.u_boot_list_2_uclass_1的段地址来得到uclass_driver table的地址
    struct uclass_driver *uclass =
        ll_entry_start(struct uclass_driver, uclass);
 
// 获得uclass_driver table的长度
    const int n_ents = ll_entry_count(struct uclass_driver, uclass);
    struct uclass_driver *entry;
 
    for (entry = uclass; entry != uclass + n_ents; entry++) {
        if (entry->id == id)
            return entry;
    }
 
    return NULL;
}
可以通过函数lists_uclass_lookup(enum uclass_id id)来查找。
 
另外,driver也是类似
/* 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)))
 
U_BOOT_DRIVER(tegra114_spi) = {
    .name    = "tegra114_spi",
    .id    = UCLASS_SPI,
    .of_match = tegra114_spi_ids,
    .ops    = &tegra114_spi_ops,
    .ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
    .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
    .priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
    .probe    = tegra114_spi_probe,
};
这样我们就能得到一个结构体,
ll_entry_declare(struct driver, tegra114_spi, driver)
 
struct driver _u_boot_list_2_driver_2_tegra114_spi
                             __aligned(4)        \
            __attribute__((unused,                \
            section(".u_boot_list_2_driver_2_tegra114_spi")))

 

存储在段,.u_boot_list_2_driver_2_tegra114_spi
但是这些段,在uboot实际加载的时候,又是如何加载到链表中去的呢!
 
首先,还是初始化列表init_sequence_f里的函数initf_dm
static int initf_dm(void)
{
#if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
    int ret;
 
    ret = dm_init_and_scan(true);
    if (ret)
        return ret;
#endif
#ifdef CONFIG_TIMER_EARLY
    re
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇嵌入式开发简介学习 下一篇Zephyr学习(二)开发环境搭建

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目