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
;
60 static const struct fb_videomode lynx750_ext
[] = {
61 /* 1024x600-60 VESA [1.71:1] */
62 {NULL
, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
63 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
64 FB_VMODE_NONINTERLACED
},
66 /* 1024x600-70 VESA */
67 {NULL
, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
68 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
69 FB_VMODE_NONINTERLACED
},
71 /* 1024x600-75 VESA */
72 {NULL
, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
73 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
74 FB_VMODE_NONINTERLACED
},
76 /* 1024x600-85 VESA */
77 {NULL
, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
78 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
79 FB_VMODE_NONINTERLACED
},
82 {NULL
, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
83 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
84 FB_VMODE_NONINTERLACED
},
86 /* 1280x720 [1.78:1] */
87 {NULL
, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
88 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
89 FB_VMODE_NONINTERLACED
},
92 {NULL
, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
93 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
94 FB_VMODE_NONINTERLACED
},
96 {NULL
, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
97 FB_SYNC_HOR_HIGH_ACT
|FB_VMODE_NONINTERLACED
},
99 /* 1360 x 768 [1.77083:1] */
100 {NULL
, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
101 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
102 FB_VMODE_NONINTERLACED
},
104 /* 1368 x 768 [1.78:1] */
105 {NULL
, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
106 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
107 FB_VMODE_NONINTERLACED
},
109 /* 1440 x 900 [16:10] */
110 {NULL
, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
111 FB_SYNC_VERT_HIGH_ACT
,
112 FB_VMODE_NONINTERLACED
},
114 /* 1440x960 [15:10] */
115 {NULL
, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
116 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
117 FB_VMODE_NONINTERLACED
},
119 /* 1920x1080 [16:9] */
120 {NULL
, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
121 FB_SYNC_VERT_HIGH_ACT
,
122 FB_VMODE_NONINTERLACED
},
128 /* no hardware cursor supported under version 2.6.10, kernel bug */
129 static int lynxfb_ops_cursor(struct fb_info
*info
, struct fb_cursor
*fbcursor
)
131 struct lynxfb_par
*par
;
132 struct lynxfb_crtc
*crtc
;
133 struct lynx_cursor
*cursor
;
137 cursor
= &crtc
->cursor
;
139 if (fbcursor
->image
.width
> cursor
->maxW
||
140 fbcursor
->image
.height
> cursor
->maxH
||
141 fbcursor
->image
.depth
> 1) {
145 cursor
->disable(cursor
);
146 if (fbcursor
->set
& FB_CUR_SETSIZE
)
147 cursor
->setSize(cursor
,
148 fbcursor
->image
.width
,
149 fbcursor
->image
.height
);
151 if (fbcursor
->set
& FB_CUR_SETPOS
)
152 cursor
->setPos(cursor
,
153 fbcursor
->image
.dx
- info
->var
.xoffset
,
154 fbcursor
->image
.dy
- info
->var
.yoffset
);
156 if (fbcursor
->set
& FB_CUR_SETCMAP
) {
157 /* get the 16bit color of kernel means */
160 fg
= ((info
->cmap
.red
[fbcursor
->image
.fg_color
] & 0xf800))|
161 ((info
->cmap
.green
[fbcursor
->image
.fg_color
] & 0xfc00) >> 5)|
162 ((info
->cmap
.blue
[fbcursor
->image
.fg_color
] & 0xf800) >> 11);
164 bg
= ((info
->cmap
.red
[fbcursor
->image
.bg_color
] & 0xf800))|
165 ((info
->cmap
.green
[fbcursor
->image
.bg_color
] & 0xfc00) >> 5)|
166 ((info
->cmap
.blue
[fbcursor
->image
.bg_color
] & 0xf800) >> 11);
168 cursor
->setColor(cursor
, fg
, bg
);
172 if (fbcursor
->set
& (FB_CUR_SETSHAPE
| FB_CUR_SETIMAGE
)) {
173 cursor
->setData(cursor
,
175 fbcursor
->image
.data
,
179 if (fbcursor
->enable
)
180 cursor
->enable(cursor
);
185 static void lynxfb_ops_fillrect(struct fb_info
*info
,
186 const struct fb_fillrect
*region
)
188 struct lynxfb_par
*par
;
189 struct lynx_share
*share
;
190 unsigned int base
, pitch
, Bpp
, rop
;
193 if (info
->state
!= FBINFO_STATE_RUNNING
)
199 /* each time 2d function begin to work,below three variable always need
200 * be set, seems we can put them together in some place */
201 base
= par
->crtc
.oScreen
;
202 pitch
= info
->fix
.line_length
;
203 Bpp
= info
->var
.bits_per_pixel
>> 3;
205 color
= (Bpp
== 1)?region
->color
:((u32
*)info
->pseudo_palette
)[region
->color
];
206 rop
= (region
->rop
!= ROP_COPY
) ? HW_ROP2_XOR
:HW_ROP2_COPY
;
209 * If not use spin_lock,system will die if user load driver
210 * and immediately unload driver frequently (dual)
213 spin_lock(&share
->slock
);
215 share
->accel
.de_fillrect(&share
->accel
,
217 region
->dx
, region
->dy
,
218 region
->width
, region
->height
,
221 spin_unlock(&share
->slock
);
224 static void lynxfb_ops_copyarea(struct fb_info
*info
,
225 const struct fb_copyarea
*region
)
227 struct lynxfb_par
*par
;
228 struct lynx_share
*share
;
229 unsigned int base
, pitch
, Bpp
;
234 /* each time 2d function begin to work,below three variable always need
235 * be set, seems we can put them together in some place */
236 base
= par
->crtc
.oScreen
;
237 pitch
= info
->fix
.line_length
;
238 Bpp
= info
->var
.bits_per_pixel
>> 3;
241 * If not use spin_lock, system will die if user load driver
242 * and immediately unload driver frequently (dual)
245 spin_lock(&share
->slock
);
247 share
->accel
.de_copyarea(&share
->accel
,
248 base
, pitch
, region
->sx
, region
->sy
,
249 base
, pitch
, Bpp
, region
->dx
, region
->dy
,
250 region
->width
, region
->height
, HW_ROP2_COPY
);
252 spin_unlock(&share
->slock
);
255 static void lynxfb_ops_imageblit(struct fb_info
*info
,
256 const struct fb_image
*image
)
258 unsigned int base
, pitch
, Bpp
;
259 unsigned int fgcol
, bgcol
;
260 struct lynxfb_par
*par
;
261 struct lynx_share
*share
;
265 /* each time 2d function begin to work,below three variable always need
266 * be set, seems we can put them together in some place */
267 base
= par
->crtc
.oScreen
;
268 pitch
= info
->fix
.line_length
;
269 Bpp
= info
->var
.bits_per_pixel
>> 3;
271 if (image
->depth
== 1) {
272 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
||
273 info
->fix
.visual
== FB_VISUAL_DIRECTCOLOR
) {
274 fgcol
= ((u32
*)info
->pseudo_palette
)[image
->fg_color
];
275 bgcol
= ((u32
*)info
->pseudo_palette
)[image
->bg_color
];
277 fgcol
= image
->fg_color
;
278 bgcol
= image
->bg_color
;
285 * If not use spin_lock, system will die if user load driver
286 * and immediately unload driver frequently (dual)
289 spin_lock(&share
->slock
);
291 share
->accel
.de_imageblit(&share
->accel
,
292 image
->data
, image
->width
>>3, 0,
294 image
->dx
, image
->dy
,
295 image
->width
, image
->height
,
296 fgcol
, bgcol
, HW_ROP2_COPY
);
298 spin_unlock(&share
->slock
);
301 static int lynxfb_ops_pan_display(struct fb_var_screeninfo
*var
,
302 struct fb_info
*info
)
304 struct lynxfb_par
*par
;
305 struct lynxfb_crtc
*crtc
;
315 ret
= crtc
->proc_panDisplay(crtc
, var
, info
);
320 static int lynxfb_ops_set_par(struct fb_info
*info
)
322 struct lynxfb_par
*par
;
323 struct lynx_share
*share
;
324 struct lynxfb_crtc
*crtc
;
325 struct lynxfb_output
*output
;
326 struct fb_var_screeninfo
*var
;
327 struct fb_fix_screeninfo
*fix
;
329 unsigned int line_length
;
338 output
= &par
->output
;
342 /* fix structur is not so FIX ... */
343 line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
344 line_length
= PADDING(crtc
->line_pad
, line_length
);
345 fix
->line_length
= line_length
;
346 pr_err("fix->line_length = %d\n", fix
->line_length
);
348 /* var->red,green,blue,transp are need to be set by driver
349 * and these data should be set before setcolreg routine
352 switch (var
->bits_per_pixel
) {
354 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
357 var
->green
.offset
= 0;
358 var
->green
.length
= 8;
359 var
->blue
.offset
= 0;
360 var
->blue
.length
= 8;
361 var
->transp
.length
= 0;
362 var
->transp
.offset
= 0;
365 var
->red
.offset
= 11;
367 var
->green
.offset
= 5;
368 var
->green
.length
= 6;
369 var
->blue
.offset
= 0;
370 var
->blue
.length
= 5;
371 var
->transp
.length
= 0;
372 var
->transp
.offset
= 0;
373 fix
->visual
= FB_VISUAL_TRUECOLOR
;
377 var
->red
.offset
= 16;
379 var
->green
.offset
= 8;
380 var
->green
.length
= 8;
381 var
->blue
.offset
= 0;
382 var
->blue
.length
= 8;
383 fix
->visual
= FB_VISUAL_TRUECOLOR
;
389 var
->height
= var
->width
= -1;
390 var
->accel_flags
= 0;/*FB_ACCELF_TEXT;*/
393 pr_err("pixel bpp format not satisfied\n.");
396 ret
= crtc
->proc_setMode(crtc
, var
, fix
);
398 ret
= output
->proc_setMode(output
, var
, fix
);
402 static inline unsigned int chan_to_field(unsigned int chan
,
403 struct fb_bitfield
*bf
)
406 chan
>>= 16 - bf
->length
;
407 return chan
<< bf
->offset
;
411 static int lynxfb_suspend(struct pci_dev
*pdev
, pm_message_t mesg
)
413 struct fb_info
*info
;
414 struct lynx_share
*share
;
417 if (mesg
.event
== pdev
->dev
.power
.power_state
.event
)
421 share
= pci_get_drvdata(pdev
);
422 switch (mesg
.event
) {
423 case PM_EVENT_FREEZE
:
424 case PM_EVENT_PRETHAW
:
425 pdev
->dev
.power
.power_state
= mesg
;
430 if (mesg
.event
& PM_EVENT_SLEEP
) {
431 info
= share
->fbinfo
[0];
433 /* 1 means do suspend */
434 fb_set_suspend(info
, 1);
435 info
= share
->fbinfo
[1];
437 /* 1 means do suspend */
438 fb_set_suspend(info
, 1);
440 ret
= pci_save_state(pdev
);
442 pr_err("error:%d occurred in pci_save_state\n", ret
);
446 /* set chip to sleep mode */
448 (*share
->suspend
)(share
);
450 pci_disable_device(pdev
);
451 ret
= pci_set_power_state(pdev
, pci_choose_state(pdev
, mesg
));
453 pr_err("error:%d occurred in pci_set_power_state\n", ret
);
458 pdev
->dev
.power
.power_state
= mesg
;
463 static int lynxfb_resume(struct pci_dev
*pdev
)
465 struct fb_info
*info
;
466 struct lynx_share
*share
;
468 struct lynxfb_par
*par
;
469 struct lynxfb_crtc
*crtc
;
470 struct lynx_cursor
*cursor
;
476 share
= pci_get_drvdata(pdev
);
480 ret
= pci_set_power_state(pdev
, PCI_D0
);
482 pr_err("error:%d occurred in pci_set_power_state\n", ret
);
487 if (pdev
->dev
.power
.power_state
.event
!= PM_EVENT_FREEZE
) {
488 pci_restore_state(pdev
);
489 ret
= pci_enable_device(pdev
);
491 pr_err("error:%d occurred in pci_enable_device\n", ret
);
494 pci_set_master(pdev
);
497 (*share
->resume
)(share
);
499 hw_sm750_inithw(share
, pdev
);
502 info
= share
->fbinfo
[0];
507 cursor
= &crtc
->cursor
;
508 memset_io(cursor
->vstart
, 0x0, cursor
->size
);
509 memset_io(crtc
->vScreen
, 0x0, crtc
->vidmem_size
);
510 lynxfb_ops_set_par(info
);
511 fb_set_suspend(info
, 0);
514 info
= share
->fbinfo
[1];
519 cursor
= &crtc
->cursor
;
520 memset_io(cursor
->vstart
, 0x0, cursor
->size
);
521 memset_io(crtc
->vScreen
, 0x0, crtc
->vidmem_size
);
522 lynxfb_ops_set_par(info
);
523 fb_set_suspend(info
, 0);
532 static int lynxfb_ops_check_var(struct fb_var_screeninfo
*var
,
533 struct fb_info
*info
)
535 struct lynxfb_par
*par
;
536 struct lynxfb_crtc
*crtc
;
537 struct lynxfb_output
*output
;
538 struct lynx_share
*share
;
540 resource_size_t request
;
545 output
= &par
->output
;
549 pr_debug("check var:%dx%d-%d\n",
552 var
->bits_per_pixel
);
555 switch (var
->bits_per_pixel
) {
558 case 24: /* support 24 bpp for only lynx712/722/720 */
562 pr_err("bpp %d not supported\n", var
->bits_per_pixel
);
567 switch (var
->bits_per_pixel
) {
569 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
572 var
->green
.offset
= 0;
573 var
->green
.length
= 8;
574 var
->blue
.offset
= 0;
575 var
->blue
.length
= 8;
576 var
->transp
.length
= 0;
577 var
->transp
.offset
= 0;
580 var
->red
.offset
= 11;
582 var
->green
.offset
= 5;
583 var
->green
.length
= 6;
584 var
->blue
.offset
= 0;
585 var
->blue
.length
= 5;
586 var
->transp
.length
= 0;
587 var
->transp
.offset
= 0;
588 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
592 var
->red
.offset
= 16;
594 var
->green
.offset
= 8;
595 var
->green
.length
= 8;
596 var
->blue
.offset
= 0;
597 var
->blue
.length
= 8;
598 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
604 var
->height
= var
->width
= -1;
605 var
->accel_flags
= 0;/* FB_ACCELF_TEXT; */
607 /* check if current fb's video memory big enought to hold the onscreen*/
608 request
= var
->xres_virtual
* (var
->bits_per_pixel
>> 3);
609 /* defaulty crtc->channel go with par->index */
611 request
= PADDING(crtc
->line_pad
, request
);
612 request
= request
* var
->yres_virtual
;
613 if (crtc
->vidmem_size
< request
) {
614 pr_err("not enough video memory for mode\n");
618 ret
= output
->proc_checkMode(output
, var
);
620 ret
= crtc
->proc_checkMode(crtc
, var
);
626 static int lynxfb_ops_setcolreg(unsigned regno
,
631 struct fb_info
*info
)
633 struct lynxfb_par
*par
;
634 struct lynxfb_crtc
*crtc
;
635 struct fb_var_screeninfo
*var
;
644 pr_err("regno = %d\n", regno
);
648 if (info
->var
.grayscale
)
649 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
651 if (var
->bits_per_pixel
== 8 &&
652 info
->fix
.visual
== FB_VISUAL_PSEUDOCOLOR
) {
656 ret
= crtc
->proc_setColReg(crtc
, regno
, red
, green
, blue
);
661 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
&& regno
< 256) {
664 if (var
->bits_per_pixel
== 16 ||
665 var
->bits_per_pixel
== 32 ||
666 var
->bits_per_pixel
== 24) {
667 val
= chan_to_field(red
, &var
->red
);
668 val
|= chan_to_field(green
, &var
->green
);
669 val
|= chan_to_field(blue
, &var
->blue
);
670 par
->pseudo_palette
[regno
] = val
;
681 static int lynxfb_ops_blank(int blank
, struct fb_info
*info
)
683 struct lynxfb_par
*par
;
684 struct lynxfb_output
*output
;
686 pr_debug("blank = %d.\n", blank
);
688 output
= &par
->output
;
689 return output
->proc_setBLANK(output
, blank
);
692 static int sm750fb_set_drv(struct lynxfb_par
*par
)
695 struct lynx_share
*share
;
696 struct sm750_share
*spec_share
;
697 struct lynxfb_output
*output
;
698 struct lynxfb_crtc
*crtc
;
703 spec_share
= container_of(share
, struct sm750_share
, share
);
704 output
= &par
->output
;
707 crtc
->vidmem_size
= (share
->dual
)?share
->vidmem_size
>>1:share
->vidmem_size
;
708 /* setup crtc and output member */
709 spec_share
->hwCursor
= g_hwcursor
;
711 crtc
->proc_setMode
= hw_sm750_crtc_setMode
;
712 crtc
->proc_checkMode
= hw_sm750_crtc_checkMode
;
713 crtc
->proc_setColReg
= hw_sm750_setColReg
;
714 crtc
->proc_panDisplay
= hw_sm750_pan_display
;
715 crtc
->clear
= hw_sm750_crtc_clear
;
721 output
->proc_setMode
= hw_sm750_output_setMode
;
722 output
->proc_checkMode
= hw_sm750_output_checkMode
;
724 output
->proc_setBLANK
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_setBLANK
:hw_sm750_setBLANK
;
725 output
->clear
= hw_sm750_output_clear
;
726 /* chip specific phase */
727 share
->accel
.de_wait
= (share
->revid
== SM750LE_REVISION_ID
)?hw_sm750le_deWait
: hw_sm750_deWait
;
728 switch (spec_share
->state
.dataflow
) {
729 case sm750_simul_pri
:
730 output
->paths
= sm750_pnc
;
731 crtc
->channel
= sm750_primary
;
733 crtc
->vScreen
= share
->pvMem
;
734 pr_info("use simul primary mode\n");
736 case sm750_simul_sec
:
737 output
->paths
= sm750_pnc
;
738 crtc
->channel
= sm750_secondary
;
740 crtc
->vScreen
= share
->pvMem
;
742 case sm750_dual_normal
:
743 if (par
->index
== 0) {
744 output
->paths
= sm750_panel
;
745 crtc
->channel
= sm750_primary
;
747 crtc
->vScreen
= share
->pvMem
;
749 output
->paths
= sm750_crt
;
750 crtc
->channel
= sm750_secondary
;
751 /* not consider of padding stuffs for oScreen,need fix */
752 crtc
->oScreen
= (share
->vidmem_size
>> 1);
753 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
756 case sm750_dual_swap
:
757 if (par
->index
== 0) {
758 output
->paths
= sm750_panel
;
759 crtc
->channel
= sm750_secondary
;
761 crtc
->vScreen
= share
->pvMem
;
763 output
->paths
= sm750_crt
;
764 crtc
->channel
= sm750_primary
;
765 /* not consider of padding stuffs for oScreen,need fix */
766 crtc
->oScreen
= (share
->vidmem_size
>> 1);
767 crtc
->vScreen
= share
->pvMem
+ crtc
->oScreen
;
777 static struct fb_ops lynxfb_ops
= {
778 .owner
= THIS_MODULE
,
779 .fb_check_var
= lynxfb_ops_check_var
,
780 .fb_set_par
= lynxfb_ops_set_par
,
781 .fb_setcolreg
= lynxfb_ops_setcolreg
,
782 .fb_blank
= lynxfb_ops_blank
,
783 .fb_fillrect
= cfb_fillrect
,
784 .fb_imageblit
= cfb_imageblit
,
785 .fb_copyarea
= cfb_copyarea
,
787 .fb_cursor
= lynxfb_ops_cursor
,
791 static int lynxfb_set_fbinfo(struct fb_info
*info
, int index
)
794 struct lynxfb_par
*par
;
795 struct lynx_share
*share
;
796 struct lynxfb_crtc
*crtc
;
797 struct lynxfb_output
*output
;
798 struct fb_var_screeninfo
*var
;
799 struct fb_fix_screeninfo
*fix
;
801 const struct fb_videomode
*pdb
[] = {
802 lynx750_ext
, NULL
, vesa_modes
,
804 int cdb
[] = {ARRAY_SIZE(lynx750_ext
), 0, VESA_MODEDB_SIZE
};
805 static const char *mdb_desc
[] = {
806 "driver prepared modes",
807 "kernel prepared default modedb",
808 "kernel HELPERS prepared vesa_modes",
812 static const char *fixId
[2] = {
813 "sm750_fb1", "sm750_fb2",
816 int ret
, line_length
;
819 par
= (struct lynxfb_par
*)info
->par
;
822 output
= &par
->output
;
828 output
->channel
= &crtc
->channel
;
829 sm750fb_set_drv(par
);
830 lynxfb_ops
.fb_pan_display
= lynxfb_ops_pan_display
;
833 /* set current cursor variable and proc pointer,
834 * must be set after crtc member initialized */
835 crtc
->cursor
.offset
= crtc
->oScreen
+ crtc
->vidmem_size
- 1024;
836 crtc
->cursor
.mmio
= share
->pvReg
+ 0x800f0 + (int)crtc
->channel
* 0x140;
838 pr_info("crtc->cursor.mmio = %p\n", crtc
->cursor
.mmio
);
839 crtc
->cursor
.maxH
= crtc
->cursor
.maxW
= 64;
840 crtc
->cursor
.size
= crtc
->cursor
.maxH
*crtc
->cursor
.maxW
*2/8;
841 crtc
->cursor
.disable
= hw_cursor_disable
;
842 crtc
->cursor
.enable
= hw_cursor_enable
;
843 crtc
->cursor
.setColor
= hw_cursor_setColor
;
844 crtc
->cursor
.setPos
= hw_cursor_setPos
;
845 crtc
->cursor
.setSize
= hw_cursor_setSize
;
846 crtc
->cursor
.setData
= hw_cursor_setData
;
847 crtc
->cursor
.vstart
= share
->pvMem
+ crtc
->cursor
.offset
;
850 crtc
->cursor
.share
= share
;
851 memset_io(crtc
->cursor
.vstart
, 0, crtc
->cursor
.size
);
853 lynxfb_ops
.fb_cursor
= NULL
;
854 crtc
->cursor
.disable(&crtc
->cursor
);
858 /* set info->fbops, must be set before fb_find_mode */
859 if (!share
->accel_off
) {
860 /* use 2d acceleration */
861 lynxfb_ops
.fb_fillrect
= lynxfb_ops_fillrect
;
862 lynxfb_ops
.fb_copyarea
= lynxfb_ops_copyarea
;
863 lynxfb_ops
.fb_imageblit
= lynxfb_ops_imageblit
;
865 info
->fbops
= &lynxfb_ops
;
867 if (!g_fbmode
[index
]) {
868 g_fbmode
[index
] = g_def_fbmode
;
870 g_fbmode
[index
] = g_fbmode
[0];
874 for (i
= 0; i
< 3; i
++) {
876 ret
= fb_find_mode(var
, info
, g_fbmode
[index
],
877 pdb
[i
], cdb
[i
], NULL
, 8);
880 pr_info("success! use specified mode:%s in %s\n",
884 } else if (ret
== 2) {
885 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
889 } else if (ret
== 3) {
890 pr_warn("wanna use default mode\n");
892 } else if (ret
== 4) {
893 pr_warn("fall back to any valid mode\n");
895 pr_warn("ret = %d,fb_find_mode failed,with %s\n",
901 /* some member of info->var had been set by fb_find_mode */
903 pr_info("Member of info->var is :\n\
910 bits_per_pixel=%d\n \
918 var
->bits_per_pixel
);
924 line_length
= PADDING(crtc
->line_pad
,
925 (var
->xres_virtual
* var
->bits_per_pixel
/8));
927 info
->pseudo_palette
= &par
->pseudo_palette
[0];
928 info
->screen_base
= crtc
->vScreen
;
929 pr_debug("screen_base vaddr = %p\n", info
->screen_base
);
930 info
->screen_size
= line_length
* var
->yres_virtual
;
931 info
->flags
= FBINFO_FLAG_DEFAULT
|0;
934 fix
->type
= FB_TYPE_PACKED_PIXELS
;
936 fix
->xpanstep
= crtc
->xpanstep
;
937 fix
->ypanstep
= crtc
->ypanstep
;
938 fix
->ywrapstep
= crtc
->ywrapstep
;
939 fix
->accel
= FB_ACCEL_SMI
;
941 strlcpy(fix
->id
, fixId
[index
], sizeof(fix
->id
));
944 fix
->smem_start
= crtc
->oScreen
+ share
->vidmem_start
;
945 pr_info("fix->smem_start = %lx\n", fix
->smem_start
);
946 /* according to mmap experiment from user space application,
947 * fix->mmio_len should not larger than virtual size
948 * (xres_virtual x yres_virtual x ByPP)
949 * Below line maybe buggy when user mmap fb dev node and write
950 * data into the bound over virtual size
952 fix
->smem_len
= crtc
->vidmem_size
;
953 pr_info("fix->smem_len = %x\n", fix
->smem_len
);
954 info
->screen_size
= fix
->smem_len
;
955 fix
->line_length
= line_length
;
956 fix
->mmio_start
= share
->vidreg_start
;
957 pr_info("fix->mmio_start = %lx\n", fix
->mmio_start
);
958 fix
->mmio_len
= share
->vidreg_size
;
959 pr_info("fix->mmio_len = %x\n", fix
->mmio_len
);
960 switch (var
->bits_per_pixel
) {
962 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
966 fix
->visual
= FB_VISUAL_TRUECOLOR
;
971 var
->activate
= FB_ACTIVATE_NOW
;
972 var
->accel_flags
= 0;
973 var
->vmode
= FB_VMODE_NONINTERLACED
;
975 pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
976 info
->cmap
.start
, info
->cmap
.len
,
977 info
->cmap
.red
, info
->cmap
.green
, info
->cmap
.blue
,
980 ret
= fb_alloc_cmap(&info
->cmap
, 256, 0);
982 pr_err("Could not allcate memory for cmap.\n");
986 pr_debug("#2 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
987 info
->cmap
.start
, info
->cmap
.len
,
988 info
->cmap
.red
, info
->cmap
.green
, info
->cmap
.blue
,
992 lynxfb_ops_check_var(var
, info
);
996 /* chip specific g_option configuration routine */
997 static void sm750fb_setup(struct lynx_share
*share
, char *src
)
999 struct sm750_share
*spec_share
;
1001 #ifdef CAP_EXPENSION
1007 spec_share
= container_of(share
, struct sm750_share
, share
);
1008 #ifdef CAP_EXPENSIION
1013 spec_share
->state
.initParm
.chip_clk
= 0;
1014 spec_share
->state
.initParm
.mem_clk
= 0;
1015 spec_share
->state
.initParm
.master_clk
= 0;
1016 spec_share
->state
.initParm
.powerMode
= 0;
1017 spec_share
->state
.initParm
.setAllEngOff
= 0;
1018 spec_share
->state
.initParm
.resetMemory
= 1;
1020 /* defaultly turn g_hwcursor on for both view */
1023 if (!src
|| !*src
) {
1024 pr_warn("no specific g_option.\n");
1028 while ((opt
= strsep(&src
, ":")) != NULL
&& *opt
!= 0) {
1029 pr_err("opt=%s\n", opt
);
1030 pr_err("src=%s\n", src
);
1032 if (!strncmp(opt
, "swap", strlen("swap")))
1034 else if (!strncmp(opt
, "nocrt", strlen("nocrt")))
1035 spec_share
->state
.nocrt
= 1;
1036 else if (!strncmp(opt
, "36bit", strlen("36bit")))
1037 spec_share
->state
.pnltype
= sm750_doubleTFT
;
1038 else if (!strncmp(opt
, "18bit", strlen("18bit")))
1039 spec_share
->state
.pnltype
= sm750_dualTFT
;
1040 else if (!strncmp(opt
, "24bit", strlen("24bit")))
1041 spec_share
->state
.pnltype
= sm750_24TFT
;
1042 #ifdef CAP_EXPANSION
1043 else if (!strncmp(opt
, "exp:", strlen("exp:")))
1044 exp_res
= opt
+ strlen("exp:");
1046 else if (!strncmp(opt
, "nohwc0", strlen("nohwc0")))
1048 else if (!strncmp(opt
, "nohwc1", strlen("nohwc1")))
1050 else if (!strncmp(opt
, "nohwc", strlen("nohwc")))
1055 pr_info("find fbmode0 : %s\n", g_fbmode
[0]);
1056 } else if (!g_fbmode
[1]) {
1058 pr_info("find fbmode1 : %s\n", g_fbmode
[1]);
1060 pr_warn("How many view you wann set?\n");
1064 #ifdef CAP_EXPANSION
1065 if (getExpRes(exp_res
,
1066 &spec_share
->state
.xLCD
,
1067 &spec_share
->state
.yLCD
)) {
1068 /* seems exp_res is not valid */
1069 spec_share
->state
.xLCD
= spec_share
->state
.yLCD
= 0;
1074 if (share
->revid
!= SM750LE_REVISION_ID
) {
1077 spec_share
->state
.dataflow
= sm750_dual_swap
;
1079 spec_share
->state
.dataflow
= sm750_dual_normal
;
1082 spec_share
->state
.dataflow
= sm750_simul_sec
;
1084 spec_share
->state
.dataflow
= sm750_simul_pri
;
1087 /* SM750LE only have one crt channel */
1088 spec_share
->state
.dataflow
= sm750_simul_sec
;
1089 /* sm750le do not have complex attributes */
1090 spec_share
->state
.nocrt
= 0;
1094 static int lynxfb_pci_probe(struct pci_dev
*pdev
,
1095 const struct pci_device_id
* ent
)
1097 struct fb_info
*info
[] = {NULL
, NULL
};
1098 struct lynx_share
*share
= NULL
;
1100 struct sm750_share
*spec_share
= NULL
;
1101 size_t spec_offset
= 0;
1106 if (pci_enable_device(pdev
)) {
1107 pr_err("can not enable device.\n");
1111 /* though offset of share in sm750_share is 0,
1112 * we use this marcro as the same */
1113 spec_offset
= offsetof(struct sm750_share
, share
);
1115 spec_share
= kzalloc(sizeof(*spec_share
), GFP_KERNEL
);
1117 pr_err("Could not allocate memory for share.\n");
1121 /* setting share structure */
1122 share
= (struct lynx_share
*)(&(spec_share
->share
));
1123 share
->fbinfo
[0] = share
->fbinfo
[1] = NULL
;
1124 share
->devid
= pdev
->device
;
1125 share
->revid
= pdev
->revision
;
1127 pr_info("share->revid = %02x\n", share
->revid
);
1130 share
->mtrr_off
= g_nomtrr
;
1131 share
->mtrr
.vram
= 0;
1132 share
->mtrr
.vram_added
= 0;
1134 share
->accel_off
= g_noaccel
;
1135 share
->dual
= g_dualview
;
1136 spin_lock_init(&share
->slock
);
1138 if (!share
->accel_off
) {
1139 /* hook deInit and 2d routines, notes that below hw_xxx
1140 * routine can work on most of lynx chips
1141 * if some chip need specific function,
1142 * please hook it in smXXX_set_drv routine */
1143 share
->accel
.de_init
= hw_de_init
;
1144 share
->accel
.de_fillrect
= hw_fillrect
;
1145 share
->accel
.de_copyarea
= hw_copyarea
;
1146 share
->accel
.de_imageblit
= hw_imageblit
;
1147 pr_info("enable 2d acceleration\n");
1149 pr_info("disable 2d acceleration\n");
1152 /* call chip specific setup routine */
1153 sm750fb_setup(share
, g_settings
);
1155 /* call chip specific mmap routine */
1156 if (hw_sm750_map(share
, pdev
)) {
1157 pr_err("Memory map failed\n");
1162 if (!share
->mtrr_off
) {
1163 pr_info("enable mtrr\n");
1164 share
->mtrr
.vram
= mtrr_add(share
->vidmem_start
,
1166 MTRR_TYPE_WRCOMB
, 1);
1168 if (share
->mtrr
.vram
< 0) {
1169 /* don't block driver with the failure of MTRR */
1170 pr_err("Unable to setup MTRR.\n");
1172 share
->mtrr
.vram_added
= 1;
1173 pr_info("MTRR added successfully\n");
1178 memset_io(share
->pvMem
, 0, share
->vidmem_size
);
1180 pr_info("sm%3x mmio address = %p\n", share
->devid
, share
->pvReg
);
1182 pci_set_drvdata(pdev
, share
);
1184 /* call chipInit routine */
1185 hw_sm750_inithw(share
, pdev
);
1187 /* allocate frame buffer info structor according to g_dualview */
1190 info
[fbidx
] = framebuffer_alloc(sizeof(struct lynxfb_par
), &pdev
->dev
);
1192 pr_err("Could not allocate framebuffer #%d.\n", fbidx
);
1194 goto err_info0_alloc
;
1196 goto err_info1_alloc
;
1198 struct lynxfb_par
*par
;
1201 pr_info("framebuffer #%d alloc okay\n", fbidx
);
1202 share
->fbinfo
[fbidx
] = info
[fbidx
];
1203 par
= info
[fbidx
]->par
;
1206 /* set fb_info structure */
1207 if (lynxfb_set_fbinfo(info
[fbidx
], fbidx
)) {
1208 pr_err("Failed to initial fb_info #%d.\n", fbidx
);
1215 /* register frame buffer */
1216 pr_info("Ready to register framebuffer #%d.\n", fbidx
);
1217 errno
= register_framebuffer(info
[fbidx
]);
1219 pr_err("Failed to register fb_info #%d. err %d\n",
1227 pr_info("Accomplished register framebuffer #%d.\n", fbidx
);
1230 /* no dual view by far */
1232 if (share
->dual
&& fbidx
< 2)
1239 framebuffer_release(info
[1]);
1241 unregister_framebuffer(info
[0]);
1244 framebuffer_release(info
[0]);
1253 static void lynxfb_pci_remove(struct pci_dev
*pdev
)
1255 struct fb_info
*info
;
1256 struct lynx_share
*share
;
1258 struct lynxfb_par
*par
;
1262 share
= pci_get_drvdata(pdev
);
1265 info
= share
->fbinfo
[cnt
];
1270 unregister_framebuffer(info
);
1271 /* clean crtc & output allocations */
1272 par
->crtc
.clear(&par
->crtc
);
1273 par
->output
.clear(&par
->output
);
1274 /* release frame buffer */
1275 framebuffer_release(info
);
1278 if (share
->mtrr
.vram_added
)
1279 mtrr_del(share
->mtrr
.vram
,
1280 share
->vidmem_start
,
1281 share
->vidmem_size
);
1284 iounmap(share
->pvReg
);
1285 iounmap(share
->pvMem
);
1286 spec_share
= container_of(share
, struct sm750_share
, share
);
1289 pci_set_drvdata(pdev
, NULL
);
1292 static int __init
lynxfb_setup(char *options
)
1298 if (!options
|| !*options
) {
1299 pr_warn("no options.\n");
1303 pr_info("options:%s\n", options
);
1305 len
= strlen(options
) + 1;
1306 g_settings
= kzalloc(len
, GFP_KERNEL
);
1313 char * strsep(char **s,const char * ct);
1314 @s: the string to be searched
1315 @ct :the characters to search for
1317 strsep() updates @options to pointer after the first found token
1318 it also returns the pointer ahead the token.
1320 while ((opt
= strsep(&options
, ":")) != NULL
) {
1321 /* options that mean for any lynx chips are configured here */
1322 if (!strncmp(opt
, "noaccel", strlen("noaccel")))
1325 else if (!strncmp(opt
, "nomtrr", strlen("nomtrr")))
1328 else if (!strncmp(opt
, "dual", strlen("dual")))
1333 if (options
!= NULL
)
1340 /* misc g_settings are transport to chip specific routines */
1341 pr_info("parameter left for chip specific analysis:%s\n", g_settings
);
1345 static struct pci_device_id smi_pci_table
[] = {
1346 { PCI_DEVICE(0x126f, 0x0750), },
1350 MODULE_DEVICE_TABLE(pci
, smi_pci_table
);
1352 static struct pci_driver lynxfb_driver
= {
1354 .id_table
= smi_pci_table
,
1355 .probe
= lynxfb_pci_probe
,
1356 .remove
= lynxfb_pci_remove
,
1358 .suspend
= lynxfb_suspend
,
1359 .resume
= lynxfb_resume
,
1364 static int __init
lynxfb_init(void)
1372 if (fb_get_options("sm750fb", &option
))
1376 lynxfb_setup(option
);
1377 ret
= pci_register_driver(&lynxfb_driver
);
1380 module_init(lynxfb_init
);
1382 static void __exit
lynxfb_exit(void)
1384 pci_unregister_driver(&lynxfb_driver
);
1386 module_exit(lynxfb_exit
);
1388 module_param(g_option
, charp
, S_IRUGO
);
1390 MODULE_PARM_DESC(g_option
,
1391 "\n\t\tCommon options:\n"
1392 "\t\tnoaccel:disable 2d capabilities\n"
1393 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1394 "\t\tdualview:dual frame buffer feature enabled\n"
1395 "\t\tnohwc:disable hardware cursor\n"
1396 "\t\tUsual example:\n"
1397 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1400 MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1401 MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1402 MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1403 MODULE_LICENSE("GPL v2");