一. 理论分析
1. 几个概念:
FIMC :
Fully Interactive Mobile Camera (完全交互式移动摄像机)
FIMD:
Fully Interactive Mobile Display (完全交互式移动显示设备)
2. 设置VCLK
在VIDCON0中
bit[3:2]-->Select the Video Clock source =00 --> HCLK=133MHZ
bit[13:6] --> CLKVAL_F = 13 (这个值是在驱动中计算出来的)
VCLK = Video Clock Source / (CLKVAL+1) where CLKVAL >= 1
= 133MHZ / (13+1) = 9.5MHZ
3. 刷新频率计算
Frame Rate = VCLK / (HSPW + HBPD + HOZVAL + HFPD) / (VSPW + VBPD + LINEVAL + VFPD)
= 9.5MHZ/(2+41+2+480)/(2+272+10+2)
=0.00006327MHZ
=63HZ
二. 驱动分析
首先在平台的目录中定义platform_device
在arch/arm/plat-samsung/dev-fb.c中
1 static struct resource s3c_fb_resource[] = {
2 [0] = {
3 .start = S3C_PA_FB,
4 .end = S3C_PA_FB + SZ_16K - 1,
5 .flags = IORESOURCE_MEM,
6 },
7 [1] = {
8 .start = IRQ_LCD_VSYNC,
9 .end = IRQ_LCD_VSYNC,
10 .flags = IORESOURCE_IRQ,
11 },
12 [2] = {
13 .start = IRQ_LCD_FIFO,
14 .end = IRQ_LCD_FIFO,
15 .flags = IORESOURCE_IRQ,
16 },
17 [3] = {
18 .start = IRQ_LCD_SYSTEM,
19 .end = IRQ_LCD_SYSTEM,
20 .flags = IORESOURCE_IRQ,
21 },
22 };
23
24 struct platform_device s3c_device_fb = {
25 .name = 's3c-fb',
26 .id = -1,
27 .num_resources = ARRAY_SIZE(s3c_fb_resource),
28 .resource = s3c_fb_resource,
29 .dev.dma_mask = &s3c_device_fb.dev.coherent_dma_mask,
30 .dev.coherent_dma_mask = 0xffffffffUL,
31 };
然后在驱动的probe函数中:
在driver/video/samsun/s3cfb.c中
1 static int __init s3cfb_probe(struct platform_device *pdev)
2 {
3 struct resource *res;
4 struct fb_info *fbinfo;
5 s3cfb_info_t *info;
6
7 char driver_name[] = 's3cfb';
8 int index = 0, ret, size;
9 //分配sizeof(fb_info+私有成员)大小的内存,使par指向s3cfb_info_t结构体
10 fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);
11
12 platform_set_drvdata(pdev, fbinfo);
13
14 info = fbinfo->par; //私有数据是一个结构体s3cfb_info_t
15 info->dev = &pdev->dev;
16
17 //获取LCD的io端口,并映射
18 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19 size = (res->end - res->start) + 1;
20 info->mem = request_mem_region(res->start, size, pdev->name);
21 info->io = ioremap(res->start, size);
22
23 s3cfb_pre_init(); //2.使能中断寄存器,s3cfb_fimd的第一次初始化
24 s3cfb_set_backlight_power(1); //设置backlight_power = 1;
25 s3cfb_set_lcd_power(1); //设置lcd_power = 1;
26 s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL); //设置backlight_level = 2;
27
28 //获取时钟,并使能
29 info->clk = clk_get(NULL, 'lcd'); //133.000Mhz,使用的是HCLK
30 clk_enable(info->clk);
31
32 s3cfb_fimd.vsync_info.count = 0;
33 init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);
34
35 //申请中断
36 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
37 ret = request_irq(res->start, s3cfb_irq, 0, 's3c-lcd', pdev);
38 msleep(5);
39 //对4个framebuffer分别初始化
40 for (index = 0; index < S3CFB_NUM; index++) {
41 s3cfb_info[index].mem = info->mem;
42 s3cfb_info[index].io = info->io;
43 s3cfb_info[index].clk = info->clk;
44
45 s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index); //3.初始化fbinfo
46 ret = s3cfb_map_video_memory(&s3cfb_info[index]); //4.分配dma内存
47
48 ret = s3cfb_init_registers(&s3cfb_info[index]); //5.写寄存器
49 ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb); //6.设置var范围
50
51 if (index < 2){
52 if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0) //7.申请color map
53 goto dealloc_fb;
54 } else {
55 if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
56 goto dealloc_fb;
57 }
58
59 ret = register_framebuffer(&s3cfb_info[index].fb); //8.注册framebuffer
60 }
61
62 ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);
63 ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);
64 ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);
65 return 0;
66 }
1.分配内存
分配fb_info+size大小的内存,并使par指向私有数据size
1 struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
2 {
3 fb_info_size += PADDING; //加上PADDING是让私有数据4字节对齐
4 char *p = kzalloc(fb_info_size + size, GFP_KERNEL);
5
6 struct fb_info * info = (struct fb_info *) p;
7 info->par = p + fb_info_size; //par指向私有数据
8 info->device = dev;
9 return info; //返回申请内存的首指针
10 }
2. 初始化视频中断控制寄存器0
在drivers/video/samsun/s3cfb_fimd4x.c中
1 void s3cfb_pre_init(void)
2 {
3 //Video Frame Interrupt 0 at start of VSYNC,并使能
4 s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
5 s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
6 s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
7 //0x9021=1001 0000 0010 0001
8 //打开video 中断,关闭fifo 中断
9 //打开 video frame 中断, Video Frame Interrupt 0 at start of VSYNC
10 writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
11 }
在driver/vidoe/samsun/s3cfb.c中
1 static void s3cfb_set_lcd_power(int to)
2 {
3 s3cfb_fimd.lcd_power = to;
4 }
5
6 static void s3cfb_set_backlight_power(int to)
7 {
8 s3cfb_fimd.backlight_power = to;
9 }
10
11 static void s3cfb_set_backlight_level(int to)
12 {
13 s3cfb_fimd.backlight_level = to;
14 }
3. 初始化s3cfb_info_t结构体
在driver/vidoe/samsun/s3cfb.c中
1 static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
2 {
3 int i = 0;
4 if (index == 0)
5 {
6 if(lcdsize == 1)
7 s3cfb_init_hw_43(); //3.1 s3cfb_fimd及gpio的初始化
8 }
9 strcpy(finfo->fb.fix.id, drv_name);
10 //下面一大段就是要将初始化好后的s3cfb_fimd赋给finfo,类似于结构体转化
11 finfo->win_id = index;
12 finfo->fb.fix.type = FB_TYPE_PACKED_PIXELS;
13 finfo->fb.fix.type_aux = 0;
14 finfo->fb.fix.xpanstep = 0;
15 finfo->fb.fix.ypanstep = 1;
16 finfo->fb.fix.ywrapstep = 0;
17 finfo->fb.fix.accel = FB_ACCEL_NONE;
18
19 finfo->fb.fbops = &s3cfb_ops; //fb操作函数
20 finfo->fb.flags = FBINFO_FLAG_DEFAULT;
21
22 finfo->fb.pseudo_palette = &finfo->pseudo_pal;
23
24 finfo->fb.var.nonstd = 0;
25 finfo->fb.var.activate = FB_ACTIVATE_NOW;
26 finfo->fb.var.accel_flags = 0;
27 finfo->fb.var.vmode = FB_VMODE_NONINTERLACED;
28
29 finfo->fb.var.xoffset = s3cfb_fimd.xoffset; //xoffset=0