i.MX8MP上的MIPI DSI驱动加载分析

1,059 阅读3分钟

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的初始值。

关注【求密勒实验室】,一起交流技术~