LCD驱动(linux-2.6.32.60)---------------平台驱动方面

来源:互联网 发布:u盘安装ubuntu一直黑屏 编辑:程序博客网 时间:2024/06/05 19:05

1048 static struct platform_driver s3c_fb_driver = {
1049     .probe      = s3c_fb_probe,//驱动的探测函数
1050     .remove     = __devexit_p(s3c_fb_remove),//remove函数
1051     .suspend    = s3c_fb_suspend,//挂起。。
1052     .resume     = s3c_fb_resume,//,,,,,
1053     .driver     = {
1054         .name   = "s3c-fb",//驱动名字
1055         .owner  = THIS_MODULE,//模块计数
1056     },
1057 };
1058
1059 static int __init s3c_fb_init(void)
1060 {
1061     return platform_driver_register(&s3c_fb_driver);//注册平台驱动
1062 }
1063
1064 static void __exit s3c_fb_cleanup(void)
1065 {
1066     platform_driver_unregister(&s3c_fb_driver);//注销平台驱动
1067 }
1068
1069 module_init(s3c_fb_init);
1070 module_exit(s3c_fb_cleanup);
1071
1072 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1073 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
1074 MODULE_LICENSE("GPL");
1075 MODULE_ALIAS("platform:s3c-fb");

-----------------------------------------------------

当前主要分析探测函数,不过还是有一些内容不懂。。。。。。

ctrl + ] (s3c_fb_driver)

先看几个结构体再进去吧!!!!

#######################################

设备结构体,内嵌在平台设备结构体中

379 struct device {
380     struct device       *parent;
381
382     struct device_private   *p;
383
384     struct kobject kobj;
385     const char      *init_name; /* initial name of the device */
386     struct device_type  *type;
387
388     struct semaphore    sem;    /* semaphore to synchronize calls to
389                      * its driver.
390                      */
391
392     struct bus_type *bus;       /* type of bus device is on */
393     struct device_driver *driver;   /* which driver has allocated this  
394                        device */
395     void        *platform_data; /* Platform specific data, device   <------ 关注,平台设备的私有成员,用于保存平台相关的数据,就是上一篇中的一个结构体
396                        core doesn't touch it */
397     struct dev_pm_info  power;
399 #ifdef CONFIG_NUMA
400     int     numa_node;  /* NUMA node this device is close to */
401 #endif
402     u64     *dma_mask;  /* dma mask (if dma'able device) */
403     u64     coherent_dma_mask;/* Like dma_mask, but for
404                          alloc_coherent mappings as
405                          not all hardware supports
406                          64 bit addresses for consistent
407                          allocations such descriptors. */
408
409     struct device_dma_parameters *dma_parms;
410
411     struct list_head    dma_pools;  /* dma pools (if dma'ble) */
412
413     struct dma_coherent_mem *dma_mem; /* internal for coherent mem
414                          override */
415     /* arch specific additions */
416     struct dev_archdata archdata;
417
418     dev_t           devt;   /* dev_t, creates the sysfs "dev" */
419
420     spinlock_t      devres_lock;
421     struct list_head    devres_head;
422
423     struct klist_node   knode_class;
424     struct class        *class;
425     const struct attribute_group **groups;  /* optional groups */
426
427     void    (*release)(struct device *dev);
428 };
------------------------------------------------------------------

LCD驱动的最核心的一个结构体,包揽了所有的内容,相当于一个总的目录,其它数据都间接或直接的与其关联

  74 /**
  75  * struct s3c_fb - overall hardware state of the hardware
  76  * @dev: The device that we bound to, for printing, etc.
  77  * @regs_res: The resource we claimed for the IO registers.
  78  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
  79  * @regs: The mapped hardware registers.
  80  * @enabled: A bitmask of enabled hardware windows.
  81  * @pdata: The platform configuration data passed with the device.
  82  * @windows: The hardware windows that have been claimed.
  83  */
  84 struct s3c_fb {
  85     struct device       *dev;//指向设备结构成员
  86     struct resource     *regs_res;//指向LCD所用到的资源结构成员
  87     struct clk      *bus_clk;//指向LCD时钟提供结构成员
  88     void __iomem        *regs;//物理地址映射后的地址(即虚拟地址)
  89
  90     unsigned char        enabled;//这个看英语注释吧,
  91
  92     struct s3c_fb_platdata  *pdata;//指向私有数据(设备)
  93     struct s3c_fb_win   *windows[S3C_FB_MAX_WIN];//表示窗口,有五个窗口,
  94 };
------------------------------------------------------------

struct s3c_fb_win xxx结构体:

  52
  53 /**
  54  * struct s3c_fb_win - per window private data for each framebuffer.
  55  * @windata: The platform data supplied for the window configuration.
  56  * @parent: The hardware that this window is part of.
  57  * @fbinfo: Pointer pack to the framebuffer info for this window.
  58  * @palette_buffer: Buffer/cache to hold palette entries.
  59  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
  60  * @index: The window number of this window.
  61  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
  62  */
  63 struct s3c_fb_win {
  64     struct s3c_fb_pd_win    *windata;//当前窗口的一些配置
  65     struct s3c_fb       *parent;//指向总目录
  66     struct fb_info      *fbinfo;//指向当前窗口的framebuffer
  67     struct s3c_fb_palette    palette;//这个不太了解,知道的回下
  68
  69     u32         *palette_buffer;
  70     u32          pseudo_palette[16];
  71     unsigned int         index;//对应窗口的索引
  72 };

 

 

#######################################

 

 859 static int __devinit s3c_fb_probe(struct platform_device *pdev)
 860 {
 861     struct device *dev = &pdev->dev;//从平台设备中获取设备结构体
 862     struct s3c_fb_platdata *pd;//用于保存私有数据
 863     //私有数据里面包含的主要是GPIO和寄存器的配置
 864     struct s3c_fb *sfb;//这个结构体相当于一个维护的总目录,其内部包含了所有的LCD需要的内容.
 865     struct resource *res;//资源结构指针
 866     int win;//窗口索引号
 867     int ret = 0;
 868
 869     pd = pdev->dev.platform_data;//设备的私有数据,
 870     if (!pd) {
 871         dev_err(dev, "no platform data specified\n");
 872         return -EINVAL;
 873     }
 874 

 875     sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);//给总目录分配空间,用于维护整个LCD系统.
 876     if (!sfb) {
 877         dev_err(dev, "no memory for framebuffers\n");
 878         return -ENOMEM;
 879     }
 880
 881     sfb->dev = dev;//给总目录成员dev赋值,就是平台设备结构体的成员设备结构体.
 882     sfb->pdata = pd;//给总目录成员pdata赋值,保存私有设备数据到总目录下.
 883
 884     sfb->bus_clk = clk_get(dev, "lcd");//获取时钟结构体.保存到总目录下

<----------------记住行号

######################################################

拓展:

        关于时钟的获取:

        时钟的处理主要在/arch/arm/plat-s3c64xx/clock.c中,

        时钟高速、低速分别维护 

 14 struct clk {
 15     struct list_head      list;
 16     struct module        *owner;
 17     struct clk           *parent;
 18     const char           *name;
 19     int           id;
 20     int           usage;
 21     unsigned long         rate;
 22     unsigned long         ctrlbit;
 23
 24     int         (*enable)(struct clk *, int enable);
 25     int         (*set_rate)(struct clk *c, unsigned long rate);
 26     unsigned long       (*get_rate)(struct clk *c);
 27     unsigned long       (*round_rate)(struct clk *c, unsigned long rate);
 28     int         (*set_parent)(struct clk *c, struct clk *parent);
 29 };

176 static struct clk init_clocks[] = {
177     {
178         .name       = "lcd",
179         .id     = -1,
180         .parent     = &clk_h,//属于高速设备
181         .enable     = s3c64xx_hclk_ctrl,
182         .ctrlbit    = S3C_CLKCON_HCLK_LCD,
183     }, {
184         .name       = "gpio",
185         .id     = -1,
186         .parent     = &clk_p,
187         .enable     = s3c64xx_pclk_ctrl,
188         .ctrlbit    = S3C_CLKCON_PCLK_GPIO,
189     }

            }

其它的不贴了。。。。。

######################################################

<==========接回行号
 885     if (IS_ERR(sfb->bus_clk)) {
 886         dev_err(dev, "failed to get bus clock\n");
 887         goto err_sfb;
 888     }
 889
 890     clk_enable(sfb->bus_clk);//使能时钟,实际上,默认时钟控制的引脚 

-----------------------------------------------------------------------------------

 892     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//通过资源结构体,获取物理地址资源.
 893     if (!res) {
 894         dev_err(dev, "failed to find registers\n");
 895         ret = -ENOENT;
 896         goto err_clk;
 897     }
 898
 899     sfb->regs_res = request_mem_region(res->start, resource_size(res),
 900                        dev_name(dev));
 901     //检测物理地址是不是申请重叠,重叠那么就代码OVER,
 902     //其实就是维护的一个链表,链表按照物理地址从低到高的顺序排列成一个一个的节点.

<----------------记住行号

######################################################

进入request_mem_region分析:

141 #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)

 32 struct resource iomem_resource = {
 33     .name   = "PCI mem",
 34     .start  = 0,
 35     .end    = -1,
 36     .flags  = IORESOURCE_MEM,
 37 };
 38 EXPORT_SYMBOL(iomem_resource);

 

------------------------------

http://wenku.baidu.com/view/7b46cc1114791711cc79175e.html

这个网址分析比较透彻!!!!!!!!

 /*
592  * This is compatibility stuff for IO resources.
593  *
594  * Note how this, unlike the above, knows about
595  * the IO flag meanings (busy etc).
596  *
597  * request_region creates a new busy region.
598  *
599  * check_region returns non-zero if the area is already busy.
600  *
601  * release_region releases a matching busy region.
602  */
603
604 /**
605  * __request_region - create a new busy resource region
606  * @parent: parent resource descriptor
607  * @start: resource start address
608  * @n: resource region size
609  * @name: reserving caller's ID string
610  * @flags: IO resource flags
611  */
612 struct resource * __request_region(struct resource *parent,
613                    resource_size_t start, resource_size_t n,
614                    const char *name, int flags)
615 {
616     struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);//给资源分配结构体,并初始化为0
617
618     if (!res)
619         return NULL;
620
621     res->name = name;//资源名字
622     res->start = start;//资源的开始地址
623     res->end = start + n - 1;//资源的结束地址
624     res->flags = IORESOURCE_BUSY;//资源状态
625     res->flags |= flags;//资源状态初始化,这里初始化为IORESOURCE_MEM
626
627     write_lock(&resource_lock);//这就不说了,知道一点点,不过忘记得更多一点(O n O )
628
629     for (;;) {
630         struct resource *conflict;
631
632         conflict = __request_resource(parent, res);
633         if (!conflict)//如果返回值为NULL,说明物理地址没有重叠,不冲突,安置好物理地址空间,并返回
634             break;
635         if (conflict != parent) {//如果不等于root说明地址有冲突
636             parent = conflict;//root指向返回的不为NULL,且不为root的指针成员
637             if (!(conflict->flags & IORESOURCE_BUSY))//如果资源不busy释放资源,反之continue
638                 continue;
639         }
640
641         /* Uhhuh, that didn't work out.. */
642         kfree(res);
643         res = NULL;
644         break;
645     }
646     write_unlock(&resource_lock);
647     return res;
648 }
649 EXPORT_SYMBOL(__request_region);
-------------------------------------------

143 /* Return the conflict entry if you can't request it */
144 static struct resource * __request_resource(struct resource *root, struct resource *new)
145 {
146     resource_size_t start = new->start;
147     resource_size_t end = new->end;
148     struct resource *tmp, **p;
149
150     if (end < start)//如果结束地址小于开始地址,显然有问题,返回
151         return root;
152     if (start < root->start)//如果开始地址小于root的开始地址,很显然也有问题,返回
153         return root;
154     if (end > root->end)//如果结束地址大于root的结束地址,更显然是问题,返回
155         return root;

//至此,问题去了一大半
156     p = &root->child;
157     for (;;) {
158         tmp = *p;
159         if (!tmp || tmp->start > end) {
160             new->sibling = tmp;
161             *p = new;
162             new->parent = root;
163             return NULL;
164         }
165         p = &tmp->sibling;
166         if (tmp->end < start)
167             continue;
168         return tmp;
169     }
170 }
这一段代码主要是检测地址是不是重叠了,就是在维护一链表,root->child,child就是一个从低地址到高地址的链表,所以整个操作过程就是链表的插入操作

第一次动作的时候:

    p = &root->child = NULL;

   if () 成立,插入链表结点成功

(root->start    new->start  new->end

第二次动作的时候:

   p = &root->child != NULL;

  if(!tmp)不成立,如果tmp->start > end,表示要在中间插入链表,。。。成功!

        (root->start                 new->start        new->end        tmp1->start        tmp1->end

  if(!tmp)不成立,如果tmp->start < end,表示还得判断

  p = &tmp->sibling = NULL;

 if(tmp->end < start)成立的话,说明新结点还要往后找位置,continue;

      (root->start      tmp1->start       tmp1->end    xx xx  xx

 如果不成立表明地址冲突了,有重叠,???

     (root->start      tmp1->start       new->start      tmp->end    xx     xx      new->end

其它情况不写了,有点麻烦,头晕。。。。。。。

######################################################

<===========接回行号
 903     if (!sfb->regs_res) {
 904         dev_err(dev, "failed to claim register region\n");
 905         ret = -ENOENT;
 906         goto err_clk;
 907     }
 908
 909     sfb->regs = ioremap(res->start, resource_size(res));
 910     //对申请合理的物理地址进行MMU映射.
 911     if (!sfb->regs) {
 912         dev_err(dev, "failed to map registers\n");
 913         ret = -ENXIO;
 914         goto err_req_region;
 915     }

 916
 917     dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
 918
 919     /* setup gpio and output polarity controls */
 920
 921     pd->setup_gpio();//调用设备私有数据函数指针(初始化GPIO用的).
 922
 923     writel(pd->vidcon1, sfb->regs + VIDCON1);//还是初始人,不过是寄存器.应该说不是初始化是,配置.
 924
 925     /* zero all windows before we do anything */
 926 

 927     for (win = 0; win < S3C_FB_MAX_WIN; win++)
 928         s3c_fb_clear_win(sfb, win);//清寄存器

 932     for (win = 0; win < S3C_FB_MAX_WIN; win++) {
 933         if (!pd->win[win])//配置5个窗口的寄存器,如果没用到就跳过.其实pd里面只是配置了窗口0的寄存器,其他的都是NULL,所以这里只用
 934                             //进行win0的配置.
 935             continue;
 936
 937         ret = s3c_fb_probe_win(sfb, win, &sfb->windows[win]);//先进行win0的处理.

<---------------------记住行号

##########################################################

 737 /**
 738  * s3c_fb_probe_win() - register an hardware window
 739  * @sfb: The base resources for the hardware
 740  * @res: Pointer to where to place the resultant window.
 741  *
 742  * Allocate and do the basic initialisation for one of the hardware's graphics
 743  * windows.
 744  */
 745 static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
 746                       struct s3c_fb_win **res)
 747 {
 748     struct fb_var_screeninfo *var;//可变参数主要是一些分辨率,时序什么的.....
 749     struct fb_videomode *initmode;//显示的模式
 750     struct s3c_fb_pd_win *windata;//主要也是显示模式
 751     struct s3c_fb_win *win;//每个窗口的私有数据(驱动的).
 752     struct fb_info *fbinfo;//frambuffer结构体
 753     int palette_size;//调色板变量
 754     int ret;
 755
 756     dev_dbg(sfb->dev, "probing window %d\n", win_no);
 757
 758     palette_size = s3c_fb_win_pal_size(win_no);
 759
 760     fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
 761                    palette_size * sizeof(u32), sfb->dev);
 762     //在调色板上,四个字节代表一种颜色

OOOOOOO《记住行号》

********************************************************

 25 /**
 26  * framebuffer_alloc - creates a new frame buffer info structure
 27  *  
 28  * @size: size of driver private data, can be zero
 29  * @dev: pointer to the device for this fb, this can be NULL
 30  *  
 31  * Creates a new frame buffer info structure. Also reserves @size bytes
 32  * for driver private data (info->par). info->par (if any) will be
 33  * aligned to sizeof(long).
 34  *  
 35  * Returns the new structure, or NULL if an error occured.
 36  *  
 37  */
 38 struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
 39 {
 40 #define BYTES_PER_LONG (BITS_PER_LONG/8)
 41 #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
 42     int fb_info_size = sizeof(struct fb_info);//framebuffer结构体大小
 43     struct fb_info *info;
 44     char *p;
 45
 46     if (size)
 47         fb_info_size += PADDING;//这个参数加上,我还真不知道是做什么用
 48
 49     p = kzalloc(fb_info_size + size, GFP_KERNEL);//开辟空间大小,framebuff + PADDING + 外部传进来的size大小,
 50
 51     if (!p)
 52         return NULL;
 53
 54     info = (struct fb_info *) p;
 55
 56     if (size)
 57         info->par = p + fb_info_size;//指向外部传进来的那个结构体的起始。。。感觉语言好别扭。。。
 58
 59     info->device = dev;//接收设备结构体
 60
 61 #ifdef CONFIG_FB_BACKLIGHT
 62     mutex_init(&info->bl_curve_mutex);
 63 #endif
 64
 65     return info;
 66 #undef PADDING
 67 #undef BYTES_PER_LONG
 68 }

********************************************************

OOOOOOO《接回行号》.
 763     if (!fbinfo) {
 764         dev_err(sfb->dev, "failed to allocate framebuffer\n");
 765         return -ENOENT;
 766     }
 767
 768     windata = sfb->pdata->win[win_no];
 769     initmode = &windata->win_mode;
 770
 771     WARN_ON(windata->max_bpp == 0);
 772     WARN_ON(windata->win_mode.xres == 0);
 773     WARN_ON(windata->win_mode.yres == 0);
 774
 775     win = fbinfo->par;//每个窗口都有这样的一个win
 776     var = &fbinfo->var;//接收可变参数结构体.目前还没有初始化,还只是一个空壳
 777     win->fbinfo = fbinfo;//保存framebuffer结构体
 778     win->parent = sfb;//指向总的目录,便于维护
 779     win->windata = windata;//从设备结构体的私有成员中提取出私有数据,保存到win中去.
 780     win->index = win_no;//保存窗口号(0号窗口)
 781     win->palette_buffer = (u32 *)(win + 1);//这不是颜色表的空间吗?,在framebuffer_alloc中申请的.
 782 
  783     ret = s3c_fb_alloc_memory(sfb, win);//framebuffer分配DMA....

OOOOOOOO《记住行号》

***************************************************************

 656 /**
 657  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
 658  * @sfb: The base resources for the hardware.
 659  * @win: The window to initialise memory for.
 660  *
 661  * Allocate memory for the given framebuffer.
 662  */
 663 static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
 664                      struct s3c_fb_win *win)
 665 {
 666     struct s3c_fb_pd_win *windata = win->windata;//当前窗口的私有数据(寄存器相关的)
 667     unsigned int real_size, virt_size, size;
 668     struct fb_info *fbi = win->fbinfo;//当前窗口的framebuffer结构体
 669     dma_addr_t map_dma;//framebuffer的物理地址,目前还没有初始化,下面会初始化此变量
 670
 671     dev_dbg(sfb->dev, "allocating memory for display\n");
 672
 673     real_size = windata->win_mode.xres * windata->win_mode.yres;//实际的尺寸
 674     virt_size = windata->virtual_x * windata->virtual_y;//虚拟的尺寸
 675
 676     dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
 677         real_size, windata->win_mode.xres, windata->win_mode.yres,
 678         virt_size, windata->virtual_x, windata->virtual_y);
 679
 680     size = (real_size > virt_size) ? real_size : virt_size;//这是做什么,难道虚拟的尺寸还会比实际的小吗?也许也许,
  681     size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
 682     size /= 8;
 683         //搞了半天,上面的内容就是在计算framebuffer的大小.就是屏的宽*屏的高*屏的bpp >> 3
 684     fbi->fix.smem_len = size;//固定数据结构体初始化frambuffer长度
 685     size = PAGE_ALIGN(size);//保证页对齐,一般好象是4K,我只是说好象,别喷!!!!
 686
 687     dev_dbg(sfb->dev, "want %u bytes for window\n", size);
 688
 689     fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
 690                           &map_dma, GFP_KERNEL);//看样子,这个函数的整个核心就在这里了.
 691     //看了一些资源,原来通过这个函数处理后,fbi->screen_base 与map_dma将达到同步的效果,当且这么说吧,
 692     //也就是操作物理地址的时候OK,操作虚拟地址的时候也是OK的.好象又不对,百度下吧!!!!!!!
 693     if (!fbi->screen_base)
 694         return -ENOMEM;
 695
 696     dev_dbg(sfb->dev, "mapped %x to %p\n",
  697         (unsigned int)map_dma, fbi->screen_base);
 698
 699     memset(fbi->screen_base, 0x0, size);//清零framebuffer
 700     fbi->fix.smem_start = map_dma;
 701
 702     return 0;
  703  }

***************************************************************

OOOOOOOO《接回行号》
 784     if (ret) {
 785         dev_err(sfb->dev, "failed to allocate display memory\n");
 786         return ret;
 787     }
 788
 789     /* setup the r/b/g positions for the window's palette */
 790     s3c_fb_init_palette(win_no, &win->palette);//初始化颜色表

OOOOOOO《记住行号》

*****************************************************************

218 static inline void s3c_fb_init_palette(unsigned int window,
219                        struct s3c_fb_palette *palette)
220 {       
221     if (window < 2) {//窗口小于2,就是说是0和1号窗口,[31-24] 空,[16-23]r,[8-15]g,[0-7]b, 24位色以上的
222         /* Windows 0/1 are 8/8/8 or A/8/8/8 */
223         palette->r.offset = 16;
224         palette->r.length = 8;
225         palette->g.offset = 8;
226         palette->g.length = 8;
227         palette->b.offset = 0;
228         palette->b.length = 8;
229     } else {//16位色,
230         /* currently we assume RGB 5/6/5 */
231         palette->r.offset = 11;
232         palette->r.length = 5;
233         palette->g.offset = 5;
234         palette->g.length = 6;
235         palette->b.offset = 0;
236         palette->b.length = 5;
237     }
238 }
239
240 /* Notes on per-window bpp settings
241  *
242  * Value    Win0     Win1     Win2     Win3     Win 4
243  * 0000     1(P)     1(P)     1(P)     1(P)     1(P)
244  * 0001     2(P)     2(P)     2(P)     2(P)     2(P)
245  * 0010     4(P)     4(P)     4(P)     4(P)     -none-
246  * 0011     8(P)     8(P)     -none-   -none-   -none-
247  * 0100     -none-   8(A232)  8(A232)  -none-   -none-
248  * 0101     16(565)  16(565)  16(565)  16(565)   16(565)
249  * 0110     -none-   16(A555) 16(A555) 16(A555)  16(A555)
250  * 0111     16(I555) 16(I565) 16(I555) 16(I555)  16(I555)
251  * 1000     18(666)  18(666)  18(666)  18(666)   18(666)
252  * 1001     -none-   18(A665) 18(A665) 18(A665)  16(A665)
253  * 1010     -none-   19(A666) 19(A666) 19(A666)  19(A666)
254  * 1011     24(888)  24(888)  24(888)  24(888)   24(888)
255  * 1100     -none-   24(A887) 24(A887) 24(A887)  24(A887)
256  * 1101     -none-   25(A888) 25(A888) 25(A888)  25(A888)
257  * 1110     -none-   -none-   -none-   -none-    -none-
258  * 1111     -none-   -none-   -none-   -none-    -none-
259 */

*****************************************************************

OOOOOOO《接回行号》
 791
 792     /* setup the initial video mode from the window */
 793     fb_videomode_to_var(&fbinfo->var, initmode);//填充可变参结构体.用于填充的数据都在设备的私有数据段中.

OOOOOOO《记住行号》

*****************************************************************

这个就不用说了吧,时序,频率相关的内容初始化。。。。

 749 /**    
 750  * fb_videomode_to_var - convert fb_videomode to fb_var_screeninfo
 751  * @var: pointer to struct fb_var_screeninfo
 752  * @mode: pointer to struct fb_videomode
 753  */
 754 void fb_videomode_to_var(struct fb_var_screeninfo *var,
 755              const struct fb_videomode *mode)
 756 {  
 757     var->xres = mode->xres;
 758     var->yres = mode->yres;
 759     var->xres_virtual = mode->xres;
 760     var->yres_virtual = mode->yres;
 761     var->xoffset = 0;  
 762     var->yoffset = 0;
 763     var->pixclock = mode->pixclock;
 764     var->left_margin = mode->left_margin;
 765     var->right_margin = mode->right_margin;
 766     var->upper_margin = mode->upper_margin;
 767     var->lower_margin = mode->lower_margin;
 768     var->hsync_len = mode->hsync_len;
 769     var->vsync_len = mode->vsync_len;
 770     var->sync = mode->sync;
 771     var->vmode = mode->vmode & FB_VMODE_MASK;
 772 }

*****************************************************************

OOOOOOO《接回行号》
 794
 795     /****下面的不太清楚是什么意思?部分,只是部分 (O  n  O)  ***********/
 796     fbinfo->fix.type    = FB_TYPE_PACKED_PIXELS;
 797     fbinfo->fix.accel   = FB_ACCEL_NONE;
 798     fbinfo->var.activate    = FB_ACTIVATE_NOW;
 799     fbinfo->var.vmode   = FB_VMODE_NONINTERLACED;
 800     fbinfo->var.bits_per_pixel = windata->default_bpp;//16bpp
 801     fbinfo->fbops       = &s3c_fb_ops;
  802     fbinfo->flags       = FBINFO_FLAG_DEFAULT;
 803     fbinfo->pseudo_palette  = &win->pseudo_palette;
 804
 805     /* prepare to actually start the framebuffer */
 806
 807     ret = s3c_fb_check_var(&fbinfo->var, fbinfo);//检查可变参的有效性

OOOOOOO《记住行号》

**********************************************************************

 108 /**
 109  * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
 110  * @var: The screen information to verify.
 111  * @info: The framebuffer device.
 112  *
 113  * Framebuffer layer call to verify the given information and allow us to
 114  * update various information depending on the hardware capabilities.
 115  */
 116 static int s3c_fb_check_var(struct fb_var_screeninfo *var,
 117                 struct fb_info *info)
 118 {
 119     struct s3c_fb_win *win = info->par;
 120     struct s3c_fb_pd_win *windata = win->windata;
 121     struct s3c_fb *sfb = win->parent;
 122
 123     dev_dbg(sfb->dev, "checking parameters\n");
 124
 125     var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);//就里都 说虚拟的大了。。。。。
 126     var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
 127
 128     if (!s3c_fb_validate_win_bpp(win->index, var->bits_per_pixel)) {//判断bpp的合理性
 129         dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
 130             win->index, var->bits_per_pixel);
 131         return -EINVAL;
 132     }
 133
 134     /* always ensure these are zero, for drop through cases below */
 135     var->transp.offset = 0;//不懂
 136     var->transp.length = 0;//接着不懂
 137
 138     switch (var->bits_per_pixel) {
 139     case 1:
 140     case 2:
 141     case 4:
 142     case 8:
 143         if (!s3c_fb_win_has_palette(win->index, var->bits_per_pixel)) {
 144             /* non palletised, A:1,R:2,G:3,B:2 mode */
 145             var->red.offset     = 4;
 146             var->green.offset   = 2;
 147             var->blue.offset    = 0;
 148             var->red.length     = 5;
 149             var->green.length   = 3;
 150             var->blue.length    = 2;
 151             var->transp.offset  = 7;
 152             var->transp.length  = 1;
 153         } else {
 154             var->red.offset = 0;
 155             var->red.length = var->bits_per_pixel;
 156             var->green  = var->red;
 157             var->blue   = var->red;
 158         }
 159         break;
 160
 161     case 19:
 162         /* 666 with one bit alpha/transparency */
 163         var->transp.offset  = 18;
 164         var->transp.length  = 1;
 165     case 18:
 166         var->bits_per_pixel = 32;
 167
 168         /* 666 format */
 169         var->red.offset     = 12;
 170         var->green.offset   = 6;
 171         var->blue.offset    = 0;
 172         var->red.length     = 6;
 173         var->green.length   = 6;
 174         var->blue.length    = 6;
 175         break;
 176
 177     case 16:
 178         /* 16 bpp, 565 format */
 179         var->red.offset     = 11;
 180         var->green.offset   = 5;
 181         var->blue.offset    = 0;
 182         var->red.length     = 5;
 183         var->green.length   = 6;
 184         var->blue.length    = 5;
 185         break;
 186
 187     case 28:
 188     case 25:
 189         var->transp.length  = var->bits_per_pixel - 24;
 190         var->transp.offset  = 24;
 191         /* drop through */
 192     case 24:
 193         /* our 24bpp is unpacked, so 32bpp */
 194         var->bits_per_pixel = 32;
 195     case 32:
 196         var->red.offset     = 16;
 197         var->red.length     = 8;
 198         var->green.offset   = 8;
 199         var->green.length   = 8;
 200         var->blue.offset    = 0;
 201         var->blue.length    = 8;
 202         break;
 203
 204     default:
 205         dev_err(sfb->dev, "invalid bpp\n");
 206     }
 207
 208     dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
 209     return 0;
 210 }

 

**********************************************************************

OOOOOOO《接回行号》
 808     if (ret < 0) {
 809         dev_err(sfb->dev, "check_var failed on initial video params\n");
 810         return ret;
 811     }
 812
 813     /* create initial colour map */
 814
 815     ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1);

//依然不懂。。。。。。
 816     if (ret == 0)
 817         fb_set_cmap(&fbinfo->cmap, fbinfo);
 818     else
 819         dev_err(sfb->dev, "failed to allocate fb cmap\n");
 820
 821     s3c_fb_set_par(fbinfo);//初始化寄存器,内容比较多

OOOOOOO《记住行号》

**********************************************************************

 257 /**
 258  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
 259  * @info: The framebuffer to change.
 260  *
 261  * Framebuffer layer request to set a new mode for the specified framebuffer
 262  */
 263 static int s3c_fb_set_par(struct fb_info *info)
 264 {
 265     struct fb_var_screeninfo *var = &info->var;//可变参数结构
 266     struct s3c_fb_win *win = info->par;//当前窗口的数据
 267     struct s3c_fb *sfb = win->parent;//总目录结构指针
 268     void __iomem *regs = sfb->regs;//framebuffer虚拟地址
 269     int win_no = win->index;//窗口号
 270     u32 osdc_data = 0;
 271     u32 data;
 272     u32 pagewidth;
 273     int clkdiv;
 274
 275     dev_dbg(sfb->dev, "setting framebuffer parameters\n");
 276
 277     switch (var->bits_per_pixel) {
 278     case 32:
 279     case 24:
 280     case 16:
 281     case 12:
 282         info->fix.visual = FB_VISUAL_TRUECOLOR;//这个参数主要是显示模式,真彩色
 283         break;
 284     case 8:
 285         if (s3c_fb_win_has_palette(win_no, 8))
 286             info->fix.visual = FB_VISUAL_PSEUDOCOLOR;//。。。。
 287         else
 288             info->fix.visual = FB_VISUAL_TRUECOLOR;
 289         break;
 290     case 1:
 291         info->fix.visual = FB_VISUAL_MONO01;//黑白
 292         break;
 293     default:
 294         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 295         break;
 296     }
 297
 298     info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;//一行多少字节
 299
 300     /* disable the window whilst we update it */
 301     writel(0, regs + WINCON(win_no));
 302
 303     /* use window 0 as the basis for the lcd output timings */
 304
 305     if (win_no == 0) {//只有窗口0需要配置,其它的一样,共用同一套。。。。。。(又好象说错了。。。。)
 306         clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);//计算频率div,就是Hclk / pixelCLK + 1
 307 
 308         data = sfb->pdata->vidcon0;
 309         data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
 310
 311         if (clkdiv > 1)
 312             data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
 313         else
 314             data &= ~VIDCON0_CLKDIR;    /* 1:1 clock */
 315
 316         /* write the timing data to the panel */
 317
 318         data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
 319         writel(data, regs + VIDCON0);//写寄存器VIDCON0
 320
 321         data = VIDTCON0_VBPD(var->upper_margin - 1) |
 322                VIDTCON0_VFPD(var->lower_margin - 1) |
 323                VIDTCON0_VSPW(var->vsync_len - 1);
 324
 325         writel(data, regs + VIDTCON0);//写时序寄存器,帧
 326
 327         data = VIDTCON1_HBPD(var->left_margin - 1) |
 328                VIDTCON1_HFPD(var->right_margin - 1) |
 329                VIDTCON1_HSPW(var->hsync_len - 1);
 330
 331         writel(data, regs + VIDTCON1);//写时序寄存器,行
 332
 333         data = VIDTCON2_LINEVAL(var->yres - 1) |//写屏尺寸寄存器,就是屏宽和屏高
 334                VIDTCON2_HOZVAL(var->xres - 1);
 335         writel(data, regs + VIDTCON2);
 336     }
 337
 338     /* write the buffer address */
 339
 340     writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no));//写framebuffer的起始地址到寄存器,
 341
 342     data = info->fix.smem_start + info->fix.line_length * var->yres;
 343     writel(data, regs + VIDW_BUF_END(win_no));//写framebuffer的结束地址到寄存器,什么寄存器,查呗!(要看清楚手册上是以什么为单位,字节,字还是什么)
 344
 345     pagewidth = (var->xres * var->bits_per_pixel) >> 3;//一行的长度(字节为单位)
 346     data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |//0
 347            VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
 348     writel(data, regs + VIDW_BUF_SIZE(win_no));
 349
 350     /* write 'OSD' registers to control position of framebuffer */
 351
 352     data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
 353     writel(data, regs + VIDOSD_A(win_no));
 354
 355     data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
 356                              var->xres - 1)) |
 357            VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
 358
 359     writel(data, regs + VIDOSD_B(win_no));//还是宽高
 360
 361     data = var->xres * var->yres;
 362
 363     osdc_data = VIDISD14C_ALPHA1_R(0xf) |
 364         VIDISD14C_ALPHA1_G(0xf) |
 365         VIDISD14C_ALPHA1_B(0xf);
 366
 367     if (s3c_fb_has_osd_d(win_no)) {
 368         writel(data, regs + VIDOSD_D(win_no));//非0号窗口的一个配置寄存器

 369         writel(osdc_data, regs + VIDOSD_C(win_no));
 370     } else
 371         writel(data, regs + VIDOSD_C(win_no));
 372
 373     data = WINCONx_ENWIN;
 374
 375     /* note, since we have to round up the bits-per-pixel, we end up
 376      * relying on the bitfield information for r/g/b/a to work out
 377      * exactly which mode of operation is intended 378
 379     switch (var->bits_per_pixel) {
 380     case 1:
 381         data |= WINCON0_BPPMODE_1BPP;
 382         data |= WINCONx_BITSWP;
 383         data |= WINCONx_BURSTLEN_4WORD;
 384         break;
 385     case 2:
 386         data |= WINCON0_BPPMODE_2BPP;
 387         data |= WINCONx_BITSWP;
 388         data |= WINCONx_BURSTLEN_8WORD;
 389         break;
 390     case 4:
 391         data |= WINCON0_BPPMODE_4BPP;
 392         data |= WINCONx_BITSWP;
 393         data |= WINCONx_BURSTLEN_8WORD;
 394         break;
 395     case 8:
 396         if (var->transp.length != 0)
 397             data |= WINCON1_BPPMODE_8BPP_1232;
 398         else
 399             data |= WINCON0_BPPMODE_8BPP_PALETTE;
 400         data |= WINCONx_BURSTLEN_8WORD;
 401         data |= WINCONx_BYTSWP;
 402         break;
 403     case 16:
 404         if (var->transp.length != 0)
 405             data |= WINCON1_BPPMODE_16BPP_A1555;
 406         else
 407             data |= WINCON0_BPPMODE_16BPP_565;
 408         data |= WINCONx_HAWSWP;
 409         data |= WINCONx_BURSTLEN_16WORD;
 410         break;
 411     case 24:
 412     case 32:
 413         if (var->red.length == 6) {
 414             if (var->transp.length != 0)
 415                 data |= WINCON1_BPPMODE_19BPP_A1666;
 416             else
 417                 data |= WINCON1_BPPMODE_18BPP_666;
 418         } else if (var->transp.length == 1)
 419             data |= WINCON1_BPPMODE_25BPP_A1888
 420                 | WINCON1_BLD_PIX;
 421         else if (var->transp.length == 4)
 422             data |= WINCON1_BPPMODE_28BPP_A4888
 423                 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
 424         else
 425             data |= WINCON0_BPPMODE_24BPP_888;
 426
 427         data |= WINCONx_BURSTLEN_16WORD;
 428         break;
 429     }
 430
 431     /* It has no color key control register for window0 */
 432     if (win_no > 0) {
 433         u32 keycon0_data = 0, keycon1_data = 0;
 434
 435         keycon0_data = ~(WxKEYCON0_KEYBL_EN |
 436                 WxKEYCON0_KEYEN_F |
 437                 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
 438
 439         keycon1_data = WxKEYCON1_COLVAL(0xffffff);
 440
 441         writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
 442         writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
 443     }
 444 
 445     writel(data, regs + WINCON(win_no));
 446     writel(0x0, regs + WINxMAP(win_no));
 447
 448     return 0;
 449 }

**********************************************************************

OOOOOOO《接回行号》
 822
 823     dev_dbg(sfb->dev, "about to register framebuffer\n");
 824 
  825     /* run the check_var and set_par on our configuration. */
 826
 827     ret = register_framebuffer(fbinfo);//注册framebuffer
 828     if (ret < 0) {
 829         dev_err(sfb->dev, "failed to register framebuffer\n");
 830         return ret;
 831     }
 832
 833     *res = win;
 834     dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
 835
 836     return 0;
 837 }

 

##########################################################

<============接回行号
 938         if (ret < 0) {
 939             dev_err(dev, "failed to create window %d\n", win);
 940             for (; win >= 0; win--)
 941                 s3c_fb_release_win(sfb, sfb->windows[win]);
 942             goto err_ioremap;
 943         }
 944     }
 945
 946     platform_set_drvdata(pdev, sfb);
 947
 948     return 0;
 949 //下面是融错处理,就不分析了
 950 err_ioremap:
 951     iounmap(sfb->regs);
 952
 953 err_req_region:
 954     release_resource(sfb->regs_res);
 955     kfree(sfb->regs_res);
 956
 957 err_clk:
 958     clk_disable(sfb->bus_clk);
 959     clk_put(sfb->bus_clk);
 960
 961 err_sfb:
 962     kfree(sfb);
 963     return ret;
 964 }