Platform 总线

什么是 Platform 总线?

简单来说,Platform 总线 是一种虚拟总线,用于管理那些在物理上没有总线的片上系统(SoC)设备。

  • 物理总线:像 PCI、USB 这样的总线,设备可以热插拔,总线控制器可以自动检测和配置设备。设备有明确的标识符(如 Vendor ID、Device ID)。
  • 虚拟总线:Platform 总线是针对那些“天生”就集成在芯片内部的设备。例如,一个 SoC 内部的 UART 控制器、GPIO 控制器、中断控制器等。这些设备无法被“探测”到,因为它们在硬件上是固定的。Platform 总线为这些设备提供了一个统一的模型来进行管理和驱动匹配。

为什么需要 Platform 总线?

在没有 Platform 总线之前,这些片上设备的驱动通常是直接在内核中进行硬编码,比如直接写死寄存器地址。这种方式存在很多问题:

  • 代码冗余:相同功能的设备(如 UART),在不同的 SoC 上地址不同,需要编写多个几乎相同的驱动。
  • 耦合度高:驱动代码和板级信息(设备地址、中断号等)紧密耦合,移植性差。
  • 不遵循标准模型:不利于内核设备模型的统一管理。

Platform 总线的引入,实现了 驱动(Driver) 和 设备(Device / Platform Data) 的分离,使得:

  • 驱动变得通用:一个驱动可以支持多个相似的设备,只要提供对应的设备信息即可。
  • 硬件信息可配置:设备的资源(地址、中断等)可以通过设备树(Device Tree)或板级文件来定义,而不是写在驱动里。
  • 符合 Linux 设备模型:与内核的电源管理、热插拔等子系统更好地集成。

Platform 总线核心组成部分

Platform 总线遵循标准的 Linux 设备模型,包含三个关键结构体:

struct platform_device (平台设备)

它代表一个具体的、真实的硬件设备。它描述了设备所使用的资源。定义于:include/linux/platform_device.h

struct platform_device {
	const char	*name;
	int		id;
	bool		id_auto;
	struct device	dev;
	u32		num_resources;
	struct resource	*resource;

	const struct platform_device_id	*id_entry;
	char *driver_override; /* Driver name to force a match */

	/* MFD cell pointer */
	struct mfd_cell *mfd_cell;

	/* arch specific additions */
	struct pdev_archdata	archdata;
};

struct platform_driver (平台驱动)

它代表一个能够管理一类 platform_device 的驱动程序。

struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
	bool prevent_deferred_probe;
};

platform_bus_type (平台总线本身)

这是总线类型的实例,内核已经定义好。它最重要的功能是定义匹配规则(Match Rule),即如何将一个 platform_device 和一个 platform_driver 关联起来。定义于: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,
};

核心关系图

platfrom 设备与驱动的匹配规则

匹配过程的本质是:当一个设备 (device) 和一个驱动 (driver) 被添加到总线 (bus) 上时,总线会调用其 .match() 函数来判断它们是否“适合”对方。如果匹配成功,总线随后会调用驱动的 .probe() 函数来初始化设备。

对于 Platform 总线,其匹配逻辑优先级如下(从高到低):

设备树 (Device Tree) 匹配:基于 compatible 属性。
ACPI 匹配:用于 x86 等架构。
ID 表 (id_table) 匹配:基于设备名称的静态匹配。
名称 (name) 匹配:直接比较驱动名称和设备名称。

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}

Tags:

No responses yet

    发表回复

    您的邮箱地址不会被公开。 必填项已用 * 标注