make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / 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.1.1.1 2005/04/11 02:50:42 jack 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 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  ***************************************************************************/