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