Linux platform子系统和设备树

1 Linux platform子系统

在Linux 2.6内核中,提出了总线、设备、驱动的架构,目的是让我们写出来的驱动通用性更强。

arm核内部总线结构:

[图片:soc内部总线结构]

1.1 核心思想

  • 将设备的信息从驱动中分离出来,我们需要在操作系统中,添加设备和驱动两部分。

  • 设备中包含是设备的信息(资源),驱动中包含的是操作设备函数接口。

  • 为了能让驱动最终能操作我们的硬件设备,我们在驱动中必须获取设备的信息(资源)。驱动是如何获取具体设备信息呢?

  • 设备和驱动都会注册到总线上,当注册设备的时候,会去寻找同名的驱动,当注册驱动的时候,也会去找同名的设备。相互查找。一旦匹配成功,操作系统就会自动调用驱动提供的probe函数。我们只需要在probe函数中,使用操作系统提供的通用API获取硬件的资源即可

[图片:设备注册时查找过程]

1.2 Linux总线的理解

  • 总线在操作系统中本质就是两个链表: 挂载设备的链表和挂载驱动的链表。
  • 在操作系统中总线种类可以分成两大类:
  • 平台总线:平台总线挂载都是控制器设备,用于CPU核与硬件控制器之间的通信。在Linux系统中用"platform bus"表示。
  • 边缘设备之间通信的总线:边缘设备之间通信的总线挂载是符合总线时序的外围设备如:i2c , spi ,usb , uart 等。不同的边缘设备之间通信的总线,总线时序是不一样的,
  • 对于这些总线,Linux 内核是单独实现的

1.3 基于总线写驱动的思路

  • 根据自己的设备,确定总线的类型
  • 根据总线的类型, 确定设备在总线上如何描述
  • 根据总线的类型, 确定驱动在总线上如何描述
  • 根据总线的类型,确定在总线上如何注册设备
  • 根据总线的类型,确定在总线上如何注册驱动
  • 根据总线的类型, 确定设备和驱动匹配原则

设备和驱动匹配后,操作系统就会调用驱动提供的probe函数。在这个函数中,一般需要做两件事情:

  • (1)获取匹配的硬件资源
  • (2)向上层提供硬件设备的操作函数接口(如:注册字符设备)

案例代码:

c 复制代码
todo

2 Linux设备树

  • Linux内核在启动的时候,要求把设备树文件传递给它。它拿到设备树之后,会解析设备树文件,从而识别设备信息

  • 因为设备的信息是针对于特定平台的,如果我们在Linux内核中包含太多设备信息,则Linux内核移植性就会变差。引入设备树之后,设备的信息的描述不再在是以代码的形式存在于Linux内核源代码中

  • dtc,device tree compiler,是将.dts 编译为.dtb需要用到的**编译工具,**是编译设备树的小工具

  • dts,device tree source,是设备树**源码文件,**是描述硬件信息的asiII文本文件

  • dtsi,device tree source include,是设备树源码文件要用到的头文件,类似头文件,描述平台共性

  • dtb,device tree binary,是将DTS 编译以后得到的二进制文件是编译后的二进制文件,可被bootloader/kernel识别并解析

一般开发的时候,把这些设备树文件拷贝出来,方便查找:

  • imx6ull-14x14-smartcar.dts:外围设备相关设备树文件
  • imx6ull.dtsi:芯片相关设备树文件

将dtb文件反编译成dts文件C.将test.dtb文件反编译成test.dts文件:dtc -O dts -I dtb -o test.dts test.dtb

2.1 设备树语法规则

一个节点就是用来描述一个设备的信息,每个节点必须有一个<名称>[@<设备地址>]形式的名字。

  • 1、名称就是一个ascii字符串,节点的命名应该根据设备的功能来命名。例如一个3com以太网适配器的节点就应该命名为ethernet,而不应该是3com509
  • 2、如果存在reg属性:则设备地址是reg属性的第一个数字。
  • 3、每个设备的节点都应该有一个compatible属性

2.2 节点属性

属性有两种格式:

  • 格式1(没有值) : property-name
  • 格式2(键值对) : property-name = value

2.3 添加设备树节点

在设备树文件的首节点的最后一个大括号之前添加新节点: 每个设备树节点必须要有compatible属性。compatible用于与驱动匹配,reg表示寄存器地址和大小。

c 复制代码
	};
	// 在首节点的最后一个大括号之前添加新节点。节点名称格式为:名称@reg中第一个数字
	smartcar-led@20c406c {
		compatible = "imx-led"; // 这个名称与驱动匹配
		reg = <0x20c406c 0x4>,<0x20e00b0 0x4>,<0x209c000 0x8>; // 设备的寄存器地址,多个寄存器,用逗号隔开
	};
};

在开发板的/sys/firemware/devicetree/base目录下可以查看设备树是否添加成功。

2.4 在驱动中匹配设备树节点

通过struct device_driver结构体中的of_match_table成员,来匹配设备树节点。

c 复制代码
static struct platform_driver imx_led_driver = {
	.driver = {
           .of_match_table = led_dt_ids, // 匹配设备树节点
		  },
};

3 pinctrl和GPIO子系统

所谓的子系统,实质上就是设备树中,对SOC芯片不同寄存器进行了定义和配置。驱动开发时,仅需了解了SOC芯片厂商是如何在设备树中定义这些寄存器的,然后将这些子系统配置,以节点属性的方式添加到我们新增的设备树节点中;最后编译设备树,并在驱动程序中调用各子系统的系统API,操作寄存器。

比如:使用IMX6ULL,通过GPIO管脚控制LED流水灯亮、灭。

  • 控制流水灯,需要根据硬件电路图,找到对应的控制管脚,设置管脚IO复用模式IOMUX为GPIO的工作模式(IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA)
  • 配置好IOMUX后,还需要配置管脚PAD属性,这些属性配置比较复杂,需要根据SOC厂商的芯片说明(IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA),进行配置,通常参考设备树中其他pinctrl的配置值即可。
  • 最后要配置管脚的输入输出工作模式。如果为输出工作模式,还需要配置高低电平。

基于以上流程:

  • SOC芯片厂商,在设备树中,对IOMUX和输入工作模式配置,通过一个宏定义直接做好了,我们只需找到对应的宏即可
  • 管脚PAD属性:参考设备树中,同一IOMUX工作模式下,厂商的配置。
  • 最后,将这些配置,在pinctrl子系统中,新增子节点。
c 复制代码
		pinctrl_rgb_led: rgb_led {
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO04__GPIO1_IO04  0x1b0b1
				MX6UL_PAD_CSI_VSYNC__GPIO4_IO19  0x1b0b1
				MX6UL_PAD_CSI_HSYNC__GPIO4_IO20  0x1b0b1
			>;
		};

GPIO子系统:

  • 在设备树文件imx6ull.dtsi中,定义了各gpioX组的设备信息,只需在我们新增的设备树节点中,以属性的方式引用对应的gpioX组;最后在驱动程序中,调用系统提供的API操作GPIO管脚。
c 复制代码
	};
	// 在首节点的最后一个大括号之前添加新节点
	smartcar-led@20c406c {
		compatible = "imx-led"; // 这个名称与驱动匹配
		reg = <0x20c406c 0x4>,<0x20e00b0 0x4>,<0x209c000 0x8>; // 设备的寄存器地址
		status = okay;
		pinctrl-0 = <&pinctrl_rgb_led>;
		rgb_led_red = <gpio1 4 GPIO_ACTIVE_LOW>;
		rgb_led_green = <gpio4 20 GPIO_ACTIVE_LOW>;
		rgb_led_red = <gpio4 19 GPIO_ACTIVE_LOW>;
	};
};
相关推荐
小灰灰__32 分钟前
Linux离线安装Docker命令,简单镜像操作
linux·docker·eureka
AI视觉网奇1 小时前
pytorch3d linux安装
linux·人工智能·pytorch
双手插兜-装高手1 小时前
Linux - 线程基础
linux·c语言·笔记
XY.散人1 小时前
初识Linux · 信号处理
linux·信号处理
XiaoCCCcCCccCcccC2 小时前
Linux环境下的基础开发工具 -- 包管理器,vim,gcc/g++,make/makefile,git,gdb/cgdb
linux·c语言·gdb
小袁搬码2 小时前
Ubuntu24.04LTS设置root用户可远程登录
linux·ubuntu24.04
很楠不爱2 小时前
Linux网络——传输层协议
linux·网络·udp
xxjkkjjkj2 小时前
udp_socket
linux·网络
钰爱&2 小时前
【操作系统】Linux之网络编程(UDP)(头歌作业)
linux·操作系统
最后一个bug3 小时前
如何理解Lua 使用虚拟堆栈
linux·c语言·开发语言·嵌入式硬件·lua