一. 理论分析
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. 1 static struct resource s3c_fb_resource[] = {
  2. 2 [0] = {
  3. 3 .start = S3C_PA_FB,
  4. 4 .end = S3C_PA_FB + SZ_16K - 1,
  5. 5 .flags = IORESOURCE_MEM,
  6. 6 },
  7. 7 [1] = {
  8. 8 .start = IRQ_LCD_VSYNC,
  9. 9 .end = IRQ_LCD_VSYNC,
  10. 10 .flags = IORESOURCE_IRQ,
  11. 11 },
  12. 12 [2] = {
  13. 13 .start = IRQ_LCD_FIFO,
  14. 14 .end = IRQ_LCD_FIFO,
  15. 15 .flags = IORESOURCE_IRQ,
  16. 16 },
  17. 17 [3] = {
  18. 18 .start = IRQ_LCD_SYSTEM,
  19. 19 .end = IRQ_LCD_SYSTEM,
  20. 20 .flags = IORESOURCE_IRQ,
  21. 21 },
  22. 22 };
  23. 23
  24. 24 struct platform_device s3c_device_fb = {
  25. 25 .name = "s3c-fb",
  26. 26 .id = -1,
  27. 27 .num_resources = ARRAY_SIZE(s3c_fb_resource),
  28. 28 .resource = s3c_fb_resource,
  29. 29 .dev.dma_mask = &s3c_device_fb.dev.coherent_dma_mask,
  30. 30 .dev.coherent_dma_mask = 0xffffffffUL,
  31. 31 };

然后在驱动的probe函数中:
在driver/video/samsun/s3cfb.c中

  1. 1 static int __init s3cfb_probe(struct platform_device *pdev)
  2. 2 {
  3. 3 struct resource *res;
  4. 4 struct fb_info *fbinfo;
  5. 5 s3cfb_info_t *info;
  6. 6
  7. 7 char driver_name[] = "s3cfb";
  8. 8 int index = 0, ret, size;
  9. 9 //分配sizeof(fb_info+私有成员)大小的内存,使par指向s3cfb_info_t结构体
  10. 10 fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);
  11. 11
  12. 12 platform_set_drvdata(pdev, fbinfo);
  13. 13
  14. 14 info = fbinfo->par; //私有数据是一个结构体s3cfb_info_t
  15. 15 info->dev = &pdev->dev;
  16. 16
  17. 17 //获取LCD的io端口,并映射
  18. 18 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  19. 19 size = (res->end - res->start) + 1;
  20. 20 info->mem = request_mem_region(res->start, size, pdev->name);
  21. 21 info->io = ioremap(res->start, size);
  22. 22
  23. 23 s3cfb_pre_init(); //2.使能中断寄存器,s3cfb_fimd的第一次初始化
  24. 24 s3cfb_set_backlight_power(1); //设置backlight_power = 1;
  25. 25 s3cfb_set_lcd_power(1); //设置lcd_power = 1;
  26. 26 s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL); //设置backlight_level = 2;
  27. 27
  28. 28 //获取时钟,并使能
  29. 29 info->clk = clk_get(NULL, "lcd"); //133.000Mhz,使用的是HCLK
  30. 30 clk_enable(info->clk);
  31. 31
  32. 32 s3cfb_fimd.vsync_info.count = 0;
  33. 33 init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);
  34. 34
  35. 35 //申请中断
  36. 36 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  37. 37 ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev);
  38. 38 msleep(5);
  39. 39 //对4个framebuffer分别初始化
  40. 40 for (index = 0; index < S3CFB_NUM; index++) {
  41. 41 s3cfb_info[index].mem = info->mem;
  42. 42 s3cfb_info[index].io = info->io;
  43. 43 s3cfb_info[index].clk = info->clk;
  44. 44
  45. 45 s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index); //3.初始化fbinfo
  46. 46 ret = s3cfb_map_video_memory(&s3cfb_info[index]); //4.分配dma内存
  47. 47
  48. 48 ret = s3cfb_init_registers(&s3cfb_info[index]); //5.写寄存器
  49. 49 ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb); //6.设置var范围
  50. 50
  51. 51 if (index < 2){
  52. 52 if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0) //7.申请color map
  53. 53 goto dealloc_fb;
  54. 54 } else {
  55. 55 if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
  56. 56 goto dealloc_fb;
  57. 57 }
  58. 58
  59. 59 ret = register_framebuffer(&s3cfb_info[index].fb); //8.注册framebuffer
  60. 60 }
  61. 61
  62. 62 ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);
  63. 63 ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);
  64. 64 ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);
  65. 65 return 0;
  66. 66 }

1.分配内存
分配fb_info+size大小的内存,并使par指向私有数据size

  1. 1 struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
  2. 2 {
  3. 3 fb_info_size += PADDING; //加上PADDING是让私有数据4字节对齐
  4. 4 char *p = kzalloc(fb_info_size + size, GFP_KERNEL);
  5. 5
  6. 6 struct fb_info * info = (struct fb_info *) p;
  7. 7 info->par = p + fb_info_size; //par指向私有数据
  8. 8 info->device = dev;
  9. 9 return info; //返回申请内存的首指针
  10. 10 }

2. 初始化视频中断控制寄存器0
在drivers/video/samsun/s3cfb_fimd4x.c中

  1. 1 void s3cfb_pre_init(void)
  2. 2 {
  3. 3 //Video Frame Interrupt 0 at start of VSYNC,并使能
  4. 4 s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
  5. 5 s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
  6. 6 s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;
  7. 7 //0x9021=1001 0000 0010 0001
  8. 8 //打开video 中断,关闭fifo 中断
  9. 9 //打开 video frame 中断, Video Frame Interrupt 0 at start of VSYNC
  10. 10 writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  11. 11 }

在driver/vidoe/samsun/s3cfb.c中

  1. 1 static void s3cfb_set_lcd_power(int to)
  2. 2 {
  3. 3 s3cfb_fimd.lcd_power = to;
  4. 4 }
  5. 5
  6. 6 static void s3cfb_set_backlight_power(int to)
  7. 7 {
  8. 8 s3cfb_fimd.backlight_power = to;
  9. 9 }
  10. 10
  11. 11 static void s3cfb_set_backlight_level(int to)
  12. 12 {
  13. 13 s3cfb_fimd.backlight_level = to;
  14. 14 }

3. 初始化s3cfb_info_t结构体
在driver/vidoe/samsun/s3cfb.c中

  1. 1 static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
  2. 2 {
  3. 3 int i = 0;
  4. 4 if (index == 0)
  5. 5 {
  6. 6 if(lcdsize == 1)
  7. 7 s3cfb_init_hw_43(); //3.1 s3cfb_fimd及gpio的初始化
  8. 8 }
  9. 9 strcpy(finfo->fb.fix.id, drv_name);
  10. 10 //下面一大段就是要将初始化好后的s3cfb_fimd赋给finfo,类似于结构体转化
  11. 11 finfo->win_id = index;
  12. 12 finfo->fb.fix.type = FB_TYPE_PACKED_PIXELS;
  13. 13 finfo->fb.fix.type_aux = 0;
  14. 14 finfo->fb.fix.xpanstep = 0;
  15. 15 finfo->fb.fix.ypanstep = 1;
  16. 16 finfo->fb.fix.ywrapstep = 0;
  17. 17 finfo->fb.fix.accel = FB_ACCEL_NONE;
  18. 18
  19. 19 finfo->fb.fbops = &s3cfb_ops; //fb操作函数
  20. 20 finfo->fb.flags = FBINFO_FLAG_DEFAULT;
  21. 21
  22. 22 finfo->fb.pseudo_palette = &finfo->pseudo_pal;
  23. 23
  24. 24 finfo->fb.var.nonstd = 0;
  25. 25 finfo->fb.var.activate = FB_ACTIVATE_NOW;
  26. 26 finfo->fb.var.accel_flags = 0;
  27. 27 finfo->fb.var.vmode = FB_VMODE_NONINTERLACED;
  28. 28
  29. 29 finfo->fb.var.xoffset = s3cfb_fimd.xoffset; //xoffset=0
  30. 30 finfo->fb.var.yoffset = s3cfb_fimd.yoffset; //yoffset=0
  31. 31
  32. 32 if (index == 0) {
  33. 33 finfo->fb.var.height = s3cfb_fimd.height; //height=272
  34. 34 finfo->fb.var.width = s3cfb_fimd.width; //width=480
  35. 35
  36. 36 finfo->fb.var.xres = s3cfb_fimd.xres; //xres=480
  37. 37 finfo->fb.var.yres = s3cfb_fimd.yres; //yres=272
  38. 38
  39. 39 finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual; //xres_virtual=480
  40. 40 finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual; //yres_virtual=544
  41. 41 } else {
  42. 42 finfo->fb.var.height = s3cfb_fimd.osd_height; //osd_height=272
  43. 43 finfo->fb.var.width = s3cfb_fimd.osd_width; //osd_height=480
  44. 44
  45. 45 finfo->fb.var.xres = s3cfb_fimd.osd_xres; //osd_xres=480
  46. 46 finfo->fb.var.yres = s3cfb_fimd.osd_yres; //osd_yres=272
  47. 47
  48. 48 finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual; //osd_xres_virtual=480
  49. 49 finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual; //osd_yres_virtaul=272
  50. 50 }
  51. 51
  52. 52 finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp; //16
  53. 53 finfo->fb.var.pixclock = s3cfb_fimd.pixclock; //9009000
  54. 54 finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len; //41
  55. 55 finfo->fb.var.left_margin = s3cfb_fimd.left_margin; //2
  56. 56 finfo->fb.var.right_margin = s3cfb_fimd.right_margin; //2
  57. 57 finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len; //10
  58. 58 finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin; //2
  59. 59 finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin; //2
  60. 60 finfo->fb.var.sync = s3cfb_fimd.sync; //0
  61. 61 finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale; //0
  62. 62 //480*544*2=522240
  63. 63 finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;
  64. 64 finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel; //480*2=960
  65. 65
  66. 66 for (i = 0; i < 256; i++)
  67. 67 finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR; //(0x80000000)
  68. 68 }

3.1 初始化s3cfb_fimd及gpio的初始化
在drviers/video/samsung/s3cfb_WXCAT43.c中

  1. 1 void s3cfb_init_hw_43(void)
  2. 2 {
  3. 3 s3cfb_set_fimd_info(); //3.1.1 s3cfb_fimd的第二次初始化
  4. 4 s3cfb_set_gpio(); //3.1.2 gpio口初始化
  5. 5 }

3.1.1 s3cfb_fimd结构体的第二次初始化
s3cfb_probe
--> s3cfb_init_fbinfo
    --> s3cfb_init_hw_43
    --> s3cfb_set_fimd_info

  1. 1 static void s3cfb_set_fimd_info(void)
  2. 2 {
  3. 3 // bit[7]= 0: RGB type LCD driver gets the video data at VCLK falling edge,下降沿获取数据
  4. 4 // bit[6]= 1: HSYNC 极性反转
  5. 5 // bit[5]= 1: VSYNC 极性反转
  6. 6 // bit[4]= 0: VDEN 极性不变
  7. 7 s3cfb_fimd.vidcon1 = S3C_VIDCON1_IHSYNC_INVERT | S3C_VIDCON1_IVSYNC_INVERT | S3C_VIDCON1_IVDEN_NORMAL; //0x60
  8. 8 //VBPDE[31-24]=0x0
  9. 9 //VBPD[23-16]=0x01
  10. 10 //VFPD[15-8]=0x01
  11. 11 //VSPW[7-0]=0x09
  12. 12 s3cfb_fimd.vidtcon0 = S3C_VIDTCON0_VBPD(S3CFB_VBP - 1) | S3C_VIDTCON0_VFPD(S3CFB_VFP - 1) | S3C_VIDTCON0_VSPW(S3CFB_VSW - 1); //0x10109
  13. 13 //HBPDE[31-24]=0x0
  14. 14 //HBPD[23-16]=0x01
  15. 15 //HFPD[15-8]=0x01
  16. 16 //HSPW[7-0]=0x28=40
  17. 17 s3cfb_fimd.vidtcon1 = S3C_VIDTCON1_HBPD(S3CFB_HBP - 1) | S3C_VIDTCON1_HFPD(S3CFB_HFP - 1) | S3C_VIDTCON1_HSPW(S3CFB_HSW - 1); //0x10128
  18. 18 //LINEVAL[21-11]=(Vertical display size)–1=10F=271
  19. 19 //HOZVAL[10-0] = (Horizontal display size)-1=1DF=479
  20. 20 s3cfb_fimd.vidtcon2 = S3C_VIDTCON2_LINEVAL(S3CFB_VRES - 1) | S3C_VIDTCON2_HOZVAL(S3CFB_HRES - 1); //0x879df
  21. 21 //OSD_LeftTopX_F[21-11] = 0
  22. 22 //OSD_LeftTopY_F[10-0] = 0 window_0左上角的坐标是(0,0)
  23. 23 s3cfb_fimd.vidosd0a = S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0); //0x0
  24. 24 //OSD_RightBotX_F[21-11] = 0x1DF=479
  25. 25 //OSD_RightBotY_F[10-0] = 0x10f =271 window_0右下角的坐标是(479,271)
  26. 26 s3cfb_fimd.vidosd0b = S3C_VIDOSDxB_OSD_RBX_F(S3CFB_HRES - 1) | S3C_VIDOSDxB_OSD_RBY_F(S3CFB_VRES - 1); //0xef90f
  27. 27 //OSD_LeftTopX_F[21-11] = 0
  28. 28 //OSD_LeftTopY_F[10-0] = 0 window_1左上角的坐标是(0,0)
  29. 29 s3cfb_fimd.vidosd1a = S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0); //0x0
  30. 30 //OSD_RightBotX_F[21-11] = 0x1DF=479
  31. 31 //OSD_RightBotY_F[10-0] = 0x10f =271 window_1右下角的坐标是(479,271)
  32. 32 s3cfb_fimd.vidosd1b = S3C_VIDOSDxB_OSD_RBX_F(S3CFB_HRES_OSD - 1) | S3C_VIDOSDxB_OSD_RBY_F(S3CFB_VRES_OSD - 1); //0xef90f
  33. 33
  34. 34 s3cfb_fimd.width = S3CFB_HRES; //480
  35. 35 s3cfb_fimd.height = S3CFB_VRES; //272
  36. 36 s3cfb_fimd.xres = S3CFB_HRES; //480
  37. 37 s3cfb_fimd.yres = S3CFB_VRES; //272
  38. 38
  39. 39 //定义了(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  40. 40 s3cfb_fimd.xres_virtual = S3CFB_HRES_VIRTUAL; //如果定义了Virtual_screen则为480*544
  41. 41 s3cfb_fimd.yres_virtual = S3CFB_VRES_VIRTUAL; //如果没有定义Virtual_screen则为480*272
  42. 42
  43. 43 s3cfb_fimd.osd_width = S3CFB_HRES_OSD; //480
  44. 44 s3cfb_fimd.osd_height = S3CFB_VRES_OSD; //272
  45. 45 s3cfb_fimd.osd_xres = S3CFB_HRES_OSD; //480
  46. 46 s3cfb_fimd.osd_yres = S3CFB_VRES_OSD; //272
  47. 47
  48. 48 s3cfb_fimd.osd_xres_virtual = S3CFB_HRES_OSD; //480
  49. 49 s3cfb_fimd.osd_yres_virtual = S3CFB_VRES_OSD; //272
  50. 50
  51. 51 s3cfb_fimd.pixclock = S3CFB_PIXEL_CLOCK; //9009000
  52. 52
  53. 53 s3cfb_fimd.hsync_len = S3CFB_HSW; //41
  54. 54 s3cfb_fimd.vsync_len = S3CFB_VSW; //10
  55. 55 s3cfb_fimd.left_margin = S3CFB_HFP; //2
  56. 56 s3cfb_fimd.upper_margin = S3CFB_VFP; //2
  57. 57 s3cfb_fimd.right_margin = S3CFB_HBP; //2
  58. 58 s3cfb_fimd.lower_margin = S3CFB_VBP; //2
  59. 59 }

小总结一下:
全局变量s3cfb_fimd_info_t s3cfb_fimd
首先定义在drivers/video/samsun/s3cfb_fimd4x.c中

第1次初始化 
s3cfb_probe
    --> s3cfb_pre_init();
打开video 中断,关闭fifo 中断
打开 video frame 中断, Video Frame Interrupt 0 at start of VSYNC

第2次初始化
s3cfb_probe
--> s3cfb_init_fbinfo
--> s3cfb_init_hw_43
    --> s3cfb_set_fimd_info

3.1.2 gpio口初始化

  1. 1 int s3cfb_set_gpio(void)
  2. 2 {
  3. 3 //将HCLK clock gating control寄存器0x7E00_F030的bit3设为1,即使能LCD的时钟
  4. 4 val = readl(S3C_HCLK_GATE);
  5. 5 val |= S3C_CLKCON_HCLK_LCD;
  6. 6 writel(val, S3C_HCLK_GATE);
  7. 7 //设置Special PortControl Register寄存器0x7F0081A0的bit[0-1]设为01,即RGB I/F style
  8. 8 val = readl(S3C64XX_SPCON);
  9. 9 val &= ~0x3;
  10. 10 val |= (1 << 0);
  11. 11 writel(val, S3C64XX_SPCON);
  12. 12
  13. 13 //VD[0-15]连在了GPI[0-15]上,所以要把GPI口配成LCD
  14. 14 for (i = 0; i < 16; i++)
  15. 15 s3c_gpio_cfgpin(S3C64XX_GPI(i), S3C_GPIO_SFN(2));
  16. 16
  17. 17 //VD[16-23]连在了GPJ[0-7]上,所以要把GPJ口配成LCD
  18. 18 //HSYNC-->GPJ8, VSYNC-->GPJ9, VDEN-->GPJ10, VCLK-->GPJ11
  19. 19 for (i = 0; i < 12; i++)
  20. 20 s3c_gpio_cfgpin(S3C64XX_GPJ(i), S3C_GPIO_SFN(2));
  21. 21
  22. 22 //ok6410跟GPE0好像没有什么关系,这儿可以去掉
  23. 23 if (gpio_is_valid(S3C64XX_GPE(0))) {
  24. 24 err = gpio_request(S3C64XX_GPE(0), "GPE");
  25. 25 gpio_direction_output(S3C64XX_GPE(0), 1);
  26. 26 }
  27. 27 gpio_set_value(S3C64XX_GPE(0), 1);
  28. 28 gpio_free(S3C64XX_GPE(0));
  29. 29 gpio_free(S3C64XX_GPF(14));
  30. 30 return 0;
  31. 31 }

4. 分配DMA内存
第1个window,双缓冲 0x7f8000=320*240*3*2
FB1: map_video_memory: dma=5f180000 cpu=ff600000 size=0007f800
Window[0] - FB2: map_video_memory: dma=5f1bfc00 cpu=ff63fc00 size=0003fc00
第2个window,双缓冲
FB1: map_video_memory: dma=5f200000 cpu=ff700000 size=0007f800
Window[1] - FB2: map_video_memory: dma=5f23fc00 cpu=ff73fc00 size=0003fc00

在drivers/vidoe/samsun/s3cfb.c中

  1. 1 static int __init s3cfb_map_video_memory(s3cfb_info_t *fbi)
  2. 2 {
  3. 3 fbi->map_size_f1 = PAGE_ALIGN(fbi->fb.fix.smem_len); //480*272*n对齐到4K
  4. 4 //index=0时在DMA空间分配480*272*4=0x7f800=对齐后0x80000大小的DMA内存
  5. 5 //index=1,2,3时在DMA空间分配480*272*2=0x3fc00=对齐后0x40000大小的DMA内存
  6. 6 fbi->map_cpu_f1 = dma_alloc_writecombine(fbi->dev, fbi->map_size_f1, &fbi->map_dma_f1, GFP_KERNEL); //分配dma内存
  7. 7 fbi->map_size_f1 = fbi->fb.fix.smem_len; //480*272*n原始大小,不对齐到4K
  8. 8
  9. 9 if (fbi->map_cpu_f1) { //map_cpu_f1是将dma映射到虚拟内存空间的地址
  10. 10 memset(fbi->map_cpu_f1, 0xf0, fbi->map_size_f1); //初始化成0xf0?这儿为什么不是0?
  11. 11 fbi->screen_dma_f1 = fbi->map_dma_f1;
  12. 12 fbi->fb.screen_base = fbi->map_cpu_f1;
  13. 13 fbi->fb.fix.smem_start = fbi->screen_dma_f1;
  14. 14 }
  15. 15 //下面的指针指向第二个 buffer
  16. 16 #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  17. 17 if (fbi->win_id<2 && fbi->map_cpu_f1) {
  18. 18 fbi->map_size_f2 = (fbi->fb.fix.smem_len / 2);
  19. 19 fbi->map_cpu_f2 = fbi->map_cpu_f1 + fbi->map_size_f2;
  20. 20 fbi->map_dma_f2 = fbi->map_dma_f1 + fbi->map_size_f2;
  21. 21 fbi->screen_dma_f2 = fbi->map_dma_f2;
  22. 22 }
  23. 23 #endif
  24. 24 return 0;
  25. 25 }

注: void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *, gfp_t);
          arg1是设备名
          arg2是分配dma buffer的长度
          arg3是分配dma的物理地址,利用指针改写
          arg4是标志GFP_KERNEL
          ret 返回分配dma的虚拟地址
ret 与 arg3都指向同一块内存,只不过argc3是物理地址,ret是虚拟地址.
dma_alloc_coherent: 禁止页表项中的C(cacheable)以及B(bufferable)域
dma_alloc_writecombine只是禁止C(Cacheable)域.即不使用cache

5. 写寄存器
在driver/video/samsun中

  1. 1 int s3cfb_init_registers(s3cfb_info_t *fbi)
  2. 2 {
  3. 3 struct clk *lcd_clock;
  4. 4 struct fb_var_screeninfo *var = &fbi->fb.var;
  5. 5 unsigned long flags = 0, page_width = 0, offset = 0;
  6. 6 unsigned long video_phy_temp_f1 = fbi->screen_dma_f1;
  7. 7 unsigned long video_phy_temp_f2 = fbi->screen_dma_f2;
  8. 8 int win_num = fbi->win_id;
  9. 9
  10. 10 local_irq_save(flags); //关中断,并保存
  11. 11
  12. 12 page_width = var->xres * s3cfb_fimd.bytes_per_pixel; //page_width=960
  13. 13 offset = (var->xres_virtual - var->xres) * s3cfb_fimd.bytes_per_pixel; //offset=0
  14. 14 if (win_num == 0) {
  15. 15 s3cfb_fimd.vidcon0 = s3cfb_fimd.vidcon0 & ~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);
  16. 16 writel(s3cfb_fimd.vidcon0, S3C_VIDCON0); //设置lcd的clk分频-->Divided by CLKVAL_F
  17. 17
  18. 18 lcd_clock = clk_get(NULL, "lcd");
  19. 19 s3cfb_fimd.vidcon0 |= S3C_VIDCON0_CLKVAL_F((int) ((clk_get_rate(lcd_clock) / s3cfb_fimd.pixclock) - 1));
  20. 20 //lcd_clock->rate=13M, s3cfb_fimd.pixclock=9M, s3cfb_fimd.vidcon0[13-6]=13
  21. 21 #if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  22. 22 offset = 0;
  23. 23 s3cfb_fimd.vidw00add0b0 = video_phy_temp_f1;
  24. 24 s3cfb_fimd.vidw00add0b1 = video_phy_temp_f2;
  25. 25 s3cfb_fimd.vidw00add1b0 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres));
  26. 26 s3cfb_fimd.vidw00add1b1 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres));
  27. 27 #endif
  28. 28 }
  29. 29
  30. 30 writel(video_phy_temp_f1, S3C_VIDW00ADD0B0 + (0x08 * win_num));
  31. 31 writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B0 + (0x08 * win_num));
  32. 32 writel(S3C_VIDWxxADD2_OFFSIZE_F(offset) | (S3C_VIDWxxADD2_PAGEWIDTH_F(page_width)), S3C_VIDW00ADD2 + (0x04 * win_num));
  33. 33
  34. 34 if (win_num < 2) {
  35. 35 writel(video_phy_temp_f2, S3C_VIDW00ADD0B1 + (0x08 * win_num));
  36. 36 writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B1 + (0x08 * win_num));
  37. 37 }
  38. 38
  39. 39 switch (win_num) {
  40. 40 case 0:
  41. 41 //wincon0=0x110014=0001 0001 0000 0000 0001 0100
  42. 42 //bit[0]=video output disable --> 导致bit[22]=0
  43. 43 //bit[5-2]=0101=16BPP (R5 G6 B5)
  44. 44 //bit[10-9]=00 = DMA's Burst Max len 16word
  45. 45 //bit[13] = 0 = input color space RGB
  46. 46 //bit[16] = 1 = half wrod swap enabel
  47. 47 //bit[20] = 1 = select buf 1
  48. 48 writel(s3cfb_fimd.wincon0, S3C_WINCON0);
  49. 49
  50. 50 //vidcon0=0x350=0011 0101 0000
  51. 51 //bit[3-2]=00 = VideoClock source = HCLK
  52. 52 //bit[4]=1=video clock Divided by CLKVAL_F
  53. 53 //bit[13-6]=00 1101 = 13 HCLK/CLKVAL_F=133/13=10.230769231M
  54. 54 writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);
  55. 55
  56. 56 //vidcon1=0x60 = 0110 0000
  57. 57 //bit[4]= VDEN polarity noraml
  58. 58 //bit[5]=VSYNC polarity inverted
  59. 59 //bit[6]=HSYNC polarity inverted
  60. 60 //bit[7]=gets the video data at vclk falling
  61. 61 writel(s3cfb_fimd.vidcon1, S3C_VIDCON1);
  62. 62
  63. 63 //vidtcon0=0x10109
  64. 64 //VBPDE[31-24]= 0x0
  65. 65 //VBPD[23-16]= 0x01
  66. 66 //VFPD[15-8]= 0x01
  67. 67 //VSPW[7-0]= 0x09
  68. 68 writel(s3cfb_fimd.vidtcon0, S3C_VIDTCON0);
  69. 69
  70. 70 //vidtcon1=0x10128
  71. 71 //VFPDE[31-24]=0x0
  72. 72 //HBPD[23-16]=0x01
  73. 73 //HFPD[15-8]=0x01
  74. 74 //HSPW[7-0]= 0x28=40
  75. 75 writel(s3cfb_fimd.vidtcon1, S3C_VIDTCON1);
  76. 76
  77. 77 //vidtcon2=0x879df
  78. 78 //LINEVAL[21-11]=(Vertical display size)–1=10F=271
  79. 79 //HOZVAL[10-0] = (Horizontal display size)-1=1DF=479
  80. 80 writel(s3cfb_fimd.vidtcon2, S3C_VIDTCON2);
  81. 81
  82. 82 //dithmode=0x0
  83. 83 //禁用dither
  84. 84 writel(s3cfb_fimd.dithmode, S3C_DITHMODE);
  85. 85
  86. 86 //vidintcon0=0x9021=0x1001 0000 0010 0001
  87. 87 //bit[0]=Video Interrupt Enable
  88. 88 //bit[1]=FIFO disable
  89. 89 //bit[4-2]=FIFO int level =25
  90. 90 //bit[11-5]=FIFO int -->win 0 control enable
  91. 91 //bit[12]=video Frame interrupt enable
  92. 92 //bit[14-13]=video frame int 1 start of None
  93. 93 //bit[16-15]=video frame int 0 start of VSYNC
  94. 94 writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  95. 95
  96. 96 //vidintcon1=0x0
  97. 97 //没看出什么用
  98. 98 writel(s3cfb_fimd.vidintcon1, S3C_VIDINTCON1);
  99. 99
  100. 100 //vidosd0a=0x0
  101. 101 //window_0左上角坐标(0,0)
  102. 102 writel(s3cfb_fimd.vidosd0a, S3C_VIDOSD0A);
  103. 103
  104. 104 //vidosd0b=0xef90f
  105. 105 //window_0右下角的坐标是(479,271)
  106. 106 writel(s3cfb_fimd.vidosd0b, S3C_VIDOSD0B);
  107. 107
  108. 108 //vidosd0c=0x0
  109. 109 //bit[23-0]=Window Size = 竟然为0?
  110. 110 writel(s3cfb_fimd.vidosd0c, S3C_VIDOSD0C);
  111. 111
  112. 112 //wpalcon=0x6
  113. 113 //
  114. 114 //
  115. 115 //
  116. 116 writel(s3cfb_fimd.wpalcon, S3C_WPALCON);
  117. 117
  118. 118 //
  119. 119 s3cfb_onoff_win(fbi, ON);
  120. 120 break;
  121. 121 case 1-4:
  122. 122 类推,省略.
  123. 123 break;
  124. 124 }
  125. 125
  126. 126 local_irq_restore(flags); //开中断,并恢复,于上面的local_irq_save正好相反
  127. 127
  128. 128 return 0;
  129. 129 }

6. 规定范围 

  1. 1 static int s3cfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  2. 2 {
  3. 3 s3cfb_info_t *fbi = (s3cfb_info_t *) info;
  4. 4 switch (var->bits_per_pixel) {
  5. 5 case 16:
  6. 6 var->red = s3cfb_rgb_16.red; //{.offset = 11, .length = 5,},
  7. 7 var->green = s3cfb_rgb_16.green; //{.offset = 5, .length = 6,},
  8. 8 var->blue = s3cfb_rgb_16.blue; //{.offset = 0, .length = 5,},
  9. 9 var->transp = s3cfb_rgb_16.transp; //{.offset = 0, .length = 0,},
  10. 10 s3cfb_fimd.bytes_per_pixel = 2; //每个像素2个字节
  11. 11 break;
  12. 12 }
  13. 13 //对窗口0进行特殊处理
  14. 14 if( (fbi->win_id == 0) && (var->bits_per_pixel == 28) )
  15. 15 var->transp.length = 0;
  16. 16
  17. 17 return 0;
  18. 18 }

7. 分配并初始化color map 
fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0);

  1. 1 int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
  2. 2 {
  3. 3 return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC);
  4. 4 }

在driver/video/fbcmap.c中

  1. 1 int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags)
  2. 2 {
  3. 3 int size = len * sizeof(u16);
  4. 4
  5. 5 if (cmap->len != len) {
  6. 6 fb_dealloc_cmap(cmap); //把以前申请的rgb内存kfree掉
  7. 7 cmap->red = kmalloc(size, flags); //重新分配内存,GFP_ATOMIC
  8. 8 cmap->green = kmalloc(size, flags); //重新分配内存,GFP_ATOMIC
  9. 9 cmap->blue = kmalloc(size, flags); //重新分配内存,GFP_ATOMIC
  10. 10 if (transp) {
  11. 11 cmap->transp = kmalloc(size, flags);
  12. 12 } else {
  13. 13 cmap->transp = NULL; //transp设为NULL
  14. 14 }
  15. 15 }
  16. 16 cmap->start = 0;
  17. 17 cmap->len = len;
  18. 18 ret = fb_copy_cmap(fb_default_cmap(len), cmap); //把default的cmap复制到新分配的cmap中
  19. 19 return 0;
  20. 20 }

上层执行fb_set_par 
     -->  s3cfb_set_par

  1. 1 static int s3cfb_set_par(struct fb_info *info)
  2. 2 {
  3. 3 //var->bits_per_pixel=16, s3cfb_fimd.bytes_per_pixel=2
  4. 4 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
  5. 5 fbi->fb.fix.line_length = var->width * s3cfb_fimd.bytes_per_pixel;
  6. 6 s3cfb_activate_var(fbi, var);
  7. 7 return 0;
  8. 8 }

上层执行fb_set_par 
     -->  s3cfb_set_par
    --> s3cfb_activate_var
根据像素数设置寄存器.

  1. 1 void s3cfb_activate_var(s3cfb_info_t *fbi, struct fb_var_screeninfo *var)
  2. 2 {
  3. 3 switch (var->bits_per_pixel) {
  4. 4 case 16:
  5. 5 s3cfb_fimd.wincon0 = S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_16BPP_565;
  6. 6 s3cfb_fimd.wincon1 = S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1;
  7. 7 s3cfb_fimd.wincon2 = S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1;
  8. 8 s3cfb_fimd.wincon3 = S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1;
  9. 9 s3cfb_fimd.wincon4 = S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1;
  10. 10 s3cfb_fimd.bpp = S3CFB_PIXEL_BPP_16;
  11. 11 s3cfb_fimd.bytes_per_pixel = 2;
  12. 12 break;
  13. 13 }
  14. 14 //配置为窗口0,1,2,3,4为rgb565模式,dma直传,burst mode, BURSTLEN=16Word
  15. 15 writel(s3cfb_fimd.wincon0, S3C_WINCON0); //0x10014
  16. 16 writel(s3cfb_fimd.wincon1, S3C_WINCON1); //0x10016
  17. 17 writel(s3cfb_fimd.wincon2, S3C_WINCON2); //0x10016
  18. 18 writel(s3cfb_fimd.wincon3, S3C_WINCON3); //0x10016
  19. 19 writel(s3cfb_fimd.wincon4, S3C_WINCON4); //0x10016
  20. 20 writel(s3cfb_fimd.wpalcon, S3C_WPALCON); //0x00006
  21. 21 //启动video output
  22. 22 writel(s3cfb_fimd.wincon0 | S3C_WINCONx_ENWIN_F_ENABLE, S3C_WINCON0); //0x10014
  23. 23 //设置clock并启动video output
  24. 24 writel(s3cfb_fimd.vidcon0 | S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE, S3C_VIDCON0); //0x350
  25. 25 }

三. 中断及数据传输
3.1 中断过程

  1. 1 irqreturn_t s3cfb_irq(int irqno, void *param)
  2. 2 {
  3. 3 writel(readl(S3C_VIDINTCON1), S3C_VIDINTCON1); //清中断
  4. 4
  5. 5 s3cfb_fimd.vsync_info.count++;
  6. 6 wake_up_interruptible(&s3cfb_fimd.vsync_info.wait_queue); //唤醒工作队列
  7. 7 return IRQ_HANDLED;
  8. 8 }

这个地方正在等侍工作队列,收到唤醒信号之后,就返回

  1. 1 int s3cfb_wait_for_vsync(void)
  2. 2 {
  3. 3 cnt = s3cfb_fimd.vsync_info.count;
  4. 4 wait_event_interruptible_timeout(s3cfb_fimd.vsync_info.wait_queue, cnt != s3cfb_fimd.vsync_info.count, HZ / 10);
  5. 5 return cnt;
  6. 6 }
  1. 1 int s3cfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  2. 2 {
  3. 3 switch(cmd){
  4. 4 case FBIO_WAITFORVSYNC:
  5. 5 if (get_user(crt, (unsigned int __user *)arg))
  6. 6 return -EFAULT;
  7. 7
  8. 8 return s3cfb_wait_for_vsync();
  9. 9 }
  10. 10 }

附录:
1. local_irq_save
s3cfb_probe
--> s3cfb_init_registers
    --> local_irq_save
2. 关于DMA
s3cfb_probe
--> s3cfb_map_video_memory
    --> dma_alloc_writecombine
    --> __dma_alloc

转自:http://blog.chinaunix.net/uid-26009923-id-3929286.html

S3C6410 LCD驱动分析(转)的更多相关文章

  1. Linux的LCD驱动分析及移植

    测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 LCD驱动分析 LCD屏的驱动总体上分成两块,一块是GUI ...

  2. 高通 android平台LCD驱动分析

    目前手机芯片厂家提供的源码里包含整个LCD驱动框架,一般厂家会定义一个xxx_fb.c的源文件,注册一个平台设备和平台驱动,在驱动的probe函数中来调用register_framebuffer(), ...

  3. LCD驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/21559153 1.S3C2440上LCD驱动 (FrameBuffer)实例开发讲解 其 ...

  4. LCD驱动分析(一)字符设备驱动框架分析

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...

  5. LCD驱动分析(三)时序分析

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二>

  6. LCD驱动分析(二)帧缓冲设备作为平台设备

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二> 1.平台设备注册 1.1在li ...

  7. Linux驱动之内核自带的S3C2440的LCD驱动分析

    先来看一下应用程序是怎么操作屏幕的:Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户 ...

  8. S3C6410触摸屏驱动分析

    一. device的注册1.0 两个注册//在smdk6410_machine_init中既注册了touchscreen的私有信息也注册了ts资源 1 在arch/arm/mach-s3c64xx/m ...

  9. FL2440驱动添加(3)LCD驱动添加学习笔记

    FL2440 LCD内置控制器,320*240 TFT型LCD. 自我理解总结的两种添加驱动模式: 非platform方式添加驱动: 加载驱动: 1,硬件初始化,申请内存,并作地址映射 2,分配设备号 ...

随机推荐

  1. wpf之DataGrid绑定DataTable,其中DataGridComboBoxColumn双向绑定枚举enum

    百度了快一天,没结果,除了几个原创的,都是复制粘贴的内容. 不想用别的笨办法,于是脑洞大开,想出了我的办法. 首先是前台代码,与网上的比较类似: xmlns:jz="clr-namespac ...

  2. 修改CentOS的yum源,改为阿里云的镜像

    修改CentOS的yum源,改为阿里云的镜像 1.备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.b ...

  3. Activiti7 流程变量(理论)

    什么是流程变量 流程变量在Activiti中是一个非常重要的角色,流程运转有时需要靠流程变量,业务系统和Activiti结合时少不了流程变量,流程变量就是Activiti在管理工作流时根据管理需要而设 ...

  4. 使用Flashback救回被误drop掉的表

    如果不慎把表drop掉了,并非一定要跑路,也许下面的文字能打救你. 比如现在有个testtb表,里面有一百万数据: SQL> select count(*) from testtb; COUNT ...

  5. 现象:当指定logback的FileNamePattern为日期2020-01-15后,如果有线程不断的往里写log,过了零点文件不会变成下一日2020-01-16,还是会在2020-01-15里继续写 结论:写log的线程不停,文件不会按日子更换。

    logback版本:1.1.11 这个是我实验验证的,昨天我配置了一个logback,然后用两个线程不断往里写log,结果发现到了今天2020-01-16日,log文件还是昨天的logbackCfg. ...

  6. RabbitMQ安装和运行

    RabbitMQ在Windows下安装和运行 1.下载Erlang: http://www.erlang.org/downloads/19.2 2.下载Windows版RabbitMq: http:/ ...

  7. selenium+python3+pycharm

    当使用selenium实现元素定位时,运行: 元素定位,常用8大方法.具体百度 在此以id定位进行解释 #from selenium import webdriver # driver=webdriv ...

  8. db2错误代码可能的原因

    一. SQL5005C运行cmd未用管理员权限打开 SQLCODE-303  数据类型不兼容 SQLCODE-305   查出的数据有NULL未处理直接写入接收变量 二.应该不会有人直接写sql用这个 ...

  9. 乔悟空-CTF-i春秋-Web-Not Found-🙋🏻‍♂️

    2020.09.08 又是匆匆忙忙的一天- 做题 题目 题目地址 做题 做题??做个屁,啥也不知道,干瞪眼

  10. 并发编程中死锁、递归锁、进程/线程池、协程TCP服务器并发等知识点

    1.死锁 定义; 类似两个人分别被囚禁在两间房子里,A手上拿着的是B囚禁房间的钥匙,而B拿着A的钥匙,两个人都没法出去,没法给对方开锁,进而造成死锁现象.具体例子代码如下: # -*-coding:u ...