zoukankan      html  css  js  c++  java
  • S3C6410 LCD驱动分析(转)

    一. 理论分析
    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 
    30     finfo->fb.var.yoffset = s3cfb_fimd.yoffset;     //yoffset=0
    31 
    32     if (index == 0) {
    33         finfo->fb.var.height = s3cfb_fimd.height;   //height=272
    34         finfo->fb.var.width = s3cfb_fimd.width;     //width=480
    35 
    36         finfo->fb.var.xres = s3cfb_fimd.xres;       //xres=480
    37         finfo->fb.var.yres = s3cfb_fimd.yres;       //yres=272
    38 
    39         finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual;  //xres_virtual=480
    40         finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual;  //yres_virtual=544
    41     } else {
    42         finfo->fb.var.height = s3cfb_fimd.osd_height;      //osd_height=272
    43         finfo->fb.var.width = s3cfb_fimd.osd_width;        //osd_height=480
    44 
    45         finfo->fb.var.xres = s3cfb_fimd.osd_xres;         //osd_xres=480   
    46         finfo->fb.var.yres = s3cfb_fimd.osd_yres;         //osd_yres=272
    47 
    48         finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual;     //osd_xres_virtual=480
    49         finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual;     //osd_yres_virtaul=272
    50     }  
    51 
    52     finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp;               //16
    53     finfo->fb.var.pixclock = s3cfb_fimd.pixclock;                //9009000
    54     finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len;              //41
    55     finfo->fb.var.left_margin = s3cfb_fimd.left_margin;          //2
    56     finfo->fb.var.right_margin = s3cfb_fimd.right_margin;        //2
    57     finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len;              //10 
    58     finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin;        //2
    59     finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin;        //2
    60     finfo->fb.var.sync = s3cfb_fimd.sync;                        //0
    61     finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale;         //0
    62     //480*544*2=522240
    63     finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;
    64     finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel;    //480*2=960
    65 
    66     for (i = 0; i < 256; i++)
    67         finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR;       //(0x80000000)
    68 }

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

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

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

     1 static void s3cfb_set_fimd_info(void)
     2 {
     3 // bit[7]= 0: RGB type LCD driver gets the video data at VCLK falling edge,下降沿获取数据 
     4 // bit[6]= 1: HSYNC 极性反转
     5 // bit[5]= 1: VSYNC 极性反转
     6 // bit[4]= 0: VDEN 极性不变
     7     s3cfb_fimd.vidcon1 = S3C_VIDCON1_IHSYNC_INVERT | S3C_VIDCON1_IVSYNC_INVERT | S3C_VIDCON1_IVDEN_NORMAL;  //0x60
     8 //VBPDE[31-24]=0x0
     9 //VBPD[23-16]=0x01
    10 //VFPD[15-8]=0x01
    11 //VSPW[7-0]=0x09
    12     s3cfb_fimd.vidtcon0 = S3C_VIDTCON0_VBPD(S3CFB_VBP - 1) | S3C_VIDTCON0_VFPD(S3CFB_VFP - 1) | S3C_VIDTCON0_VSPW(S3CFB_VSW - 1); //0x10109
    13 //HBPDE[31-24]=0x0
    14 //HBPD[23-16]=0x01
    15 //HFPD[15-8]=0x01    
    16 //HSPW[7-0]=0x28=40  
    17     s3cfb_fimd.vidtcon1 = S3C_VIDTCON1_HBPD(S3CFB_HBP - 1) | S3C_VIDTCON1_HFPD(S3CFB_HFP - 1) | S3C_VIDTCON1_HSPW(S3CFB_HSW - 1); //0x10128
    18 //LINEVAL[21-11]=(Vertical display size)–1=10F=271
    19 //HOZVAL[10-0] = (Horizontal display size)-1=1DF=479
    20     s3cfb_fimd.vidtcon2 = S3C_VIDTCON2_LINEVAL(S3CFB_VRES - 1) | S3C_VIDTCON2_HOZVAL(S3CFB_HRES - 1);                             //0x879df
    21 //OSD_LeftTopX_F[21-11] = 0 
    22 //OSD_LeftTopY_F[10-0] = 0          window_0左上角的坐标是(0,0)
    23     s3cfb_fimd.vidosd0a = S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0);                                                  //0x0
    24 //OSD_RightBotX_F[21-11] = 0x1DF=479 
    25 //OSD_RightBotY_F[10-0] = 0x10f =271   window_0右下角的坐标是(479,271) 
    26     s3cfb_fimd.vidosd0b = S3C_VIDOSDxB_OSD_RBX_F(S3CFB_HRES - 1) | S3C_VIDOSDxB_OSD_RBY_F(S3CFB_VRES - 1);                        //0xef90f
    27 //OSD_LeftTopX_F[21-11] = 0 
    28 //OSD_LeftTopY_F[10-0] = 0         window_1左上角的坐标是(0,0)
    29     s3cfb_fimd.vidosd1a = S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0);                                                  //0x0
    30 //OSD_RightBotX_F[21-11] = 0x1DF=479 
    31 //OSD_RightBotY_F[10-0] = 0x10f =271   window_1右下角的坐标是(479,271)
    32     s3cfb_fimd.vidosd1b = S3C_VIDOSDxB_OSD_RBX_F(S3CFB_HRES_OSD - 1) | S3C_VIDOSDxB_OSD_RBY_F(S3CFB_VRES_OSD - 1);                //0xef90f
    33 
    34     s3cfb_fimd.width = S3CFB_HRES;                 //480
    35     s3cfb_fimd.height = S3CFB_VRES;                //272
    36     s3cfb_fimd.xres = S3CFB_HRES;                  //480
    37     s3cfb_fimd.yres = S3CFB_VRES;                  //272
    38 
    39     //定义了(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
    40     s3cfb_fimd.xres_virtual = S3CFB_HRES_VIRTUAL;  //如果定义了Virtual_screen则为480*544
    41     s3cfb_fimd.yres_virtual = S3CFB_VRES_VIRTUAL;  //如果没有定义Virtual_screen则为480*272
    42 
    43     s3cfb_fimd.osd_width = S3CFB_HRES_OSD;         //480
    44     s3cfb_fimd.osd_height = S3CFB_VRES_OSD;        //272
    45     s3cfb_fimd.osd_xres = S3CFB_HRES_OSD;          //480  
    46     s3cfb_fimd.osd_yres = S3CFB_VRES_OSD;          //272
    47 
    48     s3cfb_fimd.osd_xres_virtual = S3CFB_HRES_OSD;    //480
    49     s3cfb_fimd.osd_yres_virtual = S3CFB_VRES_OSD;    //272
    50 
    51     s3cfb_fimd.pixclock = S3CFB_PIXEL_CLOCK;         //9009000
    52 
    53     s3cfb_fimd.hsync_len = S3CFB_HSW;                //41
    54     s3cfb_fimd.vsync_len = S3CFB_VSW;                //10
    55     s3cfb_fimd.left_margin = S3CFB_HFP;              //2
    56     s3cfb_fimd.upper_margin = S3CFB_VFP;             //2
    57     s3cfb_fimd.right_margin = S3CFB_HBP;             //2
    58     s3cfb_fimd.lower_margin = S3CFB_VBP;             //2
    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 int s3cfb_set_gpio(void)
     2 {
     3     //将HCLK clock gating control寄存器0x7E00_F030的bit3设为1,即使能LCD的时钟
     4     val = readl(S3C_HCLK_GATE);
     5     val |= S3C_CLKCON_HCLK_LCD;
     6     writel(val, S3C_HCLK_GATE);
     7     //设置Special PortControl Register寄存器0x7F0081A0的bit[0-1]设为01,即RGB I/F style
     8     val = readl(S3C64XX_SPCON);
     9     val &= ~0x3;
    10     val |= (1 << 0);
    11     writel(val, S3C64XX_SPCON);
    12     
    13     //VD[0-15]连在了GPI[0-15]上,所以要把GPI口配成LCD
    14     for (i = 0; i < 16; i++)
    15         s3c_gpio_cfgpin(S3C64XX_GPI(i), S3C_GPIO_SFN(2));
    16     
    17     //VD[16-23]连在了GPJ[0-7]上,所以要把GPJ口配成LCD
    18     //HSYNC-->GPJ8, VSYNC-->GPJ9, VDEN-->GPJ10, VCLK-->GPJ11
    19     for (i = 0; i < 12; i++)
    20         s3c_gpio_cfgpin(S3C64XX_GPJ(i), S3C_GPIO_SFN(2));
    21 
    22     //ok6410跟GPE0好像没有什么关系,这儿可以去掉
    23     if (gpio_is_valid(S3C64XX_GPE(0))) {
    24         err = gpio_request(S3C64XX_GPE(0), "GPE");
    25         gpio_direction_output(S3C64XX_GPE(0), 1);
    26     }
    27     gpio_set_value(S3C64XX_GPE(0), 1);
    28     gpio_free(S3C64XX_GPE(0));
    29     gpio_free(S3C64XX_GPF(14));
    30     return 0;
    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 static int __init s3cfb_map_video_memory(s3cfb_info_t *fbi)
     2 {
     3     fbi->map_size_f1 = PAGE_ALIGN(fbi->fb.fix.smem_len);    //480*272*n对齐到4K
     4     //index=0时在DMA空间分配480*272*4=0x7f800=对齐后0x80000大小的DMA内存
     5     //index=1,2,3时在DMA空间分配480*272*2=0x3fc00=对齐后0x40000大小的DMA内存
     6     fbi->map_cpu_f1 = dma_alloc_writecombine(fbi->dev, fbi->map_size_f1, &fbi->map_dma_f1, GFP_KERNEL); //分配dma内存
     7     fbi->map_size_f1 = fbi->fb.fix.smem_len;                //480*272*n原始大小,不对齐到4K
     8 
     9     if (fbi->map_cpu_f1) {                                  //map_cpu_f1是将dma映射到虚拟内存空间的地址
    10         memset(fbi->map_cpu_f1, 0xf0, fbi->map_size_f1);    //初始化成0xf0?这儿为什么不是0?
    11         fbi->screen_dma_f1 = fbi->map_dma_f1;
    12         fbi->fb.screen_base = fbi->map_cpu_f1;
    13         fbi->fb.fix.smem_start = fbi->screen_dma_f1;
    14     }
    15     //下面的指针指向第二个 buffer
    16 #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
    17     if (fbi->win_id<2 && fbi->map_cpu_f1) {
    18         fbi->map_size_f2 = (fbi->fb.fix.smem_len / 2);
    19         fbi->map_cpu_f2 = fbi->map_cpu_f1 + fbi->map_size_f2;
    20         fbi->map_dma_f2 = fbi->map_dma_f1 + fbi->map_size_f2;
    21         fbi->screen_dma_f2 = fbi->map_dma_f2;
    22     }
    23 #endif
    24     return 0;
    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 int s3cfb_init_registers(s3cfb_info_t *fbi)
      2 {
      3     struct clk *lcd_clock;
      4     struct fb_var_screeninfo *var = &fbi->fb.var;
      5     unsigned long flags = 0, page_width = 0, offset = 0;
      6     unsigned long video_phy_temp_f1 = fbi->screen_dma_f1;
      7     unsigned long video_phy_temp_f2 = fbi->screen_dma_f2;
      8     int win_num = fbi->win_id;
      9 
     10     local_irq_save(flags);           //关中断,并保存
     11 
     12     page_width = var->xres * s3cfb_fimd.bytes_per_pixel;                     //page_width=960
     13     offset = (var->xres_virtual - var->xres) * s3cfb_fimd.bytes_per_pixel;   //offset=0
     14     if (win_num == 0) {
     15         s3cfb_fimd.vidcon0 = s3cfb_fimd.vidcon0 & ~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);
     16         writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);     //设置lcd的clk分频-->Divided by CLKVAL_F
     17 
     18         lcd_clock = clk_get(NULL, "lcd");
     19         s3cfb_fimd.vidcon0 |= S3C_VIDCON0_CLKVAL_F((int) ((clk_get_rate(lcd_clock) / s3cfb_fimd.pixclock) - 1));
     20 //lcd_clock->rate=13M, s3cfb_fimd.pixclock=9M, s3cfb_fimd.vidcon0[13-6]=13
     21 #if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
     22         offset = 0;
     23         s3cfb_fimd.vidw00add0b0 = video_phy_temp_f1;
     24         s3cfb_fimd.vidw00add0b1 = video_phy_temp_f2;
     25         s3cfb_fimd.vidw00add1b0 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres));
     26         s3cfb_fimd.vidw00add1b1 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres));
     27 #endif
     28      }
     29 
     30     writel(video_phy_temp_f1, S3C_VIDW00ADD0B0 + (0x08 * win_num));
     31     writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B0 + (0x08 * win_num));
     32     writel(S3C_VIDWxxADD2_OFFSIZE_F(offset) | (S3C_VIDWxxADD2_PAGEWIDTH_F(page_width)), S3C_VIDW00ADD2 + (0x04 * win_num));
     33 
     34     if (win_num < 2) {
     35         writel(video_phy_temp_f2, S3C_VIDW00ADD0B1 + (0x08 * win_num));
     36         writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B1 + (0x08 * win_num));
     37     }
     38 
     39     switch (win_num) {
     40     case 0:
     41         //wincon0=0x110014=0001 0001 0000 0000 0001 0100
     42         //bit[0]=video output disable --> 导致bit[22]=0
     43         //bit[5-2]=0101=16BPP (R5 G6 B5)
     44         //bit[10-9]=00 = DMA's Burst Max len 16word
     45         //bit[13] = 0 = input color space RGB
     46         //bit[16] = 1 = half wrod swap enabel
     47         //bit[20] = 1 = select buf 1
     48         writel(s3cfb_fimd.wincon0, S3C_WINCON0);
     49 
     50         //vidcon0=0x350=0011 0101 0000 
     51         //bit[3-2]=00 = VideoClock source = HCLK
     52         //bit[4]=1=video clock Divided by CLKVAL_F
     53         //bit[13-6]=00 1101 = 13   HCLK/CLKVAL_F=133/13=10.230769231M
     54         writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);
     55 
     56         //vidcon1=0x60 = 0110 0000
     57         //bit[4]= VDEN polarity noraml
     58         //bit[5]=VSYNC polarity inverted
     59         //bit[6]=HSYNC polarity inverted
     60         //bit[7]=gets the video data at vclk falling
     61         writel(s3cfb_fimd.vidcon1, S3C_VIDCON1);
     62 
     63         //vidtcon0=0x10109
     64         //VBPDE[31-24]= 0x0
     65         //VBPD[23-16]= 0x01
     66         //VFPD[15-8]= 0x01
     67         //VSPW[7-0]= 0x09
     68         writel(s3cfb_fimd.vidtcon0, S3C_VIDTCON0);
     69 
     70         //vidtcon1=0x10128
     71         //VFPDE[31-24]=0x0
     72         //HBPD[23-16]=0x01
     73         //HFPD[15-8]=0x01
     74         //HSPW[7-0]= 0x28=40
     75         writel(s3cfb_fimd.vidtcon1, S3C_VIDTCON1);
     76 
     77         //vidtcon2=0x879df
     78         //LINEVAL[21-11]=(Vertical display size)–1=10F=271
     79         //HOZVAL[10-0] = (Horizontal display size)-1=1DF=479
     80         writel(s3cfb_fimd.vidtcon2, S3C_VIDTCON2);
     81 
     82         //dithmode=0x0
     83         //禁用dither 
     84         writel(s3cfb_fimd.dithmode, S3C_DITHMODE);
     85 
     86         //vidintcon0=0x9021=0x1001 0000 0010 0001
     87         //bit[0]=Video Interrupt Enable
     88         //bit[1]=FIFO disable
     89         //bit[4-2]=FIFO int level =25
     90         //bit[11-5]=FIFO int -->win 0 control enable
     91         //bit[12]=video Frame interrupt enable
     92         //bit[14-13]=video frame int 1 start of None
     93         //bit[16-15]=video frame int 0 start of VSYNC
     94         writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
     95 
     96         //vidintcon1=0x0
     97         //没看出什么用
     98         writel(s3cfb_fimd.vidintcon1, S3C_VIDINTCON1);
     99 
    100         //vidosd0a=0x0
    101         //window_0左上角坐标(0,0)
    102         writel(s3cfb_fimd.vidosd0a, S3C_VIDOSD0A);
    103 
    104         //vidosd0b=0xef90f
    105         //window_0右下角的坐标是(479,271)
    106         writel(s3cfb_fimd.vidosd0b, S3C_VIDOSD0B);
    107 
    108         //vidosd0c=0x0
    109         //bit[23-0]=Window Size = 竟然为0?
    110         writel(s3cfb_fimd.vidosd0c, S3C_VIDOSD0C);
    111 
    112         //wpalcon=0x6
    113         //
    114         //
    115         //
    116         writel(s3cfb_fimd.wpalcon, S3C_WPALCON);
    117 
    118         //        
    119         s3cfb_onoff_win(fbi, ON);
    120         break;
    121     case 1-4:
    122         类推,省略.
    123         break;    
    124     }
    125 
    126     local_irq_restore(flags);            //开中断,并恢复,于上面的local_irq_save正好相反
    127 
    128     return 0;
    129  }

    6. 规定范围 

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

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

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

    在driver/video/fbcmap.c中

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

    上层执行fb_set_par 
         -->  s3cfb_set_par

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

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

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

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

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

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

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

  • 相关阅读:
    Time Zone 【模拟时区转换】(HDU暑假2018多校第一场)
    HDU 1281 棋盘游戏 【二分图最大匹配】
    Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】
    Codeforces Round #527 (Div. 3) D2. Great Vova Wall (Version 2) 【思维】
    Codeforces Round #527 (Div. 3) D1. Great Vova Wall (Version 1) 【思维】
    Codeforces Round #528 (Div. 2, based on Technocup 2019 Elimination Round 4) C. Connect Three 【模拟】
    Avito Cool Challenge 2018 E. Missing Numbers 【枚举】
    Avito Cool Challenge 2018 C. Colorful Bricks 【排列组合】
    005 如何分析问题框架
    004 如何定义和澄清问题
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5590847.html
Copyright © 2011-2022 走看看