dts --> dtb
------------------------------------
dtc -I dts -O dtb -S 0x3000 -o obj_name.dtb source_name.dts
-S 指定的是生成的dtb文件的大小,需要適當(dāng)?shù)財(cái)U(kuò)大,以供u-boot創(chuàng)建/choose節(jié)點(diǎn)時(shí)使用
查看dts設(shè)備節(jié)點(diǎn)
------------------------------------
# ls -al /proc/device-tree
內(nèi)核如何解析設(shè)備樹(shù)
------------------------------------
1) 首先將從u-boot 傳遞過(guò)來(lái)的映像基地址和dtb 文件映像基地址保存通用寄存器r30,r31;
2) 通過(guò)調(diào)用machine_init() --> early_init_devtree()函數(shù)來(lái)獲
取內(nèi)核前期初始化所需的bootargs,cmd_line等系統(tǒng)引導(dǎo)參數(shù);
3) 調(diào)用start_kernel() --> setup_arch() -->
unflatten_device_tree()函數(shù)來(lái)解析dtb文件,構(gòu)建一個(gè)由device_node結(jié)構(gòu)連接而成的單項(xiàng)鏈表,并使用全局變量allnodes指針來(lái)保存這個(gè)鏈表的頭指針;
4) 內(nèi)核調(diào)用OF提供的API函數(shù)獲取allnodes鏈表信息來(lái)初始化內(nèi)核其他子系統(tǒng)、設(shè)備等。
dispAllnodes() -- 顯示DTS設(shè)備節(jié)點(diǎn)
--------------------------------------
./arch/powerpc/kernel/prom.c
void dispAllnodes()
{
?? struct device_node *dn;
?? dn = allnodes;
?? while (dn)
?? {
?????? printk("dn->name = %s
", dn->name);
?????? printk("dn->type = %s
", dn->type);
?????? printk("dn->full_name = %s
", dn->full_name);
?????? printk("
");
?????? dn = dn->next;
?? }
}
EXPORT_SYMBOL(dispAllnodes);
根據(jù)DTS文件的設(shè)備節(jié)點(diǎn),添加設(shè)備
linux-2.6.28archpowerpcootdtsmpc8548cds.dts
-------------------------------------------------------
??? soc8548@e0000000 {
??? ??? #address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
??? ??? device_type = "soc";
??? ??? ranges = <0 e0000000 00100000>;
??? ??? reg = ;??? // CCSRBAR 1M
??? ??? bus-frequency = <0>;
??? ??? mdio@24520 {
??? ??? ??? #address-cells = <1>;
??? ??? ??? #size-cells = <0>;
??? ??? ??? device_type = "mdio";
??? ??? ??? compatible = "gianfar";
??? ??? ??? reg = <24520 20>;
??? ??? ??? phy0: ethernet-phy@0 {
??? ??? ??? ??? interrupt-parent = <&mpic>;
??? ??? ??? ??? interrupts = <35 0>;
??? ??? ??? ??? reg = <0>;
??? ??? ??? ??? device_type = "ethernet-phy";
??? ??? ??? };
??? ??? };
linux-2.6.21.7
gfar_mdio_of_init() -->
??? platform_device_register_simple() -->
????????? platform_device_add() -->
?????????????? device_add()????
將mdio設(shè)備節(jié)點(diǎn)添加到platform總線上,這樣添加方式(單獨(dú)添加某個(gè)節(jié)點(diǎn))
比較麻煩,抽象度不夠,每個(gè)節(jié)點(diǎn)都需要自己的添加代碼,不科學(xué)
還是of_platform_bus_probe()比較好,統(tǒng)一添加allnodes下的所有節(jié)點(diǎn)
-------------------------------------------------------
static int?__init?gfar_mdio_of_init(void)
{
??? ...????
??? // 獲取device_type = "mdio" && compatible = "gianfar"的設(shè)備節(jié)點(diǎn)
??? np = of_find_compatible_node(np, "mdio", "gianfar"));
??? of_address_to_resource(np, 0, &res);
??? // 添加平臺(tái)設(shè)備res.start = e0024520
??? platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
??? ...?
}
arch_initcall(gfar_mdio_of_init);
struct platform_device *platform_device_register_simple(char *name,?
?????????????????????????? unsigned int id,
?? ??? ??? ??? ??? ??? ??? struct resource *res, unsigned int num)
{
?? ...
?? // 生成platform_device
?? // platform_device->name = name; "fsl-gianfar_mdio"
?? // platform_device->id = id; e0024520
?? pdev = platform_device_alloc(name, id);
?? ...
?? platform_device_add(pdev);
?? ...
}
int platform_device_add(struct platform_device *pdev)
{
?? ...
?? // 設(shè)置pdev->dev.bus_id = fsl-gianfar_mdio.e0024520
?? // bus_id長(zhǎng)度限制為BUS_ID_SIZE
?? // #define BUS_ID_SIZE??? KOBJ_NAME_LEN
?? // 如果"%s.%x"字符串的長(zhǎng)度超過(guò)KOBJ_NAME_LEN,將會(huì)造成設(shè)備節(jié)點(diǎn)名信息丟失
?? // 信息的丟失有可能導(dǎo)致設(shè)備添加失敗,所以需要將KOBJ_NAME_LEN改大(20 --> 64)
?? snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%x", pdev->name, pdev->id);
?? ...
?? device_add(&pdev->dev);
?? ...
}
int device_add(struct device *dev)
{
?? ...
?? // 設(shè)置kobject->name = fsl-gianfar_mdio.e0024520
?? // #define KOBJ_NAME_LEN 20
?? kobject_set_name(&dev->kobj, "%s", dev->bus_id);
?? ...
?? // 在/sys/devices/platform/目錄下生成設(shè)備節(jié)點(diǎn)
?? // 設(shè)備節(jié)點(diǎn)名稱為fsl-gianfar_mdio.e0024520
?? device_create_file(dev, &dev->uevent_attr);
?? ...
}
設(shè)備與驅(qū)動(dòng)的對(duì)應(yīng)關(guān)系
-----------------------------------------------------
static struct device_driver gianfar_mdio_driver = {
?? .name = "fsl-gianfar_mdio",
?? .bus = &platform_bus_type, //該驅(qū)動(dòng)所歸屬的總線
?? .probe = gfar_mdio_probe,
?? .remove = gfar_mdio_remove,
};
cat /sys/devices/platform/fsl-gianfar_mdio.e0024520/modalias
fsl-gianfar_mdio
static struct platform_driver gfar_driver = {
?? .probe = gfar_probe,
?? .remove = gfar_remove,
?? .driver??? = {
?? ??? .name = "fsl-gianfar",
?? },
};
cat /sys/devices/platform/fsl-gianfar.0/modalias
fsl-gianfar
?
評(píng)論
查看更多