精华内容
下载资源
问答
  • LinuxDTS

    千次阅读 2019-03-07 17:31:43
    Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇) Linux DTS(Device Tree Source)设备树详解之三(高通MSM8953实例分析篇) 有上一篇文章,我们了解了dts的背景知识和相关基础...

    @[T义目录标题)

    本系列导航:

    Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇)

    Linux DTS(Device Tree Source)设备树详解之三(高通MSM8953实例分析篇)


    有上一篇文章,我们了解了dts的背景知识和相关基础,这次我们对应实际设备进行一下相关分析。

     

    DTS设备树的匹配过程

    一个dts文件确定一个项目,多个项目可以包含同一个dtsi文件。找到该项目对应的dts文件即找到了该设备树的根节点。

    kernel\arch\arm\boot\dts\qcom\sdm630-mtp.dts

    
     
    1. /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
    2. *
    3. * This program is free software; you can redistribute it and/or modify
    4. * it under the terms of the GNU General Public License version 2 and
    5. * only version 2 as published by the Free Software Foundation.
    6. *
    7. * This program is distributed in the hope that it will be useful,
    8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    10. * GNU General Public License for more details.
    11. */
    12. /dts-v1/;
    13. #include "sdm630.dtsi"
    14. #include "sdm630-mtp.dtsi"
    15. //#include "sdm660-external-codec.dtsi"
    16. #include "sdm660-internal-codec.dtsi"
    17. #include "synaptics-dsx-i2c.dtsi"
    18. / {
    19. model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L MTP";
    20. compatible = "qcom,sdm630-mtp", "qcom,sdm630", "qcom,mtp";
    21. qcom,board- id = < 8 0>;
    22. qcom,pmic- id = < 0x0001001b 0x0101011a 0x0 0x0>,
    23. < 0x0001001b 0x0201011a 0x0 0x0>;
    24. };
    25. &tavil_snd {
    26. qcom,msm-mbhc-moist-cfg = < 0>, < 0>, < 3>;
    27. };

    当然devicetree的根节点也是需要和板子进行匹配的,这个匹配信息存放在sbl(second boot loader)中,对应dts文件中描述的board-id(上面代码中的qcom,board-id属性),通过共享内存传递给bootloader,由bootloader将此board-id匹配dts文件(devicetree的根节点文件),将由dtc编译后的dts文件(dtb文件)加载到内存,然后在kernel中展开dts树,并且挂载dts树上的所有设备。

    (ps:cat /proc/cmdline 查看cmdline)

     

    Dts中相关符号的含义

    /        根节点

    @     如果设备有地址,则由此符号指定

    &     引用节点

    :        冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label

    ,        属性名称中可以包含逗号。如compatible属性的名字 组成方式为"[manufacturer], [model]",加入厂商名是为了避免重名。自定义属性名中通常也要有厂商名,并以逗号分隔。

    # #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。

            空属性并不一定表示没有赋值。如 interrupt-controller 一个空属性用来声明这个node接收中断信号

    数据类型

    “”     引号中的为字符串,字符串数组:”strint1”,”string2”,”string3”

    < >    尖括号中的为32位整形数字,整形数组<12 3 4>

    [ ]      方括号中的为32位十六进制数,十六机制数据[0x11 0x12 0x13]  其中0x可省略


    构成节点名的有效字符:

    0-9a-zA-Z,._+-

    构成属性名的有效字符:

    0-9a-zA-Z,._+?#


    DTS中几个难理解的属性的解释

    a. 地址

    设备的地址特性根据一下几个属性来控制:

    
     
    1. reg
    2. #address-cells
    3. #size-cells

    reg意为region,区域。格式为:

    reg = <address1length1 [address2 length2] [address3 length3]>;
     

    父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。

    address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell。本地模块例如:

    
     
    1. spi@ 10115000{
    2. compatible = "arm,pl022";
    3. reg = < 0x10115000 0x1000 >;
    4. };

    位于0x10115000的SPI设备申请地址空间,起始地址为0x10115000,长度为0x1000,即属于这个SPI设备的地址范围是0x10115000~0x10116000。

    实际应用中,有另外一种情况,就是通过外部芯片片选激活模块。例如,挂载在外部总线上,需要通过片选线工作的一些模块:

    
     
    1. external-bus{
    2. #address-cells = <2>
    3. #size-cells = <1>;
    4. ethernet@ 0, 0 {
    5. compatible = "smc,smc91c111";
    6. reg = < 0 0 0x1000>;
    7. };
    8. i2c@ 1, 0 {
    9. compatible = "acme,a1234-i2c-bus";
    10. #address-cells = <1>;
    11. #size-cells = <0>;
    12. reg = < 1 0 0x1000>;
    13. rtc@ 58 {
    14. compatible = "maxim,ds1338";
    15. reg = < 58>;
    16. };
    17. };
    18. flash@ 2, 0 {
    19. compatible = "samsung,k8f1315ebm", "cfi-flash";
    20. reg = < 2 0 0x4000000>;
    21. };
    22. };

    external-bus使用两个cell来描述地址,一个是片选序号,另一个是片选序号上的偏移量。而地址空间长度依然用一个cell来描述。所以以上的子设备们都需要3个cell来描述地址空间属性——片选、偏移量、地址长度。在上个例子中,有一个例外,就是i2c控制器模块下的rtc模块。因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells。

    当需要描述的设备不是本地设备时,就需要描述一个从设备地址空间到CPU地址空间的映射关系,这里就需要用到ranges属性。还是以上边的external-bus举例:

    
     
    1. #address-cells= <1>;
    2. #size-cells= <1>;
    3. ...
    4. external-bus{
    5. #address-cells = <2>
    6. #size-cells = <1>;
    7. ranges = < 0 0 0x10100000 0x10000 // Chipselect 1,Ethernet
    8. 1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
    9. 2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
    10. };

    ranges属性为一个地址转换表。表中的每一行都包含了子地址、父地址、在自地址空间内的区域大小。他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。以第一行为例:

    ·        0 0 两个cell,由子节点external-bus的address-cells=<2>决定;

    ·        0x10100000 一个cell,由父节点的address-cells=<1>决定;

    ·        0x10000 一个cell,由子节点external-bus的size-cells=<1>决定。
    最终第一行说明的意思就是:片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x10100000~0x10110000中,地址长度为0x10000。

    b. 中断

    描述中断连接需要四个属性:
    1. interrupt-controller 一个空属性用来声明这个node接收中断信号;
    2. #interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符;
    3. interrupt-parent 标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;
    4. interrupts 一个中断标识符列表,表示每一个中断输出信号。

    如果有两个,第一个是中断号,第二个是中断类型,如高电平、低电平、边缘触发等触发特性。对于给定的中断控制器,应该仔细阅读相关文档来确定其中断标识该如何解析。一般如下:

    二个cell的情况

    第一个值: 该中断位于他的中断控制器的索引;

    第二个值:触发的type

    固定的取值如下:

            1 = low-to-high edge triggered
            2 = high-to-low edge triggered
            4 = active high level-sensitive
            8 = active low level-sensitive


    三个cell的情况

    第一个值:中断号

    第二个值:触发的类型

    第三个值:优先级,0级是最高的,7级是最低的;其中0级的中断系统当做 FIQ处理。


    c. 其他

    除了以上规则外,也可以自己加一些自定义的属性和子节点,但是一定要符合以下的几个规则:

    1.    新的设备属性一定要以厂家名字做前缀,这样就可以避免他们会和当前的标准属性存在命名冲突问题;

    2.    新加的属性具体含义以及子节点必须加以文档描述,这样设备驱动开发者就知道怎么解释这些数据了。描述文档中必须特别说明compatible的value的意义,应该有什么属性,可以有哪个(些)子节点,以及这代表了什么设备。每个独立的compatible都应该由单独的解释。

    新添加的这些要发送到devicetree-discuss@lists.ozlabs.org邮件列表中进行review,并且检查是否会在将来引发其他的问题。

     

    DTS设备树描述文件中什么代表总线,什么代表设备

    一个含有compatible属性的节点就是一个设备。包含一组设备节点的父节点即为总线。

     

    由DTS到device_register的过程

    dts描述的设备树是如何通过register_device进行设备挂载的呢?我们来进行一下代码分析

     在arch/arm/mach-******/******.c找到DT_MACHINE_START 和 MACHINE_END 宏, 如下:

    
     
    1. DT_MACHINE_START(******_DT, "************* SoC (Flattened DeviceTree)")
    2. .atag_offset = 0x100,
    3. .dt_compat =******_dt_compat, // 匹配dts
    4. .map_io =******_map_io, // 板级地址内存映射, linux mmu
    5. .init_irq =irqchip_init, // 板级中断初始化.
    6. .init_time =******_timer_and_clk_init, // 板级时钟初始化,如ahb,apb等
    7. .init_machine = ******_dt_init, // 这里是解析dts文件入口.
    8. .restart =******_restart, // 重启, 看门狗寄存器相关可以在这里设置
    9. MACHINE_END
    其中.dt_compat    = ******_dt_compat 这个结构体是匹配是哪个dts文件, 如:
    
     
    1. static const char * const ******_dt_compat[] = {
    2. "******,******-soc",
    3. NULL
    4. };
    这个"******,******-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 这个是structof_device_id的全局变量.
    
     
    1. const struct of_device_id of_default_bus_match_table[] = {
    2. { .compatible = "simple-bus",},
    3. #ifdef CONFIG_ARM_AMBA
    4. { .compatible = "arm,amba-bus",},
    5. #endif /* CONFIG_ARM_AMBA */
    6. {} /* Empty terminated list */
    7. };
     我们设计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, 这个设备不会被注册
    
     
    1. for_each_child_of_node(root, child) {
    2. printk( "[%s %s %d]child->name = %s, child->full_name = %s\n", __FILE__, __func__,__LINE__, child->name, child->full_name);
    3. rc = of_platform_bus_create(child,matches, lookup, parent, true);
    4. if (rc)
    5. break;
    6. }
        论询dts根节点下的子设备, 每个子设备都要of_platform_bus_create(...);
        全部完成后, 通过 of_node_put(root);释放根节点, 因为已经处理完毕;

    3. drivers/of/platform.c : of_platform_bus_create(bus, ...)
      
    
     
    1. dev = of_platform_device_create_pdata(bus, bus_id,platform_data, parent); // 我们跳到 3-1步去运行
    2. if (!dev || !of_match_node(matches, bus)) // 就是匹配
    3. // dt_compat = ******_dt_compat, 也就是 compatible = "simple-bus",
    4. // 如果匹配成功, 以本节点为父节点, 继续轮询本节点下的所有子节点
    5. return 0;
    6. for_each_child_of_node(bus, child) {
    7. pr_debug( " create child:%s\n", child->full_name);
    8. rc = of_platform_bus_create(child,matches, lookup, &dev->dev, strict); // dev->dev以本节点为父节点, 我们跳到 3-2-1步去运行
    9. if (rc) {
    10. of_node_put(child);
    11. break;
    12. }
    13. }
    3-1. drivers/of/platform.c : of_platform_device_create_pdata(...)
    
     
    1. if (!of_device_is_available(np)) // 查看节点是否有效, 如果节点有'status'属性, 必须是okay或者是ok, 才是有效, 没有'status'属性, 也有效
    2. return NULL;
    3. dev = of_device_alloc(np, bus_id, parent); // alloc设备, 设备初始化. 返回dev, 所有的设备都可认为是platform_device, 跳到3-1-1看看函数做了什么事情
    4. if (!dev)
    5. return NULL;
    6. #if defined(CONFIG_MICROBLAZE)
    7. dev->archdata.dma_mask = 0xffffffffUL;
    8. #endif
    9. dev->dev.coherent_dma_mask =DMA_BIT_MASK( 32); // dev->dev 是 struct device. 继续初始化
    10. dev->dev.bus =&platform_bus_type; //
    11. dev->dev.platform_data =platform_data;
    12. printk( "[%s %s %d] of_device_add(device register)np->name = %s\n", __FILE__, __func__, __LINE__, np->name);
    13. if (of_device_add(dev) != 0){ // 注册device,of_device_add(...) --> device_add(...) // This is part 2 ofdevice_register()
    14. platform_device_put(dev);
    15. return NULL;
    16. }
    3-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
    
     
    1. dev->num_resources = num_reg +num_irq;
    2. dev->resource = res;
    3. for (i = 0; i < num_reg; i++, res++) {
    4. rc = of_address_to_resource(np,i, res);
    5. /*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); */
    6. WARN_ON(rc);
    7. }
    8. 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. drivers/of/platform.c : 
        以 compatible = "simple-bus"的节点的子节点都会以这个节点作为父节点在这步注册设备.

        至此从dts文件的解析到最终调用of_device_add进行设备注册的过程就比较清晰了。



    查看挂载上的所有设备

    cd /sys/devices/ 查看注册成功的设备  对应devicetree中的设备描述节点^-^


    声明:本文中部分内容参考 

    http://elinux.org/Device_Tree_Usage

    https://www.devicetree.org/specifications/

    http://blog.csdn.NET/eastonwoo/article/details/51498647

    http://blog.csdn.net/airk000/article/details/21345159


    http://elinux.org/Device_Tree_Usage
    5. 增加了支持**甘特图的mermaid语法[^1]** 功能; 6. 增加了 **多屏幕编辑** Markdown文章功能; 7. 增加了 **焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置** 等功能,功能按钮位于编辑区域与预览区域中间; 8. 增加了 **检查列表** 功能 [^1]: [mermaid语法说明](https://mermaidjs.github.io/) H 无序列表: Ctrl/Command + Shift + U 有序列表: Ctrl/Command + Shift + O 检查列表: Ctrl/Command + Shift + C 插入代码: Ctrl/Command + Shift + K 插入链接: Ctrl/Command + Shift + L 插入图片: Ctrl/Command + Shift + G

    合理的创建标题,有助于目录的生成

    直接输入1次#,并按下space后,将生成1级标题。
    输入2次#,并按下space后,将生成2级标题。
    以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

    如何改变文本的样式

    强调文本 强调文本

    加粗文本 加粗文本

    标记文本

    删除文本

    引用文本

    H2O is是液体。

    210 运算结果是 1024.

    插入链接与图片

    链接: link.

    图片: Alt

    带尺寸的图片: Alt

    居中的图片: Alt

    居中并且带尺寸的图片: Alt

    当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

    如何插入一段漂亮的代码片

    博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

    // An highlighted block
    var foo = 'bar';
    

    生成一个适合你的列表

    • 项目
      • 项目
        • 项目
    1. 项目1
    2. 项目2
    3. 项目3
    • 计划任务
    • 完成任务

    创建一个表格

    一个简单的表格是这么创建的:

    项目Value
    电脑$1600
    手机$12
    导管$1

    设定内容居中、居左、居右

    使用:---------:居中
    使用:----------居左
    使用----------:居右

    第一列第二列第三列
    第一列文本居中第二列文本居右第三列文本居左

    SmartyPants

    SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

    TYPEASCIIHTML
    Single backticks'Isn't this fun?'‘Isn’t this fun?’
    Quotes"Isn't this fun?"“Isn’t this fun?”
    Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

    创建一个自定义列表

    Markdown
    Text-to- HTML conversion tool
    Authors
    John
    Luke

    如何创建一个注脚

    一个具有注脚的文本。1

    注释也是必不可少的

    Markdown将文本转换为 HTML

    KaTeX数学公式

    您可以使用渲染LaTeX数学表达式 KaTeX:

    Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

    Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

    你可以找到更多关于的信息 LaTeX 数学表达式here.

    新的甘特图功能,丰富你的文章

    Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
    • 关于 甘特图 语法,参考 这儿,

    UML 图表

    可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

    张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

    这将产生一个流程图。:

    链接
    长方形
    圆角长方形
    菱形
    • 关于 Mermaid 语法,参考 这儿,

    FLowchart流程图

    我们依旧会支持flowchart的流程图:

    Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
    • 关于 Flowchart流程图 语法,参考 这儿.

    导出与导入

    导出

    如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

    导入

    如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
    继续你的创作。


    1. 注脚的解释 ↩︎

    展开全文
  • Linux dts list python tool

    千次阅读 2020-09-19 11:20:08
    Linux dts list python tool

    Windows Notepad - Save as - Encoding (ANSI)
    Windows Notepad - Edit - Replace... - replaces ? with blank

    @ gv.py
    out_file = ''
    temp_file = ''
    dt_dir_path = ''
    nr_plats = 1
    is_oem = False
    is_ext = False
    dts_name = ''

    arg0_proc_name = ''
    arg1_plat_name = ''

    @ dts_list.py
    ################################################
    # Show dts tree for msm platform
    # Author: George Tso
    # 2015-2016, all rights reserved.
    ################################################

    import sys,os
    import shutil
    import gv

    def print_usage(toast):
        if toast != '':
            print('\n' + toast)
        print("\nUsage: python " + gv.arg0_proc_name + " [OPTION...]\n")
        print("    If you want to print all the DT of one platform, you should")
        print("    assign the directory as the first argument, otherwise it ")
        print("    will use the current work directory.")
        print("    -o    list all the .dtsi files which belong to a .dts to")
        print("        a file")
        print("    -e    list all the .dtsi files which belong to a .dts to")
        print("        a file and copy the assciated .dtsi files to")
        print("        ." + os.path.sep + 'EXT\n')
        print("For example:")
        print("    Linux:")
        print("    python " + gv.arg0_proc_name + " msm8909")
        print("    python " + gv.arg0_proc_name + " ./ msm8909")
        print("    python " + gv.arg0_proc_name + " -o msm8909-1gb-qrd-skuc.dts")
        print("    python " + gv.arg0_proc_name + " -e msm8909-1gb-qrd-skuc.dts\n")
        print("    vi KERNEL-msm8909.list")
        print("    vi OEM-msm8909-1gb-qrd-skuc.dts.list")
        print("    vi ./EXT/OEM-msm8909-1gb-qrd-skuc.dts.list\n")

        print("    <------------------------------------------------>\n")
        print("    Windows:")
        print("    python " + gv.arg0_proc_name + " msm8909")
        print("    python " + gv.arg0_proc_name + " E:\F\case\dts_test msm8909")
        print("    python " + gv.arg0_proc_name + " -o E:\F\case\dts_test\msm8909-1gb-qrd-skuc.dts")
        print("    python " + gv.arg0_proc_name + " -e E:\F\case\dts_test\msm8909-1gb-qrd-skuc.dts\n")
        print("    Open E:\F\case\dts_test\KERNEL-msm8909.list with text editor")
        print("    Open E:\F\case\dts_test\OEM-msm8909-1gb-qrd-skuc.dts.list ")
        print("        with text editor")
        print("    Open E:\F\case\dts_test\EXT\OEM-msm8909-1gb-qrd-skuc.dts.list ")
        print("        with text editor\n")

    def write_file(f_name, line):
        h = open(f_name, 'a+')
        h.writelines(line)
        h.close()

    def contains_substring(src, sub):
        if sub in src:
            return True
        elif src.startswith(sub):
            return True
        else:
            return False

    def get_dt_list(dir_path, temp_file):
        for dts_file in os.listdir(dir_path):
            if contains_substring(dts_file, gv.arg1_plat_name) > 0:
                write_file(temp_file, dir_path + os.path.sep + dts_file + '\n')

    def list_one_tree(dt_file_path, h, out_file):
        fp = open(dt_file_path, 'r')
        for line in fp:
            p = line.lstrip(' ')
            if p.startswith('/*') or p.startswith('//'):
                continue

            if line.find('include') > 0 and line.find(".dts") > 0:
                if line.find("/include/") > 0:
                    idx = line.find('/include/')
                    idx += 9
                    p = line[idx:len(line)]
                elif line.find("#include") > 0:
                    idx = line.find('#include')
                    idx += 8
                    p = line[idx:len(line)]
                else:
                    idx = line.find('include')
                    idx += 7
                    p = line[idx:len(line)]

                p = p.lstrip('/').lstrip(' ').lstrip('\"').rstrip('\"')
                p = p.rstrip('\r').rstrip('\n').rstrip('\"')
                write_file(out_file, h + p + '\n')

                # Get the next
                p = p.rstrip('\r').rstrip('\n').lstrip('\"').rstrip('\"')
                p = gv.dt_dir_path + os.path.sep + p
                if os.path.exists(p):
                    list_one_tree(p, h + '-', out_file)
        fp.close()

    def walk_dt(dt_file_path, out_file, is_oem):
        p = dt_file_path

        idx = dt_file_path.find(os.path.sep)
        if idx > 0:
            idx += 1
            p = dt_file_path[idx:len(dt_file_path)]

        if p != '':
            write_file(out_file,
                    "/**************(" + str(gv.nr_plats) +
            ") platform*****************/\n")
            gv.nr_plats += 1

            p = p.rstrip('\r').rstrip('\n')
            idx = p.rfind(os.path.sep)
            if idx > 0:
                idx += 1
                _dts = p[idx:]
            else:
                _dts = p
            write_file(out_file, _dts + '\n')

            dt_file_path = dt_file_path.rstrip('\r').rstrip('\n')
            list_one_tree(dt_file_path, "-", out_file)
            write_file(out_file, "\n")

    def _show_dt(dir_path):
        h = open(gv.temp_file, 'r')
        for line in h:
            line = line.rstrip('\r').rstrip('\n')
            if line.endswith('.dts') == True:
                walk_dt(line, gv.out_file, False)
        h.close();

    def create_file(file):
        if os.path.exists(file):
            os.remove(file)

        h = open(file, 'w')
        h.write('Author: George Tso\n')
        h.write('If you have any good advice, you can contact me directly\n\n')
        h.close()

    def remove_file(file):
        if os.path.exists(file):
            os.remove(file)

    def show_dt():
        create_file(gv.temp_file)

        if len(gv.dt_dir_path) > 1:
            get_dt_list(gv.dt_dir_path, gv.temp_file)
            _show_dt(gv.dt_dir_path)

        remove_file(gv.temp_file)

    def remove_dir(dir_path):
        if os.path.isdir(dir_path):
            for file in os.listdir(dir_path):
                if (os.path.isdir(dir_path + os.path.sep + file)):
                    remove_dir(dir_path + os.path.sep + file)
                else:
                    os.remove(dir_path + os.path.sep + file)
            os.removedirs(dir_path)

    def extract_one_DT_to_EXT(file_path):
        if not os.path.exists(file_path):
            return

        is_found = False
        src_dir = gv.dt_dir_path
        dst_dir = gv.dt_dir_path

        h = open(file_path, 'r')
        for line in h:
            if line.find('*') > 0:
                is_found = True
                continue
            if (is_found == False):
                continue
            line = line.lstrip('-').lstrip('/').lstrip('\\')
            line = line.rstrip('\r').rstrip('\n').rstrip('\"')
            src_path = src_dir + os.path.sep + line
            dst_path = dst_dir + os.path.sep + 'EXT' + os.path.sep + line
            if os.path.exists(src_path) and not os.path.isdir(src_path):
                idx = dst_path.rfind(os.path.sep)
                tmp_dst_dir = dst_path[0:idx]
                if (os.path.exists(tmp_dst_dir) == False):
                    os.makedirs(tmp_dst_dir)
                shutil.copy(src_path, dst_path)

    def parse_args():
        if len(sys.argv) == 2:
            gv.dt_dir_path = os.getcwd()
            gv.arg1_plat_name = sys.argv[1]
        elif len(sys.argv) == 3:
            if not os.path.isdir(sys.argv[1]) and cmp(sys.argv[1], '-o') and cmp(sys.argv[1], '-e'):
                print_usage()
                sys.exit(0)
            elif not cmp(sys.argv[1], '-o'):
                gv.is_oem = True
                idx = sys.argv[2].rfind(os.path.sep)
                if idx > 0:
                    idx += 1
                    gv.dt_dir_path = sys.argv[2][0:idx]
                    gv.dts_name = sys.argv[2][idx:]
                else:
                    gv.dt_dir_path = os.getcwd()
                    gv.dts_name = sys.argv[2]
            elif not cmp(sys.argv[1], '-e'):
                gv.is_ext = True
                idx = sys.argv[2].rfind(os.path.sep)
                if idx > 0:
                    idx += 1
                    gv.dt_dir_path = sys.argv[2][0:idx]
                    gv.dts_name = sys.argv[2][idx:]
                else:
                    gv.dt_dir_path = os.getcwd()
                    gv.dts_name = sys.argv[2]
            else:
                gv.dt_dir_path = sys.argv[1]
                gv.arg1_plat_name = sys.argv[2]

        gv.dt_dir_path = gv.dt_dir_path.rstrip('\r').rstrip('\n')
        gv.temp_file = gv.dt_dir_path + os.path.sep + '.tmp.log'
        if gv.is_oem == True:
            gv.out_file = gv.dt_dir_path + os.path.sep + 'OEM-' + gv.dts_name + '.list'
        elif gv.is_ext == True:
            remove_dir(gv.dt_dir_path + os.path.sep + 'EXT')
            os.makedirs(gv.dt_dir_path + os.path.sep + 'EXT')
            gv.out_file = gv.dt_dir_path + os.path.sep + 'EXT' + os.path.sep + 'OEM-' + gv.dts_name + '.list'
        else:
            gv.out_file = gv.dt_dir_path + os.path.sep + 'KERNEL-' + gv.arg1_plat_name + '.list'

        print('\nDT directory: ' + gv.dt_dir_path)
        if gv.is_ext:
            print('\nEXT directory: ' + gv.dt_dir_path + os.path.sep + 'EXT' + os.path.sep)
        print('\nout file: ' + gv.out_file + '\n')
        create_file(gv.out_file)

    def main():
        gv.arg0_proc_name = sys.argv[0]
        if sys.argv[0].rfind(os.path.sep) > 0 :
            index = sys.argv[0].rfind(os.path.sep)
            gv.arg0_proc_name = sys.argv[0][index+1:]

        if len(sys.argv) < 2:
            print_usage('')
            sys.exit(0)

        parse_args()

        if gv.is_ext == True:
            walk_dt(gv.dt_dir_path + os.path.sep + gv.dts_name,
            gv.out_file, True)
            extract_one_DT_to_EXT(gv.out_file)
        elif gv.is_oem == True:
                walk_dt(gv.dt_dir_path + os.path.sep + gv.dts_name,
            gv.out_file, True)
        else:
            if gv.arg1_plat_name.find('.dts') > 0 or gv.arg1_plat_name.find('dtsi') > 0:
                print_usage('Invalid arguments')
                sys.exit(0)
            show_dt()

    if __name__ == '__main__':
        main()

    展开全文
  • linux DTS详解.pdf

    2020-07-31 14:04:47
    DTS 是为 Linux 提供一种硬件信息的描述方法,以此代替源码中的 硬件编码 (hard code)。DTS 即 Device Tree Source 设备树源码, Device Tree 是一种描述硬件的数据结构,起源于 OpenFirmware (OF). 在 Linux 2.6 中...
  • 1 前言关于设备树,之前就已经接触过许久了,但是本着够用的原则,基本上是哪里不会点哪里,现学现卖,没有再...2 概念2.1 什么是设备树 dts(device tree)?设备树(Device Tree)是描述计算机的特定硬件设备信息的数据...

    1 前言

    关于设备树,之前就已经接触过许久了,但是本着够用的原则,基本上是哪里不会点哪里,现学现卖,没有再进行全面性的总结,导致很多知识点都是比较碎片状,没有形成一个系统的知识网络,于是乎,决定挪用一部分打篮球的时间,整理一下这方面的思路,毕竟温故知新,感觉会收获良多。

    2 概念

    2.1 什么是设备树 dts(device tree)?

    设备树(Device Tree)是描述计算机的特定硬件设备信息的数据结构,以便于操作系统的内核可以管理和使用这些硬件,包括CPU或CPU,内存,总线和其他一些外设。

    设备树是通过Open Firmware项目从基于SPARC的工作站和服务器派生而来的。当前的Devicetree一般针对嵌入式系统,但仍然与某些服务器级系统一起使用(例如,Power Architecture Platform Reference所描述的系统)。

    然而x86架构的个人计算机通常不使用设备树,而是依靠各种自动配置协议来识别硬件。使用设备树的系统通常将静态设备树(可能存储在ROM中)传递给操作系统,但也可以在引导的早期阶段生成设备树。例如,U-Boot和kexec可以在启动新操作系统时传递设备树。一些系统使用的引导加载程序可能不支持设备树,但是可以与操作系统一起安装静态设备树,Linux内核支持这种方法。

    Device Tree规范目前由名为devicetree.org的社区管理,该社区与Linaro和Arm等相关联。

    2.2 使用设备树的优势有哪些?

    Linux内核从3.x版本之后开始支持使用设备树,这样做的意义重大,可以实现驱动代码与设备的硬件信息相互的隔离,减少了代码中的耦合性,在此之前,一些与硬件设备相关的具体信息都要写在驱动代码中,如果外设发生相应的变化,那么驱动代码就需要改动。但是在引入了设备树之后,这种尴尬的情况找到了解决的办法,通过设备树对硬件信息的抽象,驱动代码只要负责处理逻辑,而关于设备的具体信息存放到设备树文件中,这样,如果只是硬件接口信息的变化而没有驱动逻辑的变化,开发者只需要修改设备树文件信息,不需要改写驱动代码。

    3 简介

    3.1 dts

    硬件的相应信息都会写在.dts为后缀的文件中,每一款硬件可以单独写一份xxxx.dts,一般在Linux源码中存在大量的dts文件,对于arm架构可以在arch/arm/boot/dts找到相应的dts,另外mips则在arch/mips/boot/dts,powerpc在arch/powerpc/boot/dts。

    3.2 dtsi

    值得一提的是,对于一些相同的dts配置可以抽象到dtsi文件中,然后类似于C语言的方式可以include到dts文件中,对于同一个节点的设置情况,dts中的配置会覆盖dtsi中的配置。具体如下图所示;

    3.3 dtc

    dtc是编译dts的工具,可以在Ubuntu系统上通过指令apt-get install device-tree-compiler安装dtc工具,不过在内核源码scripts/dtc路径下已经包含了dtc工具;

    3.4 dtb

    dtb(Device Tree Blob),dts经过dtc编译之后会得到dtb文件,dtb通过Bootloader引导程序加载到内核。所以Bootloader需要支持设备树才行;Kernel也需要加入设备树的支持;

    4 基本框架

    下图是一个设备树文件的基本架构;大概看了一下有点类似于XML文件,简单概括一下有这几个部分;

    根节点:\

    设备节点:nodex

    节点名称:图中node;

    节点地址:node@0就是节点的地址;

    子节点:childnode

    属性:属性名称(Property name)和属性值(Property value)

    标签

    具体如下图所示;

    展开全文
  • Android 驱动(12)---Linux DTS(Device Tree Source)设备树详解.pdf
  • 本系列导航:高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)高通平台8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)高通平台8953 Linux DTS(Device Tree ...

    本系列导航:

    高通平台8953  Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)

    高通平台8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)

    高通平台8953 Linux DTS(Device Tree Source)设备树详解之三(高通MSM8953 android7.1实例分析篇)


    有上一篇文章,我们了解了dts的背景知识和相关基础,这次我们对应实际设备进行一下相关分析。

     

    DTS设备树的匹配过程

    一个dts文件确定一个项目,多个项目可以包含同一个dtsi文件。找到该项目对应的dts文件即找到了该设备树的根节点。

    kernel\arch\arm\boot\dts\qcom\sdm630-mtp.dts

    [objc]  view plain  copy
    1. /* Copyright (c) 2017, The Linux Foundation. All rights reserved. 
    2.  * 
    3.  * This program is free software; you can redistribute it and/or modify 
    4.  * it under the terms of the GNU General Public License version 2 and 
    5.  * only version 2 as published by the Free Software Foundation. 
    6.  * 
    7.  * This program is distributed in the hope that it will be useful, 
    8.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
    9.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    10.  * GNU General Public License for more details. 
    11.  */  
    12.   
    13.   
    14. /dts-v1/;  
    15.   
    16. #include "sdm630.dtsi"  
    17. #include "sdm630-mtp.dtsi"  
    18. //#include "sdm660-external-codec.dtsi"  
    19. #include "sdm660-internal-codec.dtsi"  
    20. #include "synaptics-dsx-i2c.dtsi"  
    21.   
    22.   
    23. / {  
    24.     model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660L MTP";  
    25.     compatible = "qcom,sdm630-mtp""qcom,sdm630""qcom,mtp";  
    26.     qcom,board-id = <8 0>;  
    27.     qcom,pmic-id = <0x00010010x01010110x0 0x0>,  
    28.             <0x00010010x02010110x0 0x0>;  
    29. };  
    30.   
    31. &tavil_snd {  
    32.     qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;  
    33. };  

    当然devicetree的根节点也是需要和板子进行匹配的,这个匹配信息存放在sbl(second boot loader)中,对应dts文件中描述的board-id(上面代码中的qcom,board-id属性),通过共享内存传递给bootloader,由bootloader将此board-id匹配dts文件(devicetree的根节点文件),将由dtc编译后的dts文件(dtb文件)加载到内存,然后在kernel中展开dts树,并且挂载dts树上的所有设备。

    (ps:cat /proc/cmdline 查看cmdline)

     

    Dts中相关符号的含义

    /        根节点

    @     如果设备有地址,则由此符号指定

    &     引用节点

    :        冒号前的label是为了方便引用给节点起的别名,此label一般使用为&label

    ,        属性名称中可以包含逗号。如compatible属性的名字 组成方式为"[manufacturer], [model]",加入厂商名是为了避免重名。自定义属性名中通常也要有厂商名,并以逗号分隔。

    # #并不表示注释。如 #address-cells ,#size-cells 用来决定reg属性的格式。

            空属性并不一定表示没有赋值。如 interrupt-controller 一个空属性用来声明这个node接收中断信号

    数据类型

    “”     引号中的为字符串,字符串数组:”strint1”,”string2”,”string3”

    < >    尖括号中的为32位整形数字,整形数组<12 3 4>

    [ ]      方括号中的为32位十六进制数,十六机制数据[0x11 0x12 0x13]  其中0x可省略


    构成节点名的有效字符:

    0-9a-zA-Z,._+-

    构成属性名的有效字符:

    0-9a-zA-Z,._+?#


    DTS中几个难理解的属性的解释

    a. 地址

    设备的地址特性根据一下几个属性来控制:

    [objc]  view plain  copy
    1. reg  
    2. #address-cells  
    3. #size-cells  

    reg意为region,区域。格式为:

    [objc]  view plain  copy
    1. reg = <address1length1 [address2 length2] [address3 length3]>;  

    父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。

    address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell。本地模块例如:

    [objc]  view plain  copy
    1. spi@10115000{  
    2.         compatible = "arm,pl022";  
    3.         reg = <0x10115000 0x1000 >;  
    4. };  

    位于0x10115000的SPI设备申请地址空间,起始地址为0x10115000,长度为0x1000,即属于这个SPI设备的地址范围是0x10115000~0x10116000。

    实际应用中,有另外一种情况,就是通过外部芯片片选激活模块。例如,挂载在外部总线上,需要通过片选线工作的一些模块:

    [objc]  view plain  copy
    1. external-bus{  
    2.     #address-cells = <2>  
    3.     #size-cells = <1>;  
    4.    
    5.     ethernet@0,0 {  
    6.         compatible = "smc,smc91c111";  
    7.         reg = <0 0 0x1000>;  
    8.     };  
    9.    
    10.     i2c@1,0 {  
    11.         compatible ="acme,a1234-i2c-bus";  
    12.         #address-cells = <1>;  
    13.         #size-cells = <0>;  
    14.         reg = <1 0 0x1000>;  
    15.         rtc@58 {  
    16.             compatible ="maxim,ds1338";  
    17.             reg = <58>;  
    18.         };  
    19.     };  
    20.    
    21.     flash@2,0 {  
    22.         compatible ="samsung,k8f1315ebm""cfi-flash";  
    23.         reg = <2 0 0x4000000>;  
    24.     };  
    25. };  

    external-bus使用两个cell来描述地址,一个是片选序号,另一个是片选序号上的偏移量。而地址空间长度依然用一个cell来描述。所以以上的子设备们都需要3个cell来描述地址空间属性——片选、偏移量、地址长度。在上个例子中,有一个例外,就是i2c控制器模块下的rtc模块。因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells。

    当需要描述的设备不是本地设备时,就需要描述一个从设备地址空间到CPU地址空间的映射关系,这里就需要用到ranges属性。还是以上边的external-bus举例:

    [objc]  view plain  copy
    1. #address-cells= <1>;  
    2. #size-cells= <1>;  
    3. ...  
    4. external-bus{  
    5.     #address-cells = <2>  
    6.     #size-cells = <1>;  
    7.     ranges = <0 0  0x10100000  0x10000     // Chipselect 1,Ethernet  
    8.               1 0  0x10160000  0x10000     // Chipselect 2, i2c controller  
    9.               2 0  0x30000000  0x1000000>; // Chipselect 3, NOR Flash  
    10. };  

    ranges属性为一个地址转换表。表中的每一行都包含了子地址、父地址、在自地址空间内的区域大小。他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。以第一行为例:

    ·        0 0 两个cell,由子节点external-bus的address-cells=<2>决定;

    ·        0x10100000 一个cell,由父节点的address-cells=<1>决定;

    ·        0x10000 一个cell,由子节点external-bus的size-cells=<1>决定。
    最终第一行说明的意思就是:片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x10100000~0x10110000中,地址长度为0x10000。

    b. 中断

    描述中断连接需要四个属性:
    1. interrupt-controller 一个空属性用来声明这个node接收中断信号;
    2. #interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符;
    3. interrupt-parent 标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;
    4. interrupts 一个中断标识符列表,表示每一个中断输出信号。

    如果有两个,第一个是中断号,第二个是中断类型,如高电平、低电平、边缘触发等触发特性。对于给定的中断控制器,应该仔细阅读相关文档来确定其中断标识该如何解析。一般如下:

    二个cell的情况

    第一个值: 该中断位于他的中断控制器的索引;

    第二个值:触发的type

    固定的取值如下:

            1 = low-to-high edge triggered
            2 = high-to-low edge triggered
            4 = active high level-sensitive
            8 = active low level-sensitive


    三个cell的情况

    第一个值:中断号

    第二个值:触发的类型

    第三个值:优先级,0级是最高的,7级是最低的;其中0级的中断系统当做 FIQ处理。


    c. 其他

    除了以上规则外,也可以自己加一些自定义的属性和子节点,但是一定要符合以下的几个规则:

    1.    新的设备属性一定要以厂家名字做前缀,这样就可以避免他们会和当前的标准属性存在命名冲突问题;

    2.    新加的属性具体含义以及子节点必须加以文档描述,这样设备驱动开发者就知道怎么解释这些数据了。描述文档中必须特别说明compatible的value的意义,应该有什么属性,可以有哪个(些)子节点,以及这代表了什么设备。每个独立的compatible都应该由单独的解释。

    新添加的这些要发送到devicetree-discuss@lists.ozlabs.org邮件列表中进行review,并且检查是否会在将来引发其他的问题。

     

    DTS设备树描述文件中什么代表总线,什么代表设备

    一个含有compatible属性的节点就是一个设备。包含一组设备节点的父节点即为总线。

     

    由DTS到device_register的过程

    dts描述的设备树是如何通过register_device进行设备挂载的呢?我们来进行一下代码分析

     在arch/arm/mach-******/******.c找到DT_MACHINE_START 和 MACHINE_END 宏, 如下:

    [objc]  view plain  copy
    1. DT_MACHINE_START(******_DT, "************* SoC (Flattened DeviceTree)")  
    2.     .atag_offset    = 0x100,  
    3.     .dt_compat    =******_dt_compat,                // 匹配dts  
    4.     .map_io        =******_map_io,                   // 板级地址内存映射, linux mmu  
    5.     .init_irq    =irqchip_init,                    // 板级中断初始化.  
    6.     .init_time    =******_timer_and_clk_init,        // 板级时钟初始化,如ahb,apb等   
    7.     .init_machine   = ******_dt_init,              // 这里是解析dts文件入口.  
    8.     .restart    =******_restart,                  // 重启, 看门狗寄存器相关可以在这里设置  
    9. MACHINE_END  
    其中.dt_compat    = ******_dt_compat 这个结构体是匹配是哪个dts文件, 如:
    [objc]  view plain  copy
    1. static const charchar * constconst ******_dt_compat[] = {  
    2.     "******,******-soc",  
    3.     NULL  
    4. };  
    这个"******,******-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 这个是structof_device_id的全局变量.
    [objc]  view plain  copy
    1. const struct of_device_id of_default_bus_match_table[] = {  
    2.      { .compatible = "simple-bus",},  
    3.  #ifdef CONFIG_ARM_AMBA  
    4.      { .compatible = "arm,amba-bus",},  
    5.  #endif /* CONFIG_ARM_AMBA */  
    6.      {} /* Empty terminated list */  
    7.  };  
     我们设计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, 这个设备不会被注册
    [objc]  view plain  copy
    1. for_each_child_of_node(root, child) {  
    2.     printk("[%s %s %d]child->name = %s, child->full_name = %s\n", __FILE__, __func__,__LINE__, child->name, child->full_name);  
    3.     rc = of_platform_bus_create(child,matches, lookup, parent, true);  
    4.     if (rc)  
    5.         break;  
    6. }  
        论询dts根节点下的子设备, 每个子设备都要of_platform_bus_create(...);
        全部完成后, 通过 of_node_put(root);释放根节点, 因为已经处理完毕;

    3. drivers/of/platform.c : of_platform_bus_create(bus, ...)
      
    [objc]  view plain  copy
    1. dev = of_platform_device_create_pdata(bus, bus_id,platform_data, parent); // 我们跳到 3-1步去运行  
    2.   if (!dev || !of_match_node(matches, bus))  // 就是匹配  
    3.                                             // dt_compat    = ******_dt_compat, 也就是 compatible = "simple-bus",   
    4.                                             // 如果匹配成功, 以本节点为父节点, 继续轮询本节点下的所有子节点  
    5.       return 0;  
    6.   
    7.   for_each_child_of_node(bus, child) {  
    8.       pr_debug("   create child:%s\n", child->full_name);  
    9.       rc = of_platform_bus_create(child,matches, lookup, &dev->dev, strict);  // dev->dev以本节点为父节点,  我们跳到 3-2-1步去运行  
    10.       if (rc) {  
    11.           of_node_put(child);  
    12.           break;  
    13.       }  
    14.   }  
    3-1. drivers/of/platform.c : of_platform_device_create_pdata(...)
    [objc]  view plain  copy
    1. if (!of_device_is_available(np))   // 查看节点是否有效, 如果节点有'status'属性, 必须是okay或者是ok, 才是有效, 没有'status'属性, 也有效  
    2.     return NULL;  
    3.   
    4. dev = of_device_alloc(np, bus_id, parent);  // alloc设备, 设备初始化. 返回dev, 所有的设备都可认为是platform_device, 跳到3-1-1看看函数做了什么事情  
    5. if (!dev)  
    6.     return NULL;  
    7.   
    8. #if defined(CONFIG_MICROBLAZE)  
    9.     dev->archdata.dma_mask = 0xffffffffUL;  
    10. #endif  
    11.     dev->dev.coherent_dma_mask =DMA_BIT_MASK(32); // dev->dev 是 struct device. 继续初始化  
    12.     dev->dev.bus =&platform_bus_type;     //   
    13.     dev->dev.platform_data =platform_data;  
    14.   
    15. printk("[%s %s %d] of_device_add(device register)np->name = %s\n", __FILE__, __func__, __LINE__, np->name);  
    16. if (of_device_add(dev) != 0){       // 注册device,of_device_add(...) --> device_add(...) // This is part 2 ofdevice_register()  
    17.     platform_device_put(dev);  
    18.     return NULL;  
    19. }  
    3-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
    [objc]  view plain  copy
    1. dev->num_resources = num_reg +num_irq;  
    2. dev->resource = res;  
    3. for (i = 0; i < num_reg; i++, res++) {  
    4.     rc = of_address_to_resource(np,i, res);  
    5.     /*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); */  
    6.     WARN_ON(rc);  
    7. }  
    8. 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. drivers/of/platform.c :  
        以 compatible = "simple-bus"的节点的子节点都会以这个节点作为父节点在这步注册设备.

        至此从dts文件的解析到最终调用of_device_add进行设备注册的过程就比较清晰了。



    查看挂载上的所有设备

    cd /sys/devices/ 查看注册成功的设备  对应devicetree中的设备描述节点


    ##########################################################

      欢迎广大学子交流嵌入式和安卓开发

      aiku老师 微信号  :aiku868

       微信公众平台:aiku嵌入式视频教程创科之龙

       aiku老师QQ:1653687969

       技术解答QQ群:234945702


    ##########################################################



    展开全文
  • Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) Linux DTS(Device Tree Source)设备树详解之二 Linux DTS(Device Tree Source)设备树详解之三(高通MSM8953实例分析篇) 一.什么是DTS?为什么要引入DTS...
  • linux DTS介绍

    2019-07-04 23:45:00
    一. 设备树的由来 1.1. 什么是设备树 1.1.1. Device Tree 可以描述的信息包括CPU的数量和类别,内存基地址和大小,总线和桥,外设连接,中断控制器和中断使用情况,...类似于XML文件,在ARM linux中,一个.dts...
  • Linux dts 详解

    千次阅读 2019-03-07 22:07:53
    https://blog.csdn.net/radianceblau/article/details/70800076 https://blog.csdn.net/radianceblau/article/details/74722395 https://blog.csdn.net/radianceblau/article/details/76574727 ...
  • Linux DTS中和中断相关属性的解释和用法前言中断控制器的硬件结构(基于Exynos4412 ARMv7)GIC功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的...
  • linux dts interrupt

    千次阅读 2016-12-01 00:15:26
    http://blog.chinaunix.net/uid-12461657-id-3064012.html https://community.nxp.com/message/597984 1. dts configuration arch/arm/boot/dts/imx6sl-evk.dts: interrupt-parent = ;
  • Linux DTS(Device Tree Source)设备树详解 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇) Linux DTS(Device Tree Source)设备树详解之二 Linux DTS(Device Tree Source)设备树详解之三(高通MSM...
  • Linux dts 删除一个node或者属性 一、dts删除一个Node,/delete-node/与节点名之间有空格,如果节点中有地址信息,节点名后也需要加上。 /delete-node/ 节点名; 二、dts删除属性property,注意/delete-...
  • 本系列导航:高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)高通平台8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)高通平台8953 Linux DTS(Device Tree ...
  • 预留的内存区域需要从linux内核的使用区域中分离出来,仅给特定的驱动程序使用,通过memory-region参数将预留的内存空间分配给特定的设备驱动程序使用。 shared-dma-pool compatible="shared-dma-pool" 有的...
  • Linux dts解析phandle

    2020-09-10 19:38:09
    在每个dts的设备节点下device_node,如果有交叉引用其他设备节点的,即反编译出来的dts文件中有引用对应的phandle的,可用如下方法解析。 timer4_pins:timer4_pin_default{ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP...
  • Linux DTS(Device Tree Source)设备树详解之二(dts匹配及发挥作用的流程篇)     一个dts文件确定一个项目,多个项目可以包含同一个dtsi文件。找到该项目对应的dts文件即找到了该设备树的根节点 kernel\arch\...
  • linux DTS 分析

    千次阅读 2015-10-30 18:28:32
    1、现在实用的内核3.10已经开始实用DTS方法。 2、bootloader启动时将加载dtb给内核,内核分析dtb即可知道machine,所以bootloader 不再需要传递设备ID号。 例如:/ { compatible = "rockchip,rk3288";//即可...
  • 高通平台8953 Linux DTS(Device Tree Source)设备树详解之三(高通MSM8953 android7.1实例分析篇)本系列导航:高通平台8953 Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)高通平台8953 Linux DTS...
  • -src-freq = 为内核提供给bus得时钟 可不做配置 默认19.2M 写死后系统会用配置得进行deide 来进行寄存器得配置 2、在这里配置的是bus规范,实际bus上一般都挂载N个client ,在client得dts文件中需要引用这些来配置 ...
  • Linux DTS(Device Tree Source)设备树详解之一 Linux DTS(Device Tree Source)设备树详解之二 在前两篇中我们了解了DTS的背景基础知识以及发挥作用的流程,这篇文章我们以高通的MSM8953平台为例来添加一个基础...
  • Linux dts 设备树详解(一) 基础知识

    万次阅读 多人点赞 2019-05-06 22:56:31
    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2.2 使用设备树的优势有哪些? 3 简介 3.1 dts 3.2 dtsi 3.3 dtc 3.4 ...
  • 因为会涉及到很多硬件信息的绑定,详细的可以查阅Linux内核源码下的文档`Documentation/devicetree/bindings`。具体如下图所示; ![设备树文档](https://img-blog.csdnimg.cn/20190612082729898.png)
  • linux DTS gpio example

    千次阅读 2016-11-20 10:13:17
    http://developer.t-firefly.com/thread-648-1-1.html http://v.youku.com/v_show/id_XODY4NTA3OTcy.html?from=s1.8-1-1.2&spm=a2h0k.8191407.0.0 1. add configuration in dts hello-led{ compatible =
  • Linux dts设备树gpio配置

    千次阅读 2020-07-13 10:31:23
    给大伙分享下在DTS中如何配置GPIO口: download_pin { sp_reset_gpio = <&pio PB 7 1 1 2 0>; }; 在上面例子dts片段例子中,这句话的解析是: sp_reset_gpio :管脚名字,随便取,和driver代码对应...
  • Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的 platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些 板级细..
  • Linux DTS配置总结

    千次阅读 2013-05-31 15:31:31
    2、在这里配置的是bus规范,实际bus上一般都挂载N个client ,在client得dts文件中需要引用这些来配置 对应得f9966000 地址需要正确如:  i2c-1@f9927000 { /* BLSP1 QUP5 */   my_i2c_name @20 {  ...
  • 前言Linux Device Tree中定义了很多和中断相关的属性,这些属性之间的关系错综复杂。为剖析这些关系,特地查阅文档后输出本文。本文基于ARM平台,主要说明如下几个属性:interrupt-controllerinterrupt-...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,701
精华内容 5,880
关键字:

Linuxdts