Linux 设备树:如何解析包含单元格列表的 属性

Linux device tree: how to parse property containing a list of cells

我正在开发一个 Linux 设备驱动程序,用于在嵌入式 Linux (PetaLinux) 中获取数据。

为了避免在内核模块中对硬件细节进行硬编码,设备树中的一个条目有一个单元格列表,这些单元格描述了不同 ADC 芯片通过 SPI 访问的继电器映射,如下所示:

ll-adc@a1000000 {
  compatible = "ll,llmk1-adc-1.0";
  reg =   <0x0 0xa1000000 0x1000>;

  // related SPI devices to control attenutor relays
  relay-devs = <&usmk1_max4820_0 &usmk1_max4820_1>;

  // Which relays control which ADC channel attenuator
  relays =
        <0 0 0 2>, // Channel 0, att 0 --> relay dev 0, ch 2 
        <0 1 0 3>, // Channel 0, att 1 --> relay dev 0, ch 3 
        <1 0 1 3>, // Channel 1, att 0 --> relay dev 1, ch 3 
        <1 1 0 0>; // Channel 1, att 1 --> relay dev 0, ch 0 
};

在实例化设备时,我想从 属性 "relays" 中读取值并将它们保存在内核模块的 table 中。

但是,我找不到合适的函数来执行此操作。

据我所知,of_property_read_*_array 可以读取包含单个单元格的 属性 的数组。 of_for_each* 宏可以迭代一个 属性 的多个值,只要它们是 phandles、u32 或字符串。

如果可能的话,有人可以建议读取如上所示的单元格列表的正确方法是什么吗?

感谢您的帮助。

内核源代码中的示例指出了可能的解决方案。

如果您的节点 属性 由 n-tuples 的列表组成,则 of_property_read_u32_index() 可用于获取第 i 个元组的单个 u32 参数:

num_args = 4;

if (!of_get_property(np, "relays", &tmp))
    return NULL;
num_relays = tmp / (sizeof(u32) * num_args);

for (i = 0; i < num_relays; i++) {
    offset = i * num_args;
    if (of_property_read_u32_index(np, "relays", offset, &arg0))
        goto err;

    if (of_property_read_u32_index(np, "relays", offset + 1, &arg1))
        goto err;

    if (of_property_read_u32_index(np, "relays", offset + 2, &arg2))
        goto err;

    if (of_property_read_u32_index(np, "relays", offset + 3, &arg3))
        goto err;
}

驱动程序 drivers/clk/at91/clk-pll.c 使用类似的代码从 atmel,pll-clk-output-ranges 属性 中检索值:

        pmc: pmc@fffffc00 {
            plla: pllack {
                atmel,clk-input-range = <2000000 32000000>;
                atmel,pll-clk-output-ranges = <745000000 800000000 0 0>,
                            <695000000 750000000 1 0>,
                            <645000000 700000000 2 0>,
                            <595000000 650000000 3 0>,
                            <545000000 600000000 0 1>,
                            <495000000 550000000 1 1>,
                            <445000000 500000000 2 1>,
                            <400000000 450000000 3 1>;
            };  
            ...
        };            

附录

似乎 属性 定义中的尖括号对编译后的 dtb 中的整数数组没有影响。
以下两个 属性 定义:

    node1 {
        xxx = <745000000 800000000 0 0>,
            <695000000 750000000 1 0>,
            <645000000 700000000 2 0>,
            <595000000 650000000 3 0>,
            <545000000 600000000 0 1>,
            <495000000 550000000 1 1>,
            <445000000 500000000 2 1>,
            <400000000 450000000 3 1>;
    };

    node2 {
        xxx = < 745000000 800000000 0 0
            695000000 750000000 1 0
            645000000 700000000 2 0
            595000000 650000000 3 0
            545000000 600000000 0 1
            495000000 550000000 1 1
            445000000 500000000 2 1
            400000000 450000000 3 1 >;
    };

/proc/device-tree/ 转储时具有相同的值:

# hexdump -C node1/xxx
00000000  2c 67 cc 40 2f af 08 00  00 00 00 00 00 00 00 00  |,g.@/...........|
00000010  29 6c db c0 2c b4 17 80  00 00 00 01 00 00 00 00  |)l..,...........|
00000020  26 71 eb 40 29 b9 27 00  00 00 00 02 00 00 00 00  |&q.@).'.........|
00000030  23 76 fa c0 26 be 36 80  00 00 00 03 00 00 00 00  |#v..&.6.........|
00000040  20 7c 0a 40 23 c3 46 00  00 00 00 00 00 00 00 01  | |.@#.F.........|
00000050  1d 81 19 c0 20 c8 55 80  00 00 00 01 00 00 00 01  |.... .U.........|
00000060  1a 86 29 40 1d cd 65 00  00 00 00 02 00 00 00 01  |..)@..e.........|
00000070  17 d7 84 00 1a d2 74 80  00 00 00 03 00 00 00 01  |......t.........|
00000080
# hexdump -C node2/xxx
00000000  2c 67 cc 40 2f af 08 00  00 00 00 00 00 00 00 00  |,g.@/...........|
00000010  29 6c db c0 2c b4 17 80  00 00 00 01 00 00 00 00  |)l..,...........|
00000020  26 71 eb 40 29 b9 27 00  00 00 00 02 00 00 00 00  |&q.@).'.........|
00000030  23 76 fa c0 26 be 36 80  00 00 00 03 00 00 00 00  |#v..&.6.........|
00000040  20 7c 0a 40 23 c3 46 00  00 00 00 00 00 00 00 01  | |.@#.F.........|
00000050  1d 81 19 c0 20 c8 55 80  00 00 00 01 00 00 00 01  |.... .U.........|
00000060  1a 86 29 40 1d cd 65 00  00 00 00 02 00 00 00 01  |..)@..e.........|
00000070  17 d7 84 00 1a d2 74 80  00 00 00 03 00 00 00 01  |......t.........|
00000080
# cmp node1/xxx node2/xxx
# 

在任何一个版本的 属性 中,尖括号(又名人字形)和逗号似乎都被忽略了,值被简单地存储为 single-dimension 整数数组(带有 big-endian 字节序)。


附录 2

以上结果由 DeviceTree 规范(版本 v0.2-18-g8466c3b-dirty)第 6.3 节中的两条语句确认:

Arrays of cells (i.e. units of information consisting of 32 bits) are represented by angle brackets surrounding a space separated list of C-style integers

(Property) Values may have several comma-separated components, which are concatenated together.

因此,作为单个数组的 属性 值与串联的多个数组没有区别。
使用 n-tuples 的列表纯粹是为了美观和可读性。

数据的"organization"(如n-tuples)在dtb级别无法辨别。
因此n-tuple(或“单元格列表”)的大小或n应在另一个属性中传递给驱动程序,或指定在绑定文档中(在驱动程序中进行硬编码时)。