本小节来分析Linux内核中的LCD框架,只分析基于RGB接口的LCD框架,如果是涉及GPU的那就比较复杂了,
有过应用层对LCD操作的应该知道,上层应用是通过一些Ioctl函数操作/dev/fbxxx,这些函数对内核同统一出来的一套LCD的操作函数,还有,对于不同的单板,其LCD控制器的操作肯定是不同的
所以,从这两方面来看,内核LCD框架肯定有两部分工作要完成
驱动大多都是这样,应用不关心下面具体的单板,具体的单板只需要实现自己的操作函数,然后注册给内核,通过应用来调用,都是这个套路
在开始之前先来提一个概念,一个RGB接口的LCD对应到/dev/下的一个fb,这个fb就包含了这个屏幕所有的信息,一个fb的数据是由一个fb_info结构体来描述,所以,一个LCD就是一个fb_info结构体,
struct fb_info {
atomic_t count;
int node;
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
......
struct fb_ops *fbops;
}
fb_info结构体中有一些固定的参数,一些可变的参数,可变参数就包括LCD的那些时间参数,最重要的就是fb_ops操作函数,就是为应用提供的操作函数.
现在开始分析驱动,不从所谓的核心层开始分析,直接从具体的设备分析,平台为飞思卡尔的RGB LCD驱动, drivers\video\fbdev\mxsfb.c
注册平台设备驱动,如果要添加LCD的话需要注意匹配列表,
分析probe函数
static int mxsfb_probe(struct platform_device *pdev)
{
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
struct pinctrl *pinctrl;
gpio = of_get_named_gpio(pdev->dev.of_node, "enable-gpio", 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);
fb_info = framebuffer_alloc(0, &pdev->dev);
host->fb_info = fb_info;
fb_info->par = host;
ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0, dev_name(&pdev->dev), host);
host->base = devm_ioremap_resource(&pdev->dev, res);
platform_set_drvdata(pdev, host);
INIT_LIST_HEAD(&fb_info->modelist);
ret = mxsfb_init_fbinfo(host);
ret = mxsfb_dispdrv_init(pdev, fb_info);
ret = register_framebuffer(fb_info);
mxsfb_overlay_init(host);
return 0;
}
probe函数很长,我尽量留下了一些必要的信息,
这个函数很重要,
一开始是设置fb_info的一些变量,fix是固定的意思,设置一个固定参数的值,关键是设置操作函数fb_info->fbops = &mxsfb_ops;
然后调用mxsfb_init_fbinfo_dt函数进一步设置,这个函数是获取设备树中的信息来设置屏幕参数的可变信息,也就是时序
函数很长,不列出函数体,作总结即可
到这里就执行完了,所以mxsfb_init_fbinfo_dt函数是循环读取设备树的时序参数,如果有多个的话,就把他们都添加到fb_info的modelist链表中
接着分析mxsfb_init_fbinfo函数,设置完modelist之后会把第一个作为默认的显示参数,赋值为var,
然后调用mxsfb_check_var函数检查参数,这个函数中做分辨率和总线宽度的检查,
紧接着计算行分辨率的字节数和缓存大小,然后调用mxsfb_map_videomem函数分配LCD的显存空间
最后一个函数mxsfb_restore_mode,点进去可以发现,这里就是根据前面读出来的屏幕参数去设置LCD控制寄存器了,
最后,缓存清零
这个调用分支就看完了,是去读取参数设置具体单板的LCD控制寄存器的,这一动作执行完毕之后,那接下来,就无疑是去注册前面辛苦设置的fb_info结构体了
回到前面接着分析probe函数
最后调用register_framebuffer函数注册fb_info结构体
总结一下
本小节内容也相对较多了,注册fb_info结构体的分析放到下一小节分析.