设备树总结学习
1,设备树常用语法
(1)字符串:
compatible="rockchip,rk3568"
(2)字符串列表:
compatible = "rockchip,rk3568-evb ", "rockchip,rk3568";
(3)32位无符号数:
reg=<0>
(4)数组值:
reg = <address1 length1 address2 length2 address3 length3…………>
举例:
reg = <0x3000 0x20 0xFE00 0x100>;
(5) reg range 范围:
举例:
ranges = <0x0 0xe0000000 0x00100000>;
ranges属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:
child-bus-address: 子总线地址空间的物理地址,由父节点的 #address-cells 确定此物理地址所占用的字长。
parent-bus-address: 父总线地址空间的物理地址,同样由父节点的 #address-cells 确定此物理地址所占用的字长。
length: 子地址空间的长度,由父节点的 #size-cells 确定此地址长度所占用的字长。
(6)reg属性补充:
#address-cells
#size-cells
#address-cells属性值决定了子节点 reg属性中地址信息所占用的字长 (32位 ),#size-cells属性值决定了子节点 reg属性中长度信息所占的字长 (32位 )。
#address-cells和 #size-cells表明了子节点应该如何编写 reg属性值,一般 reg属性
都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度。
举例说明:。
soc {
#address-cells = <2>;
#size-cells = <1>;
serial {
compatible = "xxx";
reg = <0x4600 0x5000 0x100>; /*地址信息是:0x00004600 00005000,长度信息是:0x100*/
};
};
#address-cells属性值为 2#size-cells属性值为 1,
也就是说 子节点的 reg第一位和第二位是起始地址,第三位为长度。
(7)中断:
#interrupt-cells = <3>;
interrupt-cells
的值是一个无符号32位整数,表示构成一个完整中断specifier所需的32位单元的数量。例如,如果 interrupt-cells
的值为1,则每个中断specifier由一个单元组成;如果值为2,则由两个单元组成,以此类推。
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
第一个参数表示是IPI、PPI、SPI、SGI其中的一个。
参数说明:
IPI:inter-processer interrupt 中断号0~15
PPI:per processor interrupts 中断号16~31
SPI:shared processor interrupts 中断号 32 ~32+224
SGI:software generated interrupts (SGI).
第二个参数表示:是第一个参数里面的第几个,所以是SPI里面的一个。
第三个参数表示:中断触发的类型。(上升沿、下降沿等)
#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
其他的interrupt类型举例,#interrupt-cells
是中断控制器中的属性。
interrupt-parent = <&gpio4>;
interrupts = <34 0>;
参数说明:
中断控制器是GPIO4,然后使用它的34号中断。(这里的34号,就是指34号引脚),0是指触发的方式(上升沿、下降沿等) .
“interrupt-controller”属性用来声明当前node为中断控制器。
中断映射
interrupt-map = <
/* physical address range */ /* interrupt specifier */
0x0 0 0 0x1 0x2 /* example mapping */
0x1 0 0 0x1 0x3 /* another mapping */
/* ... more mappings ... */
>;
“interrupt-map”属性用来描述interrupt nexus设备对中断的路由。解析格式为5个元素序列:
- child unit address:被映射的子节点的单元地址。该属性的cells长度由其所在的总线节点的#address-cells属性描述。
- child interrupt specifier:被映射的子节点的中断说明符。该节点所需的单元数由#interrupt-cells属性(包含中断映射属性的关系节点)指定。
- interrupt-parent:单个值指向子域要映射到的父中断。
- parent unit address:父中断域中的单元地址。指定此地址所需的单元数由父中断域指向节点的#address-cells属性描述。
- parent interrupt specifier:父域中的中断说明符。所需的单元数由父中断域指向节点的#interrupt-cells属性描述。
参数说明:
0x0 0 0
:这是第一个映射的物理地址范围。在应用了interrupt-map-mask
后,这个地址范围对应于某个具体的设备或设备区域。0x1 0x2
:这是与上述物理地址范围相关联的中断specifier。0x1
可能是中断域标识符,而0x2
是中断号。0x1 0 0
:这是第二个映射的物理地址范围。0x1 0x3
:这是与第二个物理地址范围相关联的中断specifier。0x1
可能是相同的中断域标识符,而0x3
是另一个中断号。
(8)时钟:
clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>;
2,gpio设备树分析
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#gpio-cells = <2>;
#gpio-cells = <2>;
表示每个 GPIO 的定义需要两个 <cell>
:
- 第一个
<cell>
是 GPIO 的编号。 - 第二个
<cell>
是 GPIO 的配置信息。
gpio-ranges
属性包含四个值:
- 第一个值是引用父节点的phandle(在这个例子中是
&princtrl
)。 - 第二个值是GPIO控制器内部的一个偏移量,表示GPIO引脚范围的起始点。
- 第三个值是GPIO控制器在系统中的起始GPIO编号。
- 第四个值是GPIO控制器管理的GPIO引脚数量。
3,printctl设备树分析
(1)PinCtrl子系统的工作内容如下:
获取设备树中 pin信息。
根据获取到的 pin信息来设置 pin的复用功能
根据获取到的 pin信息来设置 pin的电气特性, 如驱动能力。
(2) 当前GPIO控制器的0号引脚, 对应pinctrlA中的32号引脚, 数量为32。
引脚复用设置的格式如下:
rockchip,pins = <PIN_BANK PIN_BANK_IDX MUX &phandle>
PIN_BANK
:引脚所在的GPIO引脚编号。PIN_BANK_IDX
:引脚在GPIO引脚中的索引。MUX
:引脚的复用功能编号,用于指定引脚的功能。&phandle
:一个指向引脚配置节点的引用,通常这个节点定义了引脚的详细配置,如驱动能力、上下拉电阻、电压等级等。
&pinctrl {
i2c0_pins: i2c0-pins {
rockchip,pins = <1 9 2 &pcfg_pull_up>; /* I2C0 SDA */
rockchip,pins = <1 10 2 &pcfg_pull_up>; /* I2C0 SCL */
};
spi0_pins: spi0-pins {
rockchip,pins = <1 4 3 &pcfg_pull_none>; /* SPI0 CS */
rockchip,pins = <1 5 3 &pcfg_pull_none>; /* SPI0 CLK */
rockchip,pins = <1 6 3 &pcfg_pull_none>; /* SPI0 MISO */
rockchip,pins = <1 7 3 &pcfg_pull_none>; /* SPI0 MOSI */
};
};
寄存器说明:
#ifndef __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
#define __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
#define RK_GPIO0 0
#define RK_GPIO1 1
#define RK_GPIO2 2
#define RK_GPIO3 3
#define RK_GPIO4 4
#define RK_GPIO6 6
#define RK_PA0 0
#define RK_PA1 1
#define RK_PA2 2
#define RK_PA3 3
#define RK_PA4 4
#define RK_PA5 5
#define RK_PA6 6
#define RK_PA7 7
#define RK_PB0 8
#define RK_PB1 9
#define RK_PB2 10
#define RK_PB3 11
#define RK_PB4 12
#define RK_PB5 13
#define RK_PB6 14
#define RK_PB7 15
#define RK_PC0 16
#define RK_PC1 17
#define RK_PC2 18
#define RK_PC3 19
#define RK_PC4 20
#define RK_PC5 21
#define RK_PC6 22
#define RK_PC7 23
#define RK_PD0 24
#define RK_PD1 25
#define RK_PD2 26
#define RK_PD3 27
#define RK_PD4 28
#define RK_PD5 29
#define RK_PD6 30
#define RK_PD7 31
#endif
功能函数说明,查看手册。
#define RK_FUNC_GPIO 0
#define RK_FUNC_0 0
#define RK_FUNC_1 1
#define RK_FUNC_2 2
#define RK_FUNC_3 3
#define RK_FUNC_4 4
#define RK_FUNC_5 5
#define RK_FUNC_6 6
#define RK_FUNC_7 7
#define RK_FUNC_8 8
#define RK_FUNC_9 9
#define RK_FUNC_10 10
#define RK_FUNC_11 11
#define RK_FUNC_12 12
#define RK_FUNC_13 13
#define RK_FUNC_14 14
#define RK_FUNC_15 15
查看上面的表,对比 数据手册
PIN | PIN Name | Func1 | Func2 | Func3 | Func4 | Func5 | Func6 | Die Power Domain |
AF24 | I2C0_SCL/GPIO0_B1_u | GPIO0_B1_u | I2C0_SCL | |||
AB21 | I2C0_SDA/GPIO0_B2_u | GPIO0_B2_u | I2C0_SDA | |||
AG24 | I2C1_SCL/CAN0_TX_M0/PCIE30X1_BUTTONRSTn/MCU_JTAG_TDO/GPIO0_B3_u | GPIO0_B3_u | I2C1_SCL | CAN0_TX_M0 | PCIE30X1_BUTTONR STn | MCU_JTAG_TDO |
AB20 | I2C1_SDA/CAN0_RX_M0/PCIE20_BUTTONRSTn/MCU_JTAG_TCK/GPIO0_B4_u | GPIO0_B4_u | I2C1_SDA | CAN0_RX_M0 | PCIE20_BUTTONRST n | MCU_JTAG_TCK |
AC22 | I2C2_SCL_M0/SPI0_CLK_M0/PCIE20_WAKEn_M0/PWM1_M1/GPIO0_B5_u | GPIO0_B5_u | I2C2_SCL_M0 | SPI0_CLK_M0 | PCIE20_WAKEn_M0 | PWM1_M1 |
AA20 | I2C2_SDA_M0/SPI0_MOSI_M0/PCIE20_PERSTn_M0/PWM2_M1/GPIO0_B6_u | GPIO0_B6_u | I2C2_SDA_M0 | SPI0_MOSI_M0 | PCIE20_PERSTn_M0 | PWM2_M1 |
AH26 | PWM0_M0/CPUAVS/GPIO0_B7_d | GPIO0_B7_d |
iic0的时钟线和数据线使用的是GPIO0_B1和GPIO0_B2
GPIO0_B1:
#define RK_GPIO0 0
#define RK_PB1 9
#define RK_FUNC_2 2
GPIO0_B2:
#define RK_GPIO0 0
#define RK_PB2 10
#define RK_FUNC_2 2
4,设备树匹配
设备树的比较的优先顺序:
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
有一个成功, 即匹配成功。
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
/* 针对特殊情况,dev中的driver_override被设置,则只匹配和driver_override名字相同的驱动程序 */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
/* Attempt an OF style match first,设备树方式匹配 */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI style match */
/* 高级配置和电源管理之类的匹配,这里不是我们这次的重点 */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
/* 有驱动中有id_table,则dev中的名字和任何一个id_table里面的值匹配就认为匹配 */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
/* 驱动和设备的名字匹配 */
return (strcmp(pdev->name, drv->name) == 0);
}