1/*
2 * Silicon Motion SM7XX frame buffer device
3 *
4 * Copyright (C) 2006 Silicon Motion Technology Corp.
5 * Authors:  Ge Wang, gewang@siliconmotion.com
6 *	     Boyod boyod.yang@siliconmotion.com.cn
7 *
8 * Copyright (C) 2009 Lemote, Inc.
9 * Author:   Wu Zhangjin, wuzhangjin@gmail.com
10 *
11 * Copyright (C) 2011 Igalia, S.L.
12 * Author:   Javier M. Mellid <jmunhoz@igalia.com>
13 *
14 * This file is subject to the terms and conditions of the GNU General Public
15 * License. See the file COPYING in the main directory of this archive for
16 * more details.
17 *
18 * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
19 */
20
21#include <linux/io.h>
22#include <linux/fb.h>
23#include <linux/pci.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/uaccess.h>
27#include <linux/module.h>
28#include <linux/console.h>
29#include <linux/screen_info.h>
30
31#ifdef CONFIG_PM
32#include <linux/pm.h>
33#endif
34
35#include "sm7xx.h"
36
37/*
38* Private structure
39*/
40struct smtcfb_info {
41	struct pci_dev *pdev;
42	struct fb_info fb;
43	u16 chip_id;
44	u8  chip_rev_id;
45
46	void __iomem *lfb;	/* linear frame buffer */
47	void __iomem *dp_regs;	/* drawing processor control regs */
48	void __iomem *vp_regs;	/* video processor control regs */
49	void __iomem *cp_regs;	/* capture processor control regs */
50	void __iomem *mmio;	/* memory map IO port */
51
52	u_int width;
53	u_int height;
54	u_int hz;
55
56	u32 colreg[17];
57};
58
59void __iomem *smtc_regbaseaddress;	/* Memory Map IO starting address */
60
61static struct fb_var_screeninfo smtcfb_var = {
62	.xres           = 1024,
63	.yres           = 600,
64	.xres_virtual   = 1024,
65	.yres_virtual   = 600,
66	.bits_per_pixel = 16,
67	.red            = {16, 8, 0},
68	.green          = {8, 8, 0},
69	.blue           = {0, 8, 0},
70	.activate       = FB_ACTIVATE_NOW,
71	.height         = -1,
72	.width          = -1,
73	.vmode          = FB_VMODE_NONINTERLACED,
74	.nonstd         = 0,
75	.accel_flags    = FB_ACCELF_TEXT,
76};
77
78static struct fb_fix_screeninfo smtcfb_fix = {
79	.id             = "smXXXfb",
80	.type           = FB_TYPE_PACKED_PIXELS,
81	.visual         = FB_VISUAL_TRUECOLOR,
82	.line_length    = 800 * 3,
83	.accel          = FB_ACCEL_SMI_LYNX,
84	.type_aux       = 0,
85	.xpanstep       = 0,
86	.ypanstep       = 0,
87	.ywrapstep      = 0,
88};
89
90struct vesa_mode {
91	char index[6];
92	u16  lfb_width;
93	u16  lfb_height;
94	u16  lfb_depth;
95};
96
97static struct vesa_mode vesa_mode_table[] = {
98	{"0x301", 640,  480,  8},
99	{"0x303", 800,  600,  8},
100	{"0x305", 1024, 768,  8},
101	{"0x307", 1280, 1024, 8},
102
103	{"0x311", 640,  480,  16},
104	{"0x314", 800,  600,  16},
105	{"0x317", 1024, 768,  16},
106	{"0x31A", 1280, 1024, 16},
107
108	{"0x312", 640,  480,  24},
109	{"0x315", 800,  600,  24},
110	{"0x318", 1024, 768,  24},
111	{"0x31B", 1280, 1024, 24},
112};
113
114static struct screen_info smtc_scr_info;
115
116static char *mode_option;
117
118/* process command line options, get vga parameter */
119static void __init sm7xx_vga_setup(char *options)
120{
121	int i;
122
123	if (!options || !*options)
124		return;
125
126	smtc_scr_info.lfb_width = 0;
127	smtc_scr_info.lfb_height = 0;
128	smtc_scr_info.lfb_depth = 0;
129
130	pr_debug("sm7xx_vga_setup = %s\n", options);
131
132	for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
133		if (strstr(options, vesa_mode_table[i].index)) {
134			smtc_scr_info.lfb_width  = vesa_mode_table[i].lfb_width;
135			smtc_scr_info.lfb_height =
136						vesa_mode_table[i].lfb_height;
137			smtc_scr_info.lfb_depth  = vesa_mode_table[i].lfb_depth;
138			return;
139		}
140	}
141}
142
143static void sm712_setpalette(int regno, unsigned red, unsigned green,
144			     unsigned blue, struct fb_info *info)
145{
146	/* set bit 5:4 = 01 (write LCD RAM only) */
147	smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
148
149	smtc_mmiowb(regno, dac_reg);
150	smtc_mmiowb(red >> 10, dac_val);
151	smtc_mmiowb(green >> 10, dac_val);
152	smtc_mmiowb(blue >> 10, dac_val);
153}
154
155/* chan_to_field
156 *
157 * convert a colour value into a field position
158 *
159 * from pxafb.c
160 */
161
162static inline unsigned int chan_to_field(unsigned int chan,
163					 struct fb_bitfield *bf)
164{
165	chan &= 0xffff;
166	chan >>= 16 - bf->length;
167	return chan << bf->offset;
168}
169
170static int smtc_blank(int blank_mode, struct fb_info *info)
171{
172	/* clear DPMS setting */
173	switch (blank_mode) {
174	case FB_BLANK_UNBLANK:
175		/* Screen On: HSync: On, VSync : On */
176		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
177		smtc_seqw(0x6a, 0x16);
178		smtc_seqw(0x6b, 0x02);
179		smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
180		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
181		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
182		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
183		smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
184		break;
185	case FB_BLANK_NORMAL:
186		/* Screen Off: HSync: On, VSync : On   Soft blank */
187		smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
188		smtc_seqw(0x6a, 0x16);
189		smtc_seqw(0x6b, 0x02);
190		smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
191		smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
192		smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
193		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
194		break;
195	case FB_BLANK_VSYNC_SUSPEND:
196		/* Screen On: HSync: On, VSync : Off */
197		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
198		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
199		smtc_seqw(0x6a, 0x0c);
200		smtc_seqw(0x6b, 0x02);
201		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
202		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
203		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
204		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
205		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
206		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
207		break;
208	case FB_BLANK_HSYNC_SUSPEND:
209		/* Screen On: HSync: Off, VSync : On */
210		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
211		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
212		smtc_seqw(0x6a, 0x0c);
213		smtc_seqw(0x6b, 0x02);
214		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
215		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
216		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
217		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
218		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
219		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
220		break;
221	case FB_BLANK_POWERDOWN:
222		/* Screen On: HSync: Off, VSync : Off */
223		smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
224		smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
225		smtc_seqw(0x6a, 0x0c);
226		smtc_seqw(0x6b, 0x02);
227		smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
228		smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
229		smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
230		smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
231		smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
232		smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
233		break;
234	default:
235		return -EINVAL;
236	}
237
238	return 0;
239}
240
241static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
242			  unsigned blue, unsigned trans, struct fb_info *info)
243{
244	struct smtcfb_info *sfb;
245	u32 val;
246
247	sfb = info->par;
248
249	if (regno > 255)
250		return 1;
251
252	switch (sfb->fb.fix.visual) {
253	case FB_VISUAL_DIRECTCOLOR:
254	case FB_VISUAL_TRUECOLOR:
255		/*
256		 * 16/32 bit true-colour, use pseudo-palette for 16 base color
257		 */
258		if (regno < 16) {
259			if (sfb->fb.var.bits_per_pixel == 16) {
260				u32 *pal = sfb->fb.pseudo_palette;
261
262				val = chan_to_field(red, &sfb->fb.var.red);
263				val |= chan_to_field(green, &sfb->fb.var.green);
264				val |= chan_to_field(blue, &sfb->fb.var.blue);
265#ifdef __BIG_ENDIAN
266				pal[regno] =
267				    ((red & 0xf800) >> 8) |
268				    ((green & 0xe000) >> 13) |
269				    ((green & 0x1c00) << 3) |
270				    ((blue & 0xf800) >> 3);
271#else
272				pal[regno] = val;
273#endif
274			} else {
275				u32 *pal = sfb->fb.pseudo_palette;
276
277				val = chan_to_field(red, &sfb->fb.var.red);
278				val |= chan_to_field(green, &sfb->fb.var.green);
279				val |= chan_to_field(blue, &sfb->fb.var.blue);
280#ifdef __BIG_ENDIAN
281				val =
282				    (val & 0xff00ff00 >> 8) |
283				    (val & 0x00ff00ff << 8);
284#endif
285				pal[regno] = val;
286			}
287		}
288		break;
289
290	case FB_VISUAL_PSEUDOCOLOR:
291		/* color depth 8 bit */
292		sm712_setpalette(regno, red, green, blue, info);
293		break;
294
295	default:
296		return 1;	/* unknown type */
297	}
298
299	return 0;
300}
301
302#ifdef __BIG_ENDIAN
303static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
304				count, loff_t *ppos)
305{
306	unsigned long p = *ppos;
307
308	u32 *buffer, *dst;
309	u32 __iomem *src;
310	int c, i, cnt = 0, err = 0;
311	unsigned long total_size;
312
313	if (!info || !info->screen_base)
314		return -ENODEV;
315
316	if (info->state != FBINFO_STATE_RUNNING)
317		return -EPERM;
318
319	total_size = info->screen_size;
320
321	if (total_size == 0)
322		total_size = info->fix.smem_len;
323
324	if (p >= total_size)
325		return 0;
326
327	if (count >= total_size)
328		count = total_size;
329
330	if (count + p > total_size)
331		count = total_size - p;
332
333	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
334	if (!buffer)
335		return -ENOMEM;
336
337	src = (u32 __iomem *) (info->screen_base + p);
338
339	if (info->fbops->fb_sync)
340		info->fbops->fb_sync(info);
341
342	while (count) {
343		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
344		dst = buffer;
345		for (i = c >> 2; i--;) {
346			*dst = fb_readl(src++);
347			*dst =
348			    (*dst & 0xff00ff00 >> 8) |
349			    (*dst & 0x00ff00ff << 8);
350			dst++;
351		}
352		if (c & 3) {
353			u8 *dst8 = (u8 *)dst;
354			u8 __iomem *src8 = (u8 __iomem *)src;
355
356			for (i = c & 3; i--;) {
357				if (i & 1) {
358					*dst8++ = fb_readb(++src8);
359				} else {
360					*dst8++ = fb_readb(--src8);
361					src8 += 2;
362				}
363			}
364			src = (u32 __iomem *)src8;
365		}
366
367		if (copy_to_user(buf, buffer, c)) {
368			err = -EFAULT;
369			break;
370		}
371		*ppos += c;
372		buf += c;
373		cnt += c;
374		count -= c;
375	}
376
377	kfree(buffer);
378
379	return (err) ? err : cnt;
380}
381
382static ssize_t
383smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
384	     loff_t *ppos)
385{
386	unsigned long p = *ppos;
387
388	u32 *buffer, *src;
389	u32 __iomem *dst;
390	int c, i, cnt = 0, err = 0;
391	unsigned long total_size;
392
393	if (!info || !info->screen_base)
394		return -ENODEV;
395
396	if (info->state != FBINFO_STATE_RUNNING)
397		return -EPERM;
398
399	total_size = info->screen_size;
400
401	if (total_size == 0)
402		total_size = info->fix.smem_len;
403
404	if (p > total_size)
405		return -EFBIG;
406
407	if (count > total_size) {
408		err = -EFBIG;
409		count = total_size;
410	}
411
412	if (count + p > total_size) {
413		if (!err)
414			err = -ENOSPC;
415
416		count = total_size - p;
417	}
418
419	buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
420	if (!buffer)
421		return -ENOMEM;
422
423	dst = (u32 __iomem *) (info->screen_base + p);
424
425	if (info->fbops->fb_sync)
426		info->fbops->fb_sync(info);
427
428	while (count) {
429		c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
430		src = buffer;
431
432		if (copy_from_user(src, buf, c)) {
433			err = -EFAULT;
434			break;
435		}
436
437		for (i = c >> 2; i--;) {
438			fb_writel((*src & 0xff00ff00 >> 8) |
439				  (*src & 0x00ff00ff << 8), dst++);
440			src++;
441		}
442		if (c & 3) {
443			u8 *src8 = (u8 *)src;
444			u8 __iomem *dst8 = (u8 __iomem *)dst;
445
446			for (i = c & 3; i--;) {
447				if (i & 1) {
448					fb_writeb(*src8++, ++dst8);
449				} else {
450					fb_writeb(*src8++, --dst8);
451					dst8 += 2;
452				}
453			}
454			dst = (u32 __iomem *)dst8;
455		}
456
457		*ppos += c;
458		buf += c;
459		cnt += c;
460		count -= c;
461	}
462
463	kfree(buffer);
464
465	return (cnt) ? cnt : err;
466}
467#endif	/* ! __BIG_ENDIAN */
468
469static void sm7xx_set_timing(struct smtcfb_info *sfb)
470{
471	int i = 0, j = 0;
472	u32 m_nscreenstride;
473
474	dev_dbg(&sfb->pdev->dev,
475		"sfb->width=%d sfb->height=%d sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
476		sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
477
478	for (j = 0; j < numvgamodes; j++) {
479		if (vgamode[j].mmsizex == sfb->width &&
480		    vgamode[j].mmsizey == sfb->height &&
481		    vgamode[j].bpp == sfb->fb.var.bits_per_pixel &&
482		    vgamode[j].hz == sfb->hz) {
483			dev_dbg(&sfb->pdev->dev,
484				"vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
485				vgamode[j].mmsizex, vgamode[j].mmsizey,
486				vgamode[j].bpp, vgamode[j].hz);
487
488			dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
489
490			smtc_mmiowb(0x0, 0x3c6);
491
492			smtc_seqw(0, 0x1);
493
494			smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
495
496			/* init SEQ register SR00 - SR04 */
497			for (i = 0; i < SIZE_SR00_SR04; i++)
498				smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
499
500			/* init SEQ register SR10 - SR24 */
501			for (i = 0; i < SIZE_SR10_SR24; i++)
502				smtc_seqw(i + 0x10,
503					  vgamode[j].init_sr10_sr24[i]);
504
505			/* init SEQ register SR30 - SR75 */
506			for (i = 0; i < SIZE_SR30_SR75; i++)
507				if ((i + 0x30) != 0x62 &&
508				    (i + 0x30) != 0x6a &&
509				    (i + 0x30) != 0x6b)
510					smtc_seqw(i + 0x30,
511						  vgamode[j].init_sr30_sr75[i]);
512
513			/* init SEQ register SR80 - SR93 */
514			for (i = 0; i < SIZE_SR80_SR93; i++)
515				smtc_seqw(i + 0x80,
516					  vgamode[j].init_sr80_sr93[i]);
517
518			/* init SEQ register SRA0 - SRAF */
519			for (i = 0; i < SIZE_SRA0_SRAF; i++)
520				smtc_seqw(i + 0xa0,
521					  vgamode[j].init_sra0_sraf[i]);
522
523			/* init Graphic register GR00 - GR08 */
524			for (i = 0; i < SIZE_GR00_GR08; i++)
525				smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
526
527			/* init Attribute register AR00 - AR14 */
528			for (i = 0; i < SIZE_AR00_AR14; i++)
529				smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
530
531			/* init CRTC register CR00 - CR18 */
532			for (i = 0; i < SIZE_CR00_CR18; i++)
533				smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
534
535			/* init CRTC register CR30 - CR4D */
536			for (i = 0; i < SIZE_CR30_CR4D; i++)
537				smtc_crtcw(i + 0x30,
538					   vgamode[j].init_cr30_cr4d[i]);
539
540			/* init CRTC register CR90 - CRA7 */
541			for (i = 0; i < SIZE_CR90_CRA7; i++)
542				smtc_crtcw(i + 0x90,
543					   vgamode[j].init_cr90_cra7[i]);
544		}
545	}
546	smtc_mmiowb(0x67, 0x3c2);
547
548	/* set VPR registers */
549	writel(0x0, sfb->vp_regs + 0x0C);
550	writel(0x0, sfb->vp_regs + 0x40);
551
552	/* set data width */
553	m_nscreenstride =
554		(sfb->width * sfb->fb.var.bits_per_pixel) / 64;
555	switch (sfb->fb.var.bits_per_pixel) {
556	case 8:
557		writel(0x0, sfb->vp_regs + 0x0);
558		break;
559	case 16:
560		writel(0x00020000, sfb->vp_regs + 0x0);
561		break;
562	case 24:
563		writel(0x00040000, sfb->vp_regs + 0x0);
564		break;
565	case 32:
566		writel(0x00030000, sfb->vp_regs + 0x0);
567		break;
568	}
569	writel((u32) (((m_nscreenstride + 2) << 16) | m_nscreenstride),
570	       sfb->vp_regs + 0x10);
571}
572
573static void smtc_set_timing(struct smtcfb_info *sfb)
574{
575	switch (sfb->chip_id) {
576	case 0x710:
577	case 0x712:
578	case 0x720:
579		sm7xx_set_timing(sfb);
580		break;
581	}
582}
583
584static void smtcfb_setmode(struct smtcfb_info *sfb)
585{
586	switch (sfb->fb.var.bits_per_pixel) {
587	case 32:
588		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
589		sfb->fb.fix.line_length  = sfb->fb.var.xres * 4;
590		sfb->fb.var.red.length   = 8;
591		sfb->fb.var.green.length = 8;
592		sfb->fb.var.blue.length  = 8;
593		sfb->fb.var.red.offset   = 16;
594		sfb->fb.var.green.offset = 8;
595		sfb->fb.var.blue.offset  = 0;
596		break;
597	case 24:
598		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
599		sfb->fb.fix.line_length  = sfb->fb.var.xres * 3;
600		sfb->fb.var.red.length   = 8;
601		sfb->fb.var.green.length = 8;
602		sfb->fb.var.blue.length  = 8;
603		sfb->fb.var.red.offset   = 16;
604		sfb->fb.var.green.offset = 8;
605		sfb->fb.var.blue.offset  = 0;
606		break;
607	case 8:
608		sfb->fb.fix.visual       = FB_VISUAL_PSEUDOCOLOR;
609		sfb->fb.fix.line_length  = sfb->fb.var.xres;
610		sfb->fb.var.red.length   = 3;
611		sfb->fb.var.green.length = 3;
612		sfb->fb.var.blue.length  = 2;
613		sfb->fb.var.red.offset   = 5;
614		sfb->fb.var.green.offset = 2;
615		sfb->fb.var.blue.offset  = 0;
616		break;
617	case 16:
618	default:
619		sfb->fb.fix.visual       = FB_VISUAL_TRUECOLOR;
620		sfb->fb.fix.line_length  = sfb->fb.var.xres * 2;
621		sfb->fb.var.red.length   = 5;
622		sfb->fb.var.green.length = 6;
623		sfb->fb.var.blue.length  = 5;
624		sfb->fb.var.red.offset   = 11;
625		sfb->fb.var.green.offset = 5;
626		sfb->fb.var.blue.offset  = 0;
627		break;
628	}
629
630	sfb->width  = sfb->fb.var.xres;
631	sfb->height = sfb->fb.var.yres;
632	sfb->hz = 60;
633	smtc_set_timing(sfb);
634}
635
636static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
637{
638	/* sanity checks */
639	if (var->xres_virtual < var->xres)
640		var->xres_virtual = var->xres;
641
642	if (var->yres_virtual < var->yres)
643		var->yres_virtual = var->yres;
644
645	/* set valid default bpp */
646	if ((var->bits_per_pixel != 8)  && (var->bits_per_pixel != 16) &&
647	    (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
648		var->bits_per_pixel = 16;
649
650	return 0;
651}
652
653static int smtc_set_par(struct fb_info *info)
654{
655	smtcfb_setmode(info->par);
656
657	return 0;
658}
659
660static struct fb_ops smtcfb_ops = {
661	.owner        = THIS_MODULE,
662	.fb_check_var = smtc_check_var,
663	.fb_set_par   = smtc_set_par,
664	.fb_setcolreg = smtc_setcolreg,
665	.fb_blank     = smtc_blank,
666	.fb_fillrect  = cfb_fillrect,
667	.fb_imageblit = cfb_imageblit,
668	.fb_copyarea  = cfb_copyarea,
669#ifdef __BIG_ENDIAN
670	.fb_read      = smtcfb_read,
671	.fb_write     = smtcfb_write,
672#endif
673};
674
675/*
676 * alloc struct smtcfb_info and assign default values
677 */
678static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
679{
680	struct smtcfb_info *sfb;
681
682	sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
683
684	if (!sfb)
685		return NULL;
686
687	sfb->pdev = pdev;
688
689	sfb->fb.flags          = FBINFO_FLAG_DEFAULT;
690	sfb->fb.fbops          = &smtcfb_ops;
691	sfb->fb.fix            = smtcfb_fix;
692	sfb->fb.var            = smtcfb_var;
693	sfb->fb.pseudo_palette = sfb->colreg;
694	sfb->fb.par            = sfb;
695
696	return sfb;
697}
698
699/*
700 * free struct smtcfb_info
701 */
702static void smtc_free_fb_info(struct smtcfb_info *sfb)
703{
704	kfree(sfb);
705}
706
707/*
708 * Unmap in the memory mapped IO registers
709 */
710
711static void smtc_unmap_mmio(struct smtcfb_info *sfb)
712{
713	if (sfb && smtc_regbaseaddress)
714		smtc_regbaseaddress = NULL;
715}
716
717/*
718 * Map in the screen memory
719 */
720
721static int smtc_map_smem(struct smtcfb_info *sfb,
722			 struct pci_dev *pdev, u_long smem_len)
723{
724	sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
725
726#ifdef __BIG_ENDIAN
727	if (sfb->fb.var.bits_per_pixel == 32)
728		sfb->fb.fix.smem_start += 0x800000;
729#endif
730
731	sfb->fb.fix.smem_len = smem_len;
732
733	sfb->fb.screen_base = sfb->lfb;
734
735	if (!sfb->fb.screen_base) {
736		dev_err(&pdev->dev,
737			"%s: unable to map screen memory\n", sfb->fb.fix.id);
738		return -ENOMEM;
739	}
740
741	return 0;
742}
743
744/*
745 * Unmap in the screen memory
746 *
747 */
748static void smtc_unmap_smem(struct smtcfb_info *sfb)
749{
750	if (sfb && sfb->fb.screen_base) {
751		iounmap(sfb->fb.screen_base);
752		sfb->fb.screen_base = NULL;
753	}
754}
755
756/*
757 * We need to wake up the device and make sure its in linear memory mode.
758 */
759static inline void sm7xx_init_hw(void)
760{
761	outb_p(0x18, 0x3c4);
762	outb_p(0x11, 0x3c5);
763}
764
765static int smtcfb_pci_probe(struct pci_dev *pdev,
766			    const struct pci_device_id *ent)
767{
768	struct smtcfb_info *sfb;
769	u_long smem_size = 0x00800000;	/* default 8MB */
770	int err;
771	unsigned long mmio_base;
772
773	dev_info(&pdev->dev, "Silicon Motion display driver.");
774
775	err = pci_enable_device(pdev);	/* enable SMTC chip */
776	if (err)
777		return err;
778
779	err = pci_request_region(pdev, 0, "sm7xxfb");
780	if (err < 0) {
781		dev_err(&pdev->dev, "cannot reserve framebuffer region\n");
782		goto failed_regions;
783	}
784
785	sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
786
787	sfb = smtc_alloc_fb_info(pdev);
788
789	if (!sfb) {
790		err = -ENOMEM;
791		goto failed_free;
792	}
793
794	sfb->chip_id = ent->device;
795
796	pci_set_drvdata(pdev, sfb);
797
798	sm7xx_init_hw();
799
800	/* get mode parameter from smtc_scr_info */
801	if (smtc_scr_info.lfb_width != 0) {
802		sfb->fb.var.xres = smtc_scr_info.lfb_width;
803		sfb->fb.var.yres = smtc_scr_info.lfb_height;
804		sfb->fb.var.bits_per_pixel = smtc_scr_info.lfb_depth;
805	} else {
806		/* default resolution 1024x600 16bit mode */
807		sfb->fb.var.xres = SCREEN_X_RES;
808		sfb->fb.var.yres = SCREEN_Y_RES;
809		sfb->fb.var.bits_per_pixel = SCREEN_BPP;
810	}
811
812#ifdef __BIG_ENDIAN
813	if (sfb->fb.var.bits_per_pixel == 24)
814		sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
815#endif
816	/* Map address and memory detection */
817	mmio_base = pci_resource_start(pdev, 0);
818	pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
819
820	switch (sfb->chip_id) {
821	case 0x710:
822	case 0x712:
823		sfb->fb.fix.mmio_start = mmio_base + 0x00400000;
824		sfb->fb.fix.mmio_len = 0x00400000;
825		smem_size = SM712_VIDEOMEMORYSIZE;
826#ifdef __BIG_ENDIAN
827		sfb->lfb = ioremap(mmio_base, 0x00c00000);
828#else
829		sfb->lfb = ioremap(mmio_base, 0x00800000);
830#endif
831		sfb->mmio = (smtc_regbaseaddress =
832		    sfb->lfb + 0x00700000);
833		sfb->dp_regs = sfb->lfb + 0x00408000;
834		sfb->vp_regs = sfb->lfb + 0x0040c000;
835#ifdef __BIG_ENDIAN
836		if (sfb->fb.var.bits_per_pixel == 32) {
837			sfb->lfb += 0x800000;
838			dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
839		}
840#endif
841		if (!smtc_regbaseaddress) {
842			dev_err(&pdev->dev,
843				"%s: unable to map memory mapped IO!",
844				sfb->fb.fix.id);
845			err = -ENOMEM;
846			goto failed_fb;
847		}
848
849		/* set MCLK = 14.31818 * (0x16 / 0x2) */
850		smtc_seqw(0x6a, 0x16);
851		smtc_seqw(0x6b, 0x02);
852		smtc_seqw(0x62, 0x3e);
853		/* enable PCI burst */
854		smtc_seqw(0x17, 0x20);
855		/* enable word swap */
856#ifdef __BIG_ENDIAN
857		if (sfb->fb.var.bits_per_pixel == 32)
858			smtc_seqw(0x17, 0x30);
859#endif
860		break;
861	case 0x720:
862		sfb->fb.fix.mmio_start = mmio_base;
863		sfb->fb.fix.mmio_len = 0x00200000;
864		smem_size = SM722_VIDEOMEMORYSIZE;
865		sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
866		sfb->lfb = sfb->dp_regs + 0x00200000;
867		sfb->mmio = (smtc_regbaseaddress =
868		    sfb->dp_regs + 0x000c0000);
869		sfb->vp_regs = sfb->dp_regs + 0x800;
870
871		smtc_seqw(0x62, 0xff);
872		smtc_seqw(0x6a, 0x0d);
873		smtc_seqw(0x6b, 0x02);
874		break;
875	default:
876		dev_err(&pdev->dev,
877			"No valid Silicon Motion display chip was detected!");
878
879		goto failed_fb;
880	}
881
882	/* can support 32 bpp */
883	if (15 == sfb->fb.var.bits_per_pixel)
884		sfb->fb.var.bits_per_pixel = 16;
885
886	sfb->fb.var.xres_virtual = sfb->fb.var.xres;
887	sfb->fb.var.yres_virtual = sfb->fb.var.yres;
888	err = smtc_map_smem(sfb, pdev, smem_size);
889	if (err)
890		goto failed;
891
892	smtcfb_setmode(sfb);
893
894	err = register_framebuffer(&sfb->fb);
895	if (err < 0)
896		goto failed;
897
898	dev_info(&pdev->dev,
899		 "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
900		 sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres,
901		 sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
902
903	return 0;
904
905failed:
906	dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
907
908	smtc_unmap_smem(sfb);
909	smtc_unmap_mmio(sfb);
910failed_fb:
911	smtc_free_fb_info(sfb);
912
913failed_free:
914	pci_release_region(pdev, 0);
915
916failed_regions:
917	pci_disable_device(pdev);
918
919	return err;
920}
921
922/*
923 * 0x710 (LynxEM)
924 * 0x712 (LynxEM+)
925 * 0x720 (Lynx3DM, Lynx3DM+)
926 */
927static const struct pci_device_id smtcfb_pci_table[] = {
928	{ PCI_DEVICE(0x126f, 0x710), },
929	{ PCI_DEVICE(0x126f, 0x712), },
930	{ PCI_DEVICE(0x126f, 0x720), },
931	{0,}
932};
933
934MODULE_DEVICE_TABLE(pci, smtcfb_pci_table);
935
936static void smtcfb_pci_remove(struct pci_dev *pdev)
937{
938	struct smtcfb_info *sfb;
939
940	sfb = pci_get_drvdata(pdev);
941	smtc_unmap_smem(sfb);
942	smtc_unmap_mmio(sfb);
943	unregister_framebuffer(&sfb->fb);
944	smtc_free_fb_info(sfb);
945	pci_release_region(pdev, 0);
946	pci_disable_device(pdev);
947}
948
949#ifdef CONFIG_PM
950static int smtcfb_pci_suspend(struct device *device)
951{
952	struct pci_dev *pdev = to_pci_dev(device);
953	struct smtcfb_info *sfb;
954
955	sfb = pci_get_drvdata(pdev);
956
957	/* set the hw in sleep mode use external clock and self memory refresh
958	 * so that we can turn off internal PLLs later on
959	 */
960	smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
961	smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
962
963	console_lock();
964	fb_set_suspend(&sfb->fb, 1);
965	console_unlock();
966
967	/* additionally turn off all function blocks including internal PLLs */
968	smtc_seqw(0x21, 0xff);
969
970	return 0;
971}
972
973static int smtcfb_pci_resume(struct device *device)
974{
975	struct pci_dev *pdev = to_pci_dev(device);
976	struct smtcfb_info *sfb;
977
978	sfb = pci_get_drvdata(pdev);
979
980	/* reinit hardware */
981	sm7xx_init_hw();
982	switch (sfb->chip_id) {
983	case 0x710:
984	case 0x712:
985		/* set MCLK = 14.31818 *  (0x16 / 0x2) */
986		smtc_seqw(0x6a, 0x16);
987		smtc_seqw(0x6b, 0x02);
988		smtc_seqw(0x62, 0x3e);
989		/* enable PCI burst */
990		smtc_seqw(0x17, 0x20);
991#ifdef __BIG_ENDIAN
992		if (sfb->fb.var.bits_per_pixel == 32)
993			smtc_seqw(0x17, 0x30);
994#endif
995		break;
996	case 0x720:
997		smtc_seqw(0x62, 0xff);
998		smtc_seqw(0x6a, 0x0d);
999		smtc_seqw(0x6b, 0x02);
1000		break;
1001	}
1002
1003	smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
1004	smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
1005
1006	smtcfb_setmode(sfb);
1007
1008	console_lock();
1009	fb_set_suspend(&sfb->fb, 0);
1010	console_unlock();
1011
1012	return 0;
1013}
1014
1015static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
1016#define SM7XX_PM_OPS (&sm7xx_pm_ops)
1017
1018#else  /* !CONFIG_PM */
1019
1020#define SM7XX_PM_OPS NULL
1021
1022#endif /* !CONFIG_PM */
1023
1024static struct pci_driver smtcfb_driver = {
1025	.name = "smtcfb",
1026	.id_table = smtcfb_pci_table,
1027	.probe = smtcfb_pci_probe,
1028	.remove = smtcfb_pci_remove,
1029	.driver.pm  = SM7XX_PM_OPS,
1030};
1031
1032static int __init sm712fb_init(void)
1033{
1034#ifndef MODULE
1035	char *option = NULL;
1036
1037	if (fb_get_options("sm712fb", &option))
1038		return -ENODEV;
1039	if (option && *option)
1040		mode_option = option;
1041#endif
1042	sm7xx_vga_setup(mode_option);
1043
1044	return pci_register_driver(&smtcfb_driver);
1045}
1046
1047module_init(sm712fb_init);
1048
1049static void __exit sm712fb_exit(void)
1050{
1051	pci_unregister_driver(&smtcfb_driver);
1052}
1053
1054module_exit(sm712fb_exit);
1055
1056MODULE_AUTHOR("Siliconmotion ");
1057MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
1058MODULE_LICENSE("GPL");
1059