1/*
2 * Permedia2 framebuffer driver.
3 * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
4 * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
5 * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
6 * --------------------------------------------------------------------------
7 * $Id: pm2fb.c,v 1.1.1.1 2008/10/15 03:27:04 james26_jang Exp $
8 * --------------------------------------------------------------------------
9 * TODO multiple boards support
10 * --------------------------------------------------------------------------
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
13 * for more details.
14 */
15
16#include <linux/config.h>
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/string.h>
21#include <linux/mm.h>
22#include <linux/tty.h>
23#include <linux/slab.h>
24#include <linux/vmalloc.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/fb.h>
28#include <linux/selection.h>
29#include <linux/console.h>
30#include <linux/init.h>
31#include <linux/pci.h>
32#include <asm/system.h>
33#include <asm/io.h>
34#include <asm/uaccess.h>
35#include <video/fbcon.h>
36#include <video/fbcon-cfb8.h>
37#include <video/fbcon-cfb16.h>
38#include <video/fbcon-cfb24.h>
39#include <video/fbcon-cfb32.h>
40#include "pm2fb.h"
41#include "cvisionppc.h"
42#ifdef __sparc__
43#include <asm/pbm.h>
44#include <asm/fbio.h>
45#endif
46
47#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
48#error	"The endianness of the target host has not been defined."
49#endif
50
51#if defined(__BIG_ENDIAN) && !defined(__sparc__)
52#define PM2FB_BE_APERTURE
53#endif
54
55/* Need to debug this some more */
56#undef PM2FB_HW_CURSOR
57
58#if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
59#undef CONFIG_FB_PM2_PCI
60#warning "support for Permedia2 PCI boards with no generic PCI support!"
61#endif
62
63#undef PM2FB_MASTER_DEBUG
64#ifdef PM2FB_MASTER_DEBUG
65#define DPRINTK(a,b...)	printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
66#else
67#define DPRINTK(a,b...)
68#endif
69
70#define PICOS2KHZ(a) (1000000000UL/(a))
71#define KHZ2PICOS(a) (1000000000UL/(a))
72
73/*
74 * The _DEFINITIVE_ memory mapping/unmapping functions.
75 * This is due to the fact that they're changing soooo often...
76 */
77#define MMAP(a,b)	ioremap((unsigned long )(a), b)
78#define UNMAP(a,b)	iounmap(a)
79
80/*
81 * The _DEFINITIVE_ memory i/o barrier functions.
82 * This is due to the fact that they're changing soooo often...
83 */
84#define DEFW()		wmb()
85#define DEFR()		rmb()
86#define DEFRW()		mb()
87
88#ifndef MIN
89#define MIN(a,b) ((a)<(b)?(a):(b))
90#endif
91
92#ifndef MAX
93#define MAX(a,b) ((a)>(b)?(a):(b))
94#endif
95
96struct pm2fb_par {
97	u32 pixclock;		/* pixclock in KHz */
98	u32 width;		/* width of virtual screen */
99	u32 height;		/* height of virtual screen */
100	u32 hsstart;		/* horiz. sync start */
101	u32 hsend;		/* horiz. sync end */
102	u32 hbend;		/* horiz. blank end (also gate end) */
103	u32 htotal;		/* total width (w/ sync & blank) */
104	u32 vsstart;		/* vert. sync start */
105	u32 vsend;		/* vert. sync end */
106	u32 vbend;		/* vert. blank end */
107	u32 vtotal;		/* total height (w/ sync & blank) */
108	u32 stride;		/* screen stride */
109	u32 base;		/* screen base (xoffset+yoffset) */
110	u32 depth;		/* screen depth (8, 16, 24 or 32) */
111	u32 video;		/* video control (hsync,vsync) */
112};
113
114#define OPTF_OLD_MEM		(1L<<0)
115#define OPTF_YPAN		(1L<<1)
116#define OPTF_VIRTUAL		(1L<<2)
117#define OPTF_USER		(1L<<3)
118static struct {
119	char font[40];
120	u32 flags;
121	struct pm2fb_par user_mode;
122} pm2fb_options =
123#ifdef __sparc__
124	/* For some reason Raptor is not happy with the low-end mode */
125	{"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
126#else
127	{"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
128#endif
129
130static char curblink __initdata = 1;
131
132static struct {
133	char name[16];
134	struct pm2fb_par par;
135} user_mode[] __initdata = {
136	{"640x480-60",
137		{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
138	{"640x480-72",
139		{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
140	{"640x480-75",
141		{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
142	{"640x480-90",
143		{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
144	{"640x480-100",
145		{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
146	{"800x600-56",
147		{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
148	{"800x600-60",
149		{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
150	{"800x600-70",
151		{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
152	{"800x600-72",
153		{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
154	{"800x600-75",
155		{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
156	{"800x600-90",
157		{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
158	{"800x600-100",
159		{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
160	{"1024x768-60",
161		{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
162	{"1024x768-70",
163		{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
164	{"1024x768-72",
165		{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
166	{"1024x768-75",
167		{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
168	{"1024x768-90",
169		{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
170	{"1024x768-100",
171		{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
172	{"1024x768-illo",
173		{120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
174	{"1152x864-60",
175		{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
176	{"1152x864-70",
177		{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
178	{"1152x864-75",
179		{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
180	{"1152x864-80",
181		{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
182	{"1280x1024-60",
183		{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
184	{"1280x1024-70",
185		{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
186	{"1280x1024-74",
187		{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
188	{"1280x1024-75",
189		{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
190	{"1600x1200-60",
191		{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
192	{"1600x1200-66",
193		{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
194	{"1600x1200-76",
195		{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
196	{"\0", },
197};
198
199#ifdef CONFIG_FB_PM2_PCI
200struct pm2pci_par {
201	u32 mem_config;
202	u32 mem_control;
203	u32 boot_address;
204	struct pci_dev* dev;
205};
206#endif
207
208#define DEFAULT_CURSOR_BLINK_RATE       (20)
209#define CURSOR_DRAW_DELAY               (2)
210
211struct pm2_cursor {
212    int	enable;
213    int on;
214    int vbl_cnt;
215    int blink_rate;
216    struct {
217        u16 x, y;
218    } pos, hot, size;
219    u8 color[6];
220    u8 bits[8][64];
221    u8 mask[8][64];
222    struct timer_list *timer;
223};
224
225static const char permedia2_name[16]="Permedia2";
226
227static struct pm2fb_info {
228	struct fb_info_gen gen;
229	int board;			/* Permedia2 board index (see
230					   board_table[] below) */
231	pm2type_t type;
232	struct {
233		unsigned long  fb_base;	/* physical framebuffer memory base */
234		u32 fb_size;		/* framebuffer memory size */
235		unsigned long  rg_base;	/* physical register memory base */
236		unsigned long  p_fb;	/* physical address of frame buffer */
237		unsigned char* v_fb;	/* virtual address of frame buffer */
238		unsigned long  p_regs;	/* physical address of registers
239					   region, must be rg_base or
240					   rg_base+PM2_REGS_SIZE depending on
241					   the host endianness */
242		unsigned char* v_regs;	/* virtual address of p_regs */
243	} regions;
244	union {				/* here, the per-board par structs */
245#ifdef CONFIG_FB_PM2_CVPPC
246		struct cvppc_par cvppc;	/* CVisionPPC data */
247#endif
248#ifdef CONFIG_FB_PM2_PCI
249		struct pm2pci_par pci;	/* Permedia2 PCI boards data */
250#endif
251	} board_par;
252	struct pm2fb_par current_par;	/* displayed screen */
253	int current_par_valid;
254	u32 memclock;			/* memclock (set by the per-board
255					   		init routine) */
256	struct display disp;
257	struct {
258		u8 transp;
259		u8 red;
260		u8 green;
261		u8 blue;
262	} palette[256];
263	union {
264#ifdef FBCON_HAS_CFB16
265		u16 cmap16[16];
266#endif
267#ifdef FBCON_HAS_CFB24
268		u32 cmap24[16];
269#endif
270#ifdef FBCON_HAS_CFB32
271		u32 cmap32[16];
272#endif
273	} cmap;
274	struct pm2_cursor *cursor;
275} fb_info;
276
277#ifdef CONFIG_FB_PM2_CVPPC
278static int cvppc_detect(struct pm2fb_info*);
279static void cvppc_init(struct pm2fb_info*);
280#endif
281
282#ifdef CONFIG_FB_PM2_PCI
283static int pm2pci_detect(struct pm2fb_info*);
284static void pm2pci_init(struct pm2fb_info*);
285#endif
286
287#ifdef PM2FB_HW_CURSOR
288static void pm2fb_cursor(struct display *p, int mode, int x, int y);
289static int pm2fb_set_font(struct display *d, int width, int height);
290static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
291static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
292static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
293static u8 cursor_color_map[2] = { 0, 0xff };
294#else
295#define pm2fb_cursor NULL
296#define pm2fb_set_font NULL
297#endif
298
299/*
300 * Table of the supported Permedia2 based boards.
301 * Three hooks are defined for each board:
302 * detect(): should return 1 if the related board has been detected, 0
303 *           otherwise. It should also fill the fields 'regions.fb_base',
304 *           'regions.fb_size', 'regions.rg_base' and 'memclock' in the
305 *           passed pm2fb_info structure.
306 * init(): called immediately after the reset of the Permedia2 chip.
307 *         It should reset the memory controller if needed (the MClk
308 *         is set shortly afterwards by the caller).
309 * cleanup(): called after the driver has been unregistered.
310 *
311 * the init and cleanup pointers can be NULL.
312 */
313static const struct {
314	int (*detect)(struct pm2fb_info*);
315	void (*init)(struct pm2fb_info*);
316	void (*cleanup)(struct pm2fb_info*);
317	char name[32];
318} board_table[] = {
319#ifdef CONFIG_FB_PM2_PCI
320	{ pm2pci_detect, pm2pci_init, NULL, "Permedia2 PCI board" },
321#endif
322#ifdef CONFIG_FB_PM2_CVPPC
323	{ cvppc_detect, cvppc_init, NULL, "CVisionPPC/BVisionPPC" },
324#endif
325	{ NULL, }
326};
327
328/*
329 * partial products for the supported horizontal resolutions.
330 */
331#define PACKPP(p0,p1,p2)	(((p2)<<6)|((p1)<<3)|(p0))
332static const struct {
333	u16 width;
334	u16 pp;
335} pp_table[] = {
336	{ 32,	PACKPP(1, 0, 0) }, { 64,	PACKPP(1, 1, 0) },
337	{ 96,	PACKPP(1, 1, 1) }, { 128,	PACKPP(2, 1, 1) },
338	{ 160,	PACKPP(2, 2, 1) }, { 192,	PACKPP(2, 2, 2) },
339	{ 224,	PACKPP(3, 2, 1) }, { 256,	PACKPP(3, 2, 2) },
340	{ 288,	PACKPP(3, 3, 1) }, { 320,	PACKPP(3, 3, 2) },
341	{ 384,	PACKPP(3, 3, 3) }, { 416,	PACKPP(4, 3, 1) },
342	{ 448,	PACKPP(4, 3, 2) }, { 512,	PACKPP(4, 3, 3) },
343	{ 544,	PACKPP(4, 4, 1) }, { 576,	PACKPP(4, 4, 2) },
344	{ 640,	PACKPP(4, 4, 3) }, { 768,	PACKPP(4, 4, 4) },
345	{ 800,	PACKPP(5, 4, 1) }, { 832,	PACKPP(5, 4, 2) },
346	{ 896,	PACKPP(5, 4, 3) }, { 1024,	PACKPP(5, 4, 4) },
347	{ 1056,	PACKPP(5, 5, 1) }, { 1088,	PACKPP(5, 5, 2) },
348	{ 1152,	PACKPP(5, 5, 3) }, { 1280,	PACKPP(5, 5, 4) },
349	{ 1536,	PACKPP(5, 5, 5) }, { 1568,	PACKPP(6, 5, 1) },
350	{ 1600,	PACKPP(6, 5, 2) }, { 1664,	PACKPP(6, 5, 3) },
351	{ 1792,	PACKPP(6, 5, 4) }, { 2048,	PACKPP(6, 5, 5) },
352	{ 0,	0 } };
353
354static void pm2fb_detect(void);
355static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
356				const void* par, struct fb_info_gen* info);
357static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
358					void* par, struct fb_info_gen* info);
359static int pm2fb_encode_var(struct fb_var_screeninfo* var,
360				const void* par, struct fb_info_gen* info);
361static void pm2fb_get_par(void* par, struct fb_info_gen* info);
362static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
363static int pm2fb_getcolreg(unsigned regno,
364			unsigned* red, unsigned* green, unsigned* blue,
365				unsigned* transp, struct fb_info* info);
366static int pm2fb_setcolreg(unsigned regno,
367			unsigned red, unsigned green, unsigned blue,
368				unsigned transp, struct fb_info* info);
369static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
370static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
371					struct fb_info_gen* info);
372static void pm2fb_set_disp(const void* par, struct display* disp,
373						struct fb_info_gen* info);
374
375static struct fbgen_hwswitch pm2fb_hwswitch={
376	pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var,
377	pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par,
378	pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display,
379	pm2fb_blank, pm2fb_set_disp
380};
381
382static struct fb_ops pm2fb_ops={
383	owner:		THIS_MODULE,
384	fb_get_fix:	fbgen_get_fix,
385	fb_get_var:	fbgen_get_var,
386	fb_set_var:	fbgen_set_var,
387	fb_get_cmap:	fbgen_get_cmap,
388	fb_set_cmap:	fbgen_set_cmap,
389	fb_pan_display:	fbgen_pan_display,
390};
391
392/***************************************************************************
393 * Begin of Permedia2 specific functions
394 ***************************************************************************/
395
396inline static u32 RD32(unsigned char* base, s32 off) {
397
398	return readl(base+off);
399}
400
401inline static void WR32(unsigned char* base, s32 off, u32 v) {
402
403	writel(v, base+off);
404}
405
406inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
407
408	return RD32(p->regions.v_regs, off);
409}
410
411inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
412
413	WR32(p->regions.v_regs, off, v);
414}
415
416inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
417
418	int index = PM2R_RD_INDEXED_DATA;
419	switch (p->type) {
420	case PM2_TYPE_PERMEDIA2:
421		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
422		break;
423	case PM2_TYPE_PERMEDIA2V:
424		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
425		index = PM2VR_RD_INDEXED_DATA;
426		break;
427	}
428	DEFRW();
429	return pm2_RD(p, index);
430}
431
432inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
433						u32 v) {
434
435	int index = PM2R_RD_INDEXED_DATA;
436	switch (p->type) {
437	case PM2_TYPE_PERMEDIA2:
438		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
439		break;
440	case PM2_TYPE_PERMEDIA2V:
441		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
442		index = PM2VR_RD_INDEXED_DATA;
443		break;
444	}
445	DEFRW();
446	pm2_WR(p, index, v);
447}
448
449inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
450
451	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
452	DEFRW();
453	return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
454}
455
456inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
457						u32 v) {
458
459	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
460	DEFRW();
461	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
462}
463
464#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
465#define WAIT_FIFO(p,a)
466#else
467inline static void WAIT_FIFO(struct pm2fb_info* p, u32 a) {
468
469	while(pm2_RD(p, PM2R_IN_FIFO_SPACE)<a);
470	DEFRW();
471}
472#endif
473
474static u32 partprod(u32 xres) {
475	int i;
476
477	for (i=0; pp_table[i].width && pp_table[i].width!=xres; i++);
478	if (!pp_table[i].width)
479		DPRINTK("invalid width %u\n", xres);
480	return pp_table[i].pp;
481}
482
483static u32 to3264(u32 timing, int bpp, int is64) {
484
485	switch (bpp) {
486		case 8:
487			timing=timing>>(2+is64);
488			break;
489		case 16:
490			timing=timing>>(1+is64);
491			break;
492		case 24:
493			timing=(timing*3)>>(2+is64);
494			break;
495		case 32:
496			if (is64)
497				timing=timing>>1;
498			break;
499	}
500	return timing;
501}
502
503static u32 from3264(u32 timing, int bpp, int is64) {
504
505	switch (bpp) {
506		case 8:
507			timing=timing<<(2+is64);
508			break;
509		case 16:
510			timing=timing<<(1+is64);
511			break;
512		case 24:
513			timing=(timing<<(2+is64))/3;
514			break;
515		case 32:
516			if (is64)
517				timing=timing<<1;
518			break;
519	}
520	return timing;
521}
522
523static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
524		unsigned char* pp) {
525	unsigned char m;
526	unsigned char n;
527	unsigned char p;
528	u32 f;
529	s32 curr;
530	s32 delta=100000;
531
532	*mm=*nn=*pp=0;
533	for (n=2; n<15; n++) {
534		for (m=2; m; m++) {
535			f=PM2_REFERENCE_CLOCK*m/n;
536			if (f>=150000 && f<=300000) {
537				for (p=0; p<5; p++, f>>=1) {
538					curr=clk>f?clk-f:f-clk;
539					if (curr<delta) {
540						delta=curr;
541						*mm=m;
542						*nn=n;
543						*pp=p;
544					}
545				}
546			}
547		}
548	}
549}
550
551static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
552		unsigned char* pp) {
553	unsigned char m;
554	unsigned char n;
555	unsigned char p;
556	u32 f;
557	s32 delta=1000;
558
559	*mm=*nn=*pp=0;
560	for (n=1; n; n++) {
561		for (m=1; m; m++) {
562			for (p=0; p<2; p++) {
563				f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
564				if (clk>f-delta && clk<f+delta) {
565					delta=clk>f?clk-f:f-clk;
566					*mm=m;
567					*nn=n;
568					*pp=p;
569				}
570			}
571		}
572	}
573}
574
575static void wait_pm2(struct pm2fb_info* i) {
576
577	WAIT_FIFO(i, 1);
578	pm2_WR(i, PM2R_SYNC, 0);
579	DEFRW();
580	do {
581		while (pm2_RD(i, PM2R_OUT_FIFO_WORDS)==0);
582		DEFR();
583	} while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
584}
585
586static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
587	int i;
588	unsigned char m, n, p;
589
590	pm2_mnp(clk, &m, &n, &p);
591	WAIT_FIFO(info, 10);
592	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
593	DEFW();
594	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
595	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_2, n);
596	DEFW();
597	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 8|p);
598	DEFW();
599	pm2_RDAC_RD(info, PM2I_RD_MEMORY_CLOCK_STATUS);
600	DEFR();
601	for (i=256; i &&
602		!(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
603}
604
605static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
606	int i;
607	unsigned char m, n, p;
608
609	switch (info->type) {
610	case PM2_TYPE_PERMEDIA2:
611		pm2_mnp(clk, &m, &n, &p);
612		WAIT_FIFO(info, 10);
613		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
614		DEFW();
615		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
616		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
617		DEFW();
618		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
619		DEFW();
620		pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
621		DEFR();
622		for (i=256; i &&
623		     !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
624		break;
625	case PM2_TYPE_PERMEDIA2V:
626		pm2v_mnp(clk/2, &m, &n, &p);
627		WAIT_FIFO(info, 8);
628		pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
629		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
630		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
631		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
632		pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
633		break;
634	}
635}
636
637static void clear_palette(struct pm2fb_info* p) {
638	int i=256;
639
640	WAIT_FIFO(p, 1);
641	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
642	DEFW();
643	while (i--) {
644		WAIT_FIFO(p, 3);
645		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
646		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
647		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
648	}
649}
650
651static void set_color(struct pm2fb_info* p, unsigned char regno,
652			unsigned char r, unsigned char g, unsigned char b) {
653
654	WAIT_FIFO(p, 4);
655	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
656	DEFW();
657	pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
658	DEFW();
659	pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
660	DEFW();
661	pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
662}
663
664static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
665
666	WAIT_FIFO(i, 2);
667#ifdef __LITTLE_ENDIAN
668	pm2_WR(i, PM2R_APERTURE_ONE, 0);
669	pm2_WR(i, PM2R_APERTURE_TWO, 0);
670#else
671	switch (p->depth) {
672		case 8:
673		case 24:
674			pm2_WR(i, PM2R_APERTURE_ONE, 0);
675			pm2_WR(i, PM2R_APERTURE_TWO, 1);
676			break;
677		case 16:
678			pm2_WR(i, PM2R_APERTURE_ONE, 2);
679			pm2_WR(i, PM2R_APERTURE_TWO, 1);
680			break;
681		case 32:
682			pm2_WR(i, PM2R_APERTURE_ONE, 1);
683			pm2_WR(i, PM2R_APERTURE_TWO, 1);
684			break;
685	}
686#endif
687}
688
689static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
690	u32 clrmode=0;
691	u32 txtmap=0;
692	u32 pixsize=0;
693	u32 clrformat=0;
694	u32 xres;
695	u32 video, tmp;
696
697	if (i->type == PM2_TYPE_PERMEDIA2V) {
698		WAIT_FIFO(i, 1);
699		pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
700	}
701	xres=(p->width+31)&~31;
702	set_aperture(i, p);
703	DEFRW();
704	WAIT_FIFO(i, 27);
705	pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
706						PM2F_COLOR_KEY_TEST_OFF);
707	switch (p->depth) {
708		case 8:
709			pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
710			clrformat=0x0e;
711			break;
712		case 16:
713			pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
714			clrmode=PM2F_RD_TRUECOLOR|0x06;
715			txtmap=PM2F_TEXTEL_SIZE_16;
716			pixsize=1;
717			clrformat=0x70;
718			break;
719		case 32:
720			pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
721			clrmode=PM2F_RD_TRUECOLOR|0x08;
722			txtmap=PM2F_TEXTEL_SIZE_32;
723			pixsize=2;
724			clrformat=0x20;
725			break;
726		case 24:
727			pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
728			clrmode=PM2F_RD_TRUECOLOR|0x09;
729			txtmap=PM2F_TEXTEL_SIZE_24;
730			pixsize=4;
731			clrformat=0x20;
732			break;
733	}
734	pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
735	pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
736	pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
737	pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
738	pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
739	pm2_WR(i, PM2R_TEXTURE_MAP_FORMAT, txtmap|partprod(xres));
740	pm2_WR(i, PM2R_H_TOTAL, p->htotal);
741	pm2_WR(i, PM2R_HS_START, p->hsstart);
742	pm2_WR(i, PM2R_HS_END, p->hsend);
743	pm2_WR(i, PM2R_HG_END, p->hbend);
744	pm2_WR(i, PM2R_HB_END, p->hbend);
745	pm2_WR(i, PM2R_V_TOTAL, p->vtotal);
746	pm2_WR(i, PM2R_VS_START, p->vsstart);
747	pm2_WR(i, PM2R_VS_END, p->vsend);
748	pm2_WR(i, PM2R_VB_END, p->vbend);
749	pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
750	DEFW();
751	pm2_WR(i, PM2R_SCREEN_BASE, p->base);
752	/* HW cursor needs /VSYNC for recognizing vert retrace */
753	video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
754	video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
755	switch (i->type) {
756	case PM2_TYPE_PERMEDIA2:
757		tmp = PM2F_RD_PALETTE_WIDTH_8;
758		pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
759						   PM2F_RD_GUI_ACTIVE|clrmode);
760		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
761			tmp |= 4; /* invert hsync */
762		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
763			tmp |= 8; /* invert vsync */
764		pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
765		break;
766	case PM2_TYPE_PERMEDIA2V:
767		tmp = 0;
768		pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
769		pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
770		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
771			tmp |= 1; /* invert hsync */
772		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
773			tmp |= 4; /* invert vsync */
774		pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
775		pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
776		break;
777	}
778	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
779	pm2_set_pixclock(i, p->pixclock);
780};
781
782/*
783 * copy with packed pixels (8/16bpp only).
784 */
785static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc,
786					s32 x, s32 y, s32 w, s32 h) {
787	s32 scale=i->current_par.depth==8?2:1;
788	s32 offset;
789
790	if (!w || !h)
791		return;
792	WAIT_FIFO(i, 7);
793	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
794				PM2F_CONFIG_FB_PACKED_DATA|
795				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
796	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
797	pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
798						((xsrc-x)&0xfff));
799	offset=(x&0x3)-(xsrc&0x3);
800	pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|(x>>scale));
801	pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|((w+7)>>scale));
802	pm2_WR(i, PM2R_PACKED_DATA_LIMITS, (offset<<29)|(x<<16)|(x+w));
803	DEFW();
804	pm2_WR(i, PM2R_RENDER,	PM2F_RENDER_RECTANGLE|
805				(x<xsrc?PM2F_INCREASE_X:0)|
806				(y<ysrc?PM2F_INCREASE_Y:0));
807	wait_pm2(i);
808}
809
810/*
811 * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
812 */
813static void pm2fb_block_op(struct pm2fb_info* i, int copy,
814					s32 xsrc, s32 ysrc,
815					s32 x, s32 y, s32 w, s32 h,
816					u32 color) {
817
818	if (!w || !h)
819		return;
820	WAIT_FIFO(i, 6);
821	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
822				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
823	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
824	if (copy)
825		pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
826							((xsrc-x)&0xfff));
827	else
828		pm2_WR(i, PM2R_FB_BLOCK_COLOR, color);
829	pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|x);
830	pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|w);
831	DEFW();
832	pm2_WR(i, PM2R_RENDER,	PM2F_RENDER_RECTANGLE|
833				(x<xsrc?PM2F_INCREASE_X:0)|
834				(y<ysrc?PM2F_INCREASE_Y:0)|
835				(copy?0:PM2F_RENDER_FASTFILL));
836	wait_pm2(i);
837}
838
839/***************************************************************************
840 * Begin of generic initialization functions
841 ***************************************************************************/
842
843static void pm2fb_reset(struct pm2fb_info* p) {
844
845	if (p->type == PM2_TYPE_PERMEDIA2V)
846		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
847	pm2_WR(p, PM2R_RESET_STATUS, 0);
848	DEFRW();
849	while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
850	DEFRW();
851#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
852	DPRINTK("FIFO disconnect enabled\n");
853	pm2_WR(p, PM2R_FIFO_DISCON, 1);
854	DEFRW();
855#endif
856	if (board_table[p->board].init)
857		board_table[p->board].init(p);
858	WAIT_FIFO(p, 48);
859	pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
860					~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
861	pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
862	pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
863	pm2_WR(p, PM2R_FIFO_CONTROL, 0);
864	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
865	pm2_WR(p, PM2R_APERTURE_ONE, 0);
866	pm2_WR(p, PM2R_APERTURE_TWO, 0);
867	pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
868	pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
869	pm2_WR(p, PM2R_LB_READ_MODE, 0);
870	pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
871	pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
872	pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
873	pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
874	pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
875	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
876	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
877	pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
878	pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
879	pm2_WR(p, PM2R_DITHER_MODE, 0);
880	pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
881	pm2_WR(p, PM2R_DEPTH_MODE, 0);
882	pm2_WR(p, PM2R_STENCIL_MODE, 0);
883	pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
884	pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
885	pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
886	pm2_WR(p, PM2R_YUV_MODE, 0);
887	pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
888	pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
889	pm2_WR(p, PM2R_FOG_MODE, 0);
890	pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
891	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
892	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
893	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
894	switch (p->type) {
895	case PM2_TYPE_PERMEDIA2:
896		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
897		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
898		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
899		break;
900	case PM2_TYPE_PERMEDIA2V:
901		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
902		break;
903	}
904	pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
905	pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
906	pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
907	pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
908	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
909	clear_palette(p);
910	if (p->memclock)
911		pm2_set_memclock(p, p->memclock);
912}
913
914static int __init pm2fb_conf(struct pm2fb_info* p){
915
916	for (p->board=0; board_table[p->board].detect &&
917			!(board_table[p->board].detect(p)); p->board++);
918	if (!board_table[p->board].detect) {
919		DPRINTK("no board found.\n");
920		return 0;
921	}
922	DPRINTK("found board: %s\n", board_table[p->board].name);
923
924	p->regions.p_fb=p->regions.fb_base;
925	if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
926		    		"pm2fb")) {
927		printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
928		return 0;
929	}
930	p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
931
932#ifndef PM2FB_BE_APERTURE
933	p->regions.p_regs=p->regions.rg_base;
934#else
935	p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
936#endif
937	if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
938		printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
939		UNMAP(p->regions.v_fb, p->regions.fb_size);
940		return 0;
941	}
942	p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
943
944#ifdef PM2FB_HW_CURSOR
945	p->cursor = pm2_init_cursor(p);
946#endif
947	return 1;
948}
949
950/***************************************************************************
951 * Begin of per-board initialization functions
952 ***************************************************************************/
953
954/*
955 * Phase5 CvisionPPC/BVisionPPC
956 */
957#ifdef CONFIG_FB_PM2_CVPPC
958static int cvppc_PCI_init(struct cvppc_par* p) {
959	extern u32 powerup_PCI_present;
960
961	if (!powerup_PCI_present) {
962		DPRINTK("no PCI bridge detected\n");
963		return 0;
964	}
965	if (!(p->pci_config=MMAP(CVPPC_PCI_CONFIG, 256))) {
966		DPRINTK("unable to map PCI config region\n");
967		return 0;
968	}
969	if (RD32(p->pci_config, PCI_VENDOR_ID)!=
970			((PCI_DEVICE_ID_TI_TVP4020<<16)|PCI_VENDOR_ID_TI)) {
971		DPRINTK("bad vendorID/deviceID\n");
972		return 0;
973	}
974	if (!(p->pci_bridge=MMAP(CSPPC_PCI_BRIDGE, 256))) {
975		DPRINTK("unable to map PCI bridge\n");
976		return 0;
977	}
978	WR32(p->pci_bridge, CSPPC_BRIDGE_ENDIAN, CSPPCF_BRIDGE_BIG_ENDIAN);
979	DEFW();
980	if (pm2fb_options.flags & OPTF_OLD_MEM)
981		WR32(p->pci_config, PCI_CACHE_LINE_SIZE, 0xff00);
982	WR32(p->pci_config, PCI_BASE_ADDRESS_0, CVPPC_REGS_REGION);
983	WR32(p->pci_config, PCI_BASE_ADDRESS_1, CVPPC_FB_APERTURE_ONE);
984	WR32(p->pci_config, PCI_BASE_ADDRESS_2, CVPPC_FB_APERTURE_TWO);
985	WR32(p->pci_config, PCI_ROM_ADDRESS, CVPPC_ROM_ADDRESS);
986	DEFW();
987	WR32(p->pci_config, PCI_COMMAND, 0xef000000 |
988						PCI_COMMAND_IO |
989						PCI_COMMAND_MEMORY |
990						PCI_COMMAND_MASTER);
991	return 1;
992}
993
994static int __init cvppc_detect(struct pm2fb_info* p) {
995
996	if (!cvppc_PCI_init(&p->board_par.cvppc))
997		return 0;
998	p->type = PM2_TYPE_PERMEDIA2;
999	p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
1000	p->regions.fb_size=CVPPC_FB_SIZE;
1001	p->regions.rg_base=CVPPC_REGS_REGION;
1002	p->memclock=CVPPC_MEMCLOCK;
1003	return 1;
1004}
1005
1006static void cvppc_init(struct pm2fb_info* p) {
1007
1008	WAIT_FIFO(p, 3);
1009	pm2_WR(p, PM2R_MEM_CONTROL, 0);
1010	pm2_WR(p, PM2R_BOOT_ADDRESS, 0x30);
1011	DEFW();
1012	if (pm2fb_options.flags & OPTF_OLD_MEM)
1013		pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_OLD);
1014	else
1015		pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_NEW);
1016}
1017#endif /* CONFIG_FB_PM2_CVPPC */
1018
1019/*
1020 * Generic PCI detection routines
1021 */
1022#ifdef CONFIG_FB_PM2_PCI
1023struct {
1024	unsigned short vendor, device;
1025	char *name;
1026	pm2type_t type;
1027} pm2pci_cards[] __initdata = {
1028{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
1029{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
1030{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
1031{ 0, 0 }
1032};
1033
1034static int __init pm2pci_detect(struct pm2fb_info* p) {
1035	struct pm2pci_par* pci=&p->board_par.pci;
1036	struct pci_dev* dev;
1037	int i;
1038	unsigned char* m;
1039#ifdef __sparc__
1040	struct pcidev_cookie *pcp;
1041#endif
1042
1043	memset(pci, 0, sizeof(struct pm2pci_par));
1044	if (!pci_present()) {
1045		DPRINTK("no PCI bus found.\n");
1046		return 0;
1047	}
1048	DPRINTK("scanning PCI bus for known chipsets...\n");
1049
1050	pci_for_each_dev(dev) {
1051		for (i = 0; pm2pci_cards[i].vendor; i++)
1052			if (pm2pci_cards[i].vendor == dev->vendor &&
1053			    pm2pci_cards[i].device == dev->device) {
1054				pci->dev = dev;
1055				p->type = pm2pci_cards[i].type;
1056				DPRINTK("... found %s\n", pm2pci_cards[i].name);
1057				break;
1058			}
1059		if (pci->dev)
1060			break;
1061	}
1062	if (!pci->dev) {
1063		DPRINTK("no PCI board found.\n");
1064		return 0;
1065	}
1066	DPRINTK("PCI board @%08lx %08lx %08lx rom %08lx\n",
1067			pci->dev->resource[0].start,
1068			pci->dev->resource[1].start,
1069			pci->dev->resource[2].start,
1070			pci->dev->resource[PCI_ROM_RESOURCE].start);
1071#ifdef __sparc__
1072	p->regions.rg_base= pci->dev->resource[0].start;
1073	p->regions.fb_base= pci->dev->resource[1].start;
1074	pcp = pci->dev->sysdata;
1075	/* If the user has not asked for a particular mode, lets guess */
1076	if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
1077		char timing[256], *q, *r;
1078		unsigned long w, h;
1079		int i;
1080		prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
1081		if (timing[0]) {
1082			w = simple_strtoul(timing, &q, 0);
1083			h = 0;
1084			if (q == timing) w = 0;
1085			if (w) {
1086				for (i = 0; i < 3; i++) {
1087					for (r = q; *r && (*r < '0' || *r > '9'); r++);
1088					simple_strtoul(r, &q, 0);
1089					if (r == q) break;
1090				}
1091				if (i < 3) w = 0;
1092			}
1093			if (w) {
1094				for (r = q; *r && (*r < '0' || *r > '9'); r++);
1095				h = simple_strtoul(r, &q, 0);
1096				if (r == q) w = 0;
1097			}
1098			if (w == 640 && h == 480) w = 0;
1099			if (w) {
1100				for (i=0; user_mode[i].name[0] &&
1101					  (w != user_mode[i].par.width ||
1102					   h != user_mode[i].par.height); i++);
1103				if (user_mode[i].name[0])
1104					memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
1105			}
1106		}
1107	}
1108#else
1109	if (pm2fb_options.flags & OPTF_VIRTUAL) {
1110		p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0));
1111		p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1));
1112	}
1113	else {
1114		p->regions.rg_base = pci_resource_start(pci->dev, 0);
1115		p->regions.fb_base = pci_resource_start(pci->dev, 1);
1116	}
1117#endif
1118#ifdef PM2FB_BE_APERTURE
1119	p->regions.rg_base += PM2_REGS_SIZE;
1120#endif
1121	if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
1122		pci->mem_control=RD32(m, PM2R_MEM_CONTROL);
1123		pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS);
1124		pci->mem_config=RD32(m, PM2R_MEM_CONFIG);
1125		switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1126			case PM2F_MEM_BANKS_1:
1127				p->regions.fb_size=0x200000;
1128				break;
1129			case PM2F_MEM_BANKS_2:
1130				p->regions.fb_size=0x400000;
1131				break;
1132			case PM2F_MEM_BANKS_3:
1133				p->regions.fb_size=0x600000;
1134				break;
1135			case PM2F_MEM_BANKS_4:
1136				p->regions.fb_size=0x800000;
1137				break;
1138		}
1139		p->memclock=CVPPC_MEMCLOCK;
1140		UNMAP(m, PM2_REGS_SIZE);
1141		return 1;
1142	}
1143	DPRINTK("MMAP() failed.\n");
1144	return 0;
1145}
1146
1147static void pm2pci_init(struct pm2fb_info* p) {
1148	struct pm2pci_par* pci=&p->board_par.pci;
1149
1150	WAIT_FIFO(p, 3);
1151	pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control);
1152	pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address);
1153	DEFW();
1154	pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);
1155}
1156#endif /* CONFIG_FB_PM2_PCI */
1157
1158/***************************************************************************
1159 * Console hw acceleration
1160 ***************************************************************************/
1161
1162
1163static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
1164	struct pm2fb_info* i=(struct pm2fb_info* )info;
1165	u32 video;
1166
1167	if (!i->current_par_valid)
1168		return 1;
1169	video=i->current_par.video;
1170	if (blank_mode>0) {
1171		switch (blank_mode-1) {
1172			case VESA_NO_BLANKING:
1173				video=video&~(PM2F_VIDEO_ENABLE);
1174				break;
1175			case VESA_HSYNC_SUSPEND:
1176				video=video&~(PM2F_HSYNC_MASK|
1177						PM2F_BLANK_LOW);
1178				break;
1179			case VESA_VSYNC_SUSPEND:
1180				video=video&~(PM2F_VSYNC_MASK|
1181						PM2F_BLANK_LOW);
1182				break;
1183			case VESA_POWERDOWN:
1184				video=video&~(PM2F_VSYNC_MASK|
1185						PM2F_HSYNC_MASK|
1186						PM2F_BLANK_LOW);
1187				break;
1188		}
1189	}
1190	WAIT_FIFO(i, 1);
1191	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
1192	return 0;
1193}
1194
1195static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
1196					struct fb_info_gen* info) {
1197	struct pm2fb_info* i=(struct pm2fb_info* )info;
1198
1199	if (!i->current_par_valid)
1200		return -EINVAL;
1201	i->current_par.base=to3264(var->yoffset*i->current_par.width+
1202				var->xoffset, i->current_par.depth, 1);
1203	WAIT_FIFO(i, 1);
1204	pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base);
1205	return 0;
1206}
1207
1208static void pm2fb_pp_bmove(struct display* p, int sy, int sx,
1209				int dy, int dx, int height, int width) {
1210
1211	if (fontwidthlog(p)) {
1212		sx=sx<<fontwidthlog(p);
1213		dx=dx<<fontwidthlog(p);
1214		width=width<<fontwidthlog(p);
1215	}
1216	else {
1217		sx=sx*fontwidth(p);
1218		dx=dx*fontwidth(p);
1219		width=width*fontwidth(p);
1220	}
1221	sy=sy*fontheight(p);
1222	dy=dy*fontheight(p);
1223	height=height*fontheight(p);
1224	pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx,
1225							dy, width, height);
1226}
1227
1228static void pm2fb_bmove(struct display* p, int sy, int sx,
1229				int dy, int dx, int height, int width) {
1230
1231	if (fontwidthlog(p)) {
1232		sx=sx<<fontwidthlog(p);
1233		dx=dx<<fontwidthlog(p);
1234		width=width<<fontwidthlog(p);
1235	}
1236	else {
1237		sx=sx*fontwidth(p);
1238		dx=dx*fontwidth(p);
1239		width=width*fontwidth(p);
1240	}
1241	sy=sy*fontheight(p);
1242	dy=dy*fontheight(p);
1243	height=height*fontheight(p);
1244	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy,
1245							width, height, 0);
1246}
1247
1248#ifdef FBCON_HAS_CFB8
1249static void pm2fb_clear8(struct vc_data* conp, struct display* p,
1250				int sy, int sx, int height, int width) {
1251	u32 c;
1252
1253	sx=sx*fontwidth(p);
1254	width=width*fontwidth(p);
1255	sy=sy*fontheight(p);
1256	height=height*fontheight(p);
1257	c=attr_bgcol_ec(p, conp);
1258	c|=c<<8;
1259	c|=c<<16;
1260	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1261							width, height, c);
1262}
1263
1264static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
1265							int bottom_only) {
1266	u32 c;
1267	u32 sx;
1268	u32 sy;
1269
1270	c=attr_bgcol_ec(p, conp);
1271	c|=c<<8;
1272	c|=c<<16;
1273	sx=conp->vc_cols*fontwidth(p);
1274	sy=conp->vc_rows*fontheight(p);
1275	if (!bottom_only)
1276		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1277			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1278	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1279				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1280}
1281
1282static struct display_switch pm2_cfb8 = {
1283	setup:		fbcon_cfb8_setup,
1284	bmove:		pm2fb_pp_bmove,
1285#ifdef __alpha__
1286	/* Not sure why, but this works and the other does not. */
1287	/* Also, perhaps we need a separate routine to wait for the
1288	   blitter to stop before doing this? */
1289	/* In addition, maybe we need to do this for 16 and 32 bit depths? */
1290	clear:		fbcon_cfb8_clear,
1291#else
1292	clear:		pm2fb_clear8,
1293#endif
1294	putc:		fbcon_cfb8_putc,
1295	putcs:		fbcon_cfb8_putcs,
1296	revc:		fbcon_cfb8_revc,
1297	cursor:		pm2fb_cursor,
1298	set_font:	pm2fb_set_font,
1299	clear_margins:	pm2fb_clear_margins8,
1300	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
1301#endif /* FBCON_HAS_CFB8 */
1302
1303#ifdef FBCON_HAS_CFB16
1304static void pm2fb_clear16(struct vc_data* conp, struct display* p,
1305				int sy, int sx, int height, int width) {
1306	u32 c;
1307
1308	sx=sx*fontwidth(p);
1309	width=width*fontwidth(p);
1310	sy=sy*fontheight(p);
1311	height=height*fontheight(p);
1312	c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1313	c|=c<<16;
1314	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1315							width, height, c);
1316}
1317
1318static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
1319							int bottom_only) {
1320	u32 c;
1321	u32 sx;
1322	u32 sy;
1323
1324	c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1325	c|=c<<16;
1326	sx=conp->vc_cols*fontwidth(p);
1327	sy=conp->vc_rows*fontheight(p);
1328	if (!bottom_only)
1329		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1330			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1331	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1332				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1333}
1334
1335static struct display_switch pm2_cfb16 = {
1336	setup:		fbcon_cfb16_setup,
1337	bmove:		pm2fb_pp_bmove,
1338	clear:		pm2fb_clear16,
1339	putc:		fbcon_cfb16_putc,
1340	putcs:		fbcon_cfb16_putcs,
1341	revc:		fbcon_cfb16_revc,
1342	cursor:		pm2fb_cursor,
1343	set_font:	pm2fb_set_font,
1344	clear_margins:	pm2fb_clear_margins16,
1345	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1346};
1347#endif /* FBCON_HAS_CFB16 */
1348
1349#ifdef FBCON_HAS_CFB24
1350/*
1351 * fast fill for 24bpp works only when red==green==blue
1352 */
1353static void pm2fb_clear24(struct vc_data* conp, struct display* p,
1354				int sy, int sx, int height, int width) {
1355	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1356	u32 c;
1357
1358	c=attr_bgcol_ec(p, conp);
1359	if (		i->palette[c].red==i->palette[c].green &&
1360			i->palette[c].green==i->palette[c].blue) {
1361		c=((u32 *)p->dispsw_data)[c];
1362		c|=(c&0xff0000)<<8;
1363		sx=sx*fontwidth(p);
1364		width=width*fontwidth(p);
1365		sy=sy*fontheight(p);
1366		height=height*fontheight(p);
1367		pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c);
1368	}
1369	else
1370		fbcon_cfb24_clear(conp, p, sy, sx, height, width);
1371
1372}
1373
1374static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
1375							int bottom_only) {
1376	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1377	u32 c;
1378	u32 sx;
1379	u32 sy;
1380
1381	c=attr_bgcol_ec(p, conp);
1382	if (		i->palette[c].red==i->palette[c].green &&
1383			i->palette[c].green==i->palette[c].blue) {
1384		c=((u32 *)p->dispsw_data)[c];
1385		c|=(c&0xff0000)<<8;
1386		sx=conp->vc_cols*fontwidth(p);
1387		sy=conp->vc_rows*fontheight(p);
1388		if (!bottom_only)
1389		pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
1390							p->var.yres_virtual, c);
1391		pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
1392						sx, p->var.yres-sy, c);
1393	}
1394	else
1395		fbcon_cfb24_clear_margins(conp, p, bottom_only);
1396
1397}
1398
1399static struct display_switch pm2_cfb24 = {
1400	setup:		fbcon_cfb24_setup,
1401	bmove:		pm2fb_bmove,
1402	clear:		pm2fb_clear24,
1403	putc:		fbcon_cfb24_putc,
1404	putcs:		fbcon_cfb24_putcs,
1405	revc:		fbcon_cfb24_revc,
1406	cursor:		pm2fb_cursor,
1407	set_font:	pm2fb_set_font,
1408	clear_margins:	pm2fb_clear_margins24,
1409	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1410};
1411#endif /* FBCON_HAS_CFB24 */
1412
1413#ifdef FBCON_HAS_CFB32
1414static void pm2fb_clear32(struct vc_data* conp, struct display* p,
1415				int sy, int sx, int height, int width) {
1416	u32 c;
1417
1418	sx=sx*fontwidth(p);
1419	width=width*fontwidth(p);
1420	sy=sy*fontheight(p);
1421	height=height*fontheight(p);
1422	c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1423	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1424							width, height, c);
1425}
1426
1427static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
1428							int bottom_only) {
1429	u32 c;
1430	u32 sx;
1431	u32 sy;
1432
1433	c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1434	sx=conp->vc_cols*fontwidth(p);
1435	sy=conp->vc_rows*fontheight(p);
1436	if (!bottom_only)
1437		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1438			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1439	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1440				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1441}
1442
1443static struct display_switch pm2_cfb32 = {
1444	setup:		fbcon_cfb32_setup,
1445	bmove:		pm2fb_bmove,
1446	clear:		pm2fb_clear32,
1447	putc:		fbcon_cfb32_putc,
1448	putcs:		fbcon_cfb32_putcs,
1449	revc:		fbcon_cfb32_revc,
1450	cursor:		pm2fb_cursor,
1451	set_font:	pm2fb_set_font,
1452	clear_margins:	pm2fb_clear_margins32,
1453	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1454};
1455#endif /* FBCON_HAS_CFB32 */
1456
1457/***************************************************************************
1458 * Framebuffer functions
1459 ***************************************************************************/
1460
1461static void pm2fb_detect(void) {}
1462
1463static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
1464			const void* par, struct fb_info_gen* info) {
1465	struct pm2fb_info* i=(struct pm2fb_info* )info;
1466	struct pm2fb_par* p=(struct pm2fb_par* )par;
1467
1468	strcpy(fix->id, permedia2_name);
1469	fix->smem_start=i->regions.p_fb;
1470	fix->smem_len=i->regions.fb_size;
1471	fix->mmio_start=i->regions.p_regs;
1472	fix->mmio_len=PM2_REGS_SIZE;
1473	fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
1474	fix->type=FB_TYPE_PACKED_PIXELS;
1475	fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
1476	if (i->current_par_valid)
1477		fix->line_length=i->current_par.width*(i->current_par.depth/8);
1478	else
1479		fix->line_length=0;
1480	fix->xpanstep=p->depth==24?8:64/p->depth;
1481	fix->ypanstep=1;
1482	fix->ywrapstep=0;
1483	return 0;
1484}
1485
1486#ifdef PM2FB_MASTER_DEBUG
1487static void pm2fb_display_var(const struct fb_var_screeninfo* var) {
1488
1489	printk( KERN_DEBUG
1490"- struct fb_var_screeninfo ---------------------------------------------------\n");
1491	printk( KERN_DEBUG
1492		"resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n",
1493			var->xres, var->yres, var->bits_per_pixel,
1494			var->xres_virtual, var->yres_virtual,
1495			var->xoffset, var->yoffset);
1496	printk( KERN_DEBUG
1497		"color: %c%c "
1498		"R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n",
1499			var->grayscale?'G':'C', var->nonstd?'N':'S',
1500			var->red.offset, var->red.length, var->red.msb_right,
1501			var->green.offset, var->green.length, var->green.msb_right,
1502			var->blue.offset, var->blue.length, var->blue.msb_right,
1503			var->transp.offset, var->transp.length,
1504			var->transp.msb_right);
1505	printk( KERN_DEBUG
1506		"timings: %ups (%u,%u)-(%u,%u)+%u+%u\n",
1507		var->pixclock,
1508		var->left_margin, var->upper_margin, var->right_margin,
1509		var->lower_margin, var->hsync_len, var->vsync_len);
1510	printk(	KERN_DEBUG
1511		"activate %08x accel_flags %08x sync %08x vmode %08x\n",
1512		var->activate, var->accel_flags, var->sync, var->vmode);
1513	printk(	KERN_DEBUG
1514"------------------------------------------------------------------------------\n");
1515}
1516
1517#define pm2fb_decode_var pm2fb_wrapped_decode_var
1518#endif
1519
1520static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1521				void* par, struct fb_info_gen* info) {
1522	struct pm2fb_info* i=(struct pm2fb_info* )info;
1523	struct pm2fb_par p;
1524	u32 xres;
1525	int data64;
1526
1527	memset(&p, 0, sizeof(struct pm2fb_par));
1528	p.width=(var->xres_virtual+7)&~7;
1529	p.height=var->yres_virtual;
1530	p.depth=(var->bits_per_pixel+7)&~7;
1531	p.depth=p.depth>32?32:p.depth;
1532	data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
1533	xres=(var->xres+31)&~31;
1534	if (p.width<xres+var->xoffset)
1535		p.width=xres+var->xoffset;
1536	if (p.height<var->yres+var->yoffset)
1537		p.height=var->yres+var->yoffset;
1538	if (!partprod(xres)) {
1539		DPRINTK("width not supported: %u\n", xres);
1540		return -EINVAL;
1541	}
1542	if (p.width>2047) {
1543		DPRINTK("virtual width not supported: %u\n", p.width);
1544		return -EINVAL;
1545	}
1546	if (var->yres<200) {
1547		DPRINTK("height not supported: %u\n",
1548						(u32 )var->yres);
1549		return -EINVAL;
1550	}
1551	if (p.height<200 || p.height>2047) {
1552		DPRINTK("virtual height not supported: %u\n", p.height);
1553		return -EINVAL;
1554	}
1555	if (p.depth>32) {
1556		DPRINTK("depth not supported: %u\n", p.depth);
1557		return -EINVAL;
1558	}
1559	if (p.width*p.height*p.depth/8>i->regions.fb_size) {
1560		DPRINTK("no memory for screen (%ux%ux%u)\n",
1561						p.width, p.height, p.depth);
1562		return -EINVAL;
1563	}
1564	p.pixclock=PICOS2KHZ(var->pixclock);
1565	if (p.pixclock>PM2_MAX_PIXCLOCK) {
1566		DPRINTK("pixclock too high (%uKHz)\n", p.pixclock);
1567		return -EINVAL;
1568	}
1569	p.hsstart=to3264(var->right_margin, p.depth, data64);
1570	p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64);
1571	p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64);
1572	p.htotal=to3264(xres, p.depth, data64)+p.hbend-1;
1573	p.vsstart=var->lower_margin?var->lower_margin-1:0;
1574	p.vsend=var->lower_margin+var->vsync_len-1;
1575	p.vbend=var->lower_margin+var->vsync_len+var->upper_margin;
1576	p.vtotal=var->yres+p.vbend-1;
1577	p.stride=to3264(p.width, p.depth, 1);
1578	p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
1579	if (data64)
1580		p.video|=PM2F_DATA_64_ENABLE;
1581	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1582		p.video|=PM2F_HSYNC_ACT_HIGH;
1583	else
1584		p.video|=PM2F_HSYNC_ACT_LOW;
1585	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1586		p.video|=PM2F_VSYNC_ACT_HIGH;
1587	else
1588		p.video|=PM2F_VSYNC_ACT_LOW;
1589	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
1590		DPRINTK("interlaced not supported\n");
1591		return -EINVAL;
1592	}
1593	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
1594		p.video|=PM2F_LINE_DOUBLE;
1595	if (var->activate==FB_ACTIVATE_NOW)
1596		p.video|=PM2F_VIDEO_ENABLE;
1597	*((struct pm2fb_par* )par)=p;
1598	return 0;
1599}
1600
1601#ifdef PM2FB_MASTER_DEBUG
1602#undef pm2fb_decode_var
1603
1604static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1605				void* par, struct fb_info_gen* info) {
1606	int result;
1607
1608	result=pm2fb_wrapped_decode_var(var, par, info);
1609	pm2fb_display_var(var);
1610	return result;
1611}
1612#endif
1613
1614static int pm2fb_encode_var(struct fb_var_screeninfo* var,
1615				const void* par, struct fb_info_gen* info) {
1616	struct pm2fb_par* p=(struct pm2fb_par* )par;
1617	struct fb_var_screeninfo v;
1618	u32 base;
1619
1620	memset(&v, 0, sizeof(struct fb_var_screeninfo));
1621	v.xres_virtual=p->width;
1622	v.yres_virtual=p->height;
1623	v.xres=(p->htotal+1)-p->hbend;
1624	v.yres=(p->vtotal+1)-p->vbend;
1625	v.right_margin=p->hsstart;
1626	v.hsync_len=p->hsend-p->hsstart;
1627	v.left_margin=p->hbend-p->hsend;
1628	v.lower_margin=p->vsstart+1;
1629	v.vsync_len=p->vsend-v.lower_margin+1;
1630	v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
1631	v.bits_per_pixel=p->depth;
1632	if (p->video & PM2F_DATA_64_ENABLE) {
1633		v.xres=v.xres<<1;
1634		v.right_margin=v.right_margin<<1;
1635		v.hsync_len=v.hsync_len<<1;
1636		v.left_margin=v.left_margin<<1;
1637	}
1638	switch (p->depth) {
1639		case 8:
1640			v.red.length=v.green.length=v.blue.length=8;
1641			v.xres=v.xres<<2;
1642			v.right_margin=v.right_margin<<2;
1643			v.hsync_len=v.hsync_len<<2;
1644			v.left_margin=v.left_margin<<2;
1645			break;
1646		case 16:
1647			v.red.offset=11;
1648			v.red.length=5;
1649			v.green.offset=5;
1650			v.green.length=6;
1651			v.blue.length=5;
1652			v.xres=v.xres<<1;
1653			v.right_margin=v.right_margin<<1;
1654			v.hsync_len=v.hsync_len<<1;
1655			v.left_margin=v.left_margin<<1;
1656			break;
1657		case 32:
1658			v.transp.offset=24;
1659			v.red.offset=16;
1660			v.green.offset=8;
1661			v.red.length=v.green.length=v.blue.length=
1662							v.transp.length=8;
1663			break;
1664		case 24:
1665			v.blue.offset=16;
1666			v.green.offset=8;
1667			v.red.length=v.green.length=v.blue.length=8;
1668			v.xres=(v.xres<<2)/3;
1669			v.right_margin=(v.right_margin<<2)/3;
1670			v.hsync_len=(v.hsync_len<<2)/3;
1671			v.left_margin=(v.left_margin<<2)/3;
1672			break;
1673	}
1674	base=from3264(p->base, p->depth, 1);
1675	v.xoffset=base%v.xres;
1676	v.yoffset=base/v.xres;
1677	v.height=v.width=-1;
1678	v.pixclock=KHZ2PICOS(p->pixclock);
1679	if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
1680		v.sync|=FB_SYNC_HOR_HIGH_ACT;
1681	if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
1682		v.sync|=FB_SYNC_VERT_HIGH_ACT;
1683	if (p->video & PM2F_LINE_DOUBLE)
1684		v.vmode=FB_VMODE_DOUBLE;
1685	*var=v;
1686	return 0;
1687}
1688
1689static void set_user_mode(struct pm2fb_info* i) {
1690
1691	if (pm2fb_options.flags & OPTF_YPAN) {
1692		int h = i->current_par.height;
1693		i->current_par.height=i->regions.fb_size/
1694			(i->current_par.width*i->current_par.depth/8);
1695		i->current_par.height=MIN(i->current_par.height,2047);
1696		i->current_par.height=MAX(i->current_par.height,h);
1697	}
1698}
1699
1700static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
1701	struct pm2fb_info* i=(struct pm2fb_info* )info;
1702
1703	if (!i->current_par_valid) {
1704		set_user_mode(i);
1705		pm2fb_reset(i);
1706		set_screen(i, &i->current_par);
1707		i->current_par_valid=1;
1708	}
1709	*((struct pm2fb_par* )par)=i->current_par;
1710}
1711
1712static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
1713	struct pm2fb_info* i=(struct pm2fb_info* )info;
1714	struct pm2fb_par* p;
1715
1716	p=(struct pm2fb_par* )par;
1717	if (i->current_par_valid) {
1718		i->current_par.base=p->base;
1719		if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
1720			WAIT_FIFO(i, 1);
1721			pm2_WR(i, PM2R_SCREEN_BASE, p->base);
1722			return;
1723		}
1724	}
1725	set_screen(i, p);
1726	i->current_par=*p;
1727	i->current_par_valid=1;
1728#ifdef PM2FB_HW_CURSOR
1729	if (i->cursor) {
1730		pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
1731		pm2v_set_cursor_shape(i);
1732	}
1733#endif
1734}
1735
1736static int pm2fb_getcolreg(unsigned regno,
1737			unsigned* red, unsigned* green, unsigned* blue,
1738				unsigned* transp, struct fb_info* info) {
1739	struct pm2fb_info* i=(struct pm2fb_info* )info;
1740
1741	if (regno<256) {
1742		*red=i->palette[regno].red<<8|i->palette[regno].red;
1743		*green=i->palette[regno].green<<8|i->palette[regno].green;
1744		*blue=i->palette[regno].blue<<8|i->palette[regno].blue;
1745		*transp=i->palette[regno].transp<<8|i->palette[regno].transp;
1746	}
1747	return regno>255;
1748}
1749
1750static int pm2fb_setcolreg(unsigned regno,
1751			unsigned red, unsigned green, unsigned blue,
1752				unsigned transp, struct fb_info* info) {
1753	struct pm2fb_info* i=(struct pm2fb_info* )info;
1754
1755	if (regno<16) {
1756		switch (i->current_par.depth) {
1757#ifdef FBCON_HAS_CFB8
1758			case 8:
1759				break;
1760#endif
1761#ifdef FBCON_HAS_CFB16
1762			case 16:
1763				i->cmap.cmap16[regno]=
1764					((u32 )red & 0xf800) |
1765					(((u32 )green & 0xfc00)>>5) |
1766					(((u32 )blue & 0xf800)>>11);
1767				break;
1768#endif
1769#ifdef FBCON_HAS_CFB24
1770			case 24:
1771				i->cmap.cmap24[regno]=
1772					(((u32 )blue & 0xff00) << 8) |
1773					((u32 )green & 0xff00) |
1774					(((u32 )red & 0xff00) >> 8);
1775				break;
1776#endif
1777#ifdef FBCON_HAS_CFB32
1778			case 32:
1779	   			i->cmap.cmap32[regno]=
1780					(((u32 )transp & 0xff00) << 16) |
1781		    			(((u32 )red & 0xff00) << 8) |
1782					(((u32 )green & 0xff00)) |
1783			 		(((u32 )blue & 0xff00) >> 8);
1784				break;
1785#endif
1786			default:
1787				DPRINTK("bad depth %u\n",
1788						i->current_par.depth);
1789				break;
1790		}
1791	}
1792	if (regno<256) {
1793		i->palette[regno].red=red >> 8;
1794		i->palette[regno].green=green >> 8;
1795		i->palette[regno].blue=blue >> 8;
1796		i->palette[regno].transp=transp >> 8;
1797		if (i->current_par.depth==8)
1798			set_color(i, regno, red>>8, green>>8, blue>>8);
1799	}
1800	return regno>255;
1801}
1802
1803static void pm2fb_set_disp(const void* par, struct display* disp,
1804						   struct fb_info_gen* info) {
1805	struct pm2fb_info* i=(struct pm2fb_info* )info;
1806	unsigned long flags;
1807	unsigned long depth;
1808
1809	save_flags(flags);
1810	cli();
1811	disp->screen_base = i->regions.v_fb;
1812	switch (depth=((struct pm2fb_par* )par)->depth) {
1813#ifdef FBCON_HAS_CFB8
1814		case 8:
1815			disp->dispsw=&pm2_cfb8;
1816			break;
1817#endif
1818#ifdef FBCON_HAS_CFB16
1819		case 16:
1820			disp->dispsw=&pm2_cfb16;
1821			disp->dispsw_data=i->cmap.cmap16;
1822			break;
1823#endif
1824#ifdef FBCON_HAS_CFB24
1825		case 24:
1826			disp->dispsw=&pm2_cfb24;
1827			disp->dispsw_data=i->cmap.cmap24;
1828			break;
1829#endif
1830#ifdef FBCON_HAS_CFB32
1831		case 32:
1832			disp->dispsw=&pm2_cfb32;
1833			disp->dispsw_data=i->cmap.cmap32;
1834			break;
1835#endif
1836		default:
1837			disp->dispsw=&fbcon_dummy;
1838			break;
1839	}
1840	restore_flags(flags);
1841}
1842
1843#ifdef PM2FB_HW_CURSOR
1844/***************************************************************************
1845 * Hardware cursor support
1846 ***************************************************************************/
1847
1848static u8 cursor_bits_lookup[16] = {
1849	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1850	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1851};
1852
1853static u8 cursor_mask_lookup[16] = {
1854	0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1855	0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
1856};
1857
1858static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
1859{
1860	struct pm2_cursor *c = fb->cursor;
1861	int i;
1862
1863	for (i = 0; i < 2; i++) {
1864		c->color[3*i] = red[i];
1865		c->color[3*i+1] = green[i];
1866		c->color[3*i+2] = blue[i];
1867	}
1868
1869	WAIT_FIFO(fb, 14);
1870	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1871	for (i = 0; i < 6; i++)
1872		pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
1873	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1874}
1875
1876static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
1877{
1878	struct pm2_cursor *c = fb->cursor;
1879	u8 m, b;
1880	int i, x, y;
1881
1882	WAIT_FIFO(fb, 1);
1883	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
1884	for (y = 0, i = 0; y < c->size.y; y++) {
1885		WAIT_FIFO(fb, 32);
1886		for (x = 0; x < c->size.x >> 3; x++) {
1887			m = c->mask[x][y];
1888			b = c->bits[x][y];
1889			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
1890				     cursor_mask_lookup[m >> 4] |
1891				     cursor_bits_lookup[(b & m) >> 4]);
1892			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
1893				     cursor_mask_lookup[m & 0x0f] |
1894				     cursor_bits_lookup[(b & m) & 0x0f]);
1895			i+=2;
1896		}
1897		for ( ; x < 8; x++) {
1898			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1899			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1900			i+=2;
1901		}
1902	}
1903	for (; y < 64; y++) {
1904		WAIT_FIFO(fb, 32);
1905		for (x = 0; x < 8; x++) {
1906			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1907			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1908			i+=2;
1909		}
1910	}
1911	WAIT_FIFO(fb, 1);
1912	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1913}
1914
1915static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
1916{
1917	struct pm2_cursor *c = fb->cursor;
1918	int x = c->pos.x;
1919
1920	if (!on) x = 4000;
1921	WAIT_FIFO(fb, 14);
1922	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1923	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
1924	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
1925	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
1926	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
1927	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
1928	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
1929}
1930
1931static void pm2_cursor_timer_handler(unsigned long dev_addr)
1932{
1933	struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
1934
1935	if (!fb->cursor->enable)
1936		goto out;
1937
1938	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
1939		fb->cursor->on ^= 1;
1940		pm2v_set_cursor(fb, fb->cursor->on);
1941		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
1942	}
1943
1944out:
1945	fb->cursor->timer->expires = jiffies + (HZ / 50);
1946	add_timer(fb->cursor->timer);
1947}
1948
1949static void pm2fb_cursor(struct display *p, int mode, int x, int y)
1950{
1951	struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
1952	struct pm2_cursor *c = fb->cursor;
1953
1954	if (!c) return;
1955
1956	x *= fontwidth(p);
1957	y *= fontheight(p);
1958	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
1959		return;
1960
1961	c->enable = 0;
1962	if (c->on)
1963		pm2v_set_cursor(fb, 0);
1964	c->pos.x = x;
1965	c->pos.y = y;
1966
1967	switch (mode) {
1968	case CM_ERASE:
1969		c->on = 0;
1970		break;
1971
1972	case CM_DRAW:
1973	case CM_MOVE:
1974		if (c->on)
1975			pm2v_set_cursor(fb, 1);
1976		else
1977			c->vbl_cnt = CURSOR_DRAW_DELAY;
1978		c->enable = 1;
1979		break;
1980	}
1981}
1982
1983static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
1984{
1985	struct pm2_cursor *cursor;
1986
1987	if (fb->type != PM2_TYPE_PERMEDIA2V)
1988		return 0;
1989
1990	cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
1991	if (!cursor)
1992		return 0;
1993	memset(cursor, 0, sizeof(*cursor));
1994
1995	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
1996	if (!cursor->timer) {
1997		kfree(cursor);
1998		return 0;
1999	}
2000	memset(cursor->timer, 0, sizeof(*cursor->timer));
2001
2002	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
2003
2004	if (curblink) {
2005		init_timer(cursor->timer);
2006		cursor->timer->expires = jiffies + (HZ / 50);
2007		cursor->timer->data = (unsigned long)fb;
2008		cursor->timer->function = pm2_cursor_timer_handler;
2009		add_timer(cursor->timer);
2010	}
2011
2012	return cursor;
2013}
2014
2015static int pm2fb_set_font(struct display *d, int width, int height)
2016{
2017	struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
2018	struct pm2_cursor *c = fb->cursor;
2019	int i, j;
2020
2021	if (c) {
2022		if (!width || !height) {
2023			width = 8;
2024			height = 16;
2025		}
2026
2027		c->hot.x = 0;
2028		c->hot.y = 0;
2029		c->size.x = width;
2030		c->size.y = height;
2031
2032		memset(c->bits, 0xff, sizeof(c->bits));
2033		memset(c->mask, 0, sizeof(c->mask));
2034
2035		for (i = 0, j = width; j >= 0; j -= 8, i++) {
2036			c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
2037			c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
2038		}
2039
2040		pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
2041		pm2v_set_cursor_shape(fb);
2042	}
2043	return 1;
2044}
2045#endif /* PM2FB_HW_CURSOR */
2046
2047/***************************************************************************
2048 * Begin of public functions
2049 ***************************************************************************/
2050
2051#ifdef MODULE
2052static void pm2fb_cleanup(void) {
2053	struct pm2fb_info* i = &fb_info;
2054
2055	unregister_framebuffer((struct fb_info *)i);
2056	pm2fb_reset(i);
2057
2058	UNMAP(i->regions.v_fb, i->regions.fb_size);
2059	release_mem_region(i->regions.p_fb, i->regions.fb_size);
2060
2061	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
2062	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
2063
2064	if (board_table[i->board].cleanup)
2065		board_table[i->board].cleanup(i);
2066}
2067#endif /* MODULE */
2068
2069int __init pm2fb_init(void){
2070
2071	MOD_INC_USE_COUNT;
2072	memset(&fb_info, 0, sizeof(fb_info));
2073	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
2074	if (!pm2fb_conf(&fb_info)) {
2075		MOD_DEC_USE_COUNT;
2076		return -ENXIO;
2077	}
2078	pm2fb_reset(&fb_info);
2079	fb_info.disp.scrollmode=SCROLL_YNOMOVE;
2080	fb_info.gen.parsize=sizeof(struct pm2fb_par);
2081	fb_info.gen.fbhw=&pm2fb_hwswitch;
2082	strcpy(fb_info.gen.info.modename, permedia2_name);
2083	fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
2084	fb_info.gen.info.fbops=&pm2fb_ops;
2085	fb_info.gen.info.disp=&fb_info.disp;
2086	strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
2087	fb_info.gen.info.switch_con=&fbgen_switch;
2088	fb_info.gen.info.updatevar=&fbgen_update_var;
2089	fb_info.gen.info.blank=&fbgen_blank;
2090	fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
2091	fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
2092	fbgen_set_disp(-1, &fb_info.gen);
2093	fbgen_install_cmap(0, &fb_info.gen);
2094	if (register_framebuffer(&fb_info.gen.info)<0) {
2095		printk(KERN_ERR "pm2fb: unable to register.\n");
2096		MOD_DEC_USE_COUNT;
2097		return -EINVAL;
2098	}
2099	printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.\n",
2100				GET_FB_IDX(fb_info.gen.info.node),
2101				board_table[fb_info.board].name,
2102				permedia2_name,
2103				(u32 )(fb_info.regions.fb_size>>10));
2104	return 0;
2105}
2106
2107static void __init pm2fb_mode_setup(char* options){
2108	int i;
2109
2110	for (i=0; user_mode[i].name[0] &&
2111		strcmp(options, user_mode[i].name); i++);
2112	if (user_mode[i].name[0]) {
2113		memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
2114					sizeof(pm2fb_options.user_mode));
2115		pm2fb_options.flags |= OPTF_USER;
2116	}
2117}
2118
2119static void __init pm2fb_font_setup(char* options){
2120
2121	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
2122	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
2123}
2124
2125int __init pm2fb_setup(char* options){
2126	char* next;
2127
2128	while (options) {
2129		if ((next=strchr(options, ',')))
2130			*(next++)='\0';
2131		if (!strncmp(options, "font:", 5))
2132			pm2fb_font_setup(options+5);
2133		else if (!strncmp(options, "mode:", 5))
2134			pm2fb_mode_setup(options+5);
2135		else if (!strcmp(options, "ypan"))
2136			pm2fb_options.flags |= OPTF_YPAN;
2137		else if (!strcmp(options, "oldmem"))
2138			pm2fb_options.flags |= OPTF_OLD_MEM;
2139		else if (!strcmp(options, "virtual"))
2140			pm2fb_options.flags |= OPTF_VIRTUAL;
2141		else if (!strcmp(options, "noblink"))
2142			curblink = 0;
2143		options=next;
2144	}
2145	return 0;
2146}
2147
2148/***************************************************************************
2149 * Begin of module functions
2150 ***************************************************************************/
2151
2152#ifdef MODULE
2153
2154MODULE_LICENSE("GPL");
2155
2156static char *mode = NULL;
2157
2158MODULE_PARM(mode, "s");
2159
2160int __init init_module(void) {
2161
2162	if (mode) pm2fb_mode_setup(mode);
2163	return pm2fb_init();
2164}
2165
2166void cleanup_module(void) {
2167
2168	pm2fb_cleanup();
2169}
2170#endif /* MODULE */
2171
2172/***************************************************************************
2173 * That's all folks!
2174 ***************************************************************************/
2175