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;
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
;
57 static char * g_option
= NULL
;
59 static const struct fb_videomode lynx750_ext
[] = {
60 /* 1024x600-60 VESA [1.71:1] */
61 {NULL
, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
62 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
64 /* 1024x600-70 VESA */
65 {NULL
, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
66 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
68 /* 1024x600-75 VESA */
69 {NULL
, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
70 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
72 /* 1024x600-85 VESA */
73 {NULL
, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
74 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
77 {NULL
, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
78 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
80 /* 1280x720 [1.78:1] */
81 {NULL
, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
82 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
85 {NULL
, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
86 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,FB_VMODE_NONINTERLACED
},
88 {NULL
, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
89 FB_SYNC_HOR_HIGH_ACT
|FB_VMODE_NONINTERLACED
},
91 /* 1360 x 768 [1.77083:1] */
92 {NULL
, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
93 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
95 /* 1368 x 768 [1.78:1] */
96 {NULL
, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
97 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
99 /* 1440 x 900 [16:10] */
100 {NULL
, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
101 FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
103 /* 1440x960 [15:10] */
104 {NULL
, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
105 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
107 /* 1920x1080 [16:9] */
108 {NULL
, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
109 FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
},
115 /* no hardware cursor supported under version 2.6.10, kernel bug */
116 static int lynxfb_ops_cursor(struct fb_info
* info
, struct fb_cursor
* fbcursor
)
118 struct lynxfb_par
* par
;
119 struct lynxfb_crtc
* crtc
;
120 struct lynx_cursor
* cursor
;
124 cursor
= &crtc
->cursor
;
126 if(fbcursor
->image
.width
> cursor
->maxW
||
127 fbcursor
->image
.height
> cursor
->maxH
||
128 fbcursor
->image
.depth
> 1){
132 cursor
->disable(cursor
);
133 if(fbcursor
->set
& FB_CUR_SETSIZE
){
134 cursor
->setSize(cursor
, fbcursor
->image
.width
, fbcursor
->image
.height
);
137 if(fbcursor
->set
& FB_CUR_SETPOS
){
138 cursor
->setPos(cursor
, fbcursor
->image
.dx
- info
->var
.xoffset
,
139 fbcursor
->image
.dy
- info
->var
.yoffset
);
142 if(fbcursor
->set
& FB_CUR_SETCMAP
){
143 /* get the 16bit color of kernel means */
145 fg
= ((info
->cmap
.red
[fbcursor
->image
.fg_color
] & 0xf800))|
146 ((info
->cmap
.green
[fbcursor
->image
.fg_color
] & 0xfc00) >> 5)|
147 ((info
->cmap
.blue
[fbcursor
->image
.fg_color
] & 0xf800) >> 11);
149 bg
= ((info
->cmap
.red
[fbcursor
->image
.bg_color
] & 0xf800))|
150 ((info
->cmap
.green
[fbcursor
->image
.bg_color
] & 0xfc00) >> 5)|
151 ((info
->cmap
.blue
[fbcursor
->image
.bg_color
] & 0xf800) >> 11);
153 cursor
->setColor(cursor
, fg
, bg
);
157 if(fbcursor
->set
& (FB_CUR_SETSHAPE
| FB_CUR_SETIMAGE
))
159 cursor
->setData(cursor
,
161 fbcursor
->image
.data
,
165 if(fbcursor
->enable
){
166 cursor
->enable(cursor
);
172 static void lynxfb_ops_fillrect(struct fb_info
* info
, const struct fb_fillrect
* region
)
174 struct lynxfb_par
* par
;
175 struct lynx_share
* share
;
176 unsigned int base
, pitch
, Bpp
, rop
;
179 if(info
->state
!= FBINFO_STATE_RUNNING
){
186 /* each time 2d function begin to work,below three variable always need
187 * be set, seems we can put them together in some place */
188 base
= par
->crtc
.oScreen
;
189 pitch
= info
->fix
.line_length
;
190 Bpp
= info
->var
.bits_per_pixel
>> 3;
192 color
= (Bpp
== 1)?region
->color
:((u32
*)info
->pseudo_palette
)[region
->color
];
193 rop
= ( region
->rop
!= ROP_COPY
) ? HW_ROP2_XOR
:HW_ROP2_COPY
;
196 * If not use spin_lock,system will die if user load driver
197 * and immediatly unload driver frequently (dual)
200 spin_lock(&share
->slock
);
202 share
->accel
.de_fillrect(&share
->accel
,
204 region
->dx
, region
->dy
,
205 region
->width
, region
->height
,
208 spin_unlock(&share
->slock
);
211 static void lynxfb_ops_copyarea(struct fb_info
* info
, const struct fb_copyarea
* region
)
213 struct lynxfb_par
* par
;
214 struct lynx_share
* share
;
215 unsigned int base
, pitch
, Bpp
;
220 /* each time 2d function begin to work,below three variable always need
221 * be set, seems we can put them together in some place */
222 base
= par
->crtc
.oScreen
;
223 pitch
= info
->fix
.line_length
;
224 Bpp
= info
->var
.bits_per_pixel
>> 3;
227 * If not use spin_lock, system will die if user load driver
228 * and immediatly unload driver frequently (dual)
231 spin_lock(&share
->slock
);
233 share
->accel
.de_copyarea(&share
->accel
,
234 base
, pitch
, region
->sx
, region
->sy
,
235 base
, pitch
, Bpp
, region
->dx
, region
->dy
,
236 region
->width
, region
->height
, HW_ROP2_COPY
);
238 spin_unlock(&share
->slock
);
241 static void lynxfb_ops_imageblit(struct fb_info
*info
, const struct fb_image
* image
)
243 unsigned int base
, pitch
, Bpp
;
244 unsigned int fgcol
, bgcol
;
245 struct lynxfb_par
* par
;
246 struct lynx_share
* share
;
250 /* each time 2d function begin to work,below three variable always need
251 * be set, seems we can put them together in some place */
252 base
= par
->crtc
.oScreen
;
253 pitch
= info
->fix
.line_length
;
254 Bpp
= info
->var
.bits_per_pixel
>> 3;
256 if(image
->depth
== 1){
257 if(info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
258 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
)
260 fgcol
= ((u32
*)info
->pseudo_palette
)[image
->fg_color
];
261 bgcol
= ((u32
*)info
->pseudo_palette
)[image
->bg_color
];
265 fgcol
= image
->fg_color
;
266 bgcol
= image
->bg_color
;
273 * If not use spin_lock, system will die if user load driver
274 * and immediatly unload driver frequently (dual)
277 spin_lock(&share
->slock
);
279 share
->accel
.de_imageblit(&share
->accel
,
280 image
->data
, image
->width
>>3, 0,
282 image
->dx
, image
->dy
,
283 image
->width
, image
->height
,
284 fgcol
, bgcol
, HW_ROP2_COPY
);
286 spin_unlock(&share
->slock
);
289 static int lynxfb_ops_pan_display(struct fb_var_screeninfo
*var
,
290 struct fb_info
*info
)
292 struct lynxfb_par
* par
;
293 struct lynxfb_crtc
* crtc
;
303 ret
= crtc
->proc_panDisplay(crtc
, var
, info
);
308 static int lynxfb_ops_set_par(struct fb_info
* info
)
310 struct lynxfb_par
* par
;
311 struct lynx_share
* share
;
312 struct lynxfb_crtc
* crtc
;
313 struct lynxfb_output
* output
;
314 struct fb_var_screeninfo
* var
;
315 struct fb_fix_screeninfo
* fix
;
317 unsigned int line_length
;
326 output
= &par
->output
;
330 /* fix structur is not so FIX ... */
331 line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
332 line_length
= PADDING(crtc
->line_pad
, line_length
);
333 fix
->line_length
= line_length
;
334 pr_err("fix->line_length = %d\n", fix
->line_length
);
336 /* var->red,green,blue,transp are need to be set by driver
337 * and these data should be set before setcolreg routine
340 switch(var
->bits_per_pixel
){
342 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
345 var
->green
.offset
= 0;
346 var
->green
.length
= 8;
347 var
->blue
.offset
= 0;
348 var
->blue
.length
= 8;
349 var
->transp
.length
= 0;
350 var
->transp
.offset
= 0;
353 var
->red
.offset
= 11;
355 var
->green
.offset
= 5;
356 var
->green
.length
= 6;
357 var
->blue
.offset
= 0;
358 var
->blue
.length
= 5;
359 var
->transp
.length
= 0;
360 var
->transp
.offset
= 0;
361 fix
->visual
= FB_VISUAL_TRUECOLOR
;
365 var
->red
.offset
= 16;
367 var
->green
.offset
= 8;
368 var
->green
.length
= 8;
369 var
->blue
.offset
= 0 ;
370 var
->blue
.length
= 8;
371 fix
->visual
= FB_VISUAL_TRUECOLOR
;
377 var
->height
= var
->width
= -1;
378 var
->accel_flags
= 0;/*FB_ACCELF_TEXT;*/
381 pr_err("pixel bpp format not satisfied\n.");
384 ret
= crtc
->proc_setMode(crtc
, var
, fix
);
386 ret
= output
->proc_setMode(output
, var
, fix
);
390 static inline unsigned int chan_to_field(unsigned int chan
, struct fb_bitfield
* bf
)
393 chan
>>= 16 - bf
->length
;
394 return chan
<< bf
->offset
;
398 static int lynxfb_suspend(struct pci_dev
*pdev
, pm_message_t mesg
)
400 struct fb_info
*info
;
401 struct lynx_share
*share
;
404 if (mesg
.event
== pdev
->dev
.power
.power_state
.event
)
408 share
= pci_get_drvdata(pdev
);
409 switch (mesg
.event
) {
410 case PM_EVENT_FREEZE
:
411 case PM_EVENT_PRETHAW
:
412 pdev
->dev
.power
.power_state
= mesg
;
417 if (mesg
.event
& PM_EVENT_SLEEP
) {
418 info
= share
->fbinfo
[0];
420 /* 1 means do suspend*/
421 fb_set_suspend(info
, 1);
422 info
= share
->fbinfo
[1];
424 /* 1 means do suspend*/
425 fb_set_suspend(info
, 1);
427 ret
= pci_save_state(pdev
);
429 pr_err("error:%d occurred in pci_save_state\n", ret
);
433 /* set chip to sleep mode*/
435 (*share
->suspend
)(share
);
437 pci_disable_device(pdev
);
438 ret
= pci_set_power_state(pdev
, pci_choose_state(pdev
, mesg
));
440 pr_err("error:%d occurred in pci_set_power_state\n", ret
);
445 pdev
->dev
.power
.power_state
= mesg
;
450 static int lynxfb_resume(struct pci_dev
* pdev
)
452 struct fb_info
* info
;
453 struct lynx_share
* share
;
455 struct lynxfb_par
* par
;
456 struct lynxfb_crtc
* crtc
;
457 struct lynx_cursor
* cursor
;
463 share
= pci_get_drvdata(pdev
);
467 if((ret
= pci_set_power_state(pdev
, PCI_D0
)) != 0){
468 pr_err("error:%d occured in pci_set_power_state\n", ret
);
473 if(pdev
->dev
.power
.power_state
.event
!= PM_EVENT_FREEZE
){
474 pci_restore_state(pdev
);
475 if ((ret
= pci_enable_device(pdev
)) != 0){
476 pr_err("error:%d occured in pci_enable_device\n", ret
);
479 pci_set_master(pdev
);
482 (*share
->resume
)(share
);
484 hw_sm750_inithw(share
, pdev
);
487 info
= share
->fbinfo
[0];
492 cursor
= &crtc
->cursor
;
493 memset_io(cursor
->vstart
, 0x0, cursor
->size
);
494 memset_io(crtc
->vScreen
, 0x0, crtc
->vidmem_size
);
495 lynxfb_ops_set_par(info
);
496 fb_set_suspend(info
, 0);
499 info
= share
->fbinfo
[1];
504 cursor
= &crtc
->cursor
;
505 memset_io(cursor
->vstart
, 0x0, cursor
->size
);
506 memset_io(crtc
->vScreen
, 0x0, crtc
->vidmem_size
);
507 lynxfb_ops_set_par(info
);
508 fb_set_suspend(info
, 0);
517 static int lynxfb_ops_check_var(struct fb_var_screeninfo
* var
, struct fb_info
* info
)
519 struct lynxfb_par
* par
;
520 struct lynxfb_crtc
* crtc
;
521 struct lynxfb_output
* output
;
522 struct lynx_share
* share
;
524 resource_size_t request
;
529 output
= &par
->output
;
533 pr_debug("check var:%dx%d-%d\n",
536 var
->bits_per_pixel
);
539 switch(var
->bits_per_pixel
){
542 case 24: /* support 24 bpp for only lynx712/722/720 */
546 pr_err("bpp %d not supported\n", var
->bits_per_pixel
);
551 switch(var
->bits_per_pixel
){
553 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
556 var
->green
.offset
= 0;
557 var
->green
.length
= 8;
558 var
->blue
.offset
= 0;
559 var
->blue
.length
= 8;
560 var
->transp
.length
= 0;
561 var
->transp
.offset
= 0;
564 var
->red
.offset
= 11;
566 var
->green
.offset
= 5;
567 var
->green
.length
= 6;
568 var
->blue
.offset
= 0;
569 var
->blue
.length
= 5;
570 var
->transp
.length
= 0;
571 var
->transp
.offset
= 0;
572 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
576 var
->red
.offset
= 16;
578 var
->green
.offset
= 8;
579 var
->green
.length
= 8;
580 var
->blue
.offset
= 0 ;
581 var
->blue
.length
= 8;
582 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
588 var
->height
= var
->width
= -1;
589 var
->accel_flags
= 0;/*FB_ACCELF_TEXT;*/
591 /* check if current fb's video memory big enought to hold the onscreen */
592 request
= var
->xres_virtual
* (var
->bits_per_pixel
>> 3);
593 /* defaulty crtc->channel go with par->index */
595 request
= PADDING(crtc
->line_pad
, request
);
596 request
= request
* var
->yres_virtual
;
597 if(crtc
->vidmem_size
< request
){
598 pr_err("not enough video memory for mode\n");
602 ret
= output
->proc_checkMode(output
, var
);
604 ret
= crtc
->proc_checkMode(crtc
, var
);
610 static int lynxfb_ops_setcolreg(unsigned regno
, unsigned red
,
611 unsigned green
, unsigned blue
,
612 unsigned transp
, struct fb_info
* info
)
614 struct lynxfb_par
* par
;
615 struct lynxfb_crtc
* crtc
;
616 struct fb_var_screeninfo
* var
;
624 //pr_debug("regno=%d,red=%d,green=%d,blue=%d\n",regno,red,green,blue);
626 pr_err("regno = %d\n", regno
);
630 if(info
->var
.grayscale
)
631 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
633 if(var
->bits_per_pixel
== 8 && info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
)
638 ret
= crtc
->proc_setColReg(crtc
, regno
, red
, green
, blue
);
643 if(info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 256 )
646 if(var
->bits_per_pixel
== 16 ||
647 var
->bits_per_pixel
== 32 ||
648 var
->bits_per_pixel
== 24)
650 val
= chan_to_field(red
, &var
->red
);
651 val
|= chan_to_field(green
, &var
->green
);
652 val
|= chan_to_field(blue
, &var
->blue
);
653 par
->pseudo_palette
[regno
] = val
;
664 static int lynxfb_ops_blank(int blank
, struct fb_info
* info
)
666 struct lynxfb_par
* par
;
667 struct lynxfb_output
* output
;
669 pr_debug("blank = %d.\n", blank
);
671 output
= &par
->output
;
672 return output
->proc_setBLANK(output
, blank
);
675 static int sm750fb_set_drv(struct lynxfb_par
* par
)
678 struct lynx_share
* share
;
679 struct sm750_share
* spec_share
;
680 struct lynxfb_output
* output
;
681 struct lynxfb_crtc
* crtc
;
686 spec_share
= container_of(share
, struct sm750_share
, share
);
687 output
= &par
->output
;
690 crtc
->vidmem_size
= (share
->dual
)?share
->vidmem_size
>>1:share
->vidmem_size
;
691 /* setup crtc and output member */
692 spec_share
->hwCursor
= g_hwcursor
;
694 crtc
->proc_setMode
= hw_sm750_crtc_setMode
;
695 crtc
->proc_checkMode
= hw_sm750_crtc_checkMode
;
696 crtc
->proc_setColReg
= hw_sm750_setColReg
;
697 crtc
->proc_panDisplay
= hw_sm750_pan_display
;
698 crtc
->clear
= hw_sm750_crtc_clear
;
700 //crtc->xpanstep = crtc->ypanstep = crtc->ywrapstep = 0;
705 output
->proc_setMode
= hw_sm750_output_setMode
;
706 output
->proc_checkMode
= hw_sm750_output_checkMode
;
708 output
->proc_setBLANK
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_setBLANK
:hw_sm750_setBLANK
;
709 output
->clear
= hw_sm750_output_clear
;
710 /* chip specific phase */
711 share
->accel
.de_wait
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_deWait
: hw_sm750_deWait
;
712 switch (spec_share
->state
.dataflow
)
714 case sm750_simul_pri
:
715 output
->paths
= sm750_pnc
;
716 crtc
->channel
= sm750_primary
;
718 crtc
->vScreen
= share
->pvMem
;
719 pr_info("use simul primary mode\n");
721 case sm750_simul_sec
:
722 output
->paths
= sm750_pnc
;
723 crtc
->channel
= sm750_secondary
;
725 crtc
->vScreen
= share
->pvMem
;
727 case sm750_dual_normal
:
729 output
->paths
= sm750_panel
;
730 crtc
->channel
= sm750_primary
;
732 crtc
->vScreen
= share
->pvMem
;
734 output
->paths
= sm750_crt
;
735 crtc
->channel
= sm750_secondary
;
736 /* not consider of padding stuffs for oScreen,need fix*/
737 crtc
->oScreen
= (share
->vidmem_size
>> 1);
738 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
741 case sm750_dual_swap
:
743 output
->paths
= sm750_panel
;
744 crtc
->channel
= sm750_secondary
;
746 crtc
->vScreen
= share
->pvMem
;
748 output
->paths
= sm750_crt
;
749 crtc
->channel
= sm750_primary
;
750 /* not consider of padding stuffs for oScreen,need fix*/
751 crtc
->oScreen
= (share
->vidmem_size
>> 1);
752 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
762 static struct fb_ops lynxfb_ops
={
763 .owner
= THIS_MODULE
,
764 .fb_check_var
= lynxfb_ops_check_var
,
765 .fb_set_par
= lynxfb_ops_set_par
,
766 .fb_setcolreg
= lynxfb_ops_setcolreg
,
767 .fb_blank
= lynxfb_ops_blank
,
768 .fb_fillrect
= cfb_fillrect
,
769 .fb_imageblit
= cfb_imageblit
,
770 .fb_copyarea
= cfb_copyarea
,
772 .fb_cursor
= lynxfb_ops_cursor
,
776 static int lynxfb_set_fbinfo(struct fb_info
* info
, int index
)
779 struct lynxfb_par
* par
;
780 struct lynx_share
* share
;
781 struct lynxfb_crtc
* crtc
;
782 struct lynxfb_output
* output
;
783 struct fb_var_screeninfo
* var
;
784 struct fb_fix_screeninfo
* fix
;
786 const struct fb_videomode
* pdb
[] = {
787 lynx750_ext
, NULL
, vesa_modes
,
789 int cdb
[] = {ARRAY_SIZE(lynx750_ext
), 0, VESA_MODEDB_SIZE
};
790 static const char * mdb_desc
[] ={
791 "driver prepared modes",
792 "kernel prepared default modedb",
793 "kernel HELPERS prepared vesa_modes",
797 static const char * fixId
[2]=
799 "sm750_fb1", "sm750_fb2",
802 int ret
, line_length
;
805 par
= (struct lynxfb_par
*)info
->par
;
808 output
= &par
->output
;
814 output
->channel
= &crtc
->channel
;
815 sm750fb_set_drv(par
);
816 lynxfb_ops
.fb_pan_display
= lynxfb_ops_pan_display
;
819 /* set current cursor variable and proc pointer,
820 * must be set after crtc member initialized */
821 crtc
->cursor
.offset
= crtc
->oScreen
+ crtc
->vidmem_size
- 1024;
822 crtc
->cursor
.mmio
= share
->pvReg
+ 0x800f0 + (int)crtc
->channel
* 0x140;
824 pr_info("crtc->cursor.mmio = %p\n", crtc
->cursor
.mmio
);
825 crtc
->cursor
.maxH
= crtc
->cursor
.maxW
= 64;
826 crtc
->cursor
.size
= crtc
->cursor
.maxH
*crtc
->cursor
.maxW
*2/8;
827 crtc
->cursor
.disable
= hw_cursor_disable
;
828 crtc
->cursor
.enable
= hw_cursor_enable
;
829 crtc
->cursor
.setColor
= hw_cursor_setColor
;
830 crtc
->cursor
.setPos
= hw_cursor_setPos
;
831 crtc
->cursor
.setSize
= hw_cursor_setSize
;
832 crtc
->cursor
.setData
= hw_cursor_setData
;
833 crtc
->cursor
.vstart
= share
->pvMem
+ crtc
->cursor
.offset
;
836 crtc
->cursor
.share
= share
;
837 memset_io(crtc
->cursor
.vstart
, 0, crtc
->cursor
.size
);
839 lynxfb_ops
.fb_cursor
= NULL
;
840 crtc
->cursor
.disable(&crtc
->cursor
);
844 /* set info->fbops, must be set before fb_find_mode */
845 if(!share
->accel_off
){
846 /* use 2d acceleration */
847 lynxfb_ops
.fb_fillrect
= lynxfb_ops_fillrect
;
848 lynxfb_ops
.fb_copyarea
= lynxfb_ops_copyarea
;
849 lynxfb_ops
.fb_imageblit
= lynxfb_ops_imageblit
;
851 info
->fbops
= &lynxfb_ops
;
853 if(!g_fbmode
[index
]){
854 g_fbmode
[index
] = g_def_fbmode
;
856 g_fbmode
[index
] = g_fbmode
[0];
862 ret
= fb_find_mode(var
, info
, g_fbmode
[index
],
863 pdb
[i
], cdb
[i
], NULL
, 8);
866 pr_info("success! use specified mode:%s in %s\n",
871 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
876 pr_warn("wanna use default mode\n");
879 pr_warn("fall back to any valid mode\n");
881 pr_warn("ret = %d,fb_find_mode failed,with %s\n", ret
, mdb_desc
[i
]);
885 /* some member of info->var had been set by fb_find_mode */
887 pr_info("Member of info->var is :\n\
894 bits_per_pixel=%d\n \
895 ...\n", var
->xres
, var
->yres
, var
->xres_virtual
, var
->yres_virtual
,
896 var
->xoffset
, var
->yoffset
, var
->bits_per_pixel
);
902 line_length
= PADDING(crtc
->line_pad
,
903 (var
->xres_virtual
* var
->bits_per_pixel
/8));
905 info
->pseudo_palette
= &par
->pseudo_palette
[0];
906 info
->screen_base
= crtc
->vScreen
;
907 pr_debug("screen_base vaddr = %p\n", info
->screen_base
);
908 info
->screen_size
= line_length
* var
->yres_virtual
;
909 info
->flags
= FBINFO_FLAG_DEFAULT
|0;
912 fix
->type
= FB_TYPE_PACKED_PIXELS
;
914 fix
->xpanstep
= crtc
->xpanstep
;
915 fix
->ypanstep
= crtc
->ypanstep
;
916 fix
->ywrapstep
= crtc
->ywrapstep
;
917 fix
->accel
= FB_ACCEL_SMI
;
919 strlcpy(fix
->id
, fixId
[index
], sizeof(fix
->id
));
922 fix
->smem_start
= crtc
->oScreen
+ share
->vidmem_start
;
923 pr_info("fix->smem_start = %lx\n", fix
->smem_start
);
924 /* according to mmap experiment from user space application,
925 * fix->mmio_len should not larger than virtual size
926 * (xres_virtual x yres_virtual x ByPP)
927 * Below line maybe buggy when user mmap fb dev node and write
928 * data into the bound over virtual size
930 fix
->smem_len
= crtc
->vidmem_size
;
931 pr_info("fix->smem_len = %x\n", fix
->smem_len
);
932 info
->screen_size
= fix
->smem_len
;
933 fix
->line_length
= line_length
;
934 fix
->mmio_start
= share
->vidreg_start
;
935 pr_info("fix->mmio_start = %lx\n", fix
->mmio_start
);
936 fix
->mmio_len
= share
->vidreg_size
;
937 pr_info("fix->mmio_len = %x\n", fix
->mmio_len
);
938 switch(var
->bits_per_pixel
)
941 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
945 fix
->visual
= FB_VISUAL_TRUECOLOR
;
950 var
->activate
= FB_ACTIVATE_NOW
;
951 var
->accel_flags
= 0;
952 var
->vmode
= FB_VMODE_NONINTERLACED
;
954 pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
955 info
->cmap
.start
, info
->cmap
.len
,
956 info
->cmap
.red
, info
->cmap
.green
, info
->cmap
.blue
,
959 if((ret
= fb_alloc_cmap(&info
->cmap
, 256, 0)) < 0){
960 pr_err("Could not allcate memory for cmap.\n");
964 pr_debug("#2 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
965 info
->cmap
.start
, info
->cmap
.len
,
966 info
->cmap
.red
, info
->cmap
.green
, info
->cmap
.blue
,
970 lynxfb_ops_check_var(var
, info
);
971 // lynxfb_ops_set_par(info);
975 /* chip specific g_option configuration routine */
976 static void sm750fb_setup(struct lynx_share
* share
, char * src
)
978 struct sm750_share
* spec_share
;
986 spec_share
= container_of(share
, struct sm750_share
, share
);
987 #ifdef CAP_EXPENSIION
992 spec_share
->state
.initParm
.chip_clk
= 0;
993 spec_share
->state
.initParm
.mem_clk
= 0;
994 spec_share
->state
.initParm
.master_clk
= 0;
995 spec_share
->state
.initParm
.powerMode
= 0;
996 spec_share
->state
.initParm
.setAllEngOff
= 0;
997 spec_share
->state
.initParm
.resetMemory
= 1;
999 /*defaultly turn g_hwcursor on for both view */
1003 pr_warn("no specific g_option.\n");
1007 while((opt
= strsep(&src
, ":")) != NULL
&& *opt
!= 0){
1008 pr_err("opt=%s\n", opt
);
1009 pr_err("src=%s\n", src
);
1011 if(!strncmp(opt
, "swap", strlen("swap")))
1013 else if(!strncmp(opt
, "nocrt", strlen("nocrt")))
1014 spec_share
->state
.nocrt
= 1;
1015 else if(!strncmp(opt
, "36bit", strlen("36bit")))
1016 spec_share
->state
.pnltype
= sm750_doubleTFT
;
1017 else if(!strncmp(opt
, "18bit", strlen("18bit")))
1018 spec_share
->state
.pnltype
= sm750_dualTFT
;
1019 else if(!strncmp(opt
, "24bit", strlen("24bit")))
1020 spec_share
->state
.pnltype
= sm750_24TFT
;
1021 #ifdef CAP_EXPANSION
1022 else if(!strncmp(opt
, "exp:", strlen("exp:")))
1023 exp_res
= opt
+ strlen("exp:");
1025 else if(!strncmp(opt
, "nohwc0", strlen("nohwc0")))
1027 else if(!strncmp(opt
, "nohwc1", strlen("nohwc1")))
1029 else if(!strncmp(opt
, "nohwc", strlen("nohwc")))
1035 pr_info("find fbmode0 : %s\n", g_fbmode
[0]);
1036 }else if(!g_fbmode
[1]){
1038 pr_info("find fbmode1 : %s\n", g_fbmode
[1]);
1040 pr_warn("How many view you wann set?\n");
1044 #ifdef CAP_EXPANSION
1045 if(getExpRes(exp_res
, &spec_share
->state
.xLCD
, &spec_share
->state
.yLCD
))
1047 /* seems exp_res is not valid*/
1048 spec_share
->state
.xLCD
= spec_share
->state
.yLCD
= 0;
1053 if(share
->revid
!= SM750LE_REVISION_ID
){
1057 spec_share
->state
.dataflow
= sm750_dual_swap
;
1059 spec_share
->state
.dataflow
= sm750_dual_normal
;
1062 spec_share
->state
.dataflow
= sm750_simul_sec
;
1064 spec_share
->state
.dataflow
= sm750_simul_pri
;
1067 /* SM750LE only have one crt channel */
1068 spec_share
->state
.dataflow
= sm750_simul_sec
;
1069 /* sm750le do not have complex attributes*/
1070 spec_share
->state
.nocrt
= 0;
1074 static int lynxfb_pci_probe(struct pci_dev
* pdev
,
1075 const struct pci_device_id
* ent
)
1077 struct fb_info
* info
[] = {NULL
, NULL
};
1078 struct lynx_share
* share
= NULL
;
1080 struct sm750_share
*spec_share
= NULL
;
1081 size_t spec_offset
= 0;
1086 if(pci_enable_device(pdev
)){
1087 pr_err("can not enable device.\n");
1091 /* though offset of share in sm750_share is 0,
1092 * we use this marcro as the same */
1093 spec_offset
= offsetof(struct sm750_share
, share
);
1095 spec_share
= kzalloc(sizeof(*spec_share
), GFP_KERNEL
);
1097 pr_err("Could not allocate memory for share.\n");
1101 /* setting share structure */
1102 share
= (struct lynx_share
* )(&(spec_share
->share
));
1103 share
->fbinfo
[0] = share
->fbinfo
[1] = NULL
;
1104 share
->devid
= pdev
->device
;
1105 share
->revid
= pdev
->revision
;
1107 pr_info("share->revid = %02x\n", share
->revid
);
1110 share
->mtrr_off
= g_nomtrr
;
1111 share
->mtrr
.vram
= 0;
1112 share
->mtrr
.vram_added
= 0;
1114 share
->accel_off
= g_noaccel
;
1115 share
->dual
= g_dualview
;
1116 spin_lock_init(&share
->slock
);
1118 if(!share
->accel_off
){
1119 /* hook deInit and 2d routines, notes that below hw_xxx
1120 * routine can work on most of lynx chips
1121 * if some chip need specific function,please hook it in smXXX_set_drv
1123 share
->accel
.de_init
= hw_de_init
;
1124 share
->accel
.de_fillrect
= hw_fillrect
;
1125 share
->accel
.de_copyarea
= hw_copyarea
;
1126 share
->accel
.de_imageblit
= hw_imageblit
;
1127 pr_info("enable 2d acceleration\n");
1129 pr_info("disable 2d acceleration\n");
1132 /* call chip specific setup routine */
1133 sm750fb_setup(share
, g_settings
);
1135 /* call chip specific mmap routine */
1136 if(hw_sm750_map(share
, pdev
)){
1137 pr_err("Memory map failed\n");
1142 if(!share
->mtrr_off
){
1143 pr_info("enable mtrr\n");
1144 share
->mtrr
.vram
= mtrr_add(share
->vidmem_start
,
1146 MTRR_TYPE_WRCOMB
, 1);
1148 if(share
->mtrr
.vram
< 0){
1149 /* don't block driver with the failure of MTRR */
1150 pr_err("Unable to setup MTRR.\n");
1152 share
->mtrr
.vram_added
= 1;
1153 pr_info("MTRR added succesfully\n");
1158 memset_io(share
->pvMem
, 0, share
->vidmem_size
);
1160 pr_info("sm%3x mmio address = %p\n", share
->devid
, share
->pvReg
);
1162 pci_set_drvdata(pdev
, share
);
1164 /* call chipInit routine */
1165 hw_sm750_inithw(share
, pdev
);
1167 /* allocate frame buffer info structor according to g_dualview */
1170 info
[fbidx
] = framebuffer_alloc(sizeof(struct lynxfb_par
), &pdev
->dev
);
1173 pr_err("Could not allocate framebuffer #%d.\n", fbidx
);
1175 goto err_info0_alloc
;
1177 goto err_info1_alloc
;
1181 struct lynxfb_par
* par
;
1183 pr_info("framebuffer #%d alloc okay\n", fbidx
);
1184 share
->fbinfo
[fbidx
] = info
[fbidx
];
1185 par
= info
[fbidx
]->par
;
1188 /* set fb_info structure */
1189 if(lynxfb_set_fbinfo(info
[fbidx
], fbidx
)){
1190 pr_err("Failed to initial fb_info #%d.\n", fbidx
);
1197 /* register frame buffer*/
1198 pr_info("Ready to register framebuffer #%d.\n", fbidx
);
1199 errno
= register_framebuffer(info
[fbidx
]);
1201 pr_err("Failed to register fb_info #%d. err %d\n", fbidx
, errno
);
1207 pr_info("Accomplished register framebuffer #%d.\n", fbidx
);
1210 /* no dual view by far */
1212 if(share
->dual
&& fbidx
< 2)
1219 framebuffer_release(info
[1]);
1221 unregister_framebuffer(info
[0]);
1224 framebuffer_release(info
[0]);
1233 static void __exit
lynxfb_pci_remove(struct pci_dev
* pdev
)
1235 struct fb_info
* info
;
1236 struct lynx_share
* share
;
1238 struct lynxfb_par
* par
;
1242 share
= pci_get_drvdata(pdev
);
1245 info
= share
->fbinfo
[cnt
];
1250 unregister_framebuffer(info
);
1251 /* clean crtc & output allocations*/
1252 par
->crtc
.clear(&par
->crtc
);
1253 par
->output
.clear(&par
->output
);
1254 /* release frame buffer*/
1255 framebuffer_release(info
);
1258 if(share
->mtrr
.vram_added
)
1259 mtrr_del(share
->mtrr
.vram
, share
->vidmem_start
, share
->vidmem_size
);
1261 // pci_release_regions(pdev);
1263 iounmap(share
->pvReg
);
1264 iounmap(share
->pvMem
);
1265 spec_share
= container_of(share
, struct sm750_share
, share
);
1268 pci_set_drvdata(pdev
, NULL
);
1271 static int __init
lynxfb_setup(char * options
)
1277 if(!options
|| !*options
){
1278 pr_warn("no options.\n");
1282 pr_info("options:%s\n", options
);
1284 len
= strlen(options
) + 1;
1285 g_settings
= kzalloc(len
, GFP_KERNEL
);
1292 char * strsep(char **s,const char * ct);
1293 @s: the string to be searched
1294 @ct :the characters to search for
1296 strsep() updates @options to pointer after the first found token
1297 it also returns the pointer ahead the token.
1299 while((opt
= strsep(&options
, ":"))!=NULL
)
1301 /* options that mean for any lynx chips are configured here */
1302 if(!strncmp(opt
, "noaccel", strlen("noaccel")))
1305 else if(!strncmp(opt
, "nomtrr", strlen("nomtrr")))
1308 else if(!strncmp(opt
, "dual", strlen("dual")))
1321 /* misc g_settings are transport to chip specific routines */
1322 pr_info("parameter left for chip specific analysis:%s\n", g_settings
);
1326 static struct pci_device_id smi_pci_table
[] = {
1327 { PCI_DEVICE(0x126f, 0x0750), },
1331 MODULE_DEVICE_TABLE(pci
, smi_pci_table
);
1333 static struct pci_driver lynxfb_driver
= {
1335 .id_table
= smi_pci_table
,
1336 .probe
= lynxfb_pci_probe
,
1337 .remove
= lynxfb_pci_remove
,
1339 .suspend
= lynxfb_suspend
,
1340 .resume
= lynxfb_resume
,
1345 static int __init
lynxfb_init(void)
1353 if(fb_get_options("sm750fb", &option
))
1357 lynxfb_setup(option
);
1358 ret
= pci_register_driver(&lynxfb_driver
);
1361 module_init(lynxfb_init
);
1363 static void __exit
lynxfb_exit(void)
1365 pci_unregister_driver(&lynxfb_driver
);
1367 module_exit(lynxfb_exit
);
1369 module_param(g_option
, charp
, S_IRUGO
);
1371 MODULE_PARM_DESC(g_option
,
1372 "\n\t\tCommon options:\n"
1373 "\t\tnoaccel:disable 2d capabilities\n"
1374 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1375 "\t\tdualview:dual frame buffer feature enabled\n"
1376 "\t\tnohwc:disable hardware cursor\n"
1377 "\t\tUsual example:\n"
1378 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1381 MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1382 MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1383 MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1384 MODULE_LICENSE("GPL v2");