platform总线简介和使用场景说明
platform
总线是 Linux 内核中一种虚拟的、软件抽象的总线类型,主要用于管理和连接那些不直接属于传统物理总线(如 PCI、USB、I2C、SPI 等)的设备。它本质上是为那些直接集成在处理器芯片内部或直接映射到处理器地址空间的外设提供一种标准化的管理框架。
一,定义 (platform_bus_type
):
在 Linux 内核源码中,platform
总线由一个名为 platform_bus_type
的全局 struct bus_type
实例表示(通常在 drivers/base/platform.c
中定义):
struct bus_type platform_bus_type = {.name = "platform",.dev_groups = platform_dev_groups,.match = platform_match, // 核心匹配函数.uevent = platform_uevent,.pm = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
.name = "platform"
: 总线名称为 “platform”。.match = platform_match
: 这是核心的匹配函数,负责比较platform_device
和platform_driver
是否匹配(匹配规则见下文)。- 其他成员:用于设备属性组、电源管理、热插拔事件等。
二,核心对象:
1. platform_device
(设备):
* 代表一个平台设备。通常描述:* 设备名称 (`name`)。* 唯一的设备 ID (`id`,用于区分同名设备)。* 该设备占用的**硬件资源**:内存映射 I/O 区域 (`resource`)、中断号 (`irq`)、DMA 通道等。这些资源通常在内核启动早期(如板级初始化代码)或通过设备树 (Device Tree) / ACPI 表静态定义。* **平台特定数据 (`platform_data`):** 一个指向任意自定义数据结构的 `void *` 指针,用于传递该设备特有的、非标准化的配置信息(例如 GPIO 引脚号、特定寄存器偏移、设备模式等)。在现代基于设备树 (DT) 或 ACPI 的系统中,`platform_data` 的使用逐渐减少,信息尽量通过 DT/ACPI 属性传递。* **设备树兼容字符串 (`of_node->compatible`):** 当使用设备树时,此设备对应的设备树节点 (`struct device_node *of_node`) 会被关联,其 `compatible` 属性是驱动匹配的关键依据。
* 通过 `platform_device_register()` 或 `platform_device_register_simple()` 等函数注册到 `platform` 总线。
2. platform_driver
(驱动):
* 代表一个平台设备的驱动程序。
* 包含一个标准的 `struct device_driver driver` 成员。
* 关键成员:* `.probe`: 当驱动和设备匹配成功时,由总线核心调用的函数。驱动在此函数中初始化硬件、申请资源、向内核子系统注册设备。* `.remove`: 当设备被移除或驱动卸载时调用的函数,负责释放资源、注销设备。* `.driver.name`: 驱动的名称(历史遗留,也可用于简单名称匹配)。* **`.id_table` (可选):** 指向 `struct platform_device_id` 数组的指针,用于基于设备名称匹配(较老方式)。* **`.of_match_table` (重要):** 指向 `struct of_device_id` 数组的指针,用于基于**设备树兼容字符串**进行匹配(现代首选方式)。该数组定义了驱动所支持的设备树节点的 `compatible` 字符串。* **`.acpi_match_table` (用于 ACPI 系统):** 类似 `of_match_table`,用于基于 ACPI ID 匹配。
* 通过 `platform_driver_register()` 注册到 `platform` 总线。通常使用 `module_platform_driver()` 宏简化模块的注册/注销。
三,匹配机制 (platform_match
):
platform_bus_type.match
函数 platform_match
按以下优先级顺序尝试匹配 platform_device
(pdev
) 和 platform_driver
(pdrv
):
1. 基于设备树/ACPI (of_match_table
/ acpi_match_table
) (现代首选):
* 如果 `pdev` 有相关联的设备树节点 (`pdev->dev.of_node` 不为 NULL) **并且** `pdrv` 提供了 `of_match_table`:* 检查 `pdev->dev.of_node->compatible` 是否与 `pdrv->of_match_table` 中的任何一项 `.compatible` 字符串**完全匹配**。* 如果找到匹配项,则匹配成功。
* 类似地,在 ACPI 系统中,使用 `pdev` 的 ACPI 句柄和 `pdrv->acpi_match_table` 进行匹配。
2. 基于 ID Table (id_table
) (较老方式):
* 如果 `pdrv` 提供了 `id_table`:* 检查 `pdev->name` 是否与 `pdrv->id_table` 中的任何一项 `.name` 字符串**完全匹配**。* 如果找到匹配项,则匹配成功。
* `id_table` 允许一个驱动支持多个具有不同名称但本质相同的设备。
3. 基于名称 (driver.name
) (最简单但最不灵活):
* 比较 `pdev->name` 和 `pdrv->driver.name` 是否**完全匹配**。
* 如果相同,则匹配成功。
* 这种方式要求设备名称和驱动名称严格一致,通常只用于一对一的简单设备。
四,使用场景 (何时使用 Platform 总线?):
platform
总线是嵌入式 Linux 和片上系统 (SoC) 开发的核心机制,适用于以下典型场景:
1. SoC 集成外设 (片上外设):
* **最核心的用途。** 处理器芯片内部集成的、不通过外部物理总线连接的外设控制器,例如:* **系统级控制器:** 中断控制器 (GIC, INTC), DMA 控制器, 时钟控制器, 复位控制器, PIN 控制器 (Pinctrl), 电源管理单元 (PMU)。* **内存接口:** 内存控制器 (DDR), NAND/NOR Flash 控制器, SRAM 控制器。* **通信接口:** 内部总线控制器 (如 AMBA AHB/APB 桥), 邮箱 (Mailbox), 硬件信号量 (HWSem)。* **片上外设:** GPIO 控制器, 看门狗 (Watchdog), 定时器/计数器 (Timers), 实时时钟 (RTC), ADC/DAC, 硬件随机数生成器 (RNG), 温度传感器。* **多媒体/加速器:** 图像处理单元 (GPU, ISP), 视频编解码器 (VPU), 加密引擎, DSP 协处理器接口。* **片上调试接口:** JTAG/SWD 控制器。
2. 内存映射 I/O (MMIO) 外设:
* 虽然可能位于片外,但其寄存器直接映射到处理器的物理地址空间,不通过标准总线协议访问,例如:* 片外的简单 UART 芯片 (通过并行总线连接)。* 片外的 FPGA 配置的逻辑模块。* 某些老式或专用的 ISA 设备(在现代系统中较少见)。
3. 伪设备/软件抽象设备:
* 代表内核或驱动创建的虚拟功能或服务,而非真实物理硬件,例如:* Framebuffer 设备 (可能由 GPU 驱动或软件模拟创建)。* 某些内核模块创建的设备节点。* 用于测试的虚拟平台设备。
4. 早期板级支持和传统代码路径:
* 在没有设备树 (DT) 或 ACPI 的旧内核或架构中,`platform_device` 和 `platform_data` 是描述板级硬件信息的**主要方式**(硬编码在板级支持包 BSP 的 C 文件中)。现代基于 DT/ACPI 的系统虽然减少了 `platform_data` 的使用,但仍大量依赖 `platform` 总线框架本身。
五,为什么需要 Platform 总线? (解决了什么问题)
- 统一管理框架: 为大量不挂载在标准物理总线上的设备提供了一个统一、一致的内核设备模型接口。这些设备也能出现在
/sys/bus/platform/
下,受电源管理、热插拔(有限)、sysfs 等机制管理。 - 资源管理: 提供标准机制 (
struct resource
) 来声明和获取设备的硬件资源 (内存区域、中断号),简化驱动编写并避免资源冲突。 - 设备与驱动分离: 遵循 Linux 设备模型的核心原则。设备信息(资源、ID)和驱动逻辑分离,提高模块化和复用性。
- 支持动态绑定: 设备或驱动可以稍后加载(模块),总线核心会自动处理匹配和绑定 (
probe
)。 - 设备树/ACPI 集成:
.of_match_table
是设备树驱动模型的核心,使得驱动可以通过声明兼容字符串来支持设备树中描述的硬件。ACPI 也有类似机制。 - 传递板级特定数据:
platform_data
提供了一种(虽然非标准化)传递设备特定配置的通道(在现代设计中应谨慎使用,优先考虑 DT/ACPI)。
六,总结:
platform
总线是 Linux 内核为管理片上集成外设、内存映射外设以及伪设备而设计的虚拟总线。它通过 platform_device
描述设备和资源,通过 platform_driver
实现驱动功能,并利用 platform_match
函数(主要基于设备树兼容字符串或设备名称)进行匹配。它是嵌入式 Linux 和 SoC 驱动开发的基石,为大量非标准总线连接的设备提供了统一、标准化的设备模型管理框架,实现了设备与驱动的分离、资源管理以及与设备树/ACPI 的紧密集成。在现代内核开发中,结合设备树使用 platform
总线是描述和驱动 SoC 外设的标准做法。