如何从嵌入式应用程序实际使用设备树Blob?

问题描述

我正在尝试了解device tree的工作方式。我已经阅读了一些文档,并且或多或少地了解了什么是dtsdtsidtb文件

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

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

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

解决方法

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

您的问题得到了回答here,我想。 是的,每个操作系统内核都将以自己的方式解析DTB文件。对于Linux, 例如,DTB将通过u-boot读取,而u-boot将启动Linux内核并传递其加载DTB BLOB的地址。

在下面的示例中,u-boot将从FAT文件系统将内核和DTB加载到内存中,然后将控件转移到地址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