make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / pm3fb.c
1 /*
2  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
3  *  
4  *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
5  *  Based on code written by:
6  *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
7  *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
8  *           Russel King, <rmk@arm.linux.org.uk>
9  *  Based on linux/drivers/video/skeletonfb.c:
10  *      Copyright (C) 1997 Geert Uytterhoeven
11  *  Based on linux/driver/video/pm2fb.c:
12  *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
13  *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
14  *
15  *  This file is subject to the terms and conditions of the GNU General Public
16  *  License. See the file COPYING in the main directory of this archive for
17  *  more details.
18  *
19  *  $Header: /cvshome/samwise/ppclinux/drivers/video/pm3fb.c,v 1.1.1.1 2005/04/11 02:50:42 jack Exp $
20  *
21  *  CHANGELOG:
22  *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
23  *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
24  *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
25  *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
26  *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
27  *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
28  *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
29  *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
30  *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
31  *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
32  *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
33  *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
34  *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
35  *  Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
36  *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
37  *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
38  *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
39  *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
40  *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
41  *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
42  *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
43  *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
44  *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
45  *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
46  *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
47  *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
48  *  Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
49  *  Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
50  *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
51  *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
52  *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
53  */
54
55 #include <linux/config.h>
56 #include <linux/module.h>
57 #include <linux/version.h>
58 #include <linux/kernel.h>
59 #include <linux/errno.h>
60 #include <linux/string.h>
61 #include <linux/mm.h>
62 #include <linux/tty.h>
63 #include <linux/slab.h>
64 #include <linux/vmalloc.h>
65 #include <linux/delay.h>
66 #include <linux/interrupt.h>
67 #include <linux/fb.h>
68 #include <linux/init.h>
69 #include <linux/pci.h>
70 #include <linux/ioport.h>
71
72 #include <video/fbcon.h>
73 #include <video/fbcon-mfb.h>
74 #include <video/fbcon-cfb2.h>
75 #include <video/fbcon-cfb4.h>
76 #include <video/fbcon-cfb8.h>
77 #include <video/fbcon-cfb16.h>
78 #include <video/fbcon-cfb24.h>
79 #include <video/fbcon-cfb32.h>
80
81 #include <asm/io.h>
82 #include <asm/uaccess.h>
83
84 #ifdef CONFIG_FB_OF
85 #include <asm/prom.h>
86 #endif
87
88 #include "pm3fb.h"
89
90 /* ************************************* */
91 /* ***** The various "global" data ***** */
92 /* ************************************* */
93
94 /* those will need a rework for multiple board support */
95 /* Driver name */
96 static const char permedia3_name[16] = "Permedia3";
97
98 /* the fb_par struct, mandatory */
99 struct pm3fb_par {
100         u32 pixclock;           /* pixclock in KHz */
101
102         u32 width;              /* width of virtual screen */
103         u32 height;             /* height of virtual screen */
104
105         u32 hsstart;            /* horiz. sync start */
106         u32 hsend;              /* horiz. sync end */
107         u32 hbend;              /* horiz. blank end (also gate end) */
108         u32 htotal;             /* total width (w/ sync & blank) */
109
110         u32 vsstart;            /* vert. sync start */
111         u32 vsend;              /* vert. sync end */
112         u32 vbend;              /* vert. blank end */
113         u32 vtotal;             /* total height (w/ sync & blank) */
114
115         u32 stride;             /* screen stride */
116         u32 base;               /* screen base (xoffset+yoffset) in 128 bits unit */
117         /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
118         u32 depth;              /* screen depth (8, 12, 15, 16 or 32) */
119         u32 video;              /* video control (hsync,vsync) */
120 };
121
122 /* memory timings */
123 struct pm3fb_timings
124 {
125         unsigned long caps;
126         unsigned long timings;
127         unsigned long control;
128         unsigned long refresh;
129         unsigned long powerdown;
130 };
131 typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
132 #define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
133 #define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
134
135 /* the fb_info struct, mandatory */
136 struct pm3fb_info {
137         struct fb_info_gen gen;
138         unsigned long board_num; /* internal board number */
139         unsigned long use_current;
140         struct pm3fb_par *current_par;
141         struct pci_dev *dev;    /* PCI device */
142 #ifdef SUPPORT_FB_OF
143         struct device_node *dn; /* OF node for the PCI device */
144 #endif /* SUPPORT_FB_OF */
145         unsigned long board_type; /* index in the cardbase */
146         unsigned char *fb_base; /* framebuffer memory base */
147         u32 fb_size;            /* framebuffer memory size */
148         unsigned char *p_fb;    /* physical address of frame buffer */
149         unsigned char *v_fb;    /* virtual address of frame buffer */
150         unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
151         unsigned char *vIOBase; /* address of registers after ioremap() */
152         struct {
153                 u8 transp;
154                 u8 red;
155                 u8 green;
156                 u8 blue;
157         } palette[256];
158         union {
159 #ifdef FBCON_HAS_CFB16
160                 u16 cmap12[16]; /* RGBA 4444 */
161                 u16 cmap15[16]; /* RGBA 5551 */
162                 u16 cmap16[16]; /* RGBA 5650 */
163 #endif
164 #ifdef FBCON_HAS_CFB32
165                 u32 cmap32[16];
166 #endif
167         } cmap;
168         struct pm3fb_timings memt;
169 };
170
171 /* regular resolution database*/
172 static struct {
173         char name[16];
174         struct pm3fb_par user_mode;
175 } mode_base[] __initdata = {
176         {
177                 "default-800x600", {
178         49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
179                             800, 0, 8,
180                             PM3VideoControl_ENABLE |
181                             PM3VideoControl_HSYNC_ACTIVE_HIGH
182                             |
183                             PM3VideoControl_VSYNC_ACTIVE_HIGH
184                             | PM3VideoControl_PIXELSIZE_8BIT}}, {
185                 "1024x768-74", {
186         78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
187                             806, 1024, 0, 8,
188                             PM3VideoControl_ENABLE |
189                             PM3VideoControl_HSYNC_ACTIVE_HIGH
190                             |
191                             PM3VideoControl_VSYNC_ACTIVE_HIGH
192                             | PM3VideoControl_PIXELSIZE_8BIT}}, {
193                 "1024x768-74-32", {
194                         78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
195                         806, 1024, 0, 32,
196                         PM3VideoControl_ENABLE |
197                         PM3VideoControl_HSYNC_ACTIVE_HIGH
198                         |
199                         PM3VideoControl_VSYNC_ACTIVE_HIGH
200                         | PM3VideoControl_PIXELSIZE_32BIT}},
201 /* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
202         {
203                 "SGI1600SW", {
204                         108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
205                         1056, 1600, 0, 8,
206                         PM3VideoControl_ENABLE|
207                         PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
208                         PM3VideoControl_PIXELSIZE_32BIT}}, 
209 /* ##### auto-generated mode, by fbtimings2pm3 */
210 /* Generated mode : "640x480-60" */
211         {
212                 "640x480-60", {
213         25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
214                             525, 640, 0, 8,
215                             PM3VideoControl_ENABLE |
216                             PM3VideoControl_HSYNC_ACTIVE_LOW
217                             |
218                             PM3VideoControl_VSYNC_ACTIVE_LOW
219                             | PM3VideoControl_PIXELSIZE_8BIT}},
220 /* Generated mode : "640x480-72" */
221         {
222                 "640x480-72", {
223         31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
224                             640, 0, 8,
225                             PM3VideoControl_ENABLE |
226                             PM3VideoControl_HSYNC_ACTIVE_LOW
227                             |
228                             PM3VideoControl_VSYNC_ACTIVE_LOW
229                             | PM3VideoControl_PIXELSIZE_8BIT}},
230 /* Generated mode : "640x480-75" */
231         {
232                 "640x480-75", {
233         31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
234                             640, 0, 8,
235                             PM3VideoControl_ENABLE |
236                             PM3VideoControl_HSYNC_ACTIVE_LOW
237                             |
238                             PM3VideoControl_VSYNC_ACTIVE_LOW
239                             | PM3VideoControl_PIXELSIZE_8BIT}},
240 /* Generated mode : "640x480-90" */
241         {
242                 "640x480-90", {
243         39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
244                             640, 0, 8,
245                             PM3VideoControl_ENABLE |
246                             PM3VideoControl_HSYNC_ACTIVE_LOW
247                             |
248                             PM3VideoControl_VSYNC_ACTIVE_LOW
249                             | PM3VideoControl_PIXELSIZE_8BIT}},
250 /* Generated mode : "640x480-100" */
251         {
252                 "640x480-100", {
253         44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
254                             531, 640, 0, 8,
255                             PM3VideoControl_ENABLE |
256                             PM3VideoControl_HSYNC_ACTIVE_LOW
257                             |
258                             PM3VideoControl_VSYNC_ACTIVE_LOW
259                             | PM3VideoControl_PIXELSIZE_8BIT}},
260 /* Generated mode : "800x600-48-lace" */
261 /* INTERLACED NOT SUPPORTED
262   {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
263    INTERLACED NOT SUPPORTED */
264 /* Generated mode : "800x600-56" */
265         {
266                 "800x600-56", {
267         35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
268                             800, 0, 8,
269                             PM3VideoControl_ENABLE |
270                             PM3VideoControl_HSYNC_ACTIVE_HIGH
271                             |
272                             PM3VideoControl_VSYNC_ACTIVE_HIGH
273                             | PM3VideoControl_PIXELSIZE_8BIT}},
274 /* Generated mode : "800x600-60" */
275         {
276                 "800x600-60", {
277         40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
278                             800, 0, 8,
279                             PM3VideoControl_ENABLE |
280                             PM3VideoControl_HSYNC_ACTIVE_HIGH
281                             |
282                             PM3VideoControl_VSYNC_ACTIVE_HIGH
283                             | PM3VideoControl_PIXELSIZE_8BIT}},
284 /* Generated mode : "800x600-70" */
285         {
286                 "800x600-70", {
287         44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
288                             636, 800, 0, 8,
289                             PM3VideoControl_ENABLE |
290                             PM3VideoControl_HSYNC_ACTIVE_HIGH
291                             |
292                             PM3VideoControl_VSYNC_ACTIVE_LOW
293                             | PM3VideoControl_PIXELSIZE_8BIT}},
294 /* Generated mode : "800x600-72" */
295         {
296                 "800x600-72", {
297         50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
298                             666, 800, 0, 8,
299                             PM3VideoControl_ENABLE |
300                             PM3VideoControl_HSYNC_ACTIVE_HIGH
301                             |
302                             PM3VideoControl_VSYNC_ACTIVE_HIGH
303                             | PM3VideoControl_PIXELSIZE_8BIT}},
304 /* Generated mode : "800x600-75" */
305         {
306                 "800x600-75", {
307         49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
308                             800, 0, 8,
309                             PM3VideoControl_ENABLE |
310                             PM3VideoControl_HSYNC_ACTIVE_HIGH
311                             |
312                             PM3VideoControl_VSYNC_ACTIVE_HIGH
313                             | PM3VideoControl_PIXELSIZE_8BIT}},
314 /* Generated mode : "800x600-90" */
315         {
316                 "800x600-90", {
317         56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
318                             800, 0, 8,
319                             PM3VideoControl_ENABLE |
320                             PM3VideoControl_HSYNC_ACTIVE_HIGH
321                             |
322                             PM3VideoControl_VSYNC_ACTIVE_HIGH
323                             | PM3VideoControl_PIXELSIZE_8BIT}},
324 /* Generated mode : "800x600-100", from /etc/fb.modes */
325 /* DISABLED, hsstart == 0
326         {
327                 "800x600-100", {
328         67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
329                             800, 0, 8,
330                             PM3VideoControl_ENABLE |
331                             PM3VideoControl_HSYNC_ACTIVE_HIGH
332                             |
333                             PM3VideoControl_VSYNC_ACTIVE_HIGH
334                             | PM3VideoControl_PIXELSIZE_8BIT}},
335 */
336 /* Generated mode : "800x600-100", from ??? */
337         {
338                 "800x600-100", {
339                         69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
340                         PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
341                         PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
342 /* Generated mode : "1024x768-43-lace" */
343 /* INTERLACED NOT SUPPORTED
344   {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
345    INTERLACED NOT SUPPORTED */
346 /* Generated mode : "1024x768-60" */
347         {
348                 "1024x768-60", {
349         64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
350                             806, 1024, 0, 8,
351                             PM3VideoControl_ENABLE |
352                             PM3VideoControl_HSYNC_ACTIVE_LOW
353                             |
354                             PM3VideoControl_VSYNC_ACTIVE_LOW
355                             | PM3VideoControl_PIXELSIZE_8BIT}},
356 /* Generated mode : "1024x768-70" */
357         {
358                 "1024x768-70", {
359         74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
360                             806, 1024, 0, 8,
361                             PM3VideoControl_ENABLE |
362                             PM3VideoControl_HSYNC_ACTIVE_LOW
363                             |
364                             PM3VideoControl_VSYNC_ACTIVE_LOW
365                             | PM3VideoControl_PIXELSIZE_8BIT}},
366 /* Generated mode : "1024x768-72" */
367         {
368                 "1024x768-72", {
369         74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
370                             806, 10224, 0, 8,
371                             PM3VideoControl_ENABLE |
372                             PM3VideoControl_HSYNC_ACTIVE_LOW
373                             |
374                             PM3VideoControl_VSYNC_ACTIVE_LOW
375                             | PM3VideoControl_PIXELSIZE_8BIT}},
376 /* Generated mode : "1024x768-75" */
377         {
378                 "1024x768-75", {
379         78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
380                             800, 1024, 0, 8,
381                             PM3VideoControl_ENABLE |
382                             PM3VideoControl_HSYNC_ACTIVE_HIGH
383                             |
384                             PM3VideoControl_VSYNC_ACTIVE_HIGH
385                             | PM3VideoControl_PIXELSIZE_8BIT}},
386 /* Generated mode : "1024x768-90" */
387         {
388                 "1024x768-90", {
389         100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
390                             845, 1024, 0, 8,
391                             PM3VideoControl_ENABLE |
392                             PM3VideoControl_HSYNC_ACTIVE_LOW
393                             |
394                             PM3VideoControl_VSYNC_ACTIVE_LOW
395                             | PM3VideoControl_PIXELSIZE_8BIT}},
396 /* Generated mode : "1024x768-100", from /etc/fb.modes */
397 /* DISABLED, vsstart == 0
398         {
399                 "1024x768-100", {
400         109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
401                             1024, 0, 8,
402                             PM3VideoControl_ENABLE |
403                             PM3VideoControl_HSYNC_ACTIVE_LOW
404                             |
405                             PM3VideoControl_VSYNC_ACTIVE_LOW
406                             | PM3VideoControl_PIXELSIZE_8BIT}},
407 */
408 /* Generated mode : "1024x768-100", from ??? */
409         {
410                 "1024x768-100", {
411                         115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
412                         PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
413                         PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
414 /* Generated mode : "1152x864-43-lace" */
415 /* INTERLACED NOT SUPPORTED
416   {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
417    INTERLACED NOT SUPPORTED */
418 /* Generated mode : "1152x864-47-lace" */
419 /* INTERLACED NOT SUPPORTED
420   {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
421    INTERLACED NOT SUPPORTED */
422 /* Generated mode : "1152x864-60" */
423         {
424                 "1152x864-60", {
425         80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
426                             916, 1152, 0, 8,
427                             PM3VideoControl_ENABLE |
428                             PM3VideoControl_HSYNC_ACTIVE_HIGH
429                             |
430                             PM3VideoControl_VSYNC_ACTIVE_HIGH
431                             | PM3VideoControl_PIXELSIZE_8BIT}},
432 /* Generated mode : "1152x864-70" */
433         {
434                 "1152x864-70", {
435         100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
436                             945, 1152, 0, 8,
437                             PM3VideoControl_ENABLE |
438                             PM3VideoControl_HSYNC_ACTIVE_HIGH
439                             |
440                             PM3VideoControl_VSYNC_ACTIVE_HIGH
441                             | PM3VideoControl_PIXELSIZE_8BIT}},
442 /* Generated mode : "1152x864-75" */
443         {
444                 "1152x864-75", {
445         109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
446                             1002, 1152, 0, 8,
447                             PM3VideoControl_ENABLE |
448                             PM3VideoControl_HSYNC_ACTIVE_HIGH
449                             |
450                             PM3VideoControl_VSYNC_ACTIVE_HIGH
451                             | PM3VideoControl_PIXELSIZE_8BIT}},
452 /* Generated mode : "1152x864-80" */
453         {
454                 "1152x864-80", {
455         109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
456                             958, 1152, 0, 8,
457                             PM3VideoControl_ENABLE |
458                             PM3VideoControl_HSYNC_ACTIVE_HIGH
459                             |
460                             PM3VideoControl_VSYNC_ACTIVE_HIGH
461                             | PM3VideoControl_PIXELSIZE_8BIT}},
462 /* Generated mode : "1280x1024-43-lace" */
463 /* INTERLACED NOT SUPPORTED
464   {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
465    INTERLACED NOT SUPPORTED */
466 /* Generated mode : "1280x1024-47-lace" */
467 /* INTERLACED NOT SUPPORTED
468   {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, 
469    INTERLACED NOT SUPPORTED */
470 /* Generated mode : "1280x1024-60" */
471         {
472                 "1280x1024-60", {
473         107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
474                             1066, 1280, 0, 8,
475                             PM3VideoControl_ENABLE |
476                             PM3VideoControl_HSYNC_ACTIVE_HIGH
477                             |
478                             PM3VideoControl_VSYNC_ACTIVE_HIGH
479                             | PM3VideoControl_PIXELSIZE_8BIT}},
480 /* Generated mode : "1280x1024-70" */
481         {
482                 "1280x1024-70", {
483         125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
484                             1066, 1280, 0, 8,
485                             PM3VideoControl_ENABLE |
486                             PM3VideoControl_HSYNC_ACTIVE_HIGH
487                             |
488                             PM3VideoControl_VSYNC_ACTIVE_HIGH
489                             | PM3VideoControl_PIXELSIZE_8BIT}},
490 /* Generated mode : "1280x1024-74" */
491         {
492                 "1280x1024-74", {
493         134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
494                             1064, 1280, 0, 8,
495                             PM3VideoControl_ENABLE |
496                             PM3VideoControl_HSYNC_ACTIVE_HIGH
497                             |
498                             PM3VideoControl_VSYNC_ACTIVE_HIGH
499                             | PM3VideoControl_PIXELSIZE_8BIT}},
500 /* Generated mode : "1280x1024-75" */
501         {
502                 "1280x1024-75", {
503         134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
504                             1066, 1280, 0, 8,
505                             PM3VideoControl_ENABLE |
506                             PM3VideoControl_HSYNC_ACTIVE_HIGH
507                             |
508                             PM3VideoControl_VSYNC_ACTIVE_HIGH
509                             | PM3VideoControl_PIXELSIZE_8BIT}},
510 /* Generated mode : "1600x1200-60" */
511         {
512                 "1600x1200-60", {
513         155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
514                             1270, 1600, 0, 8,
515                             PM3VideoControl_ENABLE |
516                             PM3VideoControl_HSYNC_ACTIVE_LOW
517                             |
518                             PM3VideoControl_VSYNC_ACTIVE_LOW
519                             | PM3VideoControl_PIXELSIZE_8BIT}},
520 /* Generated mode : "1600x1200-66" */
521         {
522                 "1600x1200-66", {
523         171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
524                             1253, 1600, 0, 8,
525                             PM3VideoControl_ENABLE |
526                             PM3VideoControl_HSYNC_ACTIVE_LOW
527                             |
528                             PM3VideoControl_VSYNC_ACTIVE_LOW
529                             | PM3VideoControl_PIXELSIZE_8BIT}},
530 /* Generated mode : "1600x1200-76" */
531         {
532                 "1600x1200-76", {
533         197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
534                             1250, 1600, 0, 8,
535                             PM3VideoControl_ENABLE |
536                             PM3VideoControl_HSYNC_ACTIVE_LOW
537                             |
538                             PM3VideoControl_VSYNC_ACTIVE_LOW
539                             | PM3VideoControl_PIXELSIZE_8BIT}},
540 /* ##### end of auto-generated mode */
541         {
542         "\0",}
543 };
544
545 /* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
546 static struct pm3fb_info fb_info[PM3_MAX_BOARD];
547 static struct pm3fb_par current_par[PM3_MAX_BOARD];
548 static int current_par_valid[PM3_MAX_BOARD];
549 /* to allow explicit filtering of board */
550 short bus[PM3_MAX_BOARD];
551 short slot[PM3_MAX_BOARD];
552 short func[PM3_MAX_BOARD];
553 short disable[PM3_MAX_BOARD];
554 short noaccel[PM3_MAX_BOARD];
555 char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
556 short depth[PM3_MAX_BOARD];
557 short flatpanel[PM3_MAX_BOARD];
558 static struct display disp[PM3_MAX_BOARD];
559 static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
560 short printtimings = 0;
561 short forcesize[PM3_MAX_BOARD];
562
563 /* ********************* */
564 /* ***** prototype ***** */
565 /* ********************* */
566 /* card-specific */
567 static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
568 /* permedia3-specific */
569 static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
570 static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
571 static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
572 static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
573                                         unsigned long r);
574 static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
575                                           unsigned long refclock,       /* In kHz units */
576                                           unsigned char *prescale,      /* ClkPreScale */
577                                           unsigned char *feedback,      /* ClkFeedBackScale */
578                                           unsigned char *postscale
579                                           /* ClkPostScale */ );
580 static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
581 static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
582 static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
583 static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
584                           unsigned long depth, int v);
585 static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
586                             unsigned long depth, int v);
587 static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
588 static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
589 #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
590 static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
591 #endif
592 static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
593 static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
594 static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
595                             struct pm3fb_par *curpar);
596 static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
597 /* accelerated permedia3-specific */
598 #ifdef PM3FB_USE_ACCEL
599 static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
600 static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
601 #ifdef FBCON_HAS_CFB32
602 static void pm3fb_cfb32_clear(struct vc_data *conp,
603                               struct display *p,
604                               int sy, int sx, int height, int width);
605 static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
606                                       struct display *p, int bottom_only);
607 #endif /* FBCON_HAS_CFB32 */
608 #ifdef FBCON_HAS_CFB16
609 static void pm3fb_cfb16_clear(struct vc_data *conp,
610                               struct display *p,
611                               int sy, int sx, int height, int width);
612 static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
613                                       struct display *p, int bottom_only);
614 #endif /* FBCON_HAS_CFB16 */
615 #ifdef FBCON_HAS_CFB8
616 static void pm3fb_cfb8_clear(struct vc_data *conp,
617                              struct display *p,
618                              int sy, int sx, int height, int width);
619 static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
620                                      struct display *p, int bottom_only);
621 #endif /* FBCON_HAS_CFB8 */
622 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
623 static void pm3fb_cfbX_bmove(struct display *p,
624                              int sy, int sx,
625                              int dy, int dx, int height, int width);
626 static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
627                             int c, int yy, int xx);
628 static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
629                              const unsigned short *s, int count, int yy,
630                              int xx);
631 static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
632 #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
633 #endif /* PM3FB_USE_ACCEL */
634 /* pre-init */
635 static void pm3fb_mode_setup(char *mode, unsigned long board_num);
636 static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
637 static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
638 static void pm3fb_real_setup(char *options);
639 /* fbdev */
640 static int pm3fb_open(struct fb_info *info, int user);
641 static int pm3fb_release(struct fb_info *info, int user);
642 static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
643                             const void *par, struct fb_info_gen *info);
644 static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
645                             void *par, struct fb_info_gen *info);
646 static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
647 static int pm3fb_encode_var(struct fb_var_screeninfo *var,
648                             const void *par, struct fb_info_gen *info);
649 static void pm3fb_get_par(void *par, struct fb_info_gen *info);
650 static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
651 static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
652                             unsigned char regno, unsigned char r,
653                             unsigned char g, unsigned char b);
654 static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
655                            unsigned *blue, unsigned *transp,
656                            struct fb_info *info);
657 static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
658                            unsigned blue, unsigned transp,
659                            struct fb_info *info);
660 static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
661 static void pm3fb_set_disp(const void *par, struct display *disp,
662                            struct fb_info_gen *info);
663 static void pm3fb_detect(void);
664 static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
665                              struct fb_info_gen *info);
666 static int pm3fb_ioctl(struct inode *inode, struct file *file,
667                        u_int cmd, u_long arg, int con,
668                        struct fb_info *info);
669
670
671 /* the struct that hold them together */
672 #ifdef KERNEL_2_2
673 struct fbgen_hwswitch pm3fb_switch = {
674         pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
675         pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg,
676         pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
677 };
678
679 static struct fb_ops pm3fb_ops = {
680         pm3fb_open, pm3fb_release,
681         fbgen_get_fix, fbgen_get_var, fbgen_set_var,
682         fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl,
683             NULL, NULL
684 };
685 #endif /* KERNEL_2_2 */
686 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
687 struct fbgen_hwswitch pm3fb_switch = {
688         pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
689         pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg,
690         pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
691 };
692
693 static struct fb_ops pm3fb_ops = {
694         THIS_MODULE,
695         pm3fb_open, pm3fb_release,
696         fbgen_get_fix, fbgen_get_var, fbgen_set_var,
697         fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl, NULL, NULL
698 };
699 #endif /* KERNEL_2_4 or KERNEL_2_5 */
700 #ifdef PM3FB_USE_ACCEL
701 #ifdef FBCON_HAS_CFB32
702 static struct display_switch pm3fb_cfb32 = {
703         fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
704         pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
705         NULL /* cursor() */ , NULL /* set_font() */ ,
706         pm3fb_cfb32_clear_margins,
707         FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
708 };
709 #endif /* FBCON_HAS_CFB32 */
710 #ifdef FBCON_HAS_CFB16
711 static struct display_switch pm3fb_cfb16 = {
712         fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
713         pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
714         NULL /* cursor() */ , NULL /* set_font() */ ,
715         pm3fb_cfb16_clear_margins,
716         FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
717 };
718 #endif /* FBCON_HAS_CFB16 */
719 #ifdef FBCON_HAS_CFB8
720 static struct display_switch pm3fb_cfb8 = {
721         fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
722         pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
723         NULL /* cursor() */ , NULL /* set_font() */ ,
724         pm3fb_cfb8_clear_margins,
725         FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
726 };
727 #endif /* FBCON_HAS_CFB8 */
728 #endif /* PM3FB_USE_ACCEL */
729
730 /* ****************************** */
731 /* ***** card-specific data ***** */
732 /* ****************************** */
733 struct pm3fb_card_timings {
734         unsigned long memsize; /* 0 for last value (i.e. default) */
735         struct pm3fb_timings memt;
736 };
737
738 static struct pm3fb_card_timings t_FormacProFormance3[] = {
739         { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
740         { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
741 };
742
743 static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
744         { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
745         { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
746 };
747
748 static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
749         { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
750         { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
751 };
752
753 static struct {
754                 char cardname[32]; /* recognized card name */
755                 u16 subvendor; /* subvendor of the card */
756                 u16 subdevice; /* subdevice of the card */
757                 u8  func; /* function of the card to which the extra init apply */
758                 void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
759         struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
760 } cardbase[] = {
761         { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
762         { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
763           t_AppianJeronimo2000
764         },
765         { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
766           t_AppianJeronimo2000
767         },
768         { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
769           t_FormacProFormance3
770         },
771         { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
772         { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
773           t_3DLabsOxygenVX1
774         },
775         { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
776         { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
777         { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
778         { "\0", 0x0, 0x0, 0, NULL, NULL }
779 };
780
781 /* ********************************** */
782 /* ***** card-specific function ***** */
783 /* ********************************** */
784 static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
785 {       /* the appian j2000 require more initialization of the second head */
786         /* l_fb_info must point to the _second_ head of the J2000 */
787         
788         DTRACE;
789
790         l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
791         
792         pm3fb_write_memory_timings(l_fb_info);
793 }
794
795 /* *************************************** */
796 /* ***** permedia3-specific function ***** */
797 /* *************************************** */
798 static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
799 {
800         l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
801         l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
802         l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
803         l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
804         l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
805
806         if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
807             (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
808             (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
809             (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
810             (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
811         {
812                 printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
813                 return(pm3fb_try_memory_timings(l_fb_info));
814         }
815         return(pm3fb_timing_ok);
816 }
817
818 static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
819 {
820         if (cardbase[l_fb_info->board_type].c_memt)
821         {
822                 int i = 0, done = 0;
823                 while (!done)
824                 {
825                         if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
826                             || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
827                         { /* will use the 0-sized timings by default */
828                                 done = 1;
829                                 l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
830                                 printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
831                                        l_fb_info->board_num,
832                                        cardbase[l_fb_info->board_type].cardname,
833                                        cardbase[l_fb_info->board_type].c_memt[i].memsize);
834                                 pm3fb_write_memory_timings(l_fb_info);
835                                 return(pm3fb_timing_retry);
836                         }
837                         i++;
838                 }
839         } else
840                 return(pm3fb_timing_problem);
841         return(pm3fb_timing_ok);
842 }
843
844 static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
845 {
846         unsigned char m, n, p;
847         unsigned long clockused;
848         
849         PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
850         PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
851         PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
852         PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
853         PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
854
855         clockused =
856             pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
857                                  &n, &p);
858
859         PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
860         PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
861         PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
862         PM3_WRITE_DAC_REG(PM3RD_KClkControl,
863                           PM3RD_KClkControl_STATE_RUN |
864                           PM3RD_KClkControl_SOURCE_PLL |
865                           PM3RD_KClkControl_ENABLE);
866         PM3_WRITE_DAC_REG(PM3RD_MClkControl,
867                           PM3RD_MClkControl_STATE_RUN |
868                           PM3RD_MClkControl_SOURCE_KCLK |
869                           PM3RD_MClkControl_ENABLE);
870         PM3_WRITE_DAC_REG(PM3RD_SClkControl,
871                           PM3RD_SClkControl_STATE_RUN |
872                           PM3RD_SClkControl_SOURCE_PCLK |
873                           PM3RD_SClkControl_ENABLE);
874 }
875
876 static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
877                                         unsigned long r)
878 {
879         DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
880                 "l_fb_info->vIOBase mapped in read dac reg\n");
881         PM3_SET_INDEX(r);
882         mb();
883         return (PM3_READ_REG(PM3RD_IndexedData));
884 }
885
886 /* Calculating various clock parameter */
887 static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
888                                           unsigned long refclock,       /* In kHz units */
889                                           unsigned char *prescale,      /* ClkPreScale */
890                                           unsigned char *feedback,      /* ClkFeedBackScale */
891                                           unsigned char *postscale
892                                           /* ClkPostScale */ )
893 {
894         int f, pre, post;
895         unsigned long freq;
896         long freqerr = 1000;
897         unsigned long actualclock = 0;
898
899         DTRACE;
900
901         for (f = 1; f < 256; f++) {
902                 for (pre = 1; pre < 256; pre++) {
903                         for (post = 0; post < 5; post++) {
904                                 freq =
905                                     ((2 * refclock * f) /
906                                      (pre * (1 << post)));
907                                 if ((reqclock > freq - freqerr)
908                                     && (reqclock < freq + freqerr)) {
909                                         freqerr =
910                                             (reqclock >
911                                              freq) ? reqclock -
912                                             freq : freq - reqclock;
913                                         *feedback = f;
914                                         *prescale = pre;
915                                         *postscale = post;
916                                         actualclock = freq;
917                                 }
918                         }
919                 }
920         }
921
922         return (actualclock);
923 }
924
925 static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
926                           unsigned long depth, int v)
927 {
928         DTRACE;
929         
930         switch (depth) {
931         case 8:
932                 return (v >> 4);
933         case 12:
934         case 15:
935         case 16:
936                 return (v >> 3);
937         case 32:
938                 return (v >> 2);
939         }
940         DPRINTK(1, "Unsupported depth %ld\n", depth);
941         return (0);
942 }
943
944 static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
945                             unsigned long depth, int v)
946 {
947         DTRACE;
948
949         switch (depth) {
950         case 8:
951                 return (v << 4);
952         case 12:        
953         case 15:
954         case 16:
955                 return (v << 3);
956         case 32:
957                 return (v << 2);
958         }
959         DPRINTK(1, "Unsupported depth %ld\n", depth);
960         return (0);
961 }
962
963 static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
964 {
965         DTRACE;
966
967         l_fb_info->vIOBase =
968             ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
969         l_fb_info->v_fb =
970             ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
971         DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
972                 (unsigned long) l_fb_info->pIOBase,
973                 (unsigned long) l_fb_info->vIOBase,
974                 (unsigned long) l_fb_info->p_fb,
975                 (unsigned long) l_fb_info->v_fb);
976 }
977
978 static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
979 {
980         DTRACE;
981
982         iounmap(l_fb_info->vIOBase);
983         iounmap(l_fb_info->v_fb);
984         l_fb_info->vIOBase = (unsigned char *) -1;
985         l_fb_info->v_fb = (unsigned char *) -1;
986 }
987
988 #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
989 static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
990 {
991         DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
992         DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
993         DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
994                 PM3_READ_REG(PM3ByAperture1Mode));
995         DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
996                 PM3_READ_REG(PM3ByAperture2Mode));
997         DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
998         DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
999         DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
1000         DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
1001         DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
1002         DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
1003         DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
1004         DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
1005                 PM3_READ_REG(PM3MemBypassWriteMask));
1006         DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
1007                 PM3_READ_REG(PM3RD_IndexControl));
1008         DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
1009         DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
1010                 PM3_READ_REG(PM3ScreenStride));
1011         DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
1012         DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
1013         DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
1014         DPRINTK(2, "PM3VideoControl: 0x%08x\n",
1015                 PM3_READ_REG(PM3VideoControl));
1016         DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
1017         DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
1018
1019         DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
1020                 PM3_READ_DAC_REG(PM3RD_ColorFormat));
1021         DPRINTK(2, "PM3RD_DACControl: %ld\n",
1022                 PM3_READ_DAC_REG(PM3RD_DACControl));
1023         DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
1024                 PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
1025         DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
1026                 PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
1027         DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
1028                 PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
1029         DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
1030                 PM3_READ_DAC_REG(PM3RD_IndexControl));
1031         DPRINTK(2, "PM3RD_MiscControl: %ld\n",
1032                 PM3_READ_DAC_REG(PM3RD_MiscControl));
1033         DPRINTK(2, "PM3RD_PixelSize: %ld\n",
1034                 PM3_READ_DAC_REG(PM3RD_PixelSize));
1035         DPRINTK(2, "PM3RD_SyncControl: %ld\n",
1036                 PM3_READ_DAC_REG(PM3RD_SyncControl));
1037 }
1038
1039 #endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
1040 static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
1041 {
1042         u16 subvendor, subdevice;
1043
1044         if ((!pci_read_config_word
1045              (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
1046             &&
1047             (!pci_read_config_word
1048              (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
1049                 /* well, nothing... */
1050         } else {
1051                 subvendor = subdevice = (u16)-1;
1052         }
1053
1054         printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
1055         printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
1056                PM3_READ_REG(PM3LocalMemCaps));
1057         printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
1058                PM3_READ_REG(PM3LocalMemTimings));
1059         printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
1060                PM3_READ_REG(PM3LocalMemControl));
1061         printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
1062                PM3_READ_REG(PM3LocalMemRefresh));
1063         printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
1064                PM3_READ_REG(PM3LocalMemPowerDown));
1065 }
1066
1067 /* write the mode to registers */
1068 static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
1069 {
1070         char tempsync = 0x00, tempmisc = 0x00;
1071         DTRACE;
1072
1073         PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
1074         PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
1075         PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
1076         PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
1077
1078         PM3_SLOW_WRITE_REG(PM3HTotal,
1079                            pm3fb_Shiftbpp(l_fb_info,
1080                                           l_fb_info->current_par->depth,
1081                                           l_fb_info->current_par->htotal -
1082                                           1));
1083         PM3_SLOW_WRITE_REG(PM3HsEnd,
1084                            pm3fb_Shiftbpp(l_fb_info,
1085                                           l_fb_info->current_par->depth,
1086                                           l_fb_info->current_par->hsend));
1087         PM3_SLOW_WRITE_REG(PM3HsStart,
1088                            pm3fb_Shiftbpp(l_fb_info,
1089                                           l_fb_info->current_par->depth,
1090                                           l_fb_info->current_par->
1091                                           hsstart));
1092         PM3_SLOW_WRITE_REG(PM3HbEnd,
1093                            pm3fb_Shiftbpp(l_fb_info,
1094                                           l_fb_info->current_par->depth,
1095                                           l_fb_info->current_par->hbend));
1096         PM3_SLOW_WRITE_REG(PM3HgEnd,
1097                            pm3fb_Shiftbpp(l_fb_info,
1098                                           l_fb_info->current_par->depth,
1099                                           l_fb_info->current_par->hbend));
1100         PM3_SLOW_WRITE_REG(PM3ScreenStride,
1101                            pm3fb_Shiftbpp(l_fb_info,
1102                                           l_fb_info->current_par->depth,
1103                                           l_fb_info->current_par->stride));
1104         PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
1105         PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
1106         PM3_SLOW_WRITE_REG(PM3VsStart,
1107                            l_fb_info->current_par->vsstart - 1);
1108         PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
1109
1110         switch (l_fb_info->current_par->depth) {
1111         case 8:
1112                 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
1113                                    PM3ByApertureMode_PIXELSIZE_8BIT);
1114                 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
1115                                    PM3ByApertureMode_PIXELSIZE_8BIT);
1116                 break;
1117
1118         case 12:
1119         case 15:
1120         case 16:
1121 #ifndef __BIG_ENDIAN
1122                 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
1123                                    PM3ByApertureMode_PIXELSIZE_16BIT);
1124                 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
1125                                    PM3ByApertureMode_PIXELSIZE_16BIT);
1126 #else
1127                 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
1128                                    PM3ByApertureMode_PIXELSIZE_16BIT |
1129                                    PM3ByApertureMode_BYTESWAP_BADC);
1130                 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
1131                                    PM3ByApertureMode_PIXELSIZE_16BIT |
1132                                    PM3ByApertureMode_BYTESWAP_BADC);
1133 #endif /* ! __BIG_ENDIAN */
1134                 break;
1135
1136         case 32:
1137 #ifndef __BIG_ENDIAN
1138                 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
1139                                    PM3ByApertureMode_PIXELSIZE_32BIT);
1140                 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
1141                                    PM3ByApertureMode_PIXELSIZE_32BIT);
1142 #else
1143                 PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
1144                                    PM3ByApertureMode_PIXELSIZE_32BIT |
1145                                    PM3ByApertureMode_BYTESWAP_DCBA);
1146                 PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
1147                                    PM3ByApertureMode_PIXELSIZE_32BIT |
1148                                    PM3ByApertureMode_BYTESWAP_DCBA);
1149 #endif /* ! __BIG_ENDIAN */
1150                 break;
1151
1152         default:
1153                 DPRINTK(1, "Unsupported depth %d\n",
1154                         l_fb_info->current_par->depth);
1155                 break;
1156         }
1157
1158         /*
1159          * Oxygen VX1 - it appears that setting PM3VideoControl and
1160          * then PM3RD_SyncControl to the same SYNC settings undoes
1161          * any net change - they seem to xor together.  Only set the
1162          * sync options in PM3RD_SyncControl.  --rmk
1163          */
1164         {
1165                 unsigned int video = l_fb_info->current_par->video;
1166
1167                 video &= ~(PM3VideoControl_HSYNC_MASK |
1168                            PM3VideoControl_VSYNC_MASK);
1169                 video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
1170                          PM3VideoControl_VSYNC_ACTIVE_HIGH;
1171                 PM3_SLOW_WRITE_REG(PM3VideoControl, video);
1172         }
1173         PM3_SLOW_WRITE_REG(PM3VClkCtl,
1174                            (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
1175         PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
1176         PM3_SLOW_WRITE_REG(PM3ChipConfig,
1177                            (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
1178
1179         {
1180                 unsigned char m;        /* ClkPreScale */
1181                 unsigned char n;        /* ClkFeedBackScale */
1182                 unsigned char p;        /* ClkPostScale */
1183                 (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
1184
1185                 DPRINTK(2,
1186                         "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
1187                         l_fb_info->current_par->pixclock, (int) m, (int) n,
1188                         (int) p);
1189
1190                 PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
1191                 PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
1192                 PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
1193         }
1194         /*
1195            PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
1196          */
1197         /*
1198            PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
1199          */
1200         if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
1201             PM3VideoControl_HSYNC_ACTIVE_HIGH)
1202                 tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
1203         if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
1204             PM3VideoControl_VSYNC_ACTIVE_HIGH)
1205                 tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
1206         
1207         PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
1208         DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
1209         
1210         if (flatpanel[l_fb_info->board_num])
1211         {
1212                 PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
1213                 PM3_WAIT(2);
1214                 PM3_WRITE_REG(PM3VSConfiguration, 0x06);
1215                 PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
1216                 tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
1217         }
1218         else
1219                 PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
1220
1221         switch (l_fb_info->current_par->depth) {
1222         case 8:
1223                 PM3_WRITE_DAC_REG(PM3RD_PixelSize,
1224                                   PM3RD_PixelSize_8_BIT_PIXELS);
1225                 PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
1226                                   PM3RD_ColorFormat_CI8_COLOR |
1227                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
1228                 tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
1229                 break;
1230         case 12:
1231                 PM3_WRITE_DAC_REG(PM3RD_PixelSize,
1232                                   PM3RD_PixelSize_16_BIT_PIXELS);
1233                 PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
1234                                   PM3RD_ColorFormat_4444_COLOR |
1235                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
1236                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
1237                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
1238                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
1239                 break;          
1240         case 15:
1241                 PM3_WRITE_DAC_REG(PM3RD_PixelSize,
1242                                   PM3RD_PixelSize_16_BIT_PIXELS);
1243                 PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
1244                                   PM3RD_ColorFormat_5551_FRONT_COLOR |
1245                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
1246                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
1247                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
1248                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
1249                 break;          
1250         case 16:
1251                 PM3_WRITE_DAC_REG(PM3RD_PixelSize,
1252                                   PM3RD_PixelSize_16_BIT_PIXELS);
1253                 PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
1254                                   PM3RD_ColorFormat_565_FRONT_COLOR |
1255                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
1256                                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
1257                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
1258                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
1259                 break;
1260         case 32:
1261                 PM3_WRITE_DAC_REG(PM3RD_PixelSize,
1262                                   PM3RD_PixelSize_32_BIT_PIXELS);
1263                 PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
1264                                   PM3RD_ColorFormat_8888_COLOR |
1265                                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
1266                 tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
1267                         PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
1268                 break;
1269         }
1270         PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
1271         
1272         PM3_SHOW_CUR_MODE;
1273 }
1274
1275 static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
1276                             struct pm3fb_par *curpar)
1277 {
1278         unsigned long pixsize1, pixsize2, clockused;
1279         unsigned long pre, feedback, post;
1280
1281         DTRACE;
1282
1283         clockused = PM3_READ_REG(PM3VClkCtl);
1284
1285         switch (clockused) {
1286         case 3:
1287                 pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
1288                 feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
1289                 post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
1290
1291                 DPRINTK(2,
1292                         "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
1293                         pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
1294                                                                 feedback,
1295                                                                 post));
1296                 break;
1297         case 2:
1298                 pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
1299                 feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
1300                 post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
1301
1302                 DPRINTK(2,
1303                         "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
1304                         pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
1305                                                                 feedback,
1306                                                                 post));
1307                 break;
1308         case 1:
1309                 pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
1310                 feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
1311                 post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
1312
1313                 DPRINTK(2,
1314                         "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
1315                         pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
1316                                                                 feedback,
1317                                                                 post));
1318                 break;
1319         case 0:
1320                 pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
1321                 feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
1322                 post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
1323
1324                 DPRINTK(2,
1325                         "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
1326                         pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
1327                                                                 feedback,
1328                                                                 post));
1329                 break;
1330         default:
1331                 pre = feedback = post = 0;
1332                 DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
1333                 break;
1334         }
1335
1336         curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
1337
1338         pixsize1 =
1339             PM3ByApertureMode_PIXELSIZE_MASK &
1340             (PM3_READ_REG(PM3ByAperture1Mode));
1341         pixsize2 =
1342             PM3ByApertureMode_PIXELSIZE_MASK &
1343             (PM3_READ_REG(PM3ByAperture2Mode));
1344
1345         DASSERT((pixsize1 == pixsize2),
1346                 "pixsize the same in both aperture\n");
1347
1348         if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
1349                 curpar->depth = 32;
1350         else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
1351         {
1352                 curpar->depth = 16;
1353         }
1354         else
1355                 curpar->depth = 8;
1356
1357         /* not sure if I need to add one on the next ; it give better result with */
1358         curpar->htotal =
1359             pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
1360                              1 + PM3_READ_REG(PM3HTotal));
1361         curpar->hsend =
1362             pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
1363                              PM3_READ_REG(PM3HsEnd));
1364         curpar->hsstart =
1365             pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
1366                              PM3_READ_REG(PM3HsStart));
1367         curpar->hbend =
1368             pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
1369                              PM3_READ_REG(PM3HbEnd));
1370
1371         curpar->stride =
1372             pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
1373                              PM3_READ_REG(PM3ScreenStride));
1374
1375         curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
1376         curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
1377         curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
1378         curpar->vbend = PM3_READ_REG(PM3VbEnd);
1379
1380         curpar->video = PM3_READ_REG(PM3VideoControl);
1381
1382         curpar->base = PM3_READ_REG(PM3ScreenBase);
1383         curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
1384         curpar->height = curpar->vtotal - curpar->vbend;
1385
1386         DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
1387                 curpar->width, curpar->height, curpar->pixclock,
1388                 curpar->stride);
1389 }
1390
1391 static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
1392 {
1393         unsigned long memsize = 0, tempBypass, i, temp1, temp2;
1394         u16 subvendor, subdevice;
1395         pm3fb_timing_result ptr;
1396
1397         DTRACE;
1398
1399         l_fb_info->fb_size = 64 * 1024 * 1024;  /* pm3 aperture always 64 MB */
1400         pm3fb_mapIO(l_fb_info); /* temporary map IO */
1401
1402         DASSERT((l_fb_info->vIOBase != NULL),
1403                 "IO successfully mapped before mem detect\n");
1404         DASSERT((l_fb_info->v_fb != NULL),
1405                 "FB successfully mapped before mem detect\n");
1406
1407         /* card-specific stuff, *before* accessing *any* FB memory */
1408         if ((!pci_read_config_word
1409              (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
1410             &&
1411             (!pci_read_config_word
1412              (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
1413                 i = 0; l_fb_info->board_type = 0;
1414                 while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
1415                         if ((cardbase[i].subvendor == subvendor) &&
1416                             (cardbase[i].subdevice == subdevice) &&
1417                             (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
1418                                 DPRINTK(2, "Card #%ld is an %s\n",
1419                                         l_fb_info->board_num,
1420                                         cardbase[i].cardname);
1421                                 if (cardbase[i].specific_setup)
1422                                         cardbase[i].specific_setup(l_fb_info);
1423                                 l_fb_info->board_type = i;
1424                         }
1425                         i++;
1426                 }
1427                 if (!l_fb_info->board_type) {
1428                         DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
1429                                 l_fb_info->board_num, subvendor, subdevice);
1430                 }
1431         } else {
1432                 printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
1433                        l_fb_info->board_num);
1434         }
1435
1436         if (printtimings)
1437                 pm3fb_show_cur_timing(l_fb_info);
1438         
1439         /* card-specific setup is done, we preserve the final
1440            memory timing for future reference */
1441         if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
1442                 return(0);
1443         }
1444         
1445         tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
1446
1447         DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
1448
1449         PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
1450
1451         /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
1452         for (i = 0; i < 32; i++) {
1453 #ifdef KERNEL_2_2
1454 #ifdef MUST_BYTESWAP
1455                 writel(__swab32(i * 0x00345678),
1456                        (l_fb_info->v_fb + (i * 1048576)));
1457 #else
1458                 writel(i * 0x00345678, (l_fb_info->v_fb + (i * 1048576)));
1459 #endif
1460                 mb();
1461 #ifdef MUST_BYTESWAP
1462                 temp1 = __swab32(readl((l_fb_info->v_fb + (i * 1048576))));
1463 #else
1464                 temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
1465 #endif
1466 #endif  /* KERNEL_2_2 */
1467 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
1468                 fb_writel(i * 0x00345678,
1469                           (l_fb_info->v_fb + (i * 1048576)));
1470                 mb();
1471                 temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
1472 #endif /* KERNEL_2_4 or KERNEL_2_5 */
1473                 /* Let's check for wrapover, write will fail at 16MB boundary */
1474                 if (temp1 == (i * 0x00345678))
1475                         memsize = i;
1476                 else
1477                         break;
1478         }
1479
1480         DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
1481
1482         if (memsize == i) {
1483                 for (i = 0; i < 32; i++) {
1484                         /* Clear first 32MB ; 0 is 0, no need to byteswap */
1485                         writel(0x0000000,
1486                                (l_fb_info->v_fb + (i * 1048576)));
1487                         mb();
1488                 }
1489
1490                 for (i = 32; i < 64; i++) {
1491 #ifdef KERNEL_2_2
1492 #ifdef MUST_BYTESWAP
1493                         writel(__swab32(i * 0x00345678),
1494                                (l_fb_info->v_fb + (i * 1048576)));
1495 #else
1496                         writel(i * 0x00345678,
1497                                (l_fb_info->v_fb + (i * 1048576)));
1498 #endif
1499                         mb();
1500 #ifdef MUST_BYTESWAP
1501                         temp1 =
1502                             __swab32(readl
1503                                      ((l_fb_info->v_fb + (i * 1048576))));
1504                         temp2 =
1505                             __swab32(readl
1506                                      ((l_fb_info->v_fb +
1507                                        ((i - 32) * 1048576))));
1508 #else
1509                         temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
1510                         temp2 =
1511                             readl((l_fb_info->v_fb +
1512                                    ((i - 32) * 1048576)));
1513 #endif
1514 #endif /* KERNEL_2_2 */
1515 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
1516                         fb_writel(i * 0x00345678,
1517                                   (l_fb_info->v_fb + (i * 1048576)));
1518                         mb();
1519                         temp1 =
1520                             fb_readl((l_fb_info->v_fb + (i * 1048576)));
1521                         temp2 =
1522                             fb_readl((l_fb_info->v_fb +
1523                                       ((i - 32) * 1048576)));
1524 #endif /* KERNEL_2_4 or KERNEL_2_5 */
1525                         if ((temp1 == (i * 0x00345678)) && (temp2 == 0))        /* different value, different RAM... */
1526                                 memsize = i;
1527                         else
1528                                 break;
1529                 }
1530         }
1531
1532         DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
1533
1534         PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
1535
1536         pm3fb_unmapIO(l_fb_info);
1537         memsize = 1048576 * (memsize + 1);
1538
1539         DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
1540
1541         if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
1542         {
1543                 printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
1544                 memsize = 1048576 * forcesize[l_fb_info->board_num];
1545         }
1546         
1547         l_fb_info->fb_size = memsize;
1548         
1549         if (ptr == pm3fb_timing_retry)
1550         {
1551                 printk(KERN_WARNING "pm3fb: retrying memory timings check");
1552                 if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
1553                         return(0);
1554         }
1555         
1556         return (memsize);
1557 }
1558
1559 static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
1560 {
1561         int i;
1562
1563         DTRACE;
1564
1565         for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
1566         {
1567 #ifdef KERNEL_2_2
1568 #ifdef MUST_BYTESWAP
1569                 writel(__swab32(cc), (l_fb_info->v_fb + (i * sizeof(u32))));
1570 #else
1571                 writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
1572 #endif
1573 #endif
1574 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
1575                 fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
1576 #endif
1577         }
1578 }
1579
1580 static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
1581 {
1582         int i;
1583
1584         DTRACE;
1585
1586         for (i = 0; i < 256 ; i++) /* fill color map with white */
1587                 pm3fb_set_color(l_fb_info, i, r, g, b);
1588
1589 }
1590
1591 /* common initialisation */
1592 static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
1593 {
1594         DTRACE;
1595
1596         DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
1597                 (unsigned long) l_fb_info);
1598
1599         strcpy(l_fb_info->gen.info.modename, permedia3_name);
1600         disp[l_fb_info->board_num].scrollmode = 0;      /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
1601         l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
1602         l_fb_info->gen.info.changevar = NULL;
1603         l_fb_info->gen.info.node = B_FREE;
1604         l_fb_info->gen.info.fbops = &pm3fb_ops;
1605         l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
1606         if (fontn[l_fb_info->board_num][0])
1607                 strcpy(l_fb_info->gen.info.fontname,
1608                        fontn[l_fb_info->board_num]);
1609         l_fb_info->gen.info.switch_con = &fbgen_switch;
1610         l_fb_info->gen.info.updatevar = &fbgen_update_var;      /* */
1611         l_fb_info->gen.info.blank = &fbgen_blank;       /* */
1612         l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
1613
1614         pm3fb_mapIO(l_fb_info);
1615
1616         pm3fb_clear_memory(l_fb_info, 0);
1617         pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
1618
1619         (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
1620                              &l_fb_info->gen.info);
1621
1622         if (depth[l_fb_info->board_num]) /* override mode-defined depth */
1623         {
1624                 pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
1625                 (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
1626         }
1627
1628         (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
1629                                 &l_fb_info->gen);
1630
1631         fbgen_set_disp(-1, &l_fb_info->gen);
1632
1633         fbgen_install_cmap(0, &l_fb_info->gen);
1634
1635         if (register_framebuffer(&l_fb_info->gen.info) < 0) {
1636                 DPRINTK(1, "Couldn't register framebuffer\n");
1637                 return;
1638         }
1639
1640         PM3_WRITE_DAC_REG(PM3RD_CursorMode,
1641                           PM3RD_CursorMode_CURSOR_DISABLE);
1642         
1643         PM3_SHOW_CUR_MODE;
1644         
1645         pm3fb_write_mode(l_fb_info);
1646         
1647         printk("fb%d: %s, using %uK of video memory (%s)\n",
1648                GET_FB_IDX(l_fb_info->gen.info.node),
1649                permedia3_name, (u32) (l_fb_info->fb_size >> 10),
1650                cardbase[l_fb_info->board_type].cardname);
1651 }
1652
1653 /* **************************************************** */
1654 /* ***** accelerated permedia3-specific functions ***** */
1655 /* **************************************************** */
1656 #ifdef PM3FB_USE_ACCEL
1657 static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
1658 {
1659         DTRACE;
1660
1661         PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
1662         PM3_SLOW_WRITE_REG(PM3Sync, 0);
1663         mb();
1664         do {
1665                 while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
1666                 rmb();
1667         } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
1668 }
1669
1670 static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
1671 {
1672         PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
1673         PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
1674         PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
1675         PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
1676         PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
1677         PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
1678         PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
1679         PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
1680         PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
1681         PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
1682         PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
1683         PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
1684         PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
1685         PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
1686         PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
1687         PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
1688         PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
1689         PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
1690         PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
1691         PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
1692         PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
1693         PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
1694         PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
1695         PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
1696         PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
1697         PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
1698         PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
1699         PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
1700         PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
1701         PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
1702         PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
1703         PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
1704         PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
1705         PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
1706         PM3_SLOW_WRITE_REG(PM3Window, 0x0);
1707
1708         PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
1709
1710         PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
1711
1712         PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
1713         PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
1714         PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
1715
1716         PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
1717
1718         PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
1719                            PM3FBDestReadEnables_E(0xff) |
1720                            PM3FBDestReadEnables_R(0xff) |
1721                            PM3FBDestReadEnables_ReferenceAlpha(0xff));
1722         PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
1723         PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
1724         PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
1725                            PM3FBDestReadBufferWidth_Width(l_fb_info->
1726                                                           current_par->
1727                                                           width));
1728
1729         PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
1730                            PM3FBDestReadMode_ReadEnable |
1731                            PM3FBDestReadMode_Enable0);
1732         PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
1733         PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
1734         PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
1735                            PM3FBSourceReadBufferWidth_Width(l_fb_info->
1736                                                             current_par->
1737                                                             width));
1738         PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
1739                            PM3FBSourceReadMode_Blocking |
1740                            PM3FBSourceReadMode_ReadEnable);
1741
1742         {
1743                 unsigned long rm = 1;
1744                 switch (l_fb_info->current_par->depth) {
1745                 case 8:
1746                         PM3_SLOW_WRITE_REG(PM3PixelSize,
1747                                            PM3PixelSize_GLOBAL_8BIT);
1748                         break;
1749                 case 12:
1750                 case 15:
1751                 case 16:
1752                         PM3_SLOW_WRITE_REG(PM3PixelSize,
1753                                            PM3PixelSize_GLOBAL_16BIT);
1754                         break;
1755                 case 32:
1756                         PM3_SLOW_WRITE_REG(PM3PixelSize,
1757                                            PM3PixelSize_GLOBAL_32BIT);
1758                         break;
1759                 default:
1760                         DPRINTK(1, "Unsupported depth %d\n",
1761                                 l_fb_info->current_par->depth);
1762                         break;
1763                 }
1764                 PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
1765         }
1766
1767         PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
1768         PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
1769         PM3_SLOW_WRITE_REG(PM3FBWriteMode,
1770                            PM3FBWriteMode_WriteEnable |
1771                            PM3FBWriteMode_OpaqueSpan |
1772                            PM3FBWriteMode_Enable0);
1773         PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
1774         PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
1775         PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
1776                            PM3FBWriteBufferWidth_Width(l_fb_info->
1777                                                        current_par->
1778                                                        width));
1779
1780         PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
1781         {
1782                 unsigned long sofb = (8UL * l_fb_info->fb_size) /
1783                         ((depth2bpp(l_fb_info->current_par->depth))
1784                          * l_fb_info->current_par->width);      /* size in lines of FB */
1785                 if (sofb > 4095)
1786                         PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
1787                 else
1788                         PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
1789                 
1790                 switch (l_fb_info->current_par->depth) {
1791                 case 8:
1792                         PM3_SLOW_WRITE_REG(PM3DitherMode,
1793                                            (1 << 10) | (2 << 3));
1794                         break;
1795                 case 12:
1796                 case 15:
1797                 case 16:
1798                         PM3_SLOW_WRITE_REG(PM3DitherMode,
1799                                            (1 << 10) | (1 << 3));
1800                         break;
1801                 case 32:
1802                         PM3_SLOW_WRITE_REG(PM3DitherMode,
1803                                            (1 << 10) | (0 << 3));
1804                         break;
1805                 default:
1806                         DPRINTK(1, "Unsupported depth %d\n",
1807                                 l_fb_info->current_par->depth);
1808                         break;
1809                 }
1810         }
1811
1812         PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
1813         PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
1814         PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
1815         PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
1816         PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
1817         PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
1818         PM3_SLOW_WRITE_REG(PM3Count, 0x0);
1819         
1820 /* Disable LocalBuffer. better safe than sorry */
1821         PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
1822         PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
1823         PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
1824         PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
1825         
1826         pm3fb_wait_pm3(l_fb_info);
1827 }
1828
1829 #ifdef FBCON_HAS_CFB32
1830 static void pm3fb_cfb32_clear(struct vc_data *conp,
1831                               struct display *p,
1832                               int sy, int sx, int height, int width)
1833 {
1834         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
1835         u32 c;
1836
1837         DTRACE;
1838
1839         sx = sx * fontwidth(p);
1840         width = width * fontwidth(p);
1841         sy = sy * fontheight(p);
1842         height = height * fontheight(p);
1843         c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
1844
1845         /* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
1846            we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
1847         if ((l_fb_info->current_par->width > 1600) ||
1848             (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
1849                 PM3_WAIT(4);
1850
1851                 PM3_WRITE_REG(PM3Config2D,
1852                                           PM3Config2D_UseConstantSource |
1853                                           PM3Config2D_ForegroundROPEnable |
1854                                           (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
1855                                           PM3Config2D_FBWriteEnable);
1856
1857                 PM3_WRITE_REG(PM3ForegroundColor, c);
1858
1859                 PM3_WRITE_REG(PM3RectanglePosition,
1860                               (PM3RectanglePosition_XOffset(sx)) |
1861                               (PM3RectanglePosition_YOffset(sy)));
1862
1863                 PM3_WRITE_REG(PM3Render2D,
1864                               PM3Render2D_XPositive |
1865                               PM3Render2D_YPositive |
1866                               PM3Render2D_Operation_Normal |
1867                               PM3Render2D_SpanOperation |
1868                               (PM3Render2D_Width(width)) |
1869                               (PM3Render2D_Height(height)));
1870         } else {
1871                 PM3_WAIT(8);
1872
1873                 PM3_WRITE_REG(PM3FBBlockColor, c);
1874
1875                 PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
1876
1877                 PM3_WRITE_REG(PM3FBWriteBufferWidth0,
1878                               PM3FBWriteBufferWidth_Width(l_fb_info->
1879                                                           current_par->
1880                                                           width << 1));
1881
1882                 PM3_WRITE_REG(PM3Config2D,
1883                                           PM3Config2D_UseConstantSource |
1884                                           PM3Config2D_ForegroundROPEnable |
1885                                           (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
1886                                           PM3Config2D_FBWriteEnable);
1887
1888                 PM3_WRITE_REG(PM3RectanglePosition,
1889                               (PM3RectanglePosition_XOffset(sx << 1)) |
1890                               (PM3RectanglePosition_YOffset(sy)));
1891
1892                 PM3_WRITE_REG(PM3Render2D,
1893                               PM3Render2D_XPositive |
1894                               PM3Render2D_YPositive |
1895                               PM3Render2D_Operation_Normal |
1896                               (PM3Render2D_Width(width << 1)) |
1897                               (PM3Render2D_Height(height)));
1898
1899                 PM3_WRITE_REG(PM3FBWriteBufferWidth0,
1900                               PM3FBWriteBufferWidth_Width(l_fb_info->
1901                                                           current_par->
1902                                                           width));
1903
1904                 PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
1905         }
1906
1907         pm3fb_wait_pm3(l_fb_info);
1908 }
1909
1910 static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
1911                                       struct display *p, int bottom_only)
1912 {
1913         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
1914         int sx, sy;
1915         u32 c;
1916
1917         DTRACE;
1918
1919         sx = conp->vc_cols * fontwidth(p);      /* right margin */
1920         sy = conp->vc_rows * fontheight(p);     /* bottom margin */
1921         c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
1922
1923         if (!bottom_only) {     /* right margin top->bottom */
1924                 PM3_WAIT(4);
1925
1926                 PM3_WRITE_REG(PM3Config2D,
1927                                           PM3Config2D_UseConstantSource |
1928                                           PM3Config2D_ForegroundROPEnable |
1929                                           (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
1930                                           PM3Config2D_FBWriteEnable);
1931
1932                 PM3_WRITE_REG(PM3ForegroundColor, c);
1933
1934                 PM3_WRITE_REG(PM3RectanglePosition,
1935                               (PM3RectanglePosition_XOffset
1936                                (p->var.xoffset +
1937                                 sx)) | (PM3RectanglePosition_YOffset(p->
1938                                                                      var.
1939                                                                      yoffset)));
1940
1941                 PM3_WRITE_REG(PM3Render2D,
1942                               PM3Render2D_XPositive |
1943                               PM3Render2D_YPositive |
1944                               PM3Render2D_Operation_Normal |
1945                               PM3Render2D_SpanOperation |
1946                               (PM3Render2D_Width(p->var.xres - sx)) |
1947                               (PM3Render2D_Height(p->var.yres)));
1948         }
1949
1950         /* bottom margin left -> right */
1951         PM3_WAIT(4);
1952
1953         PM3_WRITE_REG(PM3Config2D,
1954                                   PM3Config2D_UseConstantSource |
1955                                   PM3Config2D_ForegroundROPEnable |
1956                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
1957                                   PM3Config2D_FBWriteEnable);
1958
1959         PM3_WRITE_REG(PM3ForegroundColor, c);
1960
1961         PM3_WRITE_REG(PM3RectanglePosition,
1962                       (PM3RectanglePosition_XOffset(p->var.xoffset)) |
1963                       (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
1964
1965         PM3_WRITE_REG(PM3Render2D,
1966                       PM3Render2D_XPositive |
1967                       PM3Render2D_YPositive |
1968                       PM3Render2D_Operation_Normal |
1969                       PM3Render2D_SpanOperation |
1970                       (PM3Render2D_Width(p->var.xres)) |
1971                       (PM3Render2D_Height(p->var.yres - sy)));
1972
1973         pm3fb_wait_pm3(l_fb_info);
1974 }
1975 #endif /* FBCON_HAS_CFB32 */
1976 #ifdef FBCON_HAS_CFB16
1977 static void pm3fb_cfb16_clear(struct vc_data *conp,
1978                               struct display *p,
1979                               int sy, int sx, int height, int width)
1980 {
1981         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
1982         u32 c;
1983
1984         DTRACE;
1985
1986         sx = sx * fontwidth(p);
1987         width = width * fontwidth(p);
1988         sy = sy * fontheight(p);
1989         height = height * fontheight(p);
1990         c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
1991         c = c | (c << 16);
1992
1993         PM3_WAIT(4);
1994
1995         if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
1996                 PM3_WRITE_REG(PM3ForegroundColor, c);
1997         else
1998                 PM3_WRITE_REG(PM3FBBlockColor, c);
1999
2000         PM3_WRITE_REG(PM3Config2D,
2001                                   PM3Config2D_UseConstantSource |
2002                                   PM3Config2D_ForegroundROPEnable |
2003                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2004                                   PM3Config2D_FBWriteEnable);
2005
2006         PM3_WRITE_REG(PM3RectanglePosition,
2007                       (PM3RectanglePosition_XOffset(sx)) |
2008                       (PM3RectanglePosition_YOffset(sy)));
2009         
2010         if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2011                 PM3_WRITE_REG(PM3Render2D,
2012                               PM3Render2D_XPositive |
2013                               PM3Render2D_YPositive |
2014                               PM3Render2D_Operation_Normal |
2015                               PM3Render2D_SpanOperation |
2016                               (PM3Render2D_Width(width)) |
2017                               (PM3Render2D_Height(height)));
2018         else
2019                 PM3_WRITE_REG(PM3Render2D,
2020                               PM3Render2D_XPositive |
2021                               PM3Render2D_YPositive |
2022                               PM3Render2D_Operation_Normal |
2023                               (PM3Render2D_Width(width)) |
2024                               (PM3Render2D_Height(height)));
2025         
2026         pm3fb_wait_pm3(l_fb_info);
2027 }
2028
2029 static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
2030                                       struct display *p, int bottom_only)
2031 {
2032         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2033         int sx, sy;
2034         u32 c;
2035
2036         DTRACE;
2037
2038         sx = conp->vc_cols * fontwidth(p);      /* right margin */
2039         sy = conp->vc_rows * fontheight(p);     /* bottom margin */
2040         c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
2041         c = c | (c << 16);
2042
2043         if (!bottom_only) {     /* right margin top->bottom */
2044                 PM3_WAIT(4);
2045
2046                 PM3_WRITE_REG(PM3Config2D,
2047                                           PM3Config2D_UseConstantSource |
2048                                           PM3Config2D_ForegroundROPEnable |
2049                                           (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2050                                           PM3Config2D_FBWriteEnable);
2051                 
2052                 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2053                         PM3_WRITE_REG(PM3ForegroundColor, c);
2054                 else
2055                         PM3_WRITE_REG(PM3FBBlockColor, c);
2056                 
2057                 PM3_WRITE_REG(PM3RectanglePosition,
2058                               (PM3RectanglePosition_XOffset
2059                                (p->var.xoffset +
2060                                 sx)) | (PM3RectanglePosition_YOffset(p->
2061                                                                      var.
2062                                                                      yoffset)));
2063                 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2064                         PM3_WRITE_REG(PM3Render2D,
2065                                       PM3Render2D_XPositive |
2066                                       PM3Render2D_YPositive |
2067                                       PM3Render2D_Operation_Normal |
2068                                       PM3Render2D_SpanOperation |
2069                                       (PM3Render2D_Width(p->var.xres - sx)) |
2070                                       (PM3Render2D_Height(p->var.yres)));
2071                 else
2072                         PM3_WRITE_REG(PM3Render2D,
2073                                       PM3Render2D_XPositive |
2074                                       PM3Render2D_YPositive |
2075                                       PM3Render2D_Operation_Normal |
2076                                       (PM3Render2D_Width(p->var.xres - sx)) |
2077                                       (PM3Render2D_Height(p->var.yres)));
2078         }
2079         
2080         /* bottom margin left -> right */
2081         PM3_WAIT(4);
2082         
2083         PM3_WRITE_REG(PM3Config2D,
2084                       PM3Config2D_UseConstantSource |
2085                       PM3Config2D_ForegroundROPEnable |
2086                       (PM3Config2D_ForegroundROP(0x3)) |        /* Ox3 is GXcopy */
2087                       PM3Config2D_FBWriteEnable);
2088         
2089         if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2090                 PM3_WRITE_REG(PM3ForegroundColor, c);
2091         else
2092                 PM3_WRITE_REG(PM3FBBlockColor, c);
2093         
2094         
2095         PM3_WRITE_REG(PM3RectanglePosition,
2096                       (PM3RectanglePosition_XOffset(p->var.xoffset)) |
2097                       (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
2098         
2099         if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2100                 PM3_WRITE_REG(PM3Render2D,
2101                               PM3Render2D_XPositive |
2102                               PM3Render2D_YPositive |
2103                               PM3Render2D_Operation_Normal |
2104                               PM3Render2D_SpanOperation |
2105                               (PM3Render2D_Width(p->var.xres)) |
2106                               (PM3Render2D_Height(p->var.yres - sy)));
2107         else
2108                 PM3_WRITE_REG(PM3Render2D,
2109                               PM3Render2D_XPositive |
2110                               PM3Render2D_YPositive |
2111                               PM3Render2D_Operation_Normal |
2112                               (PM3Render2D_Width(p->var.xres)) |
2113                               (PM3Render2D_Height(p->var.yres - sy)));
2114
2115         pm3fb_wait_pm3(l_fb_info);
2116 }
2117 #endif /* FBCON_HAS_CFB16 */
2118 #ifdef FBCON_HAS_CFB8
2119 static void pm3fb_cfb8_clear(struct vc_data *conp,
2120                              struct display *p,
2121                              int sy, int sx, int height, int width)
2122 {
2123         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2124         u32 c;
2125
2126         DTRACE;
2127
2128         sx = sx * fontwidth(p);
2129         width = width * fontwidth(p);
2130         sy = sy * fontheight(p);
2131         height = height * fontheight(p);
2132
2133         c = attr_bgcol_ec(p, conp);
2134         c |= c << 8;
2135         c |= c << 16;
2136
2137         PM3_WAIT(4);
2138
2139         PM3_WRITE_REG(PM3Config2D,
2140                                   PM3Config2D_UseConstantSource |
2141                                   PM3Config2D_ForegroundROPEnable |
2142                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2143                                   PM3Config2D_FBWriteEnable);
2144
2145         PM3_WRITE_REG(PM3ForegroundColor, c);
2146
2147         PM3_WRITE_REG(PM3RectanglePosition,
2148                       (PM3RectanglePosition_XOffset(sx)) |
2149                       (PM3RectanglePosition_YOffset(sy)));
2150
2151         PM3_WRITE_REG(PM3Render2D,
2152                       PM3Render2D_XPositive |
2153                       PM3Render2D_YPositive |
2154                       PM3Render2D_Operation_Normal |
2155                       PM3Render2D_SpanOperation |
2156                       (PM3Render2D_Width(width)) |
2157                       (PM3Render2D_Height(height)));
2158
2159         pm3fb_wait_pm3(l_fb_info);
2160 }
2161
2162 static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
2163                                      struct display *p, int bottom_only)
2164 {
2165         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2166         int sx, sy;
2167         u32 c;
2168
2169         DTRACE;
2170
2171         sx = conp->vc_cols * fontwidth(p);      /* right margin */
2172         sy = conp->vc_rows * fontheight(p);     /* bottom margin */
2173         c = attr_bgcol_ec(p, conp);
2174         c |= c << 8;
2175         c |= c << 16;
2176
2177         if (!bottom_only) {     /* right margin top->bottom */
2178                 PM3_WAIT(4);
2179
2180                 PM3_WRITE_REG(PM3Config2D,
2181                                           PM3Config2D_UseConstantSource |
2182                                           PM3Config2D_ForegroundROPEnable |
2183                                           (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2184                                           PM3Config2D_FBWriteEnable);
2185
2186                 PM3_WRITE_REG(PM3ForegroundColor, c);
2187
2188                 PM3_WRITE_REG(PM3RectanglePosition,
2189                               (PM3RectanglePosition_XOffset
2190                                (p->var.xoffset +
2191                                 sx)) | (PM3RectanglePosition_YOffset(p->
2192                                                                      var.
2193                                                                      yoffset)));
2194
2195                 PM3_WRITE_REG(PM3Render2D,
2196                               PM3Render2D_XPositive |
2197                               PM3Render2D_YPositive |
2198                               PM3Render2D_Operation_Normal |
2199                               PM3Render2D_SpanOperation |
2200                               (PM3Render2D_Width(p->var.xres - sx)) |
2201                               (PM3Render2D_Height(p->var.yres)));
2202         }
2203
2204         /* bottom margin left -> right */
2205         PM3_WAIT(4);
2206
2207         PM3_WRITE_REG(PM3Config2D,
2208                                   PM3Config2D_UseConstantSource |
2209                                   PM3Config2D_ForegroundROPEnable |
2210                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2211                                   PM3Config2D_FBWriteEnable);
2212
2213         PM3_WRITE_REG(PM3ForegroundColor, c);
2214
2215         PM3_WRITE_REG(PM3RectanglePosition,
2216                       (PM3RectanglePosition_XOffset(p->var.xoffset)) |
2217                       (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
2218
2219         PM3_WRITE_REG(PM3Render2D,
2220                       PM3Render2D_XPositive |
2221                       PM3Render2D_YPositive |
2222                       PM3Render2D_Operation_Normal |
2223                       PM3Render2D_SpanOperation |
2224                       (PM3Render2D_Width(p->var.xres)) |
2225                       (PM3Render2D_Height(p->var.yres - sy)));
2226
2227         pm3fb_wait_pm3(l_fb_info);
2228 }
2229 #endif /* FBCON_HAS_CFB8 */
2230 #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
2231 static void pm3fb_cfbX_bmove(struct display *p,
2232                              int sy, int sx,
2233                              int dy, int dx, int height, int width)
2234 {
2235         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2236         int x_align, o_x, o_y;
2237
2238         DTRACE;
2239
2240         sx = sx * fontwidth(p);
2241         dx = dx * fontwidth(p);
2242         width = width * fontwidth(p);
2243         sy = sy * fontheight(p);
2244         dy = dy * fontheight(p);
2245         height = height * fontheight(p);
2246
2247         o_x = sx - dx;          /*(sx > dx ) ? (sx - dx) : (dx - sx); */
2248         o_y = sy - dy;          /*(sy > dy ) ? (sy - dy) : (dy - sy); */
2249
2250         x_align = (sx & 0x1f);
2251
2252         PM3_WAIT(6);
2253
2254         PM3_WRITE_REG(PM3Config2D,
2255                                   PM3Config2D_UserScissorEnable |
2256                                   PM3Config2D_ForegroundROPEnable |
2257                                   PM3Config2D_Blocking |
2258                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2259                                   PM3Config2D_FBWriteEnable);
2260
2261         PM3_WRITE_REG(PM3ScissorMinXY,
2262                       ((dy & 0x0fff) << 16) | (dx & 0x0fff));
2263         PM3_WRITE_REG(PM3ScissorMaxXY,
2264                                   (((dy + height) & 0x0fff) << 16) |
2265                                   ((dx + width) & 0x0fff));
2266
2267         PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
2268                       PM3FBSourceReadBufferOffset_XOffset(o_x) |
2269                       PM3FBSourceReadBufferOffset_YOffset(o_y));
2270
2271         PM3_WRITE_REG(PM3RectanglePosition,
2272                       (PM3RectanglePosition_XOffset(dx - x_align)) |
2273                       (PM3RectanglePosition_YOffset(dy)));
2274
2275         PM3_WRITE_REG(PM3Render2D,
2276                       ((sx > dx) ? PM3Render2D_XPositive : 0) |
2277                       ((sy > dy) ? PM3Render2D_YPositive : 0) |
2278                       PM3Render2D_Operation_Normal |
2279                       PM3Render2D_SpanOperation |
2280                       PM3Render2D_FBSourceReadEnable |
2281                       (PM3Render2D_Width(width + x_align)) |
2282                       (PM3Render2D_Height(height)));
2283
2284         pm3fb_wait_pm3(l_fb_info);
2285 }
2286
2287 static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
2288                             int c, int yy, int xx)
2289 {
2290         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2291         u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
2292         u32 fgx, bgx, ldat;
2293         int sx, sy, i;
2294
2295         DTRACE;
2296
2297         if (l_fb_info->current_par->depth == 8)
2298                 fgx = attr_fgcol(p, c);
2299         else if (depth2bpp(l_fb_info->current_par->depth) == 16)
2300                 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
2301         else
2302                 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
2303
2304         PM3_COLOR(fgx);
2305
2306         if (l_fb_info->current_par->depth == 8)
2307                 bgx = attr_bgcol(p, c);
2308         else if (depth2bpp(l_fb_info->current_par->depth) == 16)
2309                 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
2310         else
2311                 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
2312
2313         PM3_COLOR(bgx);
2314
2315         PM3_WAIT(4);
2316
2317         PM3_WRITE_REG(PM3Config2D,
2318                                   PM3Config2D_UseConstantSource |
2319                                   PM3Config2D_ForegroundROPEnable |
2320                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2321                                   PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
2322
2323         PM3_WRITE_REG(PM3ForegroundColor, fgx);
2324         PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
2325
2326         /* WARNING : adress select X need to specify 8 bits for fontwidth <= 8 */
2327         /* and 16 bits for fontwidth <= 16 */
2328         /* same in _putcs, same for Y and fontheight */
2329         if (fontwidth(p) <= 8)
2330                 asx = 2;
2331         else if (fontwidth(p) <= 16)
2332                 asx = 3;        /* look OK */
2333         if (fontheight(p) <= 8)
2334                 asy = 2;
2335         else if (fontheight(p) <= 16)
2336                 asy = 3;        /* look OK */
2337         else if (fontheight(p) <= 32)
2338                 asy = 4;        /* look OK */
2339
2340         sx = xx * fontwidth(p);
2341         sy = yy * fontheight(p);
2342
2343         if (fontwidth(p) <= 8)
2344                 o_x = (8 - (sx & 0x7)) & 0x7;
2345         else if (fontwidth(p) <= 16)
2346                 o_x = (16 - (sx & 0xF)) & 0xF;
2347         if (fontheight(p) <= 8)
2348                 o_y = (8 - (sy & 0x7)) & 0x7;
2349         else if (fontheight(p) <= 16)
2350                 o_y = (16 - (sy & 0xF)) & 0xF;
2351         else if (fontheight(p) <= 32)
2352                 o_y = (32 - (sy & 0x1F)) & 0x1F;
2353
2354         PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) |    /* x_offset, y_offset in pattern */
2355                       (1 << 18) |       /* BE */
2356                       1 | (asx << 1) | (asy << 4) |     /* address select x/y */
2357                       (1 << 20));       /* OpaqueSpan */
2358
2359         if (fontwidth(p) <= 8) {
2360                 cdat = p->fontdata + (c & p->charmask) * fontheight(p);
2361         } else {
2362                 cdat =
2363                     p->fontdata +
2364                     ((c & p->charmask) * (fontheight(p) << 1));
2365         }
2366
2367         PM3_WAIT(2 + fontheight(p));
2368
2369         for (i = 0; i < fontheight(p); i++) {   /* assume fontheight <= 32 */
2370                 if (fontwidth(p) <= 8) {
2371                         ldat = *cdat++;
2372                 } else {        /* assume fontwidth <= 16 ATM */
2373
2374                         ldat = ((*cdat++) << 8);
2375                         ldat |= *cdat++;
2376                 }
2377                 PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
2378         }
2379
2380         PM3_WRITE_REG(PM3RectanglePosition,
2381                       (PM3RectanglePosition_XOffset(sx)) |
2382                       (PM3RectanglePosition_YOffset(sy)));
2383
2384         PM3_WRITE_REG(PM3Render2D,
2385                       PM3Render2D_AreaStippleEnable |
2386                       PM3Render2D_XPositive |
2387                       PM3Render2D_YPositive |
2388                       PM3Render2D_Operation_Normal |
2389                       PM3Render2D_SpanOperation |
2390                       (PM3Render2D_Width(fontwidth(p))) |
2391                       (PM3Render2D_Height(fontheight(p))));
2392
2393         pm3fb_wait_pm3(l_fb_info);
2394 }
2395
2396 static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
2397                              const unsigned short *s, int count, int yy,
2398                              int xx)
2399 {
2400         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2401         u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
2402         u32 fgx, bgx, ldat;
2403         int sx, sy, i, j;
2404         u16 sc;
2405
2406         DTRACE;
2407
2408         sc = scr_readw(s);
2409         if (l_fb_info->current_par->depth == 8)
2410                 fgx = attr_fgcol(p, sc);
2411         else if (depth2bpp(l_fb_info->current_par->depth) == 16)
2412                 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
2413         else
2414                 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
2415         
2416         PM3_COLOR(fgx);
2417         
2418         if (l_fb_info->current_par->depth == 8)
2419                 bgx = attr_bgcol(p, sc);
2420         else if (depth2bpp(l_fb_info->current_par->depth) == 16)
2421                 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
2422         else
2423                 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
2424         
2425         PM3_COLOR(bgx);
2426
2427         PM3_WAIT(4);
2428
2429         PM3_WRITE_REG(PM3Config2D,
2430                                   PM3Config2D_UseConstantSource |
2431                                   PM3Config2D_ForegroundROPEnable |
2432                                   (PM3Config2D_ForegroundROP(0x3)) |    /* Ox3 is GXcopy */
2433                                   PM3Config2D_FBWriteEnable |
2434                                   PM3Config2D_OpaqueSpan);
2435
2436         PM3_WRITE_REG(PM3ForegroundColor, fgx);
2437         PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
2438
2439         /* WARNING : adress select X need to specify 8 bits for fontwidth <= 8 */
2440         /* and 16 bits for fontwidth <= 16 */
2441         /* same in _putc, same for Y and fontheight */
2442         if (fontwidth(p) <= 8)
2443                 asx = 2;
2444         else if (fontwidth(p) <= 16)
2445                 asx = 3;        /* look OK */
2446         if (fontheight(p) <= 8)
2447                 asy = 2;
2448         else if (fontheight(p) <= 16)
2449                 asy = 3;        /* look OK */
2450         else if (fontheight(p) <= 32)
2451                 asy = 4;        /* look OK */
2452
2453         sy = yy * fontheight(p);
2454
2455         if (fontheight(p) <= 8)
2456                 o_y = (8 - (sy & 0x7)) & 0x7;
2457         else if (fontheight(p) <= 16)
2458                 o_y = (16 - (sy & 0xF)) & 0xF;
2459         else if (fontheight(p) <= 32)
2460                 o_y = (32 - (sy & 0x1F)) & 0x1F;
2461
2462         for (j = 0; j < count; j++) {
2463                 sc = scr_readw(s + j);
2464                 if (fontwidth(p) <= 8)
2465                         cdat = p->fontdata +
2466                                 (sc & p->charmask) * fontheight(p);
2467                 else
2468                         cdat = p->fontdata +
2469                                 ((sc & p->charmask) * fontheight(p) << 1);
2470                 
2471                 sx = (xx + j) * fontwidth(p);
2472
2473                 if (fontwidth(p) <= 8)
2474                         o_x = (8 - (sx & 0x7)) & 0x7;
2475                 else if (fontwidth(p) <= 16)
2476                         o_x = (16 - (sx & 0xF)) & 0xF;
2477
2478                 PM3_WAIT(3 + fontheight(p));
2479
2480                 PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
2481                               (1 << 18) | /* BE */
2482                               1 | (asx << 1) | (asy << 4) | /* address select x/y */
2483                               (1 << 20)); /* OpaqueSpan */
2484
2485                 for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
2486                         if (fontwidth(p) <= 8) {
2487                                 ldat = *cdat++;
2488                         } else { /* assume fontwidth <= 16 ATM */
2489                                 ldat = ((*cdat++) << 8);
2490                                 ldat |= *cdat++;
2491                         }
2492                         PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
2493                 }
2494
2495                 PM3_WRITE_REG(PM3RectanglePosition,
2496                               (PM3RectanglePosition_XOffset(sx)) |
2497                               (PM3RectanglePosition_YOffset(sy)));
2498
2499                 PM3_WRITE_REG(PM3Render2D,
2500                               PM3Render2D_AreaStippleEnable |
2501                               PM3Render2D_XPositive |
2502                               PM3Render2D_YPositive |
2503                               PM3Render2D_Operation_Normal |
2504                               PM3Render2D_SpanOperation |
2505                               (PM3Render2D_Width(fontwidth(p))) |
2506                               (PM3Render2D_Height(fontheight(p))));
2507         }
2508         pm3fb_wait_pm3(l_fb_info);
2509 }
2510
2511 static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
2512 {
2513         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
2514
2515         xx = xx * fontwidth(p);
2516         yy = yy * fontheight(p);
2517
2518         if (l_fb_info->current_par->depth == 8)
2519         {
2520                 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2521                         PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
2522                 else
2523                         PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
2524         }
2525
2526         PM3_WAIT(3);
2527
2528         PM3_WRITE_REG(PM3Config2D,
2529                                   PM3Config2D_UseConstantSource |
2530                                   PM3Config2D_ForegroundROPEnable |
2531                                   (PM3Config2D_ForegroundROP(0xa)) |    /* Oxa is GXinvert */
2532                                   PM3Config2D_FBDestReadEnable |
2533                                   PM3Config2D_FBWriteEnable);
2534
2535         PM3_WRITE_REG(PM3RectanglePosition,
2536                       (PM3RectanglePosition_XOffset(xx)) |
2537                       (PM3RectanglePosition_YOffset(yy)));
2538
2539         PM3_WRITE_REG(PM3Render2D,
2540                       PM3Render2D_XPositive |
2541                       PM3Render2D_YPositive |
2542                       PM3Render2D_Operation_Normal |
2543                       PM3Render2D_SpanOperation |
2544                       (PM3Render2D_Width(fontwidth(p))) |
2545                       (PM3Render2D_Height(fontheight(p))));
2546
2547         pm3fb_wait_pm3(l_fb_info);
2548
2549         if (l_fb_info->current_par->depth == 8)
2550         {
2551                 if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
2552                         PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
2553                 else
2554                         PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
2555         }
2556 }
2557
2558 #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
2559 #endif /* PM3FB_USE_ACCEL */
2560 /* *********************************** */
2561 /* ***** pre-init board(s) setup ***** */
2562 /* *********************************** */
2563
2564 static void pm3fb_mode_setup(char *mode, unsigned long board_num)
2565 {
2566         struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
2567         struct pm3fb_par *l_fb_par = &(current_par[board_num]);
2568         unsigned long i = 0;
2569
2570         current_par_valid[board_num] = 0;
2571
2572         if (!strncmp(mode, "current", 7)) {
2573                 l_fb_info->use_current = 1;     /* default w/ OpenFirmware */
2574         } else {
2575                 while ((mode_base[i].name[0])
2576                        && (!current_par_valid[board_num])) {
2577                         if (!
2578                             (strncmp
2579                              (mode, mode_base[i].name,
2580                               strlen(mode_base[i].name)))) {
2581                                 memcpy(l_fb_par, &(mode_base[i].user_mode),
2582                                        sizeof(struct pm3fb_par));
2583                                 current_par_valid[board_num] = 1;
2584                                 DPRINTK(2, "Mode set to %s\n",
2585                                         mode_base[i].name);
2586                         }
2587                         i++;
2588                 }
2589                 DASSERT(current_par_valid[board_num],
2590                         "Valid mode on command line\n");
2591         }
2592 }
2593
2594 static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
2595 {
2596         short l_bus = -1, l_slot = -1, l_func = -1;
2597         char *next;
2598
2599         if (pciid) {
2600                 l_bus = simple_strtoul(pciid, &next, 10);
2601                 if (next && (next[0] == ':')) {
2602                         pciid = next + 1;
2603                         l_slot = simple_strtoul(pciid, &next, 10);
2604                         if (next && (next[0] == ':')) {
2605                                 pciid = next + 1;
2606                                 l_func =
2607                                     simple_strtoul(pciid, (char **) NULL,
2608                                                    10);
2609                         }
2610                 }
2611         } else
2612                 return;
2613
2614         if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
2615                 bus[board_num] = l_bus;
2616                 slot[board_num] = l_slot;
2617                 func[board_num] = l_func;
2618                 DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
2619                         board_num, l_bus, l_slot, l_func);
2620         } else {
2621                 DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
2622                         l_bus, l_slot, l_func, board_num);
2623         }
2624 }
2625
2626 static void pm3fb_font_setup(char *lf, unsigned long board_num)
2627 {
2628         unsigned long lfs = strlen(lf);
2629
2630         if (lfs > (PM3_FONTNAME_SIZE - 1)) {
2631                 DPRINTK(1, "Fontname %s too long\n", lf);
2632                 return;
2633         }
2634         strncpy(fontn[board_num], lf, lfs);
2635         fontn[board_num][lfs] = '\0';
2636 }
2637
2638 static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
2639 {
2640         unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
2641
2642         if (!(depth_supported(bd))) {
2643                 printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
2644                        bds, board_num);
2645                 return;
2646         }
2647         depth[board_num] = bd;
2648 }
2649
2650 static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
2651 {
2652         unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
2653
2654         if (bd > 64) {
2655                 printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
2656                        bds, board_num);
2657                 return;
2658         }
2659         forcesize[board_num] = bd;
2660 }
2661
2662 static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
2663 {
2664         char *next;
2665
2666         if (!(CHAR_IS_NUM(options[0]))) {
2667                 (*bn) = 0;
2668                 return (options);
2669         }
2670
2671         (*bn) = simple_strtoul(options, &next, 10);
2672
2673         if (next && (next[0] == ':') && ((*bn) >= 0)
2674             && ((*bn) <= PM3_MAX_BOARD)) {
2675                 DPRINTK(2, "Board_num seen as %ld\n", (*bn));
2676                 return (next + 1);
2677         } else {
2678                 (*bn) = 0;
2679                 DPRINTK(2, "Board_num default to %ld\n", (*bn));
2680                 return (options);
2681         }
2682 }
2683
2684 static void pm3fb_real_setup(char *options)
2685 {
2686         char *next;
2687         unsigned long i, bn;
2688         struct pm3fb_info *l_fb_info;
2689
2690         DTRACE;
2691
2692         DPRINTK(2, "Options : %s\n", options);
2693
2694         for (i = 0; i < PM3_MAX_BOARD; i++) {
2695                 l_fb_info = &(fb_info[i]);
2696                 memset(l_fb_info, 0, sizeof(struct pm3fb_info));
2697                 l_fb_info->gen.fbhw = &pm3fb_switch;
2698                 l_fb_info->board_num = i;
2699                 current_par_valid[i] = 0;
2700                 slot[i] = -1;
2701                 func[i] = -1;
2702                 bus[i] = -1;
2703                 disable[i] = 0;
2704                 noaccel[i] = 0;
2705                 fontn[i][0] = '\0';
2706                 depth[i] = 0;
2707                 l_fb_info->current_par = &(current_par[i]);
2708         }
2709
2710         /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
2711         if (!strncmp(options, "pm3fb", 5)) {
2712                 options += 5;
2713                 while (((*options) == ',') || ((*options) == ':')
2714                        || ((*options) == '='))
2715                         options++;
2716         }
2717
2718         while (options) {
2719                 bn = 0;
2720                 if ((next = strchr(options, ','))) {
2721                         (*next) = '\0';
2722                         next++;
2723                 }
2724
2725                 if (!strncmp(options, "mode:", 5)) {
2726                         options = pm3fb_boardnum_setup(options + 5, &bn);
2727                         DPRINTK(2, "Setting mode for board #%ld\n", bn);
2728                         pm3fb_mode_setup(options, bn);
2729                 } else if (!strncmp(options, "off:", 4)) {
2730                         options = pm3fb_boardnum_setup(options + 4, &bn);
2731                         DPRINTK(2, "Disabling board #%ld\n", bn);
2732                         disable[bn] = 1;
2733                 } else if (!strncmp(options, "off", 3)) {       /* disable everything */
2734                         for (i = 0; i < PM3_MAX_BOARD; i++)
2735                                 disable[i] = 1;
2736                 } else if (!strncmp(options, "disable:", 8)) {
2737                         options = pm3fb_boardnum_setup(options + 8, &bn);
2738                         DPRINTK(2, "Disabling board #%ld\n", bn);
2739                         disable[bn] = 1;
2740                 } else if (!strncmp(options, "pciid:", 6)) {
2741                         options = pm3fb_boardnum_setup(options + 6, &bn);
2742                         DPRINTK(2, "Setting PciID for board #%ld\n", bn);
2743                         pm3fb_pciid_setup(options, bn);
2744                 } else if (!strncmp(options, "noaccel:", 8)) {
2745                         options = pm3fb_boardnum_setup(options + 8, &bn);
2746                         noaccel[bn] = 1;
2747                 } else if (!strncmp(options, "font:", 5)) {
2748                         options = pm3fb_boardnum_setup(options + 5, &bn);
2749                         pm3fb_font_setup(options, bn);
2750                 } else if (!strncmp(options, "depth:", 6)) {
2751                         options = pm3fb_boardnum_setup(options + 6, &bn);
2752                         pm3fb_bootdepth_setup(options, bn);
2753                 } else if (!strncmp(options, "printtimings", 12)) {
2754                         printtimings = 1;
2755                 } else if (!strncmp(options, "flatpanel:", 10)) {
2756                         options = pm3fb_boardnum_setup(options + 10, &bn);
2757                         flatpanel[bn] = 1;
2758                 } else if (!strncmp(options, "forcesize:", 10)) {
2759                         options = pm3fb_boardnum_setup(options + 10, &bn);
2760                         pm3fb_forcesize_setup(options, bn);
2761                 }
2762                 options = next;
2763         }
2764 }
2765
2766 /* ********************************************** */
2767 /* ***** framebuffer API standard functions ***** */
2768 /* ********************************************** */
2769
2770 static int pm3fb_open(struct fb_info *info, int user)
2771 {
2772         DTRACE;
2773
2774         MOD_INC_USE_COUNT;
2775
2776         return (0);
2777 }
2778
2779 static int pm3fb_release(struct fb_info *info, int user)
2780 {
2781         DTRACE;
2782
2783         MOD_DEC_USE_COUNT;
2784
2785         return (0);
2786 }
2787
2788 static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
2789                             const void *par, struct fb_info_gen *info)
2790 {
2791         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
2792         struct pm3fb_par *p = (struct pm3fb_par *) par;
2793
2794         DTRACE;
2795
2796         strcpy(fix->id, permedia3_name);
2797         fix->smem_start = (unsigned long)l_fb_info->p_fb;
2798         fix->smem_len = l_fb_info->fb_size;
2799         fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
2800         fix->mmio_len = PM3_REGS_SIZE;
2801 #ifdef PM3FB_USE_ACCEL
2802         if (!(noaccel[l_fb_info->board_num]))
2803                 fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
2804         else
2805 #endif /* PM3FB_USE_ACCEL */
2806                 fix->accel = FB_ACCEL_NONE;
2807         fix->type = FB_TYPE_PACKED_PIXELS;
2808         fix->visual =
2809             (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
2810         if (current_par_valid[l_fb_info->board_num])
2811                 fix->line_length =
2812                         l_fb_info->current_par->width *
2813                         depth2ByPP(l_fb_info->current_par->depth);
2814         else
2815                 fix->line_length = 0;
2816         fix->xpanstep = 64 / depth2bpp(p->depth);
2817         fix->ypanstep = 1;
2818         fix->ywrapstep = 0;
2819         return (0);
2820 }
2821
2822 static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
2823                             void *par, struct fb_info_gen *info)
2824 {
2825         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
2826         struct pm3fb_par *p = (struct pm3fb_par *) par;
2827         struct pm3fb_par temp_p;
2828         u32 xres;
2829
2830         DTRACE;
2831
2832         DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
2833         DASSERT((p != NULL), "pm3fb_par* not NULL");
2834         DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
2835
2836         memset(&temp_p, 0, sizeof(struct pm3fb_par));
2837         temp_p.width = (var->xres_virtual + 7) & ~7;
2838         temp_p.height = var->yres_virtual;
2839
2840         if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
2841                 temp_p.depth = depth2bpp(var->bits_per_pixel);
2842         else
2843                 temp_p.depth = var->bits_per_pixel;
2844
2845         temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
2846         temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
2847
2848         if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
2849                 temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
2850
2851         if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
2852                 temp_p.depth = 12; /* RGBA 4444  is stored as depth 12 */
2853
2854
2855         DPRINTK(2,
2856                 "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
2857                 var->xres, var->yres, var->xres_virtual, var->yres_virtual,
2858                 var->xoffset, var->yoffset);
2859
2860         xres = (var->xres + 31) & ~31;
2861         if (temp_p.width < xres + var->xoffset)
2862                 temp_p.width = xres + var->xoffset;
2863         if (temp_p.height < var->yres + var->yoffset)
2864                 temp_p.height = var->yres + var->yoffset;
2865
2866         if (temp_p.width > 2048) {
2867                 DPRINTK(1, "virtual width not supported: %u\n",
2868                         temp_p.width);
2869                 return (-EINVAL);
2870         }
2871         if (var->yres < 200) {
2872                 DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
2873                 return (-EINVAL);
2874         }
2875         if (temp_p.height < 200 || temp_p.height > 4095) {
2876                 DPRINTK(1, "virtual height not supported: %u\n",
2877                         temp_p.height);
2878                 return (-EINVAL);
2879         }
2880         if (!(depth_supported(temp_p.depth))) {
2881                 DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
2882                 return (-EINVAL);
2883         }
2884         if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
2885             l_fb_info->fb_size) {
2886                 DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
2887                         temp_p.width, temp_p.height, temp_p.depth);
2888                 return (-EINVAL);
2889         }
2890
2891         if ((!var->pixclock) ||
2892             (!var->right_margin) ||
2893             (!var->hsync_len) ||
2894             (!var->left_margin) ||
2895             (!var->lower_margin) ||
2896             (!var->vsync_len) || (!var->upper_margin)
2897             ) {
2898                 unsigned long i = 0, done = 0;
2899                 printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
2900
2901                 while ((mode_base[i].user_mode.width) && !done) {
2902                         if ((mode_base[i].user_mode.width == temp_p.width)
2903                             && (mode_base[i].user_mode.height ==
2904                                 temp_p.height)) {
2905                                 printk(KERN_NOTICE "pm3fb: using close match %s\n",
2906                                        mode_base[i].name);
2907                                 temp_p = mode_base[i].user_mode;
2908                                 done = 1;
2909                         }
2910                         i++;
2911                 }
2912                 if (!done)
2913                         return (-EINVAL);
2914         } else {
2915                 temp_p.pixclock = PICOS2KHZ(var->pixclock);
2916                 if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
2917                         DPRINTK(1, "pixclock too high (%uKHz)\n",
2918                                 temp_p.pixclock);
2919                         return (-EINVAL);
2920                 }
2921
2922                 temp_p.hsstart = var->right_margin;
2923                 temp_p.hsend = var->right_margin + var->hsync_len;
2924                 temp_p.hbend =
2925                     var->right_margin + var->hsync_len + var->left_margin;
2926                 temp_p.htotal = xres + temp_p.hbend;
2927
2928                 temp_p.vsstart = var->lower_margin;
2929                 temp_p.vsend = var->lower_margin + var->vsync_len;
2930                 temp_p.vbend =
2931                     var->lower_margin + var->vsync_len + var->upper_margin;
2932                 temp_p.vtotal = var->yres + temp_p.vbend;
2933
2934                 temp_p.stride = temp_p.width;
2935
2936                 DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
2937                         temp_p.width, temp_p.height, temp_p.pixclock,
2938                         temp_p.stride);
2939
2940                 temp_p.base =
2941                     pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
2942                                    (var->yoffset * xres) + var->xoffset);
2943
2944                 temp_p.video = 0;
2945
2946                 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
2947                         temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
2948                 else
2949                         temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
2950
2951                 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
2952                         temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
2953                 else
2954                         temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
2955
2956                 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
2957                         DPRINTK(1, "Interlaced mode not supported\n\n");
2958                         return (-EINVAL);
2959                 }
2960
2961                 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
2962                         temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
2963                 else
2964                         temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
2965
2966                 if (var->activate == FB_ACTIVATE_NOW)
2967                         temp_p.video |= PM3VideoControl_ENABLE;
2968                 else {
2969                         temp_p.video |= PM3VideoControl_DISABLE;
2970                         DPRINTK(2, "PM3Video disabled\n");
2971                 }
2972
2973                 switch (temp_p.depth) {
2974                 case 8:
2975                         temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
2976                         break;
2977                 case 12:
2978                 case 15:
2979                 case 16:
2980                         temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
2981                         break;
2982                 case 32:
2983                         temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
2984                         break;
2985                 default:
2986                         DPRINTK(1, "Unsupported depth\n");
2987                         break;
2988                 }
2989         }
2990         (*p) = temp_p;
2991
2992 #ifdef PM3FB_USE_ACCEL
2993         if (var->accel_flags & FB_ACCELF_TEXT)
2994                 noaccel[l_fb_info->board_num] = 0;
2995         else
2996                 noaccel[l_fb_info->board_num] = 1;
2997 #endif /* PM3FB_USE_ACCEL */
2998
2999         return (0);
3000 }
3001
3002 static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
3003 {
3004         switch (d) {
3005         case 8:
3006                 var->red.length = var->green.length = var->blue.length = 8;
3007                 var->red.offset = var->green.offset = var->blue.offset = 0;
3008                 var->transp.offset = var->transp.length = 0;
3009                 break;
3010
3011         case 12:
3012                 var->red.offset = 8;
3013                 var->red.length = 4;
3014                 var->green.offset = 4;
3015                 var->green.length = 4;
3016                 var->blue.offset = 0;
3017                 var->blue.length = 4;
3018                 var->transp.offset = 12;
3019                 var->transp.length = 4;
3020                 break;
3021
3022         case 15:
3023                 var->red.offset = 10;
3024                 var->red.length = 5;
3025                 var->green.offset = 5;
3026                 var->green.length = 5;
3027                 var->blue.offset = 0;
3028                 var->blue.length = 5;
3029                 var->transp.offset = 15;
3030                 var->transp.length = 1;
3031                 break;
3032
3033         case 16:
3034                 var->red.offset = 11;
3035                 var->red.length = 5;
3036                 var->green.offset = 5;
3037                 var->green.length = 6;
3038                 var->blue.offset = 0;
3039                 var->blue.length = 5;
3040                 var->transp.offset = var->transp.length = 0;
3041                 break;
3042
3043         case 32:
3044                 var->transp.offset = 24;
3045                 var->red.offset = 16;
3046                 var->green.offset = 8;
3047                 var->blue.offset = 0;
3048                 var->red.length = var->green.length =
3049                         var->blue.length = var->transp.length = 8;
3050                 break;
3051
3052         default:
3053                 DPRINTK(1, "Unsupported depth %ld\n", d);
3054                 break;
3055         }
3056 }
3057
3058 static int pm3fb_encode_var(struct fb_var_screeninfo *var,
3059                             const void *par, struct fb_info_gen *info)
3060 {
3061         struct pm3fb_par *p = (struct pm3fb_par *) par;
3062         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3063
3064         u32 base;
3065
3066         DTRACE;
3067
3068         DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
3069         DASSERT((p != NULL), "pm3fb_par* not NULL");
3070         DASSERT((info != NULL), "fb_info_gen* not NULL");
3071
3072         memset(var, 0, sizeof(struct fb_var_screeninfo));
3073
3074 #ifdef PM3FB_USE_ACCEL
3075         if (!(noaccel[l_fb_info->board_num]))
3076                 var->accel_flags |= FB_ACCELF_TEXT;
3077 #endif /* PM3FB_USE_ACCEL */
3078
3079         var->xres_virtual = p->width;
3080         var->yres_virtual = p->height;
3081         var->xres = p->htotal - p->hbend;
3082         var->yres = p->vtotal - p->vbend;
3083
3084         DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
3085
3086         var->right_margin = p->hsstart;
3087         var->hsync_len = p->hsend - p->hsstart;
3088         var->left_margin = p->hbend - p->hsend;
3089         var->lower_margin = p->vsstart;
3090         var->vsync_len = p->vsend - p->vsstart;
3091         var->upper_margin = p->vbend - p->vsend;
3092         var->bits_per_pixel = depth2bpp(p->depth);
3093         
3094         pm3fb_encode_depth(var, p->depth);
3095
3096         base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
3097
3098         var->xoffset = base % var->xres;
3099         var->yoffset = base / var->xres;
3100
3101         var->height = var->width = -1;
3102
3103         var->pixclock = KHZ2PICOS(p->pixclock);
3104
3105         if ((p->video & PM3VideoControl_HSYNC_MASK) ==
3106             PM3VideoControl_HSYNC_ACTIVE_HIGH)
3107                 var->sync |= FB_SYNC_HOR_HIGH_ACT;
3108         if ((p->video & PM3VideoControl_VSYNC_MASK) ==
3109             PM3VideoControl_VSYNC_ACTIVE_HIGH)
3110                 var->sync |= FB_SYNC_VERT_HIGH_ACT;
3111         if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
3112                 var->vmode = FB_VMODE_DOUBLE;
3113
3114         return (0);
3115 }
3116
3117 static void pm3fb_get_par(void *par, struct fb_info_gen *info)
3118 {
3119         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3120
3121         DTRACE;
3122
3123         if (!current_par_valid[l_fb_info->board_num]) {
3124                 if (l_fb_info->use_current)
3125                         pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
3126                 else
3127                         memcpy(l_fb_info->current_par,
3128                                &(mode_base[0].user_mode),
3129                                sizeof(struct pm3fb_par));
3130                 current_par_valid[l_fb_info->board_num] = 1;
3131         }
3132         *((struct pm3fb_par *) par) = *(l_fb_info->current_par);
3133 }
3134
3135 static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
3136 {
3137         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3138
3139         DTRACE;
3140
3141         *(l_fb_info->current_par) = *((struct pm3fb_par *) par);
3142         current_par_valid[l_fb_info->board_num] = 1;
3143
3144         pm3fb_write_mode(l_fb_info);
3145
3146 #ifdef PM3FB_USE_ACCEL
3147         pm3fb_init_engine(l_fb_info);
3148 #endif /* PM3FB_USE_ACCEL */
3149 }
3150
3151 static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
3152                             unsigned char regno, unsigned char r,
3153                             unsigned char g, unsigned char b)
3154 {
3155         DTRACE;
3156
3157         PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
3158         PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
3159         PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
3160         PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
3161 }
3162
3163 static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
3164                            unsigned *blue, unsigned *transp,
3165                            struct fb_info *info)
3166 {
3167         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3168
3169         DTRACE;
3170
3171         if (regno < 256) {
3172                 *red =
3173                     l_fb_info->palette[regno].red << 8 | l_fb_info->
3174                     palette[regno].red;
3175                 *green =
3176                     l_fb_info->palette[regno].green << 8 | l_fb_info->
3177                     palette[regno].green;
3178                 *blue =
3179                     l_fb_info->palette[regno].blue << 8 | l_fb_info->
3180                     palette[regno].blue;
3181                 *transp =
3182                     l_fb_info->palette[regno].transp << 8 | l_fb_info->
3183                     palette[regno].transp;
3184         }
3185         return (regno > 255);
3186 }
3187
3188 static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
3189                            unsigned blue, unsigned transp,
3190                            struct fb_info *info)
3191 {
3192         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3193
3194         DTRACE;
3195
3196         if (regno < 16) {
3197                 switch (l_fb_info->current_par->depth) {
3198 #ifdef FBCON_HAS_CFB8
3199                 case 8:
3200                         break;
3201 #endif
3202 #ifdef FBCON_HAS_CFB16
3203                 case 12:
3204                         l_fb_info->cmap.cmap12[regno] =
3205                                 (((u32) red & 0xf000) >> 4) |
3206                                 (((u32) green & 0xf000) >> 8) |
3207                                 (((u32) blue & 0xf000) >> 12);
3208                         break;
3209
3210                 case 15:
3211                         l_fb_info->cmap.cmap15[regno] =
3212                                 (((u32) red & 0xf800) >> 1) |
3213                                 (((u32) green & 0xf800) >> 6) |
3214                                 (((u32) blue & 0xf800) >> 11);
3215                         break;
3216
3217                 case 16:
3218                         l_fb_info->cmap.cmap16[regno] =
3219                             ((u32) red & 0xf800) |
3220                             (((u32) green & 0xfc00) >> 5) |
3221                             (((u32) blue & 0xf800) >> 11);
3222                         break;
3223 #endif
3224 #ifdef FBCON_HAS_CFB32
3225                 case 32:
3226                         l_fb_info->cmap.cmap32[regno] =
3227                             (((u32) transp & 0xff00) << 16) |
3228                             (((u32) red & 0xff00) << 8) |
3229                             (((u32) green & 0xff00)) |
3230                             (((u32) blue & 0xff00) >> 8);
3231                         break;
3232 #endif
3233                 default:
3234                         DPRINTK(1, "bad depth %u\n",
3235                                 l_fb_info->current_par->depth);
3236                         break;
3237                 }
3238         }
3239         if (regno < 256) {
3240                 l_fb_info->palette[regno].red = red >> 8;
3241                 l_fb_info->palette[regno].green = green >> 8;
3242                 l_fb_info->palette[regno].blue = blue >> 8;
3243                 l_fb_info->palette[regno].transp = transp >> 8;
3244                 if (l_fb_info->current_par->depth == 8)
3245                         pm3fb_set_color(l_fb_info, regno, red >> 8,
3246                                         green >> 8, blue >> 8);
3247         }
3248         return (regno > 255);
3249 }
3250
3251 static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
3252 {
3253         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3254         u32 video;
3255
3256         DTRACE;
3257
3258         if (!current_par_valid[l_fb_info->board_num])
3259                 return (1);
3260
3261         video = l_fb_info->current_par->video;
3262
3263         /*
3264          * Oxygen VX1 - it appears that setting PM3VideoControl and
3265          * then PM3RD_SyncControl to the same SYNC settings undoes
3266          * any net change - they seem to xor together.  Only set the
3267          * sync options in PM3RD_SyncControl.  --rmk
3268          */
3269         video &= ~(PM3VideoControl_HSYNC_MASK |
3270                    PM3VideoControl_VSYNC_MASK);
3271         video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
3272                  PM3VideoControl_VSYNC_ACTIVE_HIGH;
3273
3274         if (blank_mode > 0) {
3275                 switch (blank_mode - 1) {
3276
3277                 case VESA_NO_BLANKING:  /* FIXME */
3278                         video = video & ~(PM3VideoControl_ENABLE);
3279                         break;
3280
3281                 case VESA_HSYNC_SUSPEND:
3282                         video = video & ~(PM3VideoControl_HSYNC_MASK |
3283                                           PM3VideoControl_BLANK_ACTIVE_LOW);
3284                         break;
3285                 case VESA_VSYNC_SUSPEND:
3286                         video = video & ~(PM3VideoControl_VSYNC_MASK |
3287                                           PM3VideoControl_BLANK_ACTIVE_LOW);
3288                         break;
3289                 case VESA_POWERDOWN:
3290                         video = video & ~(PM3VideoControl_HSYNC_MASK |
3291                                           PM3VideoControl_VSYNC_MASK |
3292                                           PM3VideoControl_BLANK_ACTIVE_LOW);
3293                         break;
3294                 default:
3295                         DPRINTK(1, "Unsupported blanking %d\n",
3296                                 blank_mode);
3297                         return (1);
3298                         break;
3299                 }
3300         }
3301
3302         PM3_SLOW_WRITE_REG(PM3VideoControl, video);
3303
3304         return (0);
3305 }
3306
3307 static void pm3fb_set_disp(const void *par, struct display *disp,
3308                            struct fb_info_gen *info)
3309 {
3310         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3311         struct pm3fb_par *p = (struct pm3fb_par *) par;
3312         u32 flags;
3313
3314         DTRACE;
3315
3316         save_flags(flags);
3317         cli();
3318         disp->screen_base = l_fb_info->v_fb;
3319         switch (p->depth) {
3320 #ifdef FBCON_HAS_CFB8
3321         case 8:
3322 #ifdef PM3FB_USE_ACCEL
3323                 if (!(noaccel[l_fb_info->board_num]))
3324                         disp->dispsw = &pm3fb_cfb8;
3325                 else
3326 #endif /* PM3FB_USE_ACCEL */
3327                         disp->dispsw = &fbcon_cfb8;
3328                 break;
3329 #endif
3330 #ifdef FBCON_HAS_CFB16
3331         case 12:
3332 #ifdef PM3FB_USE_ACCEL
3333                 if (!(noaccel[l_fb_info->board_num]))
3334                         disp->dispsw = &pm3fb_cfb16;
3335                 else
3336 #endif /* PM3FB_USE_ACCEL */
3337                         disp->dispsw = &fbcon_cfb16;
3338                 disp->dispsw_data = l_fb_info->cmap.cmap12;
3339                 break;
3340         case 15:
3341 #ifdef PM3FB_USE_ACCEL
3342                 if (!(noaccel[l_fb_info->board_num]))
3343                         disp->dispsw = &pm3fb_cfb16;
3344                 else
3345 #endif /* PM3FB_USE_ACCEL */
3346                         disp->dispsw = &fbcon_cfb16;
3347                 disp->dispsw_data = l_fb_info->cmap.cmap15;
3348                 break;
3349         case 16:
3350 #ifdef PM3FB_USE_ACCEL
3351                 if (!(noaccel[l_fb_info->board_num]))
3352                         disp->dispsw = &pm3fb_cfb16;
3353                 else
3354 #endif /* PM3FB_USE_ACCEL */
3355                         disp->dispsw = &fbcon_cfb16;
3356                 disp->dispsw_data = l_fb_info->cmap.cmap16;
3357                 break;
3358 #endif
3359 #ifdef FBCON_HAS_CFB32
3360         case 32:
3361 #ifdef PM3FB_USE_ACCEL
3362                 if (!(noaccel[l_fb_info->board_num]))
3363                         disp->dispsw = &pm3fb_cfb32;
3364                 else
3365 #endif /* PM3FB_USE_ACCEL */
3366                         disp->dispsw = &fbcon_cfb32;
3367                 disp->dispsw_data = l_fb_info->cmap.cmap32;
3368                 break;
3369 #endif /* FBCON_HAS_CFB32 */
3370         default:
3371                 disp->dispsw = &fbcon_dummy;
3372                 DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
3373                 break;
3374         }
3375         restore_flags(flags);
3376 }
3377
3378 /* */
3379 static void pm3fb_detect(void)
3380 {
3381         struct pci_dev *dev_array[PM3_MAX_BOARD];
3382         struct pci_dev *dev = NULL;
3383         struct pm3fb_info *l_fb_info = &(fb_info[0]);
3384         unsigned long i, j, done;
3385
3386         DTRACE;
3387
3388         for (i = 0; i < PM3_MAX_BOARD; i++) {
3389                 dev_array[i] = NULL;
3390                 fb_info[i].dev = NULL;
3391         }
3392
3393         dev =
3394             pci_find_device(PCI_VENDOR_ID_3DLABS,
3395                             PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
3396
3397         for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
3398                 dev_array[i] = dev;
3399                 dev =
3400                     pci_find_device(PCI_VENDOR_ID_3DLABS,
3401                                     PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
3402         }
3403
3404         if (dev) {              /* more than PM3_MAX_BOARD */
3405                 printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
3406                        PM3_MAX_BOARD);
3407         }
3408
3409         if (!dev_array[0]) {    /* not a single board, abort */
3410                 return;
3411         }
3412
3413         /* allocate user-defined boards */
3414         for (i = 0; i < PM3_MAX_BOARD; i++) {
3415                 if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
3416                         for (j = 0; j < PM3_MAX_BOARD; j++) {
3417                                 if ((dev_array[j] != NULL) &&
3418                                     (dev_array[j]->bus->number == bus[i])
3419                                     && (PCI_SLOT(dev_array[j]->devfn) ==
3420                                         slot[i])
3421                                     && (PCI_FUNC(dev_array[j]->devfn) ==
3422                                         func[i])) {
3423                                         fb_info[i].dev = dev_array[j];
3424                                         dev_array[j] = NULL;
3425                                 }
3426                         }
3427                 }
3428         }
3429         /* allocate remaining boards */
3430         for (i = 0; i < PM3_MAX_BOARD; i++) {
3431                 if (fb_info[i].dev == NULL) {
3432                         done = 0;
3433                         for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
3434                                 if (dev_array[j] != NULL) {
3435                                         fb_info[i].dev = dev_array[j];
3436                                         dev_array[j] = NULL;
3437                                         done = 1;
3438                                 }
3439                         }
3440                 }
3441         }
3442
3443         /* at that point, all PCI Permedia3 are detected and allocated */
3444         /* now, initialize... or not */
3445         for (i = 0; i < PM3_MAX_BOARD; i++) {
3446                 l_fb_info = &(fb_info[i]);
3447                 if ((l_fb_info->dev) && (!disable[i])) {        /* PCI device was found and not disabled by user */
3448 #ifdef SUPPORT_FB_OF
3449                         struct device_node *dp =
3450                             find_pci_device_OFnode(l_fb_info->dev->bus->
3451                                                    number,
3452                                                    l_fb_info->dev->devfn);
3453
3454                         if ((dp) && (!strncmp(dp->name, "formacGA12", 10))) {
3455                                 /* do nothing, init of board is done in pm3fb_of_init */
3456                         } else {
3457 #endif
3458                                 DPRINTK(2,
3459                                         "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
3460                                         (unsigned long) l_fb_info->dev,
3461                                         (unsigned long) l_fb_info->dev->
3462                                         vendor,
3463                                         (unsigned long) l_fb_info->dev->
3464                                         device,
3465                                         (unsigned long)
3466                                         pci_resource_start(l_fb_info->dev,
3467                                                            0),
3468                                         (unsigned long)
3469                                         pci_resource_start(l_fb_info->dev,
3470                                                            1),
3471                                         (unsigned long)
3472                                         pci_resource_start(l_fb_info->dev,
3473                                                            2),
3474                                         (unsigned long)
3475                                         pci_resource_start(l_fb_info->dev,
3476                                                            3),
3477                                         (unsigned long)
3478                                         pci_resource_start(l_fb_info->dev,
3479                                                            4),
3480                                         (unsigned long)
3481                                         pci_resource_start(l_fb_info->dev,
3482                                                            5),
3483                                         (unsigned long) l_fb_info->dev->
3484                                         irq);
3485
3486                                 l_fb_info->pIOBase =
3487                                     (unsigned char *)
3488                                     pci_resource_start(l_fb_info->dev, 0);
3489 #ifdef __BIG_ENDIAN
3490                                 l_fb_info->pIOBase += PM3_REGS_SIZE;
3491 #endif
3492                                 l_fb_info->vIOBase = (unsigned char *) -1;
3493                                 l_fb_info->p_fb =
3494                                     (unsigned char *)
3495                                     pci_resource_start(l_fb_info->dev, 1);
3496                                 l_fb_info->v_fb = (unsigned char *) -1;
3497
3498 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)        /* full resource management, new in linux-2.4.x */
3499                                 if (!request_mem_region
3500                                     ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
3501                                      "pm3fb")) {
3502                                         printk
3503                                             (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
3504                                              l_fb_info->board_num);
3505                                         continue;
3506                                 }
3507                                 if (!request_mem_region
3508                                     ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
3509                                      "pm3fb I/O regs")) {
3510                                         printk
3511                                             (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
3512                                              l_fb_info->board_num);
3513                                         continue;
3514                                 }
3515 #endif /* KERNEL_2_4 or KERNEL_2_5 */
3516                                 if (forcesize[l_fb_info->board_num])
3517                                         l_fb_info->fb_size = forcesize[l_fb_info->board_num];
3518                                 
3519                                 l_fb_info->fb_size =
3520                                     pm3fb_size_memory(l_fb_info);
3521
3522                                 if (l_fb_info->fb_size) {
3523                                         (void) pci_enable_device(l_fb_info->dev);
3524                                         pm3fb_common_init(l_fb_info);
3525                                 } else
3526                                         printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
3527                                 
3528 #ifdef SUPPORT_FB_OF
3529                         }
3530 #endif /* SUPPORT_FB_OF */
3531                 }
3532         }
3533 }
3534
3535 static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
3536                              struct fb_info_gen *info)
3537 {
3538         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3539
3540         DTRACE;
3541
3542         if (!current_par_valid[l_fb_info->board_num])
3543                 return -EINVAL;
3544
3545         l_fb_info->current_par->base =  /* in 128 bits chunk - i.e. AFTER Shiftbpp */
3546             pm3fb_Shiftbpp(l_fb_info,
3547                            l_fb_info->current_par->depth,
3548                            (var->yoffset * l_fb_info->current_par->width) +
3549                            var->xoffset);
3550         PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
3551         return 0;
3552 }
3553
3554 static int pm3fb_ioctl(struct inode *inode, struct file *file,
3555                        u_int cmd, u_long arg, int con,
3556                        struct fb_info *info)
3557 {
3558         struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
3559         u32 cm, i;
3560 #ifdef PM3FB_MASTER_DEBUG
3561         char cc[3];
3562 #endif /* PM3FB_MASTER_DEBUG */
3563
3564         switch(cmd)
3565         {
3566 #ifdef PM3FB_MASTER_DEBUG
3567         case PM3FBIO_CLEARMEMORY:
3568                 if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
3569                         return(-EFAULT);
3570                 pm3fb_clear_memory(l_fb_info, cm);
3571                 return(0);
3572                 break;
3573
3574         case PM3FBIO_CLEARCMAP:
3575                 if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
3576                         return(-EFAULT);
3577                 pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
3578                 return(0);
3579                 break;
3580 #endif /* PM3FB_MASTER_DEBUG */
3581
3582         case PM3FBIO_RESETCHIP:
3583                 cm = 1;
3584                 PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
3585                 for (i = 0 ; (i < 10000) && cm ; i++)
3586                 {
3587                         PM3_DELAY(10);
3588                         cm = PM3_READ_REG(PM3ResetStatus);
3589                 }
3590                 if (cm)
3591                 {
3592                         printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
3593                         return(-EIO);
3594                 }
3595                 /* first thing first, reload memory timings */
3596                 pm3fb_write_memory_timings(l_fb_info);
3597 #ifdef PM3FB_USE_ACCEL
3598                 pm3fb_init_engine(l_fb_info);
3599 #endif /* PM3FB_USE_ACCEL */
3600                 pm3fb_write_mode(l_fb_info);
3601                 return(0);
3602                 break;
3603
3604         default:
3605                 DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
3606                 return(-EINVAL);
3607         }
3608 }
3609
3610 /* ****************************************** */
3611 /* ***** standard FB API init functions ***** */
3612 /* ****************************************** */
3613
3614 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
3615 int __init pm3fb_setup(char *options)
3616 #endif
3617 #ifdef KERNEL_2_2
3618 __initfunc(void pm3fb_setup(char *options, int *ints))
3619 #endif
3620 {
3621         long opsi = strlen(options);
3622
3623         DTRACE;
3624
3625         memcpy(g_options, options,
3626                ((opsi + 1) >
3627                 PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
3628         g_options[PM3_OPTIONS_SIZE - 1] = 0;
3629
3630 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
3631         return (0);
3632 #endif
3633 }
3634
3635 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
3636 int __init pm3fb_init(void)
3637 #endif
3638 #ifdef KERNEL_2_2
3639 __initfunc(void pm3fb_init(void))
3640 #endif
3641 {
3642         DTRACE;
3643
3644         DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvshome/samwise/ppclinux/drivers/video/pm3fb.c,v 1.1.1.1 2005/04/11 02:50:42 jack Exp $");
3645
3646         pm3fb_real_setup(g_options);
3647
3648         pm3fb_detect();
3649
3650         if (!fb_info[0].dev) {  /* not even one board ??? */
3651                 DPRINTK(1, "No PCI Permedia3 board detected\n");
3652         }
3653 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
3654         return (0);
3655 #endif
3656 }
3657
3658 #ifdef SUPPORT_FB_OF            /* linux-2.2.x only */
3659 __initfunc(void pm3fb_of_init(struct device_node *dp))
3660 {
3661         struct pm3fb_info *l_fb_info = NULL;
3662         unsigned long i;
3663         long bn = -1;
3664         struct device_node *dn;
3665
3666         DTRACE;
3667
3668         DPRINTK(2, "OpenFirmware board : %s\n", dp->full_name);
3669
3670         for (i = 0; i < dp->n_addrs; i++) {
3671                 DPRINTK(2, "MemRange : 0x%08x - 0x%x\n",
3672                         dp->addrs[i].address, dp->addrs[i].size);
3673         }
3674
3675         for (i = 0; i < PM3_MAX_BOARD; i++) {   /* find which PCI board is the OF device */
3676                 if (fb_info[i].dev) {
3677                         dn = find_pci_device_OFnode(fb_info[i].dev->bus->
3678                                                     number,
3679                                                     fb_info[i].dev->devfn);
3680                         if (dn == dp) {
3681                                 if (bn == -1)
3682                                         bn = i;
3683                                 else {
3684                                         DPRINTK(1,
3685                                                 "Error: Multiple PCI device for a single OpenFirmware node\n");
3686                                 }
3687                         }
3688                 }
3689         }
3690
3691         if (bn == -1) {
3692                 DPRINTK(1, "Warning: non-PCI Permedia3 found\n");
3693                 i = 0;
3694                 while (fb_info[i].dev && (i < PM3_MAX_BOARD))
3695                         i++;
3696                 if (i < PM3_MAX_BOARD)
3697                         bn = i;
3698                 else {
3699                         printk
3700                             (KERN_ERR "pm3fb: Error: Couldn't find room for OpenFirmware device");
3701                         return;
3702                 }
3703         }
3704
3705         l_fb_info = &(fb_info[bn]);
3706
3707         l_fb_info->dn = dp;
3708
3709         l_fb_info->pIOBase = (unsigned char *) dp->addrs[3].address;
3710 #ifdef __BIG_ENDIAN
3711         l_fb_info->pIOBase += PM3_REGS_SIZE;
3712 #endif
3713         l_fb_info->vIOBase = (unsigned char *) -1;
3714         l_fb_info->p_fb = (unsigned char *) dp->addrs[1].address;
3715         l_fb_info->v_fb = (unsigned char *) -1;
3716
3717         l_fb_info->fb_size = pm3fb_size_memory(l_fb_info);      /* (unsigned long)dp->addrs[1].size; *//* OF is a liar ! it claims 256 Mb */
3718
3719         DPRINTK(2,
3720                 "OpenFirmware board (#%ld) : IOBase 0x%08lx, p_fb 0x%08lx, fb_size %d KB\n",
3721                 bn, (unsigned long) l_fb_info->pIOBase,
3722                 (unsigned long) l_fb_info->p_fb, l_fb_info->fb_size >> 10);
3723
3724         l_fb_info->use_current = 1;     /* will use current mode by default */
3725
3726         pm3fb_common_init(l_fb_info);
3727 }
3728 #endif /* SUPPORT_FB_OF */
3729
3730 /* ************************* */
3731 /* **** Module support ***** */
3732 /* ************************* */
3733
3734 #ifdef MODULE
3735 MODULE_AUTHOR("Romain Dolbeau");
3736 MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
3737 static char *mode[PM3_MAX_BOARD];
3738 MODULE_PARM(mode,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
3739 MODULE_PARM_DESC(mode,"video mode");
3740 MODULE_PARM(disable,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
3741 MODULE_PARM_DESC(disable,"disable board");
3742 static short off[PM3_MAX_BOARD];
3743 MODULE_PARM(off,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
3744 MODULE_PARM_DESC(off,"disable board");
3745 static char *pciid[PM3_MAX_BOARD];
3746 MODULE_PARM(pciid,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
3747 MODULE_PARM_DESC(pciid,"board PCI Id");
3748 MODULE_PARM(noaccel,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
3749 MODULE_PARM_DESC(noaccel,"disable accel");
3750 static char *font[PM3_MAX_BOARD];
3751 MODULE_PARM(font,PM3_MAX_BOARD_MODULE_ARRAY_STRING);
3752 MODULE_PARM_DESC(font,"choose font");
3753 MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
3754 MODULE_PARM_DESC(depth,"boot-time depth");
3755 MODULE_PARM(printtimings, "h");
3756 MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
3757 MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
3758 MODULE_PARM_DESC(forcesize, "force specified memory size");
3759 /*
3760 MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
3761 MODULE_GENERIC_TABLE(gtype,name)
3762 MODULE_DEVICE_TABLE(type,name)
3763 */
3764
3765 void pm3fb_build_options(void)
3766 {
3767         int i;
3768         char ts[128];
3769
3770         strcpy(g_options, "pm3fb");
3771         for (i = 0; i < PM3_MAX_BOARD ; i++)
3772         {
3773                 if (mode[i])
3774                 {
3775                         sprintf(ts, ",mode:%d:%s", i, mode[i]);
3776                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3777                 }
3778                 if (disable[i] || off[i])
3779                 {
3780                         sprintf(ts, ",disable:%d:", i);
3781                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3782                 }
3783                 if (pciid[i])
3784                 {
3785                         sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
3786                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3787                 }
3788                 if (noaccel[i])
3789                 {
3790                         sprintf(ts, ",noaccel:%d:", i);
3791                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3792                 }
3793                 if (font[i])
3794                 {
3795                         sprintf(ts, ",font:%d:%s", i, font[i]);
3796                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3797                 }
3798                 if (depth[i])
3799                 {
3800                         sprintf(ts, ",depth:%d:%d", i, depth[i]);
3801                         strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
3802                 }
3803         }
3804         g_options[PM3_OPTIONS_SIZE - 1] = '\0';
3805         DPRINTK(1, "pm3fb use options: %s\n", g_options);
3806 }
3807
3808 int init_module(void)
3809 {
3810         DTRACE;
3811
3812         pm3fb_build_options();
3813
3814         pm3fb_init();
3815
3816         return (0);
3817 }
3818
3819 void cleanup_module(void)
3820 {
3821         DTRACE;
3822         {
3823                 unsigned long i;
3824                 struct pm3fb_info *l_fb_info;
3825                 for (i = 0; i < PM3_MAX_BOARD; i++) {
3826                         l_fb_info = &(fb_info[i]);
3827                         if ((l_fb_info->dev != NULL)
3828                             && (!(disable[l_fb_info->board_num]))) {
3829                                 if (l_fb_info->vIOBase !=
3830                                     (unsigned char *) -1) {
3831                                         pm3fb_unmapIO(l_fb_info);
3832 #if (defined KERNEL_2_4) || (defined KERNEL_2_5)
3833                                         release_mem_region(l_fb_info->p_fb,
3834                                                            l_fb_info->
3835                                                            fb_size);
3836                                         release_mem_region(l_fb_info->
3837                                                            pIOBase,
3838                                                            PM3_REGS_SIZE);
3839 #endif /* KERNEL_2_4 or KERNEL_2_5 */
3840                                 }
3841                                 unregister_framebuffer(&l_fb_info->gen.
3842                                                        info);
3843                         }
3844                 }
3845         }
3846         return;
3847 }
3848 #endif /* MODULE */