三星SOC的显示控制器及framebuffer驱动s3c-fb.c中probe函数分析

三星SOC芯片上集成了显示控制器(有称作fimd的,Fully Interactive Mobile Display)。它的驱动分为mainline版本的和legacy版本的,mainline版本的是通用的,由Ben Dooks <ben@simtec.co.uk> 管理着的,代码比较规范。下面我们来分析一下这个驱动,这个驱动在driver/video/里,文件名是s3c-fb.c 与其相关的,主要还有arch/arm/plat-s5p/dev-fimd0.carch/arm/mach-XXXX/setup-fimd0.c 。 前者是定义platform device的,后者是定义一些比较depend on 具体芯片的东西,例如GPIO。

 

       我们这里主要分析s3c-fb.c中的probe函数, probe函数里最重要的是s3c_fb_probe_win函数,一会也一并分析。

       首先解释一个概念,很多书中有framebuffer这个概念,但是在三星的显示控制器文档或代码中,常出现win或window的概念,显示控制器可以控制0~5个windows,代码中分给它们分别编号win0, win1,win2......这里一张win或window就对应一个framebuffer, 每个framebuffer有自己的一个FBI(fb_info)结构。

      代码中, 显示控制器是s3c_fb结构体, window是s3c_fb_win结构体。

      代码中有两种data,一种是platform data(在板文件中定义),另一种是driver data(在驱动文件中定义),在它们各自的结构体里面,又可以分为两部份,一是用于sfb的data, 另一是用于win的data。

      framebuffer是fb_info结构体,里面主要存储设置参数的数据结构有两个,fb_var_screeninfo和fb_fix_screeninfo结构体。

 

 ************************************************ platform data***************************************************

[cpp]  view plain copy
  1. static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {  
  2.  .win[0]  = &smdkv210_fb_win0,                  -------->用于win的部分,下文称作“platform data中win的部分”  
  3.  .vidcon0  = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,      -------->下面开始是sfb的部分,  
  4.  .vidcon1  = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,  
  5.  .setup_gpio  = s5pv210_fb_gpio_setup_24bpp,  
  6.  };  


************************************************ driver data***************************************************

[cpp]  view plain copy
  1. static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {  
  2.  .variant = {                                             ---------->用于sfb的driverdata  
  3.  .nr_windows  = 5,  
  4.  .vidtcon  = VIDTCON0,  
  5.  .wincon  = WINCON(0),  
  6.  .winmap  = WINxMAP(0),  
  7.  .keycon  = WKEYCON,  
  8.  .osd  = VIDOSD_BASE,  
  9.  .osd_stride  = 16,  
  10.  .buf_start  = VIDW_BUF_START(0),  
  11.  .buf_size  = VIDW_BUF_SIZE(0),  
  12.  .buf_end  = VIDW_BUF_END(0),  
  13.    
  14.   
  15.  .palette = {  
  16.  [0] = 0x2400,  
  17.  [1] = 0x2800,  
  18.  [2] = 0x2c00,  
  19.  [3] = 0x3000,  
  20.  [4] = 0x3400,  
  21.  },  
  22.    
  23.   
  24.  .has_shadowcon= 1,  
  25.  .has_blendcon  = 1,  
  26.  .has_alphacon  = 1,  
  27.  .has_clksel  = 1,  
  28.  .has_fixvclk  = 1,  
  29.  },  
  30.  .win[0]  = &s3c_fb_data_s5p_wins[0],      ---------->用于各个win的部分,下文称作“driver data中win的部份”  
  31.  .win[1]  = &s3c_fb_data_s5p_wins[1],  
  32.  .win[2]  = &s3c_fb_data_s5p_wins[2],  
  33.  .win[3]  = &s3c_fb_data_s5p_wins[3],  
  34.  .win[4]  = &s3c_fb_data_s5p_wins[4],  
  35.  };  


************************************************ s3c_fb_probe() ***************************************************

[cpp]  view plain copy
  1. static int __devinit s3c_fb_probe(struct platform_device *pdev)  
  2.  {  
  3.  const struct platform_device_id *platid;                    -------> 因为一个驱动要适合很多版本的设备,每个版本的设备的设置 参数都不一样,所以要用到platid来选择哪个版本的设备,像“s5pv210-fb”, "s3c2443-fb"..., 这些就是platid(也在s3c-fb.c中定义了), 也表明了,这个驱动能适合于这些设备。  
  4.  struct s3c_fb_driverdata *fbdrv;                         ----> driver data  
  5.  struct device *dev = &pdev->dev;  
  6.  struct s3c_fb_platdata *pd;                             ----> platform data  
  7.  struct s3c_fb *sfb;                                   -----> 一个最重要的数据结据, 它代表了一个显示控制器,显示控制器的所有东东都放在这里了。但这里把它做成一个局部变量了。  
  8.  struct resource *res;                              -----> 资源  
  9.  int win;  
  10.  int default_win;  
  11.  ...  
  12.    
  13.  platid = platform_get_device_id(pdev);  ----> 从platform device 里 的id_entry 变量中获取platid,由一个宏实现  
  14.    
  15.  fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;    ---> 获取platid对应的driver data,driver data在s3c-fb.c中定义,主要是一定设置参数  
  16.    
  17. ...  
  18.    
  19.  pd = pdev->dev.platform_data;  --> 获取platform data,它在板文件中定义,这个data里包含了关于显示控制器的数据,也包含了win的数据。  
  20.    
  21.   
  22. ...  
  23.    
  24.  sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);         ------> 给这个最重要的结构分配内存空间  
  25.    
  26.   
  27. ...  
  28.    
  29.  sfb->dev = dev;                      ---> 向sfb 填入 显示控制器的 device 结构体  
  30.  sfb->pdata = pd;                   ---> 向sfb 填入 显示控制器的 platform data 结构体  
  31.  sfb->variant = fbdrv->variant;      ---> driver data结构体里 有 variant成员, 具体variant可以看下面s3c_fb_variant结构。  
  32.    
  33.   
  34. ...  
  35.    
  36. sfb->bus_clk = clk_get(dev, "lcd"); -->用"lcd"这个名字,去clock文件中找到自己的bus clock  
  37.    
  38. ...  
  39.    
  40. clk_enable(sfb->bus_clk); ---> bus clock有什么用,我还不太清楚  
  41.   
  42.    
  43. ...  
  44.    
  45. if (!sfb->variant.has_clksel) {  
  46. sfb->lcd_clk = clk_get(dev, "sclk_fimd"); --> 如果driver data里没定义 源时钟, 就用“sclk_fimd”此名字去clock文件找到自己的源时钟  
  47.    
  48. ...  
  49.    
  50. clk_enable(sfb->lcd_clk);  
  51.    
  52. ....  
  53.    
  54. res = platform_get_resource(pdev, IORESOURCE_MEM, 0); --> 获取资源的物理起始地址,终地址,大小,类型等,放在res结构中。实际上是寄存器们的物理起,终地址。  
  55.   
  56.    
  57. ...  
  58.    
  59. sfb->regs_res = request_mem_region(res->start, resource_size(res), dev_name(dev)); ---> 分配内存  
  60.    
  61. ...  
  62.    
  63. sfb->regs = ioremap(res->start, resource_size(res)); ----> 内存映射, 将寄存器的访问地址映射到刚才分配的内存上, sfb->regs为起始地址。  
  64.    
  65. ... // 中断的请求略  
  66.    
  67. platform_set_drvdata(pdev, sfb); ---> 将sfb 填入pdev->dev->p->driverdata 结构体中  
  68.  ...  
  69.    
  70. pd->setup_gpio();                      --> 执行setup_gpio函数,此函数在上面说的 setup_fimd0.c 中定义了。用来配置GPIO端口给FIMD使用。  
  71.    
  72.   
  73. ...  
  74.    
  75. writel(pd->vidcon1, sfb->regs + VIDCON1);             -->设置VIDCON1 寄存器  
  76.    
  77.   
  78. /* set video clock running at under-run */       
  79.  if (sfb->variant.has_fixvclk) {                                  --> run vclk  
  80.  reg = readl(sfb->regs + VIDCON1);  
  81.  reg &= ~VIDCON1_VCLK_MASK;  
  82.  reg |= VIDCON1_VCLK_RUN;  
  83.  writel(reg, sfb->regs + VIDCON1);  
  84.  }  
  85.    
  86.   
  87.   
  88.   
  89.   
  90.  for (win = 0; win < fbdrv->variant.nr_windows; win++)  
  91.  s3c_fb_clear_win(sfb, win);                                      ---> 将各个window的wincon寄存器清0,VIDOSDxA, VIDOSDxB, VIDOSDxC清0,禁止update各个window的shadow  
  92.    
  93.   
  94. /* initialise colour key controls */  
  95.    
  96.  for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {  
  97.    
  98.  void __iomem *regs = sfb->regs + sfb->variant.keycon;  
  99.  regs += (win * 8);  
  100.  writel(0xffffff, regs + WKEYCON0);  
  101.  writel(0xffffff, regs + WKEYCON1);  
  102.  }  
  103.    
  104.   
  105. /* we have the register setup, start allocating framebuffers */  
  106. default_win = sfb->pdata->default_win;              ---> platform data 在板文件中定义了  
  107.    
  108. for (i = 0; i < fbdrv->variant.nr_windows; i++) {  
  109.  win = i;  
  110.  if (i == 0)  
  111.  win = default_win;  
  112.  if (i == default_win)  
  113.  win = 0;  
  114.    
  115. if (!pd->win[win])  
  116.  continue;  
  117.    
  118. if (!pd->win[win]->win_mode.pixclock)-----> 像素时钟  
  119.  s3c_fb_missing_pixclock(&pd->win[win]->win_mode);----->如果像素时钟没预先定义,则由预先设定的刷新率和LCD参数来计算像素时钟  
  120.    
  121. ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], &sfb->windows[win]);       ----->分配 及 注册framebuffer的重要函数,下面会详细说  
  122.  if (ret < 0) {  
  123.  dev_err(dev, "failed to create window %d\n", win);  
  124.  for (; win >= 0; win--)  
  125.  s3c_fb_release_win(sfb, sfb->windows[win]);                     ----> 注册不成功的话就释放之前注册成功过的window  
  126.  goto err_irq;  
  127.  }  
  128.  }  
  129.    
  130.   
  131. }  
  132.    
  133. ...  
  134.    
  135. platform_set_drvdata(pdev, sfb);---> 再一次将sfb 填入pdev->dev->p->driverdata 结构体中,之前曾经这样操作过一次,现在再来一次,是因为sfb里的数据更新了很多  
  136.         ...  
  137.    
  138. #ifdef CONFIG_HAS_EARLYSUSPEND--> 如果有定义earlysuspend的话, 则注册early suspend函数  
  139. sfb->early_suspend.suspend = s3c_fb_early_suspend;  
  140. sfb->early_suspend.resume = s3c_fb_late_resume;  
  141. sfb->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;  
  142. register_early_suspend(&sfb->early_suspend);  
  143. #endif  
  144. return 0;  
  145.   ...  
  146.    
  147. 还有一些错训处理在此略过  
  148.    
  149. }  ---- > probe函数完成  


************************************************ s3c_fb_probe_win() *************************************************************

[cpp]  view plain copy
  1. static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,           --->将显示控制器的结构体作为参数传进来,它有寄存器起始地址等丰富信息;还将win的号码也作为参数传进来  
  2.       struct s3c_fb_win_variant *variant,            ----> driver data中win的部份, 它是由fbdrv->win[win]作参数传过来的。  
  3.       struct s3c_fb_win **res)       ---> per window private data for each framebuffer,它里面含有指向FBI(fb_info)结构体的针指  
  4.  {  
  5.  struct fb_var_screeninfo *var;  
  6.  struct fb_videomode *initmode;  
  7.  struct s3c_fb_pd_win *windata;    -->per window setup data,  也就是platform data中win的部份  
  8.  struct s3c_fb_win *win;  
  9.  struct fb_info *fbinfo;  
  10.  int palette_size;  
  11.  int ret;  
  12.    
  13.   
  14. init_waitqueue_head(&sfb->vsync_info.wait);  ---> 初始化等待队列头  
  15.    
  16. palette_size = variant->palette_sz * 4;         ---> 调色板大小 , 这方面内容我还不了解,为什么乘以4?  
  17.    
  18.   
  19. fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +  palette_size * sizeof(u32), sfb->dev);   ---> 重头戏来了, 分配fb_info结构体,返回一个fb_info结构体地址,这个结构体现在没什么内容,只赋值了par(win的起始地址)和device (父设备)两个变量,  
  20.    
  21. windata = sfb->pdata->win[win_no];         --->windata指向 platform data中win的部份   
  22. initmode = &windata->win_mode;  
  23.    
  24. ...  
  25.    
  26. win = fbinfo->par;  
  27. *res = win;         --->par就是win的起始地址,现在把起始地址给*res,那么*res就是指向s3c_fb_win的指针   
  28. var = &fbinfo->var;         ---> 现在fbinfo->var还是空的, 只是将地址给var而已   
  29. win->variant = *variant;         --->将win的参数填进win->variant里   
  30. win->fbinfo = fbinfo;         ---让win->fbinfo指向这个FBI结构实体   
  31. win->parent = sfb;         ---win的parent是显示控制器,所以它指向sfb结构体>   
  32. win->windata = windata;        --->让win->windata指向 platform data中win的部分   
  33. win->index = win_no;   
  34.         
  35. win->palette_buffer = (u32 *)(win + 1);       --->这个也不太理解?  
  36.    
  37. ret = s3c_fb_alloc_memory(sfb, win);    ----> 下面详解  
  38.    
  39. ...  
  40.    
  41. /* setup the r/b/g positions for the window's palette */                --->设置调色板, 未理解  
  42.  if (win->variant.palette_16bpp) {  
  43.  /* Set RGB 5:6:5 as default */  
  44.  win->palette.r.offset = 11;  
  45.  win->palette.r.length = 5;  
  46.  win->palette.g.offset = 5;  
  47.  win->palette.g.length = 6;  
  48.  win->palette.b.offset = 0;  
  49.  win->palette.b.length = 5;  
  50.    
  51.   
  52. else {  
  53.  /* Set 8bpp or 8bpp and 1bit alpha */  
  54.  win->palette.r.offset = 16;  
  55.  win->palette.r.length = 8;  
  56.  win->palette.g.offset = 8;  
  57.  win->palette.g.length = 8;  
  58.  win->palette.b.offset = 0;  
  59.  win->palette.b.length = 8;  
  60.  }  
  61.    
  62.   
  63. /* setup the initial video mode from the window */  
  64.  fb_videomode_to_var(&fbinfo->var, initmode);      --> 给FBI填上各个参数,此函数详见appendix  
  65.    
  66. fbinfo->fix.type   
  67. = FB_TYPE_PACKED_PIXELS;  
  68. fbinfo->fix.accel= FB_ACCEL_NONE;  
  69. fbinfo->var.activate= FB_ACTIVATE_NOW;  
  70. fbinfo->var.vmode= FB_VMODE_NONINTERLACED;  
  71. fbinfo->var.bits_per_pixel = windata->default_bpp;  
  72. fbinfo->var.width= windata->width;  
  73. fbinfo->var.height= windata->height;  
  74. fbinfo->fbops   
  75. = &s3c_fb_ops;    ---->对framebuffer的操作, 详见appendix  
  76. fbinfo->flags   
  77. = FBINFO_FLAG_DEFAULT;  
  78. fbinfo->pseudo_palette  = &win->pseudo_palette;   
  79.    
  80. /* prepare to actually start the framebuffer */  
  81.  ret = s3c_fb_check_var(&fbinfo->var, fbinfo);    -->检查可变参数 Framebuffer layer call to verify the given information and allow us to update various information depending on the hardware capabilities.  
  82.    
  83.   
  84. ...  
  85.    
  86. ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);  
  87.    
  88. if (ret == 0)  
  89.  fb_set_cmap(&fbinfo->cmap, fbinfo);  
  90.  else  
  91.  dev_err(sfb->dev, "failed to allocate fb cmap\n");  
  92.    
  93.   
  94. s3c_fb_set_par(fbinfo);  
  95.    
  96. ...  
  97.    
  98. ret = register_framebuffer(fbinfo);  
  99.    
  100. ...  
  101.    
  102. return 0;  
  103.    
  104. } s3c_fb_probe_win结束  

************************************************ s3c_fb_alloc_memory() ************************************************

[cpp]  view plain copy
  1. static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,  
  2.  struct s3c_fb_win *win)  
  3.  {  
  4.  struct s3c_fb_pd_win *windata = win->windata;  ---> platform data中win的部分  
  5.  unsigned int real_size, virt_size, size;  
  6.  struct fb_info *fbi = win->fbinfo;     ---> 让fbi指向FBI结构体  
  7.    
  8. dma_addr_t map_dma;  
  9.    
  10.   
  11.      ...  
  12.    
  13. real_size = windata->win_mode.xres * windata->win_mode.yres;  
  14. virt_size = windata->virtual_x * windata->virtual_y;    ---> 虚拟size  
  15.    
  16. size = (real_size > virt_size) ? real_size : virt_size; 一张framebuffer的大小,是按虚拟分辨率和实际分辨率两者中较大的来算的  
  17. size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;  
  18. size /= 8;   
  19.    
  20. fbi->fix.smem_len = size;-----> 要分配的内存大小,  
  21.  size = PAGE_ALIGN(size);    ---- 页对齐  
  22.    
  23.   
  24. ... 关于CMA 与ION部分省略  
  25.    
  26. fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,  &map_dma, GFP_KERNEL);   -->分配framebuffer的内存  
  27.    
  28. memset(fbi->screen_base, 0x0, size);    -->将framebuffer的内存清空为0  
  29.  fbi->fix.smem_start = map_dma;  
  30.  return 0;  
  31.    
  32.   
  33. }  ---->结束  

*********************************************************Appendix******************************************************

[cpp]  view plain copy
  1. struct s3c_fb_variant {  
  2.  unsigned int  is_2443:1;  
  3.  unsigned shortnr_windows;  
  4.  unsigned int  vidtcon;  
  5.  unsigned shortwincon;  
  6.  unsigned shortwinmap;  
  7.  unsigned shortkeycon;  
  8.  unsigned shortbuf_start;  
  9.  unsigned shortbuf_end;  
  10.  unsigned shortbuf_size;  
  11.  unsigned shortosd;  
  12.  unsigned shortosd_stride;  
  13.  unsigned shortpalette[S3C_FB_MAX_WIN];  
  14.    
  15.   
  16. unsigned int  has_prtcon:1;  
  17.  unsigned int  has_shadowcon:1;  
  18.  unsigned int  has_blendcon:1;  
  19.  unsigned int  has_alphacon:1;  
  20.  unsigned int  has_clksel:1;  
  21.  unsigned int  has_fixvclk:1;  
  22.    
  23.   
  24. }  
  25.    
  26.   
  27.   
  28.   
  29. /** 
  30.   * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo 
  31.   * @var: pointer to struct fb_var_screeninfo 
  32.   * @mode: pointer to struct fb_videomode 
  33.   */  
  34.  void fb_videomode_to_var(struct fb_var_screeninfo *var,  
  35.  const struct fb_videomode *mode)  
  36.  {  
  37.  var->xres = mode->xres;  
  38.  var->yres = mode->yres;  
  39.  var->xres_virtual = mode->xres;  
  40.  var->yres_virtual = mode->yres;  
  41.  var->xoffset = 0;  
  42.  var->yoffset = 0;  
  43.  var->pixclock = mode->pixclock;  
  44.  var->left_margin = mode->left_margin;  
  45.  var->right_margin = mode->right_margin;  
  46.  var->upper_margin = mode->upper_margin;  
  47.  var->lower_margin = mode->lower_margin;  
  48.  var->hsync_len = mode->hsync_len;  
  49.  var->vsync_len = mode->vsync_len;  
  50.  var->sync = mode->sync;  
  51.  var->vmode = mode->vmode & FB_VMODE_MASK;  
  52.  }  
  53.    
  54.   
  55.   
  56.   
  57.   
  58. static struct fb_ops s3c_fb_ops = {  
  59.  .owner  = THIS_MODULE,  
  60.  .fb_open  = s3c_fb_open,  
  61.  .fb_release  = s3c_fb_release,  
  62.  .fb_check_var  = s3c_fb_check_var,  
  63.  .fb_set_par  = s3c_fb_set_par,  
  64.  .fb_blank  = s3c_fb_blank,  
  65.  .fb_setcolreg  = s3c_fb_setcolreg,  
  66.  .fb_fillrect  = cfb_fillrect,  
  67.  .fb_copyarea  = cfb_copyarea,  
  68.  .fb_imageblit  = cfb_imageblit,  
  69.  .fb_pan_display= s3c_fb_pan_display,  
  70.  .fb_ioctl  = s3c_fb_ioctl,  
  71.  };  
  72.    
  73.   
  74.   
  75.   
  76.   
  77. /** 
  78.   * struct s3c_fb_win - per window private data for each framebuffer. 
  79.   * @windata: The platform data supplied for the window configuration. 
  80.   * @parent: The hardware that this window is part of. 
  81.   * @fbinfo: Pointer pack to the framebuffer info for this window. 
  82.   * @varint: The variant information for this window. 
  83.   * @palette_buffer: Buffer/cache to hold palette entries. 
  84.   * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/ 
  85.   * @index: The window number of this window. 
  86.   * @palette: The bitfields for changing r/g/b into a hardware palette entry. 
  87.   */  
  88.  struct s3c_fb_win {  
  89.  struct s3c_fb_pd_win*windata;  
  90.  struct s3c_fb  *parent;  
  91.  struct fb_info*fbinfo;  
  92.  struct s3c_fb_palettepalette;  
  93.  struct s3c_fb_win_variant variant;  
  94.    
  95.   
  96. u32  *palette_buffer;  
  97.  u32  pseudo_palette[16];  
  98.  unsigned int  index;  
  99.  #ifdef CONFIG_ION_EXYNOS  
  100.  struct ion_handle *fb_ion_handle;  
  101.  #endif  
  102.  };  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值