aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/pm2fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/pm2fb.c')
-rw-r--r--drivers/video/pm2fb.c883
1 files changed, 627 insertions, 256 deletions
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 10c0cc6e93fc..5591dfb22b18 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -11,7 +11,7 @@
11 * and additional input from James Simmon's port of Hannu Mallat's tdfx 11 * and additional input from James Simmon's port of Hannu Mallat's tdfx
12 * driver. 12 * driver.
13 * 13 *
14 * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I 14 * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
15 * have no access to other pm2fb implementations. Sparc (and thus 15 * have no access to other pm2fb implementations. Sparc (and thus
16 * hopefully other big-endian) devices now work, thanks to a lot of 16 * hopefully other big-endian) devices now work, thanks to a lot of
17 * testing work by Ron Murray. I have no access to CVision hardware, 17 * testing work by Ron Murray. I have no access to CVision hardware,
@@ -38,6 +38,9 @@
38#include <linux/fb.h> 38#include <linux/fb.h>
39#include <linux/init.h> 39#include <linux/init.h>
40#include <linux/pci.h> 40#include <linux/pci.h>
41#ifdef CONFIG_MTRR
42#include <asm/mtrr.h>
43#endif
41 44
42#include <video/permedia2.h> 45#include <video/permedia2.h>
43#include <video/cvisionppc.h> 46#include <video/cvisionppc.h>
@@ -52,15 +55,19 @@
52 55
53#undef PM2FB_MASTER_DEBUG 56#undef PM2FB_MASTER_DEBUG
54#ifdef PM2FB_MASTER_DEBUG 57#ifdef PM2FB_MASTER_DEBUG
55#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b) 58#define DPRINTK(a, b...) \
59 printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
56#else 60#else
57#define DPRINTK(a,b...) 61#define DPRINTK(a, b...)
58#endif 62#endif
59 63
64#define PM2_PIXMAP_SIZE (1600 * 4)
65
60/* 66/*
61 * Driver data 67 * Driver data
62 */ 68 */
63static char *mode __devinitdata = NULL; 69static int hwcursor = 1;
70static char *mode __devinitdata;
64 71
65/* 72/*
66 * The XFree GLINT driver will (I think to implement hardware cursor 73 * The XFree GLINT driver will (I think to implement hardware cursor
@@ -73,6 +80,11 @@ static char *mode __devinitdata = NULL;
73 */ 80 */
74static int lowhsync; 81static int lowhsync;
75static int lowvsync; 82static int lowvsync;
83static int noaccel __devinitdata;
84/* mtrr option */
85#ifdef CONFIG_MTRR
86static int nomtrr __devinitdata;
87#endif
76 88
77/* 89/*
78 * The hardware state of the graphics card that isn't part of the 90 * The hardware state of the graphics card that isn't part of the
@@ -88,6 +100,7 @@ struct pm2fb_par
88 u32 mem_control; /* MemControl reg at probe */ 100 u32 mem_control; /* MemControl reg at probe */
89 u32 boot_address; /* BootAddress reg at probe */ 101 u32 boot_address; /* BootAddress reg at probe */
90 u32 palette[16]; 102 u32 palette[16];
103 int mtrr_handle;
91}; 104};
92 105
93/* 106/*
@@ -135,60 +148,39 @@ static struct fb_var_screeninfo pm2fb_var __devinitdata = {
135 * Utility functions 148 * Utility functions
136 */ 149 */
137 150
138static inline u32 RD32(unsigned char __iomem *base, s32 off) 151static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
139{
140 return fb_readl(base + off);
141}
142
143static inline void WR32(unsigned char __iomem *base, s32 off, u32 v)
144{ 152{
145 fb_writel(v, base + off); 153 return fb_readl(p->v_regs + off);
146} 154}
147 155
148static inline u32 pm2_RD(struct pm2fb_par* p, s32 off) 156static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
149{ 157{
150 return RD32(p->v_regs, off); 158 fb_writel(v, p->v_regs + off);
151} 159}
152 160
153static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v) 161static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
154{ 162{
155 WR32(p->v_regs, off, v); 163 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
164 mb();
165 return pm2_RD(p, PM2R_RD_INDEXED_DATA);
156} 166}
157 167
158static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx) 168static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
159{ 169{
160 int index = PM2R_RD_INDEXED_DATA; 170 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
161 switch (p->type) {
162 case PM2_TYPE_PERMEDIA2:
163 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
164 break;
165 case PM2_TYPE_PERMEDIA2V:
166 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
167 index = PM2VR_RD_INDEXED_DATA;
168 break;
169 }
170 mb(); 171 mb();
171 return pm2_RD(p, index); 172 return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
172} 173}
173 174
174static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) 175static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
175{ 176{
176 int index = PM2R_RD_INDEXED_DATA; 177 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
177 switch (p->type) {
178 case PM2_TYPE_PERMEDIA2:
179 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
180 break;
181 case PM2_TYPE_PERMEDIA2V:
182 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
183 index = PM2VR_RD_INDEXED_DATA;
184 break;
185 }
186 wmb(); 178 wmb();
187 pm2_WR(p, index, v); 179 pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
188 wmb(); 180 wmb();
189} 181}
190 182
191static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v) 183static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
192{ 184{
193 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); 185 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
194 wmb(); 186 wmb();
@@ -199,10 +191,10 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
199#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 191#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
200#define WAIT_FIFO(p, a) 192#define WAIT_FIFO(p, a)
201#else 193#else
202static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) 194static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
203{ 195{
204 while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); 196 while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
205 mb(); 197 cpu_relax();
206} 198}
207#endif 199#endif
208 200
@@ -238,7 +230,7 @@ static u32 partprod(u32 xres)
238 230
239 for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) 231 for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
240 ; 232 ;
241 if ( pp_table[i].width == 0 ) 233 if (pp_table[i].width == 0)
242 DPRINTK("invalid width %u\n", xres); 234 DPRINTK("invalid width %u\n", xres);
243 return pp_table[i].pp; 235 return pp_table[i].pp;
244} 236}
@@ -246,25 +238,22 @@ static u32 partprod(u32 xres)
246static u32 to3264(u32 timing, int bpp, int is64) 238static u32 to3264(u32 timing, int bpp, int is64)
247{ 239{
248 switch (bpp) { 240 switch (bpp) {
241 case 24:
242 timing *= 3;
249 case 8: 243 case 8:
250 timing >>= 2 + is64; 244 timing >>= 1;
251 break;
252 case 16: 245 case 16:
253 timing >>= 1 + is64; 246 timing >>= 1;
254 break;
255 case 24:
256 timing = (timing * 3) >> (2 + is64);
257 break;
258 case 32: 247 case 32:
259 if (is64)
260 timing >>= 1;
261 break; 248 break;
262 } 249 }
250 if (is64)
251 timing >>= 1;
263 return timing; 252 return timing;
264} 253}
265 254
266static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, 255static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
267 unsigned char* pp) 256 unsigned char *pp)
268{ 257{
269 unsigned char m; 258 unsigned char m;
270 unsigned char n; 259 unsigned char n;
@@ -278,13 +267,13 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
278 for (m = 2; m; m++) { 267 for (m = 2; m; m++) {
279 f = PM2_REFERENCE_CLOCK * m / n; 268 f = PM2_REFERENCE_CLOCK * m / n;
280 if (f >= 150000 && f <= 300000) { 269 if (f >= 150000 && f <= 300000) {
281 for ( p = 0; p < 5; p++, f >>= 1) { 270 for (p = 0; p < 5; p++, f >>= 1) {
282 curr = ( clk > f ) ? clk - f : f - clk; 271 curr = (clk > f) ? clk - f : f - clk;
283 if ( curr < delta ) { 272 if (curr < delta) {
284 delta=curr; 273 delta = curr;
285 *mm=m; 274 *mm = m;
286 *nn=n; 275 *nn = n;
287 *pp=p; 276 *pp = p;
288 } 277 }
289 } 278 }
290 } 279 }
@@ -292,8 +281,8 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
292 } 281 }
293} 282}
294 283
295static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, 284static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
296 unsigned char* pp) 285 unsigned char *pp)
297{ 286{
298 unsigned char m; 287 unsigned char m;
299 unsigned char n; 288 unsigned char n;
@@ -302,23 +291,24 @@ static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
302 s32 delta = 1000; 291 s32 delta = 1000;
303 292
304 *mm = *nn = *pp = 0; 293 *mm = *nn = *pp = 0;
305 for ( m = 1; m < 128; m++) { 294 for (m = 1; m < 128; m++) {
306 for (n = 2 * m + 1; n; n++) { 295 for (n = 2 * m + 1; n; n++) {
307 for ( p = 0; p < 2; p++) { 296 for (p = 0; p < 2; p++) {
308 f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m; 297 f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m;
309 if ( clk > f - delta && clk < f + delta ) { 298 if (clk > f - delta && clk < f + delta) {
310 delta = ( clk > f ) ? clk - f : f - clk; 299 delta = (clk > f) ? clk - f : f - clk;
311 *mm=m; 300 *mm = m;
312 *nn=n; 301 *nn = n;
313 *pp=p; 302 *pp = p;
314 } 303 }
315 } 304 }
316 } 305 }
317 } 306 }
318} 307}
319 308
320static void clear_palette(struct pm2fb_par* p) { 309static void clear_palette(struct pm2fb_par *p)
321 int i=256; 310{
311 int i = 256;
322 312
323 WAIT_FIFO(p, 1); 313 WAIT_FIFO(p, 1);
324 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); 314 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
@@ -331,14 +321,14 @@ static void clear_palette(struct pm2fb_par* p) {
331 } 321 }
332} 322}
333 323
334static void reset_card(struct pm2fb_par* p) 324static void reset_card(struct pm2fb_par *p)
335{ 325{
336 if (p->type == PM2_TYPE_PERMEDIA2V) 326 if (p->type == PM2_TYPE_PERMEDIA2V)
337 pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); 327 pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
338 pm2_WR(p, PM2R_RESET_STATUS, 0); 328 pm2_WR(p, PM2R_RESET_STATUS, 0);
339 mb(); 329 mb();
340 while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) 330 while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
341 ; 331 cpu_relax();
342 mb(); 332 mb();
343#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT 333#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
344 DPRINTK("FIFO disconnect enabled\n"); 334 DPRINTK("FIFO disconnect enabled\n");
@@ -354,11 +344,11 @@ static void reset_card(struct pm2fb_par* p)
354 pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config); 344 pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
355} 345}
356 346
357static void reset_config(struct pm2fb_par* p) 347static void reset_config(struct pm2fb_par *p)
358{ 348{
359 WAIT_FIFO(p, 52); 349 WAIT_FIFO(p, 53);
360 pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) & 350 pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
361 ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); 351 ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED));
362 pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); 352 pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
363 pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); 353 pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
364 pm2_WR(p, PM2R_FIFO_CONTROL, 0); 354 pm2_WR(p, PM2R_FIFO_CONTROL, 0);
@@ -393,31 +383,32 @@ static void reset_config(struct pm2fb_par* p)
393 pm2_WR(p, PM2R_STATISTICS_MODE, 0); 383 pm2_WR(p, PM2R_STATISTICS_MODE, 0);
394 pm2_WR(p, PM2R_SCISSOR_MODE, 0); 384 pm2_WR(p, PM2R_SCISSOR_MODE, 0);
395 pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); 385 pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
386 pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff);
396 switch (p->type) { 387 switch (p->type) {
397 case PM2_TYPE_PERMEDIA2: 388 case PM2_TYPE_PERMEDIA2:
398 pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ 389 pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
399 pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); 390 pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
400 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); 391 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
392 pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
393 pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
394 pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
395 pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
396 pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
401 break; 397 break;
402 case PM2_TYPE_PERMEDIA2V: 398 case PM2_TYPE_PERMEDIA2V:
403 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ 399 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
404 break; 400 break;
405 } 401 }
406 pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
407 pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
408 pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
409 pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
410 pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
411} 402}
412 403
413static void set_aperture(struct pm2fb_par* p, u32 depth) 404static void set_aperture(struct pm2fb_par *p, u32 depth)
414{ 405{
415 /* 406 /*
416 * The hardware is little-endian. When used in big-endian 407 * The hardware is little-endian. When used in big-endian
417 * hosts, the on-chip aperture settings are used where 408 * hosts, the on-chip aperture settings are used where
418 * possible to translate from host to card byte order. 409 * possible to translate from host to card byte order.
419 */ 410 */
420 WAIT_FIFO(p, 4); 411 WAIT_FIFO(p, 2);
421#ifdef __LITTLE_ENDIAN 412#ifdef __LITTLE_ENDIAN
422 pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD); 413 pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
423#else 414#else
@@ -440,11 +431,11 @@ static void set_aperture(struct pm2fb_par* p, u32 depth)
440 } 431 }
441#endif 432#endif
442 433
443 // We don't use aperture two, so this may be superflous 434 /* We don't use aperture two, so this may be superflous */
444 pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD); 435 pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
445} 436}
446 437
447static void set_color(struct pm2fb_par* p, unsigned char regno, 438static void set_color(struct pm2fb_par *p, unsigned char regno,
448 unsigned char r, unsigned char g, unsigned char b) 439 unsigned char r, unsigned char g, unsigned char b)
449{ 440{
450 WAIT_FIFO(p, 4); 441 WAIT_FIFO(p, 4);
@@ -457,7 +448,7 @@ static void set_color(struct pm2fb_par* p, unsigned char regno,
457 pm2_WR(p, PM2R_RD_PALETTE_DATA, b); 448 pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
458} 449}
459 450
460static void set_memclock(struct pm2fb_par* par, u32 clk) 451static void set_memclock(struct pm2fb_par *par, u32 clk)
461{ 452{
462 int i; 453 int i;
463 unsigned char m, n, p; 454 unsigned char m, n, p;
@@ -465,7 +456,7 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
465 switch (par->type) { 456 switch (par->type) {
466 case PM2_TYPE_PERMEDIA2V: 457 case PM2_TYPE_PERMEDIA2V:
467 pm2v_mnp(clk/2, &m, &n, &p); 458 pm2v_mnp(clk/2, &m, &n, &p);
468 WAIT_FIFO(par, 8); 459 WAIT_FIFO(par, 12);
469 pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8); 460 pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
470 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0); 461 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
471 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m); 462 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
@@ -473,10 +464,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
473 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p); 464 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
474 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1); 465 pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
475 rmb(); 466 rmb();
476 for (i = 256; 467 for (i = 256; i; i--)
477 i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2); 468 if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2)
478 i--) 469 break;
479 ;
480 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0); 470 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
481 break; 471 break;
482 case PM2_TYPE_PERMEDIA2: 472 case PM2_TYPE_PERMEDIA2:
@@ -488,15 +478,14 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
488 pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p); 478 pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
489 pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS); 479 pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
490 rmb(); 480 rmb();
491 for (i = 256; 481 for (i = 256; i; i--)
492 i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); 482 if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
493 i--) 483 break;
494 ;
495 break; 484 break;
496 } 485 }
497} 486}
498 487
499static void set_pixclock(struct pm2fb_par* par, u32 clk) 488static void set_pixclock(struct pm2fb_par *par, u32 clk)
500{ 489{
501 int i; 490 int i;
502 unsigned char m, n, p; 491 unsigned char m, n, p;
@@ -504,17 +493,16 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk)
504 switch (par->type) { 493 switch (par->type) {
505 case PM2_TYPE_PERMEDIA2: 494 case PM2_TYPE_PERMEDIA2:
506 pm2_mnp(clk, &m, &n, &p); 495 pm2_mnp(clk, &m, &n, &p);
507 WAIT_FIFO(par, 8); 496 WAIT_FIFO(par, 10);
508 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0); 497 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
509 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m); 498 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
510 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n); 499 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
511 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p); 500 pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
512 pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS); 501 pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
513 rmb(); 502 rmb();
514 for (i = 256; 503 for (i = 256; i; i--)
515 i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED); 504 if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
516 i--) 505 break;
517 ;
518 break; 506 break;
519 case PM2_TYPE_PERMEDIA2V: 507 case PM2_TYPE_PERMEDIA2V:
520 pm2v_mnp(clk/2, &m, &n, &p); 508 pm2v_mnp(clk/2, &m, &n, &p);
@@ -528,11 +516,10 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk)
528 } 516 }
529} 517}
530 518
531static void set_video(struct pm2fb_par* p, u32 video) { 519static void set_video(struct pm2fb_par *p, u32 video)
520{
532 u32 tmp; 521 u32 tmp;
533 u32 vsync; 522 u32 vsync = video;
534
535 vsync = video;
536 523
537 DPRINTK("video = 0x%x\n", video); 524 DPRINTK("video = 0x%x\n", video);
538 525
@@ -542,10 +529,10 @@ static void set_video(struct pm2fb_par* p, u32 video) {
542 * driver may well. So always set +hsync/+vsync and then set 529 * driver may well. So always set +hsync/+vsync and then set
543 * the RAMDAC to invert the sync if necessary. 530 * the RAMDAC to invert the sync if necessary.
544 */ 531 */
545 vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK); 532 vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK);
546 vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH; 533 vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH;
547 534
548 WAIT_FIFO(p, 5); 535 WAIT_FIFO(p, 3);
549 pm2_WR(p, PM2R_VIDEO_CONTROL, vsync); 536 pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
550 537
551 switch (p->type) { 538 switch (p->type) {
@@ -564,16 +551,11 @@ static void set_video(struct pm2fb_par* p, u32 video) {
564 if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW) 551 if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
565 tmp |= 4; /* invert vsync */ 552 tmp |= 4; /* invert vsync */
566 pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp); 553 pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
567 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1);
568 break; 554 break;
569 } 555 }
570} 556}
571 557
572/* 558/*
573 *
574 */
575
576/**
577 * pm2fb_check_var - Optional function. Validates a var passed in. 559 * pm2fb_check_var - Optional function. Validates a var passed in.
578 * @var: frame buffer variable screen structure 560 * @var: frame buffer variable screen structure
579 * @info: frame buffer structure that represents a single frame buffer 561 * @info: frame buffer structure that represents a single frame buffer
@@ -594,15 +576,22 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
594 } 576 }
595 577
596 if (var->xres != var->xres_virtual) { 578 if (var->xres != var->xres_virtual) {
597 DPRINTK("virtual x resolution != physical x resolution not supported\n"); 579 DPRINTK("virtual x resolution != "
580 "physical x resolution not supported\n");
598 return -EINVAL; 581 return -EINVAL;
599 } 582 }
600 583
601 if (var->yres > var->yres_virtual) { 584 if (var->yres > var->yres_virtual) {
602 DPRINTK("virtual y resolution < physical y resolution not possible\n"); 585 DPRINTK("virtual y resolution < "
586 "physical y resolution not possible\n");
603 return -EINVAL; 587 return -EINVAL;
604 } 588 }
605 589
590 /* permedia cannot blit over 2048 */
591 if (var->yres_virtual > 2047) {
592 var->yres_virtual = 2047;
593 }
594
606 if (var->xoffset) { 595 if (var->xoffset) {
607 DPRINTK("xoffset not supported\n"); 596 DPRINTK("xoffset not supported\n");
608 return -EINVAL; 597 return -EINVAL;
@@ -614,7 +603,7 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
614 } 603 }
615 604
616 var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */ 605 var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
617 lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); 606 lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
618 607
619 if (var->xres < 320 || var->xres > 1600) { 608 if (var->xres < 320 || var->xres > 1600) {
620 DPRINTK("width not supported: %u\n", var->xres); 609 DPRINTK("width not supported: %u\n", var->xres);
@@ -633,15 +622,18 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
633 } 622 }
634 623
635 if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) { 624 if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
636 DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); 625 DPRINTK("pixclock too high (%ldKHz)\n",
626 PICOS2KHZ(var->pixclock));
637 return -EINVAL; 627 return -EINVAL;
638 } 628 }
639 629
640 var->transp.offset = 0; 630 var->transp.offset = 0;
641 var->transp.length = 0; 631 var->transp.length = 0;
642 switch(var->bits_per_pixel) { 632 switch (var->bits_per_pixel) {
643 case 8: 633 case 8:
644 var->red.length = var->green.length = var->blue.length = 8; 634 var->red.length = 8;
635 var->green.length = 8;
636 var->blue.length = 8;
645 break; 637 break;
646 case 16: 638 case 16:
647 var->red.offset = 11; 639 var->red.offset = 11;
@@ -657,7 +649,9 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
657 var->red.offset = 16; 649 var->red.offset = 16;
658 var->green.offset = 8; 650 var->green.offset = 8;
659 var->blue.offset = 0; 651 var->blue.offset = 0;
660 var->red.length = var->green.length = var->blue.length = 8; 652 var->red.length = 8;
653 var->green.length = 8;
654 var->blue.length = 8;
661 break; 655 break;
662 case 24: 656 case 24:
663#ifdef __BIG_ENDIAN 657#ifdef __BIG_ENDIAN
@@ -668,10 +662,13 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
668 var->blue.offset = 0; 662 var->blue.offset = 0;
669#endif 663#endif
670 var->green.offset = 8; 664 var->green.offset = 8;
671 var->red.length = var->green.length = var->blue.length = 8; 665 var->red.length = 8;
666 var->green.length = 8;
667 var->blue.length = 8;
672 break; 668 break;
673 } 669 }
674 var->height = var->width = -1; 670 var->height = -1;
671 var->width = -1;
675 672
676 var->accel_flags = 0; /* Can't mmap if this is on */ 673 var->accel_flags = 0; /* Can't mmap if this is on */
677 674
@@ -691,7 +688,9 @@ static int pm2fb_set_par(struct fb_info *info)
691{ 688{
692 struct pm2fb_par *par = info->par; 689 struct pm2fb_par *par = info->par;
693 u32 pixclock; 690 u32 pixclock;
694 u32 width, height, depth; 691 u32 width = (info->var.xres_virtual + 7) & ~7;
692 u32 height = info->var.yres_virtual;
693 u32 depth = (info->var.bits_per_pixel + 7) & ~7;
695 u32 hsstart, hsend, hbend, htotal; 694 u32 hsstart, hsend, hbend, htotal;
696 u32 vsstart, vsend, vbend, vtotal; 695 u32 vsstart, vsend, vbend, vtotal;
697 u32 stride; 696 u32 stride;
@@ -701,22 +700,19 @@ static int pm2fb_set_par(struct fb_info *info)
701 u32 txtmap = 0; 700 u32 txtmap = 0;
702 u32 pixsize = 0; 701 u32 pixsize = 0;
703 u32 clrformat = 0; 702 u32 clrformat = 0;
704 u32 xres; 703 u32 misc = 1; /* 8-bit DAC */
704 u32 xres = (info->var.xres + 31) & ~31;
705 int data64; 705 int data64;
706 706
707 reset_card(par); 707 reset_card(par);
708 reset_config(par); 708 reset_config(par);
709 clear_palette(par); 709 clear_palette(par);
710 if ( par->memclock ) 710 if (par->memclock)
711 set_memclock(par, par->memclock); 711 set_memclock(par, par->memclock);
712 712
713 width = (info->var.xres_virtual + 7) & ~7;
714 height = info->var.yres_virtual;
715 depth = (info->var.bits_per_pixel + 7) & ~7;
716 depth = (depth > 32) ? 32 : depth; 713 depth = (depth > 32) ? 32 : depth;
717 data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V; 714 data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
718 715
719 xres = (info->var.xres + 31) & ~31;
720 pixclock = PICOS2KHZ(info->var.pixclock); 716 pixclock = PICOS2KHZ(info->var.pixclock);
721 if (pixclock > PM2_MAX_PIXCLOCK) { 717 if (pixclock > PM2_MAX_PIXCLOCK) {
722 DPRINTK("pixclock too high (%uKHz)\n", pixclock); 718 DPRINTK("pixclock too high (%uKHz)\n", pixclock);
@@ -731,7 +727,8 @@ static int pm2fb_set_par(struct fb_info *info)
731 ? info->var.lower_margin - 1 727 ? info->var.lower_margin - 1
732 : 0; /* FIXME! */ 728 : 0; /* FIXME! */
733 vsend = info->var.lower_margin + info->var.vsync_len - 1; 729 vsend = info->var.lower_margin + info->var.vsync_len - 1;
734 vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin; 730 vbend = info->var.lower_margin + info->var.vsync_len +
731 info->var.upper_margin;
735 vtotal = info->var.yres + vbend - 1; 732 vtotal = info->var.yres + vbend - 1;
736 stride = to3264(width, depth, 1); 733 stride = to3264(width, depth, 1);
737 base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1); 734 base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
@@ -744,25 +741,25 @@ static int pm2fb_set_par(struct fb_info *info)
744 video |= PM2F_HSYNC_ACT_LOW; 741 video |= PM2F_HSYNC_ACT_LOW;
745 } else 742 } else
746 video |= PM2F_HSYNC_ACT_HIGH; 743 video |= PM2F_HSYNC_ACT_HIGH;
747 } 744 } else
748 else
749 video |= PM2F_HSYNC_ACT_LOW; 745 video |= PM2F_HSYNC_ACT_LOW;
746
750 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) { 747 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
751 if (lowvsync) { 748 if (lowvsync) {
752 DPRINTK("ignoring +vsync, using -vsync.\n"); 749 DPRINTK("ignoring +vsync, using -vsync.\n");
753 video |= PM2F_VSYNC_ACT_LOW; 750 video |= PM2F_VSYNC_ACT_LOW;
754 } else 751 } else
755 video |= PM2F_VSYNC_ACT_HIGH; 752 video |= PM2F_VSYNC_ACT_HIGH;
756 } 753 } else
757 else
758 video |= PM2F_VSYNC_ACT_LOW; 754 video |= PM2F_VSYNC_ACT_LOW;
759 if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) { 755
756 if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
760 DPRINTK("interlaced not supported\n"); 757 DPRINTK("interlaced not supported\n");
761 return -EINVAL; 758 return -EINVAL;
762 } 759 }
763 if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE) 760 if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
764 video |= PM2F_LINE_DOUBLE; 761 video |= PM2F_LINE_DOUBLE;
765 if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW) 762 if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
766 video |= PM2F_VIDEO_ENABLE; 763 video |= PM2F_VIDEO_ENABLE;
767 par->video = video; 764 par->video = video;
768 765
@@ -783,12 +780,10 @@ static int pm2fb_set_par(struct fb_info *info)
783 780
784 mb(); 781 mb();
785 WAIT_FIFO(par, 19); 782 WAIT_FIFO(par, 19);
786 pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
787 ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
788 switch (depth) { 783 switch (depth) {
789 case 8: 784 case 8:
790 pm2_WR(par, PM2R_FB_READ_PIXEL, 0); 785 pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
791 clrformat = 0x0e; 786 clrformat = 0x2e;
792 break; 787 break;
793 case 16: 788 case 16:
794 pm2_WR(par, PM2R_FB_READ_PIXEL, 1); 789 pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
@@ -796,6 +791,7 @@ static int pm2fb_set_par(struct fb_info *info)
796 txtmap = PM2F_TEXTEL_SIZE_16; 791 txtmap = PM2F_TEXTEL_SIZE_16;
797 pixsize = 1; 792 pixsize = 1;
798 clrformat = 0x70; 793 clrformat = 0x70;
794 misc |= 8;
799 break; 795 break;
800 case 32: 796 case 32:
801 pm2_WR(par, PM2R_FB_READ_PIXEL, 2); 797 pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
@@ -803,6 +799,7 @@ static int pm2fb_set_par(struct fb_info *info)
803 txtmap = PM2F_TEXTEL_SIZE_32; 799 txtmap = PM2F_TEXTEL_SIZE_32;
804 pixsize = 2; 800 pixsize = 2;
805 clrformat = 0x20; 801 clrformat = 0x20;
802 misc |= 8;
806 break; 803 break;
807 case 24: 804 case 24:
808 pm2_WR(par, PM2R_FB_READ_PIXEL, 4); 805 pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
@@ -810,6 +807,7 @@ static int pm2fb_set_par(struct fb_info *info)
810 txtmap = PM2F_TEXTEL_SIZE_24; 807 txtmap = PM2F_TEXTEL_SIZE_24;
811 pixsize = 4; 808 pixsize = 4;
812 clrformat = 0x20; 809 clrformat = 0x20;
810 misc |= 8;
813 break; 811 break;
814 } 812 }
815 pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE); 813 pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
@@ -834,14 +832,19 @@ static int pm2fb_set_par(struct fb_info *info)
834 pm2_WR(par, PM2R_SCREEN_BASE, base); 832 pm2_WR(par, PM2R_SCREEN_BASE, base);
835 wmb(); 833 wmb();
836 set_video(par, video); 834 set_video(par, video);
837 WAIT_FIFO(par, 4); 835 WAIT_FIFO(par, 10);
838 switch (par->type) { 836 switch (par->type) {
839 case PM2_TYPE_PERMEDIA2: 837 case PM2_TYPE_PERMEDIA2:
840 pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode); 838 pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
839 pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
840 (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
841 break; 841 break;
842 case PM2_TYPE_PERMEDIA2V: 842 case PM2_TYPE_PERMEDIA2V:
843 pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0);
843 pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize); 844 pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
844 pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat); 845 pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
846 pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc);
847 pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0);
845 break; 848 break;
846 } 849 }
847 set_pixclock(par, pixclock); 850 set_pixclock(par, pixclock);
@@ -872,16 +875,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
872 struct pm2fb_par *par = info->par; 875 struct pm2fb_par *par = info->par;
873 876
874 if (regno >= info->cmap.len) /* no. of hw registers */ 877 if (regno >= info->cmap.len) /* no. of hw registers */
875 return 1; 878 return -EINVAL;
876 /* 879 /*
877 * Program hardware... do anything you want with transp 880 * Program hardware... do anything you want with transp
878 */ 881 */
879 882
880 /* grayscale works only partially under directcolor */ 883 /* grayscale works only partially under directcolor */
881 if (info->var.grayscale) { 884 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
882 /* grayscale = 0.30*R + 0.59*G + 0.11*B */ 885 if (info->var.grayscale)
883 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; 886 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
884 }
885 887
886 /* Directcolor: 888 /* Directcolor:
887 * var->{color}.offset contains start of bitfield 889 * var->{color}.offset contains start of bitfield
@@ -931,7 +933,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
931 u32 v; 933 u32 v;
932 934
933 if (regno >= 16) 935 if (regno >= 16)
934 return 1; 936 return -EINVAL;
935 937
936 v = (red << info->var.red.offset) | 938 v = (red << info->var.red.offset) |
937 (green << info->var.green.offset) | 939 (green << info->var.green.offset) |
@@ -948,8 +950,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
948 break; 950 break;
949 } 951 }
950 return 0; 952 return 0;
951 } 953 } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
952 else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
953 set_color(par, regno, red, green, blue); 954 set_color(par, regno, red, green, blue);
954 955
955 return 0; 956 return 0;
@@ -972,11 +973,9 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var,
972{ 973{
973 struct pm2fb_par *p = info->par; 974 struct pm2fb_par *p = info->par;
974 u32 base; 975 u32 base;
975 u32 depth; 976 u32 depth = (var->bits_per_pixel + 7) & ~7;
976 u32 xres; 977 u32 xres = (var->xres + 31) & ~31;
977 978
978 xres = (var->xres + 31) & ~31;
979 depth = (var->bits_per_pixel + 7) & ~7;
980 depth = (depth > 32) ? 32 : depth; 979 depth = (depth > 32) ? 32 : depth;
981 base = to3264(var->yoffset * xres + var->xoffset, depth, 1); 980 base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
982 WAIT_FIFO(p, 1); 981 WAIT_FIFO(p, 1);
@@ -1018,15 +1017,15 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
1018 break; 1017 break;
1019 case FB_BLANK_VSYNC_SUSPEND: 1018 case FB_BLANK_VSYNC_SUSPEND:
1020 /* VSync: Off */ 1019 /* VSync: Off */
1021 video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW ); 1020 video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW);
1022 break; 1021 break;
1023 case FB_BLANK_HSYNC_SUSPEND: 1022 case FB_BLANK_HSYNC_SUSPEND:
1024 /* HSync: Off */ 1023 /* HSync: Off */
1025 video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW ); 1024 video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1026 break; 1025 break;
1027 case FB_BLANK_POWERDOWN: 1026 case FB_BLANK_POWERDOWN:
1028 /* HSync: Off, VSync: Off */ 1027 /* HSync: Off, VSync: Off */
1029 video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW); 1028 video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1030 break; 1029 break;
1031 } 1030 }
1032 set_video(par, video); 1031 set_video(par, video);
@@ -1042,48 +1041,20 @@ static int pm2fb_sync(struct fb_info *info)
1042 mb(); 1041 mb();
1043 do { 1042 do {
1044 while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) 1043 while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
1045 udelay(10); 1044 cpu_relax();
1046 rmb();
1047 } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); 1045 } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
1048 1046
1049 return 0; 1047 return 0;
1050} 1048}
1051 1049
1052/* 1050static void pm2fb_fillrect(struct fb_info *info,
1053 * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
1054 */
1055static void pm2fb_block_op(struct fb_info* info, int copy,
1056 s32 xsrc, s32 ysrc,
1057 s32 x, s32 y, s32 w, s32 h,
1058 u32 color) {
1059 struct pm2fb_par *par = info->par;
1060
1061 if (!w || !h)
1062 return;
1063 WAIT_FIFO(par, 5);
1064 pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
1065 PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
1066 if (copy)
1067 pm2_WR(par, PM2R_FB_SOURCE_DELTA,
1068 ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff));
1069 else
1070 pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
1071 pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x);
1072 pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w);
1073 wmb();
1074 pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
1075 (x<xsrc ? PM2F_INCREASE_X : 0) |
1076 (y<ysrc ? PM2F_INCREASE_Y : 0) |
1077 (copy ? 0 : PM2F_RENDER_FASTFILL));
1078}
1079
1080static void pm2fb_fillrect (struct fb_info *info,
1081 const struct fb_fillrect *region) 1051 const struct fb_fillrect *region)
1082{ 1052{
1053 struct pm2fb_par *par = info->par;
1083 struct fb_fillrect modded; 1054 struct fb_fillrect modded;
1084 int vxres, vyres; 1055 int vxres, vyres;
1085 u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? 1056 u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
1086 ((u32*)info->pseudo_palette)[region->color] : region->color; 1057 ((u32 *)info->pseudo_palette)[region->color] : region->color;
1087 1058
1088 if (info->state != FBINFO_STATE_RUNNING) 1059 if (info->state != FBINFO_STATE_RUNNING)
1089 return; 1060 return;
@@ -1098,31 +1069,46 @@ static void pm2fb_fillrect (struct fb_info *info,
1098 1069
1099 memcpy(&modded, region, sizeof(struct fb_fillrect)); 1070 memcpy(&modded, region, sizeof(struct fb_fillrect));
1100 1071
1101 if(!modded.width || !modded.height || 1072 if (!modded.width || !modded.height ||
1102 modded.dx >= vxres || modded.dy >= vyres) 1073 modded.dx >= vxres || modded.dy >= vyres)
1103 return; 1074 return;
1104 1075
1105 if(modded.dx + modded.width > vxres) 1076 if (modded.dx + modded.width > vxres)
1106 modded.width = vxres - modded.dx; 1077 modded.width = vxres - modded.dx;
1107 if(modded.dy + modded.height > vyres) 1078 if (modded.dy + modded.height > vyres)
1108 modded.height = vyres - modded.dy; 1079 modded.height = vyres - modded.dy;
1109 1080
1110 if(info->var.bits_per_pixel == 8) 1081 if (info->var.bits_per_pixel == 8)
1111 color |= color << 8; 1082 color |= color << 8;
1112 if(info->var.bits_per_pixel <= 16) 1083 if (info->var.bits_per_pixel <= 16)
1113 color |= color << 16; 1084 color |= color << 16;
1114 1085
1115 if(info->var.bits_per_pixel != 24) 1086 WAIT_FIFO(par, 3);
1116 pm2fb_block_op(info, 0, 0, 0, 1087 pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE);
1117 modded.dx, modded.dy, 1088 pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
1118 modded.width, modded.height, color); 1089 pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
1119 else 1090 if (info->var.bits_per_pixel != 24) {
1120 cfb_fillrect(info, region); 1091 WAIT_FIFO(par, 2);
1092 pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
1093 wmb();
1094 pm2_WR(par, PM2R_RENDER,
1095 PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL);
1096 } else {
1097 WAIT_FIFO(par, 4);
1098 pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
1099 pm2_WR(par, PM2R_CONSTANT_COLOR, color);
1100 wmb();
1101 pm2_WR(par, PM2R_RENDER,
1102 PM2F_RENDER_RECTANGLE |
1103 PM2F_INCREASE_X | PM2F_INCREASE_Y );
1104 pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1105 }
1121} 1106}
1122 1107
1123static void pm2fb_copyarea(struct fb_info *info, 1108static void pm2fb_copyarea(struct fb_info *info,
1124 const struct fb_copyarea *area) 1109 const struct fb_copyarea *area)
1125{ 1110{
1111 struct pm2fb_par *par = info->par;
1126 struct fb_copyarea modded; 1112 struct fb_copyarea modded;
1127 u32 vxres, vyres; 1113 u32 vxres, vyres;
1128 1114
@@ -1138,23 +1124,359 @@ static void pm2fb_copyarea(struct fb_info *info,
1138 vxres = info->var.xres_virtual; 1124 vxres = info->var.xres_virtual;
1139 vyres = info->var.yres_virtual; 1125 vyres = info->var.yres_virtual;
1140 1126
1141 if(!modded.width || !modded.height || 1127 if (!modded.width || !modded.height ||
1142 modded.sx >= vxres || modded.sy >= vyres || 1128 modded.sx >= vxres || modded.sy >= vyres ||
1143 modded.dx >= vxres || modded.dy >= vyres) 1129 modded.dx >= vxres || modded.dy >= vyres)
1144 return; 1130 return;
1145 1131
1146 if(modded.sx + modded.width > vxres) 1132 if (modded.sx + modded.width > vxres)
1147 modded.width = vxres - modded.sx; 1133 modded.width = vxres - modded.sx;
1148 if(modded.dx + modded.width > vxres) 1134 if (modded.dx + modded.width > vxres)
1149 modded.width = vxres - modded.dx; 1135 modded.width = vxres - modded.dx;
1150 if(modded.sy + modded.height > vyres) 1136 if (modded.sy + modded.height > vyres)
1151 modded.height = vyres - modded.sy; 1137 modded.height = vyres - modded.sy;
1152 if(modded.dy + modded.height > vyres) 1138 if (modded.dy + modded.height > vyres)
1153 modded.height = vyres - modded.dy; 1139 modded.height = vyres - modded.dy;
1154 1140
1155 pm2fb_block_op(info, 1, modded.sx, modded.sy, 1141 WAIT_FIFO(par, 5);
1156 modded.dx, modded.dy, 1142 pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
1157 modded.width, modded.height, 0); 1143 PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
1144 pm2_WR(par, PM2R_FB_SOURCE_DELTA,
1145 ((modded.sy - modded.dy) & 0xfff) << 16 |
1146 ((modded.sx - modded.dx) & 0xfff));
1147 pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
1148 pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
1149 wmb();
1150 pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
1151 (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) |
1152 (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0));
1153}
1154
1155static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
1156{
1157 struct pm2fb_par *par = info->par;
1158 u32 height = image->height;
1159 u32 fgx, bgx;
1160 const u32 *src = (const u32 *)image->data;
1161 u32 xres = (info->var.xres + 31) & ~31;
1162
1163 if (info->state != FBINFO_STATE_RUNNING)
1164 return;
1165 if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) {
1166 cfb_imageblit(info, image);
1167 return;
1168 }
1169 switch (info->fix.visual) {
1170 case FB_VISUAL_PSEUDOCOLOR:
1171 fgx = image->fg_color;
1172 bgx = image->bg_color;
1173 break;
1174 case FB_VISUAL_TRUECOLOR:
1175 default:
1176 fgx = par->palette[image->fg_color];
1177 bgx = par->palette[image->bg_color];
1178 break;
1179 }
1180 if (info->var.bits_per_pixel == 8) {
1181 fgx |= fgx << 8;
1182 bgx |= bgx << 8;
1183 }
1184 if (info->var.bits_per_pixel <= 16) {
1185 fgx |= fgx << 16;
1186 bgx |= bgx << 16;
1187 }
1188
1189 WAIT_FIFO(par, 13);
1190 pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
1191 pm2_WR(par, PM2R_SCISSOR_MIN_XY,
1192 ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
1193 pm2_WR(par, PM2R_SCISSOR_MAX_XY,
1194 (((image->dy + image->height) & 0x0fff) << 16) |
1195 ((image->dx + image->width) & 0x0fff));
1196 pm2_WR(par, PM2R_SCISSOR_MODE, 1);
1197 /* GXcopy & UNIT_ENABLE */
1198 pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1);
1199 pm2_WR(par, PM2R_RECTANGLE_ORIGIN,
1200 ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
1201 pm2_WR(par, PM2R_RECTANGLE_SIZE,
1202 ((image->height & 0x0fff) << 16) |
1203 ((image->width) & 0x0fff));
1204 if (info->var.bits_per_pixel == 24) {
1205 pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
1206 /* clear area */
1207 pm2_WR(par, PM2R_CONSTANT_COLOR, bgx);
1208 pm2_WR(par, PM2R_RENDER,
1209 PM2F_RENDER_RECTANGLE |
1210 PM2F_INCREASE_X | PM2F_INCREASE_Y);
1211 /* BitMapPackEachScanline & invert bits and byte order*/
1212 /* force background */
1213 pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7));
1214 pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
1215 pm2_WR(par, PM2R_RENDER,
1216 PM2F_RENDER_RECTANGLE |
1217 PM2F_INCREASE_X | PM2F_INCREASE_Y |
1218 PM2F_RENDER_SYNC_ON_BIT_MASK);
1219 } else {
1220 pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1221 /* clear area */
1222 pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx);
1223 pm2_WR(par, PM2R_RENDER,
1224 PM2F_RENDER_RECTANGLE |
1225 PM2F_RENDER_FASTFILL |
1226 PM2F_INCREASE_X | PM2F_INCREASE_Y);
1227 /* invert bits and byte order*/
1228 pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7));
1229 pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
1230 pm2_WR(par, PM2R_RENDER,
1231 PM2F_RENDER_RECTANGLE |
1232 PM2F_INCREASE_X | PM2F_INCREASE_Y |
1233 PM2F_RENDER_FASTFILL |
1234 PM2F_RENDER_SYNC_ON_BIT_MASK);
1235 }
1236
1237 while (height--) {
1238 int width = ((image->width + 7) >> 3)
1239 + info->pixmap.scan_align - 1;
1240 width >>= 2;
1241 WAIT_FIFO(par, width);
1242 while (width--) {
1243 pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src);
1244 src++;
1245 }
1246 }
1247 WAIT_FIFO(par, 3);
1248 pm2_WR(par, PM2R_RASTERIZER_MODE, 0);
1249 pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1250 pm2_WR(par, PM2R_SCISSOR_MODE, 0);
1251}
1252
1253/*
1254 * Hardware cursor support.
1255 */
1256static const u8 cursor_bits_lookup[16] = {
1257 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1258 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1259};
1260
1261static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1262{
1263 struct pm2fb_par *par = info->par;
1264 u8 mode = PM2F_CURSORMODE_TYPE_X;
1265 int x = cursor->image.dx - info->var.xoffset;
1266 int y = cursor->image.dy - info->var.yoffset;
1267
1268 if (cursor->enable)
1269 mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
1270
1271 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
1272
1273 if (!cursor->enable)
1274 x = 2047; /* push it outside display */
1275 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1276 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
1277 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
1278 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
1279
1280 /*
1281 * If the cursor is not be changed this means either we want the
1282 * current cursor state (if enable is set) or we want to query what
1283 * we can do with the cursor (if enable is not set)
1284 */
1285 if (!cursor->set)
1286 return 0;
1287
1288 if (cursor->set & FB_CUR_SETHOT) {
1289 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
1290 cursor->hot.x & 0x3f);
1291 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT,
1292 cursor->hot.y & 0x3f);
1293 }
1294
1295 if (cursor->set & FB_CUR_SETCMAP) {
1296 u32 fg_idx = cursor->image.fg_color;
1297 u32 bg_idx = cursor->image.bg_color;
1298 struct fb_cmap cmap = info->cmap;
1299
1300 /* the X11 driver says one should use these color registers */
1301 pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1302 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0,
1303 cmap.red[bg_idx] >> 8 );
1304 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1,
1305 cmap.green[bg_idx] >> 8 );
1306 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2,
1307 cmap.blue[bg_idx] >> 8 );
1308
1309 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3,
1310 cmap.red[fg_idx] >> 8 );
1311 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4,
1312 cmap.green[fg_idx] >> 8 );
1313 pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5,
1314 cmap.blue[fg_idx] >> 8 );
1315 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
1316 }
1317
1318 if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
1319 u8 *bitmap = (u8 *)cursor->image.data;
1320 u8 *mask = (u8 *)cursor->mask;
1321 int i;
1322 int pos = PM2VI_RD_CURSOR_PATTERN;
1323
1324 for (i = 0; i < cursor->image.height; i++) {
1325 int j = (cursor->image.width + 7) >> 3;
1326 int k = 8 - j;
1327
1328 pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
1329
1330 for (; j > 0; j--) {
1331 u8 data = *bitmap ^ *mask;
1332
1333 if (cursor->rop == ROP_COPY)
1334 data = *mask & *bitmap;
1335 /* Upper 4 bits of bitmap data */
1336 pm2v_RDAC_WR(par, pos++,
1337 cursor_bits_lookup[data >> 4] |
1338 (cursor_bits_lookup[*mask >> 4] << 1));
1339 /* Lower 4 bits of bitmap */
1340 pm2v_RDAC_WR(par, pos++,
1341 cursor_bits_lookup[data & 0xf] |
1342 (cursor_bits_lookup[*mask & 0xf] << 1));
1343 bitmap++;
1344 mask++;
1345 }
1346 for (; k > 0; k--) {
1347 pm2v_RDAC_WR(par, pos++, 0);
1348 pm2v_RDAC_WR(par, pos++, 0);
1349 }
1350 }
1351
1352 while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) {
1353 pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
1354 pm2v_RDAC_WR(par, pos++, 0);
1355 }
1356
1357 pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
1358 }
1359 return 0;
1360}
1361
1362static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1363{
1364 struct pm2fb_par *par = info->par;
1365 u8 mode;
1366
1367 if (!hwcursor)
1368 return -EINVAL; /* just to force soft_cursor() call */
1369
1370 /* Too large of a cursor or wrong bpp :-( */
1371 if (cursor->image.width > 64 ||
1372 cursor->image.height > 64 ||
1373 cursor->image.depth > 1)
1374 return -EINVAL;
1375
1376 if (par->type == PM2_TYPE_PERMEDIA2V)
1377 return pm2vfb_cursor(info, cursor);
1378
1379 mode = 0x40;
1380 if (cursor->enable)
1381 mode = 0x43;
1382
1383 pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
1384
1385 /*
1386 * If the cursor is not be changed this means either we want the
1387 * current cursor state (if enable is set) or we want to query what
1388 * we can do with the cursor (if enable is not set)
1389 */
1390 if (!cursor->set)
1391 return 0;
1392
1393 if (cursor->set & FB_CUR_SETPOS) {
1394 int x = cursor->image.dx - info->var.xoffset + 63;
1395 int y = cursor->image.dy - info->var.yoffset + 63;
1396
1397 WAIT_FIFO(par, 4);
1398 pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
1399 pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
1400 pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
1401 pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
1402 }
1403
1404 if (cursor->set & FB_CUR_SETCMAP) {
1405 u32 fg_idx = cursor->image.fg_color;
1406 u32 bg_idx = cursor->image.bg_color;
1407
1408 WAIT_FIFO(par, 7);
1409 pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
1410 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1411 info->cmap.red[bg_idx] >> 8);
1412 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1413 info->cmap.green[bg_idx] >> 8);
1414 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1415 info->cmap.blue[bg_idx] >> 8);
1416
1417 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1418 info->cmap.red[fg_idx] >> 8);
1419 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1420 info->cmap.green[fg_idx] >> 8);
1421 pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1422 info->cmap.blue[fg_idx] >> 8);
1423 }
1424
1425 if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
1426 u8 *bitmap = (u8 *)cursor->image.data;
1427 u8 *mask = (u8 *)cursor->mask;
1428 int i;
1429
1430 WAIT_FIFO(par, 1);
1431 pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
1432
1433 for (i = 0; i < cursor->image.height; i++) {
1434 int j = (cursor->image.width + 7) >> 3;
1435 int k = 8 - j;
1436
1437 WAIT_FIFO(par, 8);
1438 for (; j > 0; j--) {
1439 u8 data = *bitmap ^ *mask;
1440
1441 if (cursor->rop == ROP_COPY)
1442 data = *mask & *bitmap;
1443 /* bitmap data */
1444 pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
1445 bitmap++;
1446 mask++;
1447 }
1448 for (; k > 0; k--)
1449 pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1450 }
1451 for (; i < 64; i++) {
1452 int j = 8;
1453 WAIT_FIFO(par, 8);
1454 while (j-- > 0)
1455 pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1456 }
1457
1458 mask = (u8 *)cursor->mask;
1459 for (i = 0; i < cursor->image.height; i++) {
1460 int j = (cursor->image.width + 7) >> 3;
1461 int k = 8 - j;
1462
1463 WAIT_FIFO(par, 8);
1464 for (; j > 0; j--) {
1465 /* mask */
1466 pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
1467 mask++;
1468 }
1469 for (; k > 0; k--)
1470 pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1471 }
1472 for (; i < 64; i++) {
1473 int j = 8;
1474 WAIT_FIFO(par, 8);
1475 while (j-- > 0)
1476 pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1477 }
1478 }
1479 return 0;
1158} 1480}
1159 1481
1160/* ------------ Hardware Independent Functions ------------ */ 1482/* ------------ Hardware Independent Functions ------------ */
@@ -1172,8 +1494,9 @@ static struct fb_ops pm2fb_ops = {
1172 .fb_pan_display = pm2fb_pan_display, 1494 .fb_pan_display = pm2fb_pan_display,
1173 .fb_fillrect = pm2fb_fillrect, 1495 .fb_fillrect = pm2fb_fillrect,
1174 .fb_copyarea = pm2fb_copyarea, 1496 .fb_copyarea = pm2fb_copyarea,
1175 .fb_imageblit = cfb_imageblit, 1497 .fb_imageblit = pm2fb_imageblit,
1176 .fb_sync = pm2fb_sync, 1498 .fb_sync = pm2fb_sync,
1499 .fb_cursor = pm2fb_cursor,
1177}; 1500};
1178 1501
1179/* 1502/*
@@ -1194,16 +1517,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1194{ 1517{
1195 struct pm2fb_par *default_par; 1518 struct pm2fb_par *default_par;
1196 struct fb_info *info; 1519 struct fb_info *info;
1197 int err, err_retval = -ENXIO; 1520 int err;
1521 int retval = -ENXIO;
1198 1522
1199 err = pci_enable_device(pdev); 1523 err = pci_enable_device(pdev);
1200 if ( err ) { 1524 if (err) {
1201 printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err); 1525 printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
1202 return err; 1526 return err;
1203 } 1527 }
1204 1528
1205 info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev); 1529 info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
1206 if ( !info ) 1530 if (!info)
1207 return -ENOMEM; 1531 return -ENOMEM;
1208 default_par = info->par; 1532 default_par = info->par;
1209 1533
@@ -1236,14 +1560,14 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1236 DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start); 1560 DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
1237 1561
1238 /* Registers - request region and map it. */ 1562 /* Registers - request region and map it. */
1239 if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len, 1563 if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
1240 "pm2fb regbase") ) { 1564 "pm2fb regbase")) {
1241 printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n"); 1565 printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
1242 goto err_exit_neither; 1566 goto err_exit_neither;
1243 } 1567 }
1244 default_par->v_regs = 1568 default_par->v_regs =
1245 ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 1569 ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1246 if ( !default_par->v_regs ) { 1570 if (!default_par->v_regs) {
1247 printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n", 1571 printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
1248 pm2fb_fix.id); 1572 pm2fb_fix.id);
1249 release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 1573 release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
@@ -1258,72 +1582,101 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1258 default_par->mem_control, default_par->boot_address, 1582 default_par->mem_control, default_par->boot_address,
1259 default_par->mem_config); 1583 default_par->mem_config);
1260 1584
1261 if(default_par->mem_control == 0 && 1585 if (default_par->mem_control == 0 &&
1262 default_par->boot_address == 0x31 && 1586 default_par->boot_address == 0x31 &&
1263 default_par->mem_config == 0x259fffff) { 1587 default_par->mem_config == 0x259fffff) {
1264 default_par->memclock = CVPPC_MEMCLOCK; 1588 default_par->memclock = CVPPC_MEMCLOCK;
1265 default_par->mem_control=0; 1589 default_par->mem_control = 0;
1266 default_par->boot_address=0x20; 1590 default_par->boot_address = 0x20;
1267 default_par->mem_config=0xe6002021; 1591 default_par->mem_config = 0xe6002021;
1268 if (pdev->subsystem_vendor == 0x1048 && 1592 if (pdev->subsystem_vendor == 0x1048 &&
1269 pdev->subsystem_device == 0x0a31) { 1593 pdev->subsystem_device == 0x0a31) {
1270 DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", 1594 DPRINTK("subsystem_vendor: %04x, "
1595 "subsystem_device: %04x\n",
1271 pdev->subsystem_vendor, pdev->subsystem_device); 1596 pdev->subsystem_vendor, pdev->subsystem_device);
1272 DPRINTK("We have not been initialized by VGA BIOS " 1597 DPRINTK("We have not been initialized by VGA BIOS and "
1273 "and are running on an Elsa Winner 2000 Office\n"); 1598 "are running on an Elsa Winner 2000 Office\n");
1274 DPRINTK("Initializing card timings manually...\n"); 1599 DPRINTK("Initializing card timings manually...\n");
1275 default_par->memclock=70000; 1600 default_par->memclock = 100000;
1276 } 1601 }
1277 if (pdev->subsystem_vendor == 0x3d3d && 1602 if (pdev->subsystem_vendor == 0x3d3d &&
1278 pdev->subsystem_device == 0x0100) { 1603 pdev->subsystem_device == 0x0100) {
1279 DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", 1604 DPRINTK("subsystem_vendor: %04x, "
1605 "subsystem_device: %04x\n",
1280 pdev->subsystem_vendor, pdev->subsystem_device); 1606 pdev->subsystem_vendor, pdev->subsystem_device);
1281 DPRINTK("We have not been initialized by VGA BIOS " 1607 DPRINTK("We have not been initialized by VGA BIOS and "
1282 "and are running on an 3dlabs reference board\n"); 1608 "are running on an 3dlabs reference board\n");
1283 DPRINTK("Initializing card timings manually...\n"); 1609 DPRINTK("Initializing card timings manually...\n");
1284 default_par->memclock=74894; 1610 default_par->memclock = 74894;
1285 } 1611 }
1286 } 1612 }
1287 1613
1288 /* Now work out how big lfb is going to be. */ 1614 /* Now work out how big lfb is going to be. */
1289 switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { 1615 switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1290 case PM2F_MEM_BANKS_1: 1616 case PM2F_MEM_BANKS_1:
1291 pm2fb_fix.smem_len=0x200000; 1617 pm2fb_fix.smem_len = 0x200000;
1292 break; 1618 break;
1293 case PM2F_MEM_BANKS_2: 1619 case PM2F_MEM_BANKS_2:
1294 pm2fb_fix.smem_len=0x400000; 1620 pm2fb_fix.smem_len = 0x400000;
1295 break; 1621 break;
1296 case PM2F_MEM_BANKS_3: 1622 case PM2F_MEM_BANKS_3:
1297 pm2fb_fix.smem_len=0x600000; 1623 pm2fb_fix.smem_len = 0x600000;
1298 break; 1624 break;
1299 case PM2F_MEM_BANKS_4: 1625 case PM2F_MEM_BANKS_4:
1300 pm2fb_fix.smem_len=0x800000; 1626 pm2fb_fix.smem_len = 0x800000;
1301 break; 1627 break;
1302 } 1628 }
1303 pm2fb_fix.smem_start = pci_resource_start(pdev, 1); 1629 pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
1304 1630
1305 /* Linear frame buffer - request region and map it. */ 1631 /* Linear frame buffer - request region and map it. */
1306 if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len, 1632 if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
1307 "pm2fb smem") ) { 1633 "pm2fb smem")) {
1308 printk(KERN_WARNING "pm2fb: Can't reserve smem.\n"); 1634 printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
1309 goto err_exit_mmio; 1635 goto err_exit_mmio;
1310 } 1636 }
1311 info->screen_base = 1637 info->screen_base =
1312 ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 1638 ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1313 if ( !info->screen_base ) { 1639 if (!info->screen_base) {
1314 printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n"); 1640 printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
1315 release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 1641 release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1316 goto err_exit_mmio; 1642 goto err_exit_mmio;
1317 } 1643 }
1318 1644
1645#ifdef CONFIG_MTRR
1646 default_par->mtrr_handle = -1;
1647 if (!nomtrr)
1648 default_par->mtrr_handle =
1649 mtrr_add(pm2fb_fix.smem_start,
1650 pm2fb_fix.smem_len,
1651 MTRR_TYPE_WRCOMB, 1);
1652#endif
1653
1319 info->fbops = &pm2fb_ops; 1654 info->fbops = &pm2fb_ops;
1320 info->fix = pm2fb_fix; 1655 info->fix = pm2fb_fix;
1321 info->pseudo_palette = default_par->palette; 1656 info->pseudo_palette = default_par->palette;
1322 info->flags = FBINFO_DEFAULT | 1657 info->flags = FBINFO_DEFAULT |
1323 FBINFO_HWACCEL_YPAN | 1658 FBINFO_HWACCEL_YPAN |
1324 FBINFO_HWACCEL_COPYAREA | 1659 FBINFO_HWACCEL_COPYAREA |
1660 FBINFO_HWACCEL_IMAGEBLIT |
1325 FBINFO_HWACCEL_FILLRECT; 1661 FBINFO_HWACCEL_FILLRECT;
1326 1662
1663 info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
1664 if (!info->pixmap.addr) {
1665 retval = -ENOMEM;
1666 goto err_exit_pixmap;
1667 }
1668 info->pixmap.size = PM2_PIXMAP_SIZE;
1669 info->pixmap.buf_align = 4;
1670 info->pixmap.scan_align = 4;
1671 info->pixmap.access_align = 32;
1672 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1673
1674 if (noaccel) {
1675 printk(KERN_DEBUG "disabling acceleration\n");
1676 info->flags |= FBINFO_HWACCEL_DISABLED;
1677 info->pixmap.scan_align = 1;
1678 }
1679
1327 if (!mode) 1680 if (!mode)
1328 mode = "640x480@60"; 1681 mode = "640x480@60";
1329 1682
@@ -1350,6 +1703,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1350 err_exit_all: 1703 err_exit_all:
1351 fb_dealloc_cmap(&info->cmap); 1704 fb_dealloc_cmap(&info->cmap);
1352 err_exit_both: 1705 err_exit_both:
1706 kfree(info->pixmap.addr);
1707 err_exit_pixmap:
1353 iounmap(info->screen_base); 1708 iounmap(info->screen_base);
1354 release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len); 1709 release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1355 err_exit_mmio: 1710 err_exit_mmio:
@@ -1357,7 +1712,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1357 release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len); 1712 release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1358 err_exit_neither: 1713 err_exit_neither:
1359 framebuffer_release(info); 1714 framebuffer_release(info);
1360 return err_retval; 1715 return retval;
1361} 1716}
1362 1717
1363/** 1718/**
@@ -1369,34 +1724,34 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
1369 */ 1724 */
1370static void __devexit pm2fb_remove(struct pci_dev *pdev) 1725static void __devexit pm2fb_remove(struct pci_dev *pdev)
1371{ 1726{
1372 struct fb_info* info = pci_get_drvdata(pdev); 1727 struct fb_info *info = pci_get_drvdata(pdev);
1373 struct fb_fix_screeninfo* fix = &info->fix; 1728 struct fb_fix_screeninfo *fix = &info->fix;
1374 struct pm2fb_par *par = info->par; 1729 struct pm2fb_par *par = info->par;
1375 1730
1376 unregister_framebuffer(info); 1731 unregister_framebuffer(info);
1377 1732
1733#ifdef CONFIG_MTRR
1734 if (par->mtrr_handle >= 0)
1735 mtrr_del(par->mtrr_handle, info->fix.smem_start,
1736 info->fix.smem_len);
1737#endif /* CONFIG_MTRR */
1378 iounmap(info->screen_base); 1738 iounmap(info->screen_base);
1379 release_mem_region(fix->smem_start, fix->smem_len); 1739 release_mem_region(fix->smem_start, fix->smem_len);
1380 iounmap(par->v_regs); 1740 iounmap(par->v_regs);
1381 release_mem_region(fix->mmio_start, fix->mmio_len); 1741 release_mem_region(fix->mmio_start, fix->mmio_len);
1382 1742
1383 pci_set_drvdata(pdev, NULL); 1743 pci_set_drvdata(pdev, NULL);
1744 kfree(info->pixmap.addr);
1384 kfree(info); 1745 kfree(info);
1385} 1746}
1386 1747
1387static struct pci_device_id pm2fb_id_table[] = { 1748static struct pci_device_id pm2fb_id_table[] = {
1388 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, 1749 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
1389 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 1750 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1390 0xff0000, 0 },
1391 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, 1751 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
1392 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, 1752 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1393 0xff0000, 0 },
1394 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
1395 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
1396 0xff0000, 0 },
1397 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, 1753 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
1398 PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8, 1754 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1399 0xff00, 0 },
1400 { 0, } 1755 { 0, }
1401}; 1756};
1402 1757
@@ -1418,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
1418 */ 1773 */
1419static int __init pm2fb_setup(char *options) 1774static int __init pm2fb_setup(char *options)
1420{ 1775{
1421 char* this_opt; 1776 char *this_opt;
1422 1777
1423 if (!options || !*options) 1778 if (!options || !*options)
1424 return 0; 1779 return 0;
@@ -1426,13 +1781,20 @@ static int __init pm2fb_setup(char *options)
1426 while ((this_opt = strsep(&options, ",")) != NULL) { 1781 while ((this_opt = strsep(&options, ",")) != NULL) {
1427 if (!*this_opt) 1782 if (!*this_opt)
1428 continue; 1783 continue;
1429 if(!strcmp(this_opt, "lowhsync")) { 1784 if (!strcmp(this_opt, "lowhsync"))
1430 lowhsync = 1; 1785 lowhsync = 1;
1431 } else if(!strcmp(this_opt, "lowvsync")) { 1786 else if (!strcmp(this_opt, "lowvsync"))
1432 lowvsync = 1; 1787 lowvsync = 1;
1433 } else { 1788 else if (!strncmp(this_opt, "hwcursor=", 9))
1789 hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
1790#ifdef CONFIG_MTRR
1791 else if (!strncmp(this_opt, "nomtrr", 6))
1792 nomtrr = 1;
1793#endif
1794 else if (!strncmp(this_opt, "noaccel", 7))
1795 noaccel = 1;
1796 else
1434 mode = this_opt; 1797 mode = this_opt;
1435 }
1436 } 1798 }
1437 return 0; 1799 return 0;
1438} 1800}
@@ -1474,6 +1836,15 @@ module_param(lowhsync, bool, 0);
1474MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode"); 1836MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
1475module_param(lowvsync, bool, 0); 1837module_param(lowvsync, bool, 0);
1476MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode"); 1838MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
1839module_param(noaccel, bool, 0);
1840MODULE_PARM_DESC(noaccel, "Disable acceleration");
1841module_param(hwcursor, int, 0644);
1842MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1843 "(1=enable, 0=disable, default=1)");
1844#ifdef CONFIG_MTRR
1845module_param(nomtrr, bool, 0);
1846MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
1847#endif
1477 1848
1478MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>"); 1849MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
1479MODULE_DESCRIPTION("Permedia2 framebuffer device driver"); 1850MODULE_DESCRIPTION("Permedia2 framebuffer device driver");