ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / video / pm2fb.c
1 /*
2  * Permedia2 framebuffer driver.
3  *
4  * 2.5/2.6 driver:
5  * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
6  *
7  * based on 2.4 driver:
8  * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
9  * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
10  *
11  * and additional input from James Simmon's port of Hannu Mallat's tdfx
12  * driver.
13  *
14  * $Id$
15  *
16  * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86.
17  * I have no access to other pm2fb implementations, and cannot test
18  * on them. Therefore for now I am omitting Sparc and CVision code.
19  *
20  * Multiple boards support has been on the TODO list for ages.
21  * Don't expect this to change.
22  *
23  * This file is subject to the terms and conditions of the GNU General Public
24  * License. See the file COPYING in the main directory of this archive for
25  * more details.
26  *
27  * 
28  */
29
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/string.h>
35 #include <linux/mm.h>
36 #include <linux/tty.h>
37 #include <linux/slab.h>
38 #include <linux/delay.h>
39 #include <linux/fb.h>
40 #include <linux/init.h>
41 #include <linux/pci.h>
42
43 #include <video/permedia2.h>
44 #include <video/cvisionppc.h>
45
46 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
47 #error  "The endianness of the target host has not been defined."
48 #endif
49
50 #if defined(__BIG_ENDIAN) && !defined(__sparc__)
51 #define PM2FB_BE_APERTURE
52 #endif
53
54 #if !defined(CONFIG_PCI)
55 #error "Only generic PCI cards supported."
56 #endif
57
58 #undef PM2FB_MASTER_DEBUG
59 #ifdef PM2FB_MASTER_DEBUG
60 #define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
61 #else
62 #define DPRINTK(a,b...)
63 #endif
64
65 /*
66  * Driver data 
67  */
68 static char *mode __initdata = NULL;
69
70 /*
71  * The XFree GLINT driver will (I think to implement hardware cursor
72  * support on TVP4010 and similar where there is no RAMDAC - see
73  * comment in set_video) always request +ve sync regardless of what
74  * the mode requires. This screws me because I have a Sun
75  * fixed-frequency monitor which absolutely has to have -ve sync. So
76  * these flags allow the user to specify that requests for +ve sync
77  * should be silently turned in -ve sync.
78  */
79 static int lowhsync __initdata = 0;
80 static int lowvsync __initdata = 0;     
81
82 /*
83  * The hardware state of the graphics card that isn't part of the
84  * screeninfo.
85  */
86 struct pm2fb_par
87 {
88         pm2type_t       type;           /* Board type */
89         u32             fb_size;        /* framebuffer memory size */
90         unsigned char*  v_fb;           /* virtual address of frame buffer */
91         unsigned char*  v_regs;         /* virtual address of p_regs */
92         u32             memclock;       /* memclock */
93         u32             video;          /* video flags before blanking */
94 };
95
96 /*
97  * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
98  * if we don't use modedb.
99  */
100 static struct fb_fix_screeninfo pm2fb_fix __initdata = {
101         .id =           "", 
102         .type =         FB_TYPE_PACKED_PIXELS,
103         .visual =       FB_VISUAL_PSEUDOCOLOR,
104         .xpanstep =     1,
105         .ypanstep =     1,
106         .ywrapstep =    0, 
107         .accel =        FB_ACCEL_NONE,
108 };
109
110 /*
111  * Default video mode. In case the modedb doesn't work, or we're
112  * a module (in which case modedb doesn't really work).
113  */
114 static struct fb_var_screeninfo pm2fb_var __initdata = {
115         /* "640x480, 8 bpp @ 60 Hz */
116         .xres =         640,
117         .yres =         480,
118         .xres_virtual = 640,
119         .yres_virtual = 480,
120         .bits_per_pixel =8,
121         .red =          {0, 8, 0},
122         .blue =         {0, 8, 0},
123         .green =        {0, 8, 0},
124         .activate =     FB_ACTIVATE_NOW,
125         .height =       -1,
126         .width =        -1,
127         .accel_flags =  0,
128         .pixclock =     39721,
129         .left_margin =  40,
130         .right_margin = 24,
131         .upper_margin = 32,
132         .lower_margin = 11,
133         .hsync_len =    96,
134         .vsync_len =    2,
135         .vmode =        FB_VMODE_NONINTERLACED
136 };
137
138 /*
139  * Utility functions
140  */
141
142 inline static u32 RD32(unsigned char* base, s32 off)
143 {
144         return fb_readl(base + off);
145 }
146
147 inline static void WR32(unsigned char* base, s32 off, u32 v)
148 {
149         fb_writel(v, base + off);
150 }
151
152 inline static u32 pm2_RD(struct pm2fb_par* p, s32 off)
153 {
154         return RD32(p->v_regs, off);
155 }
156
157 inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v)
158 {
159         WR32(p->v_regs, off, v);
160 }
161
162 inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx)
163 {
164         int index = PM2R_RD_INDEXED_DATA;
165         switch (p->type) {
166         case PM2_TYPE_PERMEDIA2:
167                 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
168                 break;
169         case PM2_TYPE_PERMEDIA2V:
170                 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
171                 index = PM2VR_RD_INDEXED_DATA;
172                 break;
173         }       
174         mb();
175         return pm2_RD(p, index);
176 }
177
178 inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
179 {
180         int index = PM2R_RD_INDEXED_DATA;
181         switch (p->type) {
182         case PM2_TYPE_PERMEDIA2:
183                 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
184                 break;
185         case PM2_TYPE_PERMEDIA2V:
186                 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
187                 index = PM2VR_RD_INDEXED_DATA;
188                 break;
189         }       
190         mb();
191         pm2_WR(p, index, v);
192 }
193
194 inline static u32 pm2v_RDAC_RD(struct pm2fb_par* p, s32 idx)
195 {
196         pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
197         mb();
198         return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
199 }
200
201 inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
202 {
203         pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
204         mb();
205         pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
206 }
207
208 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
209 #define WAIT_FIFO(p,a)
210 #else
211 inline static void WAIT_FIFO(struct pm2fb_par* p, u32 a)
212 {
213         while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a );
214         mb();
215 }
216 #endif
217
218 /*
219  * partial products for the supported horizontal resolutions.
220  */
221 #define PACKPP(p0,p1,p2)        (((p2) << 6) | ((p1) << 3) | (p0))
222 static const struct {
223         u16 width;
224         u16 pp;
225 } pp_table[] = {
226         { 32,   PACKPP(1, 0, 0) }, { 64,        PACKPP(1, 1, 0) },
227         { 96,   PACKPP(1, 1, 1) }, { 128,       PACKPP(2, 1, 1) },
228         { 160,  PACKPP(2, 2, 1) }, { 192,       PACKPP(2, 2, 2) },
229         { 224,  PACKPP(3, 2, 1) }, { 256,       PACKPP(3, 2, 2) },
230         { 288,  PACKPP(3, 3, 1) }, { 320,       PACKPP(3, 3, 2) },
231         { 384,  PACKPP(3, 3, 3) }, { 416,       PACKPP(4, 3, 1) },
232         { 448,  PACKPP(4, 3, 2) }, { 512,       PACKPP(4, 3, 3) },
233         { 544,  PACKPP(4, 4, 1) }, { 576,       PACKPP(4, 4, 2) },
234         { 640,  PACKPP(4, 4, 3) }, { 768,       PACKPP(4, 4, 4) },
235         { 800,  PACKPP(5, 4, 1) }, { 832,       PACKPP(5, 4, 2) },
236         { 896,  PACKPP(5, 4, 3) }, { 1024,      PACKPP(5, 4, 4) },
237         { 1056, PACKPP(5, 5, 1) }, { 1088,      PACKPP(5, 5, 2) },
238         { 1152, PACKPP(5, 5, 3) }, { 1280,      PACKPP(5, 5, 4) },
239         { 1536, PACKPP(5, 5, 5) }, { 1568,      PACKPP(6, 5, 1) },
240         { 1600, PACKPP(6, 5, 2) }, { 1664,      PACKPP(6, 5, 3) },
241         { 1792, PACKPP(6, 5, 4) }, { 2048,      PACKPP(6, 5, 5) },
242         { 0,    0 } };
243
244 static u32 partprod(u32 xres)
245 {
246         int i;
247
248         for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
249                 ;
250         if ( pp_table[i].width == 0 )
251                 DPRINTK("invalid width %u\n", xres);
252         return pp_table[i].pp;
253 }
254
255 static u32 to3264(u32 timing, int bpp, int is64)
256 {
257         switch (bpp) {
258         case 8:
259                 timing >>= 2 + is64;
260                 break;
261         case 16:
262                 timing >>= 1 + is64;
263                 break;
264         case 24:
265                 timing = (timing * 3) >> (2 + is64);
266                 break;
267         case 32:
268                 if (is64)
269                         timing >>= 1;
270                 break;
271         }
272         return timing;
273 }
274
275 static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
276                     unsigned char* pp)
277 {
278         unsigned char m;
279         unsigned char n;
280         unsigned char p;
281         u32 f;
282         s32 curr;
283         s32 delta = 100000;
284
285         *mm = *nn = *pp = 0;
286         for (n = 2; n < 15; n++) {
287                 for (m = 2; m; m++) {
288                         f = PM2_REFERENCE_CLOCK * m / n;
289                         if (f >= 150000 && f <= 300000) {
290                                 for ( p = 0; p < 5; p++, f >>= 1) {
291                                         curr = ( clk > f ) ? clk - f : f - clk;
292                                         if ( curr < delta ) {
293                                                 delta=curr;
294                                                 *mm=m;
295                                                 *nn=n;
296                                                 *pp=p;
297                                         }
298                                 }
299                         }
300                 }
301         }
302 }
303
304 static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
305                      unsigned char* pp)
306 {
307         unsigned char m;
308         unsigned char n;
309         unsigned char p;
310         u32 f;
311         s32 delta = 1000;
312
313         *mm = *nn = *pp = 0;
314         for (n = 1; n; n++) {
315                 for ( m = 1; m; m++) {
316                         for ( p = 0; p < 2; p++) {
317                                 f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1)));
318                                 if ( clk > f - delta && clk < f + delta ) {
319                                         delta = ( clk > f ) ? clk - f : f - clk;
320                                         *mm=m;
321                                         *nn=n;
322                                         *pp=p;
323                                 }
324                         }
325                 }
326         }
327 }
328
329 static void clear_palette(struct pm2fb_par* p) {
330         int i=256;
331
332         WAIT_FIFO(p, 1);
333         pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
334         wmb();
335         while (i--) {
336                 WAIT_FIFO(p, 3);
337                 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
338                 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
339                 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
340         }
341 }
342
343 #if 0
344 /*
345  * FIXME:
346  * The 2.4 driver calls this at init time, where it also sets the
347  * initial mode. I don't think the driver should touch the chip
348  * until the console sets a video mode. So I was calling this
349  * at the start of setting a mode. However, certainly on 1280x1024
350  * depth 16 this causes the display to smear slightly.
351  * I don't know why. Guesses to jim.hague@acm.org.
352  */
353 static void reset_card(struct pm2fb_par* p)
354 {
355         if (p->type == PM2_TYPE_PERMEDIA2V)
356                 pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
357         pm2_WR(p, PM2R_RESET_STATUS, 0);
358         mb();
359         while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
360                 ;
361         mb();
362 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
363         DPRINTK("FIFO disconnect enabled\n");
364         pm2_WR(p, PM2R_FIFO_DISCON, 1);
365         mb();
366 #endif
367 }
368 #endif
369
370 static void reset_config(struct pm2fb_par* p)
371 {
372         WAIT_FIFO(p, 52);
373         pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
374                ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
375         pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
376         pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
377         pm2_WR(p, PM2R_FIFO_CONTROL, 0);
378         pm2_WR(p, PM2R_APERTURE_ONE, 0);
379         pm2_WR(p, PM2R_APERTURE_TWO, 0);
380         pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
381         pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
382         pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
383         pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 
384         pm2_WR(p, PM2R_LB_READ_MODE, 0);
385         pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
386         pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
387         pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
388         pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
389         pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
390         pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
391         pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
392         pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
393         pm2_WR(p, PM2R_DITHER_MODE, 0);
394         pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
395         pm2_WR(p, PM2R_DEPTH_MODE, 0);
396         pm2_WR(p, PM2R_STENCIL_MODE, 0);
397         pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
398         pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
399         pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
400         pm2_WR(p, PM2R_YUV_MODE, 0);
401         pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
402         pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
403         pm2_WR(p, PM2R_FOG_MODE, 0);
404         pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
405         pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
406         pm2_WR(p, PM2R_STATISTICS_MODE, 0);
407         pm2_WR(p, PM2R_SCISSOR_MODE, 0);
408         pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
409         switch (p->type) {
410         case PM2_TYPE_PERMEDIA2:
411                 pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
412                 pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
413                 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
414                 break;
415         case PM2_TYPE_PERMEDIA2V:
416                 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
417                 break;
418         }
419         pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
420         pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
421         pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
422         pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
423         pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
424 }
425
426 static void set_aperture(struct pm2fb_par* p, u32 depth)
427 {
428         WAIT_FIFO(p, 4);
429 #ifdef __LITTLE_ENDIAN
430         pm2_WR(p, PM2R_APERTURE_ONE, 0);
431         pm2_WR(p, PM2R_APERTURE_TWO, 0);
432 #else
433         switch (depth) {
434         case 8:
435         case 24:
436                 pm2_WR(p, PM2R_APERTURE_ONE, 0);
437                 pm2_WR(p, PM2R_APERTURE_TWO, 1);
438                 break;
439         case 16:
440                 pm2_WR(p, PM2R_APERTURE_ONE, 2);
441                 pm2_WR(p, PM2R_APERTURE_TWO, 1);
442                 break;
443         case 32:
444                 pm2_WR(p, PM2R_APERTURE_ONE, 1);
445                 pm2_WR(p, PM2R_APERTURE_TWO, 1);
446                 break;
447         }
448 #endif
449 }
450
451 static void set_color(struct pm2fb_par* p, unsigned char regno,
452                       unsigned char r, unsigned char g, unsigned char b)
453 {
454         WAIT_FIFO(p, 4);
455         pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
456         wmb();
457         pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
458         wmb();
459         pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
460         wmb();
461         pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
462 }
463
464 static void set_pixclock(struct pm2fb_par* par, u32 clk)
465 {
466         int i;
467         unsigned char m, n, p;
468
469         switch (par->type) {
470         case PM2_TYPE_PERMEDIA2:
471                 pm2_mnp(clk, &m, &n, &p);
472                 WAIT_FIFO(par, 8);
473                 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
474                 wmb();
475                 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
476                 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
477                 wmb();
478                 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
479                 wmb();
480                 pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
481                 rmb();
482                 for (i = 256;
483                      i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
484                      i--)
485                         ;
486                 break;
487         case PM2_TYPE_PERMEDIA2V:
488                 pm2v_mnp(clk/2, &m, &n, &p);
489                 WAIT_FIFO(par, 8);
490                 pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
491                 pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m);
492                 pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n);
493                 pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p);
494                 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
495                 break;
496         }
497 }
498
499 static void set_video(struct pm2fb_par* p, u32 video) {
500         u32 tmp;
501         u32 vsync;
502
503         vsync = video;
504         
505         /*
506          * The hardware cursor needs +vsync to recognise vert retrace.
507          * We may not be using the hardware cursor, but the X Glint
508          * driver may well. So always set +hsync/+vsync and then set
509          * the RAMDAC to invert the sync if necessary.
510          */
511         vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK);
512         vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
513
514         WAIT_FIFO(p, 5);
515         pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
516
517         switch (p->type) {
518         case PM2_TYPE_PERMEDIA2:
519                 tmp = PM2F_RD_PALETTE_WIDTH_8;
520                 if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
521                         tmp |= 4; /* invert hsync */
522                 if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
523                         tmp |= 8; /* invert vsync */
524                 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp);
525                 break;
526         case PM2_TYPE_PERMEDIA2V:
527                 tmp = 0;
528                 if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
529                         tmp |= 1; /* invert hsync */
530                 if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
531                         tmp |= 4; /* invert vsync */
532                 pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
533                 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1);
534                 break;
535         }
536 }
537
538 /*
539  *
540  */
541
542 /**
543  *      pm2fb_check_var - Optional function. Validates a var passed in. 
544  *      @var: frame buffer variable screen structure
545  *      @info: frame buffer structure that represents a single frame buffer 
546  *
547  *      Checks to see if the hardware supports the state requested by
548  *      var passed in.
549  *
550  *      Returns negative errno on error, or zero on success.
551  */
552 static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
553 {
554         u32 lpitch;
555
556         if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
557             var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
558                 DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
559                 return -EINVAL;
560         }
561
562         if (var->xres != var->xres_virtual) {
563                 DPRINTK("virtual x resolution != physical x resolution not supported\n");
564                 return -EINVAL;
565         }
566
567         if (var->yres > var->yres_virtual) {
568                 DPRINTK("virtual y resolution < physical y resolution not possible\n");
569                 return -EINVAL;
570         }
571
572         if (var->xoffset) {
573                 DPRINTK("xoffset not supported\n");
574                 return -EINVAL;
575         }
576
577         if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
578                 DPRINTK("interlace not supported\n");
579                 return -EINVAL;
580         }
581
582         var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
583         lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
584   
585         if (var->xres < 320 || var->xres > 1600) {
586                 DPRINTK("width not supported: %u\n", var->xres);
587                 return -EINVAL;
588         }
589   
590         if (var->yres < 200 || var->yres > 1200) {
591                 DPRINTK("height not supported: %u\n", var->yres);
592                 return -EINVAL;
593         }
594   
595         if (lpitch * var->yres_virtual > info->fix.smem_len) {
596                 DPRINTK("no memory for screen (%ux%ux%u)\n",
597                         var->xres, var->yres_virtual, var->bits_per_pixel);
598                 return -EINVAL;
599         }
600   
601         if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
602                 DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
603                 return -EINVAL;
604         }
605
606         switch(var->bits_per_pixel) {
607         case 8:
608                 var->red.length = var->green.length = var->blue.length = 8;
609                 break;
610         case 16:
611                 var->red.offset   = 11;
612                 var->red.length   = 5;
613                 var->green.offset = 5;
614                 var->green.length = 6;
615                 var->blue.offset  = 0;
616                 var->blue.length  = 5;
617                 break;
618         case 24:
619                 var->red.offset   = 16;
620                 var->green.offset = 8;
621                 var->blue.offset  = 0;
622                 var->red.length = var->green.length = var->blue.length = 8;
623         case 32:
624                 var->red.offset   = 16;
625                 var->green.offset = 8;
626                 var->blue.offset  = 0;
627                 var->red.length = var->green.length = var->blue.length = 8;
628                 break;
629         }
630         var->height = var->width = -1;
631   
632         var->accel_flags = 0;   /* Can't mmap if this is on */
633         
634         DPRINTK("Checking graphics mode at %dx%d depth %d\n",
635                 var->xres, var->yres, var->bits_per_pixel);
636         return 0;
637 }
638
639 /**
640  *      pm2fb_set_par - Alters the hardware state.
641  *      @info: frame buffer structure that represents a single frame buffer
642  *
643  *      Using the fb_var_screeninfo in fb_info we set the resolution of the
644  *      this particular framebuffer.
645  */
646 static int pm2fb_set_par(struct fb_info *info)
647 {
648         struct pm2fb_par *par = (struct pm2fb_par *) info->par;
649         u32 pixclock;
650         u32 width, height, depth;
651         u32 hsstart, hsend, hbend, htotal;
652         u32 vsstart, vsend, vbend, vtotal;
653         u32 stride;
654         u32 base;
655         u32 video = 0;
656         u32 clrmode = PM2F_RD_COLOR_MODE_RGB;
657         u32 txtmap = 0;
658         u32 pixsize = 0;
659         u32 clrformat = 0;
660         u32 xres;
661         int data64;
662
663         reset_config(par);
664         clear_palette(par);
665     
666         width = (info->var.xres_virtual + 7) & ~7;
667         height = info->var.yres_virtual;
668         depth = (info->var.bits_per_pixel + 7) & ~7;
669         depth = (depth > 32) ? 32 : depth;
670         data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
671
672         xres = (info->var.xres + 31) & ~31;
673         pixclock = PICOS2KHZ(info->var.pixclock);
674         if (pixclock > PM2_MAX_PIXCLOCK) {
675                 DPRINTK("pixclock too high (%uKHz)\n", pixclock);
676                 return -EINVAL;
677         }
678     
679         hsstart = to3264(info->var.right_margin, depth, data64);
680         hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
681         hbend = hsend + to3264(info->var.left_margin, depth, data64);
682         htotal = to3264(xres, depth, data64) + hbend - 1;
683         vsstart = (info->var.lower_margin)
684                 ? info->var.lower_margin - 1
685                 : 0;    /* FIXME! */
686         vsend = info->var.lower_margin + info->var.vsync_len - 1;
687         vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin;
688         vtotal = info->var.yres + vbend - 1;
689         stride = to3264(width, depth, 1);
690         base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
691         if (data64)
692                 video |= PM2F_DATA_64_ENABLE;
693     
694         if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
695                 if (lowhsync) {
696                         DPRINTK("ignoring +hsync, using -hsync.\n");
697                         video |= PM2F_HSYNC_ACT_LOW;
698                 } else
699                         video |= PM2F_HSYNC_ACT_HIGH;
700         }
701         else
702                 video |= PM2F_HSYNC_ACT_LOW;
703         if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
704                 if (lowvsync) {
705                         DPRINTK("ignoring +vsync, using -vsync.\n");
706                         video |= PM2F_VSYNC_ACT_LOW;
707                 } else
708                         video |= PM2F_VSYNC_ACT_HIGH;
709         }
710         else
711                 video |= PM2F_VSYNC_ACT_LOW;
712         if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
713                 DPRINTK("interlaced not supported\n");
714                 return -EINVAL;
715         }
716         if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
717                 video |= PM2F_LINE_DOUBLE;
718         if (info->var.activate==FB_ACTIVATE_NOW)
719                 video |= PM2F_VIDEO_ENABLE;
720         par->video = video;
721
722         info->fix.visual =
723                 (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
724         info->fix.line_length =
725                 info->var.xres * ((info->var.bits_per_pixel + 7) >> 3);
726         info->cmap.len = 256;
727
728         /*
729          * Settings calculated. Now write them out.
730          */
731         if (par->type == PM2_TYPE_PERMEDIA2V) {
732                 WAIT_FIFO(par, 1);
733                 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
734         }
735     
736         set_aperture(par, depth);
737     
738         mb();
739         WAIT_FIFO(par, 19);
740         pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
741                     ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
742         switch (depth) {
743         case 8:
744                 pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
745                 clrformat = 0x0e;
746                 break;
747         case 16:
748                 pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
749                 clrmode |= PM2F_RD_TRUECOLOR | 0x06;
750                 txtmap = PM2F_TEXTEL_SIZE_16;
751                 pixsize = 1;
752                 clrformat = 0x70;
753                 break;
754         case 32:
755                 pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
756                 clrmode |= PM2F_RD_TRUECOLOR | 0x08;
757                 txtmap = PM2F_TEXTEL_SIZE_32;
758                 pixsize = 2;
759                 clrformat = 0x20;
760                 break;
761         case 24:
762                 pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
763                 clrmode |= PM2F_RD_TRUECOLOR | 0x09;
764 #ifndef PM2FB_BE_APERTURE
765                 clrmode &= ~PM2F_RD_COLOR_MODE_RGB;
766 #endif
767                 txtmap = PM2F_TEXTEL_SIZE_24;
768                 pixsize = 4;
769                 clrformat = 0x20;
770                 break;
771         }
772         pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
773         pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
774         pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres));
775         pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres));
776         pm2_WR(par, PM2R_H_TOTAL, htotal);
777         pm2_WR(par, PM2R_HS_START, hsstart);
778         pm2_WR(par, PM2R_HS_END, hsend);
779         pm2_WR(par, PM2R_HG_END, hbend);
780         pm2_WR(par, PM2R_HB_END, hbend);
781         pm2_WR(par, PM2R_V_TOTAL, vtotal);
782         pm2_WR(par, PM2R_VS_START, vsstart);
783         pm2_WR(par, PM2R_VS_END, vsend);
784         pm2_WR(par, PM2R_VB_END, vbend);
785         pm2_WR(par, PM2R_SCREEN_STRIDE, stride);
786         wmb();
787         pm2_WR(par, PM2R_WINDOW_ORIGIN, 0);
788         pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width);
789         pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
790         wmb();
791         pm2_WR(par, PM2R_SCREEN_BASE, base);
792         wmb();
793         set_video(par, video);
794         WAIT_FIFO(par, 4);
795         switch (par->type) {
796         case PM2_TYPE_PERMEDIA2:
797                 pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE,
798                             PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE | clrmode);
799                 break;
800         case PM2_TYPE_PERMEDIA2V:
801                 pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
802                 pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
803                 break;
804         }
805         set_pixclock(par, pixclock);
806         return 0;       
807 }
808
809 /**
810  *      pm2fb_setcolreg - Sets a color register.
811  *      @regno: boolean, 0 copy local, 1 get_user() function
812  *      @red: frame buffer colormap structure
813  *      @green: The green value which can be up to 16 bits wide 
814  *      @blue:  The blue value which can be up to 16 bits wide.
815  *      @transp: If supported the alpha value which can be up to 16 bits wide.  
816  *      @info: frame buffer info structure
817  * 
818  *      Set a single color register. The values supplied have a 16 bit
819  *      magnitude which needs to be scaled in this function for the hardware.
820  *      Pretty much a direct lift from tdfxfb.c.
821  * 
822  *      Returns negative errno on error, or zero on success.
823  */
824 static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
825                            unsigned blue, unsigned transp,
826                            struct fb_info *info)
827 {
828         struct pm2fb_par *par = (struct pm2fb_par *) info->par;
829
830         if (regno >= info->cmap.len)  /* no. of hw registers */
831                 return 1;
832         /*
833          * Program hardware... do anything you want with transp
834          */
835
836         /* grayscale works only partially under directcolor */
837         if (info->var.grayscale) {
838                 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
839                 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
840         }
841
842         /* Directcolor:
843          *   var->{color}.offset contains start of bitfield
844          *   var->{color}.length contains length of bitfield
845          *   {hardwarespecific} contains width of DAC
846          *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
847          *   RAMDAC[X] is programmed to (red, green, blue)
848          *
849          * Pseudocolor:
850          *    uses offset = 0 && length = DAC register width.
851          *    var->{color}.offset is 0
852          *    var->{color}.length contains widht of DAC
853          *    cmap is not used
854          *    DAC[X] is programmed to (red, green, blue)
855          * Truecolor:
856          *    does not use RAMDAC (usually has 3 of them).
857          *    var->{color}.offset contains start of bitfield
858          *    var->{color}.length contains length of bitfield
859          *    cmap is programmed to (red << red.offset) | (green << green.offset) |
860          *                      (blue << blue.offset) | (transp << transp.offset)
861          *    RAMDAC does not exist
862          */
863 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
864         switch (info->fix.visual) {
865         case FB_VISUAL_TRUECOLOR:
866         case FB_VISUAL_PSEUDOCOLOR:
867                 red = CNVT_TOHW(red, info->var.red.length);
868                 green = CNVT_TOHW(green, info->var.green.length);
869                 blue = CNVT_TOHW(blue, info->var.blue.length);
870                 transp = CNVT_TOHW(transp, info->var.transp.length);
871                 set_color(par, regno, red, green, blue);
872                 break;
873         case FB_VISUAL_DIRECTCOLOR:
874                 /* example here assumes 8 bit DAC. Might be different 
875                  * for your hardware */ 
876                 red = CNVT_TOHW(red, 8);       
877                 green = CNVT_TOHW(green, 8);
878                 blue = CNVT_TOHW(blue, 8);
879                 /* hey, there is bug in transp handling... */
880                 transp = CNVT_TOHW(transp, 8);
881                 break;
882         }
883 #undef CNVT_TOHW
884         /* Truecolor has hardware independent palette */
885         if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
886                 u32 v;
887
888                 if (regno >= 16)
889                         return 1;
890
891                 v = (red << info->var.red.offset) |
892                         (green << info->var.green.offset) |
893                         (blue << info->var.blue.offset) |
894                         (transp << info->var.transp.offset);
895
896                 switch (info->var.bits_per_pixel) {
897                 case 8:
898                         /* Yes some hand held devices have this. */ 
899                         ((u8*)(info->pseudo_palette))[regno] = v;
900                         break;  
901                 case 16:
902                         ((u16*)(info->pseudo_palette))[regno] = v;
903                         break;
904                 case 24:
905                 case 32:        
906                         ((u32*)(info->pseudo_palette))[regno] = v;
907                         break;
908                 }
909                 return 0;
910         }
911         /* ... */
912         return 0;
913 }
914
915 /**
916  *      pm2fb_pan_display - Pans the display.
917  *      @var: frame buffer variable screen structure
918  *      @info: frame buffer structure that represents a single frame buffer
919  *
920  *      Pan (or wrap, depending on the `vmode' field) the display using the
921  *      `xoffset' and `yoffset' fields of the `var' structure.
922  *      If the values don't fit, return -EINVAL.
923  *
924  *      Returns negative errno on error, or zero on success.
925  *
926  */
927 static int pm2fb_pan_display(struct fb_var_screeninfo *var,
928                              struct fb_info *info)
929 {
930         struct pm2fb_par *p = (struct pm2fb_par *) info->par;
931         u32 base;
932         u32 depth;
933         u32 xres;
934
935         xres = (var->xres + 31) & ~31;
936         depth = (var->bits_per_pixel + 7) & ~7;
937         depth = (depth > 32) ? 32 : depth;
938         base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
939         WAIT_FIFO(p, 1);
940         pm2_WR(p, PM2R_SCREEN_BASE, base);    
941         return 0;
942 }
943
944 /**
945  *      pm2fb_blank - Blanks the display.
946  *      @blank_mode: the blank mode we want. 
947  *      @info: frame buffer structure that represents a single frame buffer
948  *
949  *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
950  *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a 
951  *      video mode which doesn't support it. Implements VESA suspend
952  *      and powerdown modes on hardware that supports disabling hsync/vsync:
953  *      blank_mode == 2: suspend vsync
954  *      blank_mode == 3: suspend hsync
955  *      blank_mode == 4: powerdown
956  *
957  *      Returns negative errno on error, or zero on success.
958  *
959  */
960 static int pm2fb_blank(int blank_mode, struct fb_info *info)
961 {
962         struct pm2fb_par *par = (struct pm2fb_par *) info->par;
963         u32 video = par->video;
964
965         switch (blank_mode) {
966         case 0:         /* Screen: On; HSync: On, VSync: On */
967                 break;
968         case 1:         /* Screen: Off; HSync: On, VSync: On */
969                 video &= ~PM2F_VIDEO_ENABLE;
970                 break;
971         case 2: /* Screen: Off; HSync: On, VSync: Off */
972                 video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_BLANK_LOW );
973                 break;
974         case 3: /* Screen: Off; HSync: Off, VSync: On */
975                 video &= ~(PM2F_VIDEO_ENABLE | PM2F_HSYNC_MASK | PM2F_BLANK_LOW );
976                 break;
977         case 4: /* Screen: Off; HSync: Off, VSync: Off */
978                 video &= ~(PM2F_VIDEO_ENABLE | PM2F_VSYNC_MASK | PM2F_HSYNC_MASK|
979                            PM2F_BLANK_LOW);
980                 break;
981         }
982         set_video(par, video);
983         return 0;
984 }
985
986 /* ------------ Hardware Independent Functions ------------ */
987
988 /*
989  *  Frame buffer operations
990  */
991
992 static struct fb_ops pm2fb_ops = {
993         .owner          = THIS_MODULE,
994         .fb_check_var   = pm2fb_check_var,
995         .fb_set_par     = pm2fb_set_par,
996         .fb_setcolreg   = pm2fb_setcolreg,
997         .fb_blank       = pm2fb_blank,
998         .fb_pan_display = pm2fb_pan_display,
999         .fb_fillrect    = cfb_fillrect,
1000         .fb_copyarea    = cfb_copyarea,
1001         .fb_imageblit   = cfb_imageblit,
1002         .fb_cursor      = soft_cursor,
1003 };
1004
1005 /*
1006  * PCI stuff
1007  */
1008
1009
1010 /**
1011  * Device initialisation
1012  *
1013  * Initialise and allocate resource for PCI device.
1014  *
1015  * @param       pdev    PCI device.
1016  * @param       id      PCI device ID.
1017  */
1018 static int __devinit pm2fb_probe(struct pci_dev *pdev,
1019                                  const struct pci_device_id *id)
1020 {
1021         struct pm2fb_par *default_par;
1022         struct fb_info *info;
1023         int size, err;
1024         u32 pci_mem_config;
1025         int err_retval = -ENXIO;
1026
1027         err = pci_enable_device(pdev);
1028         if ( err ) {
1029                 printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
1030                 return err;
1031         }
1032
1033         size = sizeof(struct fb_info) + sizeof(struct pm2fb_par) + 256 * sizeof(u32);
1034
1035         info = framebuffer_alloc(size, &pdev->dev);
1036         if ( !info )
1037                 return -ENOMEM;
1038         memset(info, 0, size);
1039     
1040         default_par = info->par;
1041  
1042         switch (pdev->device) {
1043         case  PCI_DEVICE_ID_TI_TVP4020:
1044                 strcpy(pm2fb_fix.id, "TVP4020");
1045                 default_par->type = PM2_TYPE_PERMEDIA2;
1046                 break;
1047         case  PCI_DEVICE_ID_3DLABS_PERMEDIA2:
1048                 strcpy(pm2fb_fix.id, "Permedia2");
1049                 default_par->type = PM2_TYPE_PERMEDIA2;
1050                 break;
1051         case  PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
1052                 strcpy(pm2fb_fix.id, "Permedia2v");
1053                 default_par->type = PM2_TYPE_PERMEDIA2V;
1054                 break;
1055         }
1056
1057         pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
1058         pm2fb_fix.mmio_len = PM2_REGS_SIZE;
1059
1060 #ifdef PM2FB_BE_APERTURE
1061         pm2fb_fix.mmio_start += PM2_REGS_SIZE;
1062 #endif
1063     
1064         /* Registers - request region and map it. */
1065         if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
1066                                  "pm2fb regbase") ) {
1067                 printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
1068                 goto err_exit_neither;
1069         }
1070         default_par->v_regs =
1071                 ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1072         if ( !default_par->v_regs ) {
1073                 printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
1074                        pm2fb_fix.id);
1075                 release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1076                 goto err_exit_neither;
1077         }
1078
1079         /* Now work out how big lfb is going to be. */
1080         pci_mem_config = RD32(default_par->v_regs, PM2R_MEM_CONFIG);
1081         switch(pci_mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1082         case PM2F_MEM_BANKS_1:
1083                 default_par->fb_size=0x200000;
1084                 break;
1085         case PM2F_MEM_BANKS_2:
1086                 default_par->fb_size=0x400000;
1087                 break;
1088         case PM2F_MEM_BANKS_3:
1089                 default_par->fb_size=0x600000;
1090                 break;
1091         case PM2F_MEM_BANKS_4:
1092                 default_par->fb_size=0x800000;
1093                 break;
1094         }
1095         default_par->memclock = CVPPC_MEMCLOCK;
1096         pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
1097         pm2fb_fix.smem_len = default_par->fb_size;
1098
1099         /* Linear frame buffer - request region and map it. */
1100         if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
1101                                  "pm2fb smem") ) {
1102                 printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
1103                 goto err_exit_mmio;
1104         }
1105         info->screen_base = default_par->v_fb =
1106                 ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1107         if ( !default_par->v_fb ) {
1108                 printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
1109                 release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1110                 goto err_exit_mmio;
1111         }
1112
1113         info->fbops             = &pm2fb_ops;
1114         info->fix               = pm2fb_fix;    
1115         info->par               = default_par;
1116         info->pseudo_palette    = (void *)(default_par + 1); 
1117         info->flags             = FBINFO_FLAG_DEFAULT;
1118
1119 #ifndef MODULE
1120         if (!mode)
1121                 mode = "640x480@60";
1122          
1123         err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8); 
1124         if (!err || err == 4)
1125 #endif
1126                 info->var = pm2fb_var;
1127
1128         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
1129                 goto err_exit_all;
1130
1131         if (register_framebuffer(info) < 0)
1132                 goto err_exit_both;
1133
1134         printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
1135                info->node, info->fix.id, default_par->fb_size / 1024);
1136
1137         /*
1138          * Our driver data
1139          */
1140         pci_set_drvdata(pdev, info);
1141
1142         return 0;
1143
1144  err_exit_all:
1145         fb_dealloc_cmap(&info->cmap);   
1146  err_exit_both:    
1147         iounmap((void*) pm2fb_fix.smem_start);
1148         release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1149  err_exit_mmio:
1150         iounmap((void*) pm2fb_fix.mmio_start);
1151         release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1152  err_exit_neither:
1153         framebuffer_release(info);
1154         return err_retval;
1155 }
1156
1157 /**
1158  * Device removal.
1159  *
1160  * Release all device resources.
1161  *
1162  * @param       pdev    PCI device to clean up.
1163  */
1164 static void __devexit pm2fb_remove(struct pci_dev *pdev)
1165 {
1166         struct fb_info* info = pci_get_drvdata(pdev);
1167         struct fb_fix_screeninfo* fix = &info->fix;
1168     
1169         unregister_framebuffer(info);
1170     
1171         iounmap((void*) fix->smem_start);
1172         release_mem_region(fix->smem_start, fix->smem_len);
1173         iounmap((void*) fix->mmio_start);
1174         release_mem_region(fix->mmio_start, fix->mmio_len);
1175
1176         pci_set_drvdata(pdev, NULL);
1177         kfree(info);
1178 }
1179
1180 static struct pci_device_id pm2fb_id_table[] = {
1181         { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
1182           PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1183           0xff0000, 0 },
1184         { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
1185           PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1186           0xff0000, 0 },
1187         { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
1188           PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1189           0xff0000, 0 },
1190         { 0, }
1191 };
1192
1193 static struct pci_driver pm2fb_driver = {
1194         .name           = "pm2fb",
1195         .id_table       = pm2fb_id_table,
1196         .probe          = pm2fb_probe,
1197         .remove         = __devexit_p(pm2fb_remove),
1198 };
1199
1200 MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
1201
1202
1203 /*
1204  *  Initialization
1205  */
1206
1207 int __init pm2fb_init(void)
1208 {
1209         return pci_module_init(&pm2fb_driver);
1210 }
1211
1212 /*
1213  *  Cleanup
1214  */
1215
1216 static void __exit pm2fb_exit(void)
1217 {
1218         pci_unregister_driver(&pm2fb_driver);
1219 }
1220
1221 /*
1222  *  Setup
1223  */
1224
1225 /**
1226  * Parse user speficied options.
1227  *
1228  * This is, comma-separated options following `video=pm2fb:'.
1229  */
1230 int __init pm2fb_setup(char *options)
1231 {
1232         char* this_opt;
1233
1234         if (!options || !*options)
1235                 return 0;
1236
1237         while ((this_opt = strsep(&options, ",")) != NULL) {    
1238                 if (!*this_opt)
1239                         continue;
1240                 if(!strcmp(this_opt, "lowhsync")) {
1241                         lowhsync = 1;
1242                 } else if(!strcmp(this_opt, "lowvsync")) {
1243                         lowvsync = 1;
1244                 } else {
1245                         mode = this_opt;
1246                 }
1247         }
1248         return 0;
1249 }
1250
1251
1252 /* ------------------------------------------------------------------------- */
1253
1254 /* ------------------------------------------------------------------------- */
1255
1256
1257
1258 #ifdef MODULE
1259 module_init(pm2fb_init);
1260 #endif 
1261 module_exit(pm2fb_exit);
1262
1263 MODULE_PARM(mode,"s");
1264 MODULE_PARM(lowhsync,"i");
1265 MODULE_PARM(lowvsync,"i");
1266
1267 MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
1268 MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
1269 MODULE_LICENSE("GPL");