在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;
dev = of_device_alloc(np, bus_id, parent); // alloc設備, 設備初始化. 返回dev, 所有的設備都可認為是platform_device, 跳到3-1-1-1看看函數做了什麼事情
if (!dev)
return NULL;
#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); // dev->dev 是 struct device. 繼續初始化
dev->dev.bus = &platform_bus_type; //
dev->dev.platform_data = platform_data;
printk("[%s %s %d] of_device_add(device register) np->name = %s\n", __FILE__, __func__, __LINE__, np->name);
if (of_device_add(dev) != 0) { // 注冊device, of_device_add(...) --> device_add(...) // This is part 2 of device_register()
platform_device_put(dev);
return NULL;
}
3-1-1-1. drivers/of/platform.c : of_device_alloc(...)
1) alloc platform_device *dev
2) 如果有reg和interrupts的相關屬性, 運行of_address_to_resource 和 of_irq_to_resource_table, 加入到dev->resource
dev->num_resources = num_reg + num_irq;
dev->resource = res;
for (i = 0; i < num_reg; i++, res++) {
rc = of_address_to_resource(np, i, res);
/* printk("[%s %s %d] res->name = %s, res->start = 0x%X, res->end = 0x%X\n", __FILE__, __func__, __LINE__, res->name, res->start, res->end); */
WARN_ON(rc);
}
WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
3) dev->dev.of_node = of_node_get(np);
// 這個node屬性裡有compatible屬性, 這個屬性從dts來, 後續driver匹配device時, 就是通過這一屬性進匹配
// 我們可以通過添加下面一句話來查看compatible.
// printk("[%s %s %d] bus->name = %s, of_get_property(...) = %s\n", __FILE__, __func__, __LINE__, np->name, (char*)of_get_property(np, "compatible", NULL));
// node 再給dev, 後續給驅動注冊使用.
4) 運行 of_device_make_bus_id 設定device的名字, 如: soc.2 或 ac000000.serial 等
3-2-1. drivers/of/platform.c :
以 compatible = "simple-bus"的節點的子節點都會以這個節點作為父節點在這步注冊設備.
這是實際的板載設備, 也是最終目的.
下一篇分析,我們來講講platform_driver的注冊, 是怎麼匹配剛才我們注冊過的platform_device的