File: /usr/src/linux/drivers/video/pm2fb.c

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.163 1999/02/21 14:06:49 illo 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     
96     struct 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)
118     static 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     
130     static char curblink __initdata = 1;
131     
132     static const 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
200     struct 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     
211     struct 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     
225     static const char permedia2_name[16]="Permedia2";
226     
227     static 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
278     static int cvppc_detect(struct pm2fb_info*);
279     static void cvppc_init(struct pm2fb_info*);
280     #endif
281     
282     #ifdef CONFIG_FB_PM2_PCI
283     static int pm2pci_detect(struct pm2fb_info*);
284     static void pm2pci_init(struct pm2fb_info*);
285     #endif
286     
287     #ifdef PM2FB_HW_CURSOR
288     static void pm2fb_cursor(struct display *p, int mode, int x, int y);
289     static int pm2fb_set_font(struct display *d, int width, int height);
290     static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
291     static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
292     static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
293     static 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      */
313     static 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))
332     static 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     
354     static void pm2fb_detect(void);
355     static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
356     				const void* par, struct fb_info_gen* info);
357     static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
358     					void* par, struct fb_info_gen* info);
359     static int pm2fb_encode_var(struct fb_var_screeninfo* var,
360     				const void* par, struct fb_info_gen* info);
361     static void pm2fb_get_par(void* par, struct fb_info_gen* info);
362     static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
363     static int pm2fb_getcolreg(unsigned regno,
364     			unsigned* red, unsigned* green, unsigned* blue,
365     				unsigned* transp, struct fb_info* info);
366     static int pm2fb_setcolreg(unsigned regno,
367     			unsigned red, unsigned green, unsigned blue,
368     				unsigned transp, struct fb_info* info);
369     static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
370     static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
371     					struct fb_info_gen* info);
372     static void pm2fb_set_disp(const void* par, struct display* disp,
373     						struct fb_info_gen* info);
374     
375     static 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     
382     static 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     
396     inline static u32 RD32(unsigned char* base, s32 off) {
397     
398     	return readl(base+off);
399     }
400     
401     inline static void WR32(unsigned char* base, s32 off, u32 v) {
402     
403     	writel(v, base+off);
404     }
405     
406     inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
407     
408     	return RD32(p->regions.v_regs, off);
409     }
410     
411     inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
412     
413     	WR32(p->regions.v_regs, off, v);
414     }
415     
416     inline 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     
432     inline 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     
449     inline 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     
456     inline 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
467     inline 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     
474     static 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     
483     static 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     
503     static 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     
523     static 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     
551     static 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     
575     static 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     
586     static 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     
605     static 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     
637     static 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     
651     static 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     
664     static 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     
689     static 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      */
785     static 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      */
813     static 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     
843     static 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     
914     static 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
958     static 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     
994     static 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     
1006     static 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
1023     struct {
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     
1034     static 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     		/* FIXME: Find out what the actual pixclock is and other values as well */
1082     		if (timing[0]) {
1083     			w = simple_strtoul(timing, &q, 0);
1084     			h = 0;
1085     			if (q == timing) w = 0;
1086     			if (w) {
1087     				for (i = 0; i < 3; i++) {
1088     					for (r = q; *r && (*r < '0' || *r > '9'); r++);
1089     					simple_strtoul(r, &q, 0);
1090     					if (r == q) break;
1091     				}
1092     				if (i < 3) w = 0;
1093     			}
1094     			if (w) {
1095     				for (r = q; *r && (*r < '0' || *r > '9'); r++);
1096     				h = simple_strtoul(r, &q, 0);
1097     				if (r == q) w = 0;
1098     			}
1099     			if (w == 640 && h == 480) w = 0;
1100     			if (w) {
1101     				for (i=0; user_mode[i].name[0] &&
1102     					  (w != user_mode[i].par.width ||
1103     					   h != user_mode[i].par.height); i++);
1104     				if (user_mode[i].name[0])
1105     					memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
1106     			}
1107     		}
1108     	}
1109     #else
1110     	if (pm2fb_options.flags & OPTF_VIRTUAL) {
1111     		p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0));
1112     		p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1));
1113     	}
1114     	else {
1115     		p->regions.rg_base = pci_resource_start(pci->dev, 0);
1116     		p->regions.fb_base = pci_resource_start(pci->dev, 1);
1117     	}
1118     #endif
1119     #ifdef PM2FB_BE_APERTURE
1120     	p->regions.rg_base += PM2_REGS_SIZE;
1121     #endif
1122     	if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
1123     		pci->mem_control=RD32(m, PM2R_MEM_CONTROL);
1124     		pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS);
1125     		pci->mem_config=RD32(m, PM2R_MEM_CONFIG);
1126     		switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1127     			case PM2F_MEM_BANKS_1:
1128     				p->regions.fb_size=0x200000;
1129     				break;
1130     			case PM2F_MEM_BANKS_2:
1131     				p->regions.fb_size=0x400000;
1132     				break;
1133     			case PM2F_MEM_BANKS_3:
1134     				p->regions.fb_size=0x600000;
1135     				break;
1136     			case PM2F_MEM_BANKS_4:
1137     				p->regions.fb_size=0x800000;
1138     				break;
1139     		}
1140     		p->memclock=CVPPC_MEMCLOCK;
1141     		UNMAP(m, PM2_REGS_SIZE);
1142     		return 1;
1143     	}
1144     	DPRINTK("MMAP() failed.\n");
1145     	return 0;
1146     }
1147     
1148     static void pm2pci_init(struct pm2fb_info* p) {
1149     	struct pm2pci_par* pci=&p->board_par.pci;
1150     
1151     	WAIT_FIFO(p, 3);
1152     	pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control);
1153     	pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address);
1154     	DEFW();
1155     	pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);
1156     }
1157     #endif /* CONFIG_FB_PM2_PCI */
1158     
1159     /***************************************************************************
1160      * Console hw acceleration
1161      ***************************************************************************/
1162     
1163     
1164     static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
1165     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1166     	u32 video;
1167     
1168     	if (!i->current_par_valid)
1169     		return 1;
1170     	video=i->current_par.video;
1171     	if (blank_mode>0) {
1172     		switch (blank_mode-1) {
1173     			case VESA_NO_BLANKING:		/* FIXME */
1174     				video=video&~(PM2F_VIDEO_ENABLE);
1175     				break;
1176     			case VESA_HSYNC_SUSPEND:
1177     				video=video&~(PM2F_HSYNC_MASK|
1178     						PM2F_BLANK_LOW);
1179     				break;
1180     			case VESA_VSYNC_SUSPEND:
1181     				video=video&~(PM2F_VSYNC_MASK|
1182     						PM2F_BLANK_LOW);
1183     				break;
1184     			case VESA_POWERDOWN:
1185     				video=video&~(PM2F_VSYNC_MASK|
1186     						PM2F_HSYNC_MASK|
1187     						PM2F_BLANK_LOW);
1188     				break;
1189     		}
1190     	}
1191     	WAIT_FIFO(i, 1);
1192     	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
1193     	return 0;
1194     }
1195     
1196     static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
1197     					struct fb_info_gen* info) {
1198     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1199     
1200     	if (!i->current_par_valid)
1201     		return -EINVAL;
1202     	i->current_par.base=to3264(var->yoffset*i->current_par.width+
1203     				var->xoffset, i->current_par.depth, 1);
1204     	WAIT_FIFO(i, 1);
1205     	pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base);
1206     	return 0;
1207     }
1208     
1209     static void pm2fb_pp_bmove(struct display* p, int sy, int sx,
1210     				int dy, int dx, int height, int width) {
1211     
1212     	if (fontwidthlog(p)) {
1213     		sx=sx<<fontwidthlog(p);
1214     		dx=dx<<fontwidthlog(p);
1215     		width=width<<fontwidthlog(p);
1216     	}
1217     	else {
1218     		sx=sx*fontwidth(p);
1219     		dx=dx*fontwidth(p);
1220     		width=width*fontwidth(p);
1221     	}
1222     	sy=sy*fontheight(p);
1223     	dy=dy*fontheight(p);
1224     	height=height*fontheight(p);
1225     	pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx,
1226     							dy, width, height);
1227     }
1228     
1229     static void pm2fb_bmove(struct display* p, int sy, int sx,
1230     				int dy, int dx, int height, int width) {
1231     
1232     	if (fontwidthlog(p)) {
1233     		sx=sx<<fontwidthlog(p);
1234     		dx=dx<<fontwidthlog(p);
1235     		width=width<<fontwidthlog(p);
1236     	}
1237     	else {
1238     		sx=sx*fontwidth(p);
1239     		dx=dx*fontwidth(p);
1240     		width=width*fontwidth(p);
1241     	}
1242     	sy=sy*fontheight(p);
1243     	dy=dy*fontheight(p);
1244     	height=height*fontheight(p);
1245     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy,
1246     							width, height, 0);
1247     }
1248     
1249     #ifdef FBCON_HAS_CFB8
1250     static void pm2fb_clear8(struct vc_data* conp, struct display* p,
1251     				int sy, int sx, int height, int width) {
1252     	u32 c;
1253     
1254     	sx=sx*fontwidth(p);
1255     	width=width*fontwidth(p);
1256     	sy=sy*fontheight(p);
1257     	height=height*fontheight(p);
1258     	c=attr_bgcol_ec(p, conp);
1259     	c|=c<<8;
1260     	c|=c<<16;
1261     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1262     							width, height, c);
1263     }
1264     
1265     static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
1266     							int bottom_only) {
1267     	u32 c;
1268     	u32 sx;
1269     	u32 sy;
1270     
1271     	c=attr_bgcol_ec(p, conp);
1272     	c|=c<<8;
1273     	c|=c<<16;
1274     	sx=conp->vc_cols*fontwidth(p);
1275     	sy=conp->vc_rows*fontheight(p);
1276     	if (!bottom_only)
1277     		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1278     			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1279     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1280     				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1281     }
1282     
1283     static struct display_switch pm2_cfb8 = {
1284     	setup:		fbcon_cfb8_setup,
1285     	bmove:		pm2fb_pp_bmove,
1286     #ifdef __alpha__
1287     	/* Not sure why, but this works and the other does not. */
1288     	/* Also, perhaps we need a separate routine to wait for the
1289     	   blitter to stop before doing this? */
1290     	/* In addition, maybe we need to do this for 16 and 32 bit depths? */
1291     	clear:		fbcon_cfb8_clear,
1292     #else
1293     	clear:		pm2fb_clear8,
1294     #endif
1295     	putc:		fbcon_cfb8_putc,
1296     	putcs:		fbcon_cfb8_putcs,
1297     	revc:		fbcon_cfb8_revc,
1298     	cursor:		pm2fb_cursor,
1299     	set_font:	pm2fb_set_font,
1300     	clear_margins:	pm2fb_clear_margins8,
1301     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
1302     #endif /* FBCON_HAS_CFB8 */
1303     
1304     #ifdef FBCON_HAS_CFB16
1305     static void pm2fb_clear16(struct vc_data* conp, struct display* p,
1306     				int sy, int sx, int height, int width) {
1307     	u32 c;
1308     
1309     	sx=sx*fontwidth(p);
1310     	width=width*fontwidth(p);
1311     	sy=sy*fontheight(p);
1312     	height=height*fontheight(p);
1313     	c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1314     	c|=c<<16;
1315     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1316     							width, height, c);
1317     }
1318     
1319     static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
1320     							int bottom_only) {
1321     	u32 c;
1322     	u32 sx;
1323     	u32 sy;
1324     
1325     	c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1326     	c|=c<<16;
1327     	sx=conp->vc_cols*fontwidth(p);
1328     	sy=conp->vc_rows*fontheight(p);
1329     	if (!bottom_only)
1330     		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1331     			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1332     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1333     				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1334     }
1335     
1336     static struct display_switch pm2_cfb16 = {
1337     	setup:		fbcon_cfb16_setup,
1338     	bmove:		pm2fb_pp_bmove,
1339     	clear:		pm2fb_clear16,
1340     	putc:		fbcon_cfb16_putc,
1341     	putcs:		fbcon_cfb16_putcs,
1342     	revc:		fbcon_cfb16_revc,
1343     	cursor:		pm2fb_cursor,
1344     	set_font:	pm2fb_set_font,
1345     	clear_margins:	pm2fb_clear_margins16,
1346     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1347     };
1348     #endif /* FBCON_HAS_CFB16 */
1349     
1350     #ifdef FBCON_HAS_CFB24
1351     /*
1352      * fast fill for 24bpp works only when red==green==blue
1353      */
1354     static void pm2fb_clear24(struct vc_data* conp, struct display* p,
1355     				int sy, int sx, int height, int width) {
1356     	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1357     	u32 c;
1358     
1359     	c=attr_bgcol_ec(p, conp);
1360     	if (		i->palette[c].red==i->palette[c].green &&
1361     			i->palette[c].green==i->palette[c].blue) {
1362     		c=((u32 *)p->dispsw_data)[c];
1363     		c|=(c&0xff0000)<<8;
1364     		sx=sx*fontwidth(p);
1365     		width=width*fontwidth(p);
1366     		sy=sy*fontheight(p);
1367     		height=height*fontheight(p);
1368     		pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c);
1369     	}
1370     	else
1371     		fbcon_cfb24_clear(conp, p, sy, sx, height, width);
1372     
1373     }
1374     
1375     static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
1376     							int bottom_only) {
1377     	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1378     	u32 c;
1379     	u32 sx;
1380     	u32 sy;
1381     
1382     	c=attr_bgcol_ec(p, conp);
1383     	if (		i->palette[c].red==i->palette[c].green &&
1384     			i->palette[c].green==i->palette[c].blue) {
1385     		c=((u32 *)p->dispsw_data)[c];
1386     		c|=(c&0xff0000)<<8;
1387     		sx=conp->vc_cols*fontwidth(p);
1388     		sy=conp->vc_rows*fontheight(p);
1389     		if (!bottom_only)
1390     		pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
1391     							p->var.yres_virtual, c);
1392     		pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
1393     						sx, p->var.yres-sy, c);
1394     	}
1395     	else
1396     		fbcon_cfb24_clear_margins(conp, p, bottom_only);
1397     
1398     }
1399     
1400     static struct display_switch pm2_cfb24 = {
1401     	setup:		fbcon_cfb24_setup,
1402     	bmove:		pm2fb_bmove,
1403     	clear:		pm2fb_clear24,
1404     	putc:		fbcon_cfb24_putc,
1405     	putcs:		fbcon_cfb24_putcs,
1406     	revc:		fbcon_cfb24_revc,
1407     	cursor:		pm2fb_cursor,
1408     	set_font:	pm2fb_set_font,
1409     	clear_margins:	pm2fb_clear_margins24,
1410     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1411     };
1412     #endif /* FBCON_HAS_CFB24 */
1413     
1414     #ifdef FBCON_HAS_CFB32
1415     static void pm2fb_clear32(struct vc_data* conp, struct display* p,
1416     				int sy, int sx, int height, int width) {
1417     	u32 c;
1418     
1419     	sx=sx*fontwidth(p);
1420     	width=width*fontwidth(p);
1421     	sy=sy*fontheight(p);
1422     	height=height*fontheight(p);
1423     	c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1424     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1425     							width, height, c);
1426     }
1427     
1428     static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
1429     							int bottom_only) {
1430     	u32 c;
1431     	u32 sx;
1432     	u32 sy;
1433     
1434     	c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1435     	sx=conp->vc_cols*fontwidth(p);
1436     	sy=conp->vc_rows*fontheight(p);
1437     	if (!bottom_only)
1438     		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1439     			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1440     	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1441     				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1442     }
1443     
1444     static struct display_switch pm2_cfb32 = {
1445     	setup:		fbcon_cfb32_setup,
1446     	bmove:		pm2fb_bmove,
1447     	clear:		pm2fb_clear32,
1448     	putc:		fbcon_cfb32_putc,
1449     	putcs:		fbcon_cfb32_putcs,
1450     	revc:		fbcon_cfb32_revc,
1451     	cursor:		pm2fb_cursor,
1452     	set_font:	pm2fb_set_font,
1453     	clear_margins:	pm2fb_clear_margins32,
1454     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1455     };
1456     #endif /* FBCON_HAS_CFB32 */
1457     
1458     /***************************************************************************
1459      * Framebuffer functions
1460      ***************************************************************************/
1461     
1462     static void pm2fb_detect(void) {}
1463     
1464     static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
1465     			const void* par, struct fb_info_gen* info) {
1466     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1467     	struct pm2fb_par* p=(struct pm2fb_par* )par;
1468     
1469     	strcpy(fix->id, permedia2_name);
1470     	fix->smem_start=i->regions.p_fb;
1471     	fix->smem_len=i->regions.fb_size;
1472     	fix->mmio_start=i->regions.p_regs;
1473     	fix->mmio_len=PM2_REGS_SIZE;
1474     	fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
1475     	fix->type=FB_TYPE_PACKED_PIXELS;
1476     	fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
1477     	if (i->current_par_valid)
1478     		fix->line_length=i->current_par.width*(i->current_par.depth/8);
1479     	else
1480     		fix->line_length=0;
1481     	fix->xpanstep=p->depth==24?8:64/p->depth;
1482     	fix->ypanstep=1;
1483     	fix->ywrapstep=0;
1484     	return 0;
1485     }
1486     
1487     #ifdef PM2FB_MASTER_DEBUG
1488     static void pm2fb_display_var(const struct fb_var_screeninfo* var) {
1489     
1490     	printk( KERN_DEBUG
1491     "- struct fb_var_screeninfo ---------------------------------------------------\n");
1492     	printk( KERN_DEBUG
1493     		"resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n",
1494     			var->xres, var->yres, var->bits_per_pixel,
1495     			var->xres_virtual, var->yres_virtual,
1496     			var->xoffset, var->yoffset);
1497     	printk( KERN_DEBUG
1498     		"color: %c%c "
1499     		"R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n",
1500     			var->grayscale?'G':'C', var->nonstd?'N':'S',
1501     			var->red.offset, var->red.length, var->red.msb_right,
1502     			var->green.offset, var->green.length, var->green.msb_right,
1503     			var->blue.offset, var->blue.length, var->blue.msb_right,
1504     			var->transp.offset, var->transp.length,
1505     			var->transp.msb_right);
1506     	printk( KERN_DEBUG
1507     		"timings: %ups (%u,%u)-(%u,%u)+%u+%u\n",
1508     		var->pixclock,
1509     		var->left_margin, var->upper_margin, var->right_margin,
1510     		var->lower_margin, var->hsync_len, var->vsync_len);
1511     	printk(	KERN_DEBUG
1512     		"activate %08x accel_flags %08x sync %08x vmode %08x\n",
1513     		var->activate, var->accel_flags, var->sync, var->vmode);
1514     	printk(	KERN_DEBUG
1515     "------------------------------------------------------------------------------\n");
1516     }
1517     
1518     #define pm2fb_decode_var pm2fb_wrapped_decode_var
1519     #endif
1520     
1521     static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1522     				void* par, struct fb_info_gen* info) {
1523     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1524     	struct pm2fb_par p;
1525     	u32 xres;
1526     	int data64;
1527     
1528     	memset(&p, 0, sizeof(struct pm2fb_par));
1529     	p.width=(var->xres_virtual+7)&~7;
1530     	p.height=var->yres_virtual;
1531     	p.depth=(var->bits_per_pixel+7)&~7;
1532     	p.depth=p.depth>32?32:p.depth;
1533     	data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
1534     	xres=(var->xres+31)&~31;
1535     	if (p.width<xres+var->xoffset)
1536     		p.width=xres+var->xoffset;
1537     	if (p.height<var->yres+var->yoffset)
1538     		p.height=var->yres+var->yoffset;
1539     	if (!partprod(xres)) {
1540     		DPRINTK("width not supported: %u\n", xres);
1541     		return -EINVAL;
1542     	}
1543     	if (p.width>2047) {
1544     		DPRINTK("virtual width not supported: %u\n", p.width);
1545     		return -EINVAL;
1546     	}
1547     	if (var->yres<200) {
1548     		DPRINTK("height not supported: %u\n",
1549     						(u32 )var->yres);
1550     		return -EINVAL;
1551     	}
1552     	if (p.height<200 || p.height>2047) {
1553     		DPRINTK("virtual height not supported: %u\n", p.height);
1554     		return -EINVAL;
1555     	}
1556     	if (p.depth>32) {
1557     		DPRINTK("depth not supported: %u\n", p.depth);
1558     		return -EINVAL;
1559     	}
1560     	if (p.width*p.height*p.depth/8>i->regions.fb_size) {
1561     		DPRINTK("no memory for screen (%ux%ux%u)\n",
1562     						p.width, p.height, p.depth);
1563     		return -EINVAL;
1564     	}
1565     	p.pixclock=PICOS2KHZ(var->pixclock);
1566     	if (p.pixclock>PM2_MAX_PIXCLOCK) {
1567     		DPRINTK("pixclock too high (%uKHz)\n", p.pixclock);
1568     		return -EINVAL;
1569     	}
1570     	p.hsstart=to3264(var->right_margin, p.depth, data64);
1571     	p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64);
1572     	p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64);
1573     	p.htotal=to3264(xres, p.depth, data64)+p.hbend-1;
1574     	p.vsstart=var->lower_margin?var->lower_margin-1:0;	/* FIXME! */
1575     	p.vsend=var->lower_margin+var->vsync_len-1;
1576     	p.vbend=var->lower_margin+var->vsync_len+var->upper_margin;
1577     	p.vtotal=var->yres+p.vbend-1;
1578     	p.stride=to3264(p.width, p.depth, 1);
1579     	p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
1580     	if (data64)
1581     		p.video|=PM2F_DATA_64_ENABLE;
1582     	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1583     		p.video|=PM2F_HSYNC_ACT_HIGH;
1584     	else
1585     		p.video|=PM2F_HSYNC_ACT_LOW;
1586     	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1587     		p.video|=PM2F_VSYNC_ACT_HIGH;
1588     	else
1589     		p.video|=PM2F_VSYNC_ACT_LOW;
1590     	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
1591     		DPRINTK("interlaced not supported\n");
1592     		return -EINVAL;
1593     	}
1594     	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
1595     		p.video|=PM2F_LINE_DOUBLE;
1596     	if (var->activate==FB_ACTIVATE_NOW)
1597     		p.video|=PM2F_VIDEO_ENABLE;
1598     	*((struct pm2fb_par* )par)=p;
1599     	return 0;
1600     }
1601     
1602     #ifdef PM2FB_MASTER_DEBUG
1603     #undef pm2fb_decode_var
1604     
1605     static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1606     				void* par, struct fb_info_gen* info) {
1607     	int result;
1608     
1609     	result=pm2fb_wrapped_decode_var(var, par, info);
1610     	pm2fb_display_var(var);
1611     	return result;
1612     }
1613     #endif
1614     
1615     static int pm2fb_encode_var(struct fb_var_screeninfo* var,
1616     				const void* par, struct fb_info_gen* info) {
1617     	struct pm2fb_par* p=(struct pm2fb_par* )par;
1618     	struct fb_var_screeninfo v;
1619     	u32 base;
1620     
1621     	memset(&v, 0, sizeof(struct fb_var_screeninfo));
1622     	v.xres_virtual=p->width;
1623     	v.yres_virtual=p->height;
1624     	v.xres=(p->htotal+1)-p->hbend;
1625     	v.yres=(p->vtotal+1)-p->vbend;
1626     	v.right_margin=p->hsstart;
1627     	v.hsync_len=p->hsend-p->hsstart;
1628     	v.left_margin=p->hbend-p->hsend;
1629     	v.lower_margin=p->vsstart+1;
1630     	v.vsync_len=p->vsend-v.lower_margin+1;
1631     	v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
1632     	v.bits_per_pixel=p->depth;
1633     	if (p->video & PM2F_DATA_64_ENABLE) {
1634     		v.xres=v.xres<<1;
1635     		v.right_margin=v.right_margin<<1;
1636     		v.hsync_len=v.hsync_len<<1;
1637     		v.left_margin=v.left_margin<<1;
1638     	}
1639     	switch (p->depth) {
1640     		case 8:
1641     			v.red.length=v.green.length=v.blue.length=8;
1642     			v.xres=v.xres<<2;
1643     			v.right_margin=v.right_margin<<2;
1644     			v.hsync_len=v.hsync_len<<2;
1645     			v.left_margin=v.left_margin<<2;
1646     			break;
1647     		case 16:
1648     			v.red.offset=11;
1649     			v.red.length=5;
1650     			v.green.offset=5;
1651     			v.green.length=6;
1652     			v.blue.length=5;
1653     			v.xres=v.xres<<1;
1654     			v.right_margin=v.right_margin<<1;
1655     			v.hsync_len=v.hsync_len<<1;
1656     			v.left_margin=v.left_margin<<1;
1657     			break;
1658     		case 32:
1659     			v.transp.offset=24;
1660     			v.red.offset=16;
1661     			v.green.offset=8;
1662     			v.red.length=v.green.length=v.blue.length=
1663     							v.transp.length=8;
1664     			break;
1665     		case 24:
1666     			v.blue.offset=16;
1667     			v.green.offset=8;
1668     			v.red.length=v.green.length=v.blue.length=8;
1669     			v.xres=(v.xres<<2)/3;
1670     			v.right_margin=(v.right_margin<<2)/3;
1671     			v.hsync_len=(v.hsync_len<<2)/3;
1672     			v.left_margin=(v.left_margin<<2)/3;
1673     			break;
1674     	}
1675     	base=from3264(p->base, p->depth, 1);
1676     	v.xoffset=base%v.xres;
1677     	v.yoffset=base/v.xres;
1678     	v.height=v.width=-1;
1679     	v.pixclock=KHZ2PICOS(p->pixclock);
1680     	if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
1681     		v.sync|=FB_SYNC_HOR_HIGH_ACT;
1682     	if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
1683     		v.sync|=FB_SYNC_VERT_HIGH_ACT;
1684     	if (p->video & PM2F_LINE_DOUBLE)
1685     		v.vmode=FB_VMODE_DOUBLE;
1686     	*var=v;
1687     	return 0;
1688     }
1689     
1690     static void set_user_mode(struct pm2fb_info* i) {
1691     
1692     	if (pm2fb_options.flags & OPTF_YPAN) {
1693     		int h = i->current_par.height;
1694     		i->current_par.height=i->regions.fb_size/
1695     			(i->current_par.width*i->current_par.depth/8);
1696     		i->current_par.height=MIN(i->current_par.height,2047);
1697     		i->current_par.height=MAX(i->current_par.height,h);
1698     	}
1699     }
1700     
1701     static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
1702     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1703     	
1704     	if (!i->current_par_valid) {
1705     		set_user_mode(i);
1706     		pm2fb_reset(i);
1707     		set_screen(i, &i->current_par);
1708     		i->current_par_valid=1;
1709     	}
1710     	*((struct pm2fb_par* )par)=i->current_par;
1711     }
1712     
1713     static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
1714     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1715     	struct pm2fb_par* p;
1716     
1717     	p=(struct pm2fb_par* )par;
1718     	if (i->current_par_valid) {
1719     		i->current_par.base=p->base;
1720     		if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
1721     			WAIT_FIFO(i, 1);
1722     			pm2_WR(i, PM2R_SCREEN_BASE, p->base);
1723     			return;
1724     		}
1725     	}
1726     	set_screen(i, p);
1727     	i->current_par=*p;
1728     	i->current_par_valid=1;
1729     #ifdef PM2FB_HW_CURSOR	
1730     	if (i->cursor) {
1731     		pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
1732     		pm2v_set_cursor_shape(i);
1733     	}
1734     #endif
1735     }
1736     
1737     static int pm2fb_getcolreg(unsigned regno,
1738     			unsigned* red, unsigned* green, unsigned* blue,
1739     				unsigned* transp, struct fb_info* info) {
1740     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1741     
1742     	if (regno<256) {
1743     		*red=i->palette[regno].red<<8|i->palette[regno].red;
1744     		*green=i->palette[regno].green<<8|i->palette[regno].green;
1745     		*blue=i->palette[regno].blue<<8|i->palette[regno].blue;
1746     		*transp=i->palette[regno].transp<<8|i->palette[regno].transp;
1747     	}
1748     	return regno>255;
1749     }
1750     
1751     static int pm2fb_setcolreg(unsigned regno,
1752     			unsigned red, unsigned green, unsigned blue,
1753     				unsigned transp, struct fb_info* info) {
1754     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1755     
1756     	if (regno<16) {
1757     		switch (i->current_par.depth) {
1758     #ifdef FBCON_HAS_CFB8
1759     			case 8:
1760     				break;
1761     #endif
1762     #ifdef FBCON_HAS_CFB16
1763     			case 16:
1764     				i->cmap.cmap16[regno]=
1765     					((u32 )red & 0xf800) |
1766     					(((u32 )green & 0xfc00)>>5) |
1767     					(((u32 )blue & 0xf800)>>11);
1768     				break;
1769     #endif
1770     #ifdef FBCON_HAS_CFB24
1771     			case 24:
1772     				i->cmap.cmap24[regno]=
1773     					(((u32 )blue & 0xff00) << 8) |
1774     					((u32 )green & 0xff00) |
1775     					(((u32 )red & 0xff00) >> 8);
1776     				break;
1777     #endif
1778     #ifdef FBCON_HAS_CFB32
1779     			case 32:
1780     	   			i->cmap.cmap32[regno]=
1781     					(((u32 )transp & 0xff00) << 16) |
1782     		    			(((u32 )red & 0xff00) << 8) |
1783     					(((u32 )green & 0xff00)) |
1784     			 		(((u32 )blue & 0xff00) >> 8);
1785     				break;
1786     #endif
1787     			default:
1788     				DPRINTK("bad depth %u\n",
1789     						i->current_par.depth);
1790     				break;
1791     		}
1792     	}
1793     	if (regno<256) {
1794     		i->palette[regno].red=red >> 8;
1795     		i->palette[regno].green=green >> 8;
1796     		i->palette[regno].blue=blue >> 8;
1797     		i->palette[regno].transp=transp >> 8;
1798     		if (i->current_par.depth==8)
1799     			set_color(i, regno, red>>8, green>>8, blue>>8);
1800     	}
1801     	return regno>255;
1802     }
1803     
1804     static void pm2fb_set_disp(const void* par, struct display* disp,
1805     						   struct fb_info_gen* info) {
1806     	struct pm2fb_info* i=(struct pm2fb_info* )info;
1807     	unsigned long flags;
1808     	unsigned long depth;
1809     
1810     	save_flags(flags);
1811     	cli();
1812     	disp->screen_base = i->regions.v_fb;
1813     	switch (depth=((struct pm2fb_par* )par)->depth) {
1814     #ifdef FBCON_HAS_CFB8
1815     		case 8:
1816     			disp->dispsw=&pm2_cfb8;
1817     			break;
1818     #endif
1819     #ifdef FBCON_HAS_CFB16
1820     		case 16:
1821     			disp->dispsw=&pm2_cfb16;
1822     			disp->dispsw_data=i->cmap.cmap16;
1823     			break;
1824     #endif
1825     #ifdef FBCON_HAS_CFB24
1826     		case 24:
1827     			disp->dispsw=&pm2_cfb24;
1828     			disp->dispsw_data=i->cmap.cmap24;
1829     			break;
1830     #endif
1831     #ifdef FBCON_HAS_CFB32
1832     		case 32:
1833     			disp->dispsw=&pm2_cfb32;
1834     			disp->dispsw_data=i->cmap.cmap32;
1835     			break;
1836     #endif
1837     		default:
1838     			disp->dispsw=&fbcon_dummy;
1839     			break;
1840     	}
1841     	restore_flags(flags);
1842     }
1843     
1844     #ifdef PM2FB_HW_CURSOR
1845     /***************************************************************************
1846      * Hardware cursor support
1847      ***************************************************************************/
1848      
1849     static u8 cursor_bits_lookup[16] = {
1850     	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1851     	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1852     };
1853     
1854     static u8 cursor_mask_lookup[16] = {
1855     	0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1856     	0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
1857     };
1858     
1859     static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
1860     {
1861     	struct pm2_cursor *c = fb->cursor;
1862     	int i;
1863     
1864     	for (i = 0; i < 2; i++) {
1865     		c->color[3*i] = red[i];
1866     		c->color[3*i+1] = green[i];
1867     		c->color[3*i+2] = blue[i];
1868     	}
1869     
1870     	WAIT_FIFO(fb, 14);
1871     	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1872     	for (i = 0; i < 6; i++)
1873     		pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
1874     	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1875     }
1876     
1877     static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
1878     {
1879     	struct pm2_cursor *c = fb->cursor;
1880     	u8 m, b;
1881     	int i, x, y;
1882     
1883     	WAIT_FIFO(fb, 1);
1884     	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
1885     	for (y = 0, i = 0; y < c->size.y; y++) {
1886     		WAIT_FIFO(fb, 32);
1887     		for (x = 0; x < c->size.x >> 3; x++) {
1888     			m = c->mask[x][y];
1889     			b = c->bits[x][y];
1890     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
1891     				     cursor_mask_lookup[m >> 4] |
1892     				     cursor_bits_lookup[(b & m) >> 4]);
1893     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
1894     				     cursor_mask_lookup[m & 0x0f] |
1895     				     cursor_bits_lookup[(b & m) & 0x0f]);
1896     			i+=2;
1897     		}
1898     		for ( ; x < 8; x++) {
1899     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1900     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1901     			i+=2;
1902     		}
1903     	}
1904     	for (; y < 64; y++) {
1905     		WAIT_FIFO(fb, 32);
1906     		for (x = 0; x < 8; x++) {
1907     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1908     			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1909     			i+=2;
1910     		}
1911     	}
1912     	WAIT_FIFO(fb, 1);
1913     	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1914     }
1915     
1916     static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
1917     {
1918     	struct pm2_cursor *c = fb->cursor;
1919     	int x = c->pos.x;
1920     
1921     	if (!on) x = 4000;
1922     	WAIT_FIFO(fb, 14);
1923     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1924     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
1925     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
1926     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
1927     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
1928     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
1929     	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
1930     }
1931     
1932     static void pm2_cursor_timer_handler(unsigned long dev_addr)
1933     {
1934     	struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
1935     
1936     	if (!fb->cursor->enable)
1937     		goto out;
1938     
1939     	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
1940     		fb->cursor->on ^= 1;
1941     		pm2v_set_cursor(fb, fb->cursor->on);
1942     		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
1943     	}
1944     
1945     out:
1946     	fb->cursor->timer->expires = jiffies + (HZ / 50);
1947     	add_timer(fb->cursor->timer);
1948     }
1949     
1950     static void pm2fb_cursor(struct display *p, int mode, int x, int y)
1951     {
1952     	struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
1953     	struct pm2_cursor *c = fb->cursor;
1954     
1955     	if (!c) return;
1956     
1957     	x *= fontwidth(p);
1958     	y *= fontheight(p);
1959     	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
1960     		return;
1961     
1962     	c->enable = 0;
1963     	if (c->on)
1964     		pm2v_set_cursor(fb, 0);
1965     	c->pos.x = x;
1966     	c->pos.y = y;
1967     
1968     	switch (mode) {
1969     	case CM_ERASE:
1970     		c->on = 0;
1971     		break;
1972     
1973     	case CM_DRAW:
1974     	case CM_MOVE:
1975     		if (c->on)
1976     			pm2v_set_cursor(fb, 1);
1977     		else
1978     			c->vbl_cnt = CURSOR_DRAW_DELAY;
1979     		c->enable = 1;
1980     		break;
1981     	}
1982     }
1983     
1984     static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
1985     {
1986     	struct pm2_cursor *cursor;
1987     
1988     	if (fb->type != PM2_TYPE_PERMEDIA2V)
1989     		return 0; /* FIXME: Support hw cursor everywhere */
1990     
1991     	cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
1992     	if (!cursor)
1993     		return 0;
1994     	memset(cursor, 0, sizeof(*cursor));
1995     
1996     	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
1997     	if (!cursor->timer) {
1998     		kfree(cursor);
1999     		return 0;
2000     	}
2001     	memset(cursor->timer, 0, sizeof(*cursor->timer));
2002     
2003     	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
2004     
2005     	if (curblink) {
2006     		init_timer(cursor->timer);
2007     		cursor->timer->expires = jiffies + (HZ / 50);
2008     		cursor->timer->data = (unsigned long)fb;
2009     		cursor->timer->function = pm2_cursor_timer_handler;
2010     		add_timer(cursor->timer);
2011     	}
2012     
2013     	return cursor;
2014     }
2015     
2016     static int pm2fb_set_font(struct display *d, int width, int height)
2017     {
2018     	struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
2019     	struct pm2_cursor *c = fb->cursor;
2020     	int i, j;
2021     
2022     	if (c) {
2023     		if (!width || !height) {
2024     			width = 8;
2025     			height = 16;
2026     		}
2027     
2028     		c->hot.x = 0;
2029     		c->hot.y = 0;
2030     		c->size.x = width;
2031     		c->size.y = height;
2032     
2033     		memset(c->bits, 0xff, sizeof(c->bits));
2034     		memset(c->mask, 0, sizeof(c->mask));
2035     
2036     		for (i = 0, j = width; j >= 0; j -= 8, i++) {
2037     			c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
2038     			c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
2039     		}
2040     
2041     		pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
2042     		pm2v_set_cursor_shape(fb);
2043     	}
2044     	return 1;
2045     }
2046     #endif /* PM2FB_HW_CURSOR */
2047     
2048     /***************************************************************************
2049      * Begin of public functions
2050      ***************************************************************************/
2051     
2052     #ifdef MODULE
2053     static void pm2fb_cleanup(void) {
2054     	struct pm2fb_info* i = &fb_info;
2055     
2056     	unregister_framebuffer((struct fb_info *)i);
2057     	pm2fb_reset(i);
2058     
2059     	UNMAP(i->regions.v_fb, i->regions.fb_size);
2060     	release_mem_region(i->regions.p_fb, i->regions.fb_size);
2061     
2062     	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
2063     	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
2064     
2065     	if (board_table[i->board].cleanup)
2066     		board_table[i->board].cleanup(i);
2067     }
2068     #endif /* MODULE */
2069     
2070     int __init pm2fb_init(void){
2071     
2072     	MOD_INC_USE_COUNT;
2073     	memset(&fb_info, 0, sizeof(fb_info));
2074     	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
2075     	if (!pm2fb_conf(&fb_info)) {
2076     		MOD_DEC_USE_COUNT;
2077     		return -ENXIO;
2078     	}
2079     	pm2fb_reset(&fb_info);
2080     	fb_info.disp.scrollmode=SCROLL_YNOMOVE;
2081     	fb_info.gen.parsize=sizeof(struct pm2fb_par);
2082     	fb_info.gen.fbhw=&pm2fb_hwswitch;
2083     	strcpy(fb_info.gen.info.modename, permedia2_name);
2084     	fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
2085     	fb_info.gen.info.fbops=&pm2fb_ops;
2086     	fb_info.gen.info.disp=&fb_info.disp;
2087     	strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
2088     	fb_info.gen.info.switch_con=&fbgen_switch;
2089     	fb_info.gen.info.updatevar=&fbgen_update_var;
2090     	fb_info.gen.info.blank=&fbgen_blank;
2091     	fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
2092     	fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
2093     	fbgen_set_disp(-1, &fb_info.gen);
2094     	fbgen_install_cmap(0, &fb_info.gen);
2095     	if (register_framebuffer(&fb_info.gen.info)<0) {
2096     		printk(KERN_ERR "pm2fb: unable to register.\n");
2097     		MOD_DEC_USE_COUNT;
2098     		return -EINVAL;
2099     	}
2100     	printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.\n",
2101     				GET_FB_IDX(fb_info.gen.info.node),
2102     				board_table[fb_info.board].name,
2103     				permedia2_name,
2104     				(u32 )(fb_info.regions.fb_size>>10));
2105     	return 0;
2106     }
2107     
2108     static void __init pm2fb_mode_setup(char* options){
2109     	int i;
2110     
2111     	for (i=0; user_mode[i].name[0] &&
2112     		strcmp(options, user_mode[i].name); i++);
2113     	if (user_mode[i].name[0]) {
2114     		memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
2115     					sizeof(pm2fb_options.user_mode));
2116     		pm2fb_options.flags |= OPTF_USER;
2117     	}
2118     }
2119     
2120     static void __init pm2fb_font_setup(char* options){
2121     
2122     	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
2123     	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
2124     }
2125     
2126     int __init pm2fb_setup(char* options){
2127     	char* next;
2128     
2129     	while (options) {
2130     		if ((next=strchr(options, ',')))
2131     			*(next++)='\0';
2132     		if (!strncmp(options, "font:", 5))
2133     			pm2fb_font_setup(options+5);
2134     		else if (!strncmp(options, "mode:", 5))
2135     			pm2fb_mode_setup(options+5);
2136     		else if (!strcmp(options, "ypan"))
2137     			pm2fb_options.flags |= OPTF_YPAN;
2138     		else if (!strcmp(options, "oldmem"))
2139     			pm2fb_options.flags |= OPTF_OLD_MEM;
2140     		else if (!strcmp(options, "virtual"))
2141     			pm2fb_options.flags |= OPTF_VIRTUAL;
2142     		else if (!strcmp(options, "noblink"))
2143     			curblink = 0;
2144     		options=next;
2145     	}
2146     	return 0;
2147     }
2148     
2149     /***************************************************************************
2150      * Begin of module functions
2151      ***************************************************************************/
2152     
2153     #ifdef MODULE
2154     
2155     MODULE_LICENSE("GPL");
2156     
2157     static char *mode = NULL;
2158     
2159     MODULE_PARM(mode, "s");
2160     
2161     int __init init_module(void) {
2162     
2163     	if (mode) pm2fb_mode_setup(mode);
2164     	return pm2fb_init();
2165     }
2166     
2167     void cleanup_module(void) {
2168     
2169     	pm2fb_cleanup();
2170     }
2171     #endif /* MODULE */
2172     
2173     /***************************************************************************
2174      * That's all folks!
2175      ***************************************************************************/
2176