基于Linux 3.10.49内核从dts文件里注册platform

Linux kernel 3.10.49+
在这里, 我们说说Linux 是怎么通过dts进行设备(platform_device)注册和初始化板载信息.
在arch/arm/mach-******/******.c找到DT_MACHINE_START 和 MACHINE_END 宏, 如下:
DT_MACHINE_START(******_DT, "************* SoC (Flattened Device Tree)")
    .atag_offset    = 0x100,
    .dt_compat    = ******_dt_compat,                // 匹配dts
    .map_io        = ******_map_io,                    // 板级地址内存映射, linux mmu
    .init_irq    = irqchip_init,                    // 板级中断初始化.
    .init_time    = ******_timer_and_clk_init,        // 板级时钟初始化,如ahb,apb等
    .init_machine  = ******_dt_init,              // 这里是解析dts文件入口.
    .restart    = ******_restart,                  // 重启, 看门狗寄存器相关可以在这里设置
MACHINE_END

其中.dt_compat    = ******_dt_compat 这个结构体是匹配是哪个dts文件, 如:
static const char * const ******_dt_compat[] = {
    "******,******-soc",
    NULL
 };
这个"******,******-soc" 字符串可以在我们的dts的根节点下可以找到.

好了, 我们来看看 init_machine  = ******_dt_init 这个回调函数.
1. arch/arm/mach-******/******.c : void __init ******_dt_init(void)
    ******_dt_init(void) --> of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
    of_default_bus_match_table 这个是struct of_device_id的全局变量.
    const struct of_device_id of_default_bus_match_table[] = {
        { .compatible = "simple-bus", },
    #ifdef CONFIG_ARM_AMBA
        { .compatible = "arm,amba-bus", },
    #endif /* CONFIG_ARM_AMBA */
        {} /* Empty terminated list */
    };
    我们设计dts时, 把一些需要指定寄存器基地址的设备放到以compatible = "simple-bus"为匹配项的设备节点下. 下面会有介绍为什么.

2. drivers/of/platform.c : int of_platform_populate(...)
    of_platform_populate(...) --> of_platform_bus_create(...)
    // 在这之前, 会有of_get_property(bus, "compatible", NULL)
    // 检查是否有compatible, 如果没有, 返回, 继续下一个, 也就是说没有compatible, 这个设备不会被注册
    for_each_child_of_node(root, child) {
        printk("[%s %s %d] child->name = %s, child->full_name = %s\n", __FILE__, __func__, __LINE__, child->name, child->full_name);
        rc = of_platform_bus_create(child, matches, lookup, parent, true);
        if (rc)
            break;
    }
    论询dts根节点下的子设备, 每个子设备都要of_platform_bus_create(...);
    全部完成后, 通过 of_node_put(root); 释放根节点, 因为已经处理完毕;

3. drivers/of/platform.c : of_platform_bus_create(bus, ...)
    dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); // 我们跳到 3-1-1步去运行
    if (!dev || !of_match_node(matches, bus))  // 就是匹配
                                              // dt_compat    = ******_dt_compat, 也就是 compatible = "simple-bus",
                                                // 如果匹配成功, 以本节点为父节点, 继续轮询本节点下的所有子节点
        return 0;

for_each_child_of_node(bus, child) {
        pr_debug("  create child: %s\n", child->full_name);
        rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);  // dev->dev以本节点为父节点,  我们跳到 3-2-1步去运行
        if (rc) {
            of_node_put(child);
            break;
        }
    }

3-1-1. drivers/of/platform.c : of_platform_device_create_pdata(...)
    if (!of_device_is_available(np))  // 查看节点是否有效, 如果节点有'status'属性, 必须是okay或者是ok, 才是有效, 没有'status'属性, 也有效
        return NULL;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/47a695a3e2e5f9ed0e9f083591c66a07.html