【ARM】内核驱动之设备树的学习-长文

news2024/11/18 15:41:13

❤️作者主页:凉开水白菜
❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步!
❤️点赞 👍 收藏 ⭐再看,养成习惯

订阅的粉丝可通过PC端文末加我微信,可对文章的内容进行一对一答疑!


文章目录

  • 一、什么是设备树,为什么叫设备树?
  • 二、如何编译设备树?
  • 三、设备树基本语法
    • 3.1 根节点
    • 3.2 子节点
    • 3.3 节点名称规则
  • 四、设备树基本语法与属性
    • 4.1 reg属性
    • 4.2 #address-cells和#size-cells属性
    • 4.3 model属性
    • 4.4 status属性
    • 4.5 phandle属性
    • 4.6 compatible属性
    • 4.7 virtual-reg
  • 五、设备树特殊节点
    • 5.1 aliases 批量取别名属性
    • 5.2 chosen节点
    • 5.3 memory设备节点
    • 5.4 device_type属性
    • 5.5 自定义属性
    • 5.6 ranges属性
    • 5.7 .dtsi头文件
    • 5.8 向设备树结点追加数据,&label
  • 六、中断节点
    • 6.1 #interrupt-cells 、interrupt-parent 、interrupts
    • 6.2 RK瑞星微
    • 6.3 imx恩智浦
    • 6.4 三星平台
    • 6.5 全志平台
    • 6.6 其他写法:引用父节点属性
    • 6.7 其他写法:级联中断控制器
    • 6.8 其他写法:使用多个中断控制器
    • 6.9 总结
  • 七、时钟节点
    • 7.1 生产者属性
      • 7.1.1 #clock-cells
      • 7.1.2 clock-output-names
      • 7.1.3 clock-frequency
      • 7.1.4 assigned-clocks和assigned-clock-rates
      • 7.1.5 clock-indices
      • 7.1.6 assigned-clock-parents
    • 7.2 消费者属性
      • 7.2.1 clocks和clock-names
  • 八、 CPU节点
    • 8.1 cpus节点
    • 8.2 cpu-map节点
    • 8.3 socket节点
    • 8.4 core节点
    • 8.5 thread节点
    • 8.6 示例分析
  • 九、GPIO节点
    • 9.1 gpio-controller、#gpio-cells
    • 9.2 gpio-ranges
  • 十、Pinctrl子系统
    • 10.1 pinctrl-names
    • 10.2 pinctrl-N
    • 10.3 全志平台
    • 10.4 IMX平台
    • 10.5 三星平台
    • 10.6 RK平台
    • 10.7 总结
  • 十一、dtb文件
  • 十二、device\_node*转化为*platform\_device
    • 12.1 转换条件
    • 12.2 代码示例
  • 十三、设备树下platform\_device与platform\_driver匹配
  • 十四、设备树常用of函数
    • 14.1查找节点的 OF 函数
      • 14.1.1 of\_find\_node\_by\_name 函数
      • 14.1.2 of\_find\_node\_by\_type 函数
      • 14.1.3 of\_find\_compatible\_node 函数
      • 14.1.4 of\_find\_matching\_node\_and\_match 函数
      • 14.1.5 of\_find\_node\_by\_path 函数
    • 14.2 查找父/子节点的 OF 函数
      • 14.2.1 of\_get\_parent 函数
      • 14.2.2 of\_get\_next\_child
    • 14.3 提取属性值的 OF 函数
      • 14.3.1 of\_find\_property 函数
      • 14.3.2 of\_property\_count\_elems\_of\_size 函数
      • 14.3.3 of\_property\_read\_u32\_index 函数
      • 14.3.4 of\_property\_read\_u32\_array 函数
      • 14.3.5 of\_property\_read\_u32 函数
      • 14.3.6 of\_property\_read\_string 函数
      • 14.3.7 of\_n\_addr\_cells 函数
      • 14.3.8 of\_n\_size\_cells 函数
    • 14.4 中断获取的OF函数
      • 14.4.1 of\_parse\_and\_map函数
    • 14.5 其他常用的 OF 函数
      • 14.5.1 of\_iomap 函数
      • 14.5.2 of\_get\_address 函数
      • 14.5.3 of\_translate\_address 函数
      • 14.5.4 of\_address\_to\_resource 函数
  • 十五、设备树与驱动结合实战
    • 15.1 如何知道我们kernel使用的是那个设备树文件?
    • 15.2 不使用设备树点亮LED
    • 15.3 杂项设备获取设备树属性点亮LED
    • 15.4 platform总线匹配设备树
    • 15.5 获取中断资源并使用pinctrl驱动案件
      • 15.5.1 设备树代码
      • 15.5.2 驱动代码
  • 十六、结尾


一、什么是设备树,为什么叫设备树?

描述硬件得文本文件,因为语法结构像树所以叫设备树

DT:device tree:设备树(arm下表示)
FDT: flattened device tree:开放设备树、扁平设备树(powerpc使用的设备树,起源的设备又称openFirmware)因为源于openFirmware所以设备树很多函数带有of字词
dts:device tree source : 设备树源码
dtsi: device tree source include:通用设备树源码
dtb:device tree blob:编译设备树源码得到得文件,镜像文件
dtc:device tree compiler:设备树编译器

在这里插入图片描述
通过DTC编译dts、dtsi文件编译出dtb文件
所有的设备树文件都存在与下面的路径

// arm32位架构设备树源码位置
板子kernel/arch/arm/boot/dts
// arm64位架构设备树源码位置
板子kernel/arch/arm64/boot/dts/品牌/

二、如何编译设备树?

DTC编译器的源码路径,dtc文件夹下面的dtc执行文件就是我们的设备树编译器(要保证源码已经编译过一次)
如果编译完成还是没有可能是内核版本太低没有引进设备树,或者是配置选项未勾选,可以在.confg文件中查看该选项

在这里插入图片描述

板子kernel/scripts/dtc

最简单的设备树源码

/dts-v1/;
/ {
   

};

编译器编译指令

编译设备树:dtc -I dts -0 dtb -o xxx.dtb xxx.dts
反编译设备树: dtc -I dtb -0 dts -o xxx.dts xxx.dtb

/home/book/licheepi/kernel/scripts/dtc/dtc需要根据我们内核实际路径来找

编译
/home/book/licheepi/kernel/scripts/dtc/dtc -I dts -O dtb -o test.dtb test.dts
反编译
/home/book/licheepi/kernel/scripts/dtc/dtc -I dtb -O dts -o test.dts test.dtb

遇到错误:

Error: test.dts:1.1-2 syntax error
FATAL ERROR: Unable to parse input tree

语法错误如果把/dts-v1/;设备树版本写错或者不写就会出现该问题

编译设备树第二种方法是在内核路径下执行ARCH是指定arm位数,CROSS_COMPILE指定交叉编译器

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs

此时编译的是“板子kernel/arch/arm/boot/dts”该路径下的设备树文件,在该路径编译可能会出现错误,因为他编译的是所有的设备树文件

三、设备树基本语法

3.1 根节点

设备树的组成是一棵树,而根节点是树干,是必须存在树的组成还有子节点和子子节点组成

/dts-v1/;
/ {
   

};

3.2 子节点

以上为根节点为固定格式,下面是子节点格式

[lable:]node-name[@unit-address]{
   
     [properties definitions]
     [child nodes]   
};
// 需要注意在统一级节点名称节点名称不能相同不同级节点名称可以相同
// 子节点不能与子节点名称重复,但子子节点可以和子节点相同
// 例如子节点为node1 子子节点也可以有node1但子节点不能再有一个node1

举例

/dts-v1/;

/ {
   
    node1{
   //子节点,子节点名称为node1
        node1_child{
   //子节点的子节点,节点名称为node1_child   
         
        };
    };
    node2{
   
        node1_child{
    
         
        };
    };
};

3.3 节点名称规则

对于节点名称,在对节点进行命名的时候一般要体现设备的类型,比如网口一般命名为ethernet,串口一般命名为uart,对于名称一般要遵循下面的命令格式。

[标签]:<名称>[@<设备地址>]

其中,[标签]和[@<设备地址>]是可选项,<名称>是必选项。另外,这里的<设备地址>没有实际意义,只是让节点名称更加人性化,更方便阅读使用

例如

uart: serial@02288000

其中uart就是这个节点标签也叫别名,serial@2288000就是节点名称

这里如果子节点内容为空编译会产生警告,这个reg属性后面会讲到

test.dtb:警告(unit_address_vs_reg):节点/gpio@02288000有单元名称,但没有reg属性
test.dtb:警告(unit_address_format):节点/gpio@02288000单元名称不应以0开头

在设备树中命名使用字符或数字需要根据以下表格约束,如同C语言中的变量命名规则不能使用某某符号不能数字开头
在这里插入图片描述

四、设备树基本语法与属性

4.1 reg属性

reg属性可以用来描述地址信息,比如寄存器地址,我们的内核驱动也是通过这些属性来获取信息的,reg属性的格式如下:

reg = <address1 length1 address2 length 2 address 3 length3....>

例如

reg = <0x2200000 0x4000>
// 寄存器的起始地址0x2200000 寄存器的长度为0x4000

reg = <0x02200000 0x4000
    0x2205000 0x4000
>

4.2 #address-cells和#size-cells属性

#address-cells和#size-cells用来描述子节点中的reg信息中的地址和长度信息,他们决定了用多少个 32 位的数来表示 address 和 size,需要注意如果是在根节点中插入此属性需要位于子节点之前

例如

node1{
   
    #address-cells=<1>; //地址信息只能有一个u32记录
    #size-cells=<0>; // 长度信息为0也就是没有长度
    node1-child{
   
        reg=<0>; // 地址为0无长度
    };
};

node1{
   
    #address-cells=<1>; //地址信息只能有一个u32记录
    #size-cells=<1>; // 长度信息一个
    node1-child{
   
        reg=<0x02200000 0x4000>; //存储一个地址和一个长度信息
    };
};

node1{
   
    #address-cells=<2>; //地址信息两个u32
    #size-cells=<0>; // 长度信息无
    node1-child{
   
        reg=<0x02200000 0x02205000>; //存储两个地址
    };
};

如果属性插入在子节点之后会报错

Error: test.dts:22.5-24 Properties must precede subnodes
FATAL ERROR: Unable to parse input tree

4.3 model属性

model属性的值是一个字符串,一般用model描述一些信息,比如设备的名称名字等
例如

model = "lan8720a-eth";
model = "this is eth device";

4.4 status属性

status属性是和设备的状态有关系的,status的属性值是字符串,属性值为下面四个状态中的其中一个表示
在这里插入图片描述

4.5 phandle属性

phandle属性为devicetree中唯一的节点指定一个数字标识符,节点中的phandle属性,它的取值必须是唯一的(不要跟其他的phandle值一样),例如:

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

注:DTS中的大多数设备树将不包含显式的phandle属性,当DTS被编译成二进制DTB格式时,DTC工具会自动插入phandle属性。

4.6 compatible属性

该属性是非常重要的一个属性,compatible是用来和驱动进行匹配的,匹配成功后会执行probe函数,推荐的格式是“制造商,型号”

例如

compatible = "i2c-oled", "i2c-display";

compatible = "fsl,mpc8641", "ns16550";

在匹配的时候会先使用第一个值进行匹配“i2c-oled”,如果没有就使用第二个值进行匹配“i2c-display”。

技巧用法:对于某个 LED,内核中可能有 A、B、C 三个驱动都支持它,那可以这样

led {
   
    compatible = "A", "B", "C";
};

4.7 virtual-reg

虚拟reg属性指定了一个映射到设备节点的reg属性中指定的第一个物理地址的有效地址。此属性使引导程序能够为客户端程序提供已设置的虚拟到物理映射。他的值由一个32位数字组成也就是物理地址

小节示例

/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells=<1>; // 地址信息一个
    #size-cells=<1>; // 长度信息一个

    node1{
   //子节点,子节点名称为node1
    // 这里重新赋予reg属性的address-cells限制和size-cells限制
        #address-cells=<1>; // 地址信息一个
        #size-cells=<0>; // 长度信息0
        node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
    };

    node2{
   
        node1_child{
    
         
        };
    };

    rgb:gpio@2288000{
   
        compatible = "rgb-led";
        // 这里采用根节点赋予的address-cells限制和size-cells限制
        reg = <0x02288000 0x40>;
        status = "okay";
    };
};

表示reg寄存器的值超过了32bit的限制

Error: test.dts:13.20-32 Value out of range for 32-bit array element

节点/node1/node1_child具有reg或range属性,但没有单元名称

test.dtb: Warning (unit_address_vs_reg): Node /node1/node1_child has a reg or ranges property, but no unit name

这个字节点的名称需要根据前面的格式来填写

// 修改前
node1_child{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>; // reg值的大小不能超过32位,否则会产生错误            
        };
//  修改后
node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
// 也可以取个别名,注意别名不能使用-这个字符可以test_node不能test-node
test_node:node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };

五、设备树特殊节点

5.1 aliases 批量取别名属性

特殊节点aliases用来定义别名。定义别名的目的就是为了方便引用节点,当然除了使用aliases来命名别名也可以在对节点命名的时候添加标签来命名别名
例如

aliases{
   
    mmc0 = &sdmmc0;
    mmc1 = &sdmmc1;
    mmc2 = &sdhc1;
    serial0 = "/simple@fe000000/serial@11c500";
};

示例

/home/book/licheepi/kernel/scripts/dtc/dtc -I dts -O dtb -o test.dtb test.dts
/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells=<1>; // 地址信息一个
    #size-cells=<1>; // 长度信息一个

    aliases{
   
        gpiotest = "/nodel/node1_child@2280000";
        gpiotest1 = "/gpio@2288000";
        gpiotest2 = &test;
    };

    node1{
   //子节点,子节点名称为node1
    // 这里重新赋予reg属性的address-cells限制和size-cells限制
        #address-cells=<1>; // 地址信息一个
        #size-cells=<0>; // 长度信息0
        node1_child@2280000{
   //子节点的子节点,节点名称为node1_child   
            reg = <0x02280000>;
        };
    };

    test:node2{
   
        node1_child{
    
         
        };
    };

    gpio@2288000{
   
        compatible = "rgb-led";
        // 这里采用根节点赋予的address-cells限制和size-cells限制
        reg = <0x02288000 0x40>;
        status = "okay";
    };
};

反编译后得到

/home/book/licheepi/kernel/scripts/dtc/dtc -I dtb -O dts -o test.dts test.dtb
/dts-v1/;

/ {
   
    model = "this is linux board";
    #address-cells = <0x1>;
    #size-cells = <0x1>;

    aliases {
   
        gpiotest = "/nodel/node1_child@2280000";
        gpiotest1 = "/gpio@2288000";
        gpiotest2 = "/node2";
    };

    node1 {
   
        #address-cells = <0x1>;
        #size-cells = <0x0>;

        node1_child@2280000 {
   
            reg = <0x2280000>;
        };
    };

    node2 {
   

        node1_child {
   
        };
    };

    gpio@2288000 {
   
        compatible = "rgb-led";
        reg = <0x2288000 0x40>;
        status = "okay";
    };
};

5.2 chosen节点

chosen节点用来给uboot给内核传递参数,重点是bootargs参数,chose节点必须是根节点的子节点。
例如

chosen{
   
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

5.3 memory设备节点

所有设备树都需要一个memory设备节点,它描述了系统的物理内存布局。如果系统有多个内存块,可以创建多个memory节点,或者可以在单个memory节点的reg属性中指定这些地址范围和内存空间大小。
例如:一个64位的系统有两块内存空间:RAM1:起始地址是0x0,地址空间是 0x80000000;RAM2:起始地址是0x10000000,地址空间也是0x80000000;同时根节点下的 #address-cells = <2>和#size-cells = <2>,这个memory节点描述为:

memory@0 {
   
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000
           0x00000000 0x10000000 0x00000000 0x80000000>;
};

或者:
memory@0 {
   
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
};
memory@10000000 {
   
    device_type = "memory";
    reg = <0x00000000 0x10000000 0x00000000 0x80000000>;
};

这里的#address-cells = <2>所以由两个u32表示一个地址,#size-cells = <2>表示一个reg有两个参数一个地址一个大小,

0x00000000 0x10000000 表示RAM2的起始地址
0x00000000 0x80000000表示地址空间为0x80000000

5.4 device_type属性

device_type 属性值为字符串, IEEE 1275 会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。某些设备树文件中可以看到device_type属性,device_type的值是字符串,只用于cpu节点或者memmory节点进行描述

例如

memory@30000000{
   
    device_type = "memory";
    reg = <0x30000000 0x4000000>;
};

例如2

cpu1: cpu@1{
   
    device_type = "cpu";
    compatible = "arm, cortex-a35", "arm, arnv8";
    reg = <0x0 0x1>;
};

5.5 自定义属性

设备树中规定的属性有时候并不能满足我们的需求,这时候我们可以自定义属性。

例如我们这里自定义一个管脚标号的属性pinnum

pinnum= <0 1 2 3 4 5>;

也就是因为这个特性所以我们在看有些设备树文件的时候经常不能理解有一些节点的意思的原因,从根本来说设备树只是一个文件记录文件,这个记录里面的数据或则说设备怎么去使用要不要使用都需要根据我们的驱动去决定;

5.6 ranges属性

ranges属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

  • child-bus-address:子总线地址空间的物理地址,由父节点的 #address-cells 确定此物理地址所占用的字长。
  • parent-bus-address:父总线地址空间的物理地址,同样由父节点的 #address-cells 确定此物理地址所占用的字长。
  • length:子地址空间的长度,由父节点的 #size-cells 确定此地址长度所占用的字长。
soc {
   
    compatible = "simple-bus";
    #address-cells = <1>;
    #size-cells = <1>;
    ranges = <0x0 0xe0000000 0x00100000>;
    serial {
   
        device_type = "serial";
        compatible = "ns16550";
        reg = <0x4600 0x100>;
        clock-frequency = <0>;
        interrupts = <0xA 0x8>;
        interrupt-parent = <&ipic>;
        };
};

节点 soc 定义的 ranges 属性,值为 <0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000) 的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。

serial 是串口设备节点,
reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。
经过地址转换, serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

5.7 .dtsi头文件

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为 .dtsi;同时也可以像C 语言一样包含 .h头文件;在设备树中包含了一些原厂提供的头文件信息包含其路径在:kernel/scripts/dtc/include-prefixes/dt-bindings或者/kernel/include/dt-bindings他们的内容都是一样的

/include/ "sun8i-v3s.dtsi" // 包含bsp原厂提供的设备树
/include/ "dt-bindings/interrupt-controller/arm-gic.h"

注:.dtsi 文件一般用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。

5.8 向设备树结点追加数据,&label

假设需要往 i2c1 节点中添加 fxls8471 子节点,i2c1 节点是定义在 imx6ull.dtsi 文件中的,如果直接在 i2c1 节点中添加 fxls8471 相当于在其他的所有板子上都添加了 fxls8471 这个设备,其他所有使用到I.MX6ULL这颗 SOC 的板子都会引用 imx6ull.dtsi 这个文件,但是其他的板子可能并没有这个设备!所以这样操作是不行的。
按照以下方式在.dts文件中添加 fxls8471子节点即可:

&i2c1 {
   
   /* 要追加或修改的内容 */
};

通过&label 来访问节点,然后直接在里面编写要追加或者修改的内容,不会对其他使用这颗SOC的板子造成任何影响。

六、中断节点

6.1 #interrupt-cells 、interrupt-parent 、interrupts


#interrupt-cells <2>; //中断有两个值,一般一个值是管脚一个是触发方式

interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;

interrupts第一个参数表示gpio组是gpio0,管脚号为rk_pb5也就是使用gpio0-pb5这个引脚,IRQ_TYPE_LEVEL_LOW低电平触发中断,interrupts有两个值是由#interrupt-cells规定的;

6.2 RK瑞星微

在这里插入图片描述
gpio控制器

gpio-controller;

表示这个gpio的参数有两个

#gpio-cells = <2>

中断控制器

interrupt-controller;

中断有两个值,一般一个值是管脚一个是触发方式

#interrupt-cells <2>;

第一个参数表示gpio组是gpio0,管脚号为rk_pb5也就是使用gpio0-pb5这个引脚,IRQ_TYPE_LEVEL_LOW低电平触发中断,interrupts有两个值是由#interrupt-cells规定的;

interrupt-parent = <&gpio0>;
interrupts = <RK_PB5 IRQ_TYPE_LEVEL_LOW>;

中断触发方式包括:

#define IRQ_TYPE_NONE            0
#define IRQ_TYPE_EDGE_RISING     1
#define IRQ_TYPE_EDGE_FALLING    2
#define IRQ_TYPE_EDGE_BOTH    (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH      4
#define IRQ_TYPE_LEVEL_LOW       8

6.3 imx恩智浦

在这里插入图片描述
一图为BSP原厂编写的节点同样包含gpio控制器(gic控制器)和终端控制器,#interrupt-cells <2>;同样限制为两个参数,interrupt-parent指定了我们使用的gpio组为gpio1,使用的引脚号为9,0一般表示低电平触发;

interrupt-parent = <&gpio1>;
interrupts = <9 0>;

6.4 三星平台

在这里插入图片描述
可以看到原厂编写的子节点只有核心的几个参数和上面俩芯片的内容相同,下方的节点中我们可以看到使用了一个宏定义判断,其实就是判断使用的屏幕类型来实现不同的定义,如果是rgb屏中断引脚为gpioc_26下降沿触发,如果是使用lvds屏幕中断引脚为gpiob_29下降沿触发;

6.5 全志平台

timer@01c20c00 {
   
    compatible = "allwinner,sun4i-a10-timer";
    reg = <0x01c20c00 0xa0>;
    #interrupt-cells = <3>;
    interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&osc24M>;
 };

在上面例子中 interrupts 属性指定了中断控制器、中断号 及 中断触发方式,
GIC 是一个通用中断控制器(Generic Interrupt Controller),SPI 是中断类型,IRQ_TYPE_LEVEL_HIGH 表示中断触发方式。
中断类型包括:
SGI(Software-generated interrupt):范围0 - 15,软件触发的中断,一般用于核间通讯,在内核中通常叫做 IPI (Inter processer interrupt)
PPI(Private processer interrupt): 范围16 - 31,私有外设中断,只对指定的core有效
SPI(Shared processer interrupt):范围32 - 1019,共享中断,不限定特定的core

该控制器的 interrupts 属性之所以有三个参数,是因为 gic 中断控制器中 #interrupt-cells 属性值为 3

6.6 其他写法:引用父节点属性

/ {
   

    interrupt-parent = <&gic>;
    
    gic:interrupt-controller@228000{
   
        compatible = "arm, gic";
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    
    ft5x@38{
   
        compatible = "ft5x06";
        interrupt = <26 0>;
    };

在这段描述中可以看到我们的ft5x@38节点中和我们之前总结的写法有差别他没有interrupt-parent属性,这是一种特殊的写法,当子节点中没有包含interrupt-parent节点来指定我们的中断控制器的时候就会去父节点中找该属性;

6.7 其他写法:级联中断控制器

 / {
   

    interrupt-parent = <&gic>;
    
    gic:interrupt-controller@228000{
   
        compatible = "arm, gic";
        interrupt-controller;
        #interrupt-cells = <2>;
    };
    
     gic2:interrupt-controller@228200{
   
        compatible = "arm, gic2";
        interrupt-controller;
        #interrupt-cells = <2>;
        interrupt-parent = <&gic>;
     };
    
    ft5x@38{
   
        compatible = "ft5x06";
        interrupt = <26 0>;
    };

可以看到上方描述的有两个gic节点,两个gic都具备 interrupt-controller属性说明他们都是属于中断控制器,但是在gic2节点中interrupt-parent = <&gic>;引用了gic节点,这这种写法表示gic2控制器与gic控制器是属于级联状态;在内核驱动中我们可以通过某一级中断控制器获取另外一级中断控制器这就是级联;

6.8 其他写法:使用多个中断控制器

/ {
   

    gic:interrupt-controller@228000{
   
            compatible = "arm, gic";
            interrupt-controller;
            #interrupt-cells = <2>;</

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/813761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

妙用指针实现qsort

妙用指针实现qsort qsort是什么qsort代码使用例子冒泡排序引言冒泡排序模拟qsort函数 qsort是什么 是一个可以对任意类型进行排序的函数 函数为&#xff1a; void qsort(void *base,size_t nmemb,size_t size,int (*compar)(const void *, const void *));参数解释 参数base …

【数据结构与算法】基数排序

基数排序 基数排序&#xff08;Radix Sort&#xff09;属于“分配式排序”&#xff0c;又称“桶子法”或 bin sort&#xff0c;顾名思义&#xff0c;它是通过键值的各个位的值&#xff0c;将要排序的元素分配至某些“桶”中&#xff0c;达到排序的作用。基数排序法是属于稳定性…

学C的第三十一天【通讯录的实现】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十天【自定义类型&#xff1a;结构体、枚举、联合】_高高的胖子的博客-CSDN博客 通讯录需求&#xff1a; 实现一个通讯录&#xff0c; 通讯录中存放保存人的信息&#xff1…

【WebGL】初探WebGL,我了解到这些

WebGL&#xff08;Web图形库&#xff09;是一种强大的技术&#xff0c;允许您在Web浏览器中直接创建交互式的3D图形和动画。它利用现代图形硬件的能力来呈现令人惊叹的视觉效果&#xff0c;使其成为Web开发人员和计算机图形爱好者必备的技能。 WebGL基础知识 WebGL基于OpenGL …

1.3 eureka+ribbon,完成服务注册与调用,负载均衡源码追踪

本篇继先前发布的1.2 eureka注册中心&#xff0c;完成服务注册的内容。 目录 环境搭建 采用eurekaribbon的方式&#xff0c;对多个user服务发送请求&#xff0c;并实现负载均衡 负载均衡原理 负载均衡源码追踪 负载均衡策略 如何选择负载均衡策略&#xff1f; 饥饿加载…

数据结构07:查找[C++][线性查找]

图源&#xff1a;文心一言 考研笔记整理~&#x1f95d;&#x1f95d; 在数据结构和算法中&#xff0c;查找是一种常见的操作&#xff0c;它的目的是在一个数据集合中找到一个满足条件的元素。本文将介绍三种常用的查找方法&#xff0c;分别是顺序查找、折半查找和分块查找~&a…

61 # http 数据处理

node 中的核心模块 http 可以快速的创建一个 web 服务 const http require("http"); const url require("url");// req > request 客户端的所有信息 // res > respone 可以给客户端写入数据 const server http.createServer();server.on("r…

使用Spring Boot AOP实现日志记录

目录 介绍 1.1 什么是AOP 1.2 AOP体系与概念 AOP简单实现 2.1 新建一个SpringBoot项目&#xff0c;无需选择依赖 2.2 设置好本地Maven配置后&#xff0c;在pom.xml文件里添加添加maven依赖 2.3 创建一个业务类接口 2.4 在实体类实现接口业务 2.5 在单元测试运行结果 …

机器学习--课后作业--hw1

机器学习(课后作业–hw1) 本篇文章全文参考这篇blog 网上找了很多教程&#xff0c;这个是相对来说清楚的&#xff0c;代码可能是一模一样&#xff0c;只是进行了一些微调&#xff0c;但是一定要理解这个模型具体的处理方法&#xff0c;这个模型我认为最巧妙的它对于数据的处理…

【1.4】Java微服务:服务注册和调用(Eureka和Ribbon实现)

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…

小研究 - JVM GC 对 IMS HSS 延迟分析(一)

用户归属服务器&#xff08;IMS HSS&#xff09;是下一代通信网&#xff08;NGN&#xff09;核心网络 IP 多媒体子系统&#xff08;IMS&#xff09;中的主要用户数据库。IMS HSS 中存储用户的配置文件&#xff0c;可执行用户的身份验证和授权&#xff0c;并提供对呼叫控制服务器…

ARTS Activity -- Using Java

About ARTS - Complete one ARTS per week: ● Algorithm: Do at least one LeetCode algorithm per week Review: Read and comment on at least one technical article in English ● Tips: Learn at least one technical trick ● Share: Share a technical article with op…

1.2 eureka注册中心,完成服务注册

目录 环境搭建 搭建eureka服务 导入eureka服务端依赖 编写启动类&#xff0c;添加EnableEurekaServer注解 编写eureka配置文件 启动服务,访问eureka Euraka服务注册 创建了两个子模块 在模块里导入rureka客户端依赖 编写eureka配置文件 添加Services 环境搭建 创建父…

08-向量的范数_范数与正则项的关系

⛳向量的范数 范数的公式是向量每个分量 绝对值 P 次方 再用幂函数计算 P 分之一&#xff0c;这里 P 肯定是整数 1&#xff0c;2&#xff0c;3…到正无穷都是可以的 向量的范数就是把向量变成一个标量&#xff0c;范数的表示就是两个竖线来表示&#xff0c;然后右下角写上 P&a…

LeetCode36.Valid-Sudoku<有效的数独>

题目&#xff1a; 思路&#xff1a; 这题并不难&#xff0c;它类似于N皇后问题。在N皇后问题中&#xff0c;行&#xff0c;列&#xff0c;对角线&#xff0c;写对角线&#xff0c;都不能出现连续的皇后。 本题类似&#xff0c;不过他是行&#xff0c;列&#xff0c;还有一个B…

【数据结构篇C++实现】- 图

友情链接&#xff1a;C/C系列系统学习目录 文章目录 &#x1f680;一、图的基本概念和术语1、有向图和无向图3、基本图和多重图4、完全图5、子图6、连通、连通图和连通分量7、强连通图、强连通分量8、生成树、生成森林9、顶点的度、入度和出度10、边的权和网11、稠密图、稀疏图…

【点云处理教程】00计算机视觉的Open3D简介

一、说明 Open3D 是一个开源库&#xff0c;使开发人员能够处理 3D 数据。它提供了一组用于 3D 数据处理、可视化和机器学习任务的工具。该库支持各种数据格式&#xff0c;例如 .ply、.obj、.stl 和 .xyz&#xff0c;并允许用户创建自定义数据结构并在程序中访问它们。 Open3D 广…

介绍壹牛NFT数字艺术藏品数藏源码

这个版本新增了不少功能&#xff0c;也修复了一些地方。 1.平台新增用户找回密码功能 2.平台新增短信注册&#xff08;实名制功能&#xff09; 3.平台新增主图后台添加功能 4.平台修复相关问题&#xff0c;系统高效运行 5、H5端与APP端在新UI完美适配 6、加入宝盒功能&…

04-导数判断凹(concave)凸(convex)性_导数用于泰勒展开

导数与函数凹凸性的关系 函数的二阶导数是和函数的凹凸性是有关系的&#xff0c;凹凸性怎么定义的&#xff1f; 先来做简单的回顾&#xff0c;更多的会在最优化方法里面给大家讲&#xff0c;这里先记住凸函数是向下凸的&#xff0c; 反正就是凹的&#xff0c;是否是凸函数可以…

Linux——平台设备及其驱动

目录 前言 一、平台设备 二、平台驱动 三、平台驱动简单实例 四、 电源管理 五、udev 和驱动的自动加载 六、使用平台设备的LED 驱动 七、自动创建设备节点 前言 要满足 Linux 设备模型&#xff0c;就必须有总线、设备和驱动。但是有的设备并没有对应的物理总线&#x…