您的位置:首页 > 其它

S3C2410驱动分析的LCD驱动

2014-01-11 19:48 405 查看
本文分析S3C2410的LCD驱动,该驱动程序基于Framebuffer机制。


一、相关数据结构

首先,我们来介绍一下基于Framebuffer的S3C2410LCD驱动涉及的几个重要数据结构:

Framebuffer的核心数据结构是fb_info,该结构体定义在include/linux/fb.h文件中:

[cpp]viewplaincopyprint?832structfb_info{
833intnode;
834intflags;
835structmutexlock;/*Lockforopen/release/ioctlfuncs*/
836structmutexmm_lock;/*Lockforfb_mmapandsmem_*fields*/
837structfb_var_screeninfovar;/*Currentvar*/
838structfb_fix_screeninfofix;/*Currentfix*/
839structfb_monspecsmonspecs;/*CurrentMonitorspecs*/
840structwork_structqueue;/*Framebuffereventqueue*/
841structfb_pixmappixmap;/*Imagehardwaremapper*/
842structfb_pixmapsprite;/*Cursorhardwaremapper*/
843structfb_cmapcmap;/*Currentcmap*/
844structlist_headmodelist;/*modelist*/
845structfb_videomode*mode;/*currentmode*/
846
847#ifdefCONFIG_FB_BACKLIGHT
848/*assignedbacklightdevice*/
849/*setbeforeframebufferregistration,
850removeafterunregister*/
851structbacklight_device*bl_dev;
852
853/*Backlightlevelcurve*/
854structmutexbl_curve_mutex;
855u8bl_curve[FB_BACKLIGHT_LEVELS];
856#endif
857#ifdefCONFIG_FB_DEFERRED_IO
858structdelayed_workdeferred_work;
859structfb_deferred_io*fbdefio;
860#endif
861
862structfb_ops*fbops;
863structdevice*device;/*Thisistheparent*/
864structdevice*dev;/*Thisisthisfbdevice*/
865intclass_flag;/*privatesysfsflags*/
866#ifdefCONFIG_FB_TILEBLITTING
867structfb_tile_ops*tileops;/*TileBlitting*/
868#endif
869char__iomem*screen_base;/*Virtualaddress*/
870unsignedlongscreen_size;/*AmountofioremappedVRAMor0*/
871void*pseudo_palette;/*Fakepaletteof16colors*/
872#defineFBINFO_STATE_RUNNING0
873#defineFBINFO_STATE_SUSPENDED1
874u32state;&n
4000
bsp;/*Hardwarestatei.esuspend*/
875void*fbcon_par;/*fbconuse-onlyprivatearea*/
876/*Fromhereoneverythingisdevicedependent*/
877void*par;
878/*weneedthePCIorsimiliaraperturebase/sizenot
879smem_start/sizeassmem_startmayjustbeanobject
880allocatedinsidetheaperturesomaynotactuallyoverlap*/
881structapertures_struct{
882unsignedintcount;
883structaperture{
884resource_size_tbase;
885resource_size_tsize;
886}ranges[0];
887}*apertures;
888};
[code]832structfb_info{
833intnode;
834intflags;
835structmutexlock;/*Lockforopen/release/ioctlfuncs*/
836structmutexmm_lock;/*Lockforfb_mmapandsmem_*fields*/
837structfb_var_screeninfovar;/*Currentvar*/
838structfb_fix_screeninfofix;/*Currentfix*/
839structfb_monspecsmonspecs;/*CurrentMonitorspecs*/
840structwork_structqueue;/*Framebuffereventqueue*/
841structfb_pixmappixmap;/*Imagehardwaremapper*/
842structfb_pixmapsprite;/*Cursorhardwaremapper*/
843structfb_cmapcmap;/*Currentcmap*/
844structlist_headmodelist;/*modelist*/
845structfb_videomode*mode;/*currentmode*/
846
847#ifdefCONFIG_FB_BACKLIGHT
848/*assignedbacklightdevice*/
849/*setbeforeframebufferregistration,
850removeafterunregister*/
851structbacklight_device*bl_dev;
852
853/*Backlightlevelcurve*/
854structmutexbl_curve_mutex;
855u8bl_curve[FB_BACKLIGHT_LEVELS];
856#endif
857#ifdefCONFIG_FB_DEFERRED_IO
858structdelayed_workdeferred_work;
859structfb_deferred_io*fbdefio;
860#endif
861
862structfb_ops*fbops;
863structdevice*device;/*Thisistheparent*/
864structdevice*dev;/*Thisisthisfbdevice*/
865intclass_flag;/*privatesysfsflags*/
866#ifdefCONFIG_FB_TILEBLITTING
867structfb_tile_ops*tileops;/*TileBlitting*/
868#endif
869char__iomem*screen_base;/*Virtualaddress*/
870unsignedlongscreen_size;/*AmountofioremappedVRAMor0*/
871void*pseudo_palette;/*Fakepaletteof16colors*/
872#defineFBINFO_STATE_RUNNING0
873#defineFBINFO_STATE_SUSPENDED1
874u32state;/*Hardwarestatei.esuspend*/
875void*fbcon_par;/*fbconuse-onlyprivatearea*/
876/*Fromhereoneverythingisdevicedependent*/
877void*par;
878/*weneedthePCIorsimiliaraperturebase/sizenot
879smem_start/sizeassmem_startmayjustbeanobject
880allocatedinsidetheaperturesomaynotactuallyoverlap*/
881structapertures_struct{
882unsignedintcount;
883structaperture{
884resource_size_tbase;
885resource_size_tsize;
886}ranges[0];
887}*apertures;
888};

fb_info结构体中,最重要的三个成员是var,fix,fbops,分别代表LCD可变参数,固定参数和对底层硬件的操作函数集。[/code]
837行,fb_var_screeninfo结构体变量var代表LCD的可变参数。该结构体定义如下:

[cpp]viewplaincopyprint?238structfb_var_screeninfo{
239__u32xres;/*visibleresolution*/
240__u32yres;
241__u32xres_virtual;/*virtualresolution*/
242__u32yres_virtual;
243__u32xoffset;/*offsetfromvirtualtovisible*/
244__u32yoffset;/*resolution*/
245
246__u32bits_per_pixel;/*guesswhat*/
247__u32grayscale;/*!=0Graylevelsinsteadofcolors*/
248
249structfb_bitfieldred;/*bitfieldinfbmemiftruecolor,*/
250structfb_bitfieldgreen;/*elseonlylengthissignificant*/
251structfb_bitfieldblue;
252structfb_bitfieldtransp;/*transparency*/
253
254__u32nonstd;/*!=0Nonstandardpixelformat*/
255
256__u32activate;/*seeFB_ACTIVATE_**/
257
258__u32height;/*heightofpictureinmm*/
259__u32width;/*widthofpictureinmm*/
260
261__u32accel_flags;/*(OBSOLETE)seefb_info.flags*/
262
263/*Timing:Allvaluesinpixclocks,exceptpixclock(ofcourse)*/
264__u32pixclock;/*pixelclockinps(picoseconds)*/
265__u32left_margin;/*timefromsynctopicture*/
266__u32right_margin;/*timefrompicturetosync*/
267__u32upper_margin;/*timefromsynctopicture*/
268__u32lower_margin;
269__u32hsync_len;/*lengthofhorizontalsync*/
270__u32vsync_len;/*lengthofverticalsync*/
271__u32sync;/*seeFB_SYNC_**/
272__u32vmode;/*seeFB_VMODE_**/
273__u32rotate;/*anglewerotatecounterclockwise*/
274__u32reserved[5];/*Reservedforfuturecompatibility*/
275};
[code]238structfb_var_screeninfo{
239__u32xres;/*visibleresolution*/
240__u32yres;
241__u32xres_virtual;/*virtualresolution*/
242__u32yres_virtual;
243__u32xoffset;/*offsetfromvirtualtovisible*/
244__u32yoffset;/*resolution*/
245
246__u32bits_per_pixel;/*guesswhat*/
247__u32grayscale;/*!=0Graylevelsinsteadofcolors*/
248
249structfb_bitfieldred;/*bitfieldinfbmemiftruecolor,*/
250structfb_bitfieldgreen;/*elseonlylengthissignificant*/
251structfb_bitfieldblue;
252structfb_bitfieldtransp;/*transparency*/
253
254__u32nonstd;/*!=0Nonstandardpixelformat*/
255
256__u32activate;/*seeFB_ACTIVATE_**/
257
258__u32height;/*heightofpictureinmm*/
259__u32width;/*widthofpictureinmm*/
260
261__u32accel_flags;/*(OBSOLETE)seefb_info.flags*/
262
263/*Timing:Allvaluesinpixclocks,exceptpixclock(ofcourse)*/
264__u32pixclock;/*pixelclockinps(picoseconds)*/
265__u32left_margin;/*timefromsynctopicture*/
266__u32right_margin;/*timefrompicturetosync*/
267__u32upper_margin;/*timefromsynctopicture*/
268__u32lower_margin;
269__u32hsync_len;/*lengthofhorizontalsync*/
270__u32vsync_len;/*lengthofverticalsync*/
271__u32sync;/*seeFB_SYNC_**/
272__u32vmode;/*seeFB_VMODE_**/
273__u32rotate;/*anglewerotatecounterclockwise*/
274__u32reserved[5];/*Reservedforfuturecompatibility*/
275};

838行,fb_fix_screeninfo结构体变量fix代表LCD的固定参数,该结构体定义如下:[/code]
[cpp]viewplaincopyprint?155structfb_fix_screeninfo{
156charid[16];/*identificationstringeg"TTBuiltin"*/
157unsignedlongsmem_start;/*Startofframebuffermem*/
158/*(physicaladdress)*/
159__u32smem_len;/*Lengthofframebuffermem*/
160__u32type;/*seeFB_TYPE_**/
161__u32type_aux;/*InterleaveforinterleavedPlanes*/
162__u32visual;/*seeFB_VISUAL_**/
163__u16xpanstep;/*zeroifnohardwarepanning*/
164__u16ypanstep;/*zeroifnohardwarepanning*/
165__u16ywrapstep;/*zeroifnohardwareywrap*/
166__u32line_length;/*lengthofalineinbytes*/
167unsignedlongmmio_start;/*StartofMemoryMappedI/O*/
168/*(physicaladdress)*/
169__u32mmio_len;/*LengthofMemoryMappedI/O*/
170__u32accel;/*Indicatetodriverwhich*/
171/*specificchip/cardwehave*/
172__u16reserved[3];/*Reservedforfuturecompatibility*/
173};
[code]155structfb_fix_screeninfo{
156charid[16];/*identificationstringeg"TTBuiltin"*/
157unsignedlongsmem_start;/*Startofframebuffermem*/
158/*(physicaladdress)*/
159__u32smem_len;/*Lengthofframebuffermem*/
160__u32type;/*seeFB_TYPE_**/
161__u32type_aux;/*InterleaveforinterleavedPlanes*/
162__u32visual;/*seeFB_VISUAL_**/
163__u16xpanstep;/*zeroifnohardwarepanning*/
164__u16ypanstep;/*zeroifnohardwarepanning*/
165__u16ywrapstep;/*zeroifnohardwareywrap*/
166__u32line_length;/*lengthofalineinbytes*/
167unsignedlongmmio_start;/*StartofMemoryMappedI/O*/
168/*(physicaladdress)*/
169__u32mmio_len;/*LengthofMemoryMappedI/O*/
170__u32accel;/*Indicatetodriverwhich*/
171/*specificchip/cardwehave*/
172__u16reserved[3];/*Reservedforfuturecompatibility*/
173};

862行,fb_ops结构体变量fbops代表对底层硬件操作的函数集,该结构体定义如下:[/code]
[cpp]viewplaincopyprint?621structfb_ops{
622/*open/releaseandusagemarking*/
623structmodule*owner;
624int(*fb_open)(structfb_info*info,intuser);
625int(*fb_release)(structfb_info*info,intuser);
626
627/*Forframebufferswithstrangenonlinearlayoutsorthatdonot
628*workwithnormalmemorymappedaccess
629*/
630ssize_t(*fb_read)(structfb_info*info,char__user*buf,
631size_tcount,loff_t*ppos);
632ssize_t(*fb_write)(structfb_info*info,constchar__user*buf,
633size_tcount,loff_t*ppos);
634
635/*checksvarandeventuallytweaksittosomethingsupported,
636*DONOTMODIFYPAR*/
637int(*fb_check_var)(structfb_var_screeninfo*var,structfb_info*info);
638
639/*setthevideomodeaccordingtoinfo->var*/
640int(*fb_set_par)(structfb_info*info);
641
642/*setcolorregister*/
643int(*fb_setcolreg)(unsignedregno,unsignedred,unsignedgreen,
644unsignedblue,unsignedtransp,structfb_info*info);
645
646/*setcolorregistersinbatch*/
647int(*fb_setcmap)(structfb_cmap*cmap,structfb_info*info);
648
649/*blankdisplay*/
650int(*fb_blank)(intblank,structfb_info*info);
651
652/*pandisplay*/
653int(*fb_pan_display)(structfb_var_screeninfo*var,structfb_info*info);
654
655/*Drawsarectangle*/
656void(*fb_fillrect)(structfb_info*info,conststructfb_fillrect*rect);
657/*Copydatafromareatoanother*/
658void(*fb_copyarea)(structfb_info*info,conststructfb_copyarea*region);
659/*Drawsaimagetothedisplay*/
660void(*fb_imageblit)(structfb_info*info,conststructfb_image*image);
661
662/*Drawscursor*/
663int(*fb_cursor)(structfb_info*info,structfb_cursor*cursor);
664
665/*Rotatesthedisplay*/
666void(*fb_rotate)(structfb_info*info,intangle);
667
668/*waitforblitidle,optional*/
669int(*fb_sync)(structfb_info*info);
670
671/*performfbspecificioctl(optional)*/
672int(*fb_ioctl)(structfb_info*info,unsignedintcmd,
673unsignedlongarg);
674
675/*Handle32bitcompatioctl(optional)*/
676int(*fb_compat_ioctl)(structfb_info*info,unsignedcmd,
677unsignedlongarg);
678
679/*performfbspecificmmap*/
680int(*fb_mmap)(structfb_info*info,structvm_area_struct*vma);
681
682/*getcapabilitygivenvar*/
683void(*fb_get_caps)(structfb_info*info,structfb_blit_caps*caps,
684structfb_var_screeninfo*var);
685
686/*teardownanyresourcestodowiththisframebuffer*/
687void(*fb_destroy)(structfb_info*info);
688
689/*calledatKDBenterandleavetimetopreparetheconsole*/
690int(*fb_debug_enter)(structfb_info*info);
691int(*fb_debug_leave)(structfb_info*info);
692};
[code]621structfb_ops{
622/*open/releaseandusagemarking*/
623structmodule*owner;
624int(*fb_open)(structfb_info*info,intuser);
625int(*fb_release)(structfb_info*info,intuser);
626
627/*Forframebufferswithstrangenonlinearlayoutsorthatdonot
628*workwithnormalmemorymappedaccess
629*/
630ssize_t(*fb_read)(structfb_info*info,char__user*buf,
631size_tcount,loff_t*ppos);
632ssize_t(*fb_write)(structfb_info*info,constchar__user*buf,
633size_tcount,loff_t*ppos);
634
635/*checksvarandeventuallytweaksittosomethingsupported,
636*DONOTMODIFYPAR*/
637int(*fb_check_var)(structfb_var_screeninfo*var,structfb_info*info);
638
639/*setthevideomodeaccordingtoinfo->var*/
640int(*fb_set_par)(structfb_info*info);
641
642/*setcolorregister*/
643int(*fb_setcolreg)(unsignedregno,unsignedred,unsignedgreen,
644unsignedblue,unsignedtransp,structfb_info*info);
645
646/*setcolorregistersinbatch*/
647int(*fb_setcmap)(structfb_cmap*cmap,structfb_info*info);
648
649/*blankdisplay*/
650int(*fb_blank)(intblank,structfb_info*info);
651
652/*pandisplay*/
653int(*fb_pan_display)(structfb_var_screeninfo*var,structfb_info*info);
654
655/*Drawsarectangle*/
656void(*fb_fillrect)(structfb_info*info,conststructfb_fillrect*rect);
657/*Copydatafromareatoanother*/
658void(*fb_copyarea)(structfb_info*info,conststructfb_copyarea*region);
659/*Drawsaimagetothedisplay*/
660void(*fb_imageblit)(structfb_info*info,conststructfb_image*image);
661
662/*Drawscursor*/
663int(*fb_cursor)(structfb_info*info,structfb_cursor*cursor);
664
665/*Rotatesthedisplay*/
666void(*fb_rotate)(structfb_info*info,intangle);
667
668/*waitforblitidle,optional*/
669int(*fb_sync)(structfb_info*info);
670
671/*performfbspecificioctl(optional)*/
672int(*fb_ioctl)(structfb_info*info,unsignedintcmd,
673unsignedlongarg);
674
675/*Handle32bitcompatioctl(optional)*/
676int(*fb_compat_ioctl)(structfb_info*info,unsignedcmd,
677unsignedlongarg);
678
679/*performfbspecificmmap*/
680int(*fb_mmap)(structfb_info*info,structvm_area_struct*vma);
681
682/*getcapabilitygivenvar*/
683void(*fb_get_caps)(structfb_info*info,structfb_blit_caps*caps,
684structfb_var_screeninfo*var);
685
686/*teardownanyresourcestodowiththisframebuffer*/
687void(*fb_destroy)(structfb_info*info);
688
689/*calledatKDBenterandleavetimetopreparetheconsole*/
690int(*fb_debug_enter)(structfb_info*info);
691int(*fb_debug_leave)(structfb_info*info);
692};

S3C2410驱动还定义了几个专用结构体:[/code]
在drivers/video/s3c2410fb.h文件中定义了s3c2410fb_info结构体:

[cpp]viewplaincopyprint?21structs3c2410fb_info{
22structdevice*dev;
23structclk*clk;
24
25structresource*mem;
26void__iomem*io;
27void__iomem*irq_base;
28
29enums3c_drv_typedrv_type;
30structs3c2410fb_hwregs;
31
32unsignedlongclk_rate;
33unsignedintpalette_ready;
34
35#ifdefCONFIG_CPU_FREQ
36structnotifier_blockfreq_transition;
37#endif
38
39/*keeptheseregistersincaseweneedtore-writepalette*/
40u32palette_buffer[256];
41u32pseudo_pal[16];
42};
[code]21structs3c2410fb_info{
22structdevice*dev;
23structclk*clk;
24
25structresource*mem;
26void__iomem*io;
27void__iomem*irq_base;
28
29enums3c_drv_typedrv_type;
30structs3c2410fb_hwregs;
31
32unsignedlongclk_rate;
33unsignedintpalette_ready;
34
35#ifdefCONFIG_CPU_FREQ
36structnotifier_blockfreq_transition;
37#endif
38
39/*keeptheseregistersincaseweneedtore-writepalette*/
40u32palette_buffer[256];
41u32pseudo_pal[16];
42};

在arch/arm/mach-s3c2410/include/mach/fb.h文件中定义了s3c2410fb_display和s3c2410fb_mach_info结构体:[/code]
[cpp]viewplaincopyprint?25/*LCDdescription*/
26structs3c2410fb_display{
27/*LCDtype*/
28unsignedtype;
29
30/*Screensize*/
31unsignedshortwidth;
32unsignedshortheight;
33
34/*Screeninfo*/
35unsignedshortxres;
36unsignedshortyres;
37unsignedshortbpp;
38
39unsignedpixclock;/*pixclockinpicoseconds*/
40unsignedshortleft_margin;/*valueinpixels(TFT)orHCLKs(STN)*/
41unsignedshortright_margin;/*valueinpixels(TFT)orHCLKs(STN)*/
42unsignedshorthsync_len;/*valueinpixels(TFT)orHCLKs(STN)*/
43unsignedshortupper_margin;/*valueinlines(TFT)or0(STN)*/
44unsignedshortlower_margin;/*valueinlines(TFT)or0(STN)*/
45unsignedshortvsync_len;/*valueinlines(TFT)or0(STN)*/
46
47/*lcdconfigurationregisters*/
48unsignedlonglcdcon5;
49};
50
51structs3c2410fb_mach_info{
52
53structs3c2410fb_display*displays;/*attacheddiplaysinfo*/
54unsignednum_displays;/*numberofdefineddisplays*/
55unsigneddefault_display;
56
57/*GPIOs*/
58
59unsignedlonggpcup;
60unsignedlonggpcup_mask;
61unsignedlonggpccon;
62unsignedlonggpccon_mask;
63unsignedlonggpdup;
64unsignedlonggpdup_mask;
65unsignedlonggpdcon;
66unsignedlonggpdcon_mask;
67
68/*lpc3600controlregister*/
69unsignedlonglpcsel;
70};
[code]25/*LCDdescription*/
26structs3c2410fb_display{
27/*LCDtype*/
28unsignedtype;
29
30/*Screensize*/
31unsignedshortwidth;
32unsignedshortheight;
33
34/*Screeninfo*/
35unsignedshortxres;
36unsignedshortyres;
37unsignedshortbpp;
38
39unsignedpixclock;/*pixclockinpicoseconds*/
40unsignedshortleft_margin;/*valueinpixels(TFT)orHCLKs(STN)*/
41unsignedshortright_margin;/*valueinpixels(TFT)orHCLKs(STN)*/
42unsignedshorthsync_len;/*valueinpixels(TFT)orHCLKs(STN)*/
43unsignedshortupper_margin;/*valueinlines(TFT)or0(STN)*/
44unsignedshortlower_margin;/*valueinlines(TFT)or0(STN)*/
45unsignedshortvsync_len;/*valueinlines(TFT)or0(STN)*/
46
47/*lcdconfigurationregisters*/
48unsignedlonglcdcon5;
49};
50
51structs3c2410fb_mach_info{
52
53structs3c2410fb_display*displays;/*attacheddiplaysinfo*/
54unsignednum_displays;/*numberofdefineddisplays*/
55unsigneddefault_display;
56
57/*GPIOs*/
58
59unsignedlonggpcup;
60unsignedlonggpcup_mask;
61unsignedlonggpccon;
62unsignedlonggpccon_mask;
63unsignedlonggpdup;
64unsignedlonggpdup_mask;
65unsignedlonggpdcon;
66unsignedlonggpdcon_mask;
67
68/*lpc3600controlregister*/
69unsignedlonglpcsel;
70};

[/code]
二、platform_driverprobe函数分析

下面我们来看模块初始化函数s3c2410fb_init:

[cpp]viewplaincopyprint?1119int__inits3c2410fb_init(void)
1120{
1121intret=platform_driver_register(&s3c2410fb_driver);
1122
1123if(ret==0)
1124ret=platform_driver_register(&s3c2412fb_driver);
1125
1126returnret;
1127}
[code]1119int__inits3c2410fb_init(void)
1120{
1121intret=platform_driver_register(&s3c2410fb_driver);
1122
1123if(ret==0)
1124ret=platform_driver_register(&s3c2412fb_driver);
1125
1126returnret;
1127}

我们只关注S3C2410,1121行,注册platform_drivers3c2410fb_driver,定义如下:[/code]
[cpp]viewplaincopyprint?1097staticstructplatform_drivers3c2410fb_driver={
1098.probe=s3c2410fb_probe,
1099.remove=__devexit_p(s3c2410fb_remove),
1100.suspend=s3c2410fb_suspend,
1101.resume=s3c2410fb_resume,
1102.driver={
1103.name="s3c2410-lcd",
1104.owner=THIS_MODULE,
1105},
1106};
[code]1097staticstructplatform_drivers3c2410fb_driver={
1098.probe=s3c2410fb_probe,
1099.remove=__devexit_p(s3c2410fb_remove),
1100.suspend=s3c2410fb_suspend,
1101.resume=s3c2410fb_resume,
1102.driver={
1103.name="s3c2410-lcd",
1104.owner=THIS_MODULE,
1105},
1106};

当模块被装载时,会调用s3c2410fb_probe函数,该函数定义如下:[/code]
[cpp]viewplaincopyprint?1007staticint__devinits3c2410fb_probe(structplatform_device*pdev)
1008{
1009returns3c24xxfb_probe(pdev,DRV_S3C2410);
1010}
[code]1007staticint__devinits3c2410fb_probe(structplatform_device*pdev)
1008{
1009returns3c24xxfb_probe(pdev,DRV_S3C2410);
1010}

实际上s3c2410fb_probe直接调用了s3c24xxfb_probe,并传递参数DVR_S3C2410,表明是S3C2410平台。下面看s3c24xxfb_probe函数:[/code]
[cpp]viewplaincopyprint?817staticint__devinits3c24xxfb_probe(structplatform_device*pdev,
818enums3c_drv_typedrv_type)
819{
820structs3c2410fb_info*info;
821structs3c2410fb_display*display;
822structfb_info*fbinfo;
823structs3c2410fb_mach_info*mach_info;
824structresource*res;
825intret;
826intirq;
827inti;
828intsize;
829u32lcdcon1;
830
831mach_info=pdev->dev.platform_data;
832if(mach_info==NULL){
833dev_err(&pdev->dev,
834"noplatformdataforlcd,cannotattach\n");
835return-EINVAL;
836}
837
838if(mach_info->default_display>=mach_info->num_displays){
839dev_err(&pdev->dev,"defaultis%dbutonly%ddisplays\n",
840mach_info->default_display,mach_info->num_displays);
841return-EINVAL;
842}
843
844display=mach_info->displays+mach_info->default_display;
845
846irq=platform_get_irq(pdev,0);
847if(irq<0){
848dev_err(&pdev->dev,"noirqfordevice\n");
849return-ENOENT;
850}
851
852fbinfo=framebuffer_alloc(sizeof(structs3c2410fb_info),&pdev->dev);
853if(!fbinfo)
854return-ENOMEM;
855
856platform_set_drvdata(pdev,fbinfo);
857
858info=fbinfo->par;
859info->dev=&pdev->dev;
860info->drv_type=drv_type;
861
862res=platform_get_resource(pdev,IORESOURCE_MEM,0);
863if(res==NULL){
864dev_err(&pdev->dev,"failedtogetmemoryregisters\n");
865ret=-ENXIO;
866gotodealloc_fb;
867}
868
869size=(res->end-res->start)+1;
870info->mem=request_mem_region(res->start,size,pdev->name);
871if(info->mem==NULL){
872dev_err(&pdev->dev,"failedtogetmemoryregion\n");
873ret=-ENOENT;
874gotodealloc_fb;
875}
876
877info->io=ioremap(res->start,size);
878if(info->io==NULL){
879dev_err(&pdev->dev,"ioremap()ofregistersfailed\n");
880ret=-ENXIO;
881gotorelease_mem;
882}
883
884info->irq_base=info->io+((drv_type==DRV_S3C2412)?S3C2412_LCDINTBASE:S3C2410_LCDINTBASE);
885
886dprintk("devinit\n");
887
888strcpy(fbinfo->fix.id,driver_name);
889
890/*Stopthevideo*/
891lcdcon1=readl(info->io+S3C2410_LCDCON1);
892writel(lcdcon1&~S3C2410_LCDCON1_ENVID,info->io+S3C2410_LCDCON1);
893
894fbinfo->fix.type=FB_TYPE_PACKED_PIXELS;
895fbinfo->fix.type_aux=0;
896fbinfo->fix.xpanstep=0;
897fbinfo->fix.ypanstep=0;
898fbinfo->fix.ywrapstep=0;
899fbinfo->fix.accel=FB_ACCEL_NONE;
900
901fbinfo->var.nonstd=0;
902fbinfo->var.activate=FB_ACTIVATE_NOW;
903fbinfo->var.accel_flags=0;
904fbinfo->var.vmode=FB_VMODE_NONINTERLACED;
905
906fbinfo->fbops=&s3c2410fb_ops;
907fbinfo->flags=FBINFO_FLAG_DEFAULT;
908fbinfo->pseudo_palette=&info->pseudo_pal;
909
910for(i=0;i<256;i++)
911info->palette_buffer[i]=PALETTE_BUFF_CLEAR;
912
913ret=request_irq(irq,s3c2410fb_irq,IRQF_DISABLED,pdev->name,info);
914if(ret){
915dev_err(&pdev->dev,"cannotgetirq%d-err%d\n",irq,ret);
916ret=-EBUSY;
917gotorelease_regs;
918}
919
920info->clk=clk_get(NULL,"lcd");
921if(!info->clk||IS_ERR(info->clk)){
922printk(KERN_ERR"failedtogetlcdclocksource\n");
923ret=-ENOENT;
924gotorelease_irq;
925}
926
927clk_enable(info->clk);
928dprintk("gotandenabledclock\n");
929
930msleep(1);
931
932info->clk_rate=clk_get_rate(info->clk);
933
934/*findmaximumrequiredmemorysizefordisplay*/
935for(i=0;i<mach_info->num_displays;i++){
936unsignedlongsmem_len=mach_info->displays[i].xres;
937
938smem_len*=mach_info->displays[i].yres;
939smem_len*=mach_info->displays[i].bpp;
940smem_len>>=3;
941if(fbinfo->fix.smem_len<smem_len)
942fbinfo->fix.smem_len=smem_len;
943}
944
945/*Initializevideomemory*/
946ret=s3c2410fb_map_video_memory(fbinfo);
947if(ret){
948printk(KERN_ERR"FailedtoallocatevideoRAM:%d\n",ret);
949ret=-ENOMEM;
950gotorelease_clock;
951}
952
953dprintk("gotvideomemory\n");
954
955fbinfo->var.xres=display->xres;
956fbinfo->var.yres=display->yres;
957fbinfo->var.bits_per_pixel=display->bpp;
958
959s3c2410fb_init_registers(fbinfo);
960
961s3c2410fb_check_var(&fbinfo->var,fbinfo);
962
963ret=s3c2410fb_cpufreq_register(info);
964if(ret<0){
965dev_err(&pdev->dev,"Failedtoregistercpufreq\n");
966gotofree_video_memory;
967}
968
969ret=register_framebuffer(fbinfo);
970if(ret<0){
971printk(KERN_ERR"Failedtoregisterframebufferdevice:%d\n",
972ret);
973gotofree_cpufreq;
974}
975
976/*createdevicefiles*/
977ret=device_create_file(&pdev->dev,&dev_attr_debug);
978if(ret){
979printk(KERN_ERR"failedtoadddebugattribute\n");
980}
981
982printk(KERN_INFO"fb%d:%sframebufferdevice\n",
983fbinfo->node,fbinfo->fix.id);
984
985return0;
986
987free_cpufreq:
988s3c2410fb_cpufreq_deregister(info);
989free_video_memory:
990s3c2410fb_unmap_video_memory(fbinfo);
991release_clock:
992clk_disable(info->clk);
993clk_put(info->clk);
994release_irq:
995free_irq(irq,info);
996release_regs:
997iounmap(info->io);
998release_mem:
999release_resource(info->mem);
1000kfree(info->mem);
1001dealloc_fb:
1002platform_set_drvdata(pdev,NULL);
1003framebuffer_release(fbinfo);
1004returnret;
1005}
[code]817staticint__devinits3c24xxfb_probe(structplatform_device*pdev,
818enums3c_drv_typedrv_type)
819{
820structs3c2410fb_info*info;
821structs3c2410fb_display*display;
822structfb_info*fbinfo;
823structs3c2410fb_mach_info*mach_info;
824structresource*res;
825intret;
826intirq;
827inti;
828intsize;
829u32lcdcon1;
830
831mach_info=pdev->dev.platform_data;
832if(mach_info==NULL){
833dev_err(&pdev->dev,
834"noplatformdataforlcd,cannotattach\n");
835return-EINVAL;
836}
837
838if(mach_info->default_display>=mach_info->num_displays){
839dev_err(&pdev->dev,"defaultis%dbutonly%ddisplays\n",
840mach_info->default_display,mach_info->num_displays);
841return-EINVAL;
842}
843
844display=mach_info->displays+mach_info->default_display;
845
846irq=platform_get_irq(pdev,0);
847if(irq<0){
848dev_err(&pdev->dev,"noirqfordevice\n");
849return-ENOENT;
850}
851
852fbinfo=framebuffer_alloc(sizeof(structs3c2410fb_info),&pdev->dev);
853if(!fbinfo)
854return-ENOMEM;
855
856platform_set_drvdata(pdev,fbinfo);
857
858info=fbinfo->par;
859info->dev=&pdev->dev;
860info->drv_type=drv_type;
861
862res=platform_get_resource(pdev,IORESOURCE_MEM,0);
863if(res==NULL){
864dev_err(&pdev->dev,"failedtogetmemoryregisters\n");
865ret=-ENXIO;
866gotodealloc_fb;
867}
868
869size=(res->end-res->start)+1;
870info->mem=request_mem_region(res->start,size,pdev->name);
871if(info->mem==NULL){
872dev_err(&pdev->dev,"failedtogetmemoryregion\n");
873ret=-ENOENT;
874gotodealloc_fb;
875}
876
877info->io=ioremap(res->start,size);
878if(info->io==NULL){
879dev_err(&pdev->dev,"ioremap()ofregistersfailed\n");
880ret=-ENXIO;
881gotorelease_mem;
882}
883
884info->irq_base=info->io+((drv_type==DRV_S3C2412)?S3C2412_LCDINTBASE:S3C2410_LCDINTBASE);
885
886dprintk("devinit\n");
887
888strcpy(fbinfo->fix.id,driver_name);
889
890/*Stopthevideo*/
891lcdcon1=readl(info->io+S3C2410_LCDCON1);
892writel(lcdcon1&~S3C2410_LCDCON1_ENVID,info->io+S3C2410_LCDCON1);
893
894fbinfo->fix.type=FB_TYPE_PACKED_PIXELS;
895fbinfo->fix.type_aux=0;
896fbinfo->fix.xpanstep=0;
897fbinfo->fix.ypanstep=0;
898fbinfo->fix.ywrapstep=0;
899fbinfo->fix.accel=FB_ACCEL_NONE;
900
901fbinfo->var.nonstd=0;
902fbinfo->var.activate=FB_ACTIVATE_NOW;
903fbinfo->var.accel_flags=0;
904fbinfo->var.vmode=FB_VMODE_NONINTERLACED;
905
906fbinfo->fbops=&s3c2410fb_ops;
907fbinfo->flags=FBINFO_FLAG_DEFAULT;
908fbinfo->pseudo_palette=&info->pseudo_pal;
909
910for(i=0;i<256;i++)
911info->palette_buffer[i]=PALETTE_BUFF_CLEAR;
912
913ret=request_irq(irq,s3c2410fb_irq,IRQF_DISABLED,pdev->name,info);
914if(ret){
915dev_err(&pdev->dev,"cannotgetirq%d-err%d\n",irq,ret);
916ret=-EBUSY;
917gotorelease_regs;
918}
919
920info->clk=clk_get(NULL,"lcd");
921if(!info->clk||IS_ERR(info->clk)){
922printk(KERN_ERR"failedtogetlcdclocksource\n");
923ret=-ENOENT;
924gotorelease_irq;
925}
926
927clk_enable(info->clk);
928dprintk("gotandenabledclock\n");
929
930msleep(1);
931
932info->clk_rate=clk_get_rate(info->clk);
933
934/*findmaximumrequiredmemorysizefordisplay*/
935for(i=0;i<mach_info->num_displays;i++){
936unsignedlongsmem_len=mach_info->displays[i].xres;
937
938smem_len*=mach_info->displays[i].yres;
939smem_len*=mach_info->displays[i].bpp;
940smem_len>>=3;
941if(fbinfo->fix.smem_len<smem_len)
942fbinfo->fix.smem_len=smem_len;
943}
944
945/*Initializevideomemory*/
946ret=s3c2410fb_map_video_memory(fbinfo);
947if(ret){
948printk(KERN_ERR"FailedtoallocatevideoRAM:%d\n",ret);
949ret=-ENOMEM;
950gotorelease_clock;
951}
952
953dprintk("gotvideomemory\n");
954
955fbinfo->var.xres=display->xres;
956fbinfo->var.yres=display->yres;
957fbinfo->var.bits_per_pixel=display->bpp;
958
959s3c2410fb_init_registers(fbinfo);
960
961s3c2410fb_check_var(&fbinfo->var,fbinfo);
962
963ret=s3c2410fb_cpufreq_register(info);
964if(ret<0){
965dev_err(&pdev->dev,"Failedtoregistercpufreq\n");
966gotofree_video_memory;
967}
968
969ret=register_framebuffer(fbinfo);
970if(ret<0){
971printk(KERN_ERR"Failedtoregisterframebufferdevice:%d\n",
972ret);
973gotofree_cpufreq;
974}
975
976/*createdevicefiles*/
977ret=device_create_file(&pdev->dev,&dev_attr_debug);
978if(ret){
979printk(KERN_ERR"failedtoadddebugattribute\n");
980}
981
982printk(KERN_INFO"fb%d:%sframebufferdevice\n",
983fbinfo->node,fbinfo->fix.id);
984
985return0;
986
987free_cpufreq:
988s3c2410fb_cpufreq_deregister(info);
989free_video_memory:
990s3c2410fb_unmap_video_memory(fbinfo);
991release_clock:
992clk_disable(info->clk);
993clk_put(info->clk);
994release_irq:
995free_irq(irq,info);
996release_regs:
997iounmap(info->io);
998release_mem:
999release_resource(info->mem);
1000kfree(info->mem);
1001dealloc_fb:
1002platform_set_drvdata(pdev,NULL);
1003framebuffer_release(fbinfo);
1004returnret;
1005}

820行,定义了s3c2410fb_info结构体指针变量info。[/code]
821行,定义了s3c2410fb_display结构体指针变量display。

822行,定义了fb_info结构体指针变量fbinfo。

823行,定义了s3c2410fb_mach_info结构体指针变量mach_info。

831行,由platform数据取得mach_info。

844行,由match_info得到display。

846行,取得中断号。

852行,调用framebuffer_alloc创建fb_info结构体变量fbinfo。fb_info结构体体是LCD驱动的核心数据结构。注意传递给framebuffer_alloc函数的第一个参数是sizeof(structs3c2410fb_info),即s3c2410fb_info结构体的大小,通过分析framebuffer_alloc函数的源码,可知,该函数除了为fb_info分配的内存空间,还多分配了第二个参数指定大小的空间,并将fb_info.par指定多分配出来的这个空间。

856行,将fbinfo保存在驱动私有数据中,以方便以后使用。

858行,将fbinfo->par指向的s3c2410fb_info结构体空间赋值给info变量。

862行,取得LCD控制器的I/O内存资源信息。

870行,调用request_mem_region取得I/O内存,这个I/O内存对应LCD控制器的寄存器集,而不是Framebuffer。

877行,通过ioremap函数得到I/O内存的虚拟地址空间,起始地址保存在fbinfo->io中。

884行,取得LCDInterruptPendingRegister寄存器的地址保存在info->irq_base中。

891-892行,通过将LCDCON1寄存器的第0位设置为0,禁用LCD。

894-908行,初始化fbinfo。其中,特别需要注意的是906行,设置fbinfo->fbops为3c2410fb_ops

910-911行,将info->palette_buffer清0,info->palette_buffer对应S3C2410内部的256*16的调色板内存。

913行,申请中断,设置中断处理函数为s3c2410fb_irq。

920行,取得LCD时钟。

927行,使能LCD时钟。

932行,取得LCD时钟频率。

935-943行,计算需要的最大显存大小。

946行,调用s3c2410fb_map_video_memory函数申请以DMA方式访问的帧缓冲区(Framebuffer)空间。这个函数我们在后面再仔细分析。

959行,调用s3c2410fb_init_registers函数初始化LCD控制器的各个寄存器,这个函数我们在后面再仔细分析。

961行,调用s3c2410fb_check_var函数检查相关变量是否符合要求。这是framebuffer驱动要求必须进行的一个检查。这个函数我们在后面再仔细分析。

963行,s3c2410fb_cpufreq_register这个函数实现变频功能,涉及Linuxcupfreq(变频)机制。根据宏CONFIG_CPU_FREQ是否被定义,可以直接返回0,也可以具体实现变频功能。

969行,调用register_framebuffer注册fb_info结构。

977行,调用device_create_file创建/sys系统文件。

s3c2410fb_map_video_memory函数定义如下:

[cpp]viewplaincopyprint?626/*
627*s3c2410fb_map_video_memory():
628*AllocatestheDRAMmemoryfortheframebuffer.Thisbufferis
629*remappedintoanon-cached,non-buffered,memoryregionto
630*allowpaletteandpixelwritestooccurwithoutflushingthe
631*cache.Oncethisareaisremapped,allvirtualmemory
632*accesstothevideomemoryshouldoccuratthenewregion.
633*/
634837837staticint__devinits3c2410fb_map_video_memory(structfb_info*info)
635{
636structs3c2410fb_info*fbi=info->par;
637dma_addr_tmap_dma;
638unsignedmap_size=PAGE_ALIGN(info->fix.smem_len);
639
640dprintk("map_video_memory(fbi=%p)map_size%u\n",fbi,map_size);
641
642info->screen_base=dma_alloc_writecombine(fbi->dev,map_size,
643&map_dma,GFP_KERNEL);
644
645if(info->screen_base){
646/*preventinitialgarbageonscreen*/
647dprintk("map_video_memory:clear%p:%08x\n",
648info->screen_base,map_size);
649memset(info->screen_base,0x00,map_size);
650
651info->fix.smem_start=map_dma;
652
653dprintk("map_video_memory:dma=%08lxcpu=%psize=%08x\n",
654info->fix.smem_start,info->screen_base,map_size);
655}
656
657returninfo->screen_base?0:-ENOMEM;
658}
[code]626/*
627*s3c2410fb_map_video_memory():
628*AllocatestheDRAMmemoryfortheframebuffer.Thisbufferis
629*remappedintoanon-cached,non-buffered,memoryregionto
630*allowpaletteandpixelwritestooccurwithoutflushingthe
631*cache.Oncethisareaisremapped,allvirtualmemory
632*accesstothevideomemoryshouldoccuratthenewregion.
633*/
634837837staticint__devinits3c2410fb_map_video_memory(structfb_info*info)
635{
636structs3c2410fb_info*fbi=info->par;
637dma_addr_tmap_dma;
638unsignedmap_size=PAGE_ALIGN(info->fix.smem_len);
639
640dprintk("map_video_memory(fbi=%p)map_size%u\n",fbi,map_size);
641
642info->screen_base=dma_alloc_writecombine(fbi->dev,map_size,
643&map_dma,GFP_KERNEL);
644
645if(info->screen_base){
646/*preventinitialgarbageonscreen*/
647dprintk("map_video_memory:clear%p:%08x\n",
648info->screen_base,map_size);
649memset(info->screen_base,0x00,map_size);
650
651info->fix.smem_start=map_dma;
652
653dprintk("map_video_memory:dma=%08lxcpu=%psize=%08x\n",
654info->fix.smem_start,info->screen_base,map_size);
655}
656
657returninfo->screen_base?0:-ENOMEM;
658}

s3c2410fb_map_video_memory函数的作用是申请以DMA方式访问的帧缓冲区(Framebuffer)地址空间。[/code]
638行,从fb_info.fb_fix_screeninfo.smem_len的注释"Lengthofframebuffermem"可以看出,这里是取得以页对齐的帧缓冲区的大小保存在map_size变量中。

642行,从fb_info->screen_base的注释"Virtualaddress"可以看出,这里是通过调用dma_alloc_writecombine函数,分配以DMA方式访问的帧缓冲区空间(Framebuffer),并将帧缓冲区的虚拟地址起始值返回保存在fb_info->screen_base中。

649行,将帧缓冲区清0。

651行,从fb_info.fb_fix_screeninfo.smem_start的注释"Startofframebuffermem(physicaladdress)"可以看出,这里是把帧缓冲区的物理地址起始地址map_dma赋值给info->fix.smem_start。

下面看s3c2410fb_init_registers函数,该函数用于初始化LCD控制器:

[cpp]viewplaincopyprint?677/*
678*s3c2410fb_init_registers-InitialiseallLCD-relatedregisters
679*/
680staticints3c2410fb_init_registers(structfb_info*info)
681{
682structs3c2410fb_info*fbi=info->par;
683structs3c2410fb_mach_info*mach_info=fbi->dev->platform_data;
684unsignedlongflags;
685void__iomem*regs=fbi->io;
686void__iomem*tpal;
687void__iomem*lpcsel;
688
689if(is_s3c2412(fbi)){
690tpal=regs+S3C2412_TPAL;
691lpcsel=regs+S3C2412_TCONSEL;
692}else{
693tpal=regs+S3C2410_TPAL;
694lpcsel=regs+S3C2410_LPCSEL;
695}
696
697/*InitialiseLCDwithvaluesfromharet*/
698
699local_irq_save(flags);
700
701/*modifythegpio(s)withinterruptsset(bjd)*/
702
703modify_gpio(S3C2410_GPCUP,mach_info->gpcup,mach_info->gpcup_mask);
704modify_gpio(S3C2410_GPCCON,mach_info->gpccon,mach_info->gpccon_mask);
705modify_gpio(S3C2410_GPDUP,mach_info->gpdup,mach_info->gpdup_mask);
706modify_gpio(S3C2410_GPDCON,mach_info->gpdcon,mach_info->gpdcon_mask);
707
708local_irq_restore(flags);
709
710dprintk("LPCSEL=0x%08lx\n",mach_info->lpcsel);
711writel(mach_info->lpcsel,lpcsel);
712
713dprintk("replacingTPAL%08x\n",readl(tpal));
714
715/*ensuretemporarypalettedisabled*/
716writel(0x00,tpal);
717
718return0;
719}
[code]677/*
678*s3c2410fb_init_registers-InitialiseallLCD-relatedregisters
679*/
680staticints3c2410fb_init_registers(structfb_info*info)
681{
682structs3c2410fb_info*fbi=info->par;
683structs3c2410fb_mach_info*mach_info=fbi->dev->platform_data;
684unsignedlongflags;
685void__iomem*regs=fbi->io;
686void__iomem*tpal;
687void__iomem*lpcsel;
688
689if(is_s3c2412(fbi)){
690tpal=regs+S3C2412_TPAL;
691lpcsel=regs+S3C2412_TCONSEL;
692}else{
693tpal=regs+S3C2410_TPAL;
694lpcsel=regs+S3C2410_LPCSEL;
695}
696
697/*InitialiseLCDwithvaluesfromharet*/
698
699local_irq_save(flags);
700
701/*modifythegpio(s)withinterruptsset(bjd)*/
702
703modify_gpio(S3C2410_GPCUP,mach_info->gpcup,mach_info->gpcup_mask);
704modify_gpio(S3C2410_GPCCON,mach_info->gpccon,mach_info->gpccon_mask);
705modify_gpio(S3C2410_GPDUP,mach_info->gpdup,mach_info->gpdup_mask);
706modify_gpio(S3C2410_GPDCON,mach_info->gpdcon,mach_info->gpdcon_mask);
707
708local_irq_restore(flags);
709
710dprintk("LPCSEL=0x%08lx\n",mach_info->lpcsel);
711writel(mach_info->lpcsel,lpcsel);
712
713dprintk("replacingTPAL%08x\n",readl(tpal));
714
715/*ensuretemporarypalettedisabled*/
716writel(0x00,tpal);
717
718return0;
719}

685行,取得LCD控制器寄存器虚拟地址的起始地址,保存在regs变量中。[/code]
693行,取得临时调色板寄存器(TempPaletteRegister)的虚拟地址保存在tpal变量中。

694行,取得LPCSEL寄存器的地址,该寄存器用于控制中是否启动LPC3600模式。LPC3600是专用于三星LTS350Q1-PD1/2液晶屏的控制器。

699行,修改寄存器的值之前,先调用local_irq_save屏蔽中断,并将中断状态保存到flags变量中。

703-706行,调用modify_gpio函数设置GPC和GPD寄存器为LCD模式。

modify_gpio函数用于设置GPIO寄存器,注意第三个参数mask的作用是把要设置的位先清0。

[cpp]viewplaincopyprint?668staticinlinevoidmodify_gpio(void__iomem*reg,
669unsignedlongset,unsignedlongmask)
670{
671unsignedlongtmp;
672
673tmp=readl(reg)&~mask;
674writel(tmp|set,reg);
675}
[code]668staticinlinevoidmodify_gpio(void__iomem*reg,
669unsignedlongset,unsignedlongmask)
670{
671unsignedlongtmp;
672
673tmp=readl(reg)&~mask;
674writel(tmp|set,reg);
675}

708行,调用local_irq_restore恢复被屏蔽的中断。[/code]
711行,设置LPCSEL寄存器。

716行,清0并禁用临时调色板寄存器。

下面我们来看s3c2410fb_check_var函数,该函数用于对LCD可变参数进行检查,其定义如下:

[cpp]viewplaincopyprint?109/*
110*s3c2410fb_check_var():
111*Getthevideoparamsoutof'var'.Ifavaluedoesn'tfit,rounditup,
112*ifit'stoobig,return-EINVAL.
113*
114*/
115staticints3c2410fb_check_var(structfb_var_screeninfo*var,
116structfb_info*info)
117{
118structs3c2410fb_info*fbi=info->par;
119structs3c2410fb_mach_info*mach_info=fbi->dev->platform_data;
120structs3c2410fb_display*display=NULL;
121structs3c2410fb_display*default_display=mach_info->displays+
122mach_info->default_display;
123inttype=default_display->type;
124unsignedi;
125
126dprintk("check_var(var=%p,info=%p)\n",var,info);
127
128/*validatex/yresolution*/
129/*choosedefaultmodeifpossible*/
130if(var->yres==default_display->yres&&
131var->xres==default_display->xres&&
132var->bits_per_pixel==default_display->bpp)
133display=default_display;
134else
135for(i=0;i<mach_info->num_displays;i++)
136if(type==mach_info->displays[i].type&&
137var->yres==mach_info->displays[i].yres&&
138var->xres==mach_info->displays[i].xres&&
139var->bits_per_pixel==mach_info->displays[i].bpp){
140display=mach_info->displays+i;
141break;
142}
143
144if(!display){
145dprintk("wrongresolutionordepth%dx%dat%dbpp\n",
146var->xres,var->yres,var->bits_per_pixel);
147return-EINVAL;
148}
149
150/*itisalwaysthesizeasthedisplay*/
151var->xres_virtual=display->xres;
152var->yres_virtual=display->yres;
153var->height=display->height;
154var->width=display->width;
155
156/*copylcdsettings*/
157var->pixclock=display->pixclock;
158var->left_margin=display->left_margin;
159var->right_margin=display->right_margin;
160var->upper_margin=display->upper_margin;
161var->lower_margin=display->lower_margin;
162var->vsync_len=display->vsync_len;
163var->hsync_len=display->hsync_len;
164
165fbi->regs.lcdcon5=display->lcdcon5;
166/*setdisplaytype*/
167fbi->regs.lcdcon1=display->type;
168
169var->transp.offset=0;
170var->transp.length=0;
171/*setr/g/bpositions*/
172switch(var->bits_per_pixel){
173case1:
174case2:
175case4:
176var->red.offset=0;
177var->red.length=var->bits_per_pixel;
178var->green=var->red;
179var->blue=var->red;
180break;
181case8:
182if(display->type!=S3C2410_LCDCON1_TFT){
183/*8bpp332*/
184var->red.length=3;
185var->red.offset=5;
186var->green.length=3;
187var->green.offset=2;
188var->blue.length=2;
189var->blue.offset=0;
190}else{
191var->red.offset=0;
192var->red.length=8;
193var->green=var->red;
194var->blue=var->red;
195}
196break;
197case12:
198/*12bpp444*/
199var->red.length=4;
200var->red.offset=8;
201var->green.length=4;
202var->green.offset=4;
203var->blue.length=4;
204var->blue.offset=0;
205break;
206
207default:
208case16:
209if(display->lcdcon5&S3C2410_LCDCON5_FRM565){
210/*16bpp,565format*/
211var->red.offset=11;
212var->green.offset=5;
213var->blue.offset=0;
214var->red.length=5;
215var->green.length=6;
216var->blue.length=5;
217}else{
218/*16bpp,5551format*/
219var->red.offset=11;
220var->green.offset=6;
221var->blue.offset=1;
222var->red.length=5;
223var->green.length=5;
224var->blue.length=5;
225}
226break;
227case32:
228/*24bpp888and8dummy*/
229var->red.length=8;
230var->red.offset=16;
231var->green.length=8;
232var->green.offset=8;
233var->blue.length=8;
234var->blue.offset=0;
235break;
236}
237return0;
238}
[code]109/*
110*s3c2410fb_check_var():
111*Getthevideoparamsoutof'var'.Ifavaluedoesn'tfit,rounditup,
112*ifit'stoobig,return-EINVAL.
113*
114*/
115staticints3c2410fb_check_var(structfb_var_screeninfo*var,
116structfb_info*info)
117{
118structs3c2410fb_info*fbi=info->par;
119structs3c2410fb_mach_info*mach_info=fbi->dev->platform_data;
120structs3c2410fb_display*display=NULL;
121structs3c2410fb_display*default_display=mach_info->displays+
122mach_info->default_display;
123inttype=default_display->type;
124unsignedi;
125
126dprintk("check_var(var=%p,info=%p)\n",var,info);
127
128/*validatex/yresolution*/
129/*choosedefaultmodeifpossible*/
130if(var->yres==default_display->yres&&
131var->xres==default_display->xres&&
132var->bits_per_pixel==default_display->bpp)
133display=default_display;
134else
135for(i=0;i<mach_info->num_displays;i++)
136if(type==mach_info->displays[i].type&&
137var->yres==mach_info->displays[i].yres&&
138var->xres==mach_info->displays[i].xres&&
139var->bits_per_pixel==mach_info->displays[i].bpp){
140display=mach_info->displays+i;
141break;
142}
143
144if(!display){
145dprintk("wrongresolutionordepth%dx%dat%dbpp\n",
146var->xres,var->yres,var->bits_per_pixel);
147return-EINVAL;
148}
149
150/*itisalwaysthesizeasthedisplay*/
151var->xres_virtual=display->xres;
152var->yres_virtual=display->yres;
153var->height=display->height;
154var->width=display->width;
155
156/*copylcdsettings*/
157var->pixclock=display->pixclock;
158var->left_margin=display->left_margin;
159var->right_margin=display->right_margin;
160var->upper_margin=display->upper_margin;
161var->lower_margin=display->lower_margin;
162var->vsync_len=display->vsync_len;
163var->hsync_len=display->hsync_len;
164
165fbi->regs.lcdcon5=display->lcdcon5;
166/*setdisplaytype*/
167fbi->regs.lcdcon1=display->type;
168
169var->transp.offset=0;
170var->transp.length=0;
171/*setr/g/bpositions*/
172switch(var->bits_per_pixel){
173case1:
174case2:
175case4:
176var->red.offset=0;
177var->red.length=var->bits_per_pixel;
178var->green=var->red;
179var->blue=var->red;
180break;
181case8:
182if(display->type!=S3C2410_LCDCON1_TFT){
183/*8bpp332*/
184var->red.length=3;
185var->red.offset=5;
186var->green.length=3;
187var->green.offset=2;
188var->blue.length=2;
189var->blue.offset=0;
190}else{
191var->red.offset=0;
192var->red.length=8;
193var->green=var->red;
194var->blue=var->red;
195}
196break;
197case12:
198/*12bpp444*/
199var->red.length=4;
200var->red.offset=8;
201var->green.length=4;
202var->green.offset=4;
203var->blue.length=4;
204var->blue.offset=0;
205break;
206
207default:
208case16:
209if(display->lcdcon5&S3C2410_LCDCON5_FRM565){
210/*16bpp,565format*/
211var->red.offset=11;
212var->green.offset=5;
213var->blue.offset=0;
214var->red.length=5;
215var->green.length=6;
216var->blue.length=5;
217}else{
218/*16bpp,5551format*/
219var->red.offset=11;
220var->green.offset=6;
221var->blue.offset=1;
222var->red.length=5;
223var->green.length=5;
224var->blue.length=5;
225}
226break;
227case32:
228/*24bpp888and8dummy*/
229var->red.length=8;
230var->red.offset=16;
231var->green.length=8;
232var->green.offset=8;
233var->blue.length=8;
234var->blue.offset=0;
235break;
236}
237return0;
238}

128-148行,验证x/y解析度。如果没有正好匹配的设置,则返回错误。[/code]
151-154行,设置屏幕的虚拟解析像素和高度宽度。

157-163行,设置时钟像素,行、帧切换值,水平同步和垂直同步长度值。

165行,配置LCDCON5寄存器。

167行,通过LCDCON1配置LCD类型。

169-170行,设置透明度。

172-236行,根据色位模式(BPP)来设置可变参数中R、G、B的颜色位域。

s3c24xxfb_probe函数的第963行,调用s3c2410fb_cpufreq_register函数实现变频功能。根据宏CONFIG_CPU_FREQ是否被定义,可以直接返回0,也可以具体实现变频功能。

下面我们要分析的中LCD中断处理函数s3c2410fb_irq:

[cpp]viewplaincopyprint?747staticirqreturn_ts3c2410fb_irq(intirq,void*dev_id)
748{
749structs3c2410fb_info*fbi=dev_id;
750void__iomem*irq_base=fbi->irq_base;
751unsignedlonglcdirq=readl(irq_base+S3C24XX_LCDINTPND);
752
753if(lcdirq&S3C2410_LCDINT_FRSYNC){
754if(fbi->palette_ready)
755s3c2410fb_write_palette(fbi);
756
757writel(S3C2410_LCDINT_FRSYNC,irq_base+S3C24XX_LCDINTPND);
758writel(S3C2410_LCDINT_FRSYNC,irq_base+S3C24XX_LCDSRCPND);
759}
760
761returnIRQ_HANDLED;
762}
[code]747staticirqreturn_ts3c2410fb_irq(intirq,void*dev_id)
748{
749structs3c2410fb_info*fbi=dev_id;
750void__iomem*irq_base=fbi->irq_base;
751unsignedlonglcdirq=readl(irq_base+S3C24XX_LCDINTPND);
752
753if(lcdirq&S3C2410_LCDINT_FRSYNC){
754if(fbi->palette_ready)
755s3c2410fb_write_palette(fbi);
756
757writel(S3C2410_LCDINT_FRSYNC,irq_base+S3C24XX_LCDINTPND);
758writel(S3C2410_LCDINT_FRSYNC,irq_base+S3C24XX_LCDSRCPND);
759}
760
761returnIRQ_HANDLED;
762}

749行,注意s3c2410fb_info实例以dev_id参数的形式传递进来,注意理解dev_id的用法。[/code]
751行,读取LCDINTPND寄存器(LCDInterruptPendingRegister)的值到lcdirq中。

753行,如果LCDINTPND寄存器的第1位为1,说明LCD触发了中断。

754行,如果fbi->palette_ready等于1,表明需要更新fbi->palette_buffer中的调色板信息到LCD控制器的调色板内存区。相反,如果fbi->palette_ready等于0,则表明不需要更新调色板内存区。

755行,调用s3c2410fb_write_palette函数将fbi->palette_buffer中的信息写入LCD控制器的调色板内存空间中。

757行,设置LCDINTPND寄存器,表明已插入中断请求,这里不理解经过了753行的判断,应该已经设置好了,这里为什么再设置一遍?

758行,设置LCDSRCPND寄存器,表明已插入中断请求。

s3c2410fb_write_palette函数用于填充调色板,其定义如下:

[cpp]viewplaincopyprint?721staticvoids3c2410fb_write_palette(structs3c2410fb_info*fbi)
722{
723unsignedinti;
724void__iomem*regs=fbi->io;
725
726fbi->palette_ready=0;
727
728for(i=0;i<256;i++){
729unsignedlongent=fbi->palette_buffer[i];
730if(ent==PALETTE_BUFF_CLEAR)
731continue;
732
733writel(ent,regs+S3C2410_TFTPAL(i));
734
735/*itseemstheonlywaytoknowexactly
736*ifthepalettewroteok,istocheck
737*toseeifthevalueverifiesok
738*/
739
740if(readw(regs+S3C2410_TFTPAL(i))==ent)
741fbi->palette_buffer[i]=PALETTE_BUFF_CLEAR;
742else
743fbi->palette_ready=1;/*retry*/
744}
745}
[code]721staticvoids3c2410fb_write_palette(structs3c2410fb_info*fbi)
722{
723unsignedinti;
724void__iomem*regs=fbi->io;
725
726fbi->palette_ready=0;
727
728for(i=0;i<256;i++){
729unsignedlongent=fbi->palette_buffer[i];
730if(ent==PALETTE_BUFF_CLEAR)
731continue;
732
733writel(ent,regs+S3C2410_TFTPAL(i));
734
735/*itseemstheonlywaytoknowexactly
736*ifthepalettewroteok,istocheck
737*toseeifthevalueverifiesok
738*/
739
740if(readw(regs+S3C2410_TFTPAL(i))==ent)
741fbi->palette_buffer[i]=PALETTE_BUFF_CLEAR;
742else
743fbi->palette_ready=1;/*retry*/
744}
745}

728-744行,将fbi->palette_buffer中的调色板信息写到LCD控制器的调色板内存区。[/code]

三、platform_driverremove函数分析

s3c2410fb_remove函数定义如下:

[cpp]viewplaincopyprint?1021staticint__devexits3c2410fb_remove(structplatform_device*pdev)
1022{
1023structfb_info*fbinfo=platform_get_drvdata(pdev);
1024structs3c2410fb_info*info=fbinfo->par;
1025intirq;
1026
1027unregister_framebuffer(fbinfo);
1028s3c2410fb_cpufreq_deregister(info);
1029
1030s3c2410fb_lcd_enable(info,0);
1031msleep(1);
1032
1033s3c2410fb_unmap_video_memory(fbinfo);
1034
1035if(info->clk){
1036clk_disable(info->clk);
1037clk_put(info->clk);
1038info->clk=NULL;
1039}
1040
1041irq=platform_get_irq(pdev,0);
1042free_irq(irq,info);
1043
1044iounmap(info->io);
1045
1046release_resource(info->mem);
1047kfree(info->mem);
1048
1049platform_set_drvdata(pdev,NULL);
1050framebuffer_release(fbinfo);
1051
1052return0;
1053}
[code]1021staticint__devexits3c2410fb_remove(structplatform_device*pdev)
1022{
1023structfb_info*fbinfo=platform_get_drvdata(pdev);
1024structs3c2410fb_info*info=fbinfo->par;
1025intirq;
1026
1027unregister_framebuffer(fbinfo);
1028s3c2410fb_cpufreq_deregister(info);
1029
1030s3c2410fb_lcd_enable(info,0);
1031msleep(1);
1032
1033s3c2410fb_unmap_video_memory(fbinfo);
1034
1035if(info->clk){
1036clk_disable(info->clk);
1037clk_put(info->clk);
1038info->clk=NULL;
1039}
1040
1041irq=platform_get_irq(pdev,0);
1042free_irq(irq,info);
1043
1044iounmap(info->io);
1045
1046release_resource(info->mem);
1047kfree(info->mem);
1048
1049platform_set_drvdata(pdev,NULL);
1050framebuffer_release(fbinfo);
1051
1052return0;
1053}

1027行,调用unregister_framebuffer,注销fb_info结构实例。[/code]
1028行,注销变频。

1030行,停止LCD控制器的工作。

1031行,延迟1毫秒,因为停止LCD控制器的工作需要一定时间。

1033行,释放帧缓冲区。

1035-1039,释放时钟资源。

1042行,释放中断号。

1044行,取消对LCDI/O内存的映射。

1046-1047,释放LCDI/O内存。

1050行,释放fb_info空间。

s3c2410fb_lcd_enable函数定义如下:

[cpp]viewplaincopyprint?530staticvoids3c2410fb_lcd_enable(structs3c2410fb_info*fbi,intenable)
531{
532unsignedlongflags;
533
534local_irq_save(flags);
535
536if(enable)
537fbi->regs.lcdcon1|=S3C2410_LCDCON1_ENVID;
538else
539fbi->regs.lcdcon1&=~S3C2410_LCDCON1_ENVID;
540
541writel(fbi->regs.lcdcon1,fbi->io+S3C2410_LCDCON1);
542
543local_irq_restore(flags);
544}
[code]530staticvoids3c2410fb_lcd_enable(structs3c2410fb_info*fbi,intenable)
531{
532unsignedlongflags;
533
534local_irq_save(flags);
535
536if(enable)
537fbi->regs.lcdcon1|=S3C2410_LCDCON1_ENVID;
538else
539fbi->regs.lcdcon1&=~S3C2410_LCDCON1_ENVID;
540
541writel(fbi->regs.lcdcon1,fbi->io+S3C2410_LCDCON1);
542
543local_irq_restore(flags);
544}

536-537行,将LCDCON1寄存器的第0位设置为1,使能LCD控制器。[/code]
538-539行,将LCDCON1寄存器的第0位设置为0,禁用LCD控制器。


四、platform_driver的电源管理支持

如果定义了CONFIG_PM宏,则需要platform_driver提供suspend和resume函数以支持电源管理功能。

[cpp]viewplaincopyprint?1057/*suspendandresumesupportforthelcdcontroller*/
1058staticints3c2410fb_suspend(structplatform_device*dev,pm_message_tstate)
1059{
1060structfb_info*fbinfo=platform_get_drvdata(dev);
1061structs3c2410fb_info*info=fbinfo->par;
1062
1063s3c2410fb_lcd_enable(info,0);
1064
1065/*sleepbeforedisablingtheclock,weneedtoensure
1066*theLCDDMAengineisnotgoingtogetbackonthebus
1067*beforetheclockgoesoffagain(bjd)*/
1068
1069msleep(1);
1070clk_disable(info->clk);
1071
1072return0;
1073}
[code]1057/*suspendandresumesupportforthelcdcontroller*/
1058staticints3c2410fb_suspend(structplatform_device*dev,pm_message_tstate)
1059{
1060structfb_info*fbinfo=platform_get_drvdata(dev);
1061structs3c2410fb_info*info=fbinfo->par;
1062
1063s3c2410fb_lcd_enable(info,0);
1064
1065/*sleepbeforedisablingtheclock,weneedtoensure
1066*theLCDDMAengineisnotgoingtogetbackonthebus
1067*beforetheclockgoesoffagain(bjd)*/
1068
1069msleep(1);
1070clk_disable(info->clk);
1071
1072return0;
1073}

1063行,禁用LCD控制器。[/code]
1070行,关闭时钟。

s3c2410fb_resume函数定义如下:

[cpp]viewplaincopyprint?1075staticints3c2410fb_resume(structplatform_device*dev)
1076{
1077structfb_info*fbinfo=platform_get_drvdata(dev);
1078structs3c2410fb_info*info=fbinfo->par;
1079
1080clk_enable(info->clk);
1081msleep(1);
1082
1083s3c2410fb_init_registers(fbinfo);
1084
1085/*re-activateourdisplayafterresume*/
1086s3c2410fb_activate_var(fbinfo);
1087s3c2410fb_blank(FB_BLANK_UNBLANK,fbinfo);
1088
1089return0;
1090}
[code]1075staticints3c2410fb_resume(structplatform_device*dev)
1076{
1077structfb_info*fbinfo=platform_get_drvdata(dev);
1078structs3c2410fb_info*info=fbinfo->par;
1079
1080clk_enable(info->clk);
1081msleep(1);
1082
1083s3c2410fb_init_registers(fbinfo);
1084
1085/*re-activateourdisplayafterresume*/
1086s3c2410fb_activate_var(fbinfo);
1087s3c2410fb_blank(FB_BLANK_UNBLANK,fbinfo);
1088
1089return0;
1090}

1080行,使能时钟。[/code]
1083行,重新初始化LCD寄存器。

1086行,重新激活fb_info的所有参数配置,这个函数在第五部分分析。

1087行,让LCD显示空白,这个函数在第五部分分析。


五、fb_ops函数集的实现

S3C2410LCD驱动程序的fb_ops函数集定义如下:

[cpp]viewplaincopyprint?615staticstructfb_opss3c2410fb_ops={
616.owner=THIS_MODULE,
617.fb_check_var=s3c2410fb_check_var,
618.fb_set_par=s3c2410fb_set_par,
619.fb_blank=s3c2410fb_blank,
620.fb_setcolreg=s3c2410fb_setcolreg,
621.fb_fillrect=cfb_fillrect,
622.fb_copyarea=cfb_copyarea,
623.fb_imageblit=cfb_imageblit,
624};
[code]615staticstructfb_opss3c2410fb_ops={
616.owner=THIS_MODULE,
617.fb_check_var=s3c2410fb_check_var,
618.fb_set_par=s3c2410fb_set_par,
619.fb_blank=s3c2410fb_blank,
620.fb_setcolreg=s3c2410fb_setcolreg,
621.fb_fillrect=cfb_fillrect,
622.fb_copyarea=cfb_copyarea,
623.fb_imageblit=cfb_imageblit,
624};

617行,s3c2410fb_check_var函数我们前面已经分析过了。[/code]
下面看s3c2410fb_set_par函数的实现:

[cpp]viewplaincopyprint?416/*
417*s3c2410fb_set_par-Altersthehardwarestate.
418*@info:framebufferstructurethatrepresentsasingleframebuffer
419*
420*/
421staticints3c2410fb_set_par(structfb_info*info)
422{
423structfb_var_screeninfo*var=&info->var;
424
425switch(var->bits_per_pixel){
426case32:
427case16:
428case12:
429info->fix.visual=FB_VISUAL_TRUECOLOR;
430break;
431case1:
432info->fix.visual=FB_VISUAL_MONO01;
433break;
434default:
435info->fix.visual=FB_VISUAL_PSEUDOCOLOR;
436break;
437}
438
439info->fix.line_length=(var->xres_virtual*var->bits_per_pixel)/8;
440
441/*activatethisnewconfiguration*/
442
443s3c2410fb_activate_var(info);
444return0;
445}
[code]416/*
417*s3c2410fb_set_par-Altersthehardwarestate.
418*@info:framebufferstructurethatrepresentsasingleframebuffer
419*
420*/
421staticints3c2410fb_set_par(structfb_info*info)
422{
423structfb_var_screeninfo*var=&info->var;
424
425switch(var->bits_per_pixel){
426case32:
427case16:
428case12:
429info->fix.visual=FB_VISUAL_TRUECOLOR;
430break;
431case1:
432info->fix.visual=FB_VISUAL_MONO01;
433break;
434default:
435info->fix.visual=FB_VISUAL_PSEUDOCOLOR;
436break;
437}
438
439info->fix.line_length=(var->xres_virtual*var->bits_per_pixel)/8;
440
441/*activatethisnewconfiguration*/
442
443s3c2410fb_activate_var(info);
444return0;
445}

425-439行,根据info->var调整info->fix的值。[/code]
443行,调用s3c2410fb_activate_var函数激活info->var指定的配置。

[cpp]viewplaincopyprint?361/*s3c2410fb_activate_var
362*
363*activate(set)thecontrollerfromthegivenframebuffer
364*information
365*/
366staticvoids3c2410fb_activate_var(structfb_info*info)
367{
368structs3c2410fb_info*fbi=info->par;
369void__iomem*regs=fbi->io;
370inttype=fbi->regs.lcdcon1&S3C2410_LCDCON1_TFT;
371structfb_var_screeninfo*var=&info->var;
372intclkdiv;
373
374clkdiv=DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi,var->pixclock),2);
375
376dprintk("%s:var->xres=%d\n",__func__,var->xres);
377dprintk("%s:var->yres=%d\n",__func__,var->yres);
378dprintk("%s:var->bpp=%d\n",__func__,var->bits_per_pixel);
379
380if(type==S3C2410_LCDCON1_TFT){
381s3c2410fb_calculate_tft_lcd_regs(info,&fbi->regs);
382--clkdiv;
383if(clkdiv<0)
384clkdiv=0;
385}else{
386s3c2410fb_calculate_stn_lcd_regs(info,&fbi->regs);
387if(clkdiv<2)
388clkdiv=2;
389}
390
391fbi->regs.lcdcon1|=S3C2410_LCDCON1_CLKVAL(clkdiv);
392
393/*writenewregisters*/
394
395dprintk("newregisterset:\n");
396dprintk("lcdcon[1]=0x%08lx\n",fbi->regs.lcdcon1);
397dprintk("lcdcon[2]=0x%08lx\n",fbi->regs.lcdcon2);
398dprintk("lcdcon[3]=0x%08lx\n",fbi->regs.lcdcon3);
399dprintk("lcdcon[4]=0x%08lx\n",fbi->regs.lcdcon4);
400dprintk("lcdcon[5]=0x%08lx\n",fbi->regs.lcdcon5);
401
402writel(fbi->regs.lcdcon1&~S3C2410_LCDCON1_ENVID,
403regs+S3C2410_LCDCON1);
404writel(fbi->regs.lcdcon2,regs+S3C2410_LCDCON2);
405writel(fbi->regs.lcdcon3,regs+S3C2410_LCDCON3);
406writel(fbi->regs.lcdcon4,regs+S3C2410_LCDCON4);
407writel(fbi->regs.lcdcon5,regs+S3C2410_LCDCON5);
408
409/*setlcdaddresspointers*/
410s3c2410fb_set_lcdaddr(info);
411
412fbi->regs.lcdcon1|=S3C2410_LCDCON1_ENVID,
413writel(fbi->regs.lcdcon1,regs+S3C2410_LCDCON1);
414}
[code]361/*s3c2410fb_activate_var
362*
363*activate(set)thecontrollerfromthegivenframebuffer
364*information
365*/
366staticvoids3c2410fb_activate_var(structfb_info*info)
367{
368structs3c2410fb_info*fbi=info->par;
369void__iomem*regs=fbi->io;
370inttype=fbi->regs.lcdcon1&S3C2410_LCDCON1_TFT;
371structfb_var_screeninfo*var=&info->var;
372intclkdiv;
373
374clkdiv=DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi,var->pixclock),2);
375
376dprintk("%s:var->xres=%d\n",__func__,var->xres);
377dprintk("%s:var->yres=%d\n",__func__,var->yres);
378dprintk("%s:var->bpp=%d\n",__func__,var->bits_per_pixel);
379
380if(type==S3C2410_LCDCON1_TFT){
381s3c2410fb_calculate_tft_lcd_regs(info,&fbi->regs);
382--clkdiv;
383if(clkdiv<0)
384clkdiv=0;
385}else{
386s3c2410fb_calculate_stn_lcd_regs(info,&fbi->regs);
387if(clkdiv<2)
388clkdiv=2;
389}
390
391fbi->regs.lcdcon1|=S3C2410_LCDCON1_CLKVAL(clkdiv);
392
393/*writenewregisters*/
394
395dprintk("newregisterset:\n");
396dprintk("lcdcon[1]=0x%08lx\n",fbi->regs.lcdcon1);
397dprintk("lcdcon[2]=0x%08lx\n",fbi->regs.lcdcon2);
398dprintk("lcdcon[3]=0x%08lx\n",fbi->regs.lcdcon3);
399dprintk("lcdcon[4]=0x%08lx\n",fbi->regs.lcdcon4);
400dprintk("lcdcon[5]=0x%08lx\n",fbi->regs.lcdcon5);
401
402writel(fbi->regs.lcdcon1&~S3C2410_LCDCON1_ENVID,
403regs+S3C2410_LCDCON1);
404writel(fbi->regs.lcdcon2,regs+S3C2410_LCDCON2);
405writel(fbi->regs.lcdcon3,regs+S3C2410_LCDCON3);
406writel(fbi->regs.lcdcon4,regs+S3C2410_LCDCON4);
407writel(fbi->regs.lcdcon5,regs+S3C2410_LCDCON5);
408
409/*setlcdaddresspointers*/
410s3c2410fb_set_lcdaddr(info);
411
412fbi->regs.lcdcon1|=S3C2410_LCDCON1_ENVID,
413writel(fbi->regs.lcdcon1,regs+S3C2410_LCDCON1);
414}

370行,获取液晶屏类型。[/code]
374行,计算LCDCON1寄存器用到的CLKVAL值(从391行可以看出)。根据S3C2410Datasheet,计算公式如下:

STN:VCLK=HCLK/(CLKVALx2)(CLKVAL>=2)

TFT:VCLK=HCLK/[(CLKVAL+1)x2](CLKVAL>=0)

DIV_ROUND_UP宏定义在include/linux/kernel.h文件中,其定义如下:

#defineDIV_ROUND_UP(n,d)(((n)+(d)-1)/(d))

s3c2410fb_calc_pixclk函数定义如下:

[cpp]viewplaincopyprint?86/*s3c2410fb_calc_pixclk()
87*
88*calculatedivisorforclk->pixclk
89*/
90staticunsignedints3c2410fb_calc_pixclk(structs3c2410fb_info*fbi,
91unsignedlongpixclk)
92{
93unsignedlongclk=fbi->clk_rate;
94unsignedlonglongdiv;
95
96/*pixclkisinpicoseconds,ourclockisinHz
97*
98*Hz->picosecondsis/10^-12
99*/
100
101div=(unsignedlonglong)clk*pixclk;
102div>>=12;/*div/2^12*/
103do_div(div,625*625UL*625);/*div/5^12*/
104
105dprintk("pixclk%ld,divisoris%ld\n",pixclk,(long)div);
106returndiv;
107}
[code]86/*s3c2410fb_calc_pixclk()
87*
88*calculatedivisorforclk->pixclk
89*/
90staticunsignedints3c2410fb_calc_pixclk(structs3c2410fb_info*fbi,
91unsignedlongpixclk)
92{
93unsignedlongclk=fbi->clk_rate;
94unsignedlonglongdiv;
95
96/*pixclkisinpicoseconds,ourclockisinHz
97*
98*Hz->picosecondsis/10^-12
99*/
100
101div=(unsignedlonglong)clk*pixclk;
102div>>=12;/*div/2^12*/
103do_div(div,625*625UL*625);/*div/5^12*/
104
105dprintk("pixclk%ld,divisoris%ld\n",pixclk,(long)div);
106returndiv;
107}

pixclk的单位是皮秒,皮秒是天文学名词,是目前最小的时间单位,一皮秒等于10的12次方分之一秒。[/code]
do_div宏的定义在arch/arm/include/asm/div64.h文件中。看注释其作用是div/5^12,但是为什么这样做,还不清楚。

回到s3c2410fb_activate_var函数,

381行,如果是TFT屏,调用s3c2410fb_calculate_tft_lcd_regs函数:

[cpp]viewplaincopyprint?300/*s3c2410fb_calculate_tft_lcd_regs
301*
302*calculateregistervaluesfromvarsettings
303*/
304staticvoids3c2410fb_calculate_tft_lcd_regs(conststructfb_info*info,
305structs3c2410fb_hw*regs)
306{
307conststructs3c2410fb_info*fbi=info->par;
308conststructfb_var_screeninfo*var=&info->var;
309
310switch(var->bits_per_pixel){
311case1:
312regs->lcdcon1|=S3C2410_LCDCON1_TFT1BPP;
313break;
314case2:
315regs->lcdcon1|=S3C2410_LCDCON1_TFT2BPP;
316break;
317case4:
318regs->lcdcon1|=S3C2410_LCDCON1_TFT4BPP;
319break;
320case8:
321regs->lcdcon1|=S3C2410_LCDCON1_TFT8BPP;
322regs->lcdcon5|=S3C2410_LCDCON5_BSWP|
323S3C2410_LCDCON5_FRM565;
324regs->lcdcon5&=~S3C2410_LCDCON5_HWSWP;
325break;
326case16:
327regs->lcdcon1|=S3C2410_LCDCON1_TFT16BPP;
328regs->lcdcon5&=~S3C2410_LCDCON5_BSWP;
329regs->lcdcon5|=S3C2410_LCDCON5_HWSWP;
330break;
331case32:
332regs->lcdcon1|=S3C2410_LCDCON1_TFT24BPP;
333regs->lcdcon5&=~(S3C2410_LCDCON5_BSWP|
334S3C2410_LCDCON5_HWSWP|
335S3C2410_LCDCON5_BPP24BL);
336break;
337default:
338/*invalidpixeldepth*/
339dev_err(fbi->dev,"invalidbpp%d\n",
340var->bits_per_pixel);
341}
342/*updateX/Yinfo*/
343dprintk("settingvert:up=%d,low=%d,sync=%d\n",
344var->upper_margin,var->lower_margin,var->vsync_len);
345
346dprintk("settinghorz:lft=%d,rt=%d,sync=%d\n",
347var->left_margin,var->right_margin,var->hsync_len);
348
349regs->lcdcon2=S3C2410_LCDCON2_LINEVAL(var->yres-1)|
350S3C2410_LCDCON2_VBPD(var->upper_margin-1)|
351S3C2410_LCDCON2_VFPD(var->lower_margin-1)|
352S3C2410_LCDCON2_VSPW(var->vsync_len-1);
353
354regs->lcdcon3=S3C2410_LCDCON3_HBPD(var->right_margin-1)|
355S3C2410_LCDCON3_HFPD(var->left_margin-1)|
356S3C2410_LCDCON3_HOZVAL(var->xres-1);
357
358regs->lcdcon4=S3C2410_LCDCON4_HSPW(var->hsync_len-1);
359}
[code]300/*s3c2410fb_calculate_tft_lcd_regs
301*
302*calculateregistervaluesfromvarsettings
303*/
304staticvoids3c2410fb_calculate_tft_lcd_regs(conststructfb_info*info,
305structs3c2410fb_hw*regs)
306{
307conststructs3c2410fb_info*fbi=info->par;
308conststructfb_var_screeninfo*var=&info->var;
309
310switch(var->bits_per_pixel){
311case1:
312regs->lcdcon1|=S3C2410_LCDCON1_TFT1BPP;
313break;
314case2:
315regs->lcdcon1|=S3C2410_LCDCON1_TFT2BPP;
316break;
317case4:
318regs->lcdcon1|=S3C2410_LCDCON1_TFT4BPP;
319break;
320case8:
321regs->lcdcon1|=S3C2410_LCDCON1_TFT8BPP;
322regs->lcdcon5|=S3C2410_LCDCON5_BSWP|
323S3C2410_LCDCON5_FRM565;
324regs->lcdcon5&=~S3C2410_LCDCON5_HWSWP;
325break;
326case16:
327regs->lcdcon1|=S3C2410_LCDCON1_TFT16BPP;
328regs->lcdcon5&=~S3C2410_LCDCON5_BSWP;
329regs->lcdcon5|=S3C2410_LCDCON5_HWSWP;
330break;
331case32:
332regs->lcdcon1|=S3C2410_LCDCON1_TFT24BPP;
333regs->lcdcon5&=~(S3C2410_LCDCON5_BSWP|
334S3C2410_LCDCON5_HWSWP|
335S3C2410_LCDCON5_BPP24BL);
336break;
337default:
338/*invalidpixeldepth*/
339dev_err(fbi->dev,"invalidbpp%d\n",
340var->bits_per_pixel);
341}
342/*updateX/Yinfo*/
343dprintk("settingvert:up=%d,low=%d,sync=%d\n",
344var->upper_margin,var->lower_margin,var->vsync_len);
345
346dprintk("settinghorz:lft=%d,rt=%d,sync=%d\n",
347var->left_margin,var->right_margin,var->hsync_len);
348
349regs->lcdcon2=S3C2410_LCDCON2_LINEVAL(var->yres-1)|
350S3C2410_LCDCON2_VBPD(var->upper_margin-1)|
351S3C2410_LCDCON2_VFPD(var->lower_margin-1)|
352S3C2410_LCDCON2_VSPW(var->vsync_len-1);
353
354regs->lcdcon3=S3C2410_LCDCON3_HBPD(var->right_margin-1)|
355S3C2410_LCDCON3_HFPD(var->left_margin-1)|
356S3C2410_LCDCON3_HOZVAL(var->xres-1);
357
358regs->lcdcon4=S3C2410_LCDCON4_HSPW(var->hsync_len-1);
359}

针对TFT屏,这个函数通过info->var的成员变量值计算各个LCDControl寄存器的值。参考Datasheet很容易理解这个函数。[/code]
386行,如果是STN屏,则调用s3c2410fb_calculate_stn_lcd_regs函数:

[cpp]viewplaincopyprint?240/*s3c2410fb_calculate_stn_lcd_regs
241*
242*calculateregistervaluesfromvarsettings
243*/
244staticvoids3c2410fb_calculate_stn_lcd_regs(conststructfb_info*info,
245structs3c2410fb_hw*regs)
246{
247conststructs3c2410fb_info*fbi=info->par;
248conststructfb_var_screeninfo*var=&info->var;
249inttype=regs->lcdcon1&~S3C2410_LCDCON1_TFT;
250inths=var->xres>>2;
251unsignedwdly=(var->left_margin>>4)-1;
252unsignedwlh=(var->hsync_len>>4)-1;
253
254if(type!=S3C2410_LCDCON1_STN4)
255hs>>=1;
256
257switch(var->bits_per_pixel){
258case1:
259regs->lcdcon1|=S3C2410_LCDCON1_STN1BPP;
260break;
261case2:
262regs->lcdcon1|=S3C2410_LCDCON1_STN2GREY;
263break;
264case4:
265regs->lcdcon1|=S3C2410_LCDCON1_STN4GREY;
266break;
267case8:
268regs->lcdcon1|=S3C2410_LCDCON1_STN8BPP;
269hs*=3;
270break;
271case12:
272regs->lcdcon1|=S3C2410_LCDCON1_STN12BPP;
273hs*=3;
274break;
275
276default:
277/*invalidpixeldepth*/
278dev_err(fbi->dev,"invalidbpp%d\n",
279var->bits_per_pixel);
280}
281/*updateX/Yinfo*/
282dprintk("settinghorz:lft=%d,rt=%d,sync=%d\n",
283var->left_margin,var->right_margin,var->hsync_len);
284
285regs->lcdcon2=S3C2410_LCDCON2_LINEVAL(var->yres-1);
286
287if(wdly>3)
288wdly=3;
289
290if(wlh>3)
291wlh=3;
292
293regs->lcdcon3=S3C2410_LCDCON3_WDLY(wdly)|
294S3C2410_LCDCON3_LINEBLANK(var->right_margin/8)|
295S3C2410_LCDCON3_HOZVAL(hs-1);
296
297regs->lcdcon4=S3C2410_LCDCON4_WLH(wlh);
298}
[code]240/*s3c2410fb_calculate_stn_lcd_regs
241*
242*calculateregistervaluesfromvarsettings
243*/
244staticvoids3c2410fb_calculate_stn_lcd_regs(conststructfb_info*info,
245structs3c2410fb_hw*regs)
246{
247conststructs3c2410fb_info*fbi=info->par;
248conststructfb_var_screeninfo*var=&info->var;
249inttype=regs->lcdcon1&~S3C2410_LCDCON1_TFT;
250inths=var->xres>>2;
251unsignedwdly=(var->left_margin>>4)-1;
252unsignedwlh=(var->hsync_len>>4)-1;
253
254if(type!=S3C2410_LCDCON1_STN4)
255hs>>=1;
256
257switch(var->bits_per_pixel){
258case1:
259regs->lcdcon1|=S3C2410_LCDCON1_STN1BPP;
260break;
261case2:
262regs->lcdcon1|=S3C2410_LCDCON1_STN2GREY;
263break;
264case4:
265regs->lcdcon1|=S3C2410_LCDCON1_STN4GREY;
266break;
267case8:
268regs->lcdcon1|=S3C2410_LCDCON1_STN8BPP;
269hs*=3;
270break;
271case12:
272regs->lcdcon1|=S3C2410_LCDCON1_STN12BPP;
273hs*=3;
274break;
275
276default:
277/*invalidpixeldepth*/
278dev_err(fbi->dev,"invalidbpp%d\n",
279var->bits_per_pixel);
280}
281/*updateX/Yinfo*/
282dprintk("settinghorz:lft=%d,rt=%d,sync=%d\n",
283var->left_margin,var->right_margin,var->hsync_len);
284
285regs->lcdcon2=S3C2410_LCDCON2_LINEVAL(var->yres-1);
286
287if(wdly>3)
288wdly=3;
289
290if(wlh>3)
291wlh=3;
292
293regs->lcdcon3=S3C2410_LCDCON3_WDLY(wdly)|
294S3C2410_LCDCON3_LINEBLANK(var->right_margin/8)|
295S3C2410_LCDCON3_HOZVAL(hs-1);
296
297regs->lcdcon4=S3C2410_LCDCON4_WLH(wlh);
298}

针对STN屏,这个函数通过info->var的成员变量值计算各个LCDControl寄存器的值。参考Datasheet理解这个函数。[/code]
回到s3c2410fb_activate_var函数,

391行,设置LCDCON1的CLKVAL。

402-407行,把相关设置写入LCD控制寄存器。

410行,调用s3c2410fb_set_lcdaddr函数设置帧缓冲区的地址,寄存器LCDSADDR1、LCDSADDR2、LCDSADDR3的含义参考Datasheet:

[cpp]viewplaincopyprint?59/*s3c2410fb_set_lcdaddr
60*
61*initialiselcdcontrolleraddresspointers
62*/
63staticvoids3c2410fb_set_lcdaddr(structfb_info*info)
64{
65unsignedlongsaddr1,saddr2,saddr3;
66structs3c2410fb_info*fbi=info->par;
67void__iomem*regs=fbi->io;
68
69saddr1=info->fix.smem_start>>1;
70saddr2=info->fix.smem_start;
71saddr2+=info->fix.line_length*info->var.yres;
72saddr2>>=1;
73
74saddr3=S3C2410_OFFSIZE(0)|
75S3C2410_PAGEWIDTH((info->fix.line_length/2)&0x3ff);
76
77dprintk("LCDSADDR1=0x%08lx\n",saddr1);
78dprintk("LCDSADDR2=0x%08lx\n",saddr2);
79dprintk("LCDSADDR3=0x%08lx\n",saddr3);
80
81writel(saddr1,regs+S3C2410_LCDSADDR1);
82writel(saddr2,regs+S3C2410_LCDSADDR2);
83writel(saddr3,regs+S3C2410_LCDSADDR3);
84}
[code]59/*s3c2410fb_set_lcdaddr
60*
61*initialiselcdcontrolleraddresspointers
62*/
63staticvoids3c2410fb_set_lcdaddr(structfb_info*info)
64{
65unsignedlongsaddr1,saddr2,saddr3;
66structs3c2410fb_info*fbi=info->par;
67void__iomem*regs=fbi->io;
68
69saddr1=info->fix.smem_start>>1;
70saddr2=info->fix.smem_start;
71saddr2+=info->fix.line_length*info->var.yres;
72saddr2>>=1;
73
74saddr3=S3C2410_OFFSIZE(0)|
75S3C2410_PAGEWIDTH((info->fix.line_length/2)&0x3ff);
76
77dprintk("LCDSADDR1=0x%08lx\n",saddr1);
78dprintk("LCDSADDR2=0x%08lx\n",saddr2);
79dprintk("LCDSADDR3=0x%08lx\n",saddr3);
80
81writel(saddr1,regs+S3C2410_LCDSADDR1);
82writel(saddr2,regs+S3C2410_LCDSADDR2);
83writel(saddr3,regs+S3C2410_LCDSADDR3);
84}

回忆一下在s3c2410fb_map_video_memory函数的651行,帧缓冲区Framebuffer的物理地址首地址保存在fb_info.fix.smem_start中。LCDADDR1寄存器的值怎样计算呢?其实就是把Framebuffer物理地址值右移1位(因为是16位BPP),写到LCDADDR1寄存器就可以了。[/code]
LCDADDR2寄存器保存Framebuffer的结束地址,在s3c2410fb_set_par函数中,439行,将每行占用的字节数保存在fb_info.fix.line_length变量中。屏幕共有多少行,保存在fb_info.var.yres中。所以,71行得到Framebuffer的结束位置,72行将结束位置右移1位(因为是16位BPP)。

74行,S3C2410_OFFSIZE宏定义如下:

[cpp]viewplaincopyprint?#defineS3C2410_OFFSIZE(x)((x)<<11)
[code]#defineS3C2410_OFFSIZE(x)((x)<<11)

75行,S3C2410_PAGEWIDTH宏定义如下:[/code]
[cpp]viewplaincopyprint?#defineS3C2410_PAGEWIDTH(x)(x)
[code]#defineS3C2410_PAGEWIDTH(x)(x)

回到s3c2410fb_activate_var函数,[/code]
413行,使能LCD控制器。

至此,s3c2410fb_activate_var函数就全部分析完了。

同时,s3c2410fb_set_par函数也就全部分析完了。

下面来分析fb_ops.fb_bank函数s3c2410fb_blank的实现:

[cpp]viewplaincopyprint?547/*
548*s3c2410fb_blank
549*@blank_mode:theblankmodewewant.
550*@info:framebufferstructurethatrepresentsasingleframebuffer
551*
552*Blankthescreenifblank_mode!=0,elseunblank.Return0if
553*blankingsucceeded,!=0ifun-/blankingfailedduetoe.g.a
554*videomodewhichdoesn'tsupportit.ImplementsVESAsuspend
555*andpowerdownmodesonhardwarethatsupportsdisablinghsync/vsync:
556*
557*Returnsnegativeerrnoonerror,orzeroonsuccess.
558*
559*/
560staticints3c2410fb_blank(intblank_mode,structfb_info*info)
561{
562structs3c2410fb_info*fbi=info->par;
563void__iomem*tpal_reg=fbi->io;
564
565dprintk("blank(mode=%d,info=%p)\n",blank_mode,info);
566
567tpal_reg+=is_s3c2412(fbi)?S3C2412_TPAL:S3C2410_TPAL;
568
569if(blank_mode==FB_BLANK_POWERDOWN){
570s3c2410fb_lcd_enable(fbi,0);
571}else{
572s3c2410fb_lcd_enable(fbi,1);
573}
574
575if(blank_mode==FB_BLANK_UNBLANK)
576writel(0x0,tpal_reg);
577else{
578dprintk("settingTPALtooutput0x000000\n");
579writel(S3C2410_TPAL_EN,tpal_reg);
580}
581
582return0;
583}
[code]547/*
548*s3c2410fb_blank
549*@blank_mode:theblankmodewewant.
550*@info:framebufferstructurethatrepresentsasingleframebuffer
551*
552*Blankthescreenifblank_mode!=0,elseunblank.Return0if
553*blankingsucceeded,!=0ifun-/blankingfailedduetoe.g.a
554*videomodewhichdoesn'tsupportit.ImplementsVESAsuspend
555*andpowerdownmodesonhardwarethatsupportsdisablinghsync/vsync:
556*
557*Returnsnegativeerrnoonerror,orzeroonsuccess.
558*
559*/
560staticints3c2410fb_blank(intblank_mode,structfb_info*info)
561{
562structs3c2410fb_info*fbi=info->par;
563void__iomem*tpal_reg=fbi->io;
564
565dprintk("blank(mode=%d,info=%p)\n",blank_mode,info);
566
567tpal_reg+=is_s3c2412(fbi)?S3C2412_TPAL:S3C2410_TPAL;
568
569if(blank_mode==FB_BLANK_POWERDOWN){
570s3c2410fb_lcd_enable(fbi,0);
571}else{
572s3c2410fb_lcd_enable(fbi,1);
573}
574
575if(blank_mode==FB_BLANK_UNBLANK)
576writel(0x0,tpal_reg);
577else{
578dprintk("settingTPALtooutput0x000000\n");
579writel(S3C2410_TPAL_EN,tpal_reg);
580}
581
582return0;
583}

如果要输出一帧单色图像,可以在TPAL寄存器中设定这个颜色值,然后使能TPAL寄存器,这种方法可以避免修改整个调色板或帧缓冲区。[/code]
579行,使能TPAL,同时显示让屏幕清屏,S3C2410_TPAL_EN宏定义如下:

[cpp]viewplaincopyprint?#defineS3C2410_TPAL_EN(1<<24)
[code]#defineS3C2410_TPAL_EN(1<<24)

下面来分析fb_ops.fb_setcolreg函数s3c2410fb_setcolreg:[/code]
[cpp]viewplaincopyprint?479staticints3c2410fb_setcolreg(unsignedregno,
480unsignedred,unsignedgreen,unsignedblue,
481unsignedtransp,structfb_info*info)
482{
483structs3c2410fb_info*fbi=info->par;
484void__iomem*regs=fbi->io;
485unsignedintval;
486
487/*dprintk("setcol:regno=%d,rgb=%d,%d,%d\n",
488regno,red,green,blue);*/
489
490switch(info->fix.visual){
491caseFB_VISUAL_TRUECOLOR:
492/*true-colour,usepseudo-palette*/
493
494if(regno<16){
495u32*pal=info->pseudo_palette;
496
497val=chan_to_field(red,&info->var.red);
498val|=chan_to_field(green,&info->var.green);
499val|=chan_to_field(blue,&info->var.blue);
500
501pal[regno]=val;
502}
503break;
504
505caseFB_VISUAL_PSEUDOCOLOR:
506if(regno<256){
507/*currentlyassumeRGB5-6-5mode*/
508
509val=(red>>0)&0xf800;
510val|=(green>>5)&0x07e0;
511val|=(blue>>11)&0x001f;
512
513writel(val,regs+S3C2410_TFTPAL(regno));
514schedule_palette_update(fbi,regno,val);
515}
516
517break;
518
519default:
520return1;/*unknowntype*/
521}
522
523return0;
524}
[code]479staticints3c2410fb_setcolreg(unsignedregno,
480unsignedred,unsignedgreen,unsignedblue,
481unsignedtransp,structfb_info*info)
482{
483structs3c2410fb_info*fbi=info->par;
484void__iomem*regs=fbi->io;
485unsignedintval;
486
487/*dprintk("setcol:regno=%d,rgb=%d,%d,%d\n",
488regno,red,green,blue);*/
489
490switch(info->fix.visual){
491caseFB_VISUAL_TRUECOLOR:
492/*true-colour,usepseudo-palette*/
493
494if(regno<16){
495u32*pal=info->pseudo_palette;
496
497val=chan_to_field(red,&info->var.red);
498val|=chan_to_field(green,&info->var.green);
499val|=chan_to_field(blue,&info->var.blue);
500
501pal[regno]=val;
502}
503break;
504
505caseFB_VISUAL_PSEUDOCOLOR:
506if(regno<256){
507/*currentlyassumeRGB5-6-5mode*/
508
509val=(red>>0)&0xf800;
510val|=(green>>5)&0x07e0;
511val|=(blue>>11)&0x001f;
512
513writel(val,regs+S3C2410_TFTPAL(regno));
514schedule_palette_update(fbi,regno,val);
515}
516
517break;
518
519default:
520return1;/*unknowntype*/
521}
522
523return0;
524}

该函数的作用是将颜色值写入调色板(或伪调色板)的指定位置。[/code]
501行,将颜色值写入伪调色板。

513行,将颜色值写入调色板。

chan_to_field函数定义如下:

[cpp]viewplaincopyprint?471staticinlineunsignedintchan_to_field(unsignedintchan,
472structfb_bitfield*bf)
473{
474chan&=0xffff;
475chan>>=16-bf->length;
476returnchan<<bf->offset;
477}
[code]471staticinlineunsignedintchan_to_field(unsignedintchan,
472structfb_bitfield*bf)
473{
474chan&=0xffff;
475chan>>=16-bf->length;
476returnchan<<bf->offset;
477}

schedule_palette_update函数定义如下:[cpp]viewplaincopyprint?447staticvoidschedule_palette_update(structs3c2410fb_info*fbi,
448unsignedintregno,unsignedintval)
449{
450unsignedlongflags;
451unsignedlongirqen;
452void__iomem*irq_base=fbi->irq_base;
453
454local_irq_save(flags);
455
456fbi->palette_buffer[regno]=val;
457
458if(!fbi->palette_ready){
459fbi->palette_ready=1;
460
461/*enableIRQ*/
462irqen=readl(irq_base+S3C24XX_LCDINTMSK);
463irqen&=~S3C2410_LCDINT_FRSYNC;
464writel(irqen,irq_base+S3C24XX_LCDINTMSK);
465}
466
467local_irq_restore(flags);
468}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: