[Freescale] LCD Driver Porting
Platform:Freescale; Android 4.2.2; Kernel-3.0.35
LCD:奇美V500HK1 - 50 inch -
接口:LVDS
板端LVDS接口:
可以看到是30pin的接口,可以支持双通道(2-channel)。
奇美Datasheet关键参数:
关键的几个参数:Pixel clock = 74.25MHz*2 = 148.5MHz ; xres = 960*2 = 1920 ; yres = 1080 ; H-Blank = 140*2 = 180 ; V-Blank = 45
注:
1. 可能是由于双通道的关系,水平方向的数据都要乘以2。
2. 文档未定义back、front、uper、lower 的margin,vsync_length 和 hsync_length也未定义。
LVDS关于知识
LVDS:Low Voltage Differential Signal,低压差分信号。
差分信号:一种信号传输的技术,区别于传统的一根信号线一根地线的做法,差分传输在这两根线上都传输信号,这两个信号的振幅相同,相位相反。在这两根线上的传输的信号就是差分信号。信号接收端比较这两个电压的差值来判断发送端发送的是逻辑0还是逻辑1。
当LVDS为双通道传输时,通道A和通道B会分别传输奇数位的像素点和偶数位的像素点。
LVDS 的每组通道由四组数据线和一组时钟线组成(24bit以内的像素数据),共10条线。
LVDS 的四组数据线的数据传输格式有一定的规范,通常分为VESA 和 JEIDA 两种标准。此处只讨论VESA标准。
从LCD的Datasheet中可以看到,根据SELLVDS这根Pin的接法,可以选择使用哪种标准,这边我们使用VESA标准。
并且,可以看到四组数据线中,一个像素要传7位数据,包含了RGB数据和一些控制数据。
LCD相关知识
根据kernel文档framebuffer.txt,可以得知一些信息:
电子枪从屏幕的左上角开始,将一个个的像素点依次打倒屏幕上,其顺序是从左往右,从上往下。 当扫描到一行的结束回到下一行的开始时,这叫做horizontal retrace;当扫描到右下角(最后一行的最后一个像素),回到左上角扫描下一个frame时,这叫做vertical retrace。
当电子枪扫描到一行的最后一个像素时,我们需要发送一个水平同步脉冲信号(vsync pulse),来告诉电子枪进行horizontal retrace,同样,当电子枪要进行vertical retrace之前,我们要发送一个垂直同步脉冲信号(hsync pulse),如下(timing summarizes):
主要涉及这些参数:xres、yres、left_margin、right_margin、upper_margin、lower_margin、hsync_len、vsync_len、pixel clock
xres、yres:水平和垂直扫描时间
left_margin:行扫描开始前的等待时间,之后打开Data Enable pin
right_margin:行有效像素扫描完成后的等待时间,之前关闭Data Enable pin
hsync_len:水平同步脉冲宽度,通知扫描枪换行
upper_margin:一个frame扫描开始前的等待时间,之后打开Data Enable pin
lower_margin:一个frame扫描完成后的等待时间,之前关闭Data Enable pin
hsync_len:水平同步脉冲宽度,通知扫描枪回左上角
pixel clock:打一个像素消耗的时间
horizontal retrace time (h-blank time)= left_margin + right_margin + hsync_length
vertical retrace time (v-blank time) = upper_margin + lower_margin + vsync_len
有些文档用以下所写来描述上述参数:
VPW: Vsync Pulse Width
VBP: Vsync Back Porch
VFP: Vsync Front Porch
HBP: Hsync Back Porch
HFP: Hsync Front Porch
有时候,LCD 的 Datasheet对参数描述不详细时,可以查阅VESA标准,如:
关于芯片内RGB数据的传输和控制
IPU:Iamge Process Unit
LDB:LVDS Display Bridge
IPU通过DMA对内存中的数据进行读取,层层处理后,分为ipu_di0 和 ipu_di1 两个通道交给 LDB Mux&Control,数据经过处理符合LVDS规范后,依据设定分发给LDB Channel 0 和 1,从而传给LCD。
此处,我的LCD是双通道,所以LDB Channel 0 和 1分别负责分发奇数位和偶数位的像素。
关于Backlight
背光有两根pin在控制,一个是enable,控制背光打开和关闭;一个是pwm,控制背光亮度。
PWM:Pulse Width Modulation,脉冲宽度调制。
当PWM高电平时发光,低电平不发光,通过调整PWM的占空比来调节亮度。
代码相关
注册 Backlight device
board-mx6q_dsa2lv.c
mx6_sabresd_pwm_backlight_data.max_brightness = 248; mx6_sabresd_pwm_backlight_data.dft_brightness = 200; mx6_sabresd_pwm_backlight_data.pwm_period_ns = 6250000; mx6_sabresd_pwm_backlight_data.pwm_id = 1; imx6q_add_mxc_pwm_backlight(0, &mx6_sabresd_pwm_backlight_data);
devices-imx6q.h
#define imx6q_add_mxc_pwm_backlight(id, pdata) \ platform_device_register_resndata(NULL, "pwm-backlight",\ id, NULL, 0, pdata, sizeof(*pdata));
注意注册设备传入的 id=0,对应:/sys/bus/platform/devices/pwm-backlight.0
Backlight 驱动
代码为pwm_bl.c 和 backlight.c
pwm_bl.c 主要是直接和pwm打交道,而 backlight.c 提供了文件节点给上层操作。
pwm_bl.c 调用了 backlight.c 的 backlight_device_register方法,又注册了一个device,这个device 的parent就是之前board-mx6q_dsa2lv.c里面注册的device。这么做的原因可能是出于结构设计的考虑:所有厂商的backlight device都要注册到backlight.c这个基本框架中,然后提供统一的文件节点给上层使用。
所以,又有:/sys/devices/platform/pwm-backlight.0/backlight/pwm-backlight.0
TODO:PWM 的研究
添加 LDB 和 IPU 相关设备
static struct ipuv3_fb_platform_data sabresd_fb_data[] = { { /*fb0*/ .disp_dev = "ldb", .interface_pix_fmt = IPU_PIX_FMT_GBR24, .mode_str = "LDB-1080P60", .default_bpp = 32, .int_clk = false, .late_init = false, }, ... ... }; imx6q_add_ipuv3(0, &ipu_data[0]); if (cpu_is_mx6q()) { imx6q_add_ipuv3(1, &ipu_data[1]); for (i = 0; i < 4 && i < ARRAY_SIZE(sabresd_fb_data); i++) imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]); } else for (i = 0; i < 2 && i < ARRAY_SIZE(sabresd_fb_data); i++) imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]); imx6q_add_vdoa(); imx6q_add_lcdif(&lcdif_data); imx6q_add_ldb(&ldb_data); imx6q_add_v4l2_output(0);
IPU_PIX_FMT_GBR24:关系到 IPU 给 LDB 传输数据的 RGB 格式
在ldb.c中配置fb_videomode结构体,配置lcd参数:
{ "LDB-1080P60B", 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN,},