栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

43.驱动--内核对设备树的解析

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

43.驱动--内核对设备树的解析

Exynos4412 内核移植(六)—— 设备树解析_知秋一叶-CSDN博客

第三课:linux内核对设备树的处理_韦东山嵌入式专栏-CSDN博客_linux内核设备数

通过大神的文章,结合自己的理解写写加深印象.其实设备树会用既可以。

1.内核对设备树的解析需要做三件事,从大到小分别是:

板级平台的识别-->运行参数的解析-->描述所有设备(device population) 

2.不使用设备树的时候,板级平台的识别和运行参数的解析由bootloader设置好机器识别ID以及ATAGS,通过theKernel函数指针传给内核

描述所有设备(device population)则在根文件系统运行后,在内核中由驱动程序注册生成。

3.如今要使用设备树实现板级平台的识别、运行参数的解析和描述所有设备(device population)这三步,在theKernel()函数指针传递的第三个值从ATAGS换成DTB的首地址,DTB内含有上述三步的所有信息,theKernel()的第二个参数板子ID就没有用,theKernel(0,板子ID(无效),DTB首地址)。

4.theKernel的三个参数在内核中会分别赋予三个寄存器,r0、r1和r2

r0一般设置为0;
r1一般设置为machine id (在使用设备树时该参数没有被使用);
r2一般设置ATAGS或DTB的开始地址;

内核第一个函数head.s会对这三个寄存器进行简单处理

a. __lookup_processor_type : 使用汇编指令读取CPU ID, 根据该ID找到对应的proc_info_list结构体(里面含有这类CPU的初始化函数、信息)
b. __vet_atags             : 判断是否存在可用的ATAGS或DTB
c. __create_page_tables    : 创建页表, 即创建虚拟地址和物理地址的映射关系
d. __enable_mmu            : 使能MMU, 以后就要使用虚拟地址了
e. __mmap_switched         : 上述函数里将会调用__mmap_switched
f. 把bootloader传入的r2参数, 保存到变量__atags_pointer中
g. 调用C函数start_kernel

head.S/head-common.S  : 
把bootloader传来的r1值, 赋给了C变量: __machine_arch_type
把bootloader传来的r2值, 赋给了C变量: __atags_pointer     // dtb首地址

5.板级平台的识别

r2参数保存在__atags_pointer了,启动了start_kernel函数了,start_kernel函数运行如下

 内核中存在很多个不同板子的meachin_desc,跟目录下的compatible属性进行匹配,一致则会调用对应meachin_desc下的初始化启动函数。compatible属性可以是一连串的单板描述字符串,匹配度从左到右依次降低。优先使用最左边的单板描述字符串。

下面是其中一个单板例子

 设别树对应的

 

 6.运行时参数的提取

运行参数不用进行特殊处理,只需要从DTB文件中提取出来赋给固定的全局变量即可。提取是在板子匹配成功后执行。

 

a. /chosen节点中bootargs属性的值, 存入全局变量: boot_command_line
b. 确定根节点的这2个属性的值: #address-cells, #size-cells
   存入全局变量: dt_root_addr_cells, dt_root_size_cells
c. 解析/memory中的reg属性, 提取出"base, size", 最终调用memblock_add(base, size);

7.描述所有设备(device population)

device population我也不知道怎么翻译,大致就是生成平台需要的device,然后和drive进行匹配

7.1 dtb文件所在的内存是会被内核自动保存起来,内核时不会去占用,即使没有指定

7.2 首先是把所有设备的描述提取出来构造节点,从根节点开始,每个大括号{}对应一个device_node结构体,device_node结构体有父指针、兄弟指针,子指针,通过父子兄弟指针的指向,把设备树所有节点关系在内存中立体成一棵树

  struct device_node {
            const char *name;  // 来自节点中的name属性, 如果没有该属性, 则设为"NULL"
            const char *type;  // 来自节点中的device_type属性, 如果没有该属性, 则设为"NULL"
            phandle phandle;
            const char *full_name;  // 节点的名字, node-name[@unit-address]
            struct fwnode_handle fwnode;

            struct  property *properties;  // 节点的属性
            struct  property *deadprops;    
            struct  device_node *parent;   // 节点的父亲
            struct  device_node *child;    // 节点的孩子(子节点)
            struct  device_node *sibling;  // 节点的兄弟(同级节点)
        #if defined(CONFIG_OF_KOBJ)
            struct  kobject kobj;
        #endif
            unsigned long _flags;
            void    *data;
        #if defined(CONFIG_SPARC)
            const char *path_component_name;
            unsigned int unique_id;
            struct of_irq_controller *irq_trans;
        #endif
        };

device_node结构中的property结构体记录节点的信息,如长度、值等,相当于树叶

 struct property {
            char    *name;    // 属性名字, 指向dtb文件中的字符串
            int length;       // 属性值的长度
            void    *value;   // 属性值, 指向dtb文件中value所在位置, 数据仍以big endian存储
            struct property *next;
        #if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
            unsigned long _flags;
        #endif
        #if defined(CONFIG_OF_PROMTREE)
            unsigned int unique_id;
        #endif
        #if defined(CONFIG_OF_KOBJ)
            struct bin_attribute attr;
        #endif
        };

通过这两个结构体,一个完整的设备树就描述完成

 7.3_device_node转换为platform_device

1.根节点下的子节点中有compatible属性的会转换成platform_device

2.如果一个结点的compatile属性含有这些特殊的值("simple-bus","simple-mfd","isa","arm,amba-bus")之一, 那么它的子结点(需含compatile属性)也可以转换为platform_device

根节点的子节点外的节点,一般交给其父节点的platform_drive来处理。

 platform_device中含有resource数组, 它来自device_node的reg, interrupts属性;
platform_device.dev.of_node指向device_node, 可以通过它获得其他属性

 生成的platform_device就会跟 platform_driver去匹配

8.platform_device和platform_drive的匹配

匹配的顺序比较重要

匹配函数是platform_bus_type.match, 即platform_match,
匹配过程按优先顺序罗列如下:

比较 platform_dev.driver_override 和 platform_driver.drv->name
比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table(设备树用这个)
比较 platform_dev.name 和 platform_driver.id_table(以前常用这个)
比较 platform_dev.name 和 platform_driver.drv->name
有一个成功, 即匹配成功
 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/728609.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号