Linux 内核设备树(Device Tree)与内核代码匹配关系详解

1. 设备树简介

设备树(Device Tree, DT)是一种描述硬件信息的数据结构,主要用于 无固化 BIOS/ACPI 的嵌入式系统,如 ARM 体系结构。Linux 内核通过解析设备树,获取硬件拓扑信息,并在驱动程序中进行匹配,使驱动能够正确初始化设备。

设备树的主要作用

  • 描述 SoC(片上系统)的硬件资源,如 CPU、内存、总线、外设等。
  • 使内核代码与硬件解耦,增强可移植性。
  • 提供统一的硬件抽象层,支持不同的 SoC。

在这里插入图片描述

2. 设备树基本结构

设备树以 文本格式(.dts) 编写,最终会被编译成 二进制设备树 blob(.dtb),在内核启动时传递给内核。

示例:

/dts-v1/;

/ {
    model = "i.MX8M Plus EVK";
    compatible = "fsl,imx8mp-evk";

    memory {
        device_type = "memory";
        reg = <0x40000000 0x8000000>; // 128MB 内存
    };

    soc {
        uart0: serial@30860000 {
            compatible = "fsl,imx-uart";
            reg = <0x30860000 0x10000>;
            interrupts = <0 110 4>;
            clocks = <&clk IMX8MP_CLK_UART1>;
        };
    };
};

关键属性解析

  • compatible:用于匹配驱动程序。
  • reg:设备的寄存器地址和大小。
  • interrupts:中断号。
  • clocks:时钟信息。

3. Linux 内核解析设备树流程

内核解析设备树的主要流程如下:

  1. Bootloader 加载 .dtb 并传递给内核
    • 例如 U-Boot 通过 fdt addr 命令设置设备树地址。
  2. 内核初始化设备树early_init_dt_scan_nodes
    • 解析 memorycpuchosen 等根节点信息。
  3. 创建设备节点of_platform_populate
    • 遍历设备树,为每个节点创建 struct device_node 结构。
  4. 驱动与设备树匹配of_match_device
    • compatible 字段用于匹配对应的驱动。
  5. 设备初始化platform_driver_probe
    • 调用匹配的驱动 probe() 函数,初始化设备。

4. 设备树节点如何与驱动匹配

4.1 内核驱动匹配机制

设备树节点和驱动程序通过 compatible 字段匹配,内核的匹配机制如下:

  1. 设备树中的 compatible
    uart0: serial@30860000 {
        compatible = "fsl,imx-uart";
    };
    
  2. 驱动程序中的匹配表of_match_table):
    static const struct of_device_id imx_uart_dt_ids[] = {
        { .compatible = "fsl,imx-uart" },
        { /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
    
  3. platform_driver 结构体
    static struct platform_driver imx_uart_driver = {
        .driver = {
            .name = "imx-uart",
            .of_match_table = imx_uart_dt_ids,
        },
        .probe = imx_uart_probe,
    };
    
  4. 驱动加载时匹配设备
    static int imx_uart_probe(struct platform_device *pdev) {
        struct device *dev = &pdev->dev;
        struct resource *res;
    
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
            return -ENODEV;
    
        dev_info(dev, "IMX UART found at 0x%08x\n", res->start);
        return 0;
    }
    

4.2 设备树解析 API

Linux 内核提供一系列 API 来解析设备树:

API作用
of_find_node_by_path()通过路径查找设备树节点
of_find_compatible_node()通过 compatible 查找节点
of_property_read_u32()读取单个 u32 属性值
of_property_read_string()读取字符串属性

示例:

struct device_node *np;
u32 val;
np = of_find_compatible_node(NULL, NULL, "fsl,imx-uart");
of_property_read_u32(np, "reg", &val);

5. 主要的内核代码解析

5.1 设备树解析代码

early_init_dt_scan_nodes()

内核启动时,arch/arm64/kernel/setup.c 调用 early_init_dt_scan_nodes() 解析设备树:

void __init early_init_dt_scan_nodes(void)
{
    dt_root = unflatten_device_tree(initial_boot_params);
    early_init_dt_check_for_initrd();
    early_init_dt_check_for_chosen();
    early_init_dt_scan_memory();
}

5.2 设备树到设备结构体转换

drivers/of/platform.cof_platform_populate() 负责将设备树转换为 struct device

static int __init of_platform_populate(void)
{
    struct device_node *np;
    for_each_child_of_node(root, np) {
        struct platform_device *pdev;
        pdev = of_platform_device_create(np, "", NULL);
    }
}

5.3 设备树与驱动匹配核心代码

drivers/of/device.c 中的 of_match_device() 负责 compatible 匹配:

const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev)
{
    while (matches->compatible[0]) {
        if (of_device_is_compatible(dev->of_node, matches->compatible))
            return matches;
        matches++;
    }
    return NULL;
}

6. 结论

本文详细讲解了 设备树与 Linux 内核代码的匹配关系,分析了内核的解析过程、设备树 API、匹配机制,并通过示例代码解析驱动如何获取设备树信息。希望读者能够深入理解设备树在内核中的作用,并能在实际开发中灵活运用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值