MIPI LCD CMD模式和VIDEO模式驱动代码分析
目前MIPI 控制器支持CMD 模式和VIDEO 模式,对于新增LCD 屏的配置如下:
文件路径:arch/arm/plat-lc/drivers/video/comipfb2
新增文件名称:lcd_xxx_sss.c (xxx: 屏厂名称;sss:IC 厂名称)
(1)所需结构体介绍:
struct comipfb_dev
struct comipfb_dev {
const char* name; /* Device name. */
unsigned int interface_info;//interface infomation MIPI or RGB
unsigned int lcd_id;
unsigned int refresh_en; /* Refresh enable. */
unsigned int pclk; /* Pixel clock in HZ. */
unsigned int bpp; /* Bits per pixel. */
unsigned int xres; /* Device resolution. */
unsigned int yres;
unsigned int width; /* Width of device in mm. */
unsigned int height; /* Height of device in mm. */
unsigned int flags; /* Device flags. */
union {
//struct comipfb_dev_timing_rgb rgb;
struct comipfb_dev_timing_mipi mipi;
} timing;
struct comipfb_dev_cmds cmds_init;
struct comipfb_dev_cmds cmds_suspend;
struct comipfb_dev_cmds cmds_resume;
struct comipfb_dev_cmds esd_cmd;
struct comipfb_dev_cmds esd_rsp;
struct bl_cmds backlight_info;
int (*reset)(struct comipfb_info *fbi);
int (*suspend)(struct comipfb_info *fbi);
int (*resume)(struct comipfb_info *fbi);
};
Name:lcd 设备名称。
Interface_info:屏使用接口信息。一般固定为COMIPFB_MIPI_IF。
Lcd_id:LCD 当同一块单板上使用两款以上的屏时,需要设置该成员。
Refresh_en:自刷新使能。一般Video 模式需要打开自刷新功能;
Pclk:像素时钟频率。该时钟需要满足如下公式:
pclk = pll1_out / (div +1) / 8 * (grp +1);其中pll1_out 默认为1248Mhz,div 和grp 为
寄存器AP_PWR_LCDC0CLK_CTL 中相应字段;
Bpp:像素深度,表示每个像素用多少个bit 位来存储,根据输入的像素格式进行配置,
一般固定为32。
Xres:显示宽度,以像素为单位。
Yres:显示高度,以像素为单位。
Width:屏幕宽度,单位为mm,目前没有设置。
Hight:屏幕高度,单位为mm,目前没有设置。
Cmds_int:初始化命令参数结构。命令的结构为:对于长包而言(命令+参数 > 2 的
包):{Delay,命令模式,命令的类型,总长度,命令及其参数的长度,命令,参数};
对于短包而言:{Delay,命令模式,命令的类型,命令及其参数的长度,命令,参数}
Cmds_suspend:睡眠命令参数结构。
Cmds_resume:唤醒命令参数结构。
esd_cmd:如果单板支持ESD 功能,该命令指向ESD 功能发送命令数组。
esd_rsp:如果单板支持ESD 功能,该命令指向ESD 功能返回命令数组。
backlight_info:如果单板的背光调节采用CABC 技术,则该数据结构设定有效,其
指向的数组代表调节背光的命令及参数,这个数据结构中包含有名为brightness_bit 的成
员变量,他表示设置的亮度值在MIPI CMD 命令的第几个字节。
reset、resume、suspend:抽象接口函数指针,驱动通过这三个函数指针访问对应的
屏的功能函数。
struct comipfb_dev_timing_mipi
struct comipfb_dev_timing_mipi {
unsigned int hs_freq; /*PHY output freq, bytes KHZ*/
unsigned int lp_freq; /*default is 10MHZ*/
unsigned int no_lanes; /*lane numbers*/
unsigned int display_mode; //video mode or command mode.
unsigned int auto_stop_clklane_en;
unsigned int im_pin_val;
struct mipi_color_bits color_mode; /*color bits*/
struct video_mode_info videomode_info;
struct command_mode_info commandmode_info;
struct phy_time_info phytime_info;
struct te_info teinfo;
struct external_info ext_info;
};
Hs_freq:每条Lane 的PHY 的高速时钟频率,以Kbytes 为单位。需要满足一下公式:
hs_freq/8 = phy_ref_freq * loop_divider * 1.0 / input_divider;其中hs_freq 为26Mhz;
Lp_freq:以KHz 为单位,表示MIPI 接口Lane0 的PHY 低速时钟频率,默认值为
10MHz。建议由hs_freq 整数倍分频得到,必须小于20Mhz;
No_lanes:lane 个数。
Auto_stop_clklane_en:clklane 自动停止使能。
Im_pin_val:VIDE/CMD 模式选择pin 脚值。该引脚一般不会使用;
Color_mode:MIPI 接口输出像素格式定义;
Videoomde_info:VIDEO 模式信息。
Commandmode_info:CMD 模式信息。
Phytime_info:PHY 时序相关信息。
Teinfo:te 相关信息。
Ext_info:扩展信息。
struct mipi_color_bits
struct mipi_color_bits {
unsigned int color_bits; // must be set !!
unsigned int is_18bit_loosely; // optional
};
color_bits:MIPI 要传输的像素bit 位数。目前一般采用COLOR_CODE_24BIT,表
示RGB888。
is_18bit_loosely:只对每个pixel 用18bits 表示有效,表示使能 18 位的loosely packet
pixel stream。
struct video_mode_info
struct video_mode_info {
unsigned int hsync; /* Horizontal Synchronization, unit : pclk. */
unsigned int hbp; /* Horizontal Back Porch, unit : pclk. */
unsigned int hfp; /* Horizontal Front Porch, unit : pclk. */
unsigned int vsync; /* Vertical Synchronization, unit : line. */
unsigned int vbp; /* Vertical Back Porch, unit : line. */
unsigned int vfp; /* Vertical Front Porch, unit : line. */
unsigned int hs_pol:1; /* lcdc hs pol 1 is high for lcdc , is low for mipi*/
unsigned int vs_pol:1; /* lcdc vs pol 1 is high for lcdc, is low for mipi*/
unsigned int dataen_pol:1; /* lcdc has not this bit, mipi dataen ,use default value
currently: 1 low activate*/
unsigned int lp_cmd_en:1;
unsigned int frame_bta_ack:1;
unsigned int lp_hfp_en:1; // default should be 1
unsigned int lp_hbp_en:1;
unsigned int lp_vact_en:1;
unsigned int lp_vfp_en:1;
unsigned int lp_vbp_en:1;
unsigned int lp_vsa_en:1;
dsih_video_mode_t mipi_trans_type; /* burst or no burst*/
};
这个结构体表示VIDEO 模式LCD 的配置信息:
Hsync:行同步信号。
Hbp:行后porch。
Hfp:行前porch。
Vsync:列同步信号。
Vbp:列后porch。
Vfp:列前porch。
Hs_pol:行同步的有效极性。
Vs_pol:列同步的有效极性。
Dataen_pol:数据使能信号有效极性。
Lp_cmd_en:在传输数据过程中,用LP 模式发送数据使能位。
Frame_bta_ack:MIPI 一帧数据传输结束响应使能位。
Lp_hfp_en:hfp 在HS 传输空闲时进行LP 状态使能位。
Lp_hbp_en:hbp 在HS 传输空闲时进行LP 状态使能位。
Lp_vact_en:vact 在HS 传输空闲时进行LP 状态使能位。
Lp_vfp_en:vfp 在HS 传输空闲时进行LP 状态使能位。
Lp_vbp_en:vbp 在HS 传输空闲时进行LP 状态使能位。
Lp_vsa_en:vsa 在HS 传输空闲时进行LP 状态使能位。
Mipi_trans_type:MIPI 传输方式选择。
struct command_mode_info
struct command_mode_info {
unsigned int tear_fx_en:1;
unsigned int ack_rqst_en:1;
unsigned int gen_sw_0p_tx:1; // default should be 1
unsigned int gen_sw_1p_tx:1; // default should be 1
unsigned int gen_sw_2p_tx:1; // default should be 1
unsigned int gen_sr_0p_tx:1; // default should be 1
unsigned int gen_sr_1p_tx:1; // default should be 1
unsigned int gen_sr_2p_tx:1; // default should be 1
unsigned int gen_lw_tx:1; // default should be 1
unsigned int dcs_sw_0p_tx:1; // default should be 1
unsigned int dcs_sw_1p_tx:1; // default should be 1
unsigned int dcs_sr_0p_tx:1; // default should be 1
unsigned int dcs_lw_tx:1; // default should be 1
unsigned int max_rd_pkt_size:1; // default should be 1
struct rw_timeout timeout;
};
Tear_fx_en:TE 响应使能位。
Ack_rqst_en:每个数据包传输结束后响应。
Gen_sw_0p_tx:GEN 短包命令以LP 模式进行写使能。
Gen_sw_1p_tx:GEN 短包命令以LP 模式进行写使能。
Gen_sw_2p_tx:GEN 短包命令以LP 模式进行写使能。
Gen_sr_0p_tx:GEN 短包命令以LP 模式进行读使能。
Gen_sr_1p_tx:GEN 短包命令以LP 模式进行读使能。
Gen_sr_2p_tx:GEN 短包命令以LP 模式进行读使能。
Gen_lw_tx:GEN 长包命令以LP 模式进行写使能。
Dcs_sw_0p_tx:DCS 短包命令以LP 模式进行写使能。
Dcs_sw_1p_tx:DCS 短包命令以LP 模式进行写使能。
Dcs_sr_0p_tx:DCS 短包命令以LP 模式进行读使能。
Dcs_lw_tx:DCS 长包命令以LP 模式进行读使能。
Max_rd_pkt_size:读包长度命令以LP 模式进行发送使能。
struct rw_timeout
struct rw_timeout {
unsigned int hs_rd_to_cnt;
unsigned int lp_rd_to_cnt;
unsigned int hs_wr_to_cnt;
unsigned int lp_wr_to_cnt;
unsigned int bta_to_cnt;
};
这个结构表示控制器发送相关请求后的等待超时时间。仅用于command 模式;
hs_rd_to_cnt:在发送完高速读操作指令后的等待时间,以lanebyteclk 为单位。
当DPHY 进入 stop state (LP11)时开始计时。
lp_rd_to_cnt:在发送完低功耗读操作指令后的等待时间,以lanebyteclk 为单位。
当DPHY 进入stop state(LP11)时开始计时。
hs_wr_to_cnt:在发送完高速写操作后的等待时间,以lanebyteclk 为单位。当
DPHY 进入stop state 时开始计时。
lp_wr_to_cnt:在发送完低功耗写操作后的等待时间,以lanebyteclk 为单位。当
DPHY 进入stopstate 时开始计时。
bta_to_cnt:在完成一次BTA 操作后的等待时间,以lanebyteclk 为单位。当DPHY
进入stop state 时开始计时。
这几个参数的值一般从屏厂家获取,当屏显示异常时,可能需要进行一定的调整。
struct phy_time_info
struct phy_time_info {
unsigned char lpx;
//unsigned char clk_lpx;
unsigned char clk_tprepare;
unsigned char clk_hs_zero;
unsigned char clk_hs_trail;
unsigned char clk_hs_exit;
unsigned char clk_hs_post;
//unsigned char data_lpx;
unsigned char data_tprepare;
unsigned char data_hs_zero;
unsigned char data_hs_trail;
unsigned char data_hs_exit;
unsigned char data_hs_post;
}
这个结构体是用来配置和调整PHY 的时序参数的,这部分是比较深层次的配置,一般
来说,采用默认值在大多数情况下都能正常工作;这部分参数不需要用户设置,驱动中均
采用默认值;
lpx:这是DSI_DATA 或者DSI_CLK 在进高速模式时LP-01 的时间长度。
clk_tprepare/ data_tprepare:表示在进高速模式时LP-00 的时间长度,以lanebyte 为单
位。
clk_hs_zero/ data_hs_zero:表示进高速模式LP-00 之后HS-0 的时间长度,以lanebyte
为单位。
clk_hs_trail,clk_hs_exit,clk_hs_post,data_hs_trail,data_hs_exit,data_hs_post:这几
个成员的含义也是代表进出高速模式的一些时间配置,这几个值在目前的驱动中不支持配
置。
struct te_info
struct te_info {
unsigned int te_source;
unsigned int te_trigger_mode;
unsigned int te_en;
unsigned int te_sync_en; // In command mode should set 1, video should set 0
};
Te_source:te 信号源。为1 表示外部信号,也就是通常意义上的通过LCD 模组的
TE 引脚输入,使用芯片外部管脚输入的TE 信号。为0 表示采用内部信号,即使用DSI
控制器输出的TE 信号。
Te_trigger_mode:te 外部信号源触发模式。0:当有上升沿时触发TE 同步,1:当有
大于 1000us 宽度高电平时触发TE 同步。通常这个位置0,上升沿触发。
Te_en:te 功能使能。表示使用TE 接收功能,对于COMMAND 模式,一般需要使
能TE 功能,用来同步图像数据传输。
Te_sync_en:start 信号与te 信号同步使能。在COMMAND 模式下时选择是否使能
TEAR_EFFECT 同步。
struct external_info
struct external_info {
unsigned char crc_rx_en:1;
unsigned char ecc_rx_en:1;
unsigned char eotp_rx_en:1;
unsigned char eotp_tx_en:1;
unsigned int dev_read_time; //HSBYTECLK is danwe
};
Crc_rx_en:读CRC 校验使能。
Ecc_rx_en:读ECC 校验使能。
Eotp_rx_en:读EOTP 使能。
Eotp_tx_en:写EOTP 使能。
Dev_read_time:屏返回数据所需时间。
(2)对于VIDEO 模式,配置举例如下,红色部分是需要修改之处:
struct comipfb_dev lcd_zetrax_8009a_dev = {
.name = "lcd_zetrax_otm8009a",
.interface_info = COMIPFB_MIPI_IF,
.lcd_id = 0,
.refresh_en = 1,
.bpp = 32,
.xres = 480,
.yres = 854,
.flags = 0,
.pclk = 31000000,//28000000
.timing = {
.mipi = {
.hs_freq = 52500, //Kbyte
.lp_freq = 15000, //KHZ
.no_lanes = 2,
.display_mode = MIPI_VIDEO_MODE,
.auto_stop_clklane_en = 0,
.im_pin_val = 1,
.color_mode = {
.color_bits = COLOR_CODE_24BIT,
.is_18bit_loosely = 0,
},
.videomode_info = {
.hsync = 4,
.hbp = 36,
.hfp = 34,
.vsync = 2,
.vbp = 20,
.vfp = 21,
.lp_cmd_en = 1,
.frame_bta_ack = 0,
.lp_hfp_en = 1,
.lp_hbp_en = 1,
.lp_vact_en = 1,
.lp_vfp_en = 1,
.lp_vbp_en = 1,
.lp_vsa_en = 1,
.mipi_trans_type
VIDEO_BURST_WITH_SYNC_PULSES,
},
.phytime_info = {
.clk_tprepare = 3, //HSBYTECLK
},
.teinfo = {
.te_source = 1, //external signal
.te_trigger_mode = 0,
.te_en = 0,
.te_sync_en = 0,
},
.ext_info = {
.eotp_tx_en = 0,
},
},
},
.cmds_init = {ARRAY_AND_SIZE(lcd_cmds_init)},
.cmds_suspend = {ARRAY_AND_SIZE(lcd_cmds_suspend)},
.cmds_resume = {ARRAY_AND_SIZE(lcd_cmds_resume)},
.reset = lcd_zetrax_8009a_reset,
.suspend = lcd_zetrax_8009a_suspend,
.resume = lcd_zetrax_8009a_resume,
.backlight_info = {ARRAY_AND_SIZE(backlight_cmds),
.brightness_bit = 8,
},
};
(3)对于CMD 模式,配置举例如下,红色部分是需要修改之处:
struct comipfb_dev lcd_zetrax_8009a_dev = {
.name = "lcd_zetrax_otm8009a",
.interface_info = COMIPFB_MIPI_IF,
.lcd_id = 0,
.refresh_en = 0,
.bpp = 32,
.xres = 480,
.yres = 854,
.flags = 0,
.pclk = 31000000,//28000000
.timing = {
.mipi = {
.hs_freq = 52500, //Kbyte
.lp_freq = 15000, //KHZ
.no_lanes = 2,
.display_mode = MIPI_COMMAND_MODE,
.auto_stop_clklane_en = 0,
.im_pin_val = 1,
.color_mode = {
.color_bits = COLOR_CODE_24BIT,
.is_18bit_loosely = 0,
},
.commandmode_info = {
.tear_fx_en = 1,
.ack_rqst_en = 0,
.gen_sw_0p_tx = 1,
.gen_sw_1p_tx = 1,
.gen_sw_2p_tx = 1,
.gen_sr_0p_tx = 1,
.gen_sr_1p_tx = 1,
.gen_sr_2p_tx = 1,
.gen_lw_tx = 1,
.dcs_sw_0p_tx = 1,
.dcs_sw_1p_tx = 1,
.dcs_sr_0p_tx = 1,
.dcs_lw_tx = 1,
.max_rd_pkt_size = 1,
.timeout = {
.hs_rd_to_cnt = 0,
.lp_rd_to_cnt = 0,
.hs_wr_to_cnt = 20,
.lp_wr_to_cnt = 20,
.bta_to_cnt = 100,
},
},
.phytime_info = {
.clk_tprepare = 3, //HSBYTECLK
},
.teinfo = {
.te_source = 1, //external signal
.te_trigger_mode = 0,
.te_en = 1,
.te_sync_en = 1,
},
.ext_info = {
.eotp_tx_en = 0,
},
},
},
.cmds_init = {ARRAY_AND_SIZE(lcd_cmds_init)},
.cmds_suspend = {ARRAY_AND_SIZE(lcd_cmds_suspend)},
.cmds_resume = {ARRAY_AND_SIZE(lcd_cmds_resume)},
.reset = lcd_zetrax_8009a_reset,
.suspend = lcd_zetrax_8009a_suspend,
.resume = lcd_zetrax_8009a_resume,
.backlight_info = {ARRAY_AND_SIZE(backlight_cmds),
.brightness_bit = 8,
},
};
(4)配置文件添加
在/arch/arm/plat-lc/drivers/video 的Kconfig 中添加如下(红色为要修改部分):
config LCD_TM_NT35516
boolean "TM NT35516(NOVATEK Driver IC) lcd panel"
---help---
TM NT35516(NOVATEK Driver IC) It's resolution is 540 x 960.
This panel is connected with MIPI interface.
在drivers/video/comip_lc1860 的Makefile 中添加如下(红色为要修改部分):
obj-$(CONFIG_LCD_ZET_SSD2075) += lcd_zetrax_ssd2075.o