前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux笔记(23)| “插件”设备树

Linux笔记(23)| “插件”设备树

作者头像
飞哥
发布2021-03-03 11:14:58
2.2K0
发布2021-03-03 11:14:58
举报

今天和大家分享的依然是设备树,上一节里主要是介绍了设备树文件的基本格式、语法规则等,今天介绍一下如何使用设备树,以及如何动态加载设备树。

设备树里记录的是“资源”,比如我们要点亮led,就可以增加一个led的节点,把led相关的寄存器放在这个节点里。

代码语言:javascript
复制
rgb_led{
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "fire,rgb_led";

    /*红灯节点*/
    ranges;
    rgb_led_red@0x020C406C{
      compatible = "fire,rgb_led_red";
      reg = <0x020C406C 0x00000004
             0x020E006C 0x00000004
             0x020E02F8 0x00000004
           0x0209C000 0x00000004
             0x0209C004 0x00000004>;
      status = "okay";
    };

    /*绿灯节点*/
    rgb_led_green@0x020C4074{
      compatible = "fire,rgb_led_green";
      reg = <0x020C4074 0x00000004
             0x020E01E0 0x00000004
             0x020E046C 0x00000004
           0x020A8000 0x00000004
             0x020A8004 0x00000004>;
      status = "okay";
    };

    /*蓝灯节点*/
    rgb_led_blue@0x020C4074{
      compatible = "fire,rgb_led_blue";
      reg = <0x020C4074 0x00000004
             0x020E01DC 0x00000004
             0x020E0468 0x00000004
           0x020A8000 0x00000004
             0x020A8004 0x00000004>;
      status = "okay";
    };
  };

rgb_led就是在根节点下的一个节点,在这个节点里面又有3个子节点,代表3颗led,里面用#address-cells = <1>#size-cells = <1>用来表示寄存器(子节点的reg属性)的地址宽度是32位的,长度是一个字长(也是32位)。

这样我们的设备树文件就写好了,参照上一节的做法,我们修改完设备树文件,然后进行编译,将生成的dtb文件替换开发板原来的dtb文件,然后重启开发板即可。

这里需要注意的一点就是,我们使用cp命令进行拷贝的时候,拷贝完最好使用sync命令进行同步,sync的作用就是将缓冲区的内容写到磁盘上,如果没有使用sync就直接给开发板断电,可能会造成数据的丢失,到时可能因为无效的设备树文件导致系统启动不了。

因为我为了确保开发板的dtb文件是我新生成的,所以在拷贝之前,我把原来的删掉了,再进行拷贝,而如果拷贝失败,就会导致dtb文件缺失。如果不把原来的删除,而直接使用cp命令拷贝,即使拷贝失败,也不会因为dtb文件缺失而启动不了。另外,重启开发板可以断电重启,也可以使用reboot命令重启,使用reboot命令重启应该会更安全一些,不容易数据丢失。如果非要断电重启,最好在断电之前敲几次sync命令。

设备树文件写好了,接下来就是写驱动文件了。其实驱动文件和我们之前在Linux笔记(21)| platform总线驱动分析介绍的基本是一样的,唯一的不同就是资源获取方式不一样,之前是在设备文件中获取,现在是在设备树文件上获取。所以重点说一下这个部分,其他的就不赘述了。

我们先定义一个led_resource类型的结构体,用来存放led相关的资源,在这个结构体里有led相关的寄存器地址(注意这个是虚拟地址),还有设备节点device_node。

代码语言:javascript
复制
struct led_resource
{
  struct device_node *device_node; //rgb_led_red的设备树节点
  void __iomem *virtual_CCM_CCGR;
  void __iomem *virtual_IOMUXC_SW_MUX_CTL_PAD;
  void __iomem *virtual_IOMUXC_SW_PAD_CTL_PAD;
  void __iomem *virtual_DR;
  void __iomem *virtual_GDIR;
};

我们实际上要调用of_find_node_by_path等一系列函数从设备树上获取资源,返回值用上面的device_node来接收。然后将device_node里面拿到的真实的物理地址进行虚拟地址映射,得到虚拟地址放在上面的结构体成员里面。然后就像裸机里面一样了,进行硬件初始化工作,给应用层提供一些接口。

因为这里是操作led,本身比较简单,所以不需要提供什么接口,只需要把对硬件的操作写好就行了。约定好从应用层接收到什么数据就进行什么操作。

整个的操作流程可以简单表示如下:

具体的说明可以参照平台总线那一节。这样基本上就完成了。

但是这样还不够好,因为每次修改设备树文件,都要修改内核源码,然后编译、拷贝、重启开发板。这样还是挺不方便的。尤其像内核源码,不应该随随便便去修改,这样子是不太安全的。

所以可以使用动态加载的方法。

动态加载的方法,首先也是写一个设备树文件,不过这个不是去内核源码修改,而是单独的一个文件,然后编译生成.dtbo文件。最后修改/boot/目录下的uEnv.txt文件,把dtbo文件加进去,最后reboot重启即可。关于这部分的详细操作,我们以后再介绍。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-02-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 电子技术研习社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档