U-boot 下DM驱动模型的相关笔记
要注意的关键两点:

DM驱动模型的一般流程bind->ofdata_to_platdata(可选)->probe
    启动,bind操作时单独完成的,主要完成设备和驱动的绑定,以及node 注:node是匹配到驱动的设备节点 之间的连接。ofdata_to_platdata(可选)->probe 则是在device_probe函数中完成的。

明确了以上两点,接下来就开始展开分析U-boot下设计到驱动模型的一半流程,我依据的是U-boot 2018.03版本
和DM相关的初始化流程主要有两次,入口函数分别是static int initf_dm(void)和static int initr_dm(void)。
第一次是在重定位之前,调用的是initf_dm函数,函数的调用关系如下所示:

initf_dm//执行bind操作,初始化一个dm模型的树形结构
    dm_init_and_scan(true)//初始化根节点设备,并bind根节点的带有u-boot,dm-pre-reloc属性的一级子节点。
        dm_init//将根节点绑定到gd->dm_root上,初始化根节点设备
            dm_scan_platdata//搜索使用宏U_BOOT_DEVICE定义的设备进行驱动匹配,也就是bind子节点
            dm_extended_scan_fdt//在其他地方(设备树)搜索设备并进行驱动匹配,然后bind
                dm_scan_fdt//在设备树种搜索设备并进行驱动匹配,然后bind
                    dm_scan_fdt_node//具体绑定设备的入口,在该函数中会确定设备是否具有boot,dm-pre-reloc属性,如果没有则不会绑定
                        lists_bind_fdt//搜索可以匹配到该设备的驱动
                            device_bind_with_driver_data//如果匹配到进行绑定
                                device_bind_common//匹配设备和驱动,并将设备节点和parent节点建立联系,也就是建立树形结构
                                    uclass_bind_device//将该设备挂在对应的U_CLASS链表上
                                    drv->bind(dev)//设备驱动的bind接口函数
                                    parent->driver->child_post_bind(dev)//父节点驱动的child_post_bind接口函数
                                    uc->uc_drv->post_bind//设备所属类的驱动的post_bind接口函数(具体的设备节点就是在这个接口下在soc下进行展开的)

至此,dm相关的一半bind流程就介绍完了,执行完initf_dm之后,内存中就有了一个深度最深为2(只有根节点时,深度为1)的树形结构,根节点挂在gd->dm_root上。
同样的,static int initr_dm(void)执行了类似的操作,只不过,

gd->dm_root_f = gd->dm_root; gd->dm_root = NULL;

重定位之后,首先将gd->dm_root的值赋值给gd->dm_root_f;然后清零了gd->dm_root,接下来才是重新执行dm_init_and_scan(false)操作,

dm_init_and_scan(false)//初始化根节点设备,并bind根节点的所有子节点
    ************省略,见initf_dm函数流程
bind操作完成之后,就可以对设备进行probe操作了,示例一下sdram的初始化流程,我用的板子是基于stm32f767igt的YYFISH board。和sdram基于fmc,并且除了sdram,fmc下还挂了一个4Gbit 的 nand flash,设备树相关的源码如下:

&fmc {
pinctrl-0 = <&fmc_pins>;
pinctrl-names = "default";
status = "okay";
#address-cells = <1>;
#size-cells = <1>;

/* Memory configuration from sdram datasheet MT48LC_4M32_B2B5-6A */
bank1: bank@0 {
       st,sdram-control = /bits/ 8 <NO_COL_9 NO_ROW_13 MWIDTH_16 BANKS_4
                        CAS_3 SDCLK_2 RD_BURST_EN
                    RD_PIPE_DL_1>;
       st,sdram-timing = /bits/ 8 <TMRD_2 TXSR_8 TRAS_7 TRC_7 TWR_2
                       TRP_2 TRCD_2>;
    /* refcount = (64msec/total_row_sdram)*freq - 20 */
       st,sdram-refcount = < 1421 >;
   };
bank3: stm32_nand {
    reg = <0xA0000080 0x20>;
    /*Nand flash configuretion from flash datasheet MT29F4G08ABADA*/
    compatible = "micron,mt29f4g", "st,nand-flash";
    st,nand-control = /bits/ 8 <FMC_PWAIT_DIS FMC_PWID_8 FMC_ECC_DIS
        FMC_TCLR_6 FMC_TAR_6 FMC_ECCPS_512>;
    st,nand-timing = /bits/ 8 <MEMSET_VALE_2 MEMWAIT_VALE_4 MEMHOLD_VALE_2
        MEMHIZ_VALE_2>;
    u-boot,dm-pre-reloc;
    };
};

从设备树文件可以看出,fmc下挂了两个节点,但是bank3;stm32_nand是我后来添加的,为了增加nand_flash的支持,所以stm32_nand就是fmc的一级子节点。fmc是root的子节点,树形结构的示意图如下

root
    \
    soc
        \
        fmc
             \
            stm32_nand

根据上面对initf_dm和initr_dm的分析,可知,这两个函数只是完成了root的一级子节点的树形创建,并且sdram的初始化是在重定向之前,也就是执行了initf_dm之后完成的(稍后会具体分析)。所以initf_dm执行之后,内存中只有如下的一个树形图:

root
    \
    soc
        \
        fmc

这时候是没有nand_flash这个设备节点的。nand_flash这个设备节点的绑定,我放在了fmc这个节点的probe流程中,具体是在ofdata_to_platdata这个接口函数中完成的。具体如下所示:

dev_for_each_subnode(bank_node, dev) {
    /* extract the bank index from DT */
    bank_name = (char *)ofnode_get_name(bank_node);
        if (!strncmp("stm32_nand", bank_name, strlen("stm32_nand")))//iysheng
        {   
            lists_bind_fdt(dev, bank_node, NULL);
            continue;
        }
}

从上述代码可以看出,当我device_probe fmc这个设备节点的时候,我会首先调用对应driver的ofdata_to_platdata函数接口,在这个接口函数中,会遍历子节点,如果发现名字是以stm32_nand开头的,那么会将这个设备节点进行进行bind操作,执行完这句话之后,设备树中的fmc节点下就会出现一个stm32_nand子节点,这时候树的深度从2变为了3。
接着会调用fmc节点对应驱动的probe接口函数,具体如下:

static int stm32_fmc_probe(struct udevice *dev)
{
    ******省略一些内容,和sdram初始化相关的内容
    if (device_has_children(dev))
    {
        struct udevice * child_devp;
        int index = 0;
        while(!device_get_child(dev, index++, &child_devp)) {
            ret = device_probe(child_devp);
            if (ret < 0)
                break;
        }
    }
}

可以看出,stm32_fmc_probe的时候,会尝试probe fmc节点下的所有子节点。因为之前已经添加了stm32_nand节点,这时候就会去probe stm32_nand那个设备了。
接下来简述一下sdram的probe流程。函数调用过程如下:

int dram_init(void)
    uclass_get_device(UCLASS_RAM, 0, &dev)
        uclass_find_device(id, index, &dev)
        uclass_get_device_tail(dev, ret, devp)
            device_probe(dev)
                device_probe(dev->parent)//递归probe父节点
                uclass_resolve_seq//父节点都probe之后,会分配一个seq给该设备
                dev->flags |= DM_FLAG_ACTIVATED//设置该设备的flag为激活状态
                pinctrl_select_state(dev, "default")//和引脚相关的初始化设置<需要进一步分析>
                dev->parent->driver->child_pre_probe(dev)//执行父节点驱动的child_pre_probe接口函数
                drv->ofdata_to_platdata(dev)//执行设备驱动的ofdata_to_platdata接口函数
                clk_set_defaults(dev)//设备时钟相关的设置
                drv->probe(dev)//调用设备驱动的probe接口函数
                uclass_post_probe_device(dev)//调用所属CLASS驱动的post_probe接口函数

至此,sdram的初始化流程介绍了一下,从上可以看出,device_probe过程中,会首先调用ofdata_to_platdata接口函数,然后才会执行probe接口函数。
————————————————
版权声明:本文为CSDN博主「iysheng」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/iysheng/article/details/79921825

最新文章

  1. 使用Ruby来实现批量更新AD中字段
  2. 实战mysql分区(PARTITION)
  3. C# 拓展方法
  4. 关于全站https必要性http流量劫持、dns劫持等相关技术
  5. 2013.08.23.diary
  6. 基于Visual C++2013拆解世界五百强面试题--题8-数组的排序和查找
  7. 读书简记-java与模式
  8. 解决MyEclipse中的Building workspace问题
  9. 芝麻HTTP:Python爬虫实战之抓取爱问知识人问题并保存至数据库
  10. ITU-T G.1081 IPTV性能监测点 (Performance monitoring points for IPTV)
  11. 重庆3Shape TRIOS都有哪些功能
  12. jQuery禁用、开启鼠标滚轮事件
  13. jQuery-4.动画篇---动画切换的比较(toggle与slideToggle以及fadeToggle的比较)
  14. go语言的条件语句和循环语句
  15. java学习之路--StringBuffer常见的功能和实例
  16. 并发包同步工具CyclicBarrier
  17. 近期写的一个控件——Well Swipe beta 1.0
  18. 学习python的第十天(内置算法:列表数据类型,元祖数据类型,字典数据类型)
  19. 我的Python分析成长之路3
  20. sublime 高速打开跳转至关联文件

热门文章

  1. 配置nginx直接使用webpack生成的gz压缩文件,而不用nginx自己压缩
  2. Python全栈开发之6、面向对象
  3. 基于SpringBoot从零构建博客网站 - 整合ehcache和开发注册登录功能
  4. [转帖]java注解与注释注解区别
  5. 查找担保圈-step5-比较各组之间的成员,对组的包含性进行查询,具体见程序的注释-版本2
  6. python -- TypeError: &#39;module&#39; object is not callable
  7. 初识numpy库
  8. Vasya and Magic Matrix CodeForces - 1042E (概率dp)
  9. Spring MVC(一)Spring MVC的原理
  10. C# List.sort排序(多权重,升序降序)