1.驱动:
基于framebuffer,整体代码参考内核s3c-fb.c
代码初始化步骤:
1、申请fb_info
2、初始化fb_info
3、管脚设置
4、时钟设置
5、控制芯片设置
6、注册fb
代码:
1/*head file*/
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include "mylcd.h"
12
13/*module info*/
14 MODULE_LICENSE("Dual BSD/GPL");
15
16staticstructfb_info *my_fbInfo = NULL;
17staticintmyLcdBpp = 32; /*位深*/
18staticshortmyPaletteSize = 256; /*调色板大小*/
19static unsigned intmyXvSize = 1024; /*缓冲列大小*/
20static unsigned intmyYvSize = 600; /*缓冲行大小*/
21static unsigned intpseudo_palette[16];
22
23/*io管脚寄存器*/
24static unsigned int * __iomem gpf0con;
25static unsigned int * __iomem gpf1con;
26static unsigned int * __iomem gpf2con;
27static unsigned int * __iomem gpf3con;
28static unsigned int * __iomem gpd0con;
29/*pwm寄存器*/
30static unsigned int * __iomem tcfg0;
31static unsigned int * __iomem tcfg1;
32static unsigned int * __iomemtcon;
33static unsigned int * __iomem tcntb1;
34static unsigned int * __iomem tcmpb1;
35/*时钟相关寄存器*/
36static unsigned int * __iomemclk_div_lcd;
37static unsigned int * __iomem clk_src_lcd0;
38static unsigned int * __iomemlcdblk_cfg;
39static unsigned int * __iomem lcdblk_cfg2;
40/*lcd寄存器*/
41static unsigned int * __iomem vidcon0;
42static unsigned int * __iomem vidcon1;
43static unsigned int * __iomem vidcon2;
44static unsigned int * __iomem vidtcon0;
45static unsigned int * __iomem vidtcon1;
46static unsigned int * __iomem vidtcon2;
47static unsigned int * __iomem wincon0;
48static unsigned int * __iomem vidoso0a;
49static unsigned int * __iomem vidoso0b;
50static unsigned int * __iomem vidoso0c;
51static unsigned int * __iomemshaadowcon;
52static unsigned int * __iomem winchmap2;
53static unsigned int * __iomem vidw00add0b0;
54static unsigned int * __iomem vidw00add1b0;
55static unsigned int * __iomem win0map;
56static unsigned int * __iomem vidw00add2;
57
58//static T_LCD_REG * __iomemlcdBase;
59
60static inline unsigned intchan_to_field(unsigned intchan,
61structfb_bitfield *bf)
62 {
63chan&= 0xffff;
64chan>>= 16 - bf->length;
65returnchan<< bf->offset;
66 }
67
68staticintmy_fb_setcolreg(unsigned regno,
69 unsigned red, unsigned green, unsigned blue,
70 unsigned transp, structfb_info *info)
71 {
72 unsigned intval = 0;
73switch (info->fix.visual) {
74case FB_VISUAL_TRUECOLOR:
75/* true-colour, use pseudo-palette */
76if (regno<16) {
77 u32 *pal = info->pseudo_palette;
78
79val =chan_to_field(red, &info->var.red);
80val |= chan_to_field(green, &info->var.green);
81val |= chan_to_field(blue, &info->var.blue);
82
83pal[regno] = val;
84 }
85break;
86default:
87return1; /* unknown type */
88 }
89
90return0;
91 }
92
93staticstructfb_opsmy_fb_ops = {
94 .owner = THIS_MODULE,
95 .fb_setcolreg = my_fb_setcolreg,
96 .fb_fillrect = cfb_fillrect,
97 .fb_copyarea = cfb_copyarea,
98 .fb_imageblit = cfb_imageblit,
99 };
100
101staticintfb_fill_var(structfb_info *myfb)
102 {
103myfb->var.activate = FB_ACTIVATE_NOW;
104myfb->var.vmode = FB_VMODE_NONINTERLACED;
105myfb->var.bits_per_pixel = myLcdBpp;
106myfb->var.xres_virtual = myXvSize;
107myfb->var.yres_virtual = myYvSize;
108myfb->var.xres = myXvSize;
109myfb->var.yres = myYvSize;
110myfb->var.xoffset = 0;
111myfb->var.yoffset = 0;
112/* always ensure these are zero, for drop through cases below */
113myfb->var.transp.offset = 0;
114myfb->var.transp.length = 0;
115
116switch (myfb->var.bits_per_pixel) {
117case1:
118case2:
119case4:
120case8:
121/* non palletised, A:1,R:2,G:3,B:2 mode */
122myfb->var.red.offset = 5;
123myfb->var.green.offset = 2;
124myfb->var.blue.offset = 0;
125myfb->var.red.length = 2;
126myfb->var.green.length = 3;
127myfb->var.blue.length = 2;
128myfb->var.transp.offset = 7;
129myfb->var.transp.length = 1;
130break;
131
132case19:
133/* 666 with one bit alpha/transparency */
134myfb->var.transp.offset = 18;
135myfb->var.transp.length = 1;
136/* drop through */
137case18:
138myfb->var.bits_per_pixel = 32;
139
140/* 666 format */
141myfb->var.red.offset = 12;
142myfb->var.green.offset = 6;
143myfb->var.blue.offset = 0;
144myfb->var.red.length = 6;
145myfb->var.green.length = 6;
146myfb->var.blue.length = 6;
147break;
148
149case16:
150/* 16 bpp, 565 format */
151myfb->var.red.offset = 11;
152myfb->var.green.offset = 5;
153myfb->var.blue.offset = 0;
154myfb->var.red.length = 5;
155myfb->var.green.length = 6;
156myfb->var.blue.length = 5;
157break;
158
159case32:
160case28:
161case25:
162myfb->var.transp.length = myfb->var.bits_per_pixel - 24;
163myfb->var.transp.offset = 24;
164/* drop through */
165case24:
166/* our 24bpp is unpacked, so 32bpp */
167myfb->var.bits_per_pixel = 32;
168myfb->var.red.offset = 16;
169myfb->var.red.length = 8;
170myfb->var.green.offset = 8;
171myfb->var.green.length = 8;
172myfb->var.blue.offset = 0;
173myfb->var.blue.length = 8;
174break;
175
176default:
177printk("invalid bpp\n");
178return -EINVAL;
179 }
180return0;
181 }
182
183staticintfb_fill_fix(structfb_info *myfb)
184 {
185 unsigned intreal_size, virt_size, size;
186dma_addr_tmap_dma;
187
188strcpy(myfb->fix.id ,"mylcd");
189
190myfb->fix.type = FB_TYPE_PACKED_PIXELS; //在该方式下,像素值与内存直接对应
191myfb->fix.accel = FB_ACCEL_NONE;
192myfb->fix.line_length = (myfb->var.xres_virtual * myfb->var.bits_per_pixel) / 8; //一行的大小(字节数)
193myfb->fix.xpanstep = myfb->var.xres_virtual>myfb->var.xres ?1 :0;
194myfb->fix.ypanstep = myfb->var.yres_virtual>myfb->var.yres ?1 :0;
195
196switch (myfb->var.bits_per_pixel) {
197case32:
198case24:
199case16:
200case12:
201myfb->fix.visual = FB_VISUAL_TRUECOLOR;
202break;
203case8:
204if (myPaletteSize>= 256)
205myfb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
206else
207myfb->fix.visual = FB_VISUAL_TRUECOLOR;
208break;
209case1:
210myfb->fix.visual = FB_VISUAL_MONO01;
211break;
212default:
213myfb->fix.visual = FB_VISUAL_TRUECOLOR;
214break;
215 }
216
217/*计算整体缓冲大小*/
218real_size = myfb->var.xres * myfb->var.yres;
219virt_size = myfb->var.xres_virtual * myfb->var.yres_virtual;
220 size = (real_size>virt_size) ?real_size :virt_size;
221 size *= (myfb->var.bits_per_pixel>16) ?32 :myLcdBpp;
222 size /= 8;
223myfb->fix.smem_len = size;
224 size = PAGE_ALIGN(size);
225myfb->screen_base = dma_alloc_writecombine(myfb->dev, size,
226&map_dma, GFP_KERNEL);
227if (!myfb->screen_base)
228 {
229return -ENOMEM;
230 }
231memset(myfb->screen_base, 0x0, size);
232myfb->fix.smem_start = map_dma;
233
234return0;
235 }
236
237/*fun*/
238staticvoidmyfb_Init(structfb_info *myfb)
239 {
240/*varinit*/
241fb_fill_var(myfb);
242/*fix init*/
243fb_fill_fix(myfb);
244/*ops init*/
245myfb->fbops = &my_fb_ops;
246/*other init*/
247myfb->flags = FBINFO_FLAG_DEFAULT;
248myfb->pseudo_palette =pseudo_palette;
249 }
250
251staticvoidmygpio_Init(void)
252 {
253 gpf0con = ioremap(LCD_F0,4);
254 gpf1con = ioremap(LCD_F1,4);
255 gpf2con = ioremap(LCD_F2,4);
256 gpf3con = ioremap(LCD_F3,4);
257
258writel(LCD_F0_VAL, gpf0con);
259writel(LCD_F1_VAL, gpf1con);
260writel(LCD_F2_VAL, gpf2con);
261writel(LCD_F3_VAL, gpf3con);
262
263//背光
264if(1) //pwm方式
265 {
266 gpd0con = ioremap(LCP_PWMIO_BASE,4);
267writel((readl(gpd0con) & (~(0xf<<4))) | (0x2<<4) , gpd0con);
268 }
269else//直接点亮方式
270 {
271intval;
272
273 unsigned int * __iomem gpd0con;
274 unsigned int * __iomem gpd0dat;
275
276 gpd0con = ioremap(0x114000A0,0x4);
277 gpd0dat = ioremap(0x114000A4,0x4);
278
279val = readl(gpd0con);
280val&= ~(0xf<<4);
281val |= (0x1<<4);
282writel(val, gpd0con);
283
284val = readl(gpd0dat);
285val |= (1<<1);
286writel(val, gpd0dat);
287 }
288 }
289
290staticvoidmyclk_Init(void)
291 {
292clk_div_lcd =ioremap(CLK_DIV_LCD,0x4);
293 clk_src_lcd0 = ioremap(CLK_SRC_LCD,0x4);
294lcdblk_cfg = ioremap(LCDBLK_CFG, 0x4);
295 lcdblk_cfg2= ioremap(LCDBLK_CFG2, 0x4);
296
297/*时钟源选择MPLL,具体参考
298 *SCLK_FIMD0 = MOUTFIMD0/(FIMD0_RATIO + 1) = 800M/1 = 800M
299*/
300writel(readl(clk_div_lcd)&~0xf,clk_div_lcd);
301writel((readl(clk_src_lcd0)&~0xf)|0x6,clk_src_lcd0);
302
303/*选择FIMD0 具体参考
304 *
305 *Using the display controller data, you can select one of the above data paths by setting LCDBLK_CFG Register
306 *(0x1001_0210). For more information, refer to the "System Others" manual.
307 *
308 *While using RGB interface, the VT_LBLKx bit fields in LCDBLKC_CFG (0x1001_0210) register should be set to
309RGB Interface out (2'b00), even though you use DSI Video Mode.*/
310writel((readl(lcdblk_cfg)&(~(0x3<<10)))|(1<<1),lcdblk_cfg);
311//writel(readl(lcdblk_cfg2)|(1<<0),lcdblk_cfg2);
312 }
313
314staticvoidmypwm_Init(void)
315 {
316 tcfg0 = ioremap(LCP_PWM_TCFG0,4);
317 tcfg1 = ioremap(LCP_PWM_TCFG1,4);
318tcon = ioremap(LCP_PWM_TCON,4);
319 tcntb1 = ioremap(LCP_PWM_TCNTB1,4);
320 tcmpb1 = ioremap(LCP_PWM_TCMPB1,4);
321/*占空比控制背光亮度*/
322writel((readl(tcfg0) &(~0xff))|0xff,tcfg0);
323writel((readl(tcfg1) &(~(0xf<<4)))|0x4<<4,tcfg1);
324writel(300,tcntb1);
325writel(150,tcmpb1);
326writel((readl(tcon)&(~(0xf<<8)))|(0x1<<9),tcon);
327
328//使能
329writel((readl(tcon)&(~(0x1<<9)))|(0x1<<8),tcon);
330 }
331
332staticintlcd_Init(structfb_info *myfb)
333 {
334 unsigned intval;
335//lcd设置,寄存器太多,懒得放头文件了
336vidcon0 =ioremap(0x11c00000,0x4);
337vidcon1 =ioremap(0x11c00004,0x4);
338vidcon2 =ioremap(0x11c00008,0x4);
339 vidtcon0 = ioremap(0x11c00010,0x4);
340 vidtcon1 = ioremap(0x11c00014,0x4);
341 vidtcon2 = ioremap(0x11c00018,0x4);
342
343 win0map = ioremap(0x11C00180, 0x4);
344 wincon0 = ioremap(0x11c00020, 0x4);
345
346 vidoso0a = ioremap(0x11c00040,0x4);
347 vidoso0b = ioremap(0x11c00044,0x4);
348 vidoso0c = ioremap(0x11c00048,0x4);
349shaadowcon = ioremap(0x11c00034,0x4);
350winchmap2 =ioremap(0x11c0003c,0x4);
351 vidw00add0b0 = ioremap(0x11c000a0,0x4);
352 vidw00add1b0 = ioremap(0x11c000d0,0x4);
353 vidw00add2 = ioremap(0x11C00104, 0x4);
354
355/*HV mode fclk :44.9~63 推荐51.2Mhz 参考
356 *vidcon0 [13-6] VCLK = FIMD*SCLK/(CLKVAL+1)
357 *50M = 800M/(CLK_VAL+1) CLK_VAL= 15 这里为了取整,取50M
358*/
359writel(15<<6, vidcon0);
360
361/*
362 * :VSYNC,HSYNC高电平触发信号,VCLK上升沿开始传输数据
363 *:VSD,HSD低电平触发信号,CLKV下降沿开始传输数据
364 *
365 *VIDCON1:
366 * [5]:IVSYNC ===> 1 : Inverted(反转)
367 * [6]:IHSYNC ===> 1 : Inverted(反转)
368 * [7]:IVCLK ===> 1 : Fetches video data at VCLK rising edge (下降沿触发,反转?)
369 * [10:9]:FIXVCLK ====> 01 : VCLK running
370 * */
371writel((1<<9)|(1<<7)|(1<<5)|(1<<6),vidcon1);
372
373//Reserved: This bit should be set to 1.
374writel(1<<14, vidcon2);
375
376/*参考 HV mode
377 * thbp: 160 (DCLK)
378 * thfp: 160 (DCLK)
379 * thpw: 1-140 (DCLK)
380 * tvpw: 1-20 (Th)
381 * tvbp: 23 (Th)
382 * tvfp: 12 (Th)
383*/
384
385#define HSPW 10 //行同步
386#define HBPD 160
387#define HFPD 160
388#define VSPW 1 //帧同步
389#define VBPD 23
390#define VFPD 12
391writel(((VBPD <<16)|(VFPD <<8)|(VSPW <<0)),vidtcon0);
392writel(((HBPD <<16)|(HFPD <<8)|(HSPW <<0)),vidtcon1);
393
394/*设置大小,参考 Display Format Graphic 1024RGB*600 Dot-matrix
395 * HOZVAL = (Horizontal display size) – 1 and LINEVAL = (Vertical display size) – 1.
396*/
397writel(((1023<<0) | (599<<11)), vidtcon2);
398
399/*绑定win,这里直接使用了win0
400 * TODO:0xd=32位,这里强行写的,具体需要参考实际情况写16或32
401*/
402writel((1<<6)|(0xD<<2)|1,wincon0);
403
404/* LCD左上角坐标*/
405writel(0<<11|0, vidoso0a);
406/* LCD右下角坐标 参考
407 * 24 BPP mode should have X position by 1 pixel. (For example, X = 0, 1, 2, 3….)
408 * 16 BPP mode should have X position by 2 pixel. (For example, X = 0, 2, 4, 6….)
409 * 8 BPP mode should have X position by 4 pixel. (For example, X = 0, 4, 8, 12….)
410*/
411if(myLcdBpp == 16)
412 {
413val = (((1023*2) <<11) | ((599*2) <<0));
414 }
415elseif((myLcdBpp == 24) || (myLcdBpp == 32))
416 {
417val = (((1023) <<11) | ((599) <<0));
418 }
419writel(val, vidoso0b);
420
421/*总大小*/
422writel(1024*600, vidoso0c);
423
424/*帧缓冲起始地址*/
425writel(myfb->fix.smem_start, vidw00add0b0);
426/*帧缓冲结束地址*/
427writel(myfb->fix.smem_start+myfb->fix.smem_len, vidw00add1b0);
428/*设置偏移和宽度*/
429writel((0<<13) | ((1024 * myLcdBpp / 8)<<0), vidw00add2);
430
431/*绑定通道和窗口*/
432writel(1, shaadowcon);
433writel((readl(winchmap2)&(~(0x7<<16))&(~0x7))|(1<<16)|(1<<0), winchmap2);
434
435/*Enables the video output and video control signal*/
436writel(readl(vidcon0)|0x3, vidcon0);
437return0;
438 }
439
440staticint fs4412_lcd_init(void)
441 {
442int ret =0 ;
443/************************kernel相关*******************************/
444/**这部分参考s3c-fb.c**/
445/*申请fb_info*/
446my_fbInfo = framebuffer_alloc(0,NULL); //这里没有私有数据,所以是0;dev没有,平台驱动需要添加。
447/*初始化fb_info*/
448myfb_Init(my_fbInfo);
449/************************硬件相关*******************************/
450/*管脚设置*/
451mygpio_Init();
452/*时钟设置*/
453myclk_Init();
454/*控制芯片设置*/
455mypwm_Init();
456lcd_Init(my_fbInfo);
457
458/*注册*/
459 ret = register_framebuffer(my_fbInfo);
460if(0> ret){
461printk(KERN_ERR "failed to register framebuffer \n");
462//dma_free_coherent(fs_info->dev, fs_info->fix.smem_len,fs_info->screen_base, fs_info->fix.smem_start);
463return ret;
464 }
465
466printk("Lcdinit ok\n");
467return0;
468 }
469
470/*没考虑退出,这里暂时没写*/
471staticvoid fs4412_lcd_exit(void)
472 {
473printk("Lcd exit\n");
474 }
475
476/**/
477module_init(fs4412_lcd_init);
478module_exit(fs4412_lcd_exit);
2.应用:
下载一个字符转换工具,转换字符,我用的是字模提取V2.2。
先取一个字符转换码:
1、先在右下角的文字输入区输入需要转码的字,按Ctrl+Enter输入结束
2、在左边列里面选择取模方式,C51 格式,点击后在右下的点阵生成区显示转换的字节数组。
3、把字节数组放到测试程序中,我为了方便,直接在c里面用了一个数组来装载。
应用编码
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11
12#define MY_W 320 //图像宽
13#define MY_H 240 //图像高
14#define MAX_SIZE 1024*600*4 //lcd屏幕大小,具体要看对应的lcd手册。我的是1024*600
15
16/*字符矩阵 16*14*/
17#define C_W 40
18#define C_H 35
19
20staticchar *fbp = 0; //映射内存起始地址
21staticintfbfd = 0; //帧缓冲fd
22
23/*存放转换后的汉字字节*/
24const unsigned charcbuf[1024]=
25 {
26/*-- 文字: 我 --*/
27/*-- 宋体26; 此字体下对应的点阵为:宽x高=35x35 --*/
28/*-- 宽度不是8的倍数,现调整为:宽度x高度=40x35 --*/
290x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x38,0x00,0x00,0x00,
300x0F,0xBE,0x00,0x00,0x00,0x7F,0xFD,0xE0,0x00,0x07,0xF8,0x3C,0x78,0x00,0x3E,0x78,
310x3C,0x7C,0x00,0x00,0x78,0x3C,0x3E,0x00,0x00,0x78,0x3C,0x1C,0x00,0x00,0x78,0x3C,
320x0C,0x00,0x00,0x78,0x3C,0x06,0x00,0x00,0x78,0x3C,0x0F,0x00,0x7F,0xFF,0xFF,0xFF,
330x80,0x00,0x78,0x3C,0x00,0x80,0x00,0x78,0x1C,0x10,0x00,0x00,0x78,0x1C,0x38,0x00,
340x00,0x78,0x1C,0x3C,0x00,0x00,0x78,0x5C,0x7E,0x00,0x00,0x7F,0xDC,0x70,0x00,0x00,
350x7E,0x1C,0xF0,0x00,0x01,0xF8,0x1F,0xE0,0x00,0x1F,0xF8,0x1F,0xC0,0x00,0x7F,0x78,
360x0F,0x80,0x00,0x3C,0x78,0x0F,0x00,0x00,0x30,0x78,0x0F,0x01,0x80,0x00,0x78,0x3F,
370x81,0x80,0x00,0x78,0x7B,0xC1,0x80,0x00,0x78,0xF1,0xE1,0x80,0x00,0x7B,0xC0,0xF3,
380x80,0x00,0x7F,0x00,0x7F,0x80,0x0F,0xFC,0x00,0x3F,0x80,0x01,0xF0,0x00,0x0F,0xC0,
390x00,0xE0,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
40 };
41
42/*转换,并显示*/
43voidpch(int *add,const unsigned char* buf)
44 {
45int row = 0;
46int col = 0;
47inti = 0;
48int color = 0x0;
49for(row=0;row>j))>0?1:0 ;
61 index++;
62 }
63i++;
64 j = 0;
65 }
66
67/*一行数据,按位显示*/
68for(col=0;col显示效果: