首页 > 系统相关 >Linux设备树

Linux设备树

时间:2023-12-21 19:56:33浏览次数:37  
标签:compatible interrupt Linux device 设备 节点 属性

Linux设备树

Linux设备树语法详解 - Abnor - 博客园 (cnblogs.com)

Linux设备树(2)——设备树格式和使用 - Hello-World3 - 博客园 (cnblogs.com)

https://www.cnblogs.com/hellokitty2/p/10999432.html

1、概念

​ 设备树的出现是为了实现驱动代码和设备信息的分离,在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写。引入了设备树之后,驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,驱动开发者只需要修改设备树文件信息,不需要改写驱动代码。比如在ARM Linux内,一个.dts(device tree source)文件对应一个ARM的machine,一般放置在内核的"arch/arm/boot/dts/"目录内。

2、设备树框架

设备树用树状结构描述设备信息,它有以下几种特性

  1. 每个设备树文件都有一个根节点,每个设备都是一个节点。
  2. 节点间可以嵌套,形成父子关系,这样就可以方便的描述设备间的关系。
  3. 每个设备的属性都用一组key-value对(键值对)来描述。
  4. 每个属性的描述用;结束

其文件布局如下所示,/表示板子:

/dts-v1/;
[memory reservations]    // 格式为: /memreserve/ <address> <length>;
/ {
    [property definitions]
    [child nodes]
};

(1)默认属性

板子的属性:

#address-cells   // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)
compatible       // 定义一系列的字符串, 用来指定内核中哪个 machine_desc 可以支持本设备,即这个板子兼容哪些平台                  
model            // 这个板子是什么,比如有2款板子配置基本一致, 它们的compatible是一样的,那么就通过model来分辨这2款板子

(2)/memory节点

device_type = "memory";
reg             // 用来指定内存的地址、大小

(3)/chosen节点

bootargs        // 内核 command line参数,跟u-boot中设置的bootargs作用一样

(4)/cpus节点

/cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu,所以 /cpus 中有以下2个属性:

#address-cells   // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size),必须设置为0
节点名

每个节点名只要是长度不超过31个字符的ASCII字符串,此外Linux中约定设备名称应写成<name>[@<unit_address>]的形式,其中name就是设备名,最长可以是31个字符长度。unit_address一般是设备地址,用来唯一标识一个节点,下面就是典型节点名的写法

firmware@0203F000{
		compatible = "samsung,secure-firmware";
		reg = <0x0203F000 0x1000>
}
引用

当我们找一个节点的时候,我们必须书写完整的节点路径,这样当一个节点嵌套比较深的时候就不是很方便,所以,设备树有两种方式给节点标注引用,就是起别名。

(1)通过phandle来引用,其取值必须是唯一的,例子:

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

(2)通过label来引用

PIC: pic@10000000 {
    interrupt-controller;
};

another-device-node {
    /*
     * 使用label来引用上述节点,使用lable时实际上也是使用phandle来引用,
     * 在编译dts文件为dtb文件时,编译器dtc会在dtb中插入phandle属性。
    */
    interrupt-parent = <&PIC>;   
};
键值对

在设备树中,键值对是描述属性的方式。Linux设备树语法中定义了一些有规范意义的属性,包括compatible、address、interrupt等。

compatible

“compatible”表示“兼容”,对于某个 LED,内核中可能有 A、B、C 三个驱
动都支持它,那可以这样写:

led {
compatible = “A”, “B”, “C”;
};

内核启动时,就会为这个 LED 按这样的优先顺序为它找到驱动程序:A、B、C。
根节点下也有 compatible 属性,用来选择哪一个“machine desc”:一个
内核可以支持 machine A,也支持 machine B,内核启动后会根据根节点的
compatible 属性找到对应的 machine desc 结构体,执行其中的初始化函数。

address

(几乎)所有的设备都需要与CPU的IO口相连,所以其IO端口信息就需要在设备节点节点中说明。常用的属性有

  • #address-cells,用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量,
  • #size-cells,用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量。
/*解析成平台设备的设备名字为"30000000.memory",设备树中的路径名是"/memory@30000000"*/
    memory@30000000 {
        /*内存的device_type是约定好的,必须写为"memory"*/
        device_type = "memory";
        /*
         * 表示一段内存,起始地址是0x30000000,大小是0x4000000字节。
         * 若是reg=<0x30000000 0x4000000 0 4096> 则表示两段内存,另一段的
         * 起始地址是0,大小是4096字节。解析成这样的结果的原因是上面指定了
         * address-cells和size-cells都为1.
         */
        reg =  <0x30000000 0x4000000>;
        
        /*解析成平台设备的设备名字为"38000000.trunk",设备树中的路径名是"/memory@30000000/trunk@38000000"*/
        trunk@38000000 {
            device_type = "memory_1";
            reg =  <0x38000000 0x4000000>;
        };
    };
interrupts

一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有

  • interrupt-controller 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。
  • #interrupt-cells,是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述子节点中"interrupts"属性使用了父节点中的interrupts属性的具体的哪个值。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式>。触发方式如下几种:
bits[3:0] 用来表示中断触发类型(trigger type and level flags):
1 = low-to-high edge triggered,上升沿触发
2 = high-to-low edge triggered,下降沿触发
4 = active high level-sensitive,高电平触发
8 = active low level-sensitive,低电平触发
  • interrupt-parent,标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的
  • interrupts,一个中断标识符列表,表示每一个中断输出信号
ethernet@5000000 {
	compatible = "davicom , dm9000" ;
	reg = <ox05000000 0×2 0x05000004 0x2>;
	interrupt-parent = <&gpx0>;
	interrupts = <64>;

ethernet@5000000节点的interrupt-parent是gpx0,gpx0节点的属性如下所示:

gpx0:gpx0 {
	gpio-controller;
	#gpio-cells = <2>;
	
	interrupt-controller;
	interrupt-parent = <&gic>;
	interrupts = <0 16 0>,<0 17 0>,<0 18 0>,<0 19 0>,
				 <0 20 0>,<0 21 0>, <0 22 0>,<0 23 0> ;
	#interrupt-cells = <2>;
};

在gpx0节点中,指定了"#interrupt-cells = <2>;",所以在ethernet@5000000节点中的属性"interrupts = <6 4>;"表示ethernet@5000000的中断在作为irq parant的gpx0中的中断偏移量,即gpx0中的属性"interrupts"中的"<0 22 0>",中断方式为高电平触发。

gpio

gpio也是最常见的IO口,常用的属性有

  • "gpio-controller",用来说明该节点描述的是一个gpio控制器
  • "#gpio-cells",用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式>

以下设备树表示foo_device节点使用了gpio组的第15个引脚,工作模式为高电平有效

foo_device {
	compatible = "acme,foo";
	...
	led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
 				<&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
 				<&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
3、内核对设备树的处理过程

从源代码文件 dts 文件开始,设备树的处理过程为:

1、dts在PC机上被编译为dtb文件

2、u-boot把dtb文件传给内核

3、内核解析dtb文件,把每一个节点都转换为device_node结构体

4、对于某些device_node结构体,会被转换为platform_device结构体

platform_device和plateform_driver如何进行配对

这两个结构体通过plateform_match函数进行匹配,函数定义如下:

1、首先比较:是否强制选择某个driver

比较platform_device.driver_overrideplatform_driver.driver.name
可以设置 platform_devicedriver_override,强制选择某个 platform_driver

2、然后比较:设备树信息

比较:platform_device.dev.of_nodeplatform_driver.driver.of_match_table

of_match_tablestruct device_driver的成员 const struct of_device_id *of_match_table,定义如下:

struct of_device_id {
    char    name[32];
    char    type[32];
    char    compatible[128];
    const void *data;
};

​ 通过设备树的compatible属性的匹配的规则就是:如果compatible属性不存在,就匹配type和name,但是权重极低。若是compatible属性存在,但是匹配补上就立即返回,不在进行后续的匹配。

3、如果平台驱动端提供了 pdrv->id_table,则使用平台设备的名字与平台驱动 id_table 列表中的名字进行匹配

4、最后直接匹配平台设备的名字和平台驱动的名字

标签:compatible,interrupt,Linux,device,设备,节点,属性
From: https://www.cnblogs.com/mjyrise/p/17919978.html

相关文章

  • Linux磁盘
    磁盘操作分区状态查询lsblk(listblockdevice)列出所有储存设备的意思[root@localhostdev]#lsblkNAMEMAJ:MINRMSIZEROTYPEMOUNTPOINTsda8:0080G0disk├─sda18:10300M0part/boot├─sda28:203.9G0part[SWAP]......
  • linux 的别名功能alias
    环境centos7.9介绍Alias是Linux系统中一个非常有用的命令,它可以为常用的命令或复杂的命令序列创建别名。通过使用alias,我们可以简化命令的输入,提高工作效率。使用在~/.bashrc或~/.bash_profile文件中添加以下新行,保存后source下查看当前已设置的别名alias设置单个命令......
  • Capture a TCP dump from a Linux node in an AKS cluster
    https://learn.microsoft.com/en-us/troubleshoot/azure/azure-kubernetes/capture-tcp-dump-linux-node-akshttps://learn.microsoft.com/en-us/azure/aks/node-access#create-an-interactive-shell-connection-to-a-linux-nodekubectlgetnodes-owidekubectldebugno......
  • protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aar
    protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aarch64版本文章目录protobuf、protobuf-c、protobuf-c-rpc在Linux(Ubuntu18.04)编译安装及交叉编译arm\aarch64版本一、前言二、protobuf、rpc、protobuf-c、protobuf-c-rpc介绍1、protobuf2、protob......
  • linux 安装 redis
    一、通用方式要在Linux上安装Redis,可以按照以下步骤进行操作:1.打开终端,使用以下命令下载Redis的压缩包: wgethttp://download.redis.io/releases/redis-x.x.x.tar.gz注意将"x.x.x"替换为你想要下载的Redis版本号。2.解压下载的压缩包:tarxzfredis-x.x.x.tar.gz进入......
  • 记录 | linux安装onnx2trt
    linux安装onnx2trt的方法#下载gitclone--recursivehttps://github.com/onnx/onnx-tensorrt.git#查看分支gittag#切换分支,与tensorRT版本一致gitcheckoutrelease/8.2-GA#或者直接下载https://codeload.github.com/onnx/onnx-tensorrt/zip/refs/heads/8.2-G......
  • 一文聊透 Linux 缺页异常的处理 —— 图解 Page Faults
    本文基于内核5.4版本源码讨论在前面两篇介绍mmap的文章中,笔者分别从原理角度以及源码实现角度带着大家深入到内核世界深度揭秘了mmap内存映射的本质。从整个mmap映射的过程可以看出,内核只是在进程的虚拟地址空间中寻找出一段空闲的虚拟内存区域vma然后分配给本次映射......
  • java基础之“获取系统类型,区分Windows和Linux系统”
    一、获取系统类型,区分Windows和Linux系统//判断是否是windows系统System.getProperties().getProperty("os.name").contains("Windows") 二、案例@TestpublicvoidtestWindows(){Stringproperty=System.getProperties().getProperty("os.name");......
  • vmware虚拟机 linux 本地yum源,网卡配置ens33,防火墙selinux
    1、挂载镜像文件,CentOS-7-x86_64-DVD-1804.iso,并且要处于连接状态#光盘挂载至/mntmount/dev/sr0/mnt#备份yum源文件cd/etc/yum.repos.d/mkdir-p./bakmvCentOS*./bak#编缉本地源vimlocal.repo[centos7]name=CentOS7baseurl=file:///mntenable=1gpgcheck=0 关闭防......
  • Linux环境离线安装Docker&Docker镜像部署
    引子相信很多同学在项目上线的时候都会遇到没有网络的情况。一般而言,我们都会想到使用Docker镜像部署,让我们看看搜索引擎给出来Docker的优势吧(如下图)。那么,问题来了,本身部署环境都没有网络,怎么离线安装Docker呢?怎么使用Docker镜像部署项目?OK,让我们开始吧。一、CenterOS7.0......