• Linux设备树详细学习笔记


    参考文献

    参考视频
    开发板及程序 原子mini
    设备树官方文档

    设备树的基本概念

    DT:Device Tree //设备树
    FDT: Flattened Device Tree //开放设备树,起源于OpenFirmware (所以后续会见到很多OF开头函数)
    dts: device tree source的缩写 //设备树源码
    dtsi: device tree source include的缩写 //通用的设备树源码<5>dtb: device tree blob的缩写//编译设备树源码得到的文件
    dtc: device tree compiler的缩写 //设备树编译器

    设备树编译

    dis和dtsi文件通过dtc编译器,生成dtb设备树二进制文件。
    在这里插入图片描述
    DTC编译器在内核源码:

    alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ find -name dtc.c./drivers/scsi/dtc.c
    ./scripts/dtc/dtc.c
    alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ cd ./scripts/dtc/dtc.c
    bash: cd: ./scripts/dtc/dtc.c: Not a directory
    alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ cd ./scripts/dtcalientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7/scripts/dtc$ ls
    checks.c                  dtc-parser.tab.h          Makefile
    checks.o                  dtc-parser.tab.h_shipped  Makefile.dtc
    data.c                    dtc-parser.tab.o          modules.order
    data.o                    dtc-parser.y              srcpos.c
    dtc                       fdtdump.c                 srcpos.h
    dtc.c                     fdtget.c                  srcpos.o
    dtc.h                     fdtput.c                  treesource.c
    dtc-lexer.l               flattree.c                treesource.o
    dtc-lexer.lex.c           flattree.o                update-dtc-source.sh
    dtc-lexer.lex.c_shipped   fstree.c                  util.c
    dtc-lexer.lex.o           fstree.o                  util.h
    dtc.o                     libfdt                    util.o
    dtc-parser.tab.c          livetree.c                version_gen.h
    dtc-parser.tab.c_shipped  livetree.o
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    编译内核时候,会同步编译dtc。
    指令格式 dtc [-I input-format] [-O output-format][-o output-filename] [-V output_version] input_filename
    编译设备树:dtc -I dts -O dtb -o xxx.dtb xxx.dts
    反编译设备树:dtc -I dtb -O dts -o xxx.dts xxx.dtb
    简单写一个dts

    /dts-v1/;
    / {
    
    };
    
    • 1
    • 2
    • 3
    • 4

    编译与反编译
    在这里插入图片描述
    在Linux根目录下,用make dtbs 可以编译所有设备树。
    arch/arm/boot/dts/Makefile,通过比配置,控制编译那些设备树

    dtb-$(CONFIG_SOC_IMX6UL) += \
    	imx6ul-14x14-ddr3-arm2.dtb \
    	imx6ul-14x14-ddr3-arm2-emmc.dtb	\
    .........
    	imx6ul-9x9-evk-csi.dtb \
    	imx6ul-9x9-evk-ldo.dtb
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    语法

    头文件

    和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi,也可以引用 C 语言中的.h 文件,甚至也可以引用.dts 文件,例如

    #include 
    #include "xxxxx.dtsi"
    
    • 1
    • 2

    一般.dtsi 描述板级信息(也就是开发板上有哪些 IIC 设备、SPI 设备等,由芯片厂提供),.dts 描述 SOC 级信息(各个外设控制器信息、那个iic上挂哪个传感器等),这样写的好处是,将芯片平台与下游odm分开,通过dts拓展原始基础dtsi。

    节点

    根节点是设备树必须要包含的节点。根节点的名字是/。
    子节点格式为

    [label:]node-name[@unit-address]{
    	[properties definitions]
    	[child nodes]
    };
    举例:
    node1{//子节点,节点名称为node1
    	node1_child{//子子节点,节点名称为node1_child
    	}}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    同级节点下节点名称不能相同,不通级节点名称可以相同。
    label 标签:引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点。
    node-name名称:必须要有。
    unit-address:设备地址,这里的设备地址没有实际用处,只是为了代码可读性的要求。

    特殊节点

    • aliases
      特殊节点aliases用来定义别名。定义别名的目的就是为了方便引用节点。当然,除了使用aliases来命名别用,也可以在对节点命名的适合添加标签来命名别名。
    举例:
    aliases(
    	mmc0= &sdmmc0
    	mmc1 = &sdmmc1:
    	mmc2 = &sdhci:
    	serial0="/simple@fe000000/serial@llc500”
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • choosen
      chosen节点用来uboot给内核传递参数。重点是bootargs参数。chosen节点必须是根节点的子节点。举例:
    chosen{
    	bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"
    }
    
    • 1
    • 2
    • 3

    属性

    • compatible:“兼容性”属性,该属性的值是一个字符串列表,compatible属性用于将设备和驱动绑定起来属性的值格式:“manufacturer,model”
      其中,manufacturer 表示厂商,model 一般是模块对应的驱动名字;如果该属性为字符串列表,则先使用第一个兼容值在 Linux
      内核里面查找,没找到的话再使用第二个兼容值查找 |
    • model:描述设备模块信息,一般为名字,例如:model = “wm8960-audio”;
    • status:字符串,设备的状态信息,包括:“okay”、“disabled”、“fail”、“fail-xxx”(各种错误信息)
    • #addresscells 和#size-cells:无符号 32 位整型,用于描述子节点的地址信息#address-cells决定了子节点 reg
      属性中地址信息所占用的字长,#size-cells决定了长度信息所占用的字长。
    • reg:寄存器信息,
      例如:父节点#address-cells值为1,#size-cells值为1,则子节点中reg的值就是一个首地址加一个地址长度为一个单元,子节点可以reg=<0x100000000 0x0100 0x200000000 0x0100>;父节点#address-cells值为1,#size-cells值为0,则子节点中reg的值就是一个首地址加一个地址长度为一个单元,子节点可以reg=<0x100000000 0x200000000>;
    • ranges 属性:是一个地址映射/转换表,它可以为空,即“ranges;”,为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。
      不为空时,格式:child-bus-address,parent-bus-address,length;
      child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长。
      parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长。
      length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。
    • device_type:在某些设备树文件中,可以看到device_type属性,device_type属性的值是字符串,只用于cpu节点或者memory节点进行描述。
    • 自定义:自由发挥

    节点含义

    如果包含gpio-controller,该节点就是gpio控制器;
    如果包含interrupt-controller,该节点就是gpio控制器;

    引用

    interrunt-parent=<&gpio0>;
    
    • 1

    追加内容

    向节点追加内容,相当于硬件上,在soc厂商的基础上,添加字节的硬件。比如,要在iic总线上挂载一个六轴设备,soc厂商可能给一个例程,也可能不给,就要自己修改和添加。
    比如dtsi中:

    i2c1: i2c@021a0000 {
    	#address-cells = <1>;
    	#size-cells = <0>;
    	compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
    	reg = <0x021a0000 0x4000>;
    	interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
    	clocks = <&clks IMX6UL_CLK_I2C1>;
    	status = "disabled";
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以直接在dtsi中加,但是代码复用性就降低了。在dts中追加:

    &i2c1 {
    	clock-frequency = <100000>;
    	pinctrl-names = "default";
    	pinctrl-0 = <&pinctrl_i2c1>;
    	status = "okay";
    
    	mag3110@0e {
    		compatible = "fsl,mag3110";
    		reg = <0x0e>;
    		position = <2>;
    	};
    
    	ap3216c@1e {
    		compatible = "ap3216c";
    		reg = <0x1e>;
    	};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里就追加了几个属性和两个子节点。
    其中,status属性进行了改写,属性名形同时,追加的值会覆盖原有的值。

    实例分析

    中断

    在中断控制器中,必须有一个属性#interrupt-cells,表示其他节点如果使用这个中断控制器需要几个cell来表示使用哪一个中断。
    在中断控制器中,必须有一个属性interrupt-controller,表示他是中断控制器。
    在设备树中使用中断,需要使用属性interrupt-parent=<&XXXX>表是中断信号链接的是哪个中断控制器。接着使用interrupts属性来表示中断引脚和触发方式。
    注: interrupt里有几个cell,是由interrupt-parent对应的中断控制器里面的#interrupt-cells属性决定。

    //原厂BSP工程师编写
    gpio1: gpio@209c000{
    	compatible = "fsl,imx6ul-gpio""fsl,imx35-gpio";
    	reg = <0x0209c000 0x4000>;
    	interrupts = <GIC_SPI 66 IROTYPE LEVEL HIGH>,<GIC SPI 67 IRO TYPE LEVEL HIGH>;
    	gpio-controller;//该节点可以是gpio控制器
    	#gpio-cells = <2>;
    	interrupt-controller;//该节点也可以是中断控制器
    	#interrupt-cells = <2>;//引用该节点的节点中,interrupt-controller属性中数据的个数
    }
    
    //开发人员编写
    edt-ft5x06g38{
    	compatible = "edt,edt-ft5x06”,"edt,edt-ft5406","edtedt-ft5306";
    	pinctrl-names = "default";
    	pinctrl-0 = <&ts_int_pin,
    				&ats_reset_pin>;
    	reg = <0X38>;
    	interrupt-parent = <&gpio1>;
    	interrupts = <9 0>;
    	reset-gpios = <&gpio5 9 GPIO ACTIVE_LOW>;//低电平触发
    	irq-gpios = <&gpio1 9 GPIO ACTIVE LOW>;
    	status = "disabled";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    设备树信息读取(of函数)

    设备树被内核解析以后,可以在/proc/device-tree/目录中查看。
    在这里插入图片描述
    设备树机制是源于IEEE 1275 Open Firmware standard规范,相关的代码都是继承下来的,因此内核中设备树相关的函数都是以of开头的。
    位置:include/linux/of.h
    Linux设备树常用的OF函数总结

  • 相关阅读:
    3分钟带你了解前端缓存-HTTP缓存
    AIGC的一些材料
    计算机毕业设计ssm基于JAVAEE的车检预约系统846ks系统+程序+源码+lw+远程部署
    CMT2380F32模块开发5-CLK例程
    FPGA project : dht11 温湿度传感器
    [探索深度学习] 之 神经网络 - 笔记01
    Vue组件的存放目录问题
    yolov8机器视觉-工业质检
    Java Method.invoke()方法具有什么功能
    【萌新向】Sql Server保姆级安装教程-图文详解手把手教你安sql
  • 原文地址:https://blog.csdn.net/renzemingcsdn/article/details/132775807