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 }
- LCD驱动(linux-2.6.32.60)---------------平台驱动方面
- LCD驱动(linux-2.6.32.60)----平台设备方面
- Linux设备驱动--LCD平台设备与驱动(smdk2440)
- Linux设备驱动--LCD平台设备与驱动(s3c64xx)
- Linux设备驱动--LCD平台设备与驱动(smdk6410)
- Linux设备驱动--LCD平台设备与驱动(tiny4412)
- Linux设备驱动--LCD平台设备与驱动(smdk2440)
- Linux驱动-LCD驱动
- 基于S3C2410平台的LCD for Linux 2.6 驱动移植
- linux LCD驱动(四) --- 驱动实现
- linux 2.6.32 在arm9(s3c2440)平台的移植 - LCD背光驱动
- linux lcd驱动
- linux lcd 驱动
- S3C2440,Linux,LCD驱动
- linux lcd 驱动
- LINUX之LCD驱动
- Linux的LCD驱动
- Linux的LCD驱动
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我学Spring3
- JS常用正则表达式
- JS性能之合理利用冒泡机制优化性能
- 利用zlib,lzo压缩与解压缩字符
- 5个帮你打破恐惧开始创业的办法
- LCD驱动(linux-2.6.32.60)---------------平台驱动方面
- RGB565 与RGB888的区别
- HDU 1234 水
- 5.1.5(大数阶乘)
- 在ruby中,如何分割太长的字符
- 你不知道的世界各国科技排行榜!
- StringUtils的isBlank与isEmply
- C++构造函数中调用另一构造函数注意事项
- vim基本操作