Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / drivers / video / pm3fb.c
1 /*
2  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
3  *
4  *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
5  *
6  *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
7  *      based on pm2fb.c
8  *
9  *  Based on code written by:
10  *         Sven Luther, <luther@dpt-info.u-strasbg.fr>
11  *         Alan Hourihane, <alanh@fairlite.demon.co.uk>
12  *         Russell King, <rmk@arm.linux.org.uk>
13  *  Based on linux/drivers/video/skeletonfb.c:
14  *      Copyright (C) 1997 Geert Uytterhoeven
15  *  Based on linux/driver/video/pm2fb.c:
16  *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
17  *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
18  *
19  *  This file is subject to the terms and conditions of the GNU General Public
20  *  License. See the file COPYING in the main directory of this archive for
21  *  more details.
22  *
23  */
24
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <linux/mm.h>
30 #include <linux/slab.h>
31 #include <linux/delay.h>
32 #include <linux/fb.h>
33 #include <linux/init.h>
34 #include <linux/pci.h>
35 #ifdef CONFIG_MTRR
36 #include <asm/mtrr.h>
37 #endif
38
39 #include <video/pm3fb.h>
40
41 #if !defined(CONFIG_PCI)
42 #error "Only generic PCI cards supported."
43 #endif
44
45 #undef PM3FB_MASTER_DEBUG
46 #ifdef PM3FB_MASTER_DEBUG
47 #define DPRINTK(a, b...)        \
48         printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
49 #else
50 #define DPRINTK(a, b...)
51 #endif
52
53 #define PM3_PIXMAP_SIZE (2048 * 4)
54
55 /*
56  * Driver data
57  */
58 static int hwcursor = 1;
59 static char *mode_option __devinitdata;
60 static int noaccel __devinitdata;
61
62 /* mtrr option */
63 #ifdef CONFIG_MTRR
64 static int nomtrr __devinitdata;
65 #endif
66
67 /*
68  * This structure defines the hardware state of the graphics card. Normally
69  * you place this in a header file in linux/include/video. This file usually
70  * also includes register information. That allows other driver subsystems
71  * and userland applications the ability to use the same header file to
72  * avoid duplicate work and easy porting of software.
73  */
74 struct pm3_par {
75         unsigned char   __iomem *v_regs;/* virtual address of p_regs */
76         u32             video;          /* video flags before blanking */
77         u32             base;           /* screen base in 128 bits unit */
78         u32             palette[16];
79         int             mtrr_handle;
80 };
81
82 /*
83  * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
84  * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
85  * to get a fb_var_screeninfo. Otherwise define a default var as well.
86  */
87 static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
88         .id =           "Permedia3",
89         .type =         FB_TYPE_PACKED_PIXELS,
90         .visual =       FB_VISUAL_PSEUDOCOLOR,
91         .xpanstep =     1,
92         .ypanstep =     1,
93         .ywrapstep =    0,
94         .accel =        FB_ACCEL_3DLABS_PERMEDIA3,
95 };
96
97 /*
98  * Utility functions
99  */
100
101 static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
102 {
103         return fb_readl(par->v_regs + off);
104 }
105
106 static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
107 {
108         fb_writel(v, par->v_regs + off);
109 }
110
111 static inline void PM3_WAIT(struct pm3_par *par, u32 n)
112 {
113         while (PM3_READ_REG(par, PM3InFIFOSpace) < n)
114                 cpu_relax();
115 }
116
117 static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
118 {
119         PM3_WAIT(par, 3);
120         PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff);
121         PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff);
122         wmb();
123         PM3_WRITE_REG(par, PM3RD_IndexedData, v);
124         wmb();
125 }
126
127 static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
128                         unsigned char r, unsigned char g, unsigned char b)
129 {
130         PM3_WAIT(par, 4);
131         PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
132         wmb();
133         PM3_WRITE_REG(par, PM3RD_PaletteData, r);
134         wmb();
135         PM3_WRITE_REG(par, PM3RD_PaletteData, g);
136         wmb();
137         PM3_WRITE_REG(par, PM3RD_PaletteData, b);
138         wmb();
139 }
140
141 static void pm3fb_clear_colormap(struct pm3_par *par,
142                         unsigned char r, unsigned char g, unsigned char b)
143 {
144         int i;
145
146         for (i = 0; i < 256 ; i++)
147                 pm3fb_set_color(par, i, r, g, b);
148
149 }
150
151 /* Calculating various clock parameters */
152 static void pm3fb_calculate_clock(unsigned long reqclock,
153                                 unsigned char *prescale,
154                                 unsigned char *feedback,
155                                 unsigned char *postscale)
156 {
157         int f, pre, post;
158         unsigned long freq;
159         long freqerr = 1000;
160         long currerr;
161
162         for (f = 1; f < 256; f++) {
163                 for (pre = 1; pre < 256; pre++) {
164                         for (post = 0; post < 5; post++) {
165                                 freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
166                                 currerr = (reqclock > freq)
167                                         ? reqclock - freq
168                                         : freq - reqclock;
169                                 if (currerr < freqerr) {
170                                         freqerr = currerr;
171                                         *feedback = f;
172                                         *prescale = pre;
173                                         *postscale = post;
174                                 }
175                         }
176                 }
177         }
178 }
179
180 static inline int pm3fb_depth(const struct fb_var_screeninfo *var)
181 {
182         if (var->bits_per_pixel == 16)
183                 return var->red.length + var->green.length
184                         + var->blue.length;
185
186         return var->bits_per_pixel;
187 }
188
189 static inline int pm3fb_shift_bpp(unsigned bpp, int v)
190 {
191         switch (bpp) {
192         case 8:
193                 return (v >> 4);
194         case 16:
195                 return (v >> 3);
196         case 32:
197                 return (v >> 2);
198         }
199         DPRINTK("Unsupported depth %u\n", bpp);
200         return 0;
201 }
202
203 /* acceleration */
204 static int pm3fb_sync(struct fb_info *info)
205 {
206         struct pm3_par *par = info->par;
207
208         PM3_WAIT(par, 2);
209         PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
210         PM3_WRITE_REG(par, PM3Sync, 0);
211         mb();
212         do {
213                 while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0)
214                         cpu_relax();
215         } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
216
217         return 0;
218 }
219
220 static void pm3fb_init_engine(struct fb_info *info)
221 {
222         struct pm3_par *par = info->par;
223         const u32 width = (info->var.xres_virtual + 7) & ~7;
224
225         PM3_WAIT(par, 50);
226         PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
227         PM3_WRITE_REG(par, PM3StatisticMode, 0x0);
228         PM3_WRITE_REG(par, PM3DeltaMode, 0x0);
229         PM3_WRITE_REG(par, PM3RasterizerMode, 0x0);
230         PM3_WRITE_REG(par, PM3ScissorMode, 0x0);
231         PM3_WRITE_REG(par, PM3LineStippleMode, 0x0);
232         PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0);
233         PM3_WRITE_REG(par, PM3GIDMode, 0x0);
234         PM3_WRITE_REG(par, PM3DepthMode, 0x0);
235         PM3_WRITE_REG(par, PM3StencilMode, 0x0);
236         PM3_WRITE_REG(par, PM3StencilData, 0x0);
237         PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0);
238         PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0);
239         PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0);
240         PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0);
241         PM3_WRITE_REG(par, PM3TextureReadMode, 0x0);
242         PM3_WRITE_REG(par, PM3LUTMode, 0x0);
243         PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0);
244         PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0);
245         PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0);
246         PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0);
247         PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0);
248         PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0);
249         PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0);
250         PM3_WRITE_REG(par, PM3FogMode, 0x0);
251         PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0);
252         PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0);
253         PM3_WRITE_REG(par, PM3AntialiasMode, 0x0);
254         PM3_WRITE_REG(par, PM3YUVMode, 0x0);
255         PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0);
256         PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0);
257         PM3_WRITE_REG(par, PM3DitherMode, 0x0);
258         PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0);
259         PM3_WRITE_REG(par, PM3RouterMode, 0x0);
260         PM3_WRITE_REG(par, PM3Window, 0x0);
261
262         PM3_WRITE_REG(par, PM3Config2D, 0x0);
263
264         PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff);
265
266         PM3_WRITE_REG(par, PM3XBias, 0x0);
267         PM3_WRITE_REG(par, PM3YBias, 0x0);
268         PM3_WRITE_REG(par, PM3DeltaControl, 0x0);
269
270         PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff);
271
272         PM3_WRITE_REG(par, PM3FBDestReadEnables,
273                            PM3FBDestReadEnables_E(0xff) |
274                            PM3FBDestReadEnables_R(0xff) |
275                            PM3FBDestReadEnables_ReferenceAlpha(0xff));
276         PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0);
277         PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0);
278         PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0,
279                            PM3FBDestReadBufferWidth_Width(width));
280
281         PM3_WRITE_REG(par, PM3FBDestReadMode,
282                            PM3FBDestReadMode_ReadEnable |
283                            PM3FBDestReadMode_Enable0);
284         PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0);
285         PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0);
286         PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth,
287                            PM3FBSourceReadBufferWidth_Width(width));
288         PM3_WRITE_REG(par, PM3FBSourceReadMode,
289                            PM3FBSourceReadMode_Blocking |
290                            PM3FBSourceReadMode_ReadEnable);
291
292         PM3_WAIT(par, 2);
293         {
294                 /* invert bits in bitmask */
295                 unsigned long rm = 1 | (3 << 7);
296                 switch (info->var.bits_per_pixel) {
297                 case 8:
298                         PM3_WRITE_REG(par, PM3PixelSize,
299                                            PM3PixelSize_GLOBAL_8BIT);
300 #ifdef __BIG_ENDIAN
301                         rm |= 3 << 15;
302 #endif
303                         break;
304                 case 16:
305                         PM3_WRITE_REG(par, PM3PixelSize,
306                                            PM3PixelSize_GLOBAL_16BIT);
307 #ifdef __BIG_ENDIAN
308                         rm |= 2 << 15;
309 #endif
310                         break;
311                 case 32:
312                         PM3_WRITE_REG(par, PM3PixelSize,
313                                            PM3PixelSize_GLOBAL_32BIT);
314                         break;
315                 default:
316                         DPRINTK(1, "Unsupported depth %d\n",
317                                 info->var.bits_per_pixel);
318                         break;
319                 }
320                 PM3_WRITE_REG(par, PM3RasterizerMode, rm);
321         }
322
323         PM3_WAIT(par, 20);
324         PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff);
325         PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff);
326         PM3_WRITE_REG(par, PM3FBWriteMode,
327                            PM3FBWriteMode_WriteEnable |
328                            PM3FBWriteMode_OpaqueSpan |
329                            PM3FBWriteMode_Enable0);
330         PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0);
331         PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0);
332         PM3_WRITE_REG(par, PM3FBWriteBufferWidth0,
333                            PM3FBWriteBufferWidth_Width(width));
334
335         PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0);
336         {
337                 /* size in lines of FB */
338                 unsigned long sofb = info->screen_size /
339                         info->fix.line_length;
340                 if (sofb > 4095)
341                         PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095);
342                 else
343                         PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb);
344
345                 switch (info->var.bits_per_pixel) {
346                 case 8:
347                         PM3_WRITE_REG(par, PM3DitherMode,
348                                            (1 << 10) | (2 << 3));
349                         break;
350                 case 16:
351                         PM3_WRITE_REG(par, PM3DitherMode,
352                                            (1 << 10) | (1 << 3));
353                         break;
354                 case 32:
355                         PM3_WRITE_REG(par, PM3DitherMode,
356                                            (1 << 10) | (0 << 3));
357                         break;
358                 default:
359                         DPRINTK(1, "Unsupported depth %d\n",
360                                 info->current_par->depth);
361                         break;
362                 }
363         }
364
365         PM3_WRITE_REG(par, PM3dXDom, 0x0);
366         PM3_WRITE_REG(par, PM3dXSub, 0x0);
367         PM3_WRITE_REG(par, PM3dY, 1 << 16);
368         PM3_WRITE_REG(par, PM3StartXDom, 0x0);
369         PM3_WRITE_REG(par, PM3StartXSub, 0x0);
370         PM3_WRITE_REG(par, PM3StartY, 0x0);
371         PM3_WRITE_REG(par, PM3Count, 0x0);
372
373 /* Disable LocalBuffer. better safe than sorry */
374         PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0);
375         PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0);
376         PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0);
377         PM3_WRITE_REG(par, PM3LBWriteMode, 0x0);
378
379         pm3fb_sync(info);
380 }
381
382 static void pm3fb_fillrect(struct fb_info *info,
383                                 const struct fb_fillrect *region)
384 {
385         struct pm3_par *par = info->par;
386         struct fb_fillrect modded;
387         int vxres, vyres;
388         int rop;
389         u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
390                 ((u32 *)info->pseudo_palette)[region->color] : region->color;
391
392         if (info->state != FBINFO_STATE_RUNNING)
393                 return;
394         if (info->flags & FBINFO_HWACCEL_DISABLED) {
395                 cfb_fillrect(info, region);
396                 return;
397         }
398         if (region->rop == ROP_COPY )
399                 rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */
400         else
401                 rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */
402                         PM3Config2D_FBDestReadEnable;
403
404         vxres = info->var.xres_virtual;
405         vyres = info->var.yres_virtual;
406
407         memcpy(&modded, region, sizeof(struct fb_fillrect));
408
409         if (!modded.width || !modded.height ||
410             modded.dx >= vxres || modded.dy >= vyres)
411                 return;
412
413         if (modded.dx + modded.width  > vxres)
414                 modded.width  = vxres - modded.dx;
415         if (modded.dy + modded.height > vyres)
416                 modded.height = vyres - modded.dy;
417
418         if (info->var.bits_per_pixel == 8)
419                 color |= color << 8;
420         if (info->var.bits_per_pixel <= 16)
421                 color |= color << 16;
422
423         PM3_WAIT(par, 4);
424         /* ROP Ox3 is GXcopy */
425         PM3_WRITE_REG(par, PM3Config2D,
426                         PM3Config2D_UseConstantSource |
427                         PM3Config2D_ForegroundROPEnable |
428                         rop |
429                         PM3Config2D_FBWriteEnable);
430
431         PM3_WRITE_REG(par, PM3ForegroundColor, color);
432
433         PM3_WRITE_REG(par, PM3RectanglePosition,
434                         PM3RectanglePosition_XOffset(modded.dx) |
435                         PM3RectanglePosition_YOffset(modded.dy));
436
437         PM3_WRITE_REG(par, PM3Render2D,
438                       PM3Render2D_XPositive |
439                       PM3Render2D_YPositive |
440                       PM3Render2D_Operation_Normal |
441                       PM3Render2D_SpanOperation |
442                       PM3Render2D_Width(modded.width) |
443                       PM3Render2D_Height(modded.height));
444 }
445
446 static void pm3fb_copyarea(struct fb_info *info,
447                                 const struct fb_copyarea *area)
448 {
449         struct pm3_par *par = info->par;
450         struct fb_copyarea modded;
451         u32 vxres, vyres;
452         int x_align, o_x, o_y;
453
454         if (info->state != FBINFO_STATE_RUNNING)
455                 return;
456         if (info->flags & FBINFO_HWACCEL_DISABLED) {
457                 cfb_copyarea(info, area);
458                 return;
459         }
460
461         memcpy(&modded, area, sizeof(struct fb_copyarea));
462
463         vxres = info->var.xres_virtual;
464         vyres = info->var.yres_virtual;
465
466         if (!modded.width || !modded.height ||
467             modded.sx >= vxres || modded.sy >= vyres ||
468             modded.dx >= vxres || modded.dy >= vyres)
469                 return;
470
471         if (modded.sx + modded.width > vxres)
472                 modded.width = vxres - modded.sx;
473         if (modded.dx + modded.width > vxres)
474                 modded.width = vxres - modded.dx;
475         if (modded.sy + modded.height > vyres)
476                 modded.height = vyres - modded.sy;
477         if (modded.dy + modded.height > vyres)
478                 modded.height = vyres - modded.dy;
479
480         o_x = modded.sx - modded.dx;    /*(sx > dx ) ? (sx - dx) : (dx - sx); */
481         o_y = modded.sy - modded.dy;    /*(sy > dy ) ? (sy - dy) : (dy - sy); */
482
483         x_align = (modded.sx & 0x1f);
484
485         PM3_WAIT(par, 6);
486
487         PM3_WRITE_REG(par, PM3Config2D,
488                         PM3Config2D_UserScissorEnable |
489                         PM3Config2D_ForegroundROPEnable |
490                         PM3Config2D_Blocking |
491                         PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */
492                         PM3Config2D_FBWriteEnable);
493
494         PM3_WRITE_REG(par, PM3ScissorMinXY,
495                         ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
496         PM3_WRITE_REG(par, PM3ScissorMaxXY,
497                         (((modded.dy + modded.height) & 0x0fff) << 16) |
498                         ((modded.dx + modded.width) & 0x0fff));
499
500         PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset,
501                         PM3FBSourceReadBufferOffset_XOffset(o_x) |
502                         PM3FBSourceReadBufferOffset_YOffset(o_y));
503
504         PM3_WRITE_REG(par, PM3RectanglePosition,
505                         PM3RectanglePosition_XOffset(modded.dx - x_align) |
506                         PM3RectanglePosition_YOffset(modded.dy));
507
508         PM3_WRITE_REG(par, PM3Render2D,
509                         ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) |
510                         ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) |
511                         PM3Render2D_Operation_Normal |
512                         PM3Render2D_SpanOperation |
513                         PM3Render2D_FBSourceReadEnable |
514                         PM3Render2D_Width(modded.width + x_align) |
515                         PM3Render2D_Height(modded.height));
516 }
517
518 static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image)
519 {
520         struct pm3_par *par = info->par;
521         u32 height = image->height;
522         u32 fgx, bgx;
523         const u32 *src = (const u32 *)image->data;
524
525         if (info->state != FBINFO_STATE_RUNNING)
526                 return;
527         if (info->flags & FBINFO_HWACCEL_DISABLED) {
528                 cfb_imageblit(info, image);
529                 return;
530         }
531         switch (info->fix.visual) {
532         case FB_VISUAL_PSEUDOCOLOR:
533                 fgx = image->fg_color;
534                 bgx = image->bg_color;
535                 break;
536         case FB_VISUAL_TRUECOLOR:
537         default:
538                 fgx = par->palette[image->fg_color];
539                 bgx = par->palette[image->bg_color];
540                 break;
541         }
542         if (image->depth != 1) {
543                 cfb_imageblit(info, image);
544                 return;
545         }
546
547         if (info->var.bits_per_pixel == 8) {
548                 fgx |= fgx << 8;
549                 bgx |= bgx << 8;
550         }
551         if (info->var.bits_per_pixel <= 16) {
552                 fgx |= fgx << 16;
553                 bgx |= bgx << 16;
554         }
555
556         PM3_WAIT(par, 7);
557
558         PM3_WRITE_REG(par, PM3ForegroundColor, fgx);
559         PM3_WRITE_REG(par, PM3BackgroundColor, bgx);
560
561         /* ROP Ox3 is GXcopy */
562         PM3_WRITE_REG(par, PM3Config2D,
563                         PM3Config2D_UserScissorEnable |
564                         PM3Config2D_UseConstantSource |
565                         PM3Config2D_ForegroundROPEnable |
566                         PM3Config2D_ForegroundROP(0x3) |
567                         PM3Config2D_OpaqueSpan |
568                         PM3Config2D_FBWriteEnable);
569         PM3_WRITE_REG(par, PM3ScissorMinXY,
570                         ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff));
571         PM3_WRITE_REG(par, PM3ScissorMaxXY,
572                         (((image->dy + image->height) & 0x0fff) << 16) |
573                         ((image->dx + image->width) & 0x0fff));
574         PM3_WRITE_REG(par, PM3RectanglePosition,
575                         PM3RectanglePosition_XOffset(image->dx) |
576                         PM3RectanglePosition_YOffset(image->dy));
577         PM3_WRITE_REG(par, PM3Render2D,
578                         PM3Render2D_XPositive |
579                         PM3Render2D_YPositive |
580                         PM3Render2D_Operation_SyncOnBitMask |
581                         PM3Render2D_SpanOperation |
582                         PM3Render2D_Width(image->width) |
583                         PM3Render2D_Height(image->height));
584
585
586         while (height--) {
587                 int width = ((image->width + 7) >> 3)
588                                 + info->pixmap.scan_align - 1;
589                 width >>= 2;
590
591                 while (width >= PM3_FIFO_SIZE) {
592                         int i = PM3_FIFO_SIZE - 1;
593
594                         PM3_WAIT(par, PM3_FIFO_SIZE);
595                         while (i--) {
596                                 PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
597                                 src++;
598                         }
599                         width -= PM3_FIFO_SIZE - 1;
600                 }
601
602                 PM3_WAIT(par, width + 1);
603                 while (width--) {
604                         PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
605                         src++;
606                 }
607         }
608 }
609 /* end of acceleration functions */
610
611 /*
612  *      Hardware Cursor support.
613  */
614 static const u8 cursor_bits_lookup[16] = {
615         0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
616         0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
617 };
618
619 static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
620 {
621         struct pm3_par *par = info->par;
622         u8 mode;
623
624         if (!hwcursor)
625                 return -EINVAL; /* just to force soft_cursor() call */
626
627         /* Too large of a cursor or wrong bpp :-( */
628         if (cursor->image.width > 64 ||
629             cursor->image.height > 64 ||
630             cursor->image.depth > 1)
631                 return -EINVAL;
632
633         mode = PM3RD_CursorMode_TYPE_X;
634         if (cursor->enable)
635                  mode |= PM3RD_CursorMode_CURSOR_ENABLE;
636
637         PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode);
638
639         /*
640          * If the cursor is not be changed this means either we want the
641          * current cursor state (if enable is set) or we want to query what
642          * we can do with the cursor (if enable is not set)
643          */
644         if (!cursor->set)
645                 return 0;
646
647         if (cursor->set & FB_CUR_SETPOS) {
648                 int x = cursor->image.dx - info->var.xoffset;
649                 int y = cursor->image.dy - info->var.yoffset;
650
651                 PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff);
652                 PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf);
653                 PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff);
654                 PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf);
655         }
656
657         if (cursor->set & FB_CUR_SETHOT) {
658                 PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX,
659                                   cursor->hot.x & 0x3f);
660                 PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY,
661                                   cursor->hot.y & 0x3f);
662         }
663
664         if (cursor->set & FB_CUR_SETCMAP) {
665                 u32 fg_idx = cursor->image.fg_color;
666                 u32 bg_idx = cursor->image.bg_color;
667                 struct fb_cmap cmap = info->cmap;
668
669                 /* the X11 driver says one should use these color registers */
670                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
671                                   cmap.red[fg_idx] >> 8 );
672                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
673                                   cmap.green[fg_idx] >> 8 );
674                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
675                                   cmap.blue[fg_idx] >> 8 );
676
677                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42),
678                                   cmap.red[bg_idx] >> 8 );
679                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43),
680                                   cmap.green[bg_idx] >> 8 );
681                 PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44),
682                                   cmap.blue[bg_idx] >> 8 );
683         }
684
685         if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
686                 u8 *bitmap = (u8 *)cursor->image.data;
687                 u8 *mask = (u8 *)cursor->mask;
688                 int i;
689                 int pos = PM3RD_CursorPattern(0);
690
691                 for (i = 0; i < cursor->image.height; i++) {
692                         int j = (cursor->image.width + 7) >> 3;
693                         int k = 8 - j;
694
695                         for (; j > 0; j--) {
696                                 u8 data = *bitmap ^ *mask;
697
698                                 if (cursor->rop == ROP_COPY)
699                                         data = *mask & *bitmap;
700                                 /* Upper 4 bits of bitmap data */
701                                 PM3_WRITE_DAC_REG(par, pos++,
702                                         cursor_bits_lookup[data >> 4] |
703                                         (cursor_bits_lookup[*mask >> 4] << 1));
704                                 /* Lower 4 bits of bitmap */
705                                 PM3_WRITE_DAC_REG(par, pos++,
706                                         cursor_bits_lookup[data & 0xf] |
707                                         (cursor_bits_lookup[*mask & 0xf] << 1));
708                                 bitmap++;
709                                 mask++;
710                         }
711                         for (; k > 0; k--) {
712                                 PM3_WRITE_DAC_REG(par, pos++, 0);
713                                 PM3_WRITE_DAC_REG(par, pos++, 0);
714                         }
715                 }
716                 while (pos < PM3RD_CursorPattern(1024))
717                         PM3_WRITE_DAC_REG(par, pos++, 0);
718         }
719         return 0;
720 }
721
722 /* write the mode to registers */
723 static void pm3fb_write_mode(struct fb_info *info)
724 {
725         struct pm3_par *par = info->par;
726         char tempsync = 0x00;
727         char tempmisc = 0x00;
728         const u32 hsstart = info->var.right_margin;
729         const u32 hsend = hsstart + info->var.hsync_len;
730         const u32 hbend = hsend + info->var.left_margin;
731         const u32 xres = (info->var.xres + 31) & ~31;
732         const u32 htotal = xres + hbend;
733         const u32 vsstart = info->var.lower_margin;
734         const u32 vsend = vsstart + info->var.vsync_len;
735         const u32 vbend = vsend + info->var.upper_margin;
736         const u32 vtotal = info->var.yres + vbend;
737         const u32 width = (info->var.xres_virtual + 7) & ~7;
738         const unsigned bpp = info->var.bits_per_pixel;
739
740         PM3_WAIT(par, 20);
741         PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
742         PM3_WRITE_REG(par, PM3Aperture0, 0x00000000);
743         PM3_WRITE_REG(par, PM3Aperture1, 0x00000000);
744         PM3_WRITE_REG(par, PM3FIFODis, 0x00000007);
745
746         PM3_WRITE_REG(par, PM3HTotal,
747                            pm3fb_shift_bpp(bpp, htotal - 1));
748         PM3_WRITE_REG(par, PM3HsEnd,
749                            pm3fb_shift_bpp(bpp, hsend));
750         PM3_WRITE_REG(par, PM3HsStart,
751                            pm3fb_shift_bpp(bpp, hsstart));
752         PM3_WRITE_REG(par, PM3HbEnd,
753                            pm3fb_shift_bpp(bpp, hbend));
754         PM3_WRITE_REG(par, PM3HgEnd,
755                            pm3fb_shift_bpp(bpp, hbend));
756         PM3_WRITE_REG(par, PM3ScreenStride,
757                            pm3fb_shift_bpp(bpp, width));
758         PM3_WRITE_REG(par, PM3VTotal, vtotal - 1);
759         PM3_WRITE_REG(par, PM3VsEnd, vsend - 1);
760         PM3_WRITE_REG(par, PM3VsStart, vsstart - 1);
761         PM3_WRITE_REG(par, PM3VbEnd, vbend);
762
763         switch (bpp) {
764         case 8:
765                 PM3_WRITE_REG(par, PM3ByAperture1Mode,
766                                    PM3ByApertureMode_PIXELSIZE_8BIT);
767                 PM3_WRITE_REG(par, PM3ByAperture2Mode,
768                                    PM3ByApertureMode_PIXELSIZE_8BIT);
769                 break;
770
771         case 16:
772 #ifndef __BIG_ENDIAN
773                 PM3_WRITE_REG(par, PM3ByAperture1Mode,
774                                    PM3ByApertureMode_PIXELSIZE_16BIT);
775                 PM3_WRITE_REG(par, PM3ByAperture2Mode,
776                                    PM3ByApertureMode_PIXELSIZE_16BIT);
777 #else
778                 PM3_WRITE_REG(par, PM3ByAperture1Mode,
779                                    PM3ByApertureMode_PIXELSIZE_16BIT |
780                                    PM3ByApertureMode_BYTESWAP_BADC);
781                 PM3_WRITE_REG(par, PM3ByAperture2Mode,
782                                    PM3ByApertureMode_PIXELSIZE_16BIT |
783                                    PM3ByApertureMode_BYTESWAP_BADC);
784 #endif /* ! __BIG_ENDIAN */
785                 break;
786
787         case 32:
788 #ifndef __BIG_ENDIAN
789                 PM3_WRITE_REG(par, PM3ByAperture1Mode,
790                                    PM3ByApertureMode_PIXELSIZE_32BIT);
791                 PM3_WRITE_REG(par, PM3ByAperture2Mode,
792                                    PM3ByApertureMode_PIXELSIZE_32BIT);
793 #else
794                 PM3_WRITE_REG(par, PM3ByAperture1Mode,
795                                    PM3ByApertureMode_PIXELSIZE_32BIT |
796                                    PM3ByApertureMode_BYTESWAP_DCBA);
797                 PM3_WRITE_REG(par, PM3ByAperture2Mode,
798                                    PM3ByApertureMode_PIXELSIZE_32BIT |
799                                    PM3ByApertureMode_BYTESWAP_DCBA);
800 #endif /* ! __BIG_ENDIAN */
801                 break;
802
803         default:
804                 DPRINTK("Unsupported depth %d\n", bpp);
805                 break;
806         }
807
808         /*
809          * Oxygen VX1 - it appears that setting PM3VideoControl and
810          * then PM3RD_SyncControl to the same SYNC settings undoes
811          * any net change - they seem to xor together.  Only set the
812          * sync options in PM3RD_SyncControl.  --rmk
813          */
814         {
815                 unsigned int video = par->video;
816
817                 video &= ~(PM3VideoControl_HSYNC_MASK |
818                            PM3VideoControl_VSYNC_MASK);
819                 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
820                          PM3VideoControl_VSYNC_ACTIVE_HIGH;
821                 PM3_WRITE_REG(par, PM3VideoControl, video);
822         }
823         PM3_WRITE_REG(par, PM3VClkCtl,
824                            (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
825         PM3_WRITE_REG(par, PM3ScreenBase, par->base);
826         PM3_WRITE_REG(par, PM3ChipConfig,
827                            (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
828
829         wmb();
830         {
831                 unsigned char uninitialized_var(m);     /* ClkPreScale */
832                 unsigned char uninitialized_var(n);     /* ClkFeedBackScale */
833                 unsigned char uninitialized_var(p);     /* ClkPostScale */
834                 unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
835
836                 (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
837
838                 DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
839                         pixclock, (int) m, (int) n, (int) p);
840
841                 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
842                 PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
843                 PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
844         }
845         /*
846            PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
847          */
848         /*
849            PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
850          */
851         if ((par->video & PM3VideoControl_HSYNC_MASK) ==
852             PM3VideoControl_HSYNC_ACTIVE_HIGH)
853                 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
854         if ((par->video & PM3VideoControl_VSYNC_MASK) ==
855             PM3VideoControl_VSYNC_ACTIVE_HIGH)
856                 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
857
858         PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
859         DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
860
861         PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
862
863         switch (pm3fb_depth(&info->var)) {
864         case 8:
865                 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
866                                   PM3RD_PixelSize_8_BIT_PIXELS);
867                 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
868                                   PM3RD_ColorFormat_CI8_COLOR |
869                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
870                 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
871                 break;
872         case 12:
873                 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
874                                   PM3RD_PixelSize_16_BIT_PIXELS);
875                 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
876                                   PM3RD_ColorFormat_4444_COLOR |
877                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
878                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
879                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
880                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
881                 break;
882         case 15:
883                 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
884                                   PM3RD_PixelSize_16_BIT_PIXELS);
885                 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
886                                   PM3RD_ColorFormat_5551_FRONT_COLOR |
887                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
888                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
889                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
890                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
891                 break;
892         case 16:
893                 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
894                                   PM3RD_PixelSize_16_BIT_PIXELS);
895                 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
896                                   PM3RD_ColorFormat_565_FRONT_COLOR |
897                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
898                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
899                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
900                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
901                 break;
902         case 32:
903                 PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
904                                   PM3RD_PixelSize_32_BIT_PIXELS);
905                 PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
906                                   PM3RD_ColorFormat_8888_COLOR |
907                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
908                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
909                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
910                 break;
911         }
912         PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
913 }
914
915 /*
916  * hardware independent functions
917  */
918 static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
919 {
920         u32 lpitch;
921         unsigned bpp = var->red.length + var->green.length
922                         + var->blue.length + var->transp.length;
923
924         if (bpp != var->bits_per_pixel) {
925                 /* set predefined mode for bits_per_pixel settings */
926
927                 switch (var->bits_per_pixel) {
928                 case 8:
929                         var->red.length = 8;
930                         var->green.length = 8;
931                         var->blue.length = 8;
932                         var->red.offset = 0;
933                         var->green.offset = 0;
934                         var->blue.offset = 0;
935                         var->transp.offset = 0;
936                         var->transp.length = 0;
937                         break;
938                 case 16:
939                         var->red.length = 5;
940                         var->blue.length = 5;
941                         var->green.length = 6;
942                         var->transp.length = 0;
943                         break;
944                 case 32:
945                         var->red.length = 8;
946                         var->green.length = 8;
947                         var->blue.length = 8;
948                         var->transp.length = 8;
949                         break;
950                 default:
951                         DPRINTK("depth not supported: %u\n",
952                                 var->bits_per_pixel);
953                         return -EINVAL;
954                 }
955         }
956         /* it is assumed BGRA order */
957         if (var->bits_per_pixel > 8 ) {
958                 var->blue.offset = 0;
959                 var->green.offset = var->blue.length;
960                 var->red.offset = var->green.offset + var->green.length;
961                 var->transp.offset = var->red.offset + var->red.length;
962         }
963         var->height = -1;
964         var->width = -1;
965
966         if (var->xres != var->xres_virtual) {
967                 DPRINTK("virtual x resolution != "
968                         "physical x resolution not supported\n");
969                 return -EINVAL;
970         }
971
972         if (var->yres > var->yres_virtual) {
973                 DPRINTK("virtual y resolution < "
974                         "physical y resolution not possible\n");
975                 return -EINVAL;
976         }
977
978         if (var->xoffset) {
979                 DPRINTK("xoffset not supported\n");
980                 return -EINVAL;
981         }
982
983         if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
984                 DPRINTK("interlace not supported\n");
985                 return -EINVAL;
986         }
987
988         var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
989         lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
990
991         if (var->xres < 200 || var->xres > 2048) {
992                 DPRINTK("width not supported: %u\n", var->xres);
993                 return -EINVAL;
994         }
995
996         if (var->yres < 200 || var->yres > 4095) {
997                 DPRINTK("height not supported: %u\n", var->yres);
998                 return -EINVAL;
999         }
1000
1001         if (lpitch * var->yres_virtual > info->fix.smem_len) {
1002                 DPRINTK("no memory for screen (%ux%ux%u)\n",
1003                         var->xres, var->yres_virtual, var->bits_per_pixel);
1004                 return -EINVAL;
1005         }
1006
1007         if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
1008                 DPRINTK("pixclock too high (%ldKHz)\n",
1009                         PICOS2KHZ(var->pixclock));
1010                 return -EINVAL;
1011         }
1012
1013         var->accel_flags = 0;   /* Can't mmap if this is on */
1014
1015         DPRINTK("Checking graphics mode at %dx%d depth %d\n",
1016                 var->xres, var->yres, var->bits_per_pixel);
1017         return 0;
1018 }
1019
1020 static int pm3fb_set_par(struct fb_info *info)
1021 {
1022         struct pm3_par *par = info->par;
1023         const u32 xres = (info->var.xres + 31) & ~31;
1024         const unsigned bpp = info->var.bits_per_pixel;
1025
1026         par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres)
1027                                         + info->var.xoffset);
1028         par->video = 0;
1029
1030         if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
1031                 par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
1032         else
1033                 par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
1034
1035         if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
1036                 par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
1037         else
1038                 par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
1039
1040         if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1041                 par->video |= PM3VideoControl_LINE_DOUBLE_ON;
1042
1043         if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
1044                 par->video |= PM3VideoControl_ENABLE;
1045         else
1046                 DPRINTK("PM3Video disabled\n");
1047
1048         switch (bpp) {
1049         case 8:
1050                 par->video |= PM3VideoControl_PIXELSIZE_8BIT;
1051                 break;
1052         case 16:
1053                 par->video |= PM3VideoControl_PIXELSIZE_16BIT;
1054                 break;
1055         case 32:
1056                 par->video |= PM3VideoControl_PIXELSIZE_32BIT;
1057                 break;
1058         default:
1059                 DPRINTK("Unsupported depth\n");
1060                 break;
1061         }
1062
1063         info->fix.visual =
1064                 (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1065         info->fix.line_length = ((info->var.xres_virtual + 7)  >> 3) * bpp;
1066
1067 /*      pm3fb_clear_memory(info, 0);*/
1068         pm3fb_clear_colormap(par, 0, 0, 0);
1069         PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);
1070         pm3fb_init_engine(info);
1071         pm3fb_write_mode(info);
1072         return 0;
1073 }
1074
1075 static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
1076                            unsigned blue, unsigned transp,
1077                            struct fb_info *info)
1078 {
1079         struct pm3_par *par = info->par;
1080
1081         if (regno >= 256)  /* no. of hw registers */
1082            return -EINVAL;
1083
1084         /* grayscale works only partially under directcolor */
1085         /* grayscale = 0.30*R + 0.59*G + 0.11*B */
1086         if (info->var.grayscale)
1087            red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
1088
1089         /* Directcolor:
1090          *   var->{color}.offset contains start of bitfield
1091          *   var->{color}.length contains length of bitfield
1092          *   {hardwarespecific} contains width of DAC
1093          *   pseudo_palette[X] is programmed to (X << red.offset) |
1094          *                                      (X << green.offset) |
1095          *                                      (X << blue.offset)
1096          *   RAMDAC[X] is programmed to (red, green, blue)
1097          *   color depth = SUM(var->{color}.length)
1098          *
1099          * Pseudocolor:
1100          *      var->{color}.offset is 0
1101          *      var->{color}.length contains width of DAC or the number
1102          *                      of unique colors available (color depth)
1103          *      pseudo_palette is not used
1104          *      RAMDAC[X] is programmed to (red, green, blue)
1105          *      color depth = var->{color}.length
1106          */
1107
1108         /*
1109          * This is the point where the color is converted to something that
1110          * is acceptable by the hardware.
1111          */
1112 #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
1113         red = CNVT_TOHW(red, info->var.red.length);
1114         green = CNVT_TOHW(green, info->var.green.length);
1115         blue = CNVT_TOHW(blue, info->var.blue.length);
1116         transp = CNVT_TOHW(transp, info->var.transp.length);
1117 #undef CNVT_TOHW
1118
1119         if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
1120         info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
1121                 u32 v;
1122
1123                 if (regno >= 16)
1124                         return -EINVAL;
1125
1126                 v = (red << info->var.red.offset) |
1127                         (green << info->var.green.offset) |
1128                         (blue << info->var.blue.offset) |
1129                         (transp << info->var.transp.offset);
1130
1131                 switch (info->var.bits_per_pixel) {
1132                 case 8:
1133                         break;
1134                 case 16:
1135                 case 32:
1136                         ((u32 *)(info->pseudo_palette))[regno] = v;
1137                         break;
1138                 }
1139                 return 0;
1140         } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
1141                 pm3fb_set_color(par, regno, red, green, blue);
1142
1143         return 0;
1144 }
1145
1146 static int pm3fb_pan_display(struct fb_var_screeninfo *var,
1147                                  struct fb_info *info)
1148 {
1149         struct pm3_par *par = info->par;
1150         const u32 xres = (var->xres + 31) & ~31;
1151
1152         par->base = pm3fb_shift_bpp(var->bits_per_pixel,
1153                                         (var->yoffset * xres)
1154                                         + var->xoffset);
1155         PM3_WAIT(par, 1);
1156         PM3_WRITE_REG(par, PM3ScreenBase, par->base);
1157         return 0;
1158 }
1159
1160 static int pm3fb_blank(int blank_mode, struct fb_info *info)
1161 {
1162         struct pm3_par *par = info->par;
1163         u32 video = par->video;
1164
1165         /*
1166          * Oxygen VX1 - it appears that setting PM3VideoControl and
1167          * then PM3RD_SyncControl to the same SYNC settings undoes
1168          * any net change - they seem to xor together.  Only set the
1169          * sync options in PM3RD_SyncControl.  --rmk
1170          */
1171         video &= ~(PM3VideoControl_HSYNC_MASK |
1172                    PM3VideoControl_VSYNC_MASK);
1173         video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
1174                  PM3VideoControl_VSYNC_ACTIVE_HIGH;
1175
1176         switch (blank_mode) {
1177         case FB_BLANK_UNBLANK:
1178                 video |= PM3VideoControl_ENABLE;
1179                 break;
1180         case FB_BLANK_NORMAL:
1181                 video &= ~PM3VideoControl_ENABLE;
1182                 break;
1183         case FB_BLANK_HSYNC_SUSPEND:
1184                 video &= ~(PM3VideoControl_HSYNC_MASK |
1185                           PM3VideoControl_BLANK_ACTIVE_LOW);
1186                 break;
1187         case FB_BLANK_VSYNC_SUSPEND:
1188                 video &= ~(PM3VideoControl_VSYNC_MASK |
1189                           PM3VideoControl_BLANK_ACTIVE_LOW);
1190                 break;
1191         case FB_BLANK_POWERDOWN:
1192                 video &= ~(PM3VideoControl_HSYNC_MASK |
1193                           PM3VideoControl_VSYNC_MASK |
1194                           PM3VideoControl_BLANK_ACTIVE_LOW);
1195                 break;
1196         default:
1197                 DPRINTK("Unsupported blanking %d\n", blank_mode);
1198                 return 1;
1199         }
1200
1201         PM3_WAIT(par, 1);
1202         PM3_WRITE_REG(par, PM3VideoControl, video);
1203         return 0;
1204 }
1205
1206         /*
1207          *  Frame buffer operations
1208          */
1209
1210 static struct fb_ops pm3fb_ops = {
1211         .owner          = THIS_MODULE,
1212         .fb_check_var   = pm3fb_check_var,
1213         .fb_set_par     = pm3fb_set_par,
1214         .fb_setcolreg   = pm3fb_setcolreg,
1215         .fb_pan_display = pm3fb_pan_display,
1216         .fb_fillrect    = pm3fb_fillrect,
1217         .fb_copyarea    = pm3fb_copyarea,
1218         .fb_imageblit   = pm3fb_imageblit,
1219         .fb_blank       = pm3fb_blank,
1220         .fb_sync        = pm3fb_sync,
1221         .fb_cursor      = pm3fb_cursor,
1222 };
1223
1224 /* ------------------------------------------------------------------------- */
1225
1226         /*
1227          *  Initialization
1228          */
1229
1230 /* mmio register are already mapped when this function is called */
1231 /* the pm3fb_fix.smem_start is also set */
1232 static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
1233 {
1234         unsigned long   memsize = 0;
1235         unsigned long   tempBypass, i, temp1, temp2;
1236         unsigned char   __iomem *screen_mem;
1237
1238         pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */
1239         /* Linear frame buffer - request region and map it. */
1240         if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
1241                                  "pm3fb smem")) {
1242                 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
1243                 return 0;
1244         }
1245         screen_mem =
1246                 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1247         if (!screen_mem) {
1248                 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
1249                 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1250                 return 0;
1251         }
1252
1253         /* TODO: card-specific stuff, *before* accessing *any* FB memory */
1254         /* For Appian Jeronimo 2000 board second head */
1255
1256         tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
1257
1258         DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
1259
1260         PM3_WAIT(par, 1);
1261         PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
1262
1263         /* pm3 split up memory, replicates, and do a lot of
1264          * nasty stuff IMHO ;-)
1265          */
1266         for (i = 0; i < 32; i++) {
1267                 fb_writel(i * 0x00345678,
1268                           (screen_mem + (i * 1048576)));
1269                 mb();
1270                 temp1 = fb_readl((screen_mem + (i * 1048576)));
1271
1272                 /* Let's check for wrapover, write will fail at 16MB boundary */
1273                 if (temp1 == (i * 0x00345678))
1274                         memsize = i;
1275                 else
1276                         break;
1277         }
1278
1279         DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
1280
1281         if (memsize + 1 == i) {
1282                 for (i = 0; i < 32; i++) {
1283                         /* Clear first 32MB ; 0 is 0, no need to byteswap */
1284                         writel(0x0000000, (screen_mem + (i * 1048576)));
1285                 }
1286                 wmb();
1287
1288                 for (i = 32; i < 64; i++) {
1289                         fb_writel(i * 0x00345678,
1290                                   (screen_mem + (i * 1048576)));
1291                         mb();
1292                         temp1 =
1293                             fb_readl((screen_mem + (i * 1048576)));
1294                         temp2 =
1295                             fb_readl((screen_mem + ((i - 32) * 1048576)));
1296                         /* different value, different RAM... */
1297                         if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
1298                                 memsize = i;
1299                         else
1300                                 break;
1301                 }
1302         }
1303         DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
1304
1305         PM3_WAIT(par, 1);
1306         PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
1307
1308         iounmap(screen_mem);
1309         release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1310         memsize = 1048576 * (memsize + 1);
1311
1312         DPRINTK("Returning 0x%08lx bytes\n", memsize);
1313
1314         return memsize;
1315 }
1316
1317 static int __devinit pm3fb_probe(struct pci_dev *dev,
1318                                   const struct pci_device_id *ent)
1319 {
1320         struct fb_info *info;
1321         struct pm3_par *par;
1322         struct device *device = &dev->dev; /* for pci drivers */
1323         int err;
1324         int retval = -ENXIO;
1325
1326         err = pci_enable_device(dev);
1327         if (err) {
1328                 printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
1329                 return err;
1330         }
1331         /*
1332          * Dynamically allocate info and par
1333          */
1334         info = framebuffer_alloc(sizeof(struct pm3_par), device);
1335
1336         if (!info)
1337                 return -ENOMEM;
1338         par = info->par;
1339
1340         /*
1341          * Here we set the screen_base to the virtual memory address
1342          * for the framebuffer.
1343          */
1344         pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
1345         pm3fb_fix.mmio_len = PM3_REGS_SIZE;
1346 #if defined(__BIG_ENDIAN)
1347         pm3fb_fix.mmio_start += PM3_REGS_SIZE;
1348         DPRINTK("Adjusting register base for big-endian.\n");
1349 #endif
1350
1351         /* Registers - request region and map it. */
1352         if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
1353                                  "pm3fb regbase")) {
1354                 printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
1355                 goto err_exit_neither;
1356         }
1357         par->v_regs =
1358                 ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1359         if (!par->v_regs) {
1360                 printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
1361                         pm3fb_fix.id);
1362                 release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1363                 goto err_exit_neither;
1364         }
1365
1366         /* Linear frame buffer - request region and map it. */
1367         pm3fb_fix.smem_start = pci_resource_start(dev, 1);
1368         pm3fb_fix.smem_len = pm3fb_size_memory(par);
1369         if (!pm3fb_fix.smem_len) {
1370                 printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
1371                 goto err_exit_mmio;
1372         }
1373         if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
1374                                  "pm3fb smem")) {
1375                 printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
1376                 goto err_exit_mmio;
1377         }
1378         info->screen_base =
1379                 ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1380         if (!info->screen_base) {
1381                 printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
1382                 release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1383                 goto err_exit_mmio;
1384         }
1385         info->screen_size = pm3fb_fix.smem_len;
1386
1387 #ifdef CONFIG_MTRR
1388         if (!nomtrr)
1389                 par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start,
1390                                                 pm3fb_fix.smem_len,
1391                                                 MTRR_TYPE_WRCOMB, 1);
1392 #endif
1393         info->fbops = &pm3fb_ops;
1394
1395         par->video = PM3_READ_REG(par, PM3VideoControl);
1396
1397         info->fix = pm3fb_fix;
1398         info->pseudo_palette = par->palette;
1399         info->flags = FBINFO_DEFAULT |
1400                         FBINFO_HWACCEL_XPAN |
1401                         FBINFO_HWACCEL_YPAN |
1402                         FBINFO_HWACCEL_COPYAREA |
1403                         FBINFO_HWACCEL_IMAGEBLIT |
1404                         FBINFO_HWACCEL_FILLRECT;
1405
1406         if (noaccel) {
1407                 printk(KERN_DEBUG "disabling acceleration\n");
1408                 info->flags |= FBINFO_HWACCEL_DISABLED;
1409         }
1410         info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);
1411         if (!info->pixmap.addr) {
1412                 retval = -ENOMEM;
1413                 goto err_exit_pixmap;
1414         }
1415         info->pixmap.size = PM3_PIXMAP_SIZE;
1416         info->pixmap.buf_align = 4;
1417         info->pixmap.scan_align = 4;
1418         info->pixmap.access_align = 32;
1419         info->pixmap.flags = FB_PIXMAP_SYSTEM;
1420
1421         /*
1422          * This should give a reasonable default video mode. The following is
1423          * done when we can set a video mode.
1424          */
1425         if (!mode_option)
1426                 mode_option = "640x480@60";
1427
1428         retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
1429
1430         if (!retval || retval == 4) {
1431                 retval = -EINVAL;
1432                 goto err_exit_both;
1433         }
1434
1435         if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
1436                 retval = -ENOMEM;
1437                 goto err_exit_both;
1438         }
1439
1440         /*
1441          * For drivers that can...
1442          */
1443         pm3fb_check_var(&info->var, info);
1444
1445         if (register_framebuffer(info) < 0) {
1446                 retval = -EINVAL;
1447                 goto err_exit_all;
1448         }
1449         printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
1450            info->fix.id);
1451         pci_set_drvdata(dev, info);
1452         return 0;
1453
1454  err_exit_all:
1455         fb_dealloc_cmap(&info->cmap);
1456  err_exit_both:
1457         kfree(info->pixmap.addr);
1458  err_exit_pixmap:
1459         iounmap(info->screen_base);
1460         release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1461  err_exit_mmio:
1462         iounmap(par->v_regs);
1463         release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1464  err_exit_neither:
1465         framebuffer_release(info);
1466         return retval;
1467 }
1468
1469         /*
1470          *  Cleanup
1471          */
1472 static void __devexit pm3fb_remove(struct pci_dev *dev)
1473 {
1474         struct fb_info *info = pci_get_drvdata(dev);
1475
1476         if (info) {
1477                 struct fb_fix_screeninfo *fix = &info->fix;
1478                 struct pm3_par *par = info->par;
1479
1480                 unregister_framebuffer(info);
1481                 fb_dealloc_cmap(&info->cmap);
1482
1483 #ifdef CONFIG_MTRR
1484         if (par->mtrr_handle >= 0)
1485                 mtrr_del(par->mtrr_handle, info->fix.smem_start,
1486                          info->fix.smem_len);
1487 #endif /* CONFIG_MTRR */
1488                 iounmap(info->screen_base);
1489                 release_mem_region(fix->smem_start, fix->smem_len);
1490                 iounmap(par->v_regs);
1491                 release_mem_region(fix->mmio_start, fix->mmio_len);
1492
1493                 pci_set_drvdata(dev, NULL);
1494                 kfree(info->pixmap.addr);
1495                 framebuffer_release(info);
1496         }
1497 }
1498
1499 static struct pci_device_id pm3fb_id_table[] = {
1500         { PCI_VENDOR_ID_3DLABS, 0x0a,
1501           PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1502         { 0, }
1503 };
1504
1505 /* For PCI drivers */
1506 static struct pci_driver pm3fb_driver = {
1507         .name =         "pm3fb",
1508         .id_table =     pm3fb_id_table,
1509         .probe =        pm3fb_probe,
1510         .remove =       __devexit_p(pm3fb_remove),
1511 };
1512
1513 MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
1514
1515 #ifndef MODULE
1516         /*
1517          *  Setup
1518          */
1519
1520 /*
1521  * Only necessary if your driver takes special options,
1522  * otherwise we fall back on the generic fb_setup().
1523  */
1524 static int __init pm3fb_setup(char *options)
1525 {
1526         char *this_opt;
1527
1528         /* Parse user speficied options (`video=pm3fb:') */
1529         if (!options || !*options)
1530                 return 0;
1531
1532         while ((this_opt = strsep(&options, ",")) != NULL) {
1533                 if (!*this_opt)
1534                         continue;
1535                 else if (!strncmp(this_opt, "noaccel", 7))
1536                         noaccel = 1;
1537                 else if (!strncmp(this_opt, "hwcursor=", 9))
1538                         hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
1539 #ifdef CONFIG_MTRR
1540                 else if (!strncmp(this_opt, "nomtrr", 6))
1541                         nomtrr = 1;
1542 #endif
1543                 else
1544                         mode_option = this_opt;
1545         }
1546         return 0;
1547 }
1548 #endif /* MODULE */
1549
1550 static int __init pm3fb_init(void)
1551 {
1552         /*
1553          *  For kernel boot options (in 'video=pm3fb:<options>' format)
1554          */
1555 #ifndef MODULE
1556         char *option = NULL;
1557
1558         if (fb_get_options("pm3fb", &option))
1559                 return -ENODEV;
1560         pm3fb_setup(option);
1561 #endif
1562
1563         return pci_register_driver(&pm3fb_driver);
1564 }
1565
1566 #ifdef MODULE
1567 static void __exit pm3fb_exit(void)
1568 {
1569         pci_unregister_driver(&pm3fb_driver);
1570 }
1571
1572 module_exit(pm3fb_exit);
1573 #endif
1574 module_init(pm3fb_init);
1575
1576 module_param(mode_option, charp, 0);
1577 MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
1578 module_param(noaccel, bool, 0);
1579 MODULE_PARM_DESC(noaccel, "Disable acceleration");
1580 module_param(hwcursor, int, 0644);
1581 MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1582                         "(1=enable, 0=disable, default=1)");
1583 #ifdef CONFIG_MTRR
1584 module_param(nomtrr, bool, 0);
1585 MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
1586 #endif
1587
1588 MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
1589 MODULE_LICENSE("GPL");