drm显示驱动的加载过程:
1.加载GPU驱动 mix_gpu_ml
2.加载lcdifv3驱动
3.加载mipi dsim驱动
4.加载lvds驱动
5.加载hdmi驱动
6.加载panel驱动
drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c是vivante gpu的drm驱动中间层,实现了drm对GPU的访问,GPU最底层驱动代码不开源。
我们这里分析drm_core->mipi dsim->panel的显示驱动过程。
首先是master设备的加载,imx-drm-core作为master设备会被优先加载,在整个drm框架中作为master节点,然后会去dts中查找ports节点,每个port就是一个component设备。于是在找到后又会去调用每一个component设备的bind函数(HDMI/LVDS/MIPI)来绑定,以mipi为例,就是调用imx_sec_dsim_bind函数。再所有的component绑定完成后,imx-drm-core才真正驱动成功。
这是一个简单的结构图,根据流程图,读者可以自行了解drm驱动的加载过程。
现在默认代码已经进入了mipi bridge的驱动,入口函数是sec_mipi_dsim_bind。下面将主要说明两个ops函数。
1.sec_mipi_dsim_host_ops
static const struct mipi_dsi_host_ops sec_mipi_dsim_host_ops = {
.attach = sec_mipi_dsim_host_attach,
.detach = sec_mipi_dsim_host_detach,
.transfer = sec_mipi_dsim_host_transfer,
};
这个数据结构主要是用于dsim的host端和panel端的绑定、解绑和命令传输。
在绑定的时候,需要对mipi_dsi_device的设备属性进行排查(这里的mipi_dsi_device其实就是panel,具体的屏幕设备),i.MX8MP上的mipi只支持三种dsi模式:MIPI_DSI_MODE_VIDEO、MIPI_DSI_MODE_VIDEO_BURST、MIPI_DSI_MODE_VIDEO_SYNC_PULSE。
数据格式只支持RGB888、RGB565、RGB666、RGB666_PACKED,最后将panel里的属性(通道数、数据格式、工作模式)设置进mipi ip里。
命令传输(mipi host->mipi bridge),sec_mipi_dsim_host_transfer将mipi_msg那边需要发送的command设置进SFR寄存器,并且读取SFR寄存器获得mipi返回的响应。
2.sec_mipi_dsim_bridge_funcs
static const struct drm_bridge_funcs sec_mipi_dsim_bridge_funcs = {
.attach = sec_mipi_dsim_bridge_attach,
.enable = sec_mipi_dsim_bridge_enable,
.disable = sec_mipi_dsim_bridge_disable,
.mode_set = sec_mipi_dsim_bridge_mode_set,
.mode_fixup = sec_mipi_dsim_bridge_mode_fixup,
};
sec_mipi_dsim_bridge_funcs主要是操作mipi bridge这个ip的一系列功能函数。
sec_mipi_dsim_bridge_attach在dts中查找bridge(这里的bridge是虚拟化的,可以看成是lcdif和dsi之间的数据通道)并绑定,将lcdif1接口和dsi进行绑定。mipi dsi驱动可以视为encoder,lcdif是crtc,bridge就是mipi ip的驱动
2.1 sec_mipi_dsim_bridge_enable
设置显示模式、dpi、pll、dphy时序;打开panel硬件;设置数据传输位,数据开始传输。
2.2 sec_mipi_dsim_bridge_mode_set
将用户层显示模式的改动设置进驱动层。
2.3 sec_mipi_dsim_bridge_mode_fixup
模式修正函数,检查lcdif传入的数据格式是否和mipi输出的数据格式相同;对1280x720@60
模式进行修正。
3.设置connector的功能
连接使用connector一端物理panel,一端连接encoder(dsi)。
3.1 sec_mipi_dsim_connector_helper_funcs
static const struct drm_connector_helper_funcs
sec_mipi_dsim_connector_helper_funcs = {
.get_modes = sec_mipi_dsim_connector_get_modes,
};
获取屏幕的显示模式。
3.2 sec_mipi_dsim_connector_funcs
static const struct drm_connector_funcs sec_mipi_dsim_connector_funcs = {
.detect = sec_mipi_dsim_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = drm_connector_cleanup,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
3.2.1 sec_mipi_dsim_connector_detect
检测panel是否连接上,这里驱动未实现具体的检测方法,直接返回已连接。
3.2.2 drm_helper_probe_single_connector_modes
由drm_probe_helper.c实现,这是linux自带的官方drm代码,非i.MX独有。
3.2.3 drm_atomic_helper_connector_duplicate_state
atomic框架参考文章:lwn.net/Articles/65…
在每次commit之前,都会调用panel/crtc的drm_atomic_helper_connector_duplicate_state接口,以便将上一次的state复制为下一次commit的初始值。
关注【求密勒实验室】,一起交流技术~