一个嵌入式系统如果有了LCD显示,那肯定会添彩不少,正好俺们的EVB上是标配LCD的,所以可以给它添个Frame Buffer驱动。以前改过S3C2410的Frame Buffer驱动,代码过于冗长,而且S3C2410是是大户人家的东东,自己带LCD控制器,可以直接支持“玻璃“也可以支持模组(通过总线)的,关于玻璃和模组请看文章后面的备注。俺们设计芯片的原则不是Low Cost, 而是Ultra Low Cost,还美名其曰ULC。不过好歹也是个外企,虽然在51Job上叫外企(其它),我们还是有一个专门的硬件模块LCD Bridge来接LCD模组的,包括了经典51单片机书上讲的通过74xx芯片生成RS, WR,RD,CS信号的电路,主要在于没有哪个做手机的用户会在一堆BGA中间加两个突兀的SOC封装74xx,明显不专业嘛,所以我们只能依了客户。此外这个LCD Bridge里面还有一点FIFO和颜色转换的东东。FIFO还有点用,那个颜色转换到目前为止还没用过。
写Linux程序如果说还要Start From Scratch,明显Out了,没看大家张嘴闭嘴都是”移植......移植“还是”移植“吗?最经典的模板当然非skeletonfb.c莫数了,不过这个文件注释居多,有效内容太少。我还是选一个实际一点的,对driver/video按照大小排序,最后在矮子里面找高个,发现q40fb.c资质不错,就是它了。
第一步当然是要把q40fb.c该个名字cbp-fb.c,放到driver/video下面,然后添加Kconfig和Makefile选项使它能被编译了,照葫芦画瓢:
1. driver/video/Kconfig:
config FB_CBP
tristate "VIA(VTC) CBP LCD framebuffer support"
depends on FB && ARCH_CBP
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Frame Buffer Driver for VIA Telecom(VTC) CBP chipset.
其中的FB_CFB_XX是为了将CFB相关的函数编译进去,相当于软件对画框等操作进行加速
2. driver/video/Makefile
obj-$(CONFIG_FB_CBP) +=cbp-fb.o
第二步当然是把这个文件改改,一方面把那些名字都替换成俺喜欢的名字,其次只好还要能够编译过,无非就是修修补补,这个比较容易。
3.修改跟EVB相关的参数
主要是修改分辨率,修改RGB565的bit定义等等,就是修改传说中的fix和var参数
static struct fb_fix_screeninfo cbp_fb_fix __initdata = {
.id = "cbp",
.smem_len = 240*320*2,
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.line_length = 240*2,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo cbp_fb_var __initdata = {
.xres = 240,
.yres = 320,
.xres_virtual = 240,
.yres_virtual = 320,
.bits_per_pixel = 16,
.red = {11, 5, 0},
.green = {5, 6, 0},
.blue = {0, 5, 0},
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.vmode = FB_VMODE_NONINTERLACED,
};
4.为驱动分配内存
现在这个世道,没有Money甚吗都干不了,就像Frame Buffer驱动没有内存一样。当系统调用cbp_fb_init中的platform_xxx函数的时候已经注定后面要调用的第一个函数就是probe函数了。先调用以下函数:
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
紧接着申请显示缓存,没错,就是显存了,俺们这个系统不是独立显存,还得和CPU共享。分配的时候当然要分配一段没有Cache的区域了,不然当使用CPU刷新屏幕的时候很可能会是这里一个小黑条,那里一片花条,这个是俺多年与CPU,GFX,DMA,CACHE打交道的经验了。
cbp_fb_fix.smem_start = dma_alloc_writecombine(&(dev->dev),
map_size,
&map_dma,
GFP_KERNEL);
这个函数的返回值就是申请到的地址,虚拟的。物理的存在那个map_dma里面。
既然已经有了info这个筐,又有了显存地址、fix info、var info这一堆东东,赶紧往里面装吧。
info->var = cbp_fb_var;
info->fix = cbp_fb_fix;
info->fbops = &cbp_fb_ops;
info->flags = FBINFO_DEFAULT; /* not as module for now */
info->pseudo_palette = info->par;
info->par = NULL;
info->screen_base = (char *) cbp_fb_fix.smem_start;
4.注册
现在万事具备,陆毅也给周瑜借来了东风,调用Color Map和Register函数即可:
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
framebuffer_release(info);
return -ENOMEM;
}
//master_outb(3, DISPLAY_CONTROL_REG);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "Unable to register cbp frame buffer\n");
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
return -EINVAL;
}
return 0;
现在我可以打保票说,这个Frame Buffer驱动已经呱呱坠地OK了,其实Frame Buffer驱动一点都不复杂,是那些写书的人把它写复杂了,不过我的启蒙教材ldd2和它的后续好像根本不写Frame Buffer。或许就是觉得它太简单。。。。。。。。?!
不过要让这个驱动产生点实际的效果,比如显示俺们那熟悉的可爱的小企鹅哦,还得明天继续分解。
备注:
我的前任台湾老板,一个卖液晶的朋友(注:两个人,男的)告诉我,那种不带LCD控制器的液晶面板叫玻璃,也就是LCD,就是只有带液晶控制器的MCU才能和它们对接,比如大家猛汉S3C2410,这些玻璃的扫描时序有MCU产生,因此MCU要不停的刷,会占用很多的Memory带宽。 而自己带LCD控制器的叫LCM,也就是LCD Module,俗称模组了,中发电子市场那种黑白的后面有绿色电路板12864模块就是典型,不过现在很多也没有后面背的绿色电路板了,芯片直接坐在玻璃上,俗称COG,就是Chip On Glass了,是不是很土?而且很多模组都是彩色的,比如俺用的,深圳无名氏所产的以ILI932x作为控制器的240x320彩色模组。模组的好处就是像51单片机这种带宽吃紧的MCU,或者说跟S3C2410相比带宽可以忽略的处理器可以接这种液晶,显示点控制信息啥的。而像Samsung这种豪门,反正卖芯片就是卖沙子,帮客户把LCD控制器做里面了,客户只用买玻璃就OK了,反而可以为客户节省成本。
阅读(1458) | 评论(0) | 转发(0) |