Linux内核Device Tree-创建platform device

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] [<ffffff80080888d8>] dump_backtrace+0x0/0x220
[    0.311232] [<ffffff8008088b1c>] show_stack+0x24/0x30
[    0.311244] [<ffffff800856ebec>] dump_stack+0x98/0xc0
[    0.311258] [<ffffff80089a1000>] of_platform_populate+0x30/0xb8
[    0.311268] [<ffffff8009113b68>] arm64_device_init+0x30/0x4c
[    0.311278] [<ffffff80080831cc>] do_one_initcall+0x18c/0x194
[    0.311290] [<ffffff8009110e10>] kernel_init_freeable+0x228/0x22c
[    0.311301] [<ffffff8008c75080>] kernel_init+0x18/0x100
[    0.311311] [<ffffff8008082ef0>] 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@e460
root@linaro-alip:/sys/firmware/devicetree/base# ls display-subsystem/
clock-names  compatible  logo-memory-region  phandle  route
clocks       devfreq     name                ports    status
root@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/    modalias
ff770000.syscon:mipi-dphy-rx0/ of_node/
ff770000.syscon:phy@f780/      power/
ff770000.syscon:pvtm/          subsystem/
ff770000.syscon:usb2-phy@e450/ uevent
root@linaro-alip:/sys/devices/platform# ls display-subsystem/
driver           drm       modalias  power      uevent
driver_override  graphics  of_node   subsystem
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容