赞
踩
kernel-5.10/driver/gpu/drm/
name | path |
---|---|
DRM Core | drivers/gpu/drm/ |
MTK implement | drivers/gpu/drm/mediatek/mediatek_v2/ |
Panel driver | drivers/gpu/drm/panel/ |
DRM Header File | include/drm/ include/uapi/drm/ |
MTK implement
name | files |
---|---|
DRM framework relative | mtk_drm_xxx.c |
MTK ddp implement | mtk_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
name | files |
---|---|
hidl HWC | hardware/interfaces/graphics/composer/ |
MTK implement HWC | vendor/mediatek/proprietary/hardware/hwcomposer/ |
MTK libhwc | vendor/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()函数的处理流程:
打开"/dev/dri/card0"文件节点;
设置drmmode的的能力;
a. 设置DRM_CLIENT_CAP_UNIVERSAL_PLANES,获取所有支持的Plane资源;
b. 设置DRM_CLIENT_CAP_ATOMIC,告知DRM驱动该应用程序支持Atomic操作;
c. 设置DRM_CLIENT_CAP_WRITEBACK_CONNECTORS,开启DRM驱动支持writeback;
调用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的实现。
注:本文仅仅只是笔者对流程的梳理和一些理解,强烈建议自行去研究源码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。