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

对于设备bme280对应的绑定文件关系为:

  • bosch,bme280-spi.yaml
    • spi-device.yaml 在spi-device.yaml中含有on-bus: spi 总线控制器和总线设备就通过bus和on-bus的类型匹配起来

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-allowlistproperty-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