mtk-drm初始化

kernel初始化

相关文件

kernel-5.10/driver/gpu/drm/

namepath
DRM Coredrivers/gpu/drm/
MTK implementdrivers/gpu/drm/mediatek/mediatek_v2/
Panel driverdrivers/gpu/drm/panel/
DRM Header Fileinclude/drm/ include/uapi/drm/

MTK implement

namefiles
DRM framework relativemtk_drm_xxx.c
MTK ddp implementmtk_disp_xxx.c

我们已经知道,drm需要依次实现kms的如下模块:crtc,plane,connector,encoder和panel(这里不考虑bridge的情况)。

 针对display这种subsystem,内核使用component框架来保证subsystem能够按照一定的顺序初始化设备。在component框架中,包含两个基本概念,master和component。master被称为“超级设备”,component是由master管理的“普通设备”,要求先被初始化。先看master设备初始化:

=》mtk_drm_init    // module_init

​    =》platform_driver_register(mtk_drm_drivers[i])

​        =》mtk_drm_probe   // mtk_drm_platform_driver作为数组的第一项最先被注册并调用probe

​            // for_each_child_of_node来遍历根节点的子节点,

            // 并找到mtk_ddp_comp_dt_ids数组指定的of_node并加入到component普通设备中;

​            =》of_id = of_match_node(mtk_ddp_comp_dt_ids, node)

​            =》component_match_add(dev, &match, compare_of, node)

​            =》component_master_add_with_match(dev, &mtk_drm_ops, match)   // 注册master设备

 上图的platform_driver会被依次注册进内核并调用他们的probe函数,以此完成mtk_ddp和drm的初始化。本文聚焦mtk-drm的实现,这里只看mtk_dsi所实现的encoder和connector。

》mtk_dsi_probe

​    =》mipi_dsi_host_register(&dsi->host)     // 注册dsi_host,这里还会去注册mipi_dsi_device

​    =》component_add(&pdev->dev, &mtk_dsi_component_ops)  // 注册component普通设备

当所有的component普通设备通过component_add注册后,最后就会调用master的bind函数,也就是上面mtk_drm_ops.bind函数。

=》mtk_drm_bind

​    =》drm = drm_dev_alloc(&mtk_drm_driver, dev)    // 根据drm_driver来创建drm_device

​    =》mtk_drm_kms_init(drm)

​        =》drm_mode_config_init(drm)

​        =》component_bind_all(drm->dev, drm)    // 这里会依次回调component设备的bind函数

​            。。。。。。    // 这里省略其他component设备的bind回调

​            =》mtk_dsi_bind

​                =》dsi->panel = of_drm_find_panel(remote_node) 

​                =》mtk_dsi_create_conn_enc(drm, dsi)     // 注册connector和encoder

​                    =》drm_encoder_init

​                    =》drm_encoder_helper_add

​                    =》mtk_dsi_create_connector(drm, dsi)

​                        =》drm_connector_init

​                        =》drm_connector_helper_add

​                        =》drm_connector_attach_encoder(&dsi->conn, &dsi->encoder)

​        =》mtk_drm_crtc_create(drm, private->data->main_path_data)

​            =》mtk_plane_init      // 注册plane

​                =》drm_universal_plane_init

​                =》drm_plane_helper_add

​            =》mtk_drm_crtc_init   // 注册crtc

​                =》drm_crtc_init_with_planes

​                =》drm_crtc_helper_add

​    =》drm_dev_register(drm, 0)     // 注册drm_device

当我们向内核成功注册drm_device后,drm-core会自动完成如下事情:

  • 创建设备节点:/dev/dri/card0

  • 创建 sysfs 节点:/sys/class/drm/card0

  • 创建 debugfs 节点:/sys/kernel/debug/dri/0

drm-hwc初始化

相关文件

namefiles
hidl HWChardware/interfaces/graphics/composer/
MTK implement HWCvendor/mediatek/proprietary/hardware/hwcomposer/
MTK libhwcvendor/mediatek/proprietary/hardware/libhwcomposer/

hwc的请求会转成g_hwc2_api这个全局变量去完成对应的功能。当g_hwc2_api对象被实例化,会调用类的构造函数HWCMediator::HWCMediator()。构造函数中会调用:sp<IOverlayDevice> primary_disp_dev = getHwDevice(),并将primary_disp_dev赋值到<vector>m_displays,到这里hwc才跟drm扯上了关系。MTK通过MTK_HWC_USE_DRM_DEVICE宏定义来兼容egacy和drm两个方式,代码分布在:hardware/libhwcomposer/2.0.0/drm/和hardware/libhwcomposer/2.0.0/legacy/。下面简单看一下drm的初始化。

 这是一个典型的单例模式。类的构造函数会完成对drm资源的初始化。

=》DrmDevice::DrmDevice()

​    =》m_drm.init()      // m_drm是DrmModeResource对象

​        =》DrmModeResource::init()

​            =》m_fd = open(DRM_DISPLAY_PATH, O_RDWR)   // "/dev/dri/card0"

​            =》initDrmCap()

​                =》drmSetClientCap(m_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)

​                =》drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1)

​                =》drmSetClientCap(m_fd, DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1)

​            =》initDrmResource()

​                =》drmModeResPtr res = drmModeGetResources(m_fd)

​                =》initDrmCrtc(res)

​                    =》drmModeCrtcPtr c = drmModeGetCrtc(m_fd, r->crtcs[i])

​                    =》DrmModeCrtc *crtc = new DrmModeCrtc(this, c)

​                    =》m_crtc_list.push_back(crtc)

​                =》initDrmEncoder(res)

​                =》initDrmConnector(res)

​                =》initDrmPlane()

简单介绍DrmModeResource::init()函数的处理流程:

  1. 打开"/dev/dri/card0"文件节点;

  2. 设置drmmode的的能力;

    a. 设置DRM_CLIENT_CAP_UNIVERSAL_PLANES,获取所有支持的Plane资源;

    b. 设置DRM_CLIENT_CAP_ATOMIC,告知DRM驱动该应用程序支持Atomic操作;

    c. 设置DRM_CLIENT_CAP_WRITEBACK_CONNECTORS,开启DRM驱动支持writeback;

  3. 调用initDrmResource()函数,依次获取所有的:crtc,plane,connector和encoder,创建对应的对象并加入到对应的list中;

    a. initDrmCrtc(res)

    b. initDrmEncoder(res)

    c. initDrmConnector(res)

    d. initDrmPlane()

到这里,hwc-drm对ctrc,plane,encoder和connector的初始化结束了。这里还需要提一嘴fb的初始化。

=》DrmDevice::setOverlaySessionMode

        =》m_drm.setDisplay

                =》crtc->prepareFb()

                        =》m_drm->allocateBuffer(&m_fb_bo)

                                =》drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB, &create_arg)

                                =》addFb(fb_bo)

                                        =》drmModeAddFB2WithModifiers

                                                =》DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2

                =》drmModeSetCrtc

                        =》DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc)

对这一块不太了解的话,请移步龙哥的《最简单的DRM应用程序》和这位同学《一瓶布满》。简单说一下,

        1. 调用DRM_IOCTL_MODE_CREATE_DUMB创建一个drm的buffer,也就是gem_obj;

        2. 然后调用DRM_IOCTL_MODE_ADDFB2,将前面创建的gem_obj和一块drm_framebuffer进行绑定,因为最终刷图使用的是fb;

        3. 最后调用drmModeSetCrtc送显,进行刷图。

本节是对mtk-drm初始化的走读,基本都是drm框架的东西,如drm-core和drmlib。后面的计划是介绍mtk平台对fence,vblank,atomic_commit的实现。

注:本文仅仅只是笔者对流程的梳理和一些理解,强烈建议自行去研究源码。

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值