学习交流加
- 个人qq:
1126137994- 个人微信:
liu1126137994- 学习交流资源分享qq群:
962535112
今天记录一下项目中的关于LVDS显示屏的驱动程序的分析与移植。因为驱动源码厂家已经提供好,我们需要做的就是读懂驱动程序的代码,以及平台层的匹配过程,以及如何在uboot中获取lvds参数,来匹配你的具体显示屏的参数。
首先我们来大致分析一下驱动程序的重要的结构部分:
1.mxc_ipuv3_fb.c 是imx6具体显示模块平台核心的驱动,最终用于把fb_info结构体注册到
framebuffer驱动核心层中。
2.mxc_dispdrv.c 通用注册handle接口,用于统一管理imx6显示模块的各种接口,
比如lvds,lcd,hdmi等显示接口。
3.ldb.c是LVDS 驱动的具体实现过程。
分析:
mxc_ipuv3_fb.c中
在mxc_ipuv3_fb.c文件中初始化mxcfb_init函数注册mxcfb_driver结构体,
当mxcfb_driver结构体成员驱动name与平台设备层中name匹配相同时调用mxcfb_probe初始化函数。
imx6具体显示模块平台核心的驱动的工作主要是在mxcfb_probe里完成。
以下是将重要的函数抽出来分析,并不是具体的代码程序。具体的代码程序见最后的分析。
mxcfb_probe
mxcfb_init_fbinfo
framebuffer_alloc
mxcfb_option_setup
fb_get_options(根据uboot传进来的参数,比较是否匹配,获取分辨率,bpp等参数)
mxcfb_dispdrv_init
mxc_dispdrv_gethandle
if (!strcmp(entry->drv->name, name) && (entry->drv->init)) //如果uboot传进来的参数名字
与ldb_driver里注册的名字匹配时,就会进入就会执行ldb.c文件里的ldb_disp_init函数
entry->drv->init //mxc_dispdrv.c 调用对应driver的init函数,这里就是ldb driver对应的init了。
mxcfb_register
register_framebuffer
entry->drv->init是如何调用ldb_disp_init?当ldb.c中ldb_grv结构体中的name与uboot传进来的名字
相匹配,就会调用.init,
static struct mxc_dispdrv_driver ldb_drv = {
.name = DISPDRV_LDB,
.init = ldb_disp_init,
.deinit = ldb_disp_deinit,
.setup = ldb_disp_setup,
};
ldb.c中ldb_probe()
第三步调用mxcfb_dispdrv_init函数,它会调用在mxc_dispdrv.c文件的mxc_dispdrv_gethandle函数;
根据uboot传到内核的显示设备name(ldb),在dispdrv_list链表中匹配获取对应的driver handle;
这里是获取的是ldb的handle,它的注册是ldb_probe()里的mxc_dispdrv_register函数的,它将自己
添加到dispdrv_list。通过entry->drv->init函数,当从uboot获取的显示设备名字和ldb driver里
注册的名字match匹配时,就会执行ldb.c文件里的ldb_disp_init函数(具体见另一个文档,告诉你
如何实现参数匹配),然后通过结构体fb_videomode[]来设置屏幕的分辨率、刷新频率、上下左右
页边距、行扫描脉宽、场扫描脉宽等参数。ldb_disp_init函数是LVDS驱动具体实现函数。
ldb_disp_init
ret = fb_find_mode(具体硬件参数的匹配过程,分析见另一篇文章链接为:)
return ret
上面大致框架分析好后,一定要看一下具体硬件的参数匹配过程,见上面链接(链接:iMX6开发板移植Linux系统之LVDS显示屏驱动程序分析之LVDS参数的匹配过程分析),然后就是如何设置我的参数,来匹配我的开发板了:
首先在这个结构体中,需要知道具体的参数:
/* include/linux/fb.h */
struct fb_videomode {
2. const char *name; “LDB-WSVGA” /* 名字 */
3. u32 refresh; 60 /* 刷新频率 */
4. u32 xres; 1024 //行像素
5. u32 yres; 768 //列像素
6. u32 pixclock; 19528(14065) //时钟频率,单位ps,14430
7. u32 left_margin; 140 // HBPD(horizontal back porch):80
8. u32 right_margin; 160 // HFPD(horizontal front porth):48
9. u32 upper_margin; 20 // VBPD(vertical back porch),15
10. u32 lower_margin; 12 // VFBD(vertical front porch),2
11. u32 hsync_len; 20 // HSPW(horizontal sync pulse width):32
12. u32 vsync_len; 3 // VSPW(vertical sync pulse width):47
13. u32 sync; 0
14. u32 vmode;
15. u32 flag;
16.};
我们的参数为:
整屏刷新频率 60M
屏幕分辨率 1024*768
时钟频率 14065
left_margin 40(单位像素)
right_margin 40(单位像素)
upper_margin 10(单位像素)
lower_margin 3(单位像素)
行扫描脉宽 hsync_len 80(单位像素时间)
场扫描脉宽vsync_len 10(单位像素时间)
在i.mx6中,关于lvds液晶屏的这个结构体参数(系统lvds接口支持的lcd时序参数都在此了)所属文件为:driver/video/mxc/ldb.c
static struct fb_videomode ldb_modedb[] = {
{
"LDB-WXGA", 60, 1280, 800, 14065,
40, 40,
10, 3,
80, 10,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{
"LDB-XGA", 60, 1024, 768, 15385,
220, 40,
21, 7,
60, 10,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{"LDB-WSVGA", 60, 1024, 600, 19528,
140, 160,
20, 12,
20, 3,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{"LDB-WSVGA480", 60, 1024, 480, 23000,
140, 160,
20, 12,
20, 3,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{
"LDB-1080P60", 60, 1920, 1080, 7692,
100, 40,
30, 3,
10, 2,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
{
"LDB-QXGA", 30, 2048, 1536, 9746,
5, 150,
9, 3,
5, 1,
0,
FB_VMODE_NONINTERLACED,
FB_MODE_IS_DETAILED,},
};
我们选用"LDB-WSVGA"这个结构体里的内容作为我们的参数,将参数修改好适合我们的的参数。
经过后来做实验,发现启动后显示屏显示的有问题,显示的不完全,经过后来的搜索,我在uboot启动后,输入参数,来覆盖上面的结构体参数,屏幕显示就正常了。具体原因没有分析,以后有时间再做具体分析。
uboot启动后输入的具体参数为:
setenv bootargs_mmc 'setenv bootargs ${bootargs} ip=off root=/dev/mmcblk0p1 rootwait rw video=mxcfb0:dev=ldb,LDB-WSVGA,if=RGB24,bpp=32 video=mxcfb1:off video=mxcfb2:off ldb=sin0 fbmem=28M fb0base=0x27b00000 '
想一起探讨以及获得各种学习资源加我(有我博客中写的代码的原稿):
qq:1126137994
微信:liu1126137994
可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题。