1

我正在尝试学习如何device tree工作。我已经阅读了一些文档,并且或多或少地了解了什么是dts,dtsidtb文件。

我不太了解的是如何dtb从最终应用程序中访问文件中的信息。我一直在阅读zephyros 文档和一些 linux 内核来理解这一点,但对我来说仍然不是很清楚。

我现在所理解的是最终应用程序(可能是操作系统内核)dtb“手动”读取和解析文件。这意味着每个操作系统内核都会dtb以自己的方式解析文件,对吗?

但是,据我了解,应用程序没有链接到dtb文件,后者在一些内存区域中闪烁,然后是应用程序。以某种方式访问​​它。那么,如果这些符号在构建时不可用,如何构建应用程序?

4

1 回答 1

1

免责声明:我不是 Linux 内核专家。

我猜你的问题在这里得到了回答。是的,每个操作系统内核都会以自己的方式解析 DTB 文件。在 Linux 的情况下,例如 DTB 将由 u-boot 读取,u-boot 将启动 Linux 内核并传递它加载 DTB BLOB 的地址。

在下面的示例中,u-boot 会将内核和 DTB 从 FAT 文件系统加载到内存中,然后将控制权转移到地址 0x80300000 处的内核,同时告诉它其 DTB BLOB 将在地址 0x815f0000 处可用:

fatload mmc 0:1 0x80300000 zImage
fatload mmc 0:1 0x815f0000 beagle-xm.dtb
bootz 0x80300000 - 0x815f0000

DTB BLOB 确实包含符号名称及其相关值。应用程序将使用一些专门用于读取 DTB 格式的代码,例如 libfdt,以从其符号名称中检索值。现在不需要在构建它时了解 DTB 内容。这确实允许相同的编译内核在不修改的情况下在不同的硬件上运行,DTB 中描述了各种硬件功能。

为了使操作系统能够有效地访问 DTB 中包含的信息,使用 libfdt 将信息从 DTB BLOB 中提取一次,然后放入一个有效的数据结构中。例如,从“扁平化”格式转换为“扩展”格式。

我强烈建议阅读:

请注意,Zephyr 方法不是标准的:当开放固件/设备树方案被设计为允许应用程序和硬件描述的“后期绑定”时,他们选择了更静态的方法。

Zephyr 实际上使用了一个自定义工具,它处理 DTB 文件并生成 C 头文件,其中包含遵循某些命名约定的宏形式的相同信息。这可能是您对 DTB 内容和使用它的应用程序绑定在一起的确切阶段感到困惑的原因。

不要尝试使用 Zephyr 来提升设备树的概念。此外,他们的工具还远非完美,在处理完全有效的 DTB 文件时会卡住。

将 DTB 绑定到驱动程序的 Linux 内核驱动程序代码摘录:

static const struct platform_device_id mxs_auart_devtype[] = {
    { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
    { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
    { .name = "as-auart-asm9260", .driver_data = ASM9260_AUART },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, mxs_auart_devtype);

static const struct of_device_id mxs_auart_dt_ids[] = {
    {
        .compatible = "fsl,imx28-auart",
        .data = &mxs_auart_devtype[IMX28_AUART]
    }, {
        .compatible = "fsl,imx23-auart",
        .data = &mxs_auart_devtype[IMX23_AUART]
    }, {
        .compatible = "alphascale,asm9260-auart",
        .data = &mxs_auart_devtype[ASM9260_AUART]
    }, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);

在 Zephyr 代码中找到一个等效的(虽然不同的驱动程序):

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(flexcomm5), nxp_lpc_spi, okay)
    /* Attach 12 MHz clock to FLEXCOMM5 */
    CLOCK_AttachClk(kFRO_HF_to_FLEXCOMM5);
    
    /* reset FLEXCOMM for SPI */
    RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn);
#endif
于 2020-09-13T01:11:34.097 回答