• 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

  • 相关阅读:
    程序性能优化1
    在archlinux上搭建twitter storm cluster
    .Net 跨平台可移植类库PCL可用于任何平台包括Mono
    .NET面向对象特性之封装
    哈夫曼(Huffman)编码
    高质量视频学习网站
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1071 潜伏者
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5590847.html
Copyright © 2020-2023  润新知