Zephyr Devicetree详解 Devicetree绑定文件语法
Zephyr Devicetree绑定是Zephyr特有的,和其它OS不能通用。Zephyr Devicetree绑定文件的结构也是树形结构,大致如下
# 对绑定文件的描述,可以单行也可以多行
description: |
This is the Vendomatic company's foo-device.
Descriptions which span multiple lines (like this) are OK,
and are encouraged for complex bindings.
See https://yaml-multiline.info/ for formatting help.
# 包含其他绑定文件的定义,促进代码重用
include: other.yaml
# 和节点绑定的compatible
compatible: "manufacturer,foo-device"
properties:
#这里放置此绑定节点需要满足的属性要求和描述
child-binding:
# 可以使用这个关键字来约束匹配此绑定的节点的子节点。
# 使用bus描述节点含有硬件总线,如SoC上的SPI总线控制器
bus: spi
# 使用on-bus描述节点是某种硬件总线上的设备
on-bus: spi
foo-cells:
# 这里放置'foo'领域的"说明符"单元名称
这里的description/include/compatible/properties/child-binding/bus/on-bus/*-cells
都是属于第一级的关键字,这里以这些关键字来展开说明。
description 链接到标题
description* 是节点硬件的自由描述,支持单行或多行,多行的规则参考https://yaml-multiline.info/ 单行示例
# zephyr/dts/bindings/i2c/adi,max32-i2c.yaml
description: ADI MAX32 I2C
多行示例
# zephyr/dts/bindings/timer/st,stm32-lptim.yaml
description: |
STM32 lptim : low power timer
The lptim node to be used for counting ticks during lowpower modes
must be named stm32_lp_tick_source in the DTS, as follows:
stm32_lp_tick_source: &lptim1 {
status = "okay";
}
compatible 链接到标题
compatible 用于将Devicetree内节点与绑定相匹配,通常格式为**compatible** = "manufacturer,device"
,manufacturer 前缀标识设备供应商。供应商前缀的列表,参阅 dts/bindings/vendor-prefixes.txt。 device 部分通常来自芯片spec。例如:
# zephyr/dts/bindings/i2c/adi,max32-i2c.yaml
compatible: "adi,max32-i2c"
某些绑定适用于没有特定供应商的通用类设备。在这些情况下,没有供应商前缀。例如描述连接到 GPIO LED:
# led/gpio-leds.yaml
compatible: "gpio-leds"
properties 链接到标题
properties 描述与绑定匹配的节点所包含的属性。例如,max32 外设的绑定属性如下所示:
# zephyr/dts/bindings/i2c/adi,max32-i2c.yaml
properties:
reg:
required: true
clocks:
required: true
interrupts:
required: true
构建系统使用绑定的属性生成 C 宏。一般来说,构建系统仅为Devicetree中匹配绑定的 properties生成宏。绑定中未提及的属性通常会被构建系统忽略。 properties下有很多关键字用于限定属性的类型,取值范围等,之后会有文章专门展开说明
child-binding 链接到标题
child-binding 定义和约束父节点下的子节点属性,用于描述有相同属性的多个子设备。例如pwm-leds指定了其子节点的绑定属性有pwms和label,并且指定了其类型
# zephyr/dts/bindings/led/pwm-leds.yaml
description: PWM LEDs parent node
compatible: "pwm-leds"
child-binding:
description: PWM LED child node
properties:
pwms:
required: true
type: phandle-array
label:
type: string
在dts中有一个节点pwm_leds,其有两个子节点pwm_led_0和pwm_led_1都遵守pwm-leds的child-binding约束
pwm_leds {
compatible = "pwm-leds";
status = "disabled";
pwm_led0: pwm_led_0 {
pwms = <&pwm 9 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
label = "PWM_LED_BLUE";
};
pwm_led1: pwm_led_1 {
pwms = <&pwm 10 PWM_MSEC(20) PWM_POLARITY_INVERTED>;
label = "PWM_LED_READ";
};
};
child-binding 也支持递归。例如下面这个绑定:
compatible: foo
child-binding:
child-binding:
properties:
my-property:
type: int
required: true
应用到dts中的grandchild节点:
parent {
compatible = "foo";
child {
grandchild {
my-property = <123>;
};
};
};
bus 链接到标题
bus 用于总线控制器,说明总线类型, 例如
# zephyr/dts/bindings/i2s/i2s-controller.yaml
bus: i2s
对于支持多协议的单总线,使用列表,例如
# zephyr/dts/bindings/i3c/i3c-controller.yaml
bus: [i3c, i2c]
on-bus 链接到标题
on-bus 表明节点属于指定bus类型上的设备,例如限定一个i2s设备,其绑定文件中需要含有
on-bus: i2c
当构建系统寻找节点的绑定时,会检查父节点的绑定是否包含 bus: <bus type>
。如果包含,接下来首先搜索具有显式 on-bus: <bus type>
的绑定,然后再搜索没有显式 on-bus 的绑定。按顺序对节点的 compatible 属性中的每一项重复搜索。
下面是rpi2040的spi0下挂了一个bme280的设备
&spi0 {
status = "okay";
compatible = "raspberrypi,pico-spi", "arm,pl022";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi0_default>;
bme280@0 {
compatible = "bosch,bme280";
reg = <0>;
spi-max-frequency = <1000000>; /* conservatively set to 1MHz */
};
};
对于设备总线控制器spi0对应的绑定文件关系为
- raspberrypi,pico-spi.yaml
- arm,pl022.yaml
- spi-controller.yaml
在spi-controller.yaml中含有
bus: spi
- spi-controller.yaml
在spi-controller.yaml中含有
- arm,pl022.yaml
对于设备bme280对应的绑定文件关系为:
- bosch,bme280-spi.yaml
- spi-device.yaml
在spi-device.yaml中含有
on-bus: spi
总线控制器和总线设备就通过bus和on-bus的类型匹配起来
- spi-device.yaml
在spi-device.yaml中含有
Specifier cell 链接到标题
*-cell 说明符(specifier)单元,用于限定phandles类型的属性,给定phandles的属性成员。例如有foo,pwm和bar,pwm两个绑定,都定义了pwm-cells的说明符
# foo,pwm.yaml
compatible: "foo,pwm"
...
pwm-cells:
- channel
- period
# bar,pwm.yaml
compatible: "bar,pwm"
...
pwm-cells:
- period
在dts中,对说明符要指定其cell的数量:
- foo,pwm的pwm-cells有两个成员,所以为2,
- bar,pwm的pwm-cell只有一个成员,所以为1
pwm1: pwm@deadbeef {
compatible = "foo,pwm";
#pwm-cells = <2>;
};
pwm2: pwm@deadbeef {
compatible = "bar,pwm";
#pwm-cells = <1>;
};
my-node {
# pwm1的channel为1 period为2000
# pwm2只有period为3000
pwms = <&pwm1 1 2000>, <&pwm2 3000>;
};
关于phandles的内容在后续文章中另行说明
include 链接到标题
include 绑定用inculde包含共享公共属性定义的其它绑定文件,例如
include: pwm-controller.yaml
允许同时include多个文件
include: [pwm-controller.yaml, pinctrl-device.yaml, base.yaml]
也可以写作
include:
- pwm-controller.yaml
- pinctrl-device.yaml
- base.yaml
如果希望只include绑定文件中的一部分属性,可以采用property-allowlist
或property-blocklist
, 例如下面的绑定包含foo.yaml的fp1和fp2属性,foo.yaml中的其它属性不会被包含,而bar.yaml中除了bp1和bp2以外的其它属性都会包含。
include:
- name: foo.yaml
property-allowlist:
- fp1
- fp2
- name: bar.yaml
property-blocklist:
- bp1
- bp2
参考 链接到标题
https://docs.zephyrproject.org/latest/build/dts/bindings-syntax.html