1 #include<linux/kernel.h>
2 #include<linux/module.h>
3 #include<linux/errno.h>
4 #include<linux/string.h>
7 #include<linux/delay.h>
9 #include<linux/ioport.h>
10 #include<linux/init.h>
12 #include<linux/mm_types.h>
13 #include<linux/vmalloc.h>
14 #include<linux/pagemap.h>
15 #include<linux/screen_info.h>
16 #include<linux/vmalloc.h>
17 #include<linux/pagemap.h>
18 #include <linux/console.h>
25 #include "sm750_accel.h"
26 #include "sm750_cursor.h"
35 ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf,
36 size_t count, loff_t *ppos);
37 ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf,
38 size_t count, loff_t *ppos);
42 typedef void (*PROC_SPEC_SETUP
)(struct lynx_share
*,char *);
43 typedef int (*PROC_SPEC_MAP
)(struct lynx_share
*,struct pci_dev
*);
44 typedef int (*PROC_SPEC_INITHW
)(struct lynx_share
*,struct pci_dev
*);
47 /* common var for all device */
48 static int g_hwcursor
= 1;
49 static int g_noaccel
= 0;
51 static int g_nomtrr
= 0;
53 static const char * g_fbmode
[] = {NULL
,NULL
};
54 static const char * g_def_fbmode
= "800x600-16@60";
55 static char * g_settings
= NULL
;
56 static int g_dualview
= 0;
57 static char * g_option
= NULL
;
59 /* if not use spin_lock,system will die if user load driver
60 * and immediatly unload driver frequently (dual)*/
61 static inline void myspin_lock(spinlock_t
* sl
){
62 struct lynx_share
* share
;
63 share
= container_of(sl
,struct lynx_share
,slock
);
69 static inline void myspin_unlock(spinlock_t
* sl
){
70 struct lynx_share
* share
;
71 share
= container_of(sl
,struct lynx_share
,slock
);
76 static const struct fb_videomode lynx750_ext
[] = {
77 /* 1024x600-60 VESA [1.71:1] */
78 {NULL
, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
79 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
81 /* 1024x600-70 VESA */
82 {NULL
, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
83 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
85 /* 1024x600-75 VESA */
86 {NULL
, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
87 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
89 /* 1024x600-85 VESA */
90 {NULL
, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
91 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
94 {NULL
, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
95 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
97 /* 1280x720 [1.78:1] */
98 {NULL
, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
99 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,FB_VMODE_NONINTERLACED
},
102 {NULL
,60,1280,768,12579,192,64,20,3,128,7,
103 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,FB_VMODE_NONINTERLACED
},
105 {NULL
,60,1360,768,11804,208,64,23,1,144,3,
106 FB_SYNC_HOR_HIGH_ACT
|FB_VMODE_NONINTERLACED
},
108 /* 1360 x 768 [1.77083:1] */
109 {NULL
, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
110 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
112 /* 1368 x 768 [1.78:1] */
113 {NULL
, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
114 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
116 /* 1440 x 900 [16:10] */
117 {NULL
, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
118 FB_SYNC_VERT_HIGH_ACT
,FB_VMODE_NONINTERLACED
},
120 /* 1440x960 [15:10] */
121 {NULL
, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
122 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
124 /* 1920x1080 [16:9] */
125 {NULL
, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
126 FB_SYNC_VERT_HIGH_ACT
,FB_VMODE_NONINTERLACED
},
132 /* no hardware cursor supported under version 2.6.10, kernel bug */
133 static int lynxfb_ops_cursor(struct fb_info
* info
,struct fb_cursor
* fbcursor
)
135 struct lynxfb_par
* par
;
136 struct lynxfb_crtc
* crtc
;
137 struct lynx_cursor
* cursor
;
141 cursor
= &crtc
->cursor
;
143 if(fbcursor
->image
.width
> cursor
->maxW
||
144 fbcursor
->image
.height
> cursor
->maxH
||
145 fbcursor
->image
.depth
> 1){
149 cursor
->disable(cursor
);
150 if(fbcursor
->set
& FB_CUR_SETSIZE
){
151 cursor
->setSize(cursor
,fbcursor
->image
.width
,fbcursor
->image
.height
);
154 if(fbcursor
->set
& FB_CUR_SETPOS
){
155 cursor
->setPos(cursor
,fbcursor
->image
.dx
- info
->var
.xoffset
,
156 fbcursor
->image
.dy
- info
->var
.yoffset
);
159 if(fbcursor
->set
& FB_CUR_SETCMAP
){
160 /* get the 16bit color of kernel means */
162 fg
= ((info
->cmap
.red
[fbcursor
->image
.fg_color
] & 0xf800))|
163 ((info
->cmap
.green
[fbcursor
->image
.fg_color
] & 0xfc00) >> 5)|
164 ((info
->cmap
.blue
[fbcursor
->image
.fg_color
] & 0xf800) >> 11);
166 bg
= ((info
->cmap
.red
[fbcursor
->image
.bg_color
] & 0xf800))|
167 ((info
->cmap
.green
[fbcursor
->image
.bg_color
] & 0xfc00) >> 5)|
168 ((info
->cmap
.blue
[fbcursor
->image
.bg_color
] & 0xf800) >> 11);
170 cursor
->setColor(cursor
,fg
,bg
);
174 if(fbcursor
->set
& (FB_CUR_SETSHAPE
| FB_CUR_SETIMAGE
))
176 cursor
->setData(cursor
,
178 fbcursor
->image
.data
,
182 if(fbcursor
->enable
){
183 cursor
->enable(cursor
);
189 static void lynxfb_ops_fillrect(struct fb_info
* info
,const struct fb_fillrect
* region
)
191 struct lynxfb_par
* par
;
192 struct lynx_share
* share
;
193 unsigned int base
,pitch
,Bpp
,rop
;
196 if(info
->state
!= FBINFO_STATE_RUNNING
){
203 /* each time 2d function begin to work,below three variable always need
204 * be set, seems we can put them together in some place */
205 base
= par
->crtc
.oScreen
;
206 pitch
= info
->fix
.line_length
;
207 Bpp
= info
->var
.bits_per_pixel
>> 3;
209 color
= (Bpp
== 1)?region
->color
:((u32
*)info
->pseudo_palette
)[region
->color
];
210 rop
= ( region
->rop
!= ROP_COPY
) ? HW_ROP2_XOR
:HW_ROP2_COPY
;
212 myspin_lock(&share
->slock
);
213 share
->accel
.de_fillrect(&share
->accel
,
215 region
->dx
,region
->dy
,
216 region
->width
,region
->height
,
218 myspin_unlock(&share
->slock
);
221 static void lynxfb_ops_copyarea(struct fb_info
* info
,const struct fb_copyarea
* region
)
223 struct lynxfb_par
* par
;
224 struct lynx_share
* share
;
225 unsigned int base
,pitch
,Bpp
;
230 /* each time 2d function begin to work,below three variable always need
231 * be set, seems we can put them together in some place */
232 base
= par
->crtc
.oScreen
;
233 pitch
= info
->fix
.line_length
;
234 Bpp
= info
->var
.bits_per_pixel
>> 3;
236 myspin_lock(&share
->slock
);
237 share
->accel
.de_copyarea(&share
->accel
,
238 base
,pitch
,region
->sx
,region
->sy
,
239 base
,pitch
,Bpp
,region
->dx
,region
->dy
,
240 region
->width
,region
->height
,HW_ROP2_COPY
);
241 myspin_unlock(&share
->slock
);
244 static void lynxfb_ops_imageblit(struct fb_info
*info
,const struct fb_image
* image
)
246 unsigned int base
,pitch
,Bpp
;
247 unsigned int fgcol
,bgcol
;
248 struct lynxfb_par
* par
;
249 struct lynx_share
* share
;
253 /* each time 2d function begin to work,below three variable always need
254 * be set, seems we can put them together in some place */
255 base
= par
->crtc
.oScreen
;
256 pitch
= info
->fix
.line_length
;
257 Bpp
= info
->var
.bits_per_pixel
>> 3;
259 if(image
->depth
== 1){
260 if(info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
261 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
263 fgcol
= ((u32
*)info
->pseudo_palette
)[image
->fg_color
];
264 bgcol
= ((u32
*)info
->pseudo_palette
)[image
->bg_color
];
268 fgcol
= image
->fg_color
;
269 bgcol
= image
->bg_color
;
275 myspin_lock(&share
->slock
);
276 share
->accel
.de_imageblit(&share
->accel
,
277 image
->data
,image
->width
>>3,0,
280 image
->width
,image
->height
,
281 fgcol
,bgcol
,HW_ROP2_COPY
);
282 myspin_unlock(&share
->slock
);
285 static int lynxfb_ops_pan_display(struct fb_var_screeninfo
*var
,
286 struct fb_info
*info
)
288 struct lynxfb_par
* par
;
289 struct lynxfb_crtc
* crtc
;
299 ret
= crtc
->proc_panDisplay(crtc
, var
, info
);
304 static int lynxfb_ops_set_par(struct fb_info
* info
)
306 struct lynxfb_par
* par
;
307 struct lynx_share
* share
;
308 struct lynxfb_crtc
* crtc
;
309 struct lynxfb_output
* output
;
310 struct fb_var_screeninfo
* var
;
311 struct fb_fix_screeninfo
* fix
;
313 unsigned int line_length
;
322 output
= &par
->output
;
326 /* fix structur is not so FIX ... */
327 line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
328 line_length
= PADDING(crtc
->line_pad
,line_length
);
329 fix
->line_length
= line_length
;
330 pr_err("fix->line_length = %d\n",fix
->line_length
);
332 /* var->red,green,blue,transp are need to be set by driver
333 * and these data should be set before setcolreg routine
336 switch(var
->bits_per_pixel
){
338 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
341 var
->green
.offset
= 0;
342 var
->green
.length
= 8;
343 var
->blue
.offset
= 0;
344 var
->blue
.length
= 8;
345 var
->transp
.length
= 0;
346 var
->transp
.offset
= 0;
349 var
->red
.offset
= 11;
351 var
->green
.offset
= 5;
352 var
->green
.length
= 6;
353 var
->blue
.offset
= 0;
354 var
->blue
.length
= 5;
355 var
->transp
.length
= 0;
356 var
->transp
.offset
= 0;
357 fix
->visual
= FB_VISUAL_TRUECOLOR
;
361 var
->red
.offset
= 16;
363 var
->green
.offset
= 8;
364 var
->green
.length
= 8;
365 var
->blue
.offset
= 0 ;
366 var
->blue
.length
= 8;
367 fix
->visual
= FB_VISUAL_TRUECOLOR
;
373 var
->height
= var
->width
= -1;
374 var
->accel_flags
= 0;/*FB_ACCELF_TEXT;*/
377 pr_err("pixel bpp format not satisfied\n.");
380 ret
= crtc
->proc_setMode(crtc
,var
,fix
);
382 ret
= output
->proc_setMode(output
,var
,fix
);
386 static inline unsigned int chan_to_field(unsigned int chan
,struct fb_bitfield
* bf
)
389 chan
>>= 16 - bf
->length
;
390 return chan
<< bf
->offset
;
394 static int lynxfb_suspend(struct pci_dev
*pdev
, pm_message_t mesg
)
396 struct fb_info
*info
;
397 struct lynx_share
*share
;
400 if (mesg
.event
== pdev
->dev
.power
.power_state
.event
)
404 share
= pci_get_drvdata(pdev
);
405 switch (mesg
.event
) {
406 case PM_EVENT_FREEZE
:
407 case PM_EVENT_PRETHAW
:
408 pdev
->dev
.power
.power_state
= mesg
;
413 if (mesg
.event
& PM_EVENT_SLEEP
) {
414 info
= share
->fbinfo
[0];
416 /* 1 means do suspend*/
417 fb_set_suspend(info
, 1);
418 info
= share
->fbinfo
[1];
420 /* 1 means do suspend*/
421 fb_set_suspend(info
, 1);
423 ret
= pci_save_state(pdev
);
425 pr_err("error:%d occurred in pci_save_state\n", ret
);
429 /* set chip to sleep mode*/
431 (*share
->suspend
)(share
);
433 pci_disable_device(pdev
);
434 ret
= pci_set_power_state(pdev
, pci_choose_state(pdev
, mesg
));
436 pr_err("error:%d occurred in pci_set_power_state\n", ret
);
441 pdev
->dev
.power
.power_state
= mesg
;
446 static int lynxfb_resume(struct pci_dev
* pdev
)
448 struct fb_info
* info
;
449 struct lynx_share
* share
;
451 struct lynxfb_par
* par
;
452 struct lynxfb_crtc
* crtc
;
453 struct lynx_cursor
* cursor
;
459 share
= pci_get_drvdata(pdev
);
463 if((ret
= pci_set_power_state(pdev
, PCI_D0
)) != 0){
464 pr_err("error:%d occured in pci_set_power_state\n",ret
);
469 if(pdev
->dev
.power
.power_state
.event
!= PM_EVENT_FREEZE
){
470 pci_restore_state(pdev
);
471 if ((ret
= pci_enable_device(pdev
)) != 0){
472 pr_err("error:%d occured in pci_enable_device\n",ret
);
475 pci_set_master(pdev
);
478 (*share
->resume
)(share
);
480 hw_sm750_inithw(share
,pdev
);
483 info
= share
->fbinfo
[0];
488 cursor
= &crtc
->cursor
;
489 memset(cursor
->vstart
, 0x0, cursor
->size
);
490 memset(crtc
->vScreen
,0x0,crtc
->vidmem_size
);
491 lynxfb_ops_set_par(info
);
492 fb_set_suspend(info
, 0);
495 info
= share
->fbinfo
[1];
500 cursor
= &crtc
->cursor
;
501 memset(cursor
->vstart
, 0x0, cursor
->size
);
502 memset(crtc
->vScreen
,0x0,crtc
->vidmem_size
);
503 lynxfb_ops_set_par(info
);
504 fb_set_suspend(info
, 0);
513 static int lynxfb_ops_check_var(struct fb_var_screeninfo
* var
,struct fb_info
* info
)
515 struct lynxfb_par
* par
;
516 struct lynxfb_crtc
* crtc
;
517 struct lynxfb_output
* output
;
518 struct lynx_share
* share
;
520 resource_size_t request
;
525 output
= &par
->output
;
529 pr_debug("check var:%dx%d-%d\n",
532 var
->bits_per_pixel
);
535 switch(var
->bits_per_pixel
){
538 case 24: /* support 24 bpp for only lynx712/722/720 */
542 pr_err("bpp %d not supported\n",var
->bits_per_pixel
);
547 switch(var
->bits_per_pixel
){
549 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
552 var
->green
.offset
= 0;
553 var
->green
.length
= 8;
554 var
->blue
.offset
= 0;
555 var
->blue
.length
= 8;
556 var
->transp
.length
= 0;
557 var
->transp
.offset
= 0;
560 var
->red
.offset
= 11;
562 var
->green
.offset
= 5;
563 var
->green
.length
= 6;
564 var
->blue
.offset
= 0;
565 var
->blue
.length
= 5;
566 var
->transp
.length
= 0;
567 var
->transp
.offset
= 0;
568 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
572 var
->red
.offset
= 16;
574 var
->green
.offset
= 8;
575 var
->green
.length
= 8;
576 var
->blue
.offset
= 0 ;
577 var
->blue
.length
= 8;
578 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
584 var
->height
= var
->width
= -1;
585 var
->accel_flags
= 0;/*FB_ACCELF_TEXT;*/
587 /* check if current fb's video memory big enought to hold the onscreen */
588 request
= var
->xres_virtual
* (var
->bits_per_pixel
>> 3);
589 /* defaulty crtc->channel go with par->index */
591 request
= PADDING(crtc
->line_pad
,request
);
592 request
= request
* var
->yres_virtual
;
593 if(crtc
->vidmem_size
< request
){
594 pr_err("not enough video memory for mode\n");
598 ret
= output
->proc_checkMode(output
,var
);
600 ret
= crtc
->proc_checkMode(crtc
,var
);
606 static int lynxfb_ops_setcolreg(unsigned regno
,unsigned red
,
607 unsigned green
,unsigned blue
,
608 unsigned transp
,struct fb_info
* info
)
610 struct lynxfb_par
* par
;
611 struct lynxfb_crtc
* crtc
;
612 struct fb_var_screeninfo
* var
;
620 //pr_debug("regno=%d,red=%d,green=%d,blue=%d\n",regno,red,green,blue);
622 pr_err("regno = %d\n",regno
);
626 if(info
->var
.grayscale
)
627 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
629 if(var
->bits_per_pixel
== 8 && info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
)
634 ret
= crtc
->proc_setColReg(crtc
,regno
,red
,green
,blue
);
639 if(info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 256 )
642 if(var
->bits_per_pixel
== 16 ||
643 var
->bits_per_pixel
== 32 ||
644 var
->bits_per_pixel
== 24)
646 val
= chan_to_field(red
,&var
->red
);
647 val
|= chan_to_field(green
,&var
->green
);
648 val
|= chan_to_field(blue
,&var
->blue
);
649 par
->pseudo_palette
[regno
] = val
;
660 static int lynxfb_ops_blank(int blank
,struct fb_info
* info
)
662 struct lynxfb_par
* par
;
663 struct lynxfb_output
* output
;
665 pr_debug("blank = %d.\n",blank
);
667 output
= &par
->output
;
668 return output
->proc_setBLANK(output
,blank
);
671 static int sm750fb_set_drv(struct lynxfb_par
* par
)
674 struct lynx_share
* share
;
675 struct sm750_share
* spec_share
;
676 struct lynxfb_output
* output
;
677 struct lynxfb_crtc
* crtc
;
682 spec_share
= container_of(share
,struct sm750_share
,share
);
683 output
= &par
->output
;
686 crtc
->vidmem_size
= (share
->dual
)?share
->vidmem_size
>>1:share
->vidmem_size
;
687 /* setup crtc and output member */
688 spec_share
->hwCursor
= g_hwcursor
;
690 crtc
->proc_setMode
= hw_sm750_crtc_setMode
;
691 crtc
->proc_checkMode
= hw_sm750_crtc_checkMode
;
692 crtc
->proc_setColReg
= hw_sm750_setColReg
;
693 crtc
->proc_panDisplay
= hw_sm750_pan_display
;
694 crtc
->clear
= hw_sm750_crtc_clear
;
696 //crtc->xpanstep = crtc->ypanstep = crtc->ywrapstep = 0;
701 output
->proc_setMode
= hw_sm750_output_setMode
;
702 output
->proc_checkMode
= hw_sm750_output_checkMode
;
704 output
->proc_setBLANK
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_setBLANK
:hw_sm750_setBLANK
;
705 output
->clear
= hw_sm750_output_clear
;
706 /* chip specific phase */
707 share
->accel
.de_wait
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_deWait
: hw_sm750_deWait
;
708 switch (spec_share
->state
.dataflow
)
710 case sm750_simul_pri
:
711 output
->paths
= sm750_pnc
;
712 crtc
->channel
= sm750_primary
;
714 crtc
->vScreen
= share
->pvMem
;
715 pr_info("use simul primary mode\n");
717 case sm750_simul_sec
:
718 output
->paths
= sm750_pnc
;
719 crtc
->channel
= sm750_secondary
;
721 crtc
->vScreen
= share
->pvMem
;
723 case sm750_dual_normal
:
725 output
->paths
= sm750_panel
;
726 crtc
->channel
= sm750_primary
;
728 crtc
->vScreen
= share
->pvMem
;
730 output
->paths
= sm750_crt
;
731 crtc
->channel
= sm750_secondary
;
732 /* not consider of padding stuffs for oScreen,need fix*/
733 crtc
->oScreen
= (share
->vidmem_size
>> 1);
734 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
737 case sm750_dual_swap
:
739 output
->paths
= sm750_panel
;
740 crtc
->channel
= sm750_secondary
;
742 crtc
->vScreen
= share
->pvMem
;
744 output
->paths
= sm750_crt
;
745 crtc
->channel
= sm750_primary
;
746 /* not consider of padding stuffs for oScreen,need fix*/
747 crtc
->oScreen
= (share
->vidmem_size
>> 1);
748 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
758 static struct fb_ops lynxfb_ops
={
759 .owner
= THIS_MODULE
,
760 .fb_check_var
= lynxfb_ops_check_var
,
761 .fb_set_par
= lynxfb_ops_set_par
,
762 .fb_setcolreg
= lynxfb_ops_setcolreg
,
763 .fb_blank
= lynxfb_ops_blank
,
764 .fb_fillrect
= cfb_fillrect
,
765 .fb_imageblit
= cfb_imageblit
,
766 .fb_copyarea
= cfb_copyarea
,
768 .fb_cursor
= lynxfb_ops_cursor
,
772 static int lynxfb_set_fbinfo(struct fb_info
* info
,int index
)
775 struct lynxfb_par
* par
;
776 struct lynx_share
* share
;
777 struct lynxfb_crtc
* crtc
;
778 struct lynxfb_output
* output
;
779 struct fb_var_screeninfo
* var
;
780 struct fb_fix_screeninfo
* fix
;
782 const struct fb_videomode
* pdb
[] = {
783 lynx750_ext
, NULL
,vesa_modes
,
785 int cdb
[] = {ARRAY_SIZE(lynx750_ext
),0,VESA_MODEDB_SIZE
};
786 static const char * mdb_desc
[] ={
787 "driver prepared modes",
788 "kernel prepared default modedb",
789 "kernel HELPERS prepared vesa_modes",
793 static const char * fixId
[2]=
795 "sm750_fb1","sm750_fb2",
801 par
= (struct lynxfb_par
*)info
->par
;
804 output
= &par
->output
;
810 output
->channel
= &crtc
->channel
;
811 sm750fb_set_drv(par
);
812 lynxfb_ops
.fb_pan_display
= lynxfb_ops_pan_display
;
815 /* set current cursor variable and proc pointer,
816 * must be set after crtc member initialized */
817 crtc
->cursor
.offset
= crtc
->oScreen
+ crtc
->vidmem_size
- 1024;
818 crtc
->cursor
.mmio
= share
->pvReg
+ 0x800f0 + (int)crtc
->channel
* 0x140;
820 pr_info("crtc->cursor.mmio = %p\n",crtc
->cursor
.mmio
);
821 crtc
->cursor
.maxH
= crtc
->cursor
.maxW
= 64;
822 crtc
->cursor
.size
= crtc
->cursor
.maxH
*crtc
->cursor
.maxW
*2/8;
823 crtc
->cursor
.disable
= hw_cursor_disable
;
824 crtc
->cursor
.enable
= hw_cursor_enable
;
825 crtc
->cursor
.setColor
= hw_cursor_setColor
;
826 crtc
->cursor
.setPos
= hw_cursor_setPos
;
827 crtc
->cursor
.setSize
= hw_cursor_setSize
;
828 crtc
->cursor
.setData
= hw_cursor_setData
;
829 crtc
->cursor
.vstart
= share
->pvMem
+ crtc
->cursor
.offset
;
832 crtc
->cursor
.share
= share
;
833 memset(crtc
->cursor
.vstart
, 0, crtc
->cursor
.size
);
835 lynxfb_ops
.fb_cursor
= NULL
;
836 crtc
->cursor
.disable(&crtc
->cursor
);
840 /* set info->fbops, must be set before fb_find_mode */
841 if(!share
->accel_off
){
842 /* use 2d acceleration */
843 lynxfb_ops
.fb_fillrect
= lynxfb_ops_fillrect
;
844 lynxfb_ops
.fb_copyarea
= lynxfb_ops_copyarea
;
845 lynxfb_ops
.fb_imageblit
= lynxfb_ops_imageblit
;
847 info
->fbops
= &lynxfb_ops
;
849 if(!g_fbmode
[index
]){
850 g_fbmode
[index
] = g_def_fbmode
;
852 g_fbmode
[index
] = g_fbmode
[0];
858 ret
= fb_find_mode(var
,info
,g_fbmode
[index
],
859 pdb
[i
],cdb
[i
],NULL
,8);
862 pr_info("success! use specified mode:%s in %s\n",
867 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
872 pr_warn("wanna use default mode\n");
875 pr_warn("fall back to any valid mode\n");
877 pr_warn("ret = %d,fb_find_mode failed,with %s\n",ret
,mdb_desc
[i
]);
881 /* some member of info->var had been set by fb_find_mode */
883 pr_info("Member of info->var is :\n\
890 bits_per_pixel=%d\n \
891 ...\n",var
->xres
,var
->yres
,var
->xres_virtual
,var
->yres_virtual
,
892 var
->xoffset
,var
->yoffset
,var
->bits_per_pixel
);
898 line_length
= PADDING(crtc
->line_pad
,
899 (var
->xres_virtual
* var
->bits_per_pixel
/8));
901 info
->pseudo_palette
= &par
->pseudo_palette
[0];
902 info
->screen_base
= crtc
->vScreen
;
903 pr_debug("screen_base vaddr = %p\n",info
->screen_base
);
904 info
->screen_size
= line_length
* var
->yres_virtual
;
905 info
->flags
= FBINFO_FLAG_DEFAULT
|0;
908 fix
->type
= FB_TYPE_PACKED_PIXELS
;
910 fix
->xpanstep
= crtc
->xpanstep
;
911 fix
->ypanstep
= crtc
->ypanstep
;
912 fix
->ywrapstep
= crtc
->ywrapstep
;
913 fix
->accel
= FB_ACCEL_SMI
;
915 strlcpy(fix
->id
,fixId
[index
],sizeof(fix
->id
));
918 fix
->smem_start
= crtc
->oScreen
+ share
->vidmem_start
;
919 pr_info("fix->smem_start = %lx\n",fix
->smem_start
);
920 /* according to mmap experiment from user space application,
921 * fix->mmio_len should not larger than virtual size
922 * (xres_virtual x yres_virtual x ByPP)
923 * Below line maybe buggy when user mmap fb dev node and write
924 * data into the bound over virtual size
926 fix
->smem_len
= crtc
->vidmem_size
;
927 pr_info("fix->smem_len = %x\n",fix
->smem_len
);
928 info
->screen_size
= fix
->smem_len
;
929 fix
->line_length
= line_length
;
930 fix
->mmio_start
= share
->vidreg_start
;
931 pr_info("fix->mmio_start = %lx\n",fix
->mmio_start
);
932 fix
->mmio_len
= share
->vidreg_size
;
933 pr_info("fix->mmio_len = %x\n",fix
->mmio_len
);
934 switch(var
->bits_per_pixel
)
937 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
941 fix
->visual
= FB_VISUAL_TRUECOLOR
;
946 var
->activate
= FB_ACTIVATE_NOW
;
947 var
->accel_flags
= 0;
948 var
->vmode
= FB_VMODE_NONINTERLACED
;
950 pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
951 info
->cmap
.start
,info
->cmap
.len
,
952 info
->cmap
.red
,info
->cmap
.green
,info
->cmap
.blue
,
955 if((ret
= fb_alloc_cmap(&info
->cmap
,256,0)) < 0){
956 pr_err("Could not allcate memory for cmap.\n");
960 pr_debug("#2 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
961 info
->cmap
.start
,info
->cmap
.len
,
962 info
->cmap
.red
,info
->cmap
.green
,info
->cmap
.blue
,
966 lynxfb_ops_check_var(var
,info
);
967 // lynxfb_ops_set_par(info);
971 /* chip specific g_option configuration routine */
972 static void sm750fb_setup(struct lynx_share
* share
,char * src
)
974 struct sm750_share
* spec_share
;
982 spec_share
= container_of(share
,struct sm750_share
,share
);
983 #ifdef CAP_EXPENSIION
988 spec_share
->state
.initParm
.chip_clk
= 0;
989 spec_share
->state
.initParm
.mem_clk
= 0;
990 spec_share
->state
.initParm
.master_clk
= 0;
991 spec_share
->state
.initParm
.powerMode
= 0;
992 spec_share
->state
.initParm
.setAllEngOff
= 0;
993 spec_share
->state
.initParm
.resetMemory
= 1;
995 /*defaultly turn g_hwcursor on for both view */
999 pr_warn("no specific g_option.\n");
1003 while((opt
= strsep(&src
,":")) != NULL
&& *opt
!= 0){
1004 pr_err("opt=%s\n",opt
);
1005 pr_err("src=%s\n",src
);
1007 if(!strncmp(opt
,"swap",strlen("swap")))
1009 else if(!strncmp(opt
,"nocrt",strlen("nocrt")))
1010 spec_share
->state
.nocrt
= 1;
1011 else if(!strncmp(opt
,"36bit",strlen("36bit")))
1012 spec_share
->state
.pnltype
= sm750_doubleTFT
;
1013 else if(!strncmp(opt
,"18bit",strlen("18bit")))
1014 spec_share
->state
.pnltype
= sm750_dualTFT
;
1015 else if(!strncmp(opt
,"24bit",strlen("24bit")))
1016 spec_share
->state
.pnltype
= sm750_24TFT
;
1017 #ifdef CAP_EXPANSION
1018 else if(!strncmp(opt
,"exp:",strlen("exp:")))
1019 exp_res
= opt
+ strlen("exp:");
1021 else if(!strncmp(opt
,"nohwc0",strlen("nohwc0")))
1023 else if(!strncmp(opt
,"nohwc1",strlen("nohwc1")))
1025 else if(!strncmp(opt
,"nohwc",strlen("nohwc")))
1031 pr_info("find fbmode0 : %s\n",g_fbmode
[0]);
1032 }else if(!g_fbmode
[1]){
1034 pr_info("find fbmode1 : %s\n",g_fbmode
[1]);
1036 pr_warn("How many view you wann set?\n");
1040 #ifdef CAP_EXPANSION
1041 if(getExpRes(exp_res
,&spec_share
->state
.xLCD
,&spec_share
->state
.yLCD
))
1043 /* seems exp_res is not valid*/
1044 spec_share
->state
.xLCD
= spec_share
->state
.yLCD
= 0;
1049 if(share
->revid
!= SM750LE_REVISION_ID
){
1053 spec_share
->state
.dataflow
= sm750_dual_swap
;
1055 spec_share
->state
.dataflow
= sm750_dual_normal
;
1058 spec_share
->state
.dataflow
= sm750_simul_sec
;
1060 spec_share
->state
.dataflow
= sm750_simul_pri
;
1063 /* SM750LE only have one crt channel */
1064 spec_share
->state
.dataflow
= sm750_simul_sec
;
1065 /* sm750le do not have complex attributes*/
1066 spec_share
->state
.nocrt
= 0;
1070 static int lynxfb_pci_probe(struct pci_dev
* pdev
,
1071 const struct pci_device_id
* ent
)
1073 struct fb_info
* info
[] = {NULL
,NULL
};
1074 struct lynx_share
* share
= NULL
;
1076 struct sm750_share
*spec_share
= NULL
;
1077 size_t spec_offset
= 0;
1082 if(pci_enable_device(pdev
)){
1083 pr_err("can not enable device.\n");
1087 /* though offset of share in sm750_share is 0,
1088 * we use this marcro as the same */
1089 spec_offset
= offsetof(struct sm750_share
,share
);
1091 spec_share
= kzalloc(sizeof(*spec_share
),GFP_KERNEL
);
1093 pr_err("Could not allocate memory for share.\n");
1097 /* setting share structure */
1098 share
= (struct lynx_share
* )(&(spec_share
->share
));
1099 share
->fbinfo
[0] = share
->fbinfo
[1] = NULL
;
1100 share
->devid
= pdev
->device
;
1101 share
->revid
= pdev
->revision
;
1103 pr_info("share->revid = %02x\n",share
->revid
);
1106 share
->mtrr_off
= g_nomtrr
;
1107 share
->mtrr
.vram
= 0;
1108 share
->mtrr
.vram_added
= 0;
1110 share
->accel_off
= g_noaccel
;
1111 share
->dual
= g_dualview
;
1112 spin_lock_init(&share
->slock
);
1114 if(!share
->accel_off
){
1115 /* hook deInit and 2d routines, notes that below hw_xxx
1116 * routine can work on most of lynx chips
1117 * if some chip need specific function,please hook it in smXXX_set_drv
1119 share
->accel
.de_init
= hw_de_init
;
1120 share
->accel
.de_fillrect
= hw_fillrect
;
1121 share
->accel
.de_copyarea
= hw_copyarea
;
1122 share
->accel
.de_imageblit
= hw_imageblit
;
1123 pr_info("enable 2d acceleration\n");
1125 pr_info("disable 2d acceleration\n");
1128 /* call chip specific setup routine */
1129 sm750fb_setup(share
,g_settings
);
1131 /* call chip specific mmap routine */
1132 if(hw_sm750_map(share
,pdev
)){
1133 pr_err("Memory map failed\n");
1138 if(!share
->mtrr_off
){
1139 pr_info("enable mtrr\n");
1140 share
->mtrr
.vram
= mtrr_add(share
->vidmem_start
,
1142 MTRR_TYPE_WRCOMB
,1);
1144 if(share
->mtrr
.vram
< 0){
1145 /* don't block driver with the failure of MTRR */
1146 pr_err("Unable to setup MTRR.\n");
1148 share
->mtrr
.vram_added
= 1;
1149 pr_info("MTRR added succesfully\n");
1154 memset(share
->pvMem
,0,share
->vidmem_size
);
1156 pr_info("sm%3x mmio address = %p\n",share
->devid
,share
->pvReg
);
1158 pci_set_drvdata(pdev
,share
);
1160 /* call chipInit routine */
1161 hw_sm750_inithw(share
,pdev
);
1163 /* allocate frame buffer info structor according to g_dualview */
1166 info
[fbidx
] = framebuffer_alloc(sizeof(struct lynxfb_par
),&pdev
->dev
);
1169 pr_err("Could not allocate framebuffer #%d.\n",fbidx
);
1171 goto err_info0_alloc
;
1173 goto err_info1_alloc
;
1177 struct lynxfb_par
* par
;
1179 pr_info("framebuffer #%d alloc okay\n",fbidx
);
1180 share
->fbinfo
[fbidx
] = info
[fbidx
];
1181 par
= info
[fbidx
]->par
;
1184 /* set fb_info structure */
1185 if(lynxfb_set_fbinfo(info
[fbidx
],fbidx
)){
1186 pr_err("Failed to initial fb_info #%d.\n",fbidx
);
1193 /* register frame buffer*/
1194 pr_info("Ready to register framebuffer #%d.\n",fbidx
);
1195 errno
= register_framebuffer(info
[fbidx
]);
1197 pr_err("Failed to register fb_info #%d. err %d\n",fbidx
, errno
);
1203 pr_info("Accomplished register framebuffer #%d.\n",fbidx
);
1206 /* no dual view by far */
1208 if(share
->dual
&& fbidx
< 2)
1215 framebuffer_release(info
[1]);
1217 unregister_framebuffer(info
[0]);
1220 framebuffer_release(info
[0]);
1229 static void __exit
lynxfb_pci_remove(struct pci_dev
* pdev
)
1231 struct fb_info
* info
;
1232 struct lynx_share
* share
;
1234 struct lynxfb_par
* par
;
1238 share
= pci_get_drvdata(pdev
);
1241 info
= share
->fbinfo
[cnt
];
1246 unregister_framebuffer(info
);
1247 /* clean crtc & output allocations*/
1248 par
->crtc
.clear(&par
->crtc
);
1249 par
->output
.clear(&par
->output
);
1250 /* release frame buffer*/
1251 framebuffer_release(info
);
1254 if(share
->mtrr
.vram_added
)
1255 mtrr_del(share
->mtrr
.vram
,share
->vidmem_start
,share
->vidmem_size
);
1257 // pci_release_regions(pdev);
1259 iounmap(share
->pvReg
);
1260 iounmap(share
->pvMem
);
1261 spec_share
= container_of(share
,struct sm750_share
,share
);
1264 pci_set_drvdata(pdev
,NULL
);
1267 static int __init
lynxfb_setup(char * options
)
1273 if(!options
|| !*options
){
1274 pr_warn("no options.\n");
1278 pr_info("options:%s\n",options
);
1280 len
= strlen(options
) + 1;
1281 g_settings
= kzalloc(len
, GFP_KERNEL
);
1288 char * strsep(char **s,const char * ct);
1289 @s: the string to be searched
1290 @ct :the characters to search for
1292 strsep() updates @options to pointer after the first found token
1293 it also returns the pointer ahead the token.
1295 while((opt
= strsep(&options
,":"))!=NULL
)
1297 /* options that mean for any lynx chips are configured here */
1298 if(!strncmp(opt
,"noaccel",strlen("noaccel")))
1301 else if(!strncmp(opt
,"nomtrr",strlen("nomtrr")))
1304 else if(!strncmp(opt
,"dual",strlen("dual")))
1317 /* misc g_settings are transport to chip specific routines */
1318 pr_info("parameter left for chip specific analysis:%s\n",g_settings
);
1322 static struct pci_device_id smi_pci_table
[] = {
1323 { PCI_DEVICE(0x126f, 0x0750), },
1327 MODULE_DEVICE_TABLE(pci
,smi_pci_table
);
1329 static struct pci_driver lynxfb_driver
= {
1331 .id_table
= smi_pci_table
,
1332 .probe
= lynxfb_pci_probe
,
1333 .remove
= lynxfb_pci_remove
,
1335 .suspend
= lynxfb_suspend
,
1336 .resume
= lynxfb_resume
,
1341 static int __init
lynxfb_init(void)
1349 if(fb_get_options("sm750fb",&option
))
1353 lynxfb_setup(option
);
1354 ret
= pci_register_driver(&lynxfb_driver
);
1357 module_init(lynxfb_init
);
1359 static void __exit
lynxfb_exit(void)
1361 pci_unregister_driver(&lynxfb_driver
);
1363 module_exit(lynxfb_exit
);
1365 module_param(g_option
,charp
,S_IRUGO
);
1367 MODULE_PARM_DESC(g_option
,
1368 "\n\t\tCommon options:\n"
1369 "\t\tnoaccel:disable 2d capabilities\n"
1370 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1371 "\t\tdualview:dual frame buffer feature enabled\n"
1372 "\t\tnohwc:disable hardware cursor\n"
1373 "\t\tUsual example:\n"
1374 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1377 MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1378 MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1379 MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1380 MODULE_LICENSE("GPL v2");