最近在学习MIPI接口的LCD驱动开发与调试,这里我主要用的是MIPI-DSI接口,它学习起来真的是太复杂了,特别是对于我这种很久都没写驱动来说更是头疼,但是头疼归头疼,工作咱们还是要完成的,那就只能硬着头皮往下肝吧!
首先了解下什么是MIPI-DSI
:
MIPI-DSI
是一种应用于显示技术的串行接口,兼容DPI(显示像素接口,Display Pixel Interface
)、DBI(显示总线接口,Display Bus Interface
)和DCS(显示命令集,Display Command Set
),以串行的方式发送像素信息或指令给外设,而且从外设中读取状态信息或像素信息,而且在传输的过程中享有自己独立的通信协议,包括数据包格式和纠错检错机制。下图所示的是MIPI-DSI接口的简单示意图。MIPI-DSI
具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等格式通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。此外,一个主机端可允许同时与多个从属端进行通信。(摘抄自网友)
那么,在Linux中调试MIPI LCD
需要注意哪些细节呢?分别是:
- 供电
- 复位
- 时序
- 像素时钟
- MIPI时钟(本章不涉及)
- MIPI命令(本章不涉及)
- MIPI数据格式(本章不涉及)
在Linux驱动开发过程中,一般通用的MIPI的驱动都是现成的,比如以下的simple-panel-dsi
,就是通用的MIPI接口LCD驱动,它在Linux内核中位于driver/gpu/drm/panel
目录下,对应的文件是:panel-simple.c
。
一般使用通用的MIPI LCD驱动,我们只需要根据自己选购的屏的参数进行配置即可,也就是只需要配置设备树即可顺利完成点屏的操作,那么如何来配置相关参数呢?这里我用的是瑞芯微的RV1109方案,在此借用荣品LCD的设备树我们来学习下它的设备树参数:
代码语言:javascript复制&dsi {
status = "okay";
rockchip,lane-rate = <480>;
panel@0 {
compatible ="simple-panel-dsi";
reg = <0>;
backlight = <&backlight>;
/delete-property/ power-supply;
prepare-delay-ms = <100>;
reset-delay-ms = <10>;
init-delay-ms = <100>;
disable-delay-ms = <50>;
unprepare-delay-ms = <20>;
width-mm = <68>;
height-mm = <121>;
pinctrl-names = "default";
pinctrl-0 = <&vdd_5v_3v3_h>;
enable-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
dsi,format = <MIPI_DSI_FMT_RGB888>;
dsi,lanes = <4>;
panel-init-sequence = [
05 78 01 11
05 78 01 29
];
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <51000000>;
hactive = <1024>;
vactive = <600>;
hback-porch = <160>;
hfront-porch = <136>;
vback-porch = <16>;
vfront-porch = <16>;
hsync-len = <4>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in_dsi: endpoint {
remote-endpoint = <&dsi_out_panel>;
};
};
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
dsi_out_panel: endpoint {
remote-endpoint = <&panel_in_dsi>;
};
};
};
};
上面提供了非常多的节点,但是怎么去理解这些节点呢??Linux内核为我们提供了丰富的文档:
有了这些文档,我们再来看上面设备树节点的内容就简单多了,当然我们也可以结合代码来理解这些参数的含义:
先列举一些重要的参数:
1、enable-gpios和reset-gpios
enable-gpios配置的是LCD的使能脚,reset-gpios配置的是LCD的复位脚:
代码语言:javascript复制enable-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
如上所示,为什么是27和4,我们要查询下IO口绑定的编号,如下:
2、hactive, vactive:
表示显示分辨率,在设备树里一般如下表示:
代码语言:javascript复制hactive = <1024>; //水平分辨率
vactive = <600>; //垂直分辨率
跟分辨率相关的内容我们一般都可以从LCD厂家提供的数据手册里找到它们:
3、dsi,lanes
确定接口类型为MIPI,MIPI能够实现多通道差分传输,所以通过数据手册我们可以了解它具体有多少路:
根据数据手册,我们很容易了解到数据通道有4组,所以对应设备树中的配置如下:
代码语言:javascript复制dsi,lanes = <4>; //表示使用 4lane 传输数据
4、时序
一般厂家FAE会给到我们一组参数,分别是:
代码语言:javascript复制lane个数(与原理图匹配)
HSA、HBP、HACT、HFP
VSA、VBP、VACT、VFP
FR
pixel_clk (KHZ)
phy_data_rate (Mbps)
其中参考了网上的一些计算公式:
(1)HBB = HSA HBP
(2)VBB = VSA VBP
(3)pixel_clk = round((HBB HACT HFP)*(VBB VACT VFP)*FR/1000) KHZ
(4)phy_data_rate = round((HBB HACT HFP)*(VBB VACT VFP)*FR*output_format/lane个数/1000000) Mbps
output_format是输出数据字节数,例:RBG24即为24
根据以上提供的这些参数就可以完成MIPI DSI
的时序初始化。比如我随便找一个LCD的数据手册就会看到:
4.1、以像素为单位的水平显示时序参数
在LCD屏厂手册里一般都会提供以下三个参数,分别是:
- hfront-porch:(HFP)
- hback-porch:(HBP)
- hsync-len:(HSA)
荣品的LCD手册里没有提供这部分的时序描述,仅在设备树里配置了几个参数而已,至于为什么那么配,我也不知道,只能说知道是什么含义就行了:
代码语言:javascript复制hback-porch = <160>;
hfront-porch = <136>;
hsync-len = <4>;
相对应的在以像素为单位的水平时序里还有一个水平脉冲的配置选项:hsync-active
,官方文档描述是:hsync pulse is active low/high/ignored
,也就是说,如果要配置的话要么就是0/1,要么就不配置,默认配置:
hsync-active = <0>;
4.2、以行为单位的垂直显示时序参数
在LCD屏厂手册里一般都会提供以下三个参数,分别是:
- vfront-porch:(VFP)
- vback-porch:(VBP)
- vsync-len:(VSA)
荣品的LCD手册里没有提供这部分的时序描述,仅在设备树里配置了几个参数而已,至于为什么那么配,我也不知道,只能说知道是什么含义就行了:
代码语言:javascript复制vback-porch = <16>;
vfront-porch = <16>;
vsync-len = <2>;
相对应的在以行为单位的垂直显示时序里还有一个水平脉冲的配置选项:vsync-active
,官方文档描述是:vsync pulse is active low/high/ignored
,也就是说,如果要配置的话要么就是0/1,要么就不配置,默认配置:
vsync-active = <0>;
4.3、数据使能 & 像素时钟脉冲参数
(1)de-active:data-enable pulse is active low/high/ignored
de-active = <0>;
(2)pixelclk-active:数据采样的方式
配置为1:上升沿驱动像素数据/下降沿采样数据
配置为0:下降沿驱动像素数据/上升沿采样数据
代码语言:javascript复制pixelclk-active = <0>;
5、像素时钟的配置
一般像素时钟有一个计算公式,如下:
代码语言:javascript复制(h hbp hfp hsa)*(v vbp vfp vsa)*60
也就是说把厂家手册提供给我们的时序参数往这个公式里面套,最终就可以算出我们的像素时钟是多少了。
6、panel-init-sequence
这部分一般指的是厂家给我们提供的屏幕的初始化代码,官方文档的介绍是这样的:
代码语言:javascript复制A byte stream formed by simple multiple dcs packets.
byte 0: dcs data type
byte 1: wait number of specified ms after dcs command transmitted
byte 2: packet payload length
byte 3 and beyond: number byte of payload
荣品的设备树这部分配置如下:
代码语言:javascript复制panel-init-sequence = [
05 78 01 11
05 78 01 29
];
还有很多内容,分几个章节来写吧,今天就学习总结到这了。