千家信息网

Linux内核Device Tree怎么创建

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"Linux内核Device Tree怎么创建",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Linux内核Device Tree怎么
千家信息网最后更新 2026年11月03日Linux内核Device Tree怎么创建

这篇文章主要讲解了"Linux内核Device Tree怎么创建",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Linux内核Device Tree怎么创建"吧!

在Linux内核启动时,内核通过of_platform_populate()函数,将dts中的device node创建成platform device。为后续和各类驱动的platform driver匹配做准备。

of_platform_populate()函数在文件drivers/of/platform.c中实现。下面基于RockPI 4A单板的内核代码介绍其调用流程和实现过程。

一、函数调用流程

在Linux内核中,可以使用dump_stack()函数查看函数的调用流程。

/** * of_platform_populate() - Populate platform_devices from device tree data... #省略部分注释 */int of_platform_populate(struct device_node *root,            const struct of_device_id *matches,            const struct of_dev_auxdata *lookup,            struct device *parent){    struct device_node *child;    int rc = 0;    dump_stack();    ### 打印函数调用的堆栈信息    //1.如果root为NULL,则通过of_find_node_by_path()查找    root = root ? of_node_get(root) : of_find_node_by_path("/");    if (!root)        return -EINVAL;    //2.遍历dts中的节点    for_each_child_of_node(root, child) {        //3.为每个节点和子节点创建platform device        rc = of_platform_bus_create(child, matches, lookup, parent, true);        ...    }    ...}EXPORT_SYMBOL_GPL(of_platform_populate);

dump_stack()堆栈信息如下:

[    0.311191] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.154-00036-gcef30e88a9f5-dirty #36[    0.311198] Hardware name: ROCK PI 4A 2 (DT)[    0.311206] Call trace:[    0.311220] [] dump_backtrace+0x0/0x220[    0.311232] [] show_stack+0x24/0x30[    0.311244] [] dump_stack+0x98/0xc0[    0.311258] [] of_platform_populate+0x30/0xb8[    0.311268] [] arm64_device_init+0x30/0x4c[    0.311278] [] do_one_initcall+0x18c/0x194[    0.311290] [] kernel_init_freeable+0x228/0x22c[    0.311301] [] kernel_init+0x18/0x100[    0.311311] [] ret_from_fork+0x10/0x20

从堆栈信息中,可以看出:在arm64_device_init()函数中实现了of_platform_populate()函数的调用。后续介绍kernel_init()函数,暂时先留个念想。

注:

arm64_device_init()函数在arch/arm64/kernel/setup.c文件中实现。此时,串口驱动尚未加载,串口日志保存在缓冲区中。由于RK3399是多核,在Linux内核启动时,堆栈信息或其它日志有可能会丢失。在系统启动时,可以增加nosmp配置,关闭其他CPU的加载,保证尽可能多的日志输出。在配置文件/boot/extlinux/extlinux.conf最后增加:

label kernel-debug    kernel /debug/Image    fdt /debug/rk3399-rock-pi-4a.dtb    append earlyprintk console=ttyFIQ0,1500000n8 init=/sbin/init root=PARTUUID=b921b045-1d rw rootwait rootfstype=ext4 nosmp
二、函数实现过程

of_platform_populate()函数主要通过of_platform_bus_create()函数创建platform device。为了理解其实现过程,通过printk增加了部分调试日志,代码如下:

/** * of_platform_bus_create() - Create a device for a node and its children. * @bus: device node of the bus to instantiate * @matches: match table for bus nodes * @lookup: auxdata table for matching id and platform_data with device nodes * @parent: parent for new device, or NULL for top level. * @strict: require compatible property * * Creates a platform_device for the provided device_node, and optionally * recursively create devices for all the child nodes. */static int of_platform_bus_create(struct device_node *bus,                  const struct of_device_id *matches,                  const struct of_dev_auxdata *lookup,                  struct device *parent, bool strict){    ...    printk(KERN_ERR"--- name %s \n",bus->name);        //1.判断是否有compatible属性,没有则返回    /* Make sure it has a compatible property */    if (strict && (!of_get_property(bus, "compatible", NULL))) {        printk(KERN_ERR"--- %s() - skipping %s, no compatible prop\n",             __func__, bus->full_name);        return 0;    }    ...    //2.创建platform device    dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);    if (!dev || !of_match_node(matches, bus)) {        printk(KERN_ERR"--- no match node\n");        return 0;    }    //3.遍历子节点。如果存在,则创建platform device    for_each_child_of_node(bus, child) {        printk(KERN_ERR"---   create child: %s\n", child->full_name);        rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);        if (rc) {            of_node_put(child);            break;        }    }    of_node_set_flag(bus, OF_POPULATED_BUS);    return rc;}

更新内核映像后,截取了部分内核启动日志,如下:

[    0.326151] --- name syscon[    0.326311] ---   create child: /syscon@ff770000/io-domains[    0.326318] --- name io-domains[    0.326458] --- no match node[    0.326466] ---   create child: /syscon@ff770000/usb2-phy@e450[    0.326472] --- name usb2-phy[    0.326627] --- no match node[    0.326635] ---   create child: /syscon@ff770000/usb2-phy@e460[    0.326641] --- name usb2-phy[    0.326791] --- no match node[    0.326798] ---   create child: /syscon@ff770000/phy@f780[    0.326804] --- name phy[    0.326958] --- no match node[    0.326965] ---   create child: /syscon@ff770000/mipi-dphy-rx0[    0.326972] --- name mipi-dphy-rx0[    0.327113] --- no match node[    0.327120] ---   create child: /syscon@ff770000/pvtm[    0.327126] --- name pvtm[    0.327291] --- no match node...                                              ## 省略部分log[    0.330604] --- name display-subsystem        ## drm[    0.330742] --- no match node...

上述日志中的节点名称bus->name和子节点名称child->full_name可在arch/arm64/boot/dts/rockchip/rk3399.dtsi文件中查到:

    grf: syscon@ff770000 {                        ## syscon对应节点名        compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";        reg = <0x0 0xff770000 0x0 0x10000>;        #address-cells = <1>;        #size-cells = <1>;        io_domains: io-domains {            compatible = "rockchip,rk3399-io-voltage-domain";            status = "disabled";        };        u2phy0: usb2-phy@e450 {                     ## usb2-phy@e450对应子节点名            compatible = "rockchip,rk3399-usb2phy";            reg = <0xe450 0x10>;            clocks = <&cru SCLK_USB2PHY0_REF>;            clock-names = "phyclk";            #clock-cells = <0>;            clock-output-names = "clk_usbphy0_480m";            status = "disabled";            ...        }    }    ...    display_subsystem: display-subsystem {          ## display-subsystem 对应节点名        compatible = "rockchip,display-subsystem";        ports = <&vopl_out>, <&vopb_out>;        clocks = <&cru PLL_VPLL>, <&cru PLL_CPLL>;        clock-names = "hdmi-tmds-pll", "default-vop-pll";        devfreq = <&dmc>;        status = "disabled";    };

在系统启动后,可以在/sys/firmware/devicetree/base路径下查看dts文件节点,在/sys/devices/platform路径下查看platform device。

root@linaro-alip:/sys/firmware/devicetree/base# ls syscon@ff770000/#address-cells  compatible  mipi-dphy-rx0  phandle   pvtm  usb2-phy@e450#size-cells     io-domains  name           phy@f780  reg   usb2-phy@e460root@linaro-alip:/sys/firmware/devicetree/base# ls display-subsystem/clock-names  compatible  logo-memory-region  phandle  routeclocks       devfreq     name                ports    statusroot@linaro-alip:/sys/firmware/devicetree/base#
root@linaro-alip:/sys/devices/platform# ls ff770000.syscon/driver_override                ff770000.syscon:usb2-phy@e460/ff770000.syscon:io-domains/    modaliasff770000.syscon:mipi-dphy-rx0/ of_node/ff770000.syscon:phy@f780/      power/ff770000.syscon:pvtm/          subsystem/ff770000.syscon:usb2-phy@e450/ ueventroot@linaro-alip:/sys/devices/platform# ls display-subsystem/driver           drm       modalias  power      ueventdriver_override  graphics  of_node   subsyste

感谢各位的阅读,以上就是"Linux内核Device Tree怎么创建"的内容了,经过本文的学习后,相信大家对Linux内核Device Tree怎么创建这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

函数 内核 节点 日志 文件 信息 堆栈 部分 流程 过程 中实 学习 串口 代码 内容 名称 系统 路径 配置 驱动 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网和科技技术 美国互联网保险保险科技 科技互联网龙头 广州善班互联网科技 兼蜜互联网科技 银川新华互联网科技职业技术培训学校图片 茂名市互联网科技产业园 厦门比较好的科技互联网公司 成都互联网科技公司工作好不好 银川新华互联网科技学校联系电话 深圳艾果互联网通讯科技 长沙茂晟互联网科技有限公司 伍佰万互联网科技怎么赚钱 图游互联网科技 互联网科技包装股份有限公司上市 广州互联网高科技取餐柜 美国五大互联网科技公司市值多少 亚光科技低轨卫星互联网 承德科技产业互联网平台 株洲百竞科技的互联网营销顾问 喔噻互联网科技 长亮科技互联网金融 大白互联网科技 互联网科技中介 互联网对科技的发展 广西互联网科技孵化中心 996高科技互联网公司 畅思互联网科技 互联网科技包装股份有限公司上市 互联网科技自媒体灵感
0