以下内容从正点原子文档种摘取。
一、使用设备树之前设备匹配方法
在没有使用设备树以前,uboot 会向 Linux 内核传递一个叫做 machine id 的值,machine id 也就是设备 ID,告诉 Linux 内核自己是个什么设备,看看 Linux 内核是否支持。Linux 内核是 支持很多设备的,针对每一个设备(板子),Linux 内核都用 MACHINE_START 和 MACHINE_END 来定义一个 machine_desc 结构体来描述这个设备。比如在文件 arch/arm/mach-imx/machmx35_3ds.c 中有如下定义:
MACHINE_START(MX35_3DS, "Freescale MX35PDK")
/* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
MACHINE_END
上述代码就是定义了 “Freescale MX35PDK” 这个设备,其中 MACHINE_START 和 MACHINE_END 定义在文件arch/arm/include/asm/mach/arch.h 中,内容如下:
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
根据 MACHINE_START 和 MACHINE_END 的宏定义,将示例代码展开后如下所示:
static const struct machine_desc __mach_desc_MX35_3DS \
__used \
__attribute__((__section__(".arch.info.init"))) = {
.nr = MACH_TYPE_MX35_3DS,
.name = "Freescale MX35PDK",
/* Maintainer: Freescale Semiconductor, Inc */
.atag_offset = 0x100,
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = mx35_init_irq,
.init_time = mx35pdk_timer_init,
.init_machine = mx35_3ds_init,
.reserve = mx35_3ds_reserve,
.restart = mxc_restart,
}
从示例代码中可以看出,这里定义了一个 machine_desc 类型的结构体变量 __mach_desc_MX35_3DS , 这 个 变 量 存 储 在 “ .arch.info.init ” 段 中 。第 4 行的 MACH_TYPE_MX35_3DS 就 是 “ Freescale MX35PDK ” 这 个 板 子 的 machine id 。 MACH_TYPE_MX35_3DS 定义在文件 include/generated/mach-types.h 中,此文件定义了大量的 machine id,内容如下所示:
第 287 行就是 MACH_TYPE_MX35_3DS 的值,为 1645。
前面说了,uboot 会给 Linux 内核传递 machine id 这个参数,Linux 内核会检查这个 machine id,其实就是将 machine id 与示例代码中的这些 MACH_TYPE_XXX 宏进行对比,看 看有没有相等的,如果相等的话就表示 Linux 内核支持这个设备,如果不支持的话那么这个设 备就没法启动 Linux 内核。
二、使用设备树以后的设备匹配方法
当 Linux 内核引入设备树以后就不再使用 MACHINE_START 了,而是换为了 DT_MACHINE_START。DT_MACHINE_START 也定义在文件 arch/arm/include/asm/mach/arch.h 里面,定义如下:
#define DT_MACHINE_START(_name, _namestr) \
static const struct machine_desc __mach_desc_##_name \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = ~0, \
.name = _namestr,
#endif
可以看出,DT_MACHINE_START 和 MACHINE_START 基本相同,只是 .nr 的设置不同,在 DT_MACHINE_START 里面直接将 .nr 设置为 ~0。说明引入设备树以后不会再根据 machine id 来检查 Linux 内核是否支持某个设备了。
打开文件 arch/arm/mach-imx/mach-imx6ul.c,有如下所示内容:
static const char *imx6ul_dt_compat[] __initconst = {
"fsl,imx6ul",
"fsl,imx6ull",
NULL,
};
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END
machine_desc 结构体中有个 .dt_compat 成员变量,此成员变量保存着本设备兼容属性,示例代码中设置 .dt_compat = imx6ul_dt_compat,imx6ul_dt_compat 表里面有 "fsl,imx6ul" 和 "fsl,imx6ull" 这两个兼容值。
只要某个设备(板子)根节点 “/” 的 compatible 属性值与 imx6ul_dt_compat 表中的任何一个值相等,那么就表示 Linux 内核支持此设备。