设备树匹配内核匹配驱动程序的理解

使用设备树时,给驱动程序调用的过程

我们把设备树.dts 变成plantform_device的资源 过程一步步了解清楚
在这里插入图片描述

设备树中运行时配置启动信息的处理

设备树只是起一个信息传递的作用,对这些信息配置的处理,也比较简单,即从设备树的DTB文件中,把这些设备信息提取出来赋给内核中的某个变量即可。
1./chosen节点中bootargs属性就是内核启动的命令行参数,它里面可以指定根文件系统在哪里,第一个运行的应用程序是哪一个,指定内核的打印信息从哪个设备里打印出来。

2./memory中的reg属性指定了不同板子内存的大小和起始地址。

3.根节点的#address-cells和#size-cells属性指定属性参数的位数,比如指定前面memory中的reg属性的地址是32位还是64位,大小是用一个32位表示,还是两个32位表示。

设备树中平台信息的处理(选择machinedesc)

一个编译成uImage的内核镜像文件,可以支持多个单板,这里假设支持smdk2410、smdk2440、jz2440(其中smdk2410、smdk2440是厂家的公板,国内的厂家参考公板设计出了自己的板子,比如jz2440)。
这些板子的配置稍有不同,需要做一些单独的初始化,在内核里面,对于这些单板,都构造了一个machinedesc结构体,里面有.init和.nr。 对于JZ2440,它源自smdk2440,内核没有它的单独文件,它使用smdk2440的相关文件,代码。 在上一节视频里面我们说过,以前uboot使用ATAGS给内核传参数时,它会传入一个机器ID,内核会使用这个机器ID找到最合适的machinedesc。即机器ID与machine_desc里面的.nr比较,相等就表示找到了对应的machinedesc。 当我们的uboot不使用ATAGS传参数,而使用DTB文件时,那么这时内核是如何选择对应的machinedesc呢? 在设备树文件的根节点里,有如下两行:

c model = "SMDK24440"; compatible = "samsung,smdk2440""samsung,smdk24140""samsung,smdk24xx";

这里的compatible属性声明想要什么machinedesc,属性值可以是一系列字符串,依次与machinedesc匹配。 内核最好支持samsung,smdk2440,如果不支持,再尝试是否支持samsung,smdk24140,再不支持,最后尝试samsung,smdk24xx

a. 设备树根节点的compatible属性列出了一系列的字符串, 表示它兼容的单板名,从"最兼容"到次之;
b. 内核中有多个machinedesc, 其中有dtcompat成员, 它指向一个字符串数组, 里面表示该machine_desc支持哪些单板;

c. 使用compatile属性的值, 跟’’‘每一个machinedesc.dtcompat’’'比较, 成绩为"吻合的compatile属性值的位置", 成绩越低越匹配, 对应的machine_desc即被选中

dtb转换为devicenode

在dts文件里,每个大括号{ }代表一个节点,比如根节点里有个大括号,对应一个devicenode结构体;memory也有一个大括号,也对应一个devicenode结构体。 节点里面有各种属性,也可能里面还有子节点,所以它们还有一些父子关系。 根节点下的memory、chosen、led等节点是并列关系,兄弟关系。 对于父子关系、兄弟关系,在device_node结构体里面肯定有成员来描述这些关系。

打开include/linux/Of.h可以看到devicenode结构体的定义如下:
struct devicenode { const char *name; // 来自节点中的name属性, 如果没有该属性, 则设为"NULL"
const char *type; // 来自节点中的device_type属性, 如果没有该属性, 则设为"NULL"
phandle phandle;
const char *fullname; // 节点的名字, node-name[@unit-address] struct fwnodehandle fwnode;

struct  property *properties;  // 节点的属性
        struct  property *deadprops;    /* removed properties */
        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 转换成planfrom_device

哪些device_node可以转换为plantfrom_device?

a.根节点下含有compatile属性的子节点
b.除了根节点的子节点外,子节点的子节点里compatile属性里有特殊值(“simple-bus”,“simple-mfd”,“isa”,“arm,amba-bus”)之一,那么子节点的子节点可以转换为plantform_device
c.i2c,spi已经转化为plantform_device,所以他们的子节点应该被,总线drv的probe来调用

eg1:

/dts-v1/;

/memreserve/ 0x33f00000 0x100000;

/ {
	model = "SMDK24440";
	compatible = "samsung,smdk2440";

	#address-cells = <1>;
	#size-cells = <1>;
		
	memory {  /* /memory */
		device_type = "memory";
		reg =  <0x30000000 0x4000000 0 4096>;		
	};

	
/*
	cpus {
		cpu {
			compatible = "arm,arm926ej-s";
		};
	};
*/	
	chosen {
		bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
	};

	
	led {
		compatible = "jz2440_led";
		pin = <S3C2410_GPF(5)>;
	};
};

上面只有led节点有compatbile属性,他被转化为drv

怎么转换device_node 变成planfrom_device

a. platform_device中含有resource数组, 它来自device_node的reg, interrupts属性;
b. platform_device.dev.of_node指向device_node, 可以通过它获得其他属性(我们自定义比如pin)
eg:

 / {
          mytest {
              compatile = "mytest", "simple-bus";
              mytest@0 {
                    compatile = "mytest_0";
              };
          };
          
          i2c {
              compatile = "samsung,i2c";
              at24c02 {
                    compatile = "at24c02";                      
              };
          };

          spi {
              compatile = "samsung,spi";              
              flash@0 {
                    compatible = "winbond,w25q32dw";
                    spi-max-frequency = <25000000>;
                    reg = <0>;
                  };
          };
      };

/mytest会被转换为platform_device,
因为它兼容"simple-bus", 它的子节点/mytest/mytest@0 也会被转换为platform_device

/i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
/i2c/at24c02节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个i2c_client。

类似的也有/spi节点, 它一般也是用来表示SPI控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
/spi/flash@0节点不会被转换为platform_device, 它被如何处理完全由父节点的platform_driver决定, 一般是被创建为一个spi_device。

platform_device跟platform_driver的匹配

当我们把设备树文件转换为dev时,就能进行drv的匹配
在这里插入图片描述
比较的优先顺序:
a. 比较 platform_dev.driver_override 和 platform_driver.drv->name
b. 比较 platform_dev.dev.of_node的compatible属性 和 platform_driver.drv->of_match_table
c. 比较 platform_dev.name 和 platform_driver.id_table
d. 比较 platform_dev.name 和 platform_driver.drv->name
有一个成功, 即匹配成功

在根文件系统查看设备树(有助于调试)

a. /sys/firmware/fdt // 原始dtb文件

对这个文件使用命令

hexdump -C /sys/firmware/fdt

可以查看到原始的dtb文件
在这里插入图片描述

b. /sys/firmware/devicetree

以目录结构程现的dtb文件, 根节点对应base目录, 每一个节点对应一个目录, 每一个属性对应一个文件
同样用命令hexdump -C ./led 进行查看
在这里插入图片描述

/sys/devices/platform

系统中所有的platform_device, 有来自设备树的, 也有来有.c文件中注册的
对于来自设备树的platform_device,
可以进入 /sys/devices/platform/<设备名>/of_node 查看它的设备树属性

在这里插入图片描述

/proc/device-tree

/proc/device-tree 是链接文件, 指向 /sys/firmware/devicetree/base
在这里插入图片描述

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值