一個嵌入式系統如果有了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了,反而可以爲客戶節省成本。