Android14显示系统 - DRM框架

文章目录

1、资料快车

1、Linux DRM Developer's Guide英文资料

1)http://landley.net/kdocs/

2)http://landley.net/kdocs/htmldocs/drm.html

2、基于DRM的kernel图显系统(Linux and SOC专栏)

https://blog.csdn.net/weixin_43644245/category_11305753.html

3、蜗窝科技(graphic subsystem)

http://www.wowotech.net/sort/graphic_subsystem

4、野火:

https://doc.embedfire.com/linux/rk356x/linux_base/zh/latest/linux_app/drm/drm.html

5、Linux Graphics领域专家-何小龙专栏

https://blog.csdn.net/hexiaolong2009/category_9281458.html

6、深入理解Linux DRM显示子系统:架构、实战项目与关键问题全解析

https://blog.csdn.net/Interview_TC/article/details/148558251

7、【嵌入式Linux应用开发 | DRM 】在泰山派RK3566使用DRM控制屏幕(超详细)

https://modelers.csdn.net/6912deb25511483559e7586f.html

8、RK Graphics and Multimedia user guide

2、preface

1)传统的基于FB显示开发已经不能满足当下日益发展的显示硬件,有很多新的硬件技术产生,多层合成(即HWC)、VSYNC(HWC功能之一)、ION/DMA-BUF(android的gralloc)、异步更新、fence机制,这些驱动互相独立存在,开发DRM则为了解决这些问题;统一架构集中管理的需求迫在眉睫;

2)DRM架构将显示相关的机制统一管理,同时DRM可以统一管理GPU、Display驱动、HWC驱动、Fence驱动等等,使得软件架构更为统一,方便管理和维护;

3)DRM已经是Linux目前主流的图形显示框架,比如应用在智能座舱、智慧硬件、工业大屏、医疗影像;

4)高版本Android系统当然也要跟上,使用DRM框架;

DRM的意义?

1)假如没有DRM,则kernel下的Display 相关的模块则是独立,应用层使用它们也是互相独立,则会出现以下情况,试想一下,用户层调用将会是多么的繁琐,扩展性也差;

2)而DRM则为了解决零散的问题,提供一套框架(这套框架当然由专业的团队复杂维护),将上述模块在内核层"包起来",建立互相联系,并向上提供统一的调用接口,思想与ALSA、V4L2等等是类似的;

用户层统一通过libdrm来使用Display模块

从用户层的角度,来看看DRM的好处

复制代码
1、使用DRM的伪代码:
int main(int argc, char **argv)
{
	/* open the drm device */
	open("/dev/dri/card0");

	/* get crtc/encoder/connector id */
	drmModeGetResources(...);
	
	/* get connector for display mode */
	drmModeGetConnector(...);
	
	/* create a dumb-buffer */
	drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB);
	
	/* bind the dumb-buffer to an FB object */
	drmModeAddFB(...);
	
	/* map the dumb buffer for userspace drawing */
	drmIoctl(DRM_IOCTL_MODE_MAP_DUMB);
	mmap(...);  //当执行完mmap之后,我们就可以直接在应用层对framebuffer进行绘图操作了。
	
	/* start display */
	drmModeSetCrtc(crtc_id, fb_id, connector_id, mode); //正式开始显示
}
通过DRM框架提供的接口,仅需调用少量的函数完成一系列的配置和操作
如果没有DRM,这段代码则会相当复杂;

3、术语&基本概念

1)术语

复制代码
1、DRM - Direct rendering manager 直接图像管理
注意区分 DRM(Digital Rights management) 数字版权管理 - hdcp/playready/widewive

DRI - Direct rendering Infrastructure
KMS - kernel mode setting
VBL - vblank - vertical blank 垂直消隐
DP - display port

plane : 硬件图层

两种内存模型:
DUMB:只支持连续物理内存,基于kernel中通用CMA API实现,多用于小分辨率简单场景
prime:连续、非连续物理内存都支持,基于DMA-BUF机制,可以实现buffer共享,多用于大内存复杂场景

2)vblank handing

场景:在游戏中关闭垂直同步时如果帧速率超过显示器的刷新率 (例如 60Hz 显示器为每秒 120 帧) 的话,就会出现屏幕撕裂情形

https://blog.csdn.net/yaoyutian/article/details/121128725

基本概念:vertical blank : 直译垂直空白,指的是扫描点从画面的右下角到左上角的时间间隔,术语叫做垂直消隐,也称场消隐

作用:底层驱动 硬件产生vblank中断信号,并会向上提供给VSYNC使用

4、DRM框架

1)DRM系统框架

1、分配两部分

1)应用层- libdrm,应用程序可以选择使用libdrm方便地访问DRM各个组件驱动;

2)内核驱动层

1、GEM (graphic execution manager) - 管理Framebuffer内存分配,代替Android的ION/DMA-BUF

2、KMS (kernel mode setting) - 功能丰富,包括CRTC、Encoder、Connector等

​ 1)更新画面:显示buffer的切换、多图层的合成方式,以及每个图层的显示位置;

​ 2)设置显示参数:包括分辨率、刷新率、电源状态(唤醒休眠)等

3、GPU驱动 - 开源驱动panfrost/Lima

2)DRM子系统框架

组件介绍:

1)DRM中Framebuffer也是一片存放图像的内存区域, 且需要设置图像的格式(RGB888,YUV,C8等) 以及画布的大小 - 配置图像格式,与实际的显示设备无关;

2)plane(图层): 一个包含项CRTC发送数据的缓存块的内存对象,每个CRTC必须关联一个Planes,他是CRTC决定采用哪种视频模式的根据 - 显示分辨率、像素大小、像素格式,刷新率等;通常驱动会把framebuffer绑定到 DRM_PLANE_TYPE_PRIMARY 上。

Planes会分为三种类型:

1、DRM_PLANE_TYPE_PRIMARY: 主要图层,显示背景或者图像内容,每个CRTC中含一个

2、DRM_PLANE_TYPE_OVERLAY: 用于显示叠加、缩放,每个CRTC中含一个以上,比如overlay图层播放视频

3、DRM_PLANE_TYPE_CURSOR: 用于显示鼠标,每个CRTC中含0-N个

plane包含图像数据?还是属性集合?与framebuffer的关系?

drm中的plane是指硬件图层,注意区别应用层的plane 不同概念,固定数量,不同平台支持的数量不同;

多个plane给到crct进行合成(即HWC的功能),需要硬件支持,硬件不支持则也必然有对应软件实现;

图显数据流(一对一场景):fb -> plane -> crtc -> encoder -> connector;

图显数据流(多对多场景):plane固定不变,framebuffer则由用户自行分配,用户构造好数据再指定给哪个plane;

3)CRTC (代表显示设备) :配置实际的显示设备参数,在DRM显示系统中CRTC会配置display timings和显示分辨率(Planes提供) 来扫描framebuffer上的内容,传给Encoder。

4)Encoder : 将pixel像素编码(转换)为显示器所需要的信号,比如HDMI connector,Encoder需要将图像转换为TMDS信号;

5)Connector:物理连接器,LCD/HDMI/DP,与当前物理连接的输出设备相关的信息(如连接状态,EDID数据,DPMS状态或支持的视频模式)也存储在 Connector 内。

6)Bridge:有些SOC缺乏某种Connector,可以使用Bridge来转接,比如DSI2HDMI;

多屏异显功能

采用RK3568的板卡支持多屏异显,最大可支持3屏异显,RK3568总plane数量为6个

  • 当开启一个屏幕时,屏幕会分配3个图层(第三个图层Cluster仅支持AFBC格式的图像)
  • 当开启两个屏幕时,两个屏幕均会分配3个图层(第三个图层Cluster仅支持AFBC格式的图像)
  • 当开启三个屏幕时,第一个屏幕分配3个图层,第二个屏幕分配两个图层, 最后屏幕分配一个图层 (第一个屏幕的第三个图层Cluster以及第二个屏幕的第二个图层Cluster仅支持AFBC格式的图像)
小结-DRM框架元素汇总

3)AML方案的drm-meson

1、整体框架
复制代码
注意有两部分
1)项目部分 - TV项目
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm

2)开源部分-通用
┌─────────────────────────────────────────────────────────┐
│                    DRM Framework                         │
│  (drm_device, drm_crtc, drm_plane, drm_encoder)         │
└─────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────┐
│              Meson DRM Driver (meson_drv.c)            │
│  - 驱动初始化和组件管理                                  │
│  - DRM 设备注册                                         │
│  - 中断处理                                             │
└─────────────────────────────────────────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
┌──────────────┐    ┌──────────────┐   ┌──────────────┐
│  meson_crtc  │    │ meson_plane  │   │meson_overlay │
│  (CRTC)      │    │  (OSD1)      │   │  (VD1)       │
└──────────────┘    └──────────────┘   └──────────────┘
        │                   │                   │
        └───────────────────┼───────────────────┘
                            ▼
┌─────────────────────────────────────────────────────────┐
│              Video Processing Pipeline                  │
│                                                          │
│  VIU (Video Input Unit) ──► VPP (Video Post Process)   │
│       │                            │                    │
│       │                            ▼                    │
│       └──────────────────► VENC (Video Encoder)        │
│                                  │                      │
│                                  ▼                      │
│                          HDMI / CVBS Output            │
└─────────────────────────────────────────────────────────┘

源码结构
drivers/gpu/drm/meson/
├── meson_drv.c/h          # 主驱动入口,DRM 设备管理
├── meson_crtc.c/h         # CRTC(显示控制器)
├── meson_plane.c/h        # 主平面层(OSD1,用于 UI)
├── meson_overlay.c/h      # 覆盖层(VD1,用于视频)
├── meson_venc.c/h         # 视频编码器(ENCI/ENCP)
├── meson_viu.c/h          # 视频输入单元(OSD 处理)
├── meson_vpp.c/h          # 视频后处理
├── meson_vclk.c/h         # 视频时钟管理
├── meson_registers.h      # 寄存器定义
├── meson_dw_hdmi.c/h      # HDMI 输出(可选)
└── meson_venc_cvbs.c/h    # CVBS 输出

LVDS

复制代码
android\vendor\amlogic\common\kernel\common_5.4\drivers\gpu\drm\panel\panel-lvds.c

5、源码分析

1)源码框架

1、源码目录

复制代码
├── i2c  //HDMI DDC/EDID支持
├── ingenic
├── lib
├── lima  //lima GPU驱动
├── mcde  //multichannel display engine
├── meson
├── panel  //显示面板驱动
├── panfrost  //panfrost GPU驱动
├── rcar-du
├── scheduler   //GPU作业调度器
├── selftests
├── ttm
├── udl  //USB displaylink video
├── vgem  //Virtual graphic execution manager - 软件实现GEM
├── vkms  //virtual kernel mode setting - 软件实现KMS
├── bridge  //显示桥接芯片,比如DSI2HDMI

├── ati_pcigart.c
├── drm_agpsupport.c
├── drm_atomic.c
├── drm_atomic_helper.c
├── drm_atomic_state_helper.c
├── drm_atomic_uapi.c
├── drm_auth.c
├── drm_blend.c
├── drm_bridge.c
├── drm_bufs.c
├── drm_cache.c
├── drm_client.c
├── drm_client_modeset.c
├── drm_color_mgmt.c
├── drm_connector.c
├── drm_context.c
├── drm_crtc.c
├── drm_crtc_helper.c
├── drm_crtc_helper_internal.h
├── drm_crtc_internal.h
├── drm_damage_helper.c
├── drm_debugfs.c
├── drm_debugfs_crc.c
├── drm_dma.c
├── drm_dp_aux_dev.c
├── drm_dp_cec.c
├── drm_dp_dual_mode_helper.c
├── drm_dp_helper.c
├── drm_dp_mst_topology.c
├── drm_drv.c
├── drm_dsc.c
├── drm_dumb_buffers.c
├── drm_edid.c
├── drm_edid_load.c
├── drm_encoder.c
├── drm_encoder_slave.c
├── drm_fb_cma_helper.c
├── drm_fb_helper.c
├── drm_file.c
├── drm_flip_work.c
├── drm_format_helper.c
├── drm_fourcc.c
├── drm_framebuffer.c
├── drm_gem.c
├── drm_gem_cma_helper.c
├── drm_gem_framebuffer_helper.c
├── drm_gem_shmem_helper.c
├── drm_gem_vram_helper.c
├── drm_hashtab.c
├── drm_hdcp.c
├── drm_internal.h
├── drm_ioc32.c
├── drm_ioctl.c
├── drm_irq.c
├── drm_kms_helper_common.c
├── drm_lease.c
├── drm_legacy.h
├── drm_legacy_misc.c
├── drm_lock.c
├── drm_memory.c
├── drm_mipi_dbi.c
├── drm_mipi_dsi.c
├── drm_mm.c
├── drm_mode_config.c
├── drm_mode_object.c
├── drm_modes.c
├── drm_modeset_helper.c
├── drm_modeset_lock.c
├── drm_of.c
├── drm_panel.c
├── drm_panel_orientation_quirks.c
├── drm_pci.c
├── drm_plane.c
├── drm_plane_helper.c
├── drm_prime.c
├── drm_print.c
├── drm_probe_helper.c
├── drm_property.c
├── drm_rect.c
├── drm_scatter.c
├── drm_scdc_helper.c
├── drm_self_refresh_helper.c
├── drm_simple_kms_helper.c
├── drm_syncobj.c
├── drm_sysfs.c
├── drm_trace.h
├── drm_trace_points.c
├── drm_vblank.c
├── drm_vma_manager.c
├── drm_vm.c
├── drm_vram_helper_common.c
├── drm_vram_mm_helper.c
├── drm_writeback.c

2、

复制代码
1、DRM源码实现
android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm

2、AML方案的DRM主机驱动代码(利用drm框架接口完成核心任务)
android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson

3、各模块debug
android\vendor\amlogic\common\kernel\common_5.4\drivers\gpu\drm\drm_drv.c
MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug category.\n"
"\t\tBit 0 (0x01)  will enable CORE messages (drm core code)\n"
"\t\tBit 1 (0x02)  will enable DRIVER messages (drm controller code)\n"
"\t\tBit 2 (0x04)  will enable KMS messages (modesetting code)\n"
"\t\tBit 3 (0x08)  will enable PRIME messages (prime code)\n"
"\t\tBit 4 (0x10)  will enable ATOMIC messages (atomic code)\n"
"\t\tBit 5 (0x20)  will enable VBL messages (vblank code)\n"
"\t\tBit 7 (0x80)  will enable LEASE messages (leasing code)\n"
"\t\tBit 8 (0x100) will enable DP messages (displayport code)");
module_param_named(debug, drm_debug, int, 0600);

2)数据结构

复制代码
1. component
/android/vendor/amlogic/common/kernel/common_5.4/include/linux/component.h
struct component_ops {
    int (*bind)(struct device *comp, struct device *master, void *master_data);
    int (*unbinde)()
}


1、drm_device
android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_device.h
struct drm_device {
    struct list_head legacy_dev_list;
    struct device *dev;
    struct drm_driver *driver;
    void *dev_private;
    struct drm_minor *primary;
    struct drm_minor *rendor;
    struct drm_master *master;
    
    struct list_head clientlist;
    struct drm_vblank_crtc *vblank;
    spinlock_t vb1_lock;
    u32 max_vblank_count;
    
    unsigned int num_crtcs;  //crtcs数量
    struct drm_mode_config mode_config;
    
    //GEM information
    struct mutex object_name_lock;
    struct idr object_name_idr;  //idr, id allocator
    
    struct drm_vma_offset_manager *vma_offset_manager;
    struct drm_vram_mm *vram_mm;
    
    struct drm_fb_helper *fb_helper;
}

2、drm_driver
android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_drv.h
struct drm_driver {
    int (*load)(struct drm_device *, ...);
    int (*open)(struct drm_device *, struct drm_file *);
    u32 (*get_vblank_counter)(struct drm_device *dev, unsigned int pipe);
    int (*enbale_vblank) (struct drm_device *dev, unsigned int pipe);
    irqreturn_t(*irq_handler) (int irq, void *arg);
    int (*master_create)(struct drm_device *dev, struct drm_master *master);
    int (*debugfs_init)(struct drm_minor *minor);
    int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
    struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
						    size_t size);
	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
				uint32_t handle, uint32_t flags, int *prime_fd);
    struct vm_operations_struct *gem_vm_ops;
    struct drm_ioctrl_desc *ioctrl;
    struct file_operations *fops;
    int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
}

3)DRM的component注册机制

复制代码
1、图显系统包括图显处理器、时序控制设备、编解码设备、PHY等,每个设备的驱动代码可以独立编写,最后通过drm api组织成一个整体,模块化大成;

2、设计思想:
1)master代表图显控制器;辅助单元component,是一堆的图显控制器外围设备,如HDMI、MIPI、LVDS等等。

2)组件式代码架构,由设备树代码和驱动代码组成。
设备树代码
在设备树文件中定义一个master设备结点,以master设备结点为核心,规划和其他组件之间的 连接关系,形成一个完整的图显系统拓扑结构图。
驱动代码
master负责绑定各个component组件,当所有组件均匹配、绑定成功后,DRM图显系统才能正常工作。任何一个组件或master结点被移除,都会引起解绑定事件并将subsystem的状态设置为down。


3、数据结构和接口
/android/vendor/amlogic/common/kernel/common_5.4/include/linux/component.h
struct component_ops {
    int (*bind)(struct device *comp, struct device *master, void *master_data);
    int (*unbinde)()
}

4.
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson/meson_dw_hdmi.c
static const struct component_ops meson_dw_hdmi_ops = {
	.bind	= meson_dw_hdmi_bind,
	.unbind	= meson_dw_hdmi_unbind,
};

static int meson_dw_hdmi_probe(struct platform_device *pdev)
{
	return component_add(&pdev->dev, &meson_dw_hdmi_ops);
}

5.component匹配规则的创建
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_of.c
drm_of_component_match_add(struct device *master, struct component_match **matchptr, int (*compare), struct device_node *node)
/android/vendor/amlogic/common/kernel/common_5.4/drivers/base/component.c
--component_match_add_release()

3)master

复制代码
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson/meson_drv.c

基本数据结构
1.drm_device代表显卡设备
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_device.h
struct drm_device {
    struct device *dev;
    struct drm_driver *driver;
    struct drm_master *master;
    struct drm_vblank_crtc *vblank;
    struct drm_mode_config mode_config; //KMS
    struct drm_vram_mm *vram_mm;
    struct drm_fb_helper *fb_helper;
    struct drm_device_dma *dma;
}

2.master
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_auth.h
struct drm_master {
    struct drm_device *dev;
    struct drm_master *lessor;
}

kernel下的master的初始化
static struct platform_driver meson_drm_platform_driver = {
	.probe      = meson_drv_probe,
	.shutdown   = meson_drv_shutdown,
	.driver     = {
		.name	= "meson-drm",
		.of_match_table = dt_match,
	},
};

module_platform_driver(meson_drm_platform_driver);

meson_drv_probe()
--for_each_endpoint_of_node() //读取设备树节点
//创建并初始化各个component
--meson_drv_bind_master(&pdev->dev) 
----drm_vblank_init(drm, 1);
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_mode_config.c
----drm_mode_config_init(drm);  //初始化KMS
//Hardware Inittialization
----meson_vpu_init(priv);
----meson_venc_init(priv);
----meson_vpp_init(priv);
----meson_viu_init(priv);
----component_bind_all(drm->dev, drm);//绑定所有组件
----meson_plane_create(priv);
----meson_overlay_create(priv);
----meson_crtc_create(priv);
----drm_dev_register(drm, 0); //注册drm核心
1.实例化CRTC的父设备(图显控制器)和功能函数;
2.CRTC的OBJECT添加到DRM中;
3.绑定drm_mode_object;
--component_master_add_with_match(&pdev->dev, &meson_drv_master_ops, match) 

3)KMS

复制代码
与CRTC的差异?由CRTC负责调用KMS接口,进行设置

数据结构
1.drm_mode_config
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_mode_config.h
struct drm_mode_config {
    struct drm_property *tv_subconnector_property; //大量的各种属性
    struct drm_mode_config_funcs *funcs;
    struct drm_atomic_state *suspend_state;
    struct drm_mode_config_helper_funcs *helper_private;
}

2.drm_mode_config_funcs
struct drm_mode_config_funcs {
    struct drm_framebuffer *(*fb_create)();
    struct drm_format_info *(*get_format_info)();
    enum drm_mode_status (*mode_valid)();
    int (*atomic_commit)()
    int (*atomic_check)();
}

3.驱动实现
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_drv.c
static const struct drm_mode_config_funcs meson_mode_config_funcs = {
	.output_poll_changed = am_meson_fb_output_poll_changed,
	.atomic_check        = drm_atomic_helper_check,
	.atomic_commit       = meson_atomic_commit,
#ifdef CONFIG_DRM_MESON_USE_ION
	.fb_create           = am_meson_fb_create,
#else
	.fb_create           = drm_gem_fb_create,
#endif
};

用户会提交各种各样的图显系统的模式配置信息,比如屏幕分辨率以及色彩属性 都是模式配置

实例化KMS的各种资源

3)CRTC

复制代码
功能:
DRM下的CRCT代表RGB数据通道,从drm_plane接收像素数据并将其混合到一起,传输给下级显示设备drm_encoder,由drm_display_mode控制时序;


数据结构
1.
struct drm_crtc {
    struct drm_device *dev;
    struct device_nde *port;
    struct drm_plane *primary;
    struct drm_plane *cursor;
    struct drm_display_mode mode;
    struct drm_display_mode hwmode;
    struct drm_crtc_funcs *funcs;
    drm_crtc_helper_funcs *helper_private;
    drm_object_properties properties;
    struct drm_property *scaling_filter_property;
    struct drm_crtc_state *state;
}

2.主要用来控制 CRTC
struct drm_crtc_funcs {
    void (*reset)(struct drm_crtc *crtc);
    int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
			  uint32_t handle, uint32_t width, uint32_t height);
    int (*set_config)(struct drm_mode_set *set,
			  struct drm_modeset_acquire_ctx *ctx);
    int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
			 uint32_t size,
			 struct drm_modeset_acquire_ctx *ctx);
	int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
			 struct drm_pending_vblank_event *event,
			 uint32_t flags,
			 struct drm_modeset_acquire_ctx *ctx);
    int (*enable_vblank)(struct drm_crtc *crtc);
}

3.配置 CRTC 相关模块时所需的中间辅助代码
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_modeset_helper_vtables.h
struct drm_crtc_helper_funcs {
    void (*prepare)(struct drm_crtc *crtc);
    void (*commit)(struct drm_crtc *crtc);
    int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
			struct drm_display_mode *adjusted_mode, int x, int y,
			struct drm_framebuffer *old_fb);
    int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *state);
    void (*atomic_begin)(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state);
    void (*atomic_flush)(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state);
    void (*atomic_enable)(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state);
}

4. drm_display_mode - 屏参配置
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_modes.h
drm_display_mode
 *               Active                 Front           Sync           Back
 *              Region                 Porch                          Porch
 *     <-----------------------><----------------><-------------><-------------->
 *       //////////////////////|
 *      ////////////////////// |
 *     //////////////////////  |..................               ................
 *                                                _______________
 *     <----- [hv]display ----->
 *     <------------- [hv]sync_start ------------>
 *     <--------------------- [hv]sync_end --------------------->
 *     <-------------------------------- [hv]total ----------------------------->*

 struct drm_display_mode {
     char name[DRM_DISPLAY_MODE_LEN];
     /**
	 * @clock:
	 *
	 * Pixel clock in kHz.
	 */
	int clock;		/* in kHz */
	int hdisplay;
	int hsync_start;
	int hsync_end;
	int htotal;
	int hskew;
	int vdisplay;
	int vsync_start;
	int vsync_end;
	int vtotal;
	int vscan;
	/**
	 * @crtc_clock:
	 *
	int crtc_clock;
	int crtc_hdisplay;
	int crtc_hblank_start;
	int crtc_hblank_end;
	int crtc_hsync_start;
	int crtc_hsync_end;
	int crtc_htotal;
	int crtc_hskew;
	int crtc_vdisplay;
	int crtc_vblank_start;
	int crtc_vblank_end;
	int crtc_vsync_start;
	int crtc_vsync_end;
	int crtc_vtotal;
 }


crtc初始化
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson/meson_crtc.c
meson_crtc_create()
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_crtc.c
--drm_crtc_init_with_planes(priv->drm, crtc, priv->primary_plane, NULL, &meson_crtc_funcs, "meson_crtc")
--meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)
----meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1;
----meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1;
----meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET;


TEST
1、CRTC模式配置
echo 0xf > /sys/module/drm/parameters/debug
测试程序
./tests/modetest/modetest -M vmwgfx -D 0 -a -s 34@36:1280x960  -P 32@36:1280x960 -Ftiles

2、dmesg信息
[46312.678360] [drm:drm_vblank_enable [drm]] enabling vblank on crtc 0, ret: -22
[46312.728218] [drm:drm_ioctl [drm]] pid=1036, dev=0xe200, auth=1, DRM_IOCTL_MODE_SETCRTC
[46312.728238] [drm:drm_mode_setcrtc [drm]] [CRTC:36:crtc-0]
[46312.728593] [drm:drm_calc_timestamping_constants [drm]] crtc 36: hwmode: htotal 1737, vtotal 1011, vdisplay 861
[46312.729432] [drm:vmw_du_crtc_gamma_set [vmwgfx]] 0 r/g/b = 0x0000 / 0x0000 / 0x0000
[46416.541769] [drm:drm_ioctl [drm]] pid=94191, dev=0xe200, auth=1, DRM_IOCTL_MODE_GETCRTC

3)plane-即HWC

复制代码
基本作用:
1)DRM PLANE 从 drm_framebuffer 接收数据,构造送显图像的雏形,完成图像的剪裁、缩放、旋转、叠加等效果后发送到&drm_crtc。除此之外,还通过 drm_plane_state来提供图像旋转功能。
2)与CRTC的关系,每个CRTC 需要定义一个 primary plane 以及可选的 overlay plane、cursor plane。

3) PLANE(即HWC)存在的意义主要有两点:
1、增强系统灵活性
对于桌面系统而言,显示器背景图案和鼠标光标通常是基本的显示元素,并且一直存在直到系统关机。因此,对于这种变化不是很频繁的基本图显输出,可以由通用 plane 来实现。而那些频繁变化的图显输出,交由专用的 plane 来实现。
2、提高系统性能
由于 plane 具备图像缩放、剪裁、多图层叠加等功能,因此,可以让 GPU 来将更多的精力放在图形渲染上,这种基本的图像处理交由 plane 实现。

4)plane的数量由硬件决定(即HWC合成的层数)
1、AML平台划分为:vd1、vd2、osd1、osd2等
2、

数据结构
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_plane.h
struct drm_plane {
    struct drm_device *dev;
    struct drm_mode_object base;
    uint32_t possible_crtcs;
    uint32_t *format_types;
    unsigned int format_count;
    uint64_t *modifiers;
    struct drm_crtc *crtc;
    struct drm_framebuffer *fb;
    struct drm_plane_funcs *funcs;
    enum drm_plane_type type;
    struct drm_plane_helper_funcs *helper_private;
    struct drm_property *scaling_filter_property;
}

enum drm_plane_type {
    DRM_PLANE_TYPE_OVERLAY,
    DRM_PLANE_TYPE_PRIMARY,
    DRM_PLANE_TYPE_CURSOR,
}

初始化
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson/meson_plane.c
meson_plane_create()
--drm_universal_plane_init(priv->drm, plane, 0xFF, &meson_plane_funcs, supported_drm_formats)
--drm_plane_helper_add(plane, &meson_plane_helper_funcs);
--drm_plane_create_zpos_immutable_property(plane, 1);
--priv->primary_plane = plane;

更新plane,执行合成动作
1、meson_plane_atomic_update()
2、drm_atomic_helper_update_plane()


测试验证
echo 0xf > /sys/module/drm/parameters/debug

./tests/modetest/modetest -M vmwgfx -D 0 -a -s 34@36:1280x960  -P 32@36:1280x960 -Ftiles

dmesg

atomic_set_planes()
[  438.833181] [drm:drm_ioctl [drm]] pid=8888, dev=0xe200, auth=1, DRM_IOCTL_MODE_OBJ_GETPROPERTIES
[  438.833191] [drm:drm_ioctl [drm]] pid=8888, dev=0xe200, auth=1, DRM_IOCTL_MODE_GETPROPERTY
...
[  794.887990] [drm:drm_atomic_set_fb_for_plane [drm]] Set [FB:227] for plane state 0000000082b6801c
...
[  796.326527] [drm:drm_atomic_get_plane_state [drm]] Added [PLANE:32:plane-0] 00000000c67dc9f6 state to 000000006b70d79e

图层叠加流程

plane属性对应的显示参数关系图:

4)Encoder&connector

复制代码
基本概念
Encoder包含外设控制器功能(LCD控制器、HDMI控制器);
connecter包含外设PHY或显示器参数;

数据结构
1、
/android/common-5.15/common/include/drm/drm_encoder.h
struct drm_encoder {
    struct drm_device *dev;
    struct list_head head;
    
    struct drm_mode_object base;
    char *name;
    int encoder_type;
    unsigned index;
    uint32_t possible_crtcs;
    uint32_t possible_clones;
    struct drm_crtc *crtc;
    struct list_head bridge_chain;
    const struct drm_encoder_funcs *funcs;
    const struct drm_encoder_helper_funs *helper_private;
}

/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_encoder.h
struct drm_encoder_funcs {
    void (*reset)(struct drm_encoder *encoder);
    void (*destroy)(struct drm_encoder *encoder);
    int (*late_register)(struct drm_encoder *encoder);
    void (*early_unregister)(struct drm_encoder *encoder);
}

/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_modeset_helper_vtables.h
struct drm_encoder_helper_funcs {
    void (*dpms)(struct drm_encoder *encoder, int mode);
    enum drm_mode_status (*mode_valid)(struct drm_encoder *crtc,
					   const struct drm_display_mode *mode);
	void (*prepare)(struct drm_encoder *encoder);
	void (*commit)(struct drm_encoder *encoder);
	void (*atomic_mode_set)(struct drm_encoder *encoder,
				struct drm_crtc_state *crtc_state,
				struct drm_connector_state *conn_state);
	struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
					    struct drm_connector *connector);
    void (*atomic_enable)(struct drm_encoder *encoder,
			      struct drm_atomic_state *state);
    int (*atomic_check)(struct drm_encoder *encoder,
			    struct drm_crtc_state *crtc_state,
			    struct drm_connector_state *conn_state);
}

meson下有两个encoder
1.HDMI
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_hdmi.c
2.CVBS
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_cvbs.c
3.lcd
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_lcd.c

int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, const struct drm_encoder_funcs *funcs, int encoder_type, const char *name, ...)


1、hdmi encoder初始化
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/meson/meson_dw_hdmi.c
static struct platform_driver meson_dw_hdmi_platform_driver = {
	.probe		= meson_dw_hdmi_probe,
	.remove		= meson_dw_hdmi_remove,
	.driver		= {
		.name		= DRIVER_NAME,
		.of_match_table	= meson_dw_hdmi_of_table,
	},
};
module_platform_driver(meson_dw_hdmi_platform_driver);

1.组件添加
meson_dw_hdmi_probe(struct platform_device *pdev)
--component_add(&pdev->dev, &meson_dw_hdmi_ops);

2.bind
meson_dw_hdmi_bind()
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_modeset_helper_vtables.h
--drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_encoder.c
2.构造encode结构体
--drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,DRM_MODE_ENCODER_TMDS, "meson_hdmi");
----drm_mode_object_add(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);

5)GEM

复制代码
基本概念
Graphics Execution Management
Buffer管理和分配,类似android下的ion(低版本)、高版本DMA-BUFF(Android12),对接Android的gralloc hal

cma : contiguous memory allocator
vma

数据结构
1.drm_gem_object作为gem模块的内存分配单位
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_gem.h
struct drm_gem_object {
    struct kref refcount;
    unsigned handle_count;
    struct drm_device *dev;
    struct file *file;
    struct drm_vma_offset_node vma_node;
    size_t size;
    int name;
    struct dma_buf *dma_buf;
    struct dma_buf_attachment *import_attach;
    struct dma_resv *resv;
    struct dma_resv _resv;
    struct drm_gem_object_funcs *funcs;
}


2.用户空间ioctl接口
drm_gem_object的分配和销毁
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, 0),


3.内核通过kmalloc、dma、mmap等内存分配接口 分配对应内存,再返回给应用程序
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_gem.c
/android/vendor/amlogic/common/kernel/common_5.4/drivers/dma-buf

1)object 的create/destroy等接口
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_drv.c
static struct drm_driver meson_driver = {
 	/* GEM Ops */
  	.dumb_create			= am_meson_gem_dumb_create,
  	.dumb_destroy		= am_meson_gem_dumb_destroy,
  	.dumb_map_offset		= am_meson_gem_dumb_map_offset,
  	.gem_free_object_unlocked	= am_meson_gem_object_free,
  	.gem_vm_ops			= &drm_gem_cma_vm_ops,
  	.ioctls			= meson_ioctls,
  	.num_ioctls		= ARRAY_SIZE(meson_ioctls),
}

函数 drm_mode_create_dumb()里创建 buffer 的功能实体,需要由驱动来实现,当然,驱动代码若未实现 SoC 特定的 create buffer 代码,也可以使用 DRM 提供的 drm_gem_cma_dumb_create()。

4.GEM object的使用
GEM object是在内核空间创建的,并没有导出到用户空间。在用户空间有两种操控方法,第一种是基于I/O 的方式,第二种是mmap 的方式。而实际应用中,普遍采用的是后者。
1)mmap映射给用户空间
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0),
--drm_gem_dumb_map_offset()
----drm_gem_create_mmap_offset()
----drm_vma_node_offset_addr()

应用层完成GEM object的内存映射后,可以向该缓冲区刷新图像数据。完成fb相关的其他配置后,将地址信息传递给图像处理器的plane即可。

2)填充数据
/android/external/libdrm/tests/util/pattern.c
fill_tiles_rgb32()

1、应用层配置framebuffer
atomic_set_plane()
{
		if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
			handles, pitches, offsets, &p->fb_id, 0)) {
			fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
			return -1;
		}
}

2、将GEM object的handle和FRAMEBUFFER的fb_id关联,由驱动获取GEM内存地址,再将地址信息传递给图像处理器的PLANE模块。
struct drm_gem_cma_object *obj;
obj = drm_fb_cma_get_gem_obj(fb, plane_index);

if (WARN_ON(!obj))
	return;
paddr = obj->paddr;	

6)FRAMEBUFFER

复制代码
1、FB的地位层级
参照传统fb架构,Drm下实现的FRAMEBUFFER,额外增加了GEM管家统一管理FRAMEBUFFER

2、基本数据结构
/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_framebuffer.h
struct drm_framebuffer {
    struct drm_device *dev;
    struct drm_mode_object base;
    char comm[TASK_COMM_LEN]; //每一块fb内存 的名字
    struct drm_format_info *format;
    struct drm_framebuffer_funcs *funcs;
    struct drm_gem_object *obj[4];
}

/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_framebuffer.h
struct drm_framebuffer_funcs {
    void (*destory)(struct drm_framebuffer *framebuffer);
    int (*create_handle)(struct drm_framebuffer *fb, struct drm_file *file_priv, int *handle);
    int (*dirty)(struct drm_framebuffer *framebuffer,
		     struct drm_file *file_priv, unsigned flags,
		     unsigned color, struct drm_clip_rect *clips,
		     unsigned num_clip )
}

/android/vendor/amlogic/common/kernel/common_5.4/include/drm/drm_mode_object.h
struct drm_mode_object {
	uint32_t id;
	uint32_t type;
	struct drm_object_properties *properties;
	struct kref refcount;
	void (*free_cb)(struct kref *kref);
};


3、用户层申请fb
/android/external/libdrm/include/drm/drm.h
对应的ioctrl
#define DRM_IOCTL_MODE_ADDFB2		DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)

/android/external/libdrm/include/drm/drm_mode.h
struct drm_mode_fb_cmd2 {
	__u32 fb_id; //kernel DRM fb_create()创建的 fb id
	__u32 width;
	__u32 height;
	__u32 pixel_format;
	__u32 flags;
	__u32 handles[4]; //GEM 的 handle,最多支持 4 个内存区域
	__u32 pitches[4]; //单行数据所占的内存大小,单位是 Byte
	__u32 offsets[4];
	__u64 modifier[4];
};

/android/external/libdrm/xf86drmMode.c
drmModeAddFB2WithModifiers()
--DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f)
----陷入到内核

4、kernel下的meson fb初始化
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_drv.c
am_meson_drm_bind()
--am_meson_drm_fbdev_init()
----am_meson_create_drm_fbdev(dev, drmdev->primary_plane);
------drm_fb_helper_prepare(dev, helper, &meson_drm_fb_helper_funcs);
--------am_meson_drm_fbdev_probe()
----------am_meson_drm_framebuffer_init()

/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_fbdev.c
static const struct drm_fb_helper_funcs meson_drm_fb_helper_funcs = {
	.fb_probe = am_meson_drm_fbdev_probe,
};

/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_fb.c
struct drm_framebuffer_funcs am_meson_fb_funcs = {
	.create_handle = am_meson_fb_create_handle, //must for fbdev emulate
	.destroy = am_meson_fb_destroy,
};

/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_fb.c
am_meson_drm_framebuffer_init()
--am_meson_fb_alloc()
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_framebuffer.c
----drm_framebuffer_init(dev, &meson_fb->base, &am_meson_fb_funcs);
------__drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,); //注册fb类型的 object
------drm_mode_object_register(dev, &fb->base);

5、plane使用fb
1) plane关联fb
/android/vendor/amlogic/common/kernel/common_5.4/drivers/gpu/drm/drm_atomic_uapi.c
drm_atomic_plane_set_property()
--drm_atomic_set_fb_for_plane()

add_property(dev, p->plane_id, "FB_ID", p->fb_id);
add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id);
复制代码
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_drv.c
am_meson_drm_bind()
/android/vendor/amlogic/common/kernel/common_5.4/drivers/amlogic/drm/meson_logo.c
--am_meson_logo_init()
----drm_framebuffer_put(fb);

6、Android下的libdrm

1、Android libdrm基本API: https://www.jianshu.com/p/d21d7093fbff

2、源码分析

复制代码
谁来调用?hwcomposer

1、drm接口汇总
/android/external/libdrm/core-symbols.txt

1、打开/dev/dri/card0设备节点
/android/external/libdrm/xf86drm.c //User-level interface to DRM device,xFree86为历史命名
drmOpen()
--drmOpenWithType()
----drmOpenByName()
------drmOpenDevice()

/android/external/libdrm/xf86drm.h
#define DRM_DIR_NAME  "/dev/dri"
#define DRM_PRIMARY_MINOR_NAME  "card"
#define DRM_CONTROL_MINOR_NAME  "controlD"
#define DRM_RENDER_MINOR_NAME   "renderD"

2、打开/dev/dri/Control设备节点
drm_public int drmOpenControl(int minor)
{
    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
}

3、打开/dev/dri/Render设备节点
drm_public int drmOpenRender(int minor)
{
    return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
}

4、drmIoctl
/android/external/libdrm/xf86drm.c
drmIoctl(int fd, unsigned long request, void *arg);
/android/external/libdrm/include/drm/drm.h
#define DRM_IOCTL_MODE_GETCRTC		DRM_IOWR(0xA1, struct drm_mode_crtc)
#define DRM_IOCTL_MODE_SETCRTC		DRM_IOWR(0xA2, struct drm_mode_crtc)

5、常用API
1) drmSetClientCap(int fd, uint64_t capability, uint64_t value); //设置 drm 的capability 属性
2) drmModeGetResources(int fd); //获取connector、encoder、crtc的数量和ID信息

7、DRM调试

复制代码
/sys/module/drm/parameters

echo 0xf > /sys/module/drm/parameters/debug  //打开DRM打印

测试crtc
./tests/modetest/modetest -M vmwgfx -D 0 -a -s 34@36:1280x960  -P 32@36:1280x960 -Ftiles

dmesg --follow > /data/dmesg_drm_1.log &
相关推荐
STCNXPARM1 天前
Android14显示系统 - SurfaceFlinger
surfaceflinger·android显示系统