首页 > 系统相关 >ARM Linux 设备树详细介绍(2)共二篇

ARM Linux 设备树详细介绍(2)共二篇

时间:2024-06-17 21:31:09浏览次数:24  
标签:二篇 结点 const Tree machine Linux device compatible ARM

承接上文,第一篇

        3. Device&Tree 引发的 BSP 和驱动变更

        有了 Device Tree 后,大量的板级信息都不再需要,譬如过去经常在 arch/arm/plat-xxx 和 arch/arm/mach-xxx 实施的如下事情:

        1. 注册 platform_device,绑定 resource,即内存、IRQ 等板级信息。

        透过 Device Tree 后,形如

                

       之类的 platform_device 代码都不再需要,其中 platform_device 会由 kernel 自动展开。而这 些 resource 实际来源于.dts 中设备结点的 reg、interrupts 属性。

        典型地,大多数总线都与“simple_bus”兼容,而在 SoC 对应的 machine 的.init_machine 成员函数中,调用 of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL);即可自动展开所有 的 platform_device。譬如,假设我们有个 XXX SoC,则可在 arch/arm/mach-xxx/的板文件 中透过如下方式展开.dts 中的设备结点对应的 platform_device:

                        

        2. 注册 i2c_board_info,指定 IRQ 等板级信息。 形如

                        

        之类的 i2c_board_info 代码,目前不再需要出现,现在只需要把 tlv320aic23、fm3130、 24c64 这些设备结点填充作为相应的 I 2 C controller 结点的子结点即可,类似于前面的

                        

        之类的 spi_board_info 代码,目前不再需要出现,与 I 2 C 类似,现在只需要把 mtd_dataflash 之类的结点,作为 SPI 控制器的子结点即可,SPI host 驱动的 probe 函数透过 spi_register_master()注册 master 的时候,会自动展开依附于它的 slave。

        4. 多个针对不同电路板的 machine,以及相关的 callback。

        过去,ARM Linux 针对不同的电路板会建立由 MACHINE_START 和 MACHINE_END 包围起来的针对这个 machine 的一系列 callback,譬如:

                        

        这些不同的 machine 会有不同的 MACHINE ID,Uboot 在启动 Linux 内核时会将 MACHINE ID 存放在 r1 寄存器,Linux 启动时会匹配 Bootloader 传递的 MACHINE ID 和 MACHINE_START 声明的 MACHINE ID,然后执行相应 machine 的一系列初始化函数。

        引入 Device Tree 之后,MACHINE_START 变更为 DT_MACHINE_START,其中 含有一个.dt_compat 成员,用于表明相关的 machine 与.dts 中 root 结点的 compatible 属性兼 容关系。如果 Bootloader 传递给内核的 Device Tree 中 root 结点的 compatible 属性出现在某 machine 的.dt_compat 表中,相关的 machine 就与对应的 Device Tree 匹配,从而引发这一 machine 的一系列初始化函数被执行。

                        

        Linux 倡导针对多个 SoC、多个电路板的通用 DT machine,即一个 DT machine 的.dt_compat 表含多个电路板.dts 文件的 root 结点 compatible 属性字符串。之后,如果的电 路板的初始化序列不一样,可以透过 int of_machine_is_compatible(const char *compat) API 判断具体的电路板是什么。

        譬如 arch/arm/mach-exynos/mach-exynos5-dt.c 的 EXYNOS5_DT machine 同时兼容 "samsung,exynos5250"和"samsung,exynos5440":

                

        它的.init_machine 成员函数就针对不同的 machine 进行了不同的分支处理:

                        

        使用 Device Tree 后,驱动需要与.dts 中描述的设备结点进行匹配,从而引发驱动的 probe()函数执行。对于 platform_driver 而言,需要添加一个 OF 匹配表,如前文的.dts 文件 的"acme,a1234-i2c-bus"兼容 I 2 C 控制器结点的 OF 匹配表可以是:

                        

        对于 I2C 和 SPI 从设备而言,同样也可以透过 of_match_table 添加匹配的.dts 中的 相关结点的 compatible 属性,如 sound/soc/codecs/wm8753.c 中的:

                        

        不过这边有一点需要提醒的是,I 2 C 和 SPI 外设驱动和 Device Tree 中设备结点的 compatible 属性还有一种弱式匹配方法,就是别名匹配。compatible 属性的组织形式为 ,,别名其实就是去掉 compatible 属性中逗号前的 manufacturer 前缀。 关于这一点,可查看 drivers/spi/spi.c 的源代码,函数 spi_match_device()暴露了更多的细节, 如果别名出现在设备 spi_driver 的 id_table 里面,或者别名与 spi_driver 的 name 字段相同, SPI 设备和驱动都可以匹配上:

                

        4. 常用 OF&API

        在 Linux 的 BSP 和驱动代码中,还经常会使用到 Linux 中一组 Device Tree 的 API, 这些 API 通常被冠以 of_前缀,它们的实现代码位于内核的 drivers/of 目录。这些常用的 API 包括:

        int of_device_is_compatible(const struct device_node *device,const char *compat);

        判断设备结点的 compatible 属性是否包含 compat 指定的字符串。当一个驱动支持 2 个或多个设备的时候,这些不同.dts 文件中设备的 compatible 属性都会进入驱动 OF 匹配 表。因此驱动可以透过 Bootloader 传递给内核的 Device Tree 中的真正结点的 compatible 属 性以确定究竟是哪一种设备,从而根据不同的设备类型进行不同的处理。如 drivers/pinctrl/pinctrl-sirf.c 即兼容于"sirf,prima2-pinctrl",又兼容于"sirf,prima2-pinctrl",在驱 动中就有相应分支处理:

       

        struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);

        根据 compatible 属性,获得设备结点。遍历 Device Tree 中所有的设备结点,看看 哪个结点的类型、compatible 属性与本函数的输入参数匹配,大多数情况下,from、type 为 NULL。

        int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz);

        int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz);

        int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz);

        int of_property_read_u64(const struct device_node *np, const char *propname, u64 *out_value);

        读取设备结点 np 的属性名为 propname,类型为 8、16、32、64 位整型数组的属性。 对于 32 位处理器来讲,最常用的是 of_property_read_u32_array()。如在 arch/arm/mm/cachel2x0.c 中,透过如下语句读取 L2 cache 的"arm,data-latency"属性:

        ​​​​​​​                

        在 arch/arm/boot/dts/vexpress-v2p-ca9.dts 中,含有"arm,data-latency"属性的 L2 cache 结点如下:

                        

        有些情况下,整形属性的长度可能为 1,于是内核为了方便调用者,又在上述 API 的基础上封装出了更加简单的读单一整形属性的 API,它们为 int of_property_read_u8()、 of_property_read_u16()等,实现于 include/linux/of.h:

                        

        int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);

        int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output);

        前者读取字符串属性,后者读取字符串数组属性中的第 index 个字符串。如 drivers/clk/clk.c 中的 of_clk_get_parent_name()透过 of_property_read_string_index()遍历 clkspec 结点的所有"clock-output-names"字符串数组属性。

                        

                        

        static inline bool of_property_read_bool(const struct device_node *np, const char *propname);

        如果设备结点 np 含有 propname 属性,则返回 true,否则返回 false。一般用于检查 空属性是否存在。

        void __iomem *of_iomap(struct device_node *node, int index);

        通过设备结点直接进行设备内存区间的 ioremap(),index 是内存段的索引。若设备 结点的 reg 属性有多段,可通过 index 标示要 ioremap 的是哪一段,只有 1 段的情况,index 为 0。采用 Device Tree 后,大量的设备驱动通过 of_iomap()进行映射,而不再通过传统的 ioremap。         unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

        透过 Device Tree 或者设备的中断号,实际上是从.dts 中的 interrupts 属性解析出中 断号。若设备使用了多个中断,index 指定中断的索引号。 还有一些 OF API,这里不一一列举,具体可参考 include/linux/of.h 头文件。

        5. 总结

        ARM 社区一贯充斥的大量垃圾代码导致 Linus 盛怒,因此社区在 2011 年到 2012 年进 行了大量的工作。ARM Linux 开始围绕 Device Tree 展开,Device Tree 有自己的独立的语 法,它的源文件为.dts,编译后得到.dtb,Bootloader 在引导 Linux 内核的时候会将.dtb 地址 告知内核。之后内核会展开 Device Tree 并创建和注册相关的设备,因此 arch/arm/mach-xxx 和 arch/arm/plat-xxx 中大量的用于注册 platform、I 2 C、SPI 板级信息的代码被删除,而驱动 也以新的方式和.dts 中定义的设备结点进行匹配。

ARM Linux 设备树详细介绍(2)共二篇《全篇结束》

标签:二篇,结点,const,Tree,machine,Linux,device,compatible,ARM
From: https://blog.csdn.net/qq_42837317/article/details/139721340

相关文章

  • ssh-key-deploy:一个在Windows上创建ssh密钥并且自动部署到Linux服务器上的小工具
    ssh-key-deploy简介使用Python编写的一个在Windows上创建ssh密钥并且自动部署到Linux服务器上的小工具。功能特点创建具有自定义名称和可选密码的SSH密钥。列出本地存储的所有SSH密钥。将SSH密钥安全地上传到远程服务器。使用直观的命令行界面进行操作,支持菜单导航。友好......
  • pycharm中Allure的安装及其环境配置
    目录一、安装Allure二、配置环境三、借助Allure生成美观又方面的测试报告注:Windows系统,在pycharm中安装Allure,Allure是由Java语⾔开发的⼀个轻量级,灵活的测试报告⼯具。在安装Allure之前请确保电脑已安装JDK。         Allure是一种灵活的轻量级多语言测试......
  • OpenCloudOS 支持 Linux 原生版微信,开启生态新篇章
    如今,微信已成为办公领域、日常生活以及娱乐方面的刚性需求软件。作为一款通用开源操作系统,OpenCloudOS积极地与微信展开Linux平台的适配工作,全方位地满足广大用户的需求。近期,经过数月的开发与测试,OpenCloudOS社区与微信团队实现了OpenCloudOS与Linux原生版微信的适配支......
  • linux在文件夹中查找文件内容
    linux在文件夹中查找文件内容在Linux中,可以通过以下多个途径,在文件夹中查找文件内容:1、使用grep命令:grep-r"要查找的内容"/path/to/folder-r参数表示递归地在文件夹及其子文件夹中搜索。/path/to/folder是要搜索的文件夹路径。2、使用ack命令ack"要查找的内容......
  • linux清除history
    linux清除history要清除Linux系统中的历史记录(history),可以使用以下几种方法:方法1:通过修改.bash_history文件这是最简单直接的方法,但是只会影响当前用户的历史记录。执行以下命令即可清除:1>~/.bash_history2history-c 方法2:使用export命令同样只会影响当前......
  • linux远程访问及控制
    补充:终端:接收用户的指令TTY终端虚拟终端ssh:22端口号,加密。telnet:23端口号,不加密。解释器:shellSSH远程管理SSH(SecureShell)是一种安全通道协议,主要用来实现字符界面的远程登录、远程复制等功能。SSH协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的......
  • 手把手教你安装Pycharm,详细安装教程!
    PyCharm:可以去PyCharm官网:https://www.jetbrains.com下载对应机器的安装包。安装包下载第一步:进入PyCharm官网,点击Tools,如下图所示:第二步:点击“PyCharm”,进入安装包现在页面,如下图所示:第三步:点击“DOWNLOADNOW”,根据自己需要下载匹配的操作系统的安装包,如下图所示:......
  • 从Linux内核设计者的角度看 - 设备驱动的架构设计
    Linux中的设备驱动概念中的设备和驱动指的是啥?  直接说设备驱动其实是比较抽象的,举个例子就特别明了了,比如我们要控制1个led的亮灭,那么led就是设备,控制led运行的软件就是该设备的驱动。也就是说,这里的设备就是现实中的一个电子设备,设备驱动就是控制这个电子设备运行的软件程序......
  • Linux 提权-Capabilities
    本文通过Google翻译Capabilities–LinuxPrivilegeEscalation-Juggernaut-Sec这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。导航0前言1什么是Capabilities?2枚举Capabilities2.1枚举Capabilities-手动方法2.1.......
  • Linux上java-jar Spingboot项目
    百度的,后面再补一个Linux文档操作手册,是不是很大胆?准备工作1、首先得有两个软件Xftp(用来上传文件到)和XShell(连接服务器执行命令)2、Linux上有JDK(怎么安装可以转到Linux安装JDK流程)3、项目的JAR包项目jar包导jar<build><plugins><plugin><groupId......