OK6410內核驅動分析(轉)

来源:http://www.cnblogs.com/chd-zhangbo/archive/2016/02/04/5182364.html
-Advertisement-
Play Games

一. 理論分析1. 幾個概念:FIMC : Fully Interactive Mobile Camera (完全互動式移動攝像機)FIMD: Fully Interactive Mobile Display (完全互動式移動顯示設備)2. 設置VCLK在VIDCON0中bit[3:2]-->Sel


一. 理論分析
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. struct platform_device s3c_device_fb = {
  24.     .name         = "s3c-fb",
  25.     .id         = -1,
  26.     .num_resources     = ARRAY_SIZE(s3c_fb_resource),
  27.     .resource     = s3c_fb_resource,
  28.     .dev.dma_mask     = &s3c_device_fb.dev.coherent_dma_mask,
  29.     .dev.coherent_dma_mask = 0xffffffffUL,
  30. };

然後在驅動的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.     char driver_name[] = "s3cfb";
  7.     int index = 0, ret, size;
  8.     //分配sizeof(fb_info+私有成員)大小的記憶體,使par指向s3cfb_info_t結構體
  9.     fbinfo = framebuffer_alloc(sizeof(s3cfb_info_t), &pdev->dev);   
  10.     platform_set_drvdata(pdev, fbinfo);
  11.     info = fbinfo->par;                //私有數據是一個結構體s3cfb_info_t
  12.     info->dev = &pdev->dev;
  13.     
  14.     //獲取LCD的io埠,並映射
  15.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  16.     size = (res->end - res->start) + 1;
  17.     info->mem = request_mem_region(res->start, size, pdev->name);
  18.     info->io = ioremap(res->start, size);
  19.     s3cfb_pre_init();                                 //2.使能中斷寄存器,s3cfb_fimd的第一次初始化
  20.     s3cfb_set_backlight_power(1);                     //設置backlight_power = 1;
  21.     s3cfb_set_lcd_power(1);                           //設置lcd_power = 1;
  22.     s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL); //設置backlight_level = 2;
  23.     
  24.     //獲取時鐘,並使能
  25.     info->clk = clk_get(NULL, "lcd");     //133.000Mhz,使用的是HCLK
  26.     clk_enable(info->clk);
  27.     s3cfb_fimd.vsync_info.count = 0;
  28.     init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue);
  29.     
  30.     //申請中斷
  31.     res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  32.     ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev);
  33.     msleep(5);
  34.     //對4個framebuffer分別初始化
  35.     for (index = 0; index < S3CFB_NUM; index++) {
  36.         s3cfb_info[index].mem = info->mem;
  37.         s3cfb_info[index].io = info->io;
  38.         s3cfb_info[index].clk = info->clk;
  39.         s3cfb_init_fbinfo(&s3cfb_info[index], driver_name, index);  //3.初始化fbinfo
  40.         ret = s3cfb_map_video_memory(&s3cfb_info[index]);           //4.分配dma記憶體 
  41.         ret = s3cfb_init_registers(&s3cfb_info[index]);            //5.寫寄存器
  42.         ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb);  //6.設置var範圍
  43.         if (index < 2){
  44.             if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0)     //7.color map
  45.                 goto dealloc_fb;
  46.         } else {
  47.             if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
  48.                 goto dealloc_fb;
  49.         }
  50.         ret = register_framebuffer(&s3cfb_info[index].fb);                 //8.註冊framebuffer
  51.     }
  52.     ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);
  53.     ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);
  54.     ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);
  55.     return 0;
  56. }



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.     struct fb_info * info = (struct fb_info *) p;
  6.     info->par = p + fb_info_size;     //par指向私有數據
  7.     info->device = dev;
  8.     return info;                      //返回申請記憶體的首指針
  9. }


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
        writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
  10. }

在driver/vidoe/samsun/s3cfb.c中

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


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.     finfo->fb.fbops = &s3cfb_ops;                //fb操作函數
  19.     finfo->fb.flags    = FBINFO_FLAG_DEFAULT;
  20.     finfo->fb.pseudo_palette = &finfo->pseudo_pal;
  21.     finfo->fb.var.nonstd = 0;
  22.     finfo->fb.var.activate = FB_ACTIVATE_NOW;
  23.     finfo->fb.var.accel_flags = 0;
  24.     finfo->fb.var.vmode = FB_VMODE_NONINTERLACED;
  25.     finfo->fb.var.xoffset = s3cfb_fimd.xoffset;     //xoffset=0 
  26.     finfo->fb.var.yoffset = s3cfb_fimd.yoffset;     //yoffset=0
  27.     if (index == 0) {
  28.         finfo->fb.var.height = s3cfb_fimd.height;   //height=272
  29.         finfo->fb.var.width = s3cfb_fimd.width;     //width=480
  30.         finfo->fb.var.xres = s3cfb_fimd.xres;       //xres=480
  31.         finfo->fb.var.yres = s3cfb_fimd.yres;       //yres=272
  32.         finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual;  //xres_virtual=480
  33.         finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual;  //yres_virtual=544
  34.     } else {
  35.         finfo->fb.var.height = s3cfb_fimd.osd_height;      //osd_height=272
  36.         finfo->fb.var.width = s3cfb_fimd.osd_width;        //osd_height=480
  37.         finfo->fb.var.xres = s3cfb_fimd.osd_xres;         //osd_xres=480   
  38.         finfo->fb.var.yres = s3cfb_fimd.osd_yres;         //osd_yres=272
  39.         finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual;     //osd_xres_virtual=480
  40.         finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual;     //osd_yres_virtaul=272
  41.     }  
  42.     finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp;               //16
  43.     finfo->fb.var.pixclock = s3cfb_fimd.pixclock;                //9009000
  44.     finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len;              //41
  45.     finfo->fb.var.left_margin = s3cfb_fimd.left_margin;          //2
  46.     finfo->fb.var.right_margin = s3cfb_fimd.right_margin;        //2
  47.     finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len;              //10 
  48.     finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin;        //2
  49.     finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin;        //2
  50.     finfo->fb.var.sync = s3cfb_fimd.sync;                        //0
  51.     finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale;         //0
  52.     //480*544*2=522240
  53.     finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;
  54.     finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel;    //480*2=960
  55.     for (i = 0; i < 256; i++)
  56.         finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR;       //(0x80000000)
  57. }


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.     s3cfb_fimd.width = S3CFB_HRES;                 //480
  34.     s3cfb_fimd.height = S3CFB_VRES;                //272
  35.     s3cfb_fimd.xres = S3CFB_HRES;                  //480
  36.     s3cfb_fimd.yres = S3CFB_VRES;                  //272
  37.     //定義了(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)
  38.     s3cfb_fimd.xres_virtual = S3CFB_HRES_VIRTUAL;  //如果定義了Virtual_screen則為480*544
  39.     s3cfb_fimd.yres_virtual = S3CFB_VRES_VIRTUAL;  //如果沒有定義Virtual_screen則為480*272
  40.     s3cfb_fimd.osd_width = S3CFB_HRES_OSD;         //480
  41.     s3cfb_fimd.osd_height = S3CFB_VRES_OSD;        //272
  42.     s3cfb_fimd.osd_xres = S3CFB_HRES_OSD;          //480  
  43.     s3cfb_fimd.osd_yres = S3CFB_VRES_OSD;          //272
  44.     s3cfb_fimd.osd_xres_virtual = S3CFB_HRES_OSD;    //480
  45.     s3cfb_fimd.osd_yres_virtual = S3CFB_VRES_OSD;    //272
  46.     s3cfb_fimd.pixclock = S3CFB_PIXEL_CLOCK;         //9009000
  47.     s3cfb_fimd.hsync_len = S3CFB_HSW;                //41
  48.     s3cfb_fimd.vsync_len = S3CFB_VSW;                //10
  49.     s3cfb_fimd.left_margin = S3CFB_HFP;              //2
  50.     s3cfb_fimd.upper_margin = S3CFB_VFP;             //2
  51.     s3cfb_fimd.right_margin = S3CFB_HBP;             //2
  52.     s3cfb_fimd.lower_margin = S3CFB_VBP;             //2
  53. }


小總結一下:
全局變數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.     //ok6410跟GPE0好像沒有什麼關係,這兒可以去掉
  22.     if (gpio_is_valid(S3C64XX_GPE(0))) {
  23.         err = gpio_request(S3C64XX_GPE(0), "GPE");
  24.         gpio_direction_output(S3C64XX_GPE(0), 1);
  25.     }
  26.     gpio_set_value(S3C64XX_GPE(0), 1);
  27.     gpio_free(S3C64XX_GPE(0));
  28.     gpio_free(S3C64XX_GPF(14));
  29.     return 0;
  30. }


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.     if (fbi->map_cpu_f1) {                                  //map_cpu_f1是將dma映射到虛擬記憶體空間的地址
  9.         memset(fbi->map_cpu_f1, 0xf0, fbi->map_size_f1);    //初始化成0xf0?這兒為什麼不是0?
  10.         fbi->screen_dma_f1 = fbi->map_dma_f1;
  11.         fbi->fb.screen_base = fbi->map_cpu_f1;
  12.         fbi->fb.fix.smem_start = fbi->screen_dma_f1;
  13.     }
  14.     //下麵的指針指向第二個 buffer
  15. #if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)
  16.     if (fbi->win_id<2 && fbi->map_cpu_f1) {
  17.         fbi->map_size_f2 = (fbi->fb.fix.smem_len / 2);
  18.         fbi->map_cpu_f2 = fbi->map_cpu_f1 + fbi->map_size_f2;
  19.         fbi->map_dma_f2 = fbi->map_dma_f1 + fbi->map_size_f2;
  20.         fbi->screen_dma_f2 = fbi->map_dma_f2;
  21.     }
  22. #endif
  23.     return 0;
  24. }

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



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.     if (cmap->len != len) {
  5.         fb_dealloc_cmap(cmap);               //把以前申請的rgb記憶體kfree掉
  6.         cmap->red = kmalloc(size, flags);    //重新分配記憶體,GFP_ATOMIC
  7.         cmap->green = kmalloc(size, flags);  //重新分配記憶體,GFP_ATOMIC
  8.         cmap->blue = kmalloc(size, flags);   //重新分配記憶體,GFP_ATOMIC
  9.         if (transp) {
  10.             cmap->transp = kmalloc(size, flags);
  11.         } else {
  12.             cmap->transp = NULL;             //transp設為NULL
  13.         }
  14.     }
  15.     cmap->start = 0;
  16.     cmap->len = len;
  17.     ret = fb_copy_cmap(fb_default_cmap(len), cmap);  //把default的cmap複製到新分配的cmap中
  18.     return 0;
  19. }




上層執行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.     s3cfb_fimd.vsync_info.count++;
  5.     wake_up_interruptible(&s3cfb_fimd.vsync_info.wait_queue);  //喚醒工作隊列
  6.     return IRQ_HANDLED;
  7. }

這個地方正在等侍工作隊列,收到喚醒信號之後,就返回

  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.         return s3cfb_wait_for_vsync();
  8.     }
  9. }






附錄:
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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近公司資料庫用到MongoDB,而之前只關註知道它是分散式非關係資料庫,數據以文檔的形式存儲,數據格式是類似json的bson格式.而對於具體用法以及java如何調用並沒有過多接觸,今天花費一天的時間瞭解了MongoDB在linux下的安裝以及基本的命令行調用. 1. Linux下安裝MongoD
  • 刪除mysql sudo apt-get autoremove --purge mysql-server-5.0 sudo apt-get remove mysql-server sudo apt-get autoremove mysql-server sudo apt-get remove mys
  • 在linux系統中,可以使用mount命令掛載光碟鏡像文件、移動硬碟、U盤以及Windows網路共用和UNIX NFS網路共用等 linux是一個優秀的開放源碼的操作系統,可以運行在大到巨型小到掌上型各類電腦系統上,隨著 linux系統的日漸成熟和穩定以及它開放源代碼特有的優越性,linux在全世
  • 1、安裝客戶端和伺服器端 確認mysql是否已安裝: ? 1 2 yum list installed mysql* rpm -qa | grep mysql* 查看是否有安裝包: ? 1 yum list mysql* 安裝mysql客戶端: ? 1 yum install mysql 安裝mys
  • 安裝好的CentOS會自帶OpenJdk,用命令 java -version ,會有下麵的信息: java version "1.6.0"OpenJDK Runtime Environment (build 1.6.0-b09)OpenJDK 64-Bit Server VM (build 1.6.
  • Linux下怎麼查看當前系統的版本: uname -r 功能說明:uname用來獲取電腦和操作系統的相關信息。 語 法:uname [-amnrsvpio][--help][--version] 補充說明:uname可顯示linux主機所用的操作系統的版本、硬體的名稱等基本信息。 參 數: -a或–
  • 我的環境:主機是win7的,虛擬機是VWare Workstation 6.0 ,linux系統為Red Hat Enterprise Linux 5 64位 各軟體版本:jdk是jdk-6u35-linux-x64.bin,tomcat是apache-tomcat-6.0.35.tar.gz,數據
  • #!/bin/bashDATE=`date +%Y-%m-%d-%H:%M -d -3minute`USER=rootPASSWORD=mayboBACKUP_DIR='/home/mysqlbak/'LOG_DIR='/home/mysqlbak/mysqlbak_log.log'DATABASE
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...