dts dtb linux 原理,详细介绍DTS的基本原理和构造

dts --> dtb

------------------------------------

dtc -I dts -O dtb -S 0x3000 -o obj_name.dtb source_name.dts

-S 指定的是生成的dtb文件的大小,需要适当地扩大,以供u-boot创建/choose节点时使用

75eda2ed6eb2b5eef378afca469aae76.png

查看dts设备节点

------------------------------------

# ls -al /proc/device-tree

内核如何解析设备树

------------------------------------

1) 首先将从u-boot 传递过来的映像基地址和dtb 文件映像基地址保存通用寄存器r30,r31;

2) 通过调用machine_init() --> early_init_devtree()函数来获

取内核前期初始化所需的bootargs,cmd_line等系统引导参数;

3) 调用start_kernel() --> setup_arch() -->

unflatten_device_tree()函数来解析dtb文件,构建一个由device_node结构连接而成的单项链表,并使用全局变量allnodes指针来保存这个链表的头指针;

4) 内核调用OF提供的API函数获取allnodes链表信息来初始化内核其他子系统、设备等。

dispAllnodes() -- 显示DTS设备节点

--------------------------------------

./arch/powerpc/kernel/prom.c

void dispAllnodes()

{

struct device_node *dn;

dn = allnodes;

while (dn)

{

printk("dn->name = %s\n", dn->name);

printk("dn->type = %s\n", dn->type);

printk("dn->full_name = %s\n", dn->full_name);

printk("\n");

dn = dn->next;

}

}

EXPORT_SYMBOL(dispAllnodes);

根据DTS文件的设备节点,添加设备

linux-2.6.28\arch\powerpc\boot\dts\mpc8548cds.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 = ;

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设备节点添加到platform总线上,这样添加方式(单独添加某个节点)

比较麻烦,抽象度不够,每个节点都需要自己的添加代码,不科学

还是of_platform_bus_probe()比较好,统一添加allnodes下的所有节点

-------------------------------------------------------

staTIc int __init gfar_mdio_of_init(void)

{

...

// 获取device_type = "mdio" && compaTIble = "gianfar"的设备节点

np = of_find_compaTIble_node(np, "mdio", "gianfar"));

of_address_to_resource(np, 0, &res);

// 添加平台设备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)

{

...

// 设置pdev->dev.bus_id = fsl-gianfar_mdio.e0024520

// bus_id长度限制为BUS_ID_SIZE

// #define BUS_ID_SIZE    KOBJ_NAME_LEN

// 如果"%s.%x"字符串的长度超过KOBJ_NAME_LEN,将会造成设备节点名信息丢失

// 信息的丢失有可能导致设备添加失败,所以需要将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)

{

...

// 设置kobject->name = fsl-gianfar_mdio.e0024520

// #define KOBJ_NAME_LEN 20

kobject_set_name(&dev->kobj, "%s", dev->bus_id);

...

// 在/sys/devices/platform/目录下生成设备节点

// 设备节点名称为fsl-gianfar_mdio.e0024520

device_create_file(dev, &dev->uevent_attr);

...

}

设备与驱动的对应关系

-----------------------------------------------------

staTIc struct device_driver gianfar_mdio_driver = {

.name = "fsl-gianfar_mdio",

.bus = &platform_bus_type, //该驱动所归属的总线

.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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值