Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-block.git] / drivers / video / cyblafb.c
CommitLineData
9fa68eae
KP
1/*
2 * Frame buffer driver for Trident Cyberblade/i1 graphics core
3 *
4 * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de>
5 *
6 * CREDITS:
7 * tridentfb.c by Jani Monoses
8 * see files above for further credits
9 *
9fa68eae
KP
10 */
11
12#define CYBLAFB_DEBUG 0
44637a12
KP
13#define CYBLAFB_KD_GRAPHICS_QUIRK 1
14
15#define CYBLAFB_PIXMAPSIZE 8192
9fa68eae 16
9fa68eae
KP
17#include <linux/module.h>
18#include <linux/string.h>
19#include <linux/fb.h>
20#include <linux/init.h>
21#include <linux/pci.h>
22#include <asm/types.h>
23#include <video/cyblafb.h>
24
44637a12 25#define VERSION "0.62"
9fa68eae
KP
26
27struct cyblafb_par {
28 u32 pseudo_pal[16];
29 struct fb_ops ops;
30};
31
32static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
33 .id = "CyBla",
34 .type = FB_TYPE_PACKED_PIXELS,
44637a12 35 .xpanstep = 1,
9fa68eae 36 .ypanstep = 1,
44637a12 37 .ywrapstep = 1,
9fa68eae
KP
38 .visual = FB_VISUAL_PSEUDOCOLOR,
39 .accel = FB_ACCEL_NONE,
40};
41
42static char *mode __devinitdata = NULL;
43static int bpp __devinitdata = 8;
44static int ref __devinitdata = 75;
45static int fp __devinitdata;
46static int crt __devinitdata;
47static int memsize __devinitdata;
9fa68eae 48
44637a12
KP
49static int basestride;
50static int vesafb;
9fa68eae
KP
51static int nativex;
52static int center;
53static int stretch;
54static int pciwb = 1;
55static int pcirb = 1;
56static int pciwr = 1;
57static int pcirr = 1;
44637a12 58static int disabled;
9fa68eae
KP
59static int verbosity;
60static int displaytype;
61
44637a12
KP
62static void __iomem *io_virt; // iospace virtual memory address
63
64module_param(mode, charp, 0);
65module_param(bpp, int, 0);
66module_param(ref, int, 0);
67module_param(fp, int, 0);
68module_param(crt, int, 0);
69module_param(nativex, int, 0);
70module_param(center, int, 0);
71module_param(stretch, int, 0);
72module_param(pciwb, int, 0);
73module_param(pcirb, int, 0);
74module_param(pciwr, int, 0);
75module_param(pcirr, int, 0);
76module_param(memsize, int, 0);
77module_param(verbosity, int, 0);
78
79//=========================================
80//
81// Well, we have to fix the upper layers.
82// Until this has been done, we work around
83// the bugs.
84//
85//=========================================
86
87#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
88 if (disabled) { \
89 printk("********\n");\
90 dump_stack();\
91 return val;\
92 }
93
94#elif CYBLAFB_KD_GRAPHICS_QUIRK
95#define KD_GRAPHICS_RETURN(val)\
96 if (disabled) {\
97 return val;\
98 }
99#else
100#define KD_GRAPHICS_RETURN(val)
101#endif
9fa68eae
KP
102
103//=========================================
104//
105// Port access macros for memory mapped io
106//
107//=========================================
108
44637a12
KP
109#define out8(r, v) writeb(v, io_virt + r)
110#define out32(r, v) writel(v, io_virt + r)
111#define in8(r) readb(io_virt + r)
112#define in32(r) readl(io_virt + r)
9fa68eae
KP
113
114//======================================
115//
116// Hardware access inline functions
117//
118//======================================
119
44637a12 120static inline u8 read3X4(u32 reg)
9fa68eae 121{
44637a12 122 out8(0x3D4, reg);
9fa68eae
KP
123 return in8(0x3D5);
124}
125
44637a12 126static inline u8 read3C4(u32 reg)
9fa68eae 127{
44637a12 128 out8(0x3C4, reg);
9fa68eae
KP
129 return in8(0x3C5);
130}
131
44637a12 132static inline u8 read3CE(u32 reg)
9fa68eae 133{
44637a12 134 out8(0x3CE, reg);
9fa68eae
KP
135 return in8(0x3CF);
136}
137
44637a12 138static inline void write3X4(u32 reg, u8 val)
9fa68eae 139{
44637a12
KP
140 out8(0x3D4, reg);
141 out8(0x3D5, val);
9fa68eae
KP
142}
143
44637a12 144static inline void write3C4(u32 reg, u8 val)
9fa68eae 145{
44637a12
KP
146 out8(0x3C4, reg);
147 out8(0x3C5, val);
9fa68eae
KP
148}
149
44637a12 150static inline void write3CE(u32 reg, u8 val)
9fa68eae 151{
44637a12
KP
152 out8(0x3CE, reg);
153 out8(0x3CF, val);
9fa68eae
KP
154}
155
44637a12 156static inline void write3C0(u32 reg, u8 val)
9fa68eae 157{
44637a12
KP
158 in8(0x3DA); // read to reset index
159 out8(0x3C0, reg);
160 out8(0x3C0, val);
9fa68eae
KP
161}
162
163//=================================================
164//
165// Enable memory mapped io and unprotect registers
166//
167//=================================================
168
44637a12 169static void enable_mmio(void)
9fa68eae 170{
44637a12 171 u8 tmp;
9fa68eae 172
44637a12 173 outb(0x0B, 0x3C4);
9fa68eae 174 inb(0x3C5); // Set NEW mode
44637a12
KP
175 outb(SR0E, 0x3C4); // write enable a lot of extended ports
176 outb(0x80, 0x3C5);
9fa68eae 177
44637a12
KP
178 outb(SR11, 0x3C4); // write enable those extended ports that
179 outb(0x87, 0x3C5); // are not affected by SR0E_New
9fa68eae 180
44637a12
KP
181 outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2
182 tmp = inb(0x3d5) & 0xBF;
183 outb(CR1E, 0x3d4);
184 outb(tmp, 0x3d5);
9fa68eae 185
44637a12
KP
186 outb(CR39, 0x3D4);
187 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
9fa68eae
KP
188}
189
190//=================================================
191//
192// Set pixel clock VCLK1
44637a12
KP
193// - multipliers set elswhere
194// - freq in units of 0.01 MHz
195//
196// Hardware bug: SR18 >= 250 is broken for the
197// cyberblade/i1
9fa68eae
KP
198//
199//=================================================
200
201static void set_vclk(struct cyblafb_par *par, int freq)
202{
44637a12
KP
203 u32 m, n, k;
204 int f, fi, d, di;
205 u8 lo = 0, hi = 0;
9fa68eae
KP
206
207 d = 2000;
208 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
44637a12
KP
209 for (m = 0; m < 64; m++)
210 for (n = 0; n < 250; n++) {
211 fi = (int)(((5864727 * (n + 8)) /
212 ((m + 2) * (1 << k))) >> 12);
213 if ((di = abs(fi - freq)) < d) {
214 d = di;
215 f = fi;
216 lo = (u8) n;
217 hi = (u8) ((k << 6) | m);
218 }
9fa68eae 219 }
44637a12
KP
220 write3C4(SR19, hi);
221 write3C4(SR18, lo);
222 if (verbosity > 0)
9fa68eae 223 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
44637a12 224 freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
9fa68eae
KP
225}
226
227//================================================
228//
229// Cyberblade specific Graphics Engine (GE) setup
230//
231//================================================
232
44637a12 233static void cyblafb_setup_GE(int pitch, int bpp)
9fa68eae 234{
44637a12 235 KD_GRAPHICS_RETURN();
9fa68eae
KP
236
237 switch (bpp) {
44637a12
KP
238 case 8:
239 basestride = ((pitch >> 3) << 20) | (0 << 29);
240 break;
241 case 15:
242 basestride = ((pitch >> 3) << 20) | (5 << 29);
243 break;
244 case 16:
245 basestride = ((pitch >> 3) << 20) | (1 << 29);
246 break;
247 case 24:
248 case 32:
249 basestride = ((pitch >> 3) << 20) | (2 << 29);
250 break;
9fa68eae
KP
251 }
252
44637a12
KP
253 write3X4(CR36, 0x90); // reset GE
254 write3X4(CR36, 0x80); // enable GE
255 out32(GE24, 1 << 7); // reset all GE pointers by toggling
256 out32(GE24, 0); // d7 of GE24
257 write3X4(CR2D, 0x00); // GE Timinigs, no delays
258 out32(GE6C, 0); // Pattern and Style, p 129, ok
9fa68eae
KP
259}
260
261//=====================================================================
262//
44637a12
KP
263// Cyberblade specific syncing
264//
265// A timeout might be caused by disabled mmio.
266// Cause:
267// - bit CR39 & 1 == 0 upon return, X trident driver bug
268// - kdm bug (KD_GRAPHICS not set on first switch)
269// - kernel design flaw (it believes in the correctness
270// of kdm/X
271// First we try to sync ignoring that problem, as most of the
272// time that will succeed immediately and the enable_mmio()
273// would only degrade performance.
9fa68eae
KP
274//
275//=====================================================================
276
277static int cyblafb_sync(struct fb_info *info)
278{
44637a12
KP
279 u32 status, i = 100000;
280
281 KD_GRAPHICS_RETURN(0);
282
283 while (((status = in32(GE20)) & 0xFe800000) && i != 0)
9fa68eae
KP
284 i--;
285
286 if (i == 0) {
9fa68eae 287 enable_mmio();
44637a12
KP
288 i = 1000000;
289 while (((status = in32(GE20)) & 0xFA800000) && i != 0)
9fa68eae
KP
290 i--;
291 if (i == 0) {
44637a12
KP
292 output("GE Timeout, status: %x\n", status);
293 if (status & 0x80000000)
9fa68eae 294 output("Bresenham Engine : Busy\n");
44637a12 295 if (status & 0x40000000)
9fa68eae 296 output("Setup Engine : Busy\n");
44637a12 297 if (status & 0x20000000)
9fa68eae 298 output("SP / DPE : Busy\n");
44637a12 299 if (status & 0x10000000)
9fa68eae 300 output("Memory Interface : Busy\n");
44637a12 301 if (status & 0x08000000)
9fa68eae 302 output("Com Lst Proc : Busy\n");
44637a12 303 if (status & 0x04000000)
9fa68eae 304 output("Block Write : Busy\n");
44637a12 305 if (status & 0x02000000)
9fa68eae 306 output("Command Buffer : Full\n");
44637a12 307 if (status & 0x01000000)
9fa68eae 308 output("RESERVED : Busy\n");
44637a12 309 if (status & 0x00800000)
9fa68eae
KP
310 output("PCI Write Buffer : Busy\n");
311 cyblafb_setup_GE(info->var.xres,
312 info->var.bits_per_pixel);
313 }
314 }
315
316 return 0;
317}
318
319//==============================
320//
321// Cyberblade specific fillrect
322//
323//==============================
324
44637a12 325static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
9fa68eae 326{
44637a12
KP
327 u32 bpp = info->var.bits_per_pixel, col, desty, height;
328
329 KD_GRAPHICS_RETURN();
9fa68eae
KP
330
331 switch (bpp) {
44637a12
KP
332 default:
333 case 8:
334 col = fr->color;
335 col |= col << 8;
336 col |= col << 16;
337 break;
338 case 16:
339 col = ((u32 *) (info->pseudo_palette))[fr->color];
340 col |= col << 16;
341 break;
342 case 32:
343 col = ((u32 *) (info->pseudo_palette))[fr->color];
344 break;
9fa68eae
KP
345 }
346
44637a12
KP
347 desty = fr->dy;
348 height = fr->height;
349 while (height) {
350 out32(GEB8, basestride | ((desty * info->var.xres_virtual *
351 bpp) >> 6));
352 out32(GE60, col);
353 out32(GE48, fr->rop ? 0x66 : ROP_S);
354 out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
355 out32(GE08, point(fr->dx, 0));
356 out32(GE0C, point(fr->dx + fr->width - 1,
357 height > 4096 ? 4095 : height - 1));
358 if (likely(height <= 4096))
359 return;
360 desty += 4096;
361 height -= 4096;
362 }
9fa68eae
KP
363}
364
44637a12 365//================================================
9fa68eae
KP
366//
367// Cyberblade specific copyarea
368//
44637a12
KP
369// This function silently assumes that it never
370// will be called with width or height exceeding
371// 4096.
372//
373//================================================
9fa68eae 374
44637a12 375static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
9fa68eae 376{
44637a12
KP
377 u32 s1, s2, d1, d2, direction;
378
379 KD_GRAPHICS_RETURN();
380
381 s1 = point(ca->sx, 0);
382 s2 = point(ca->sx + ca->width - 1, ca->height - 1);
383 d1 = point(ca->dx, 0);
384 d2 = point(ca->dx + ca->width - 1, ca->height - 1);
9fa68eae 385
9fa68eae
KP
386 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
387 direction = 0;
388 else
389 direction = 2;
390
44637a12
KP
391 out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
392 info->var.bits_per_pixel) >> 6));
393 out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
394 info->var.bits_per_pixel) >> 6));
395 out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
396 out32(GE00, direction ? s2 : s1);
397 out32(GE04, direction ? s1 : s2);
398 out32(GE08, direction ? d2 : d1);
399 out32(GE0C, direction ? d1 : d2);
9fa68eae
KP
400}
401
402//=======================================================================
403//
404// Cyberblade specific imageblit
405//
44637a12
KP
406// Accelerated for the most usual case, blitting 1 - bit deep
407// character images. Everything else is passed to the generic imageblit
408// unless it is so insane that it is better to printk an alert.
409//
410// Hardware bug: _Never_ blit across pixel column 2048, that will lock
411// the system. We split those blit requests into three blitting
412// operations.
9fa68eae
KP
413//
414//=======================================================================
415
416static void cyblafb_imageblit(struct fb_info *info,
417 const struct fb_image *image)
418{
9fa68eae 419 u32 fgcol, bgcol;
44637a12
KP
420 u32 *pd = (u32 *) image->data;
421 u32 bpp = info->var.bits_per_pixel;
9fa68eae 422
44637a12
KP
423 KD_GRAPHICS_RETURN();
424
425 // Used only for drawing the penguine (image->depth > 1)
426 if (image->depth != 1) {
427 cfb_imageblit(info, image);
428 return;
429 }
430 // That should never happen, but it would be fatal
431 if (image->width == 0 || image->height == 0) {
432 output("imageblit: width/height 0 detected\n");
9fa68eae
KP
433 return;
434 }
435
436 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
437 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
44637a12
KP
438 fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
439 bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
9fa68eae
KP
440 } else {
441 fgcol = image->fg_color;
442 bgcol = image->bg_color;
443 }
444
445 switch (bpp) {
44637a12
KP
446 case 8:
447 fgcol |= fgcol << 8;
448 bgcol |= bgcol << 8;
449 case 16:
450 fgcol |= fgcol << 16;
451 bgcol |= bgcol << 16;
452 default:
453 break;
9fa68eae
KP
454 }
455
44637a12
KP
456 out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
457 bpp) >> 6));
458 out32(GE60, fgcol);
459 out32(GE64, bgcol);
460
461 if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
462 u32 dds = ((image->width + 31) >> 5) * image->height;
463 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
464 out32(GE08, point(image->dx, 0));
465 out32(GE0C, point(image->dx + image->width - 1,
466 image->height - 1));
467 while (dds--)
468 out32(GE9C, *pd++);
469 } else {
470 int i, j;
471 u32 ddstotal = (image->width + 31) >> 5;
472 u32 ddsleft = (2048 - image->dx + 31) >> 5;
473 u32 skipleft = ddstotal - ddsleft;
474
475 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
476 out32(GE08, point(image->dx, 0));
477 out32(GE0C, point(2048 - 1, image->height - 1));
478 for (i = 0; i < image->height; i++) {
479 for (j = 0; j < ddsleft; j++)
480 out32(GE9C, *pd++);
481 pd += skipleft;
482 }
9fa68eae 483
44637a12
KP
484 if (image->dx % 32) {
485 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
486 out32(GE08, point(2048, 0));
487 if (image->width > ddsleft << 5)
488 out32(GE0C, point(image->dx + (ddsleft << 5) -
489 1, image->height - 1));
490 else
491 out32(GE0C, point(image->dx + image->width - 1,
492 image->height - 1));
493 pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
494 for (i = 0; i < image->height; i++) {
495 out32(GE9C, swab32(swab32(*pd) << ((32 -
496 (image->dx & 31)) & 31)));
497 pd += ddstotal;
498 }
9fa68eae 499 }
44637a12
KP
500
501 if (skipleft) {
502 out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
503 out32(GE08, point(image->dx + (ddsleft << 5), 0));
504 out32(GE0C, point(image->dx + image->width - 1,
505 image->height - 1));
506 pd = (u32 *) image->data;
507 for (i = 0; i < image->height; i++) {
508 pd += ddsleft;
509 for (j = 0; j < skipleft; j++)
510 out32(GE9C, *pd++);
511 }
9fa68eae
KP
512 }
513 }
514}
515
516//==========================================================
517//
518// Check if video mode is acceptable. We change var->??? if
519// video mode is slightly off or return error otherwise.
520// info->??? must not be changed!
521//
522//==========================================================
523
524static int cyblafb_check_var(struct fb_var_screeninfo *var,
525 struct fb_info *info)
526{
527 int bpp = var->bits_per_pixel;
9fa68eae
KP
528
529 //
530 // we try to support 8, 16, 24 and 32 bpp modes,
531 // default to 8
532 //
533 // there is a 24 bpp mode, but for now we change requests to 32 bpp
534 // (This is what tridentfb does ... will be changed in the future)
535 //
536 //
44637a12 537 if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
9fa68eae 538 bpp = 8;
44637a12 539 if (bpp == 24)
9fa68eae
KP
540 bpp = var->bits_per_pixel = 32;
541
542 //
543 // interlaced modes are broken, fail if one is requested
544 //
545 if (var->vmode & FB_VMODE_INTERLACED)
546 return -EINVAL;
547
548 //
549 // fail if requested resolution is higher than physical
550 // flatpanel resolution
551 //
552 if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)
553 return -EINVAL;
554
555 //
44637a12
KP
556 // we do not allow vclk to exceed 230 MHz. If the requested
557 // vclk is too high, we default to 200 MHz
9fa68eae 558 //
44637a12
KP
559 if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
560 var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
9fa68eae
KP
561
562 //
44637a12 563 // enforce (h|v)sync_len limits
9fa68eae 564 //
44637a12
KP
565 var->hsync_len &= ~7;
566 if(var->hsync_len > 248)
567 var->hsync_len = 248;
568
569 var->vsync_len &= 15;
9fa68eae
KP
570
571 //
44637a12
KP
572 // Enforce horizontal and vertical hardware limits.
573 // 1600x1200 is mentioned as a maximum, but higher resolutions could
574 // work with slow refresh, small margins and short sync.
9fa68eae 575 //
44637a12
KP
576 var->xres &= ~7;
577
578 if (((var->xres + var->left_margin + var->right_margin +
579 var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
580 ((var->yres + var->upper_margin + var->lower_margin +
581 var->vsync_len) > 2047))
9fa68eae
KP
582 return -EINVAL;
583
44637a12
KP
584 if ((var->xres > 1600) || (var->yres > 1200))
585 output("Mode %dx%d exceeds documented limits.\n",
586 var->xres, var->yres);
587 //
588 // try to be smart about (x|y)res_virtual problems.
589 //
590 if (var->xres > var->xres_virtual)
591 var->xres_virtual = var->xres;
592 if (var->yres > var->yres_virtual)
593 var->yres_virtual = var->yres;
594
595 if (bpp == 8 || bpp == 16) {
596 if (var->xres_virtual > 4088)
597 var->xres_virtual = 4088;
598 } else {
599 if (var->xres_virtual > 2040)
600 var->xres_virtual = 2040;
601 }
602 var->xres_virtual &= ~7;
603 while (var->xres_virtual * var->yres_virtual * bpp / 8 >
604 info->fix.smem_len) {
605 if (var->yres_virtual > var->yres)
606 var->yres_virtual--;
607 else if (var->xres_virtual > var->xres)
608 var->xres_virtual -= 8;
609 else
9fa68eae
KP
610 return -EINVAL;
611 }
612
44637a12
KP
613 switch (bpp) {
614 case 8:
615 var->red.offset = 0;
616 var->green.offset = 0;
617 var->blue.offset = 0;
618 var->red.length = 6;
619 var->green.length = 6;
620 var->blue.length = 6;
621 break;
622 case 16:
623 var->red.offset = 11;
624 var->green.offset = 5;
625 var->blue.offset = 0;
626 var->red.length = 5;
627 var->green.length = 6;
628 var->blue.length = 5;
629 break;
630 case 32:
631 var->red.offset = 16;
632 var->green.offset = 8;
633 var->blue.offset = 0;
634 var->red.length = 8;
635 var->green.length = 8;
636 var->blue.length = 8;
637 break;
638 default:
639 return -EINVAL;
640 }
9fa68eae 641
44637a12 642 return 0;
9fa68eae
KP
643}
644
645//=====================================================================
646//
647// Pan the display
648//
649// The datasheets defines crt start address to be 20 bits wide and
650// to be programmed to CR0C, CR0D, CR1E and CR27. Actually there is
651// CR2B[5] as an undocumented extension bit. Epia BIOS 2.07 does use
652// it, so it is also safe to be used here. BTW: datasheet CR0E on page
653// 90 really is CR1E, the real CRE is documented on page 72.
654//
44637a12
KP
655// BUT:
656//
657// As of internal version 0.60 we do not use vga panning any longer.
658// Vga panning did not allow us the use of all available video memory
659// and thus prevented ywrap scrolling. We do use the "right view"
660// register now.
661//
662//
9fa68eae
KP
663//=====================================================================
664
665static int cyblafb_pan_display(struct fb_var_screeninfo *var,
666 struct fb_info *info)
667{
44637a12 668 KD_GRAPHICS_RETURN(0);
9fa68eae 669
9fa68eae
KP
670 info->var.xoffset = var->xoffset;
671 info->var.yoffset = var->yoffset;
44637a12
KP
672 out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
673 var->xres_virtual)) * var->bits_per_pixel / 32));
9fa68eae
KP
674 return 0;
675}
676
677//============================================
678//
679// This will really help in case of a bug ...
680// dump most gaphics core registers.
681//
682//============================================
683
684static void regdump(struct cyblafb_par *par)
685{
686 int i;
687
688 if (verbosity < 2)
689 return;
690
691 printk("\n");
44637a12
KP
692 for (i = 0; i <= 0xff; i++) {
693 outb(i, 0x3d4);
694 printk("CR%02x=%02x ", i, inb(0x3d5));
695 if (i % 16 == 15)
9fa68eae
KP
696 printk("\n");
697 }
698
44637a12
KP
699 outb(0x30, 0x3ce);
700 outb(inb(0x3cf) | 0x40, 0x3cf);
701 for (i = 0; i <= 0x1f; i++) {
702 if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
703 || i == 0x16) {
704 outb(i, 0x3d4);
705 printk("CR%02x=%02x ", i, inb(0x3d5));
9fa68eae
KP
706 } else
707 printk("------- ");
44637a12 708 if (i % 16 == 15)
9fa68eae
KP
709 printk("\n");
710 }
44637a12
KP
711 outb(0x30, 0x3ce);
712 outb(inb(0x3cf) & 0xbf, 0x3cf);
9fa68eae
KP
713
714 printk("\n");
44637a12
KP
715 for (i = 0; i <= 0x7f; i++) {
716 outb(i, 0x3ce);
717 printk("GR%02x=%02x ", i, inb(0x3cf));
718 if (i % 16 == 15)
9fa68eae
KP
719 printk("\n");
720 }
721
722 printk("\n");
44637a12
KP
723 for (i = 0; i <= 0xff; i++) {
724 outb(i, 0x3c4);
725 printk("SR%02x=%02x ", i, inb(0x3c5));
726 if (i % 16 == 15)
9fa68eae
KP
727 printk("\n");
728 }
729
730 printk("\n");
44637a12
KP
731 for (i = 0; i <= 0x1F; i++) {
732 inb(0x3da); // next access is index!
733 outb(i, 0x3c0);
734 printk("AR%02x=%02x ", i, inb(0x3c1));
735 if (i % 16 == 15)
9fa68eae
KP
736 printk("\n");
737 }
738 printk("\n");
739
44637a12
KP
740 inb(0x3DA); // reset internal flag to 3c0 index
741 outb(0x20, 0x3C0); // enable attr
742
743 return;
744}
745
746//=======================================================================
747//
748// Save State
749//
750// This function is called while a switch to KD_TEXT is in progress,
751// before any of the other functions are called.
752//
753//=======================================================================
9fa68eae 754
44637a12
KP
755static void cyblafb_save_state(struct fb_info *info)
756{
757 struct cyblafb_par *par = info->par;
758 if (verbosity > 0)
759 output("Switching to KD_TEXT\n");
760 disabled = 0;
761 regdump(par);
762 enable_mmio();
763 return;
764}
765
766//=======================================================================
767//
768// Restore State
769//
770// This function is called while a switch to KD_GRAPHICS is in progress,
771// We have to turn on vga style panning registers again because the
772// trident driver of X does not know about GE10.
773//
774//=======================================================================
775
776static void cyblafb_restore_state(struct fb_info *info)
777{
778 if (verbosity > 0)
779 output("Switching to KD_GRAPHICS\n");
780 out32(GE10, 0);
781 disabled = 1;
9fa68eae
KP
782 return;
783}
784
785//======================================
786//
787// Set hardware to requested video mode
788//
789//======================================
790
791static int cyblafb_set_par(struct fb_info *info)
792{
793 struct cyblafb_par *par = info->par;
44637a12
KP
794 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
795 hblankend, preendfetch, vtotal, vdispend, vsyncstart,
796 vsyncend, vblankstart, vblankend;
9fa68eae
KP
797 struct fb_var_screeninfo *var = &info->var;
798 int bpp = var->bits_per_pixel;
799 int i;
800
44637a12
KP
801 KD_GRAPHICS_RETURN(0);
802
9fa68eae
KP
803 if (verbosity > 0)
804 output("Switching to new mode: "
805 "fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
44637a12
KP
806 var->xres, var->yres, var->xres_virtual,
807 var->yres_virtual, var->bits_per_pixel, var->pixclock,
808 var->left_margin, var->right_margin, var->upper_margin,
809 var->lower_margin, var->hsync_len, var->vsync_len);
9fa68eae
KP
810
811 htotal = (var->xres + var->left_margin + var->right_margin +
44637a12
KP
812 var->hsync_len) / 8 - 5;
813 hdispend = var->xres / 8 - 1;
814 hsyncstart = (var->xres + var->right_margin) / 8;
815 hsyncend = var->hsync_len / 8;
9fa68eae
KP
816 hblankstart = hdispend + 1;
817 hblankend = htotal + 3; // should be htotal + 5, bios does it this way
44637a12 818 preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
9fa68eae
KP
819
820 vtotal = var->yres + var->upper_margin + var->lower_margin +
44637a12 821 var->vsync_len - 2;
9fa68eae
KP
822 vdispend = var->yres - 1;
823 vsyncstart = var->yres + var->lower_margin;
824 vblankstart = var->yres;
825 vblankend = vtotal; // should be vtotal + 2, but bios does it this way
826 vsyncend = var->vsync_len;
827
828 enable_mmio(); // necessary! ... check X ...
829
44637a12 830 write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
9fa68eae 831
44637a12 832 write3CE(GR30, 8);
9fa68eae
KP
833
834 if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
835
836 // stretch or center ?
837
44637a12 838 out8(0x3C2, 0xEB);
9fa68eae 839
44637a12 840 write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on
9fa68eae
KP
841
842 if (center) {
44637a12
KP
843 write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80);
844 write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80);
845 } else if (stretch) {
846 write3CE(GR5D, 0);
847 write3CE(GR52, (read3CE(GR52) & 0x7C) | 1);
848 write3CE(GR53, (read3CE(GR53) & 0x7C) | 1);
9fa68eae
KP
849 }
850
851 } else {
44637a12
KP
852 out8(0x3C2, 0x2B);
853 write3CE(GR30, 8);
9fa68eae
KP
854 }
855
856 //
857 // Setup CRxx regs
858 //
859
44637a12
KP
860 write3X4(CR00, htotal & 0xFF);
861 write3X4(CR01, hdispend & 0xFF);
862 write3X4(CR02, hblankstart & 0xFF);
863 write3X4(CR03, hblankend & 0x1F);
864 write3X4(CR04, hsyncstart & 0xFF);
865 write3X4(CR05, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
866 write3X4(CR06, vtotal & 0xFF);
867 write3X4(CR07, (vtotal & 0x100) >> 8 |
868 (vdispend & 0x100) >> 7 |
869 (vsyncstart & 0x100) >> 6 |
870 (vblankstart & 0x100) >> 5 |
871 0x10 |
872 (vtotal & 0x200) >> 4 |
873 (vdispend & 0x200) >> 3 | (vsyncstart & 0x200) >> 2);
874 write3X4(CR08, 0);
875 write3X4(CR09, (vblankstart & 0x200) >> 4 | 0x40 | // FIX !!!
876 ((info->var.vmode & FB_VMODE_DOUBLE) ? 0x80 : 0));
877 write3X4(CR0A, 0); // Init to some reasonable default
878 write3X4(CR0B, 0); // Init to some reasonable default
879 write3X4(CR0C, 0); // Offset 0
880 write3X4(CR0D, 0); // Offset 0
881 write3X4(CR0E, 0); // Init to some reasonable default
882 write3X4(CR0F, 0); // Init to some reasonable default
883 write3X4(CR10, vsyncstart & 0xFF);
884 write3X4(CR11, (vsyncend & 0x0F));
885 write3X4(CR12, vdispend & 0xFF);
886 write3X4(CR13, ((info->var.xres_virtual * bpp) / (4 * 16)) & 0xFF);
887 write3X4(CR14, 0x40); // double word mode
888 write3X4(CR15, vblankstart & 0xFF);
889 write3X4(CR16, vblankend & 0xFF);
890 write3X4(CR17, 0xE3);
891 write3X4(CR18, 0xFF);
9fa68eae 892 // CR19: needed for interlaced modes ... ignore it for now
44637a12
KP
893 write3X4(CR1A, 0x07); // Arbitration Control Counter 1
894 write3X4(CR1B, 0x07); // Arbitration Control Counter 2
895 write3X4(CR1C, 0x07); // Arbitration Control Counter 3
896 write3X4(CR1D, 0x00); // Don't know, doesn't hurt ; -)
897 write3X4(CR1E, (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80);
9fa68eae 898 // CR1F: do not set, contains BIOS info about memsize
44637a12
KP
899 write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode
900 write3X4(CR21, 0x20); // enable linear memory access
9fa68eae
KP
901 // CR22: RO cpu latch readback
902 // CR23: ???
903 // CR24: RO AR flag state
904 // CR25: RAMDAC rw timing, pclk buffer tristate control ????
905 // CR26: ???
44637a12
KP
906 write3X4(CR27, (vdispend & 0x400) >> 6 |
907 (vsyncstart & 0x400) >> 5 |
908 (vblankstart & 0x400) >> 4 |
909 (vtotal & 0x400) >> 3 |
910 0x8);
9fa68eae 911 // CR28: ???
44637a12
KP
912 write3X4(CR29, (read3X4(CR29) & 0xCF) | ((((info->var.xres_virtual *
913 bpp) / (4 * 16)) & 0x300) >> 4));
914 write3X4(CR2A, read3X4(CR2A) | 0x40);
915 write3X4(CR2B, (htotal & 0x100) >> 8 |
916 (hdispend & 0x100) >> 7 |
917 // (0x00 & 0x100) >> 6 | hinterlace para bit 8 ???
918 (hsyncstart & 0x100) >> 5 |
919 (hblankstart & 0x100) >> 4);
9fa68eae
KP
920 // CR2C: ???
921 // CR2D: initialized in cyblafb_setup_GE()
44637a12 922 write3X4(CR2F, 0x92); // conservative, better signal quality
9fa68eae
KP
923 // CR30: reserved
924 // CR31: reserved
925 // CR32: reserved
926 // CR33: reserved
927 // CR34: disabled in CR36
928 // CR35: disabled in CR36
929 // CR36: initialized in cyblafb_setup_GE
930 // CR37: i2c, ignore for now
44637a12
KP
931 write3X4(CR38, (bpp == 8) ? 0x00 : //
932 (bpp == 16) ? 0x05 : // highcolor
933 (bpp == 24) ? 0x29 : // packed 24bit truecolor
934 (bpp == 32) ? 0x09 : 0); // truecolor, 16 bit pixelbus
935 write3X4(CR39, 0x01 | // MMIO enable
936 (pcirb ? 0x02 : 0) | // pci read burst enable
937 (pciwb ? 0x04 : 0)); // pci write burst enable
938 write3X4(CR55, 0x1F | // pci clocks * 2 for STOP# during 1st data phase
939 (pcirr ? 0x40 : 0) | // pci read retry enable
940 (pciwr ? 0x80 : 0)); // pci write retry enable
941 write3X4(CR56, preendfetch >> 8 < 2 ? (preendfetch >> 8 & 0x01) | 2
942 : 0);
943 write3X4(CR57, preendfetch >> 8 < 2 ? preendfetch & 0xff : 0);
944 write3X4(CR58, 0x82); // Bios does this .... don't know more
9fa68eae
KP
945 //
946 // Setup SRxx regs
947 //
44637a12
KP
948 write3C4(SR00, 3);
949 write3C4(SR01, 1); //set char clock 8 dots wide
950 write3C4(SR02, 0x0F); //enable 4 maps needed in chain4 mode
951 write3C4(SR03, 0); //no character map select
952 write3C4(SR04, 0x0E); //memory mode: ext mem, even, chain4
9fa68eae 953
44637a12 954 out8(0x3C4, 0x0b);
9fa68eae 955 in8(0x3C5); // Set NEW mode
44637a12 956 write3C4(SR0D, 0x00); // test ... check
9fa68eae 957
44637a12
KP
958 set_vclk(par, (bpp == 32 ? 200000000 : 100000000)
959 / info->var.pixclock); //SR18, SR19
9fa68eae
KP
960
961 //
962 // Setup GRxx regs
963 //
44637a12
KP
964 write3CE(GR00, 0x00); // test ... check
965 write3CE(GR01, 0x00); // test ... check
966 write3CE(GR02, 0x00); // test ... check
967 write3CE(GR03, 0x00); // test ... check
968 write3CE(GR04, 0x00); // test ... check
969 write3CE(GR05, 0x40); // no CGA compat, allow 256 col
970 write3CE(GR06, 0x05); // graphics mode
971 write3CE(GR07, 0x0F); // planes?
972 write3CE(GR08, 0xFF); // test ... check
973 write3CE(GR0F, (bpp == 32) ? 0x1A : 0x12); // vclk / 2 if 32bpp, chain4
974 write3CE(GR20, 0xC0); // test ... check
975 write3CE(GR2F, 0xA0); // PCLK = VCLK, no skew,
9fa68eae
KP
976
977 //
978 // Setup ARxx regs
979 //
44637a12
KP
980 for (i = 0; i < 0x10; i++) // set AR00 .. AR0f
981 write3C0(i, i);
982 write3C0(AR10, 0x41); // graphics mode and support 256 color modes
983 write3C0(AR12, 0x0F); // planes
984 write3C0(AR13, 0); // horizontal pel panning
9fa68eae 985 in8(0x3DA); // reset internal flag to 3c0 index
44637a12 986 out8(0x3C0, 0x20); // enable attr
9fa68eae
KP
987
988 //
989 // Setup hidden RAMDAC command register
990 //
44637a12
KP
991 in8(0x3C8); // these reads are
992 in8(0x3C6); // necessary to
993 in8(0x3C6); // unmask the RAMDAC
994 in8(0x3C6); // command reg, otherwise
995 in8(0x3C6); // we would write the pixelmask reg!
996 out8(0x3C6, (bpp == 8) ? 0x00 : // 256 colors
997 (bpp == 15) ? 0x10 : //
998 (bpp == 16) ? 0x30 : // hicolor
999 (bpp == 24) ? 0xD0 : // truecolor
1000 (bpp == 32) ? 0xD0 : 0); // truecolor
9fa68eae
KP
1001 in8(0x3C8);
1002
1003 //
1004 // GR31 is not mentioned in the datasheet
1005 //
1006 if (displaytype == DISPLAY_FP)
44637a12 1007 write3CE(GR31, (read3CE(GR31) & 0x8F) |
9fa68eae 1008 ((info->var.yres > 1024) ? 0x50 :
44637a12
KP
1009 (info->var.yres > 768) ? 0x30 :
1010 (info->var.yres > 600) ? 0x20 :
1011 (info->var.yres > 480) ? 0x10 : 0));
9fa68eae
KP
1012
1013 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR
1014 : FB_VISUAL_TRUECOLOR;
44637a12
KP
1015 info->fix.line_length = info->var.xres_virtual * (bpp >> 3);
1016 info->cmap.len = (bpp == 8) ? 256 : 16;
9fa68eae
KP
1017
1018 //
1019 // init acceleration engine
1020 //
44637a12
KP
1021 cyblafb_setup_GE(info->var.xres_virtual, info->var.bits_per_pixel);
1022
1023 //
1024 // Set/clear flags to allow proper scroll mode selection.
1025 //
1026 if (var->xres == var->xres_virtual)
1027 info->flags &= ~FBINFO_HWACCEL_XPAN;
1028 else
1029 info->flags |= FBINFO_HWACCEL_XPAN;
1030
1031 if (var->yres == var->yres_virtual)
1032 info->flags &= ~FBINFO_HWACCEL_YPAN;
1033 else
1034 info->flags |= FBINFO_HWACCEL_YPAN;
1035
1036 if (info->fix.smem_len !=
1037 var->xres_virtual * var->yres_virtual * bpp / 8)
1038 info->flags &= ~FBINFO_HWACCEL_YWRAP;
1039 else
1040 info->flags |= FBINFO_HWACCEL_YWRAP;
9fa68eae
KP
1041
1042 regdump(par);
1043
1044 return 0;
1045}
1046
1047//========================
1048//
1049// Set one color register
1050//
1051//========================
1052
1053static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
1054 unsigned blue, unsigned transp,
1055 struct fb_info *info)
1056{
1057 int bpp = info->var.bits_per_pixel;
1058
44637a12
KP
1059 KD_GRAPHICS_RETURN(0);
1060
9fa68eae
KP
1061 if (regno >= info->cmap.len)
1062 return 1;
1063
1064 if (bpp == 8) {
44637a12
KP
1065 out8(0x3C6, 0xFF);
1066 out8(0x3C8, regno);
1067 out8(0x3C9, red >> 10);
1068 out8(0x3C9, green >> 10);
1069 out8(0x3C9, blue >> 10);
1070
75921810
AD
1071 } else if (regno < 16) {
1072 if (bpp == 16) // RGB 565
1073 ((u32 *) info->pseudo_palette)[regno] =
1074 (red & 0xF800) |
1075 ((green & 0xFC00) >> 5) |
1076 ((blue & 0xF800) >> 11);
1077 else if (bpp == 32) // ARGB 8888
1078 ((u32 *) info->pseudo_palette)[regno] =
1079 ((transp & 0xFF00) << 16) |
1080 ((red & 0xFF00) << 8) |
1081 ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
1082 }
9fa68eae
KP
1083
1084 return 0;
1085}
1086
1087//==========================================================
1088//
1089// Try blanking the screen. For flat panels it does nothing
1090//
1091//==========================================================
1092
1093static int cyblafb_blank(int blank_mode, struct fb_info *info)
1094{
44637a12
KP
1095 unsigned char PMCont, DPMSCont;
1096
1097 KD_GRAPHICS_RETURN(0);
9fa68eae
KP
1098
1099 if (displaytype == DISPLAY_FP)
1100 return 0;
1101
44637a12 1102 out8(0x83C8, 0x04); // DPMS Control
9fa68eae
KP
1103 PMCont = in8(0x83C6) & 0xFC;
1104
1105 DPMSCont = read3CE(GR23) & 0xFC;
1106
44637a12
KP
1107 switch (blank_mode) {
1108 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On
1109 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On
9fa68eae
KP
1110 PMCont |= 0x03;
1111 DPMSCont |= 0x00;
1112 break;
44637a12 1113 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On
9fa68eae
KP
1114 PMCont |= 0x02;
1115 DPMSCont |= 0x01;
1116 break;
44637a12 1117 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off
9fa68eae
KP
1118 PMCont |= 0x02;
1119 DPMSCont |= 0x02;
1120 break;
44637a12 1121 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off
9fa68eae
KP
1122 PMCont |= 0x00;
1123 DPMSCont |= 0x03;
1124 break;
1125 }
1126
44637a12
KP
1127 write3CE(GR23, DPMSCont);
1128 out8(0x83C8, 4);
1129 out8(0x83C6, PMCont);
9fa68eae
KP
1130 //
1131 // let fbcon do a softblank for us
1132 //
1133 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1134}
1135
1136static struct fb_ops cyblafb_ops __devinitdata = {
44637a12 1137 .owner = THIS_MODULE,
9fa68eae
KP
1138 .fb_setcolreg = cyblafb_setcolreg,
1139 .fb_pan_display = cyblafb_pan_display,
1140 .fb_blank = cyblafb_blank,
1141 .fb_check_var = cyblafb_check_var,
1142 .fb_set_par = cyblafb_set_par,
1143 .fb_fillrect = cyblafb_fillrect,
44637a12 1144 .fb_copyarea = cyblafb_copyarea,
9fa68eae 1145 .fb_imageblit = cyblafb_imageblit,
44637a12
KP
1146 .fb_sync = cyblafb_sync,
1147 .fb_restore_state = cyblafb_restore_state,
1148 .fb_save_state = cyblafb_save_state,
9fa68eae
KP
1149};
1150
1151//==========================================================================
1152//
1153// getstartupmode() decides about the inital video mode
1154//
1155// There is no reason to use modedb, a lot of video modes there would
1156// need altered timings to display correctly. So I decided that it is much
1157// better to provide a limited optimized set of modes plus the option of
1158// using the mode in effect at startup time (might be selected using the
44363f14 1159// vga=??? parameter). After that the user might use fbset to select any
9fa68eae
KP
1160// mode he likes, check_var will not try to alter geometry parameters as
1161// it would be necessary otherwise.
1162//
1163//==========================================================================
1164
1165static int __devinit getstartupmode(struct fb_info *info)
1166{
44637a12
KP
1167 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,
1168 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,
1169 cr00, cr01, cr02, cr03, cr04, cr05, cr2b,
1170 cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,
1171 cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;
9fa68eae
KP
1172
1173 struct modus {
44637a12
KP
1174 int xres; int vxres; int yres; int vyres;
1175 int bpp; int pxclk;
1176 int left_margin; int right_margin;
1177 int upper_margin; int lower_margin;
1178 int hsync_len; int vsync_len;
1179 } modedb[5] = {
1180 {
1181 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {
1182 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {
1183 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {
1184 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {
1185 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}
9fa68eae
KP
1186 };
1187
44637a12
KP
1188 outb(0x00, 0x3d4); cr00 = inb(0x3d5);
1189 outb(0x01, 0x3d4); cr01 = inb(0x3d5);
1190 outb(0x02, 0x3d4); cr02 = inb(0x3d5);
1191 outb(0x03, 0x3d4); cr03 = inb(0x3d5);
1192 outb(0x04, 0x3d4); cr04 = inb(0x3d5);
1193 outb(0x05, 0x3d4); cr05 = inb(0x3d5);
1194 outb(0x06, 0x3d4); cr06 = inb(0x3d5);
1195 outb(0x07, 0x3d4); cr07 = inb(0x3d5);
1196 outb(0x09, 0x3d4); cr09 = inb(0x3d5);
1197 outb(0x10, 0x3d4); cr10 = inb(0x3d5);
1198 outb(0x11, 0x3d4); cr11 = inb(0x3d5);
1199 outb(0x12, 0x3d4); cr12 = inb(0x3d5);
1200 outb(0x15, 0x3d4); cr15 = inb(0x3d5);
1201 outb(0x16, 0x3d4); cr16 = inb(0x3d5);
1202 outb(0x27, 0x3d4); cr27 = inb(0x3d5);
1203 outb(0x2b, 0x3d4); cr2b = inb(0x3d5);
1204 outb(0x38, 0x3d4); cr38 = inb(0x3d5);
1205
1206 outb(0x0b, 0x3c4);
1207 inb(0x3c5);
1208
1209 outb(0x0d, 0x3c4); sr0d = inb(0x3c5);
1210 outb(0x18, 0x3c4); sr18 = inb(0x3c5);
1211 outb(0x19, 0x3c4); sr19 = inb(0x3c5);
1212 outb(0x0f, 0x3ce); gr0f = inb(0x3cf);
1213
1214 htotal = cr00 | (cr2b & 0x01) << 8;
1215 hdispend = cr01 | (cr2b & 0x02) << 7;
9fa68eae 1216 hblankstart = cr02 | (cr2b & 0x10) << 4;
44637a12
KP
1217 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;
1218 hsyncstart = cr04 | (cr2b & 0x08) << 5;
1219 hsyncend = cr05 & 0x1f;
9fa68eae
KP
1220
1221 modedb[0].xres = hblankstart * 8;
1222 modedb[0].hsync_len = hsyncend * 8;
1223 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;
1224 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -
44637a12
KP
1225 modedb[0].right_margin - modedb[0].hsync_len;
1226
1227 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4
1228 | (cr27 & 0x80) << 3;
1229 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3
1230 | (cr27 & 0x10) << 6;
1231 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2
1232 | (cr27 & 0x20) << 5;
1233 vsyncend = cr11 & 0x0f;
9fa68eae 1234 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4
44637a12
KP
1235 | (cr27 & 0x40) << 4;
1236 vblankend = cr16;
9fa68eae 1237
44637a12
KP
1238 modedb[0].yres = vdispend + 1;
1239 modedb[0].vsync_len = vsyncend;
9fa68eae
KP
1240 modedb[0].lower_margin = vsyncstart - modedb[0].yres;
1241 modedb[0].upper_margin = vtotal - modedb[0].yres -
44637a12 1242 modedb[0].lower_margin - modedb[0].vsync_len + 2;
9fa68eae
KP
1243
1244 tmp = cr38 & 0x3c;
1245 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :
44637a12 1246 tmp == 8 ? 32 : 8;
9fa68eae 1247
44637a12
KP
1248 fi = ((5864727 * (sr18 + 8)) /
1249 (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;
9fa68eae
KP
1250 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;
1251 tmp = sr0d & 0x06;
1252 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !
1253 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;
1254
1255 if (verbosity > 0)
1256 output("detected startup mode: "
1257 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",
44637a12
KP
1258 modedb[0].xres, modedb[0].yres, modedb[0].xres,
1259 modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,
1260 modedb[0].right_margin, modedb[0].upper_margin,
1261 modedb[0].lower_margin, modedb[0].hsync_len,
9fa68eae
KP
1262 modedb[0].vsync_len);
1263
1264 //
1265 // We use this goto target in case of a failed check_var. No, I really
1266 // do not want to do it in another way!
1267 //
1268
44637a12 1269 tryagain:
9fa68eae
KP
1270
1271 i = (mode == NULL) ? 0 :
44637a12
KP
1272 !strncmp(mode, "640x480", 7) ? 1 :
1273 !strncmp(mode, "800x600", 7) ? 2 :
1274 !strncmp(mode, "1024x768", 8) ? 3 :
1275 !strncmp(mode, "1280x1024", 9) ? 4 : 0;
9fa68eae
KP
1276
1277 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;
1278
44637a12 1279 if (i == 0) {
9fa68eae
KP
1280 info->var.pixclock = modedb[i].pxclk;
1281 info->var.bits_per_pixel = modedb[i].bpp;
1282 } else {
1283 info->var.pixclock = (100000000 /
44637a12
KP
1284 ((modedb[i].left_margin +
1285 modedb[i].xres +
1286 modedb[i].right_margin +
1287 modedb[i].hsync_len) *
1288 (modedb[i].upper_margin +
1289 modedb[i].yres +
1290 modedb[i].lower_margin +
1291 modedb[i].vsync_len) * ref / 10000));
9fa68eae
KP
1292 info->var.bits_per_pixel = bpp;
1293 }
1294
1295 info->var.left_margin = modedb[i].left_margin;
1296 info->var.right_margin = modedb[i].right_margin;
1297 info->var.xres = modedb[i].xres;
44637a12
KP
1298 if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))
1299 info->var.xres_virtual = modedb[i].vxres;
1300 else
1301 info->var.xres_virtual = modedb[i].xres;
9fa68eae
KP
1302 info->var.xoffset = 0;
1303 info->var.hsync_len = modedb[i].hsync_len;
1304 info->var.upper_margin = modedb[i].upper_margin;
1305 info->var.yres = modedb[i].yres;
1306 info->var.yres_virtual = modedb[i].vyres;
1307 info->var.yoffset = 0;
1308 info->var.lower_margin = modedb[i].lower_margin;
1309 info->var.vsync_len = modedb[i].vsync_len;
1310 info->var.sync = 0;
1311 info->var.vmode = FB_VMODE_NONINTERLACED;
1312
44637a12
KP
1313 if (cyblafb_check_var(&info->var, info)) {
1314 // 640x480 - 8@75 should really never fail. One case would
9fa68eae 1315 // be fp == 1 and nativex < 640 ... give up then
44637a12 1316 if (i == 1 && bpp == 8 && ref == 75) {
9fa68eae
KP
1317 output("Can't find a valid mode :-(\n");
1318 return -EINVAL;
1319 }
1320 // Our detected mode is unlikely to fail. If it does,
44637a12
KP
1321 // try 640x480 - 8@75 ...
1322 if (i == 0) {
1323 mode = "640x480";
1324 bpp = 8;
1325 ref = 75;
9fa68eae 1326 output("Detected mode failed check_var! "
44637a12 1327 "Trying 640x480 - 8@75\n");
9fa68eae
KP
1328 goto tryagain;
1329 }
1330 // A specified video mode failed for some reason.
1331 // Try the startup mode first
1332 output("Specified mode '%s' failed check! "
44637a12
KP
1333 "Falling back to startup mode.\n", mode);
1334 mode = NULL;
9fa68eae
KP
1335 goto tryagain;
1336 }
1337
1338 return 0;
9fa68eae
KP
1339}
1340
1341//========================================================
1342//
1343// Detect activated memory size. Undefined values require
1344// memsize parameter.
1345//
1346//========================================================
1347
1348static unsigned int __devinit get_memsize(void)
1349{
1350 unsigned char tmp;
1351 unsigned int k;
1352
1353 if (memsize)
1354 k = memsize * Kb;
1355 else {
1356 tmp = read3X4(CR1F) & 0x0F;
1357 switch (tmp) {
44637a12
KP
1358 case 0x03:
1359 k = 1 * 1024 * 1024;
1360 break;
1361 case 0x07:
1362 k = 2 * 1024 * 1024;
1363 break;
1364 case 0x0F:
1365 k = 4 * 1024 * 1024;
1366 break;
1367 case 0x04:
1368 k = 8 * 1024 * 1024;
1369 break;
1370 default:
1371 k = 1 * 1024 * 1024;
1372 output("Unknown memory size code %x in CR1F."
1373 " We default to 1 Mb for now, please"
1374 " do provide a memsize parameter!\n", tmp);
9fa68eae
KP
1375 }
1376 }
1377
1378 if (verbosity > 0)
44637a12 1379 output("framebuffer size = %d Kb\n", k / Kb);
9fa68eae
KP
1380 return k;
1381}
1382
1383//=========================================================
1384//
1385// Detect if a flat panel monitor connected to the special
1386// interface is active. Override is possible by fp and crt
1387// parameters.
1388//
1389//=========================================================
1390
1391static unsigned int __devinit get_displaytype(void)
1392{
1393 if (fp)
1394 return DISPLAY_FP;
1395 if (crt)
1396 return DISPLAY_CRT;
44637a12 1397 return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
9fa68eae
KP
1398}
1399
1400//=====================================
1401//
1402// Get native resolution of flat panel
1403//
1404//=====================================
1405
1406static int __devinit get_nativex(void)
1407{
44637a12 1408 int x, y, tmp;
9fa68eae
KP
1409
1410 if (nativex)
1411 return nativex;
1412
1413 tmp = (read3CE(GR52) >> 4) & 3;
1414
1415 switch (tmp) {
44637a12
KP
1416 case 0: x = 1280; y = 1024;
1417 break;
1418 case 2: x = 1024; y = 768;
1419 break;
1420 case 3: x = 800; y = 600;
1421 break;
1422 case 4: x = 1400; y = 1050;
1423 break;
1424 case 1:
1425 default:
1426 x = 640; y = 480;
1427 break;
9fa68eae
KP
1428 }
1429
1430 if (verbosity > 0)
44637a12 1431 output("%dx%d flat panel found\n", x, y);
9fa68eae
KP
1432 return x;
1433}
1434
44637a12
KP
1435static int __devinit cybla_pci_probe(struct pci_dev *dev,
1436 const struct pci_device_id *id)
9fa68eae
KP
1437{
1438 struct fb_info *info;
1439 struct cyblafb_par *par;
1440
44637a12 1441 info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);
9fa68eae 1442 if (!info)
44637a12
KP
1443 goto errout_alloc_info;
1444
1445 info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);
1446 if (!info->pixmap.addr) {
1447 output("allocation of pixmap buffer failed!\n");
1448 goto errout_alloc_pixmap;
1449 }
1450 info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;
1451 info->pixmap.buf_align = 4;
1452 info->pixmap.access_align = 32;
1453 info->pixmap.flags = FB_PIXMAP_SYSTEM;
1454 info->pixmap.scan_align = 4;
9fa68eae
KP
1455
1456 par = info->par;
1457 par->ops = cyblafb_ops;
1458
1459 info->fix = cyblafb_fix;
1460 info->fbops = &par->ops;
1461 info->fix = cyblafb_fix;
1462
1463 if (pci_enable_device(dev)) {
1464 output("could not enable device!\n");
1465 goto errout_enable;
1466 }
9fa68eae
KP
1467 // might already be requested by vga console or vesafb,
1468 // so we do care about success
44637a12
KP
1469 if (!request_region(0x3c0, 0x20, "cyblafb")) {
1470 output("region 0x3c0/0x20 already reserved\n");
1471 vesafb |= 1;
9fa68eae 1472
44637a12 1473 }
9fa68eae
KP
1474 //
1475 // Graphics Engine Registers
1476 //
44637a12
KP
1477 if (!request_region(GEBase, 0x100, "cyblafb")) {
1478 output("region %#x/0x100 already reserved\n", GEBase);
1479 vesafb |= 2;
1480 }
9fa68eae
KP
1481
1482 regdump(par);
1483
1484 enable_mmio();
1485
1486 // setup MMIO region
44637a12 1487 info->fix.mmio_start = pci_resource_start(dev, 1);
9fa68eae
KP
1488 info->fix.mmio_len = 0x20000;
1489
1490 if (!request_mem_region(info->fix.mmio_start,
44637a12 1491 info->fix.mmio_len, "cyblafb")) {
9fa68eae
KP
1492 output("request_mem_region failed for mmio region!\n");
1493 goto errout_mmio_reqmem;
1494 }
1495
1496 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1497
1498 if (!io_virt) {
1499 output("ioremap failed for mmio region\n");
1500 goto errout_mmio_remap;
1501 }
9fa68eae
KP
1502 // setup framebuffer memory ... might already be requested
1503 // by vesafb. Not to fail in case of an unsuccessful request
44637a12
KP
1504 // is useful if both are loaded.
1505 info->fix.smem_start = pci_resource_start(dev, 0);
9fa68eae
KP
1506 info->fix.smem_len = get_memsize();
1507
1508 if (!request_mem_region(info->fix.smem_start,
44637a12
KP
1509 info->fix.smem_len, "cyblafb")) {
1510 output("region %#lx/%#x already reserved\n",
1511 info->fix.smem_start, info->fix.smem_len);
1512 vesafb |= 4;
9fa68eae
KP
1513 }
1514
1515 info->screen_base = ioremap_nocache(info->fix.smem_start,
1516 info->fix.smem_len);
1517
1518 if (!info->screen_base) {
1519 output("ioremap failed for smem region\n");
1520 goto errout_smem_remap;
1521 }
1522
1523 displaytype = get_displaytype();
1524
44637a12 1525 if (displaytype == DISPLAY_FP)
9fa68eae
KP
1526 nativex = get_nativex();
1527
44637a12
KP
1528 info->flags = FBINFO_DEFAULT
1529 | FBINFO_HWACCEL_COPYAREA
1530 | FBINFO_HWACCEL_FILLRECT
1531 | FBINFO_HWACCEL_IMAGEBLIT
1532 | FBINFO_READS_FAST
1533// | FBINFO_PARTIAL_PAN_OK
1534 | FBINFO_MISC_ALWAYS_SETPAR;
9fa68eae
KP
1535
1536 info->pseudo_palette = par->pseudo_pal;
1537
44637a12 1538 if (getstartupmode(info))
9fa68eae
KP
1539 goto errout_findmode;
1540
44637a12 1541 fb_alloc_cmap(&info->cmap, 256, 0);
9fa68eae
KP
1542
1543 if (register_framebuffer(info)) {
1544 output("Could not register CyBla framebuffer\n");
1545 goto errout_register;
1546 }
1547
44637a12 1548 pci_set_drvdata(dev, info);
9fa68eae
KP
1549
1550 //
1551 // normal exit and error paths
1552 //
1553
1554 return 0;
1555
44637a12
KP
1556 errout_register:
1557 errout_findmode:
9fa68eae 1558 iounmap(info->screen_base);
44637a12
KP
1559 errout_smem_remap:
1560 if (!(vesafb & 4))
1561 release_mem_region(info->fix.smem_start, info->fix.smem_len);
9fa68eae 1562 iounmap(io_virt);
44637a12
KP
1563 errout_mmio_remap:
1564 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
1565 errout_mmio_reqmem:
1566 if (!(vesafb & 1))
1567 release_region(0x3c0, 32);
1568 errout_enable:
1569 kfree(info->pixmap.addr);
1570 errout_alloc_pixmap:
9fa68eae 1571 framebuffer_release(info);
44637a12
KP
1572 errout_alloc_info:
1573 output("CyblaFB version %s aborting init.\n", VERSION);
9fa68eae
KP
1574 return -ENODEV;
1575}
1576
1577static void __devexit cybla_pci_remove(struct pci_dev *dev)
1578{
1579 struct fb_info *info = pci_get_drvdata(dev);
1580
1581 unregister_framebuffer(info);
1582 iounmap(io_virt);
1583 iounmap(info->screen_base);
44637a12
KP
1584 if (!(vesafb & 4))
1585 release_mem_region(info->fix.smem_start, info->fix.smem_len);
1586 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
9fa68eae 1587 fb_dealloc_cmap(&info->cmap);
44637a12
KP
1588 if (!(vesafb & 2))
1589 release_region(GEBase, 0x100);
1590 if (!(vesafb & 1))
1591 release_region(0x3c0, 32);
1592 kfree(info->pixmap.addr);
9fa68eae 1593 framebuffer_release(info);
44637a12 1594 output("CyblaFB version %s normal exit.\n", VERSION);
9fa68eae
KP
1595}
1596
1597//
1598// List of boards that we are trying to support
1599//
1600static struct pci_device_id cybla_devices[] = {
44637a12 1601 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
9fa68eae
KP
1602 {0,}
1603};
1604
44637a12 1605MODULE_DEVICE_TABLE(pci, cybla_devices);
9fa68eae
KP
1606
1607static struct pci_driver cyblafb_pci_driver = {
44637a12
KP
1608 .name = "cyblafb",
1609 .id_table = cybla_devices,
1610 .probe = cybla_pci_probe,
1611 .remove = __devexit_p(cybla_pci_remove)
9fa68eae
KP
1612};
1613
1614//=============================================================
1615//
1616// kernel command line example:
1617//
44637a12 1618// video=cyblafb:1280x1024, bpp=16, ref=50 ...
9fa68eae
KP
1619//
1620// modprobe command line example:
1621//
1622// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...
1623//
1624//=============================================================
1625
1626static int __devinit cyblafb_init(void)
1627{
1628#ifndef MODULE
1629 char *options = NULL;
1630 char *opt;
1631
44637a12 1632 if (fb_get_options("cyblafb", &options))
9fa68eae
KP
1633 return -ENODEV;
1634
1635 if (options && *options)
44637a12
KP
1636 while ((opt = strsep(&options, ",")) != NULL) {
1637 if (!*opt)
1638 continue;
1639 else if (!strncmp(opt, "bpp=", 4))
1640 bpp = simple_strtoul(opt + 4, NULL, 0);
1641 else if (!strncmp(opt, "ref=", 4))
1642 ref = simple_strtoul(opt + 4, NULL, 0);
1643 else if (!strncmp(opt, "fp", 2))
9fa68eae 1644 displaytype = DISPLAY_FP;
44637a12 1645 else if (!strncmp(opt, "crt", 3))
9fa68eae 1646 displaytype = DISPLAY_CRT;
44637a12
KP
1647 else if (!strncmp(opt, "nativex=", 8))
1648 nativex = simple_strtoul(opt + 8, NULL, 0);
1649 else if (!strncmp(opt, "center", 6))
9fa68eae 1650 center = 1;
44637a12 1651 else if (!strncmp(opt, "stretch", 7))
9fa68eae 1652 stretch = 1;
44637a12
KP
1653 else if (!strncmp(opt, "pciwb=", 6))
1654 pciwb = simple_strtoul(opt + 6, NULL, 0);
1655 else if (!strncmp(opt, "pcirb=", 6))
1656 pcirb = simple_strtoul(opt + 6, NULL, 0);
1657 else if (!strncmp(opt, "pciwr=", 6))
1658 pciwr = simple_strtoul(opt + 6, NULL, 0);
1659 else if (!strncmp(opt, "pcirr=", 6))
1660 pcirr = simple_strtoul(opt + 6, NULL, 0);
1661 else if (!strncmp(opt, "memsize=", 8))
1662 memsize = simple_strtoul(opt + 8, NULL, 0);
1663 else if (!strncmp(opt, "verbosity=", 10))
1664 verbosity = simple_strtoul(opt + 10, NULL, 0);
9fa68eae
KP
1665 else
1666 mode = opt;
1667 }
1668#endif
44637a12 1669 output("CyblaFB version %s initializing\n", VERSION);
93b47684 1670 return pci_register_driver(&cyblafb_pci_driver);
9fa68eae
KP
1671}
1672
1673static void __exit cyblafb_exit(void)
1674{
1675 pci_unregister_driver(&cyblafb_pci_driver);
1676}
1677
1678module_init(cyblafb_init);
1679module_exit(cyblafb_exit);
1680
1681MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");
1682MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");
1683MODULE_LICENSE("GPL");