Linux内核通过module_platform_driver(rockchip_drm_platform_driver)
函数注册RK3399 DRM框架驱动代码,该宏展开如下:
static int __init rockchip_drm_platform_driver_init(void)
{
return platform_driver_register(&rockchip_drm_platform_driver);
}
...
下面通过分析函数platform_driver_register()
的调用流程,展示RK3399 DRM框架platform_device
和platform_driver
匹配过程和驱动探测过程。
具体调用流程如下:
rockchip_drm_platform_driver_init()-> ## rockchip_drm_drv.c
platform_driver_register()-> ## platform_device.h
__platform_driver_register()-> ## platform.c
driver_register()-> ## driver.c
bus_add_driver()-> ## bus.c
driver_attach()-> ## dd.c
bus_for_each_dev()-> ## bus.c
__driver_attach()-> ## dd.c
1.driver_match_device()-> ## base.h match
platform_match() ## platform.c 开始match
2.driver_probe_device()-> ## dd.c probe
really_probe()-> ## dd.c
platform_drv_probe()-> ## platform.c 开始probe
rockchip_drm_platform_probe() ## rockchip_drm_drv.c
一、match实现
在注册Linux内核platform
总线时,相关的总线类型定义如下:
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);
在bus_type
结构体中定义了platform device
和platform driver
的匹配函数platform_match()
,具体实现如下:
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);
## 1.设备树匹配
/* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
## 2.ACPI类型匹配(无)
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
## 3.id table匹配
/* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
## 4.device和driver名字匹配
/* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
platform device
和platform driver
的匹配方法包括:
1、设备树匹配
匹配方法:比较dts设备节点的compatible
属性定义和驱动文件中of_device_id
中的compatible
定义是否相同。
注:RK3399 DRM驱动使用的是设备树匹配.
#1. rockchip_drm_drv.c compatible定义
static const struct of_device_id rockchip_drm_dt_ids[] = {
{ .compatible = "rockchip,display-subsystem", },
...
};
MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids);
static struct platform_driver rockchip_drm_platform_driver = {
...
.driver = {
.name = "rockchip-drm",
.of_match_table = rockchip_drm_dt_ids,
...
},
};
#2. rk3399.dtsi compatible定义
display_subsystem: display-subsystem {
compatible = "rockchip,display-subsystem";
...
};
2、ACPI类型匹配 (无)
3、id table匹配
4、device和driver名字匹配
二、probe实现
在实现了DRM的platform device
和platform driver
匹配后,会进入Linux内核的platform_driver
中的probe
探测函数进行DRM驱动探测函数的调用。platform_driver
初始化如下:
int __platform_driver_register(struct platform_driver *drv,
struct module *owner)
{
drv->driver.owner = owner;
drv->driver.bus = &platform_bus_type;
drv->driver.probe = platform_drv_probe;
drv->driver.remove = platform_drv_remove;
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
platform_drv_probe
实现如下:
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
int ret;
...
ret = dev_pm_domain_attach(_dev, true);
if (ret != -EPROBE_DEFER) {
if (drv->probe) {
## 调用各驱动的probe函数(例:DRM的rockchip_drm_platform_driver())
ret = drv->probe(dev);
if (ret)
dev_pm_domain_detach(_dev, true);
} else {
/* don't fail if just dev_pm_domain_attach failed */
ret = 0;
}
}
...
}
小结:
1、RK3399 DRM框架的platform device
和platform driver
在Linux内核platform bus
的match
函数中实现匹配。
2、RK3399 DRM驱动的probe
是在Linux内核platform driver
的probe
中调用。
注:本文基于RockPI 4A单板的Debian系统 Linux4.4内核。
网友评论