2 * Silicon Motion SM7XX frame buffer device
4 * Copyright (C) 2006 Silicon Motion Technology Corp.
5 * Authors: Ge Wang, gewang@siliconmotion.com
6 * Boyod boyod.yang@siliconmotion.com.cn
8 * Copyright (C) 2009 Lemote, Inc.
9 * Author: Wu Zhangjin, wuzhangjin@gmail.com
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive for
15 * Version 0.10.26192.21.01
16 * - Add PowerPC/Big endian support
17 * - Add 2D support for Lynx
18 * - Verified on2.6.19.2 Boyod.yang <boyod.yang@siliconmotion.com.cn>
20 * Version 0.09.2621.00.01
21 * - Only support Linux Kernel's version 2.6.21.
22 * Boyod.yang <boyod.yang@siliconmotion.com.cn>
25 * - Only support Linux Kernel's version 2.6.12.
26 * Boyod.yang <boyod.yang@siliconmotion.com.cn>
35 #include <linux/pci.h>
36 #include <linux/init.h>
37 #include <linux/uaccess.h>
38 #include <linux/console.h>
39 #include <linux/screen_info.h>
45 struct screen_info smtc_screen_info
;
51 #define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
53 #define smdbg(format, arg...)
61 * The following is a pointer to be passed into the
62 * functions below. The modules outside the main
63 * voyager.c driver have no knowledge as to what
64 * is within this structure.
67 struct display_switch
*dispsw
;
83 unsigned char __iomem
*m_pMMIO
;
92 u_long BaseAddressInVRAM
;
96 struct vesa_mode_table
{
103 static struct vesa_mode_table vesa_mode
[] = {
104 {"0x301", 640, 480, 8},
105 {"0x303", 800, 600, 8},
106 {"0x305", 1024, 768, 8},
107 {"0x307", 1280, 1024, 8},
109 {"0x311", 640, 480, 16},
110 {"0x314", 800, 600, 16},
111 {"0x317", 1024, 768, 16},
112 {"0x31A", 1280, 1024, 16},
114 {"0x312", 640, 480, 24},
115 {"0x315", 800, 600, 24},
116 {"0x318", 1024, 768, 24},
117 {"0x31B", 1280, 1024, 24},
120 char __iomem
*smtc_RegBaseAddress
; /* Memory Map IO starting address */
121 char __iomem
*smtc_VRAMBaseAddress
; /* video memory starting address */
123 char *smtc_2DBaseAddress
; /* 2D engine starting address */
124 char *smtc_2Ddataport
; /* 2D data port offset */
125 short smtc_2Dacceleration
;
127 static u32 colreg
[17];
128 static struct par_info hw
; /* hardware information */
130 u16 smtc_ChipIDs
[] = {
136 #define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16))
138 void deWaitForNotBusy(void)
140 unsigned long i
= 0x1000000;
142 if ((smtc_seqr(0x16) & 0x18) == 0x10)
148 static void sm712_set_timing(struct smtcfb_info
*sfb
,
149 struct par_info
*ppar_info
)
154 smdbg("\nppar_info->width = %d ppar_info->height = %d"
155 "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
156 ppar_info
->width
, ppar_info
->height
,
157 sfb
->fb
.var
.bits_per_pixel
, ppar_info
->hz
);
159 for (j
= 0; j
< numVGAModes
; j
++) {
160 if (VGAMode
[j
].mmSizeX
== ppar_info
->width
&&
161 VGAMode
[j
].mmSizeY
== ppar_info
->height
&&
162 VGAMode
[j
].bpp
== sfb
->fb
.var
.bits_per_pixel
&&
163 VGAMode
[j
].hz
== ppar_info
->hz
) {
165 smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY ="
166 "%d VGAMode[j].bpp = %d"
167 "VGAMode[j].hz=%d\n",
168 VGAMode
[j
].mmSizeX
, VGAMode
[j
].mmSizeY
,
169 VGAMode
[j
].bpp
, VGAMode
[j
].hz
);
171 smdbg("VGAMode index=%d\n", j
);
173 smtc_mmiowb(0x0, 0x3c6);
177 smtc_mmiowb(VGAMode
[j
].Init_MISC
, 0x3c2);
179 /* init SEQ register SR00 - SR04 */
180 for (i
= 0; i
< SIZE_SR00_SR04
; i
++)
181 smtc_seqw(i
, VGAMode
[j
].Init_SR00_SR04
[i
]);
183 /* init SEQ register SR10 - SR24 */
184 for (i
= 0; i
< SIZE_SR10_SR24
; i
++)
186 VGAMode
[j
].Init_SR10_SR24
[i
]);
188 /* init SEQ register SR30 - SR75 */
189 for (i
= 0; i
< SIZE_SR30_SR75
; i
++)
190 if (((i
+ 0x30) != 0x62) \
191 && ((i
+ 0x30) != 0x6a) \
192 && ((i
+ 0x30) != 0x6b))
194 VGAMode
[j
].Init_SR30_SR75
[i
]);
196 /* init SEQ register SR80 - SR93 */
197 for (i
= 0; i
< SIZE_SR80_SR93
; i
++)
199 VGAMode
[j
].Init_SR80_SR93
[i
]);
201 /* init SEQ register SRA0 - SRAF */
202 for (i
= 0; i
< SIZE_SRA0_SRAF
; i
++)
204 VGAMode
[j
].Init_SRA0_SRAF
[i
]);
206 /* init Graphic register GR00 - GR08 */
207 for (i
= 0; i
< SIZE_GR00_GR08
; i
++)
208 smtc_grphw(i
, VGAMode
[j
].Init_GR00_GR08
[i
]);
210 /* init Attribute register AR00 - AR14 */
211 for (i
= 0; i
< SIZE_AR00_AR14
; i
++)
212 smtc_attrw(i
, VGAMode
[j
].Init_AR00_AR14
[i
]);
214 /* init CRTC register CR00 - CR18 */
215 for (i
= 0; i
< SIZE_CR00_CR18
; i
++)
216 smtc_crtcw(i
, VGAMode
[j
].Init_CR00_CR18
[i
]);
218 /* init CRTC register CR30 - CR4D */
219 for (i
= 0; i
< SIZE_CR30_CR4D
; i
++)
221 VGAMode
[j
].Init_CR30_CR4D
[i
]);
223 /* init CRTC register CR90 - CRA7 */
224 for (i
= 0; i
< SIZE_CR90_CRA7
; i
++)
226 VGAMode
[j
].Init_CR90_CRA7
[i
]);
229 smtc_mmiowb(0x67, 0x3c2);
231 /* set VPR registers */
232 writel(0x0, ppar_info
->m_pVPR
+ 0x0C);
233 writel(0x0, ppar_info
->m_pVPR
+ 0x40);
237 (ppar_info
->width
* sfb
->fb
.var
.bits_per_pixel
) / 64;
238 switch (sfb
->fb
.var
.bits_per_pixel
) {
240 writel(0x0, ppar_info
->m_pVPR
+ 0x0);
243 writel(0x00020000, ppar_info
->m_pVPR
+ 0x0);
246 writel(0x00040000, ppar_info
->m_pVPR
+ 0x0);
249 writel(0x00030000, ppar_info
->m_pVPR
+ 0x0);
252 writel((u32
) (((m_nScreenStride
+ 2) << 16) | m_nScreenStride
),
253 ppar_info
->m_pVPR
+ 0x10);
257 static void sm712_setpalette(int regno
, unsigned red
, unsigned green
,
258 unsigned blue
, struct fb_info
*info
)
260 struct par_info
*cur_par
= (struct par_info
*)info
->par
;
262 if (cur_par
->BaseAddressInVRAM
)
264 * second display palette for dual head. Enable CRT RAM, 6-bit
267 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20);
269 /* primary display palette. Enable LCD RAM only, 6-bit RAM */
270 smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
271 smtc_mmiowb(regno
, dac_reg
);
272 smtc_mmiowb(red
>> 10, dac_val
);
273 smtc_mmiowb(green
>> 10, dac_val
);
274 smtc_mmiowb(blue
>> 10, dac_val
);
277 static void smtc_set_timing(struct smtcfb_info
*sfb
, struct par_info
280 switch (ppar_info
->chipID
) {
284 sm712_set_timing(sfb
, ppar_info
);
289 static struct fb_var_screeninfo smtcfb_var
= {
292 .xres_virtual
= 1024,
294 .bits_per_pixel
= 16,
298 .activate
= FB_ACTIVATE_NOW
,
301 .vmode
= FB_VMODE_NONINTERLACED
,
304 static struct fb_fix_screeninfo smtcfb_fix
= {
306 .type
= FB_TYPE_PACKED_PIXELS
,
307 .visual
= FB_VISUAL_TRUECOLOR
,
308 .line_length
= 800 * 3,
309 .accel
= FB_ACCEL_SMI_LYNX
,
314 * convert a colour value into a field position
319 static inline unsigned int chan_to_field(unsigned int chan
,
320 struct fb_bitfield
*bf
)
323 chan
>>= 16 - bf
->length
;
324 return chan
<< bf
->offset
;
327 static int smtcfb_blank(int blank_mode
, struct fb_info
*info
)
329 /* clear DPMS setting */
330 switch (blank_mode
) {
331 case FB_BLANK_UNBLANK
:
332 /* Screen On: HSync: On, VSync : On */
333 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
334 smtc_seqw(0x6a, 0x16);
335 smtc_seqw(0x6b, 0x02);
336 smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
337 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
338 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
339 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
340 smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
342 case FB_BLANK_NORMAL
:
343 /* Screen Off: HSync: On, VSync : On Soft blank */
344 smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
345 smtc_seqw(0x6a, 0x16);
346 smtc_seqw(0x6b, 0x02);
347 smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
348 smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
349 smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
350 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
352 case FB_BLANK_VSYNC_SUSPEND
:
353 /* Screen On: HSync: On, VSync : Off */
354 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
355 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
356 smtc_seqw(0x6a, 0x0c);
357 smtc_seqw(0x6b, 0x02);
358 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
359 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
360 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
361 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
362 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
363 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
365 case FB_BLANK_HSYNC_SUSPEND
:
366 /* Screen On: HSync: Off, VSync : On */
367 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
368 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
369 smtc_seqw(0x6a, 0x0c);
370 smtc_seqw(0x6b, 0x02);
371 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
372 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
373 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
374 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
375 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
376 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
378 case FB_BLANK_POWERDOWN
:
379 /* Screen On: HSync: Off, VSync : Off */
380 smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
381 smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
382 smtc_seqw(0x6a, 0x0c);
383 smtc_seqw(0x6b, 0x02);
384 smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
385 smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
386 smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
387 smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
388 smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
389 smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
398 static int smtc_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
399 unsigned blue
, unsigned trans
, struct fb_info
*info
)
401 struct smtcfb_info
*sfb
= (struct smtcfb_info
*)info
;
407 switch (sfb
->fb
.fix
.visual
) {
408 case FB_VISUAL_DIRECTCOLOR
:
409 case FB_VISUAL_TRUECOLOR
:
411 * 16/32 bit true-colour, use pseuo-palette for 16 base color
414 if (sfb
->fb
.var
.bits_per_pixel
== 16) {
415 u32
*pal
= sfb
->fb
.pseudo_palette
;
416 val
= chan_to_field(red
, &sfb
->fb
.var
.red
);
417 val
|= chan_to_field(green
, \
419 val
|= chan_to_field(blue
, &sfb
->fb
.var
.blue
);
422 ((red
& 0xf800) >> 8) |
423 ((green
& 0xe000) >> 13) |
424 ((green
& 0x1c00) << 3) |
425 ((blue
& 0xf800) >> 3);
430 u32
*pal
= sfb
->fb
.pseudo_palette
;
431 val
= chan_to_field(red
, &sfb
->fb
.var
.red
);
432 val
|= chan_to_field(green
, \
434 val
|= chan_to_field(blue
, &sfb
->fb
.var
.blue
);
437 (val
& 0xff00ff00 >> 8) |
438 (val
& 0x00ff00ff << 8);
445 case FB_VISUAL_PSEUDOCOLOR
:
446 /* color depth 8 bit */
447 sm712_setpalette(regno
, red
, green
, blue
, info
);
451 return 1; /* unknown type */
459 static ssize_t
smtcfb_read(struct fb_info
*info
, char __user
* buf
, size_t
462 unsigned long p
= *ppos
;
466 int c
, i
, cnt
= 0, err
= 0;
467 unsigned long total_size
;
469 if (!info
|| !info
->screen_base
)
472 if (info
->state
!= FBINFO_STATE_RUNNING
)
475 total_size
= info
->screen_size
;
478 total_size
= info
->fix
.smem_len
;
483 if (count
>= total_size
)
486 if (count
+ p
> total_size
)
487 count
= total_size
- p
;
489 buffer
= kmalloc((count
> PAGE_SIZE
) ? PAGE_SIZE
: count
, GFP_KERNEL
);
493 src
= (u32 __iomem
*) (info
->screen_base
+ p
);
495 if (info
->fbops
->fb_sync
)
496 info
->fbops
->fb_sync(info
);
499 c
= (count
> PAGE_SIZE
) ? PAGE_SIZE
: count
;
501 for (i
= c
>> 2; i
--;) {
502 *dst
= fb_readl(src
++);
504 (*dst
& 0xff00ff00 >> 8) |
505 (*dst
& 0x00ff00ff << 8);
509 u8
*dst8
= (u8
*) dst
;
510 u8 __iomem
*src8
= (u8 __iomem
*) src
;
512 for (i
= c
& 3; i
--;) {
514 *dst8
++ = fb_readb(++src8
);
516 *dst8
++ = fb_readb(--src8
);
520 src
= (u32 __iomem
*) src8
;
523 if (copy_to_user(buf
, buffer
, c
)) {
535 return (err
) ? err
: cnt
;
539 smtcfb_write(struct fb_info
*info
, const char __user
*buf
, size_t count
,
542 unsigned long p
= *ppos
;
546 int c
, i
, cnt
= 0, err
= 0;
547 unsigned long total_size
;
549 if (!info
|| !info
->screen_base
)
552 if (info
->state
!= FBINFO_STATE_RUNNING
)
555 total_size
= info
->screen_size
;
558 total_size
= info
->fix
.smem_len
;
563 if (count
> total_size
) {
568 if (count
+ p
> total_size
) {
572 count
= total_size
- p
;
575 buffer
= kmalloc((count
> PAGE_SIZE
) ? PAGE_SIZE
: count
, GFP_KERNEL
);
579 dst
= (u32 __iomem
*) (info
->screen_base
+ p
);
581 if (info
->fbops
->fb_sync
)
582 info
->fbops
->fb_sync(info
);
585 c
= (count
> PAGE_SIZE
) ? PAGE_SIZE
: count
;
588 if (copy_from_user(src
, buf
, c
)) {
593 for (i
= c
>> 2; i
--;) {
594 fb_writel((*src
& 0xff00ff00 >> 8) |
595 (*src
& 0x00ff00ff << 8), dst
++);
599 u8
*src8
= (u8
*) src
;
600 u8 __iomem
*dst8
= (u8 __iomem
*) dst
;
602 for (i
= c
& 3; i
--;) {
604 fb_writeb(*src8
++, ++dst8
);
606 fb_writeb(*src8
++, --dst8
);
610 dst
= (u32 __iomem
*) dst8
;
621 return (cnt
) ? cnt
: err
;
623 #endif /* ! __BIG_ENDIAN */
627 void smtcfb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
629 struct par_info
*p
= (struct par_info
*)info
->par
;
631 if (smtc_2Dacceleration
) {
632 if (!area
->width
|| !area
->height
)
635 deCopy(p
->BaseAddressInVRAM
, 0, info
->var
.bits_per_pixel
,
636 area
->dx
, area
->dy
, area
->width
, area
->height
,
637 p
->BaseAddressInVRAM
, 0, area
->sx
, area
->sy
, 0, 0xC);
640 cfb_copyarea(info
, area
);
643 void smtcfb_fillrect(struct fb_info
*info
, const struct fb_fillrect
*rect
)
645 struct par_info
*p
= (struct par_info
*)info
->par
;
647 if (smtc_2Dacceleration
) {
648 if (!rect
->width
|| !rect
->height
)
650 if (info
->var
.bits_per_pixel
>= 24)
651 deFillRect(p
->BaseAddressInVRAM
, 0, rect
->dx
* 3,
652 rect
->dy
* 3, rect
->width
* 3, rect
->height
,
655 deFillRect(p
->BaseAddressInVRAM
, 0, rect
->dx
, rect
->dy
,
656 rect
->width
, rect
->height
, rect
->color
);
658 cfb_fillrect(info
, rect
);
661 void smtcfb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
663 struct par_info
*p
= (struct par_info
*)info
->par
;
664 u32 bg_col
= 0, fg_col
= 0;
666 if ((smtc_2Dacceleration
) && (image
->depth
== 1)) {
670 switch (info
->var
.bits_per_pixel
) {
672 bg_col
= image
->bg_color
;
673 fg_col
= image
->fg_color
;
677 ((u32
*) (info
->pseudo_palette
))[image
->bg_color
];
679 ((u32
*) (info
->pseudo_palette
))[image
->fg_color
];
683 ((u32
*) (info
->pseudo_palette
))[image
->bg_color
];
685 ((u32
*) (info
->pseudo_palette
))[image
->fg_color
];
689 deSystemMem2VideoMemMonoBlt(
693 p
->BaseAddressInVRAM
,
696 image
->dx
, image
->dy
,
697 image
->width
, image
->height
,
702 cfb_imageblit(info
, image
);
705 static struct fb_ops smtcfb_ops
= {
706 .owner
= THIS_MODULE
,
707 .fb_setcolreg
= smtc_setcolreg
,
708 .fb_blank
= smtcfb_blank
,
709 .fb_fillrect
= smtcfb_fillrect
,
710 .fb_imageblit
= smtcfb_imageblit
,
711 .fb_copyarea
= smtcfb_copyarea
,
713 .fb_read
= smtcfb_read
,
714 .fb_write
= smtcfb_write
,
719 void smtcfb_setmode(struct smtcfb_info
*sfb
)
721 switch (sfb
->fb
.var
.bits_per_pixel
) {
723 sfb
->fb
.fix
.visual
= FB_VISUAL_TRUECOLOR
;
724 sfb
->fb
.fix
.line_length
= sfb
->fb
.var
.xres
* 4;
725 sfb
->fb
.var
.red
.length
= 8;
726 sfb
->fb
.var
.green
.length
= 8;
727 sfb
->fb
.var
.blue
.length
= 8;
728 sfb
->fb
.var
.red
.offset
= 16;
729 sfb
->fb
.var
.green
.offset
= 8;
730 sfb
->fb
.var
.blue
.offset
= 0;
734 sfb
->fb
.fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
735 sfb
->fb
.fix
.line_length
= sfb
->fb
.var
.xres
;
736 sfb
->fb
.var
.red
.offset
= 5;
737 sfb
->fb
.var
.red
.length
= 3;
738 sfb
->fb
.var
.green
.offset
= 2;
739 sfb
->fb
.var
.green
.length
= 3;
740 sfb
->fb
.var
.blue
.offset
= 0;
741 sfb
->fb
.var
.blue
.length
= 2;
744 sfb
->fb
.fix
.visual
= FB_VISUAL_TRUECOLOR
;
745 sfb
->fb
.fix
.line_length
= sfb
->fb
.var
.xres
* 3;
746 sfb
->fb
.var
.red
.length
= 8;
747 sfb
->fb
.var
.green
.length
= 8;
748 sfb
->fb
.var
.blue
.length
= 8;
750 sfb
->fb
.var
.red
.offset
= 16;
751 sfb
->fb
.var
.green
.offset
= 8;
752 sfb
->fb
.var
.blue
.offset
= 0;
757 sfb
->fb
.fix
.visual
= FB_VISUAL_TRUECOLOR
;
758 sfb
->fb
.fix
.line_length
= sfb
->fb
.var
.xres
* 2;
760 sfb
->fb
.var
.red
.length
= 5;
761 sfb
->fb
.var
.green
.length
= 6;
762 sfb
->fb
.var
.blue
.length
= 5;
764 sfb
->fb
.var
.red
.offset
= 11;
765 sfb
->fb
.var
.green
.offset
= 5;
766 sfb
->fb
.var
.blue
.offset
= 0;
771 hw
.width
= sfb
->fb
.var
.xres
;
772 hw
.height
= sfb
->fb
.var
.yres
;
774 smtc_set_timing(sfb
, &hw
);
775 if (smtc_2Dacceleration
) {
776 printk("2D acceleration enabled!\n");
777 /* Init smtc drawing engine */
778 deInit(sfb
->fb
.var
.xres
, sfb
->fb
.var
.yres
,
779 sfb
->fb
.var
.bits_per_pixel
);
784 * Alloc struct smtcfb_info and assign the default value
786 static struct smtcfb_info
*smtc_alloc_fb_info(struct pci_dev
*dev
,
789 struct smtcfb_info
*sfb
;
791 sfb
= kmalloc(sizeof(struct smtcfb_info
), GFP_KERNEL
);
796 memset(sfb
, 0, sizeof(struct smtcfb_info
));
801 /*** Init sfb->fb with default value ***/
802 sfb
->fb
.flags
= FBINFO_FLAG_DEFAULT
;
803 sfb
->fb
.fbops
= &smtcfb_ops
;
804 sfb
->fb
.var
= smtcfb_var
;
805 sfb
->fb
.fix
= smtcfb_fix
;
807 strcpy(sfb
->fb
.fix
.id
, name
);
809 sfb
->fb
.fix
.type
= FB_TYPE_PACKED_PIXELS
;
810 sfb
->fb
.fix
.type_aux
= 0;
811 sfb
->fb
.fix
.xpanstep
= 0;
812 sfb
->fb
.fix
.ypanstep
= 0;
813 sfb
->fb
.fix
.ywrapstep
= 0;
814 sfb
->fb
.fix
.accel
= FB_ACCEL_SMI_LYNX
;
816 sfb
->fb
.var
.nonstd
= 0;
817 sfb
->fb
.var
.activate
= FB_ACTIVATE_NOW
;
818 sfb
->fb
.var
.height
= -1;
819 sfb
->fb
.var
.width
= -1;
820 /* text mode acceleration */
821 sfb
->fb
.var
.accel_flags
= FB_ACCELF_TEXT
;
822 sfb
->fb
.var
.vmode
= FB_VMODE_NONINTERLACED
;
824 sfb
->fb
.pseudo_palette
= colreg
;
830 * Unmap in the memory mapped IO registers
833 static void smtc_unmap_mmio(struct smtcfb_info
*sfb
)
835 if (sfb
&& smtc_RegBaseAddress
)
836 smtc_RegBaseAddress
= NULL
;
840 * Map in the screen memory
843 static int smtc_map_smem(struct smtcfb_info
*sfb
,
844 struct pci_dev
*dev
, u_long smem_len
)
846 if (sfb
->fb
.var
.bits_per_pixel
== 32) {
848 sfb
->fb
.fix
.smem_start
= pci_resource_start(dev
, 0)
851 sfb
->fb
.fix
.smem_start
= pci_resource_start(dev
, 0);
854 sfb
->fb
.fix
.smem_start
= pci_resource_start(dev
, 0);
857 sfb
->fb
.fix
.smem_len
= smem_len
;
859 sfb
->fb
.screen_base
= smtc_VRAMBaseAddress
;
861 if (!sfb
->fb
.screen_base
) {
862 printk(KERN_INFO
"%s: unable to map screen memory\n",
871 * Unmap in the screen memory
874 static void smtc_unmap_smem(struct smtcfb_info
*sfb
)
876 if (sfb
&& sfb
->fb
.screen_base
) {
877 iounmap(sfb
->fb
.screen_base
);
878 sfb
->fb
.screen_base
= NULL
;
883 * We need to wake up the LynxEM+, and make sure its in linear memory mode.
885 static inline void sm7xx_init_hw(void)
891 static void smtc_free_fb_info(struct smtcfb_info
*sfb
)
894 fb_alloc_cmap(&sfb
->fb
.cmap
, 0, 0);
900 * sm712vga_setup - process command line options, get vga parameter
901 * @options: string of options
905 static int __init __maybe_unused
sm712vga_setup(char *options
)
909 if (!options
|| !*options
) {
910 smdbg("\n No vga parameter\n");
914 smtc_screen_info
.lfb_width
= 0;
915 smtc_screen_info
.lfb_height
= 0;
916 smtc_screen_info
.lfb_depth
= 0;
918 smdbg("\nsm712vga_setup = %s\n", options
);
921 index
< (sizeof(vesa_mode
) / sizeof(struct vesa_mode_table
));
923 if (strstr(options
, vesa_mode
[index
].mode_index
)) {
924 smtc_screen_info
.lfb_width
= vesa_mode
[index
].lfb_width
;
925 smtc_screen_info
.lfb_height
=
926 vesa_mode
[index
].lfb_height
;
927 smtc_screen_info
.lfb_depth
= vesa_mode
[index
].lfb_depth
;
934 __setup("vga=", sm712vga_setup
);
936 /* Jason (08/13/2009)
937 * Original init function changed to probe method to be used by pci_drv
938 * process used to detect chips replaced with kernel process in pci_drv
940 static int __init
smtcfb_pci_probe(struct pci_dev
*pdev
,
941 const struct pci_device_id
*ent
)
943 struct smtcfb_info
*sfb
;
944 u_long smem_size
= 0x00800000; /* default 8MB */
947 unsigned long pFramebufferPhysical
;
950 "Silicon Motion display driver " SMTC_LINUX_FB_VERSION
"\n");
952 err
= pci_enable_device(pdev
); /* enable SMTC chip */
958 hw
.chipID
= ent
->device
;
959 sprintf(name
, "sm%Xfb", hw
.chipID
);
961 sfb
= smtc_alloc_fb_info(pdev
, name
);
965 /* Jason (08/13/2009)
966 * Store fb_info to be further used when suspending and resuming
968 pci_set_drvdata(pdev
, sfb
);
972 /*get mode parameter from smtc_screen_info */
973 if (smtc_screen_info
.lfb_width
!= 0) {
974 sfb
->fb
.var
.xres
= smtc_screen_info
.lfb_width
;
975 sfb
->fb
.var
.yres
= smtc_screen_info
.lfb_height
;
976 sfb
->fb
.var
.bits_per_pixel
= smtc_screen_info
.lfb_depth
;
978 /* default resolution 1024x600 16bit mode */
979 sfb
->fb
.var
.xres
= SCREEN_X_RES
;
980 sfb
->fb
.var
.yres
= SCREEN_Y_RES
;
981 sfb
->fb
.var
.bits_per_pixel
= SCREEN_BPP
;
985 if (sfb
->fb
.var
.bits_per_pixel
== 24)
986 sfb
->fb
.var
.bits_per_pixel
= (smtc_screen_info
.lfb_depth
= 32);
988 /* Map address and memory detection */
989 pFramebufferPhysical
= pci_resource_start(pdev
, 0);
990 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &hw
.chipRevID
);
995 sfb
->fb
.fix
.mmio_start
= pFramebufferPhysical
+ 0x00400000;
996 sfb
->fb
.fix
.mmio_len
= 0x00400000;
997 smem_size
= SM712_VIDEOMEMORYSIZE
;
999 hw
.m_pLFB
= (smtc_VRAMBaseAddress
=
1000 ioremap(pFramebufferPhysical
, 0x00c00000));
1002 hw
.m_pLFB
= (smtc_VRAMBaseAddress
=
1003 ioremap(pFramebufferPhysical
, 0x00800000));
1005 hw
.m_pMMIO
= (smtc_RegBaseAddress
=
1006 smtc_VRAMBaseAddress
+ 0x00700000);
1007 smtc_2DBaseAddress
= (hw
.m_pDPR
=
1008 smtc_VRAMBaseAddress
+ 0x00408000);
1009 smtc_2Ddataport
= smtc_VRAMBaseAddress
+ DE_DATA_PORT_712
;
1010 hw
.m_pVPR
= hw
.m_pLFB
+ 0x0040c000;
1012 if (sfb
->fb
.var
.bits_per_pixel
== 32) {
1013 smtc_VRAMBaseAddress
+= 0x800000;
1014 hw
.m_pLFB
+= 0x800000;
1016 "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
1017 smtc_VRAMBaseAddress
, hw
.m_pLFB
);
1020 if (!smtc_RegBaseAddress
) {
1022 "%s: unable to map memory mapped IO\n",
1027 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1028 smtc_seqw(0x6a, 0x16);
1029 smtc_seqw(0x6b, 0x02);
1030 smtc_seqw(0x62, 0x3e);
1031 /* enable PCI burst */
1032 smtc_seqw(0x17, 0x20);
1033 /* enable word swap */
1035 if (sfb
->fb
.var
.bits_per_pixel
== 32)
1036 smtc_seqw(0x17, 0x30);
1038 #ifdef CONFIG_FB_SM7XX_ACCEL
1039 smtc_2Dacceleration
= 1;
1043 sfb
->fb
.fix
.mmio_start
= pFramebufferPhysical
;
1044 sfb
->fb
.fix
.mmio_len
= 0x00200000;
1045 smem_size
= SM722_VIDEOMEMORYSIZE
;
1046 smtc_2DBaseAddress
= (hw
.m_pDPR
=
1047 ioremap(pFramebufferPhysical
, 0x00a00000));
1048 hw
.m_pLFB
= (smtc_VRAMBaseAddress
=
1049 smtc_2DBaseAddress
+ 0x00200000);
1050 hw
.m_pMMIO
= (smtc_RegBaseAddress
=
1051 smtc_2DBaseAddress
+ 0x000c0000);
1052 smtc_2Ddataport
= smtc_2DBaseAddress
+ DE_DATA_PORT_722
;
1053 hw
.m_pVPR
= smtc_2DBaseAddress
+ 0x800;
1055 smtc_seqw(0x62, 0xff);
1056 smtc_seqw(0x6a, 0x0d);
1057 smtc_seqw(0x6b, 0x02);
1058 smtc_2Dacceleration
= 0;
1062 "No valid Silicon Motion display chip was detected!\n");
1064 smtc_free_fb_info(sfb
);
1068 /* can support 32 bpp */
1069 if (15 == sfb
->fb
.var
.bits_per_pixel
)
1070 sfb
->fb
.var
.bits_per_pixel
= 16;
1072 sfb
->fb
.var
.xres_virtual
= sfb
->fb
.var
.xres
;
1073 sfb
->fb
.var
.yres_virtual
= sfb
->fb
.var
.yres
;
1074 err
= smtc_map_smem(sfb
, pdev
, smem_size
);
1078 smtcfb_setmode(sfb
);
1079 /* Primary display starting from 0 postion */
1080 hw
.BaseAddressInVRAM
= 0;
1083 err
= register_framebuffer(&sfb
->fb
);
1087 printk(KERN_INFO
"Silicon Motion SM%X Rev%X primary display mode"
1088 "%dx%d-%d Init Complete.\n", hw
.chipID
, hw
.chipRevID
,
1089 sfb
->fb
.var
.xres
, sfb
->fb
.var
.yres
,
1090 sfb
->fb
.var
.bits_per_pixel
);
1095 printk(KERN_INFO
"Silicon Motion, Inc. primary display init fail\n");
1097 smtc_unmap_smem(sfb
);
1098 smtc_unmap_mmio(sfb
);
1099 smtc_free_fb_info(sfb
);
1105 /* Jason (08/11/2009) PCI_DRV wrapper essential structs */
1106 static struct pci_device_id smtcfb_pci_table
[] = {
1107 {0x126f, 0x710, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1108 {0x126f, 0x712, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1109 {0x126f, 0x720, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1114 /* Jason (08/14/2009)
1115 * do some clean up when the driver module is removed
1117 static void __devexit
smtcfb_pci_remove(struct pci_dev
*pdev
)
1119 struct smtcfb_info
*sfb
;
1121 sfb
= pci_get_drvdata(pdev
);
1122 pci_set_drvdata(pdev
, NULL
);
1123 smtc_unmap_smem(sfb
);
1124 smtc_unmap_mmio(sfb
);
1125 unregister_framebuffer(&sfb
->fb
);
1126 smtc_free_fb_info(sfb
);
1129 /* Jason (08/14/2009)
1130 * suspend function, called when the suspend event is triggered
1132 static int __maybe_unused
smtcfb_suspend(struct pci_dev
*pdev
, pm_message_t msg
)
1134 struct smtcfb_info
*sfb
;
1137 sfb
= pci_get_drvdata(pdev
);
1139 /* set the hw in sleep mode use externel clock and self memory refresh
1140 * so that we can turn off internal PLLs later on
1142 smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
1143 smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
1145 switch (msg
.event
) {
1146 case PM_EVENT_FREEZE
:
1147 case PM_EVENT_PRETHAW
:
1148 pdev
->dev
.power
.power_state
= msg
;
1152 /* when doing suspend, call fb apis and pci apis */
1153 if (msg
.event
== PM_EVENT_SUSPEND
) {
1154 acquire_console_sem();
1155 fb_set_suspend(&sfb
->fb
, 1);
1156 release_console_sem();
1157 retv
= pci_save_state(pdev
);
1158 pci_disable_device(pdev
);
1159 retv
= pci_choose_state(pdev
, msg
);
1160 retv
= pci_set_power_state(pdev
, retv
);
1163 pdev
->dev
.power
.power_state
= msg
;
1165 /* additionaly turn off all function blocks including internal PLLs */
1166 smtc_seqw(0x21, 0xff);
1171 static int __maybe_unused
smtcfb_resume(struct pci_dev
*pdev
)
1173 struct smtcfb_info
*sfb
;
1176 sfb
= pci_get_drvdata(pdev
);
1178 /* when resuming, restore pci data and fb cursor */
1179 if (pdev
->dev
.power
.power_state
.event
!= PM_EVENT_FREEZE
) {
1180 retv
= pci_set_power_state(pdev
, PCI_D0
);
1181 retv
= pci_restore_state(pdev
);
1182 if (pci_enable_device(pdev
))
1184 pci_set_master(pdev
);
1187 /* reinit hardware */
1189 switch (hw
.chipID
) {
1192 /* set MCLK = 14.31818 * (0x16 / 0x2) */
1193 smtc_seqw(0x6a, 0x16);
1194 smtc_seqw(0x6b, 0x02);
1195 smtc_seqw(0x62, 0x3e);
1196 /* enable PCI burst */
1197 smtc_seqw(0x17, 0x20);
1199 if (sfb
->fb
.var
.bits_per_pixel
== 32)
1200 smtc_seqw(0x17, 0x30);
1204 smtc_seqw(0x62, 0xff);
1205 smtc_seqw(0x6a, 0x0d);
1206 smtc_seqw(0x6b, 0x02);
1210 smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1211 smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1213 smtcfb_setmode(sfb
);
1215 acquire_console_sem();
1216 fb_set_suspend(&sfb
->fb
, 0);
1217 release_console_sem();
1222 /* Jason (08/13/2009)
1223 * pci_driver struct used to wrap the original driver
1224 * so that it can be registered into the kernel and
1225 * the proper method would be called when suspending and resuming
1227 static struct pci_driver smtcfb_driver
= {
1229 .id_table
= smtcfb_pci_table
,
1230 .probe
= smtcfb_pci_probe
,
1231 .remove
= __devexit_p(smtcfb_pci_remove
),
1233 .suspend
= smtcfb_suspend
,
1234 .resume
= smtcfb_resume
,
1238 static int __init
smtcfb_init(void)
1240 return pci_register_driver(&smtcfb_driver
);
1243 static void __exit
smtcfb_exit(void)
1245 pci_unregister_driver(&smtcfb_driver
);
1248 module_init(smtcfb_init
);
1249 module_exit(smtcfb_exit
);
1251 MODULE_AUTHOR("Siliconmotion ");
1252 MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1253 MODULE_LICENSE("GPL");