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