Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19-rc2 1680 lines 45 kB view raw
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// 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 102 103//========================================= 104// 105// Port access macros for memory mapped io 106// 107//========================================= 108 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) 113 114//====================================== 115// 116// Hardware access inline functions 117// 118//====================================== 119 120static inline u8 read3X4(u32 reg) 121{ 122 out8(0x3D4, reg); 123 return in8(0x3D5); 124} 125 126static inline u8 read3C4(u32 reg) 127{ 128 out8(0x3C4, reg); 129 return in8(0x3C5); 130} 131 132static inline u8 read3CE(u32 reg) 133{ 134 out8(0x3CE, reg); 135 return in8(0x3CF); 136} 137 138static inline void write3X4(u32 reg, u8 val) 139{ 140 out8(0x3D4, reg); 141 out8(0x3D5, val); 142} 143 144static inline void write3C4(u32 reg, u8 val) 145{ 146 out8(0x3C4, reg); 147 out8(0x3C5, val); 148} 149 150static inline void write3CE(u32 reg, u8 val) 151{ 152 out8(0x3CE, reg); 153 out8(0x3CF, val); 154} 155 156static inline void write3C0(u32 reg, u8 val) 157{ 158 in8(0x3DA); // read to reset index 159 out8(0x3C0, reg); 160 out8(0x3C0, val); 161} 162 163//================================================= 164// 165// Enable memory mapped io and unprotect registers 166// 167//================================================= 168 169static void enable_mmio(void) 170{ 171 u8 tmp; 172 173 outb(0x0B, 0x3C4); 174 inb(0x3C5); // Set NEW mode 175 outb(SR0E, 0x3C4); // write enable a lot of extended ports 176 outb(0x80, 0x3C5); 177 178 outb(SR11, 0x3C4); // write enable those extended ports that 179 outb(0x87, 0x3C5); // are not affected by SR0E_New 180 181 outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2 182 tmp = inb(0x3d5) & 0xBF; 183 outb(CR1E, 0x3d4); 184 outb(tmp, 0x3d5); 185 186 outb(CR39, 0x3D4); 187 outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio 188} 189 190//================================================= 191// 192// Set pixel clock VCLK1 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 198// 199//================================================= 200 201static void set_vclk(struct cyblafb_par *par, int freq) 202{ 203 u32 m, n, k; 204 int f, fi, d, di; 205 u8 lo = 0, hi = 0; 206 207 d = 2000; 208 k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3; 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 } 219 } 220 write3C4(SR19, hi); 221 write3C4(SR18, lo); 222 if (verbosity > 0) 223 output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n", 224 freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo); 225} 226 227//================================================ 228// 229// Cyberblade specific Graphics Engine (GE) setup 230// 231//================================================ 232 233static void cyblafb_setup_GE(int pitch, int bpp) 234{ 235 KD_GRAPHICS_RETURN(); 236 237 switch (bpp) { 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; 251 } 252 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 259} 260 261//===================================================================== 262// 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. 274// 275//===================================================================== 276 277static int cyblafb_sync(struct fb_info *info) 278{ 279 u32 status, i = 100000; 280 281 KD_GRAPHICS_RETURN(0); 282 283 while (((status = in32(GE20)) & 0xFe800000) && i != 0) 284 i--; 285 286 if (i == 0) { 287 enable_mmio(); 288 i = 1000000; 289 while (((status = in32(GE20)) & 0xFA800000) && i != 0) 290 i--; 291 if (i == 0) { 292 output("GE Timeout, status: %x\n", status); 293 if (status & 0x80000000) 294 output("Bresenham Engine : Busy\n"); 295 if (status & 0x40000000) 296 output("Setup Engine : Busy\n"); 297 if (status & 0x20000000) 298 output("SP / DPE : Busy\n"); 299 if (status & 0x10000000) 300 output("Memory Interface : Busy\n"); 301 if (status & 0x08000000) 302 output("Com Lst Proc : Busy\n"); 303 if (status & 0x04000000) 304 output("Block Write : Busy\n"); 305 if (status & 0x02000000) 306 output("Command Buffer : Full\n"); 307 if (status & 0x01000000) 308 output("RESERVED : Busy\n"); 309 if (status & 0x00800000) 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 325static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr) 326{ 327 u32 bpp = info->var.bits_per_pixel, col, desty, height; 328 329 KD_GRAPHICS_RETURN(); 330 331 switch (bpp) { 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; 345 } 346 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 } 363} 364 365//================================================ 366// 367// Cyberblade specific copyarea 368// 369// This function silently assumes that it never 370// will be called with width or height exceeding 371// 4096. 372// 373//================================================ 374 375static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca) 376{ 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); 385 386 if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx))) 387 direction = 0; 388 else 389 direction = 2; 390 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); 400} 401 402//======================================================================= 403// 404// Cyberblade specific imageblit 405// 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. 413// 414//======================================================================= 415 416static void cyblafb_imageblit(struct fb_info *info, 417 const struct fb_image *image) 418{ 419 u32 fgcol, bgcol; 420 u32 *pd = (u32 *) image->data; 421 u32 bpp = info->var.bits_per_pixel; 422 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"); 433 return; 434 } 435 436 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 437 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 438 fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color]; 439 bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color]; 440 } else { 441 fgcol = image->fg_color; 442 bgcol = image->bg_color; 443 } 444 445 switch (bpp) { 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; 454 } 455 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 } 483 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 } 499 } 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 } 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; 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 // 537 if (bpp % 8 != 0 || bpp < 8 || bpp > 32) 538 bpp = 8; 539 if (bpp == 24) 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 // 556 // we do not allow vclk to exceed 230 MHz. If the requested 557 // vclk is too high, we default to 200 MHz 558 // 559 if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000) 560 var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000; 561 562 // 563 // enforce (h|v)sync_len limits 564 // 565 var->hsync_len &= ~7; 566 if(var->hsync_len > 248) 567 var->hsync_len = 248; 568 569 var->vsync_len &= 15; 570 571 // 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. 575 // 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)) 582 return -EINVAL; 583 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 610 return -EINVAL; 611 } 612 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 } 641 642 return 0; 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// 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// 663//===================================================================== 664 665static int cyblafb_pan_display(struct fb_var_screeninfo *var, 666 struct fb_info *info) 667{ 668 KD_GRAPHICS_RETURN(0); 669 670 info->var.xoffset = var->xoffset; 671 info->var.yoffset = var->yoffset; 672 out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset * 673 var->xres_virtual)) * var->bits_per_pixel / 32)); 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"); 692 for (i = 0; i <= 0xff; i++) { 693 outb(i, 0x3d4); 694 printk("CR%02x=%02x ", i, inb(0x3d5)); 695 if (i % 16 == 15) 696 printk("\n"); 697 } 698 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)); 706 } else 707 printk("------- "); 708 if (i % 16 == 15) 709 printk("\n"); 710 } 711 outb(0x30, 0x3ce); 712 outb(inb(0x3cf) & 0xbf, 0x3cf); 713 714 printk("\n"); 715 for (i = 0; i <= 0x7f; i++) { 716 outb(i, 0x3ce); 717 printk("GR%02x=%02x ", i, inb(0x3cf)); 718 if (i % 16 == 15) 719 printk("\n"); 720 } 721 722 printk("\n"); 723 for (i = 0; i <= 0xff; i++) { 724 outb(i, 0x3c4); 725 printk("SR%02x=%02x ", i, inb(0x3c5)); 726 if (i % 16 == 15) 727 printk("\n"); 728 } 729 730 printk("\n"); 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) 736 printk("\n"); 737 } 738 printk("\n"); 739 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//======================================================================= 754 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; 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; 794 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, 795 hblankend, preendfetch, vtotal, vdispend, vsyncstart, 796 vsyncend, vblankstart, vblankend; 797 struct fb_var_screeninfo *var = &info->var; 798 int bpp = var->bits_per_pixel; 799 int i; 800 801 KD_GRAPHICS_RETURN(0); 802 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", 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); 810 811 htotal = (var->xres + var->left_margin + var->right_margin + 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; 816 hblankstart = hdispend + 1; 817 hblankend = htotal + 3; // should be htotal + 5, bios does it this way 818 preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3); 819 820 vtotal = var->yres + var->upper_margin + var->lower_margin + 821 var->vsync_len - 2; 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 830 write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07 831 832 write3CE(GR30, 8); 833 834 if ((displaytype == DISPLAY_FP) && var->xres < nativex) { 835 836 // stretch or center ? 837 838 out8(0x3C2, 0xEB); 839 840 write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on 841 842 if (center) { 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); 849 } 850 851 } else { 852 out8(0x3C2, 0x2B); 853 write3CE(GR30, 8); 854 } 855 856 // 857 // Setup CRxx regs 858 // 859 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); 892 // CR19: needed for interlaced modes ... ignore it for now 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); 898 // CR1F: do not set, contains BIOS info about memsize 899 write3X4(CR20, 0x20); // enabe wr buf, disable 16bit planar mode 900 write3X4(CR21, 0x20); // enable linear memory access 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: ??? 906 write3X4(CR27, (vdispend & 0x400) >> 6 | 907 (vsyncstart & 0x400) >> 5 | 908 (vblankstart & 0x400) >> 4 | 909 (vtotal & 0x400) >> 3 | 910 0x8); 911 // CR28: ??? 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); 920 // CR2C: ??? 921 // CR2D: initialized in cyblafb_setup_GE() 922 write3X4(CR2F, 0x92); // conservative, better signal quality 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 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 945 // 946 // Setup SRxx regs 947 // 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 953 954 out8(0x3C4, 0x0b); 955 in8(0x3C5); // Set NEW mode 956 write3C4(SR0D, 0x00); // test ... check 957 958 set_vclk(par, (bpp == 32 ? 200000000 : 100000000) 959 / info->var.pixclock); //SR18, SR19 960 961 // 962 // Setup GRxx regs 963 // 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, 976 977 // 978 // Setup ARxx regs 979 // 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 985 in8(0x3DA); // reset internal flag to 3c0 index 986 out8(0x3C0, 0x20); // enable attr 987 988 // 989 // Setup hidden RAMDAC command register 990 // 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 1001 in8(0x3C8); 1002 1003 // 1004 // GR31 is not mentioned in the datasheet 1005 // 1006 if (displaytype == DISPLAY_FP) 1007 write3CE(GR31, (read3CE(GR31) & 0x8F) | 1008 ((info->var.yres > 1024) ? 0x50 : 1009 (info->var.yres > 768) ? 0x30 : 1010 (info->var.yres > 600) ? 0x20 : 1011 (info->var.yres > 480) ? 0x10 : 0)); 1012 1013 info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR 1014 : FB_VISUAL_TRUECOLOR; 1015 info->fix.line_length = info->var.xres_virtual * (bpp >> 3); 1016 info->cmap.len = (bpp == 8) ? 256 : 16; 1017 1018 // 1019 // init acceleration engine 1020 // 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; 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 1059 KD_GRAPHICS_RETURN(0); 1060 1061 if (regno >= info->cmap.len) 1062 return 1; 1063 1064 if (bpp == 8) { 1065 out8(0x3C6, 0xFF); 1066 out8(0x3C8, regno); 1067 out8(0x3C9, red >> 10); 1068 out8(0x3C9, green >> 10); 1069 out8(0x3C9, blue >> 10); 1070 1071 } else if (bpp == 16) // RGB 565 1072 ((u32 *) info->pseudo_palette)[regno] = 1073 (red & 0xF800) | 1074 ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); 1075 else if (bpp == 32) // ARGB 8888 1076 ((u32 *) info->pseudo_palette)[regno] = 1077 ((transp & 0xFF00) << 16) | 1078 ((red & 0xFF00) << 8) | 1079 ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); 1080 1081 return 0; 1082} 1083 1084//========================================================== 1085// 1086// Try blanking the screen. For flat panels it does nothing 1087// 1088//========================================================== 1089 1090static int cyblafb_blank(int blank_mode, struct fb_info *info) 1091{ 1092 unsigned char PMCont, DPMSCont; 1093 1094 KD_GRAPHICS_RETURN(0); 1095 1096 if (displaytype == DISPLAY_FP) 1097 return 0; 1098 1099 out8(0x83C8, 0x04); // DPMS Control 1100 PMCont = in8(0x83C6) & 0xFC; 1101 1102 DPMSCont = read3CE(GR23) & 0xFC; 1103 1104 switch (blank_mode) { 1105 case FB_BLANK_UNBLANK: // Screen: On, HSync: On, VSync: On 1106 case FB_BLANK_NORMAL: // Screen: Off, HSync: On, VSync: On 1107 PMCont |= 0x03; 1108 DPMSCont |= 0x00; 1109 break; 1110 case FB_BLANK_HSYNC_SUSPEND: // Screen: Off, HSync: Off, VSync: On 1111 PMCont |= 0x02; 1112 DPMSCont |= 0x01; 1113 break; 1114 case FB_BLANK_VSYNC_SUSPEND: // Screen: Off, HSync: On, VSync: Off 1115 PMCont |= 0x02; 1116 DPMSCont |= 0x02; 1117 break; 1118 case FB_BLANK_POWERDOWN: // Screen: Off, HSync: Off, VSync: Off 1119 PMCont |= 0x00; 1120 DPMSCont |= 0x03; 1121 break; 1122 } 1123 1124 write3CE(GR23, DPMSCont); 1125 out8(0x83C8, 4); 1126 out8(0x83C6, PMCont); 1127 // 1128 // let fbcon do a softblank for us 1129 // 1130 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; 1131} 1132 1133static struct fb_ops cyblafb_ops __devinitdata = { 1134 .owner = THIS_MODULE, 1135 .fb_setcolreg = cyblafb_setcolreg, 1136 .fb_pan_display = cyblafb_pan_display, 1137 .fb_blank = cyblafb_blank, 1138 .fb_check_var = cyblafb_check_var, 1139 .fb_set_par = cyblafb_set_par, 1140 .fb_fillrect = cyblafb_fillrect, 1141 .fb_copyarea = cyblafb_copyarea, 1142 .fb_imageblit = cyblafb_imageblit, 1143 .fb_sync = cyblafb_sync, 1144 .fb_restore_state = cyblafb_restore_state, 1145 .fb_save_state = cyblafb_save_state, 1146}; 1147 1148//========================================================================== 1149// 1150// getstartupmode() decides about the inital video mode 1151// 1152// There is no reason to use modedb, a lot of video modes there would 1153// need altered timings to display correctly. So I decided that it is much 1154// better to provide a limited optimized set of modes plus the option of 1155// using the mode in effect at startup time (might be selected using the 1156// vga=??? paramter). After that the user might use fbset to select any 1157// mode he likes, check_var will not try to alter geometry parameters as 1158// it would be necessary otherwise. 1159// 1160//========================================================================== 1161 1162static int __devinit getstartupmode(struct fb_info *info) 1163{ 1164 u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend, 1165 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend, 1166 cr00, cr01, cr02, cr03, cr04, cr05, cr2b, 1167 cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27, 1168 cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i; 1169 1170 struct modus { 1171 int xres; int vxres; int yres; int vyres; 1172 int bpp; int pxclk; 1173 int left_margin; int right_margin; 1174 int upper_margin; int lower_margin; 1175 int hsync_len; int vsync_len; 1176 } modedb[5] = { 1177 { 1178 0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, { 1179 640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, { 1180 800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, { 1181 1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, { 1182 1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3} 1183 }; 1184 1185 outb(0x00, 0x3d4); cr00 = inb(0x3d5); 1186 outb(0x01, 0x3d4); cr01 = inb(0x3d5); 1187 outb(0x02, 0x3d4); cr02 = inb(0x3d5); 1188 outb(0x03, 0x3d4); cr03 = inb(0x3d5); 1189 outb(0x04, 0x3d4); cr04 = inb(0x3d5); 1190 outb(0x05, 0x3d4); cr05 = inb(0x3d5); 1191 outb(0x06, 0x3d4); cr06 = inb(0x3d5); 1192 outb(0x07, 0x3d4); cr07 = inb(0x3d5); 1193 outb(0x09, 0x3d4); cr09 = inb(0x3d5); 1194 outb(0x10, 0x3d4); cr10 = inb(0x3d5); 1195 outb(0x11, 0x3d4); cr11 = inb(0x3d5); 1196 outb(0x12, 0x3d4); cr12 = inb(0x3d5); 1197 outb(0x15, 0x3d4); cr15 = inb(0x3d5); 1198 outb(0x16, 0x3d4); cr16 = inb(0x3d5); 1199 outb(0x27, 0x3d4); cr27 = inb(0x3d5); 1200 outb(0x2b, 0x3d4); cr2b = inb(0x3d5); 1201 outb(0x38, 0x3d4); cr38 = inb(0x3d5); 1202 1203 outb(0x0b, 0x3c4); 1204 inb(0x3c5); 1205 1206 outb(0x0d, 0x3c4); sr0d = inb(0x3c5); 1207 outb(0x18, 0x3c4); sr18 = inb(0x3c5); 1208 outb(0x19, 0x3c4); sr19 = inb(0x3c5); 1209 outb(0x0f, 0x3ce); gr0f = inb(0x3cf); 1210 1211 htotal = cr00 | (cr2b & 0x01) << 8; 1212 hdispend = cr01 | (cr2b & 0x02) << 7; 1213 hblankstart = cr02 | (cr2b & 0x10) << 4; 1214 hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2; 1215 hsyncstart = cr04 | (cr2b & 0x08) << 5; 1216 hsyncend = cr05 & 0x1f; 1217 1218 modedb[0].xres = hblankstart * 8; 1219 modedb[0].hsync_len = hsyncend * 8; 1220 modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres; 1221 modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres - 1222 modedb[0].right_margin - modedb[0].hsync_len; 1223 1224 vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4 1225 | (cr27 & 0x80) << 3; 1226 vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3 1227 | (cr27 & 0x10) << 6; 1228 vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2 1229 | (cr27 & 0x20) << 5; 1230 vsyncend = cr11 & 0x0f; 1231 vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4 1232 | (cr27 & 0x40) << 4; 1233 vblankend = cr16; 1234 1235 modedb[0].yres = vdispend + 1; 1236 modedb[0].vsync_len = vsyncend; 1237 modedb[0].lower_margin = vsyncstart - modedb[0].yres; 1238 modedb[0].upper_margin = vtotal - modedb[0].yres - 1239 modedb[0].lower_margin - modedb[0].vsync_len + 2; 1240 1241 tmp = cr38 & 0x3c; 1242 modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 : 1243 tmp == 8 ? 32 : 8; 1244 1245 fi = ((5864727 * (sr18 + 8)) / 1246 (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12; 1247 pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1; 1248 tmp = sr0d & 0x06; 1249 vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 ! 1250 modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi; 1251 1252 if (verbosity > 0) 1253 output("detected startup mode: " 1254 "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n", 1255 modedb[0].xres, modedb[0].yres, modedb[0].xres, 1256 modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin, 1257 modedb[0].right_margin, modedb[0].upper_margin, 1258 modedb[0].lower_margin, modedb[0].hsync_len, 1259 modedb[0].vsync_len); 1260 1261 // 1262 // We use this goto target in case of a failed check_var. No, I really 1263 // do not want to do it in another way! 1264 // 1265 1266 tryagain: 1267 1268 i = (mode == NULL) ? 0 : 1269 !strncmp(mode, "640x480", 7) ? 1 : 1270 !strncmp(mode, "800x600", 7) ? 2 : 1271 !strncmp(mode, "1024x768", 8) ? 3 : 1272 !strncmp(mode, "1280x1024", 9) ? 4 : 0; 1273 1274 ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref; 1275 1276 if (i == 0) { 1277 info->var.pixclock = modedb[i].pxclk; 1278 info->var.bits_per_pixel = modedb[i].bpp; 1279 } else { 1280 info->var.pixclock = (100000000 / 1281 ((modedb[i].left_margin + 1282 modedb[i].xres + 1283 modedb[i].right_margin + 1284 modedb[i].hsync_len) * 1285 (modedb[i].upper_margin + 1286 modedb[i].yres + 1287 modedb[i].lower_margin + 1288 modedb[i].vsync_len) * ref / 10000)); 1289 info->var.bits_per_pixel = bpp; 1290 } 1291 1292 info->var.left_margin = modedb[i].left_margin; 1293 info->var.right_margin = modedb[i].right_margin; 1294 info->var.xres = modedb[i].xres; 1295 if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32)) 1296 info->var.xres_virtual = modedb[i].vxres; 1297 else 1298 info->var.xres_virtual = modedb[i].xres; 1299 info->var.xoffset = 0; 1300 info->var.hsync_len = modedb[i].hsync_len; 1301 info->var.upper_margin = modedb[i].upper_margin; 1302 info->var.yres = modedb[i].yres; 1303 info->var.yres_virtual = modedb[i].vyres; 1304 info->var.yoffset = 0; 1305 info->var.lower_margin = modedb[i].lower_margin; 1306 info->var.vsync_len = modedb[i].vsync_len; 1307 info->var.sync = 0; 1308 info->var.vmode = FB_VMODE_NONINTERLACED; 1309 1310 if (cyblafb_check_var(&info->var, info)) { 1311 // 640x480 - 8@75 should really never fail. One case would 1312 // be fp == 1 and nativex < 640 ... give up then 1313 if (i == 1 && bpp == 8 && ref == 75) { 1314 output("Can't find a valid mode :-(\n"); 1315 return -EINVAL; 1316 } 1317 // Our detected mode is unlikely to fail. If it does, 1318 // try 640x480 - 8@75 ... 1319 if (i == 0) { 1320 mode = "640x480"; 1321 bpp = 8; 1322 ref = 75; 1323 output("Detected mode failed check_var! " 1324 "Trying 640x480 - 8@75\n"); 1325 goto tryagain; 1326 } 1327 // A specified video mode failed for some reason. 1328 // Try the startup mode first 1329 output("Specified mode '%s' failed check! " 1330 "Falling back to startup mode.\n", mode); 1331 mode = NULL; 1332 goto tryagain; 1333 } 1334 1335 return 0; 1336} 1337 1338//======================================================== 1339// 1340// Detect activated memory size. Undefined values require 1341// memsize parameter. 1342// 1343//======================================================== 1344 1345static unsigned int __devinit get_memsize(void) 1346{ 1347 unsigned char tmp; 1348 unsigned int k; 1349 1350 if (memsize) 1351 k = memsize * Kb; 1352 else { 1353 tmp = read3X4(CR1F) & 0x0F; 1354 switch (tmp) { 1355 case 0x03: 1356 k = 1 * 1024 * 1024; 1357 break; 1358 case 0x07: 1359 k = 2 * 1024 * 1024; 1360 break; 1361 case 0x0F: 1362 k = 4 * 1024 * 1024; 1363 break; 1364 case 0x04: 1365 k = 8 * 1024 * 1024; 1366 break; 1367 default: 1368 k = 1 * 1024 * 1024; 1369 output("Unknown memory size code %x in CR1F." 1370 " We default to 1 Mb for now, please" 1371 " do provide a memsize parameter!\n", tmp); 1372 } 1373 } 1374 1375 if (verbosity > 0) 1376 output("framebuffer size = %d Kb\n", k / Kb); 1377 return k; 1378} 1379 1380//========================================================= 1381// 1382// Detect if a flat panel monitor connected to the special 1383// interface is active. Override is possible by fp and crt 1384// parameters. 1385// 1386//========================================================= 1387 1388static unsigned int __devinit get_displaytype(void) 1389{ 1390 if (fp) 1391 return DISPLAY_FP; 1392 if (crt) 1393 return DISPLAY_CRT; 1394 return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT; 1395} 1396 1397//===================================== 1398// 1399// Get native resolution of flat panel 1400// 1401//===================================== 1402 1403static int __devinit get_nativex(void) 1404{ 1405 int x, y, tmp; 1406 1407 if (nativex) 1408 return nativex; 1409 1410 tmp = (read3CE(GR52) >> 4) & 3; 1411 1412 switch (tmp) { 1413 case 0: x = 1280; y = 1024; 1414 break; 1415 case 2: x = 1024; y = 768; 1416 break; 1417 case 3: x = 800; y = 600; 1418 break; 1419 case 4: x = 1400; y = 1050; 1420 break; 1421 case 1: 1422 default: 1423 x = 640; y = 480; 1424 break; 1425 } 1426 1427 if (verbosity > 0) 1428 output("%dx%d flat panel found\n", x, y); 1429 return x; 1430} 1431 1432static int __devinit cybla_pci_probe(struct pci_dev *dev, 1433 const struct pci_device_id *id) 1434{ 1435 struct fb_info *info; 1436 struct cyblafb_par *par; 1437 1438 info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev); 1439 if (!info) 1440 goto errout_alloc_info; 1441 1442 info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL); 1443 if (!info->pixmap.addr) { 1444 output("allocation of pixmap buffer failed!\n"); 1445 goto errout_alloc_pixmap; 1446 } 1447 info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4; 1448 info->pixmap.buf_align = 4; 1449 info->pixmap.access_align = 32; 1450 info->pixmap.flags = FB_PIXMAP_SYSTEM; 1451 info->pixmap.scan_align = 4; 1452 1453 par = info->par; 1454 par->ops = cyblafb_ops; 1455 1456 info->fix = cyblafb_fix; 1457 info->fbops = &par->ops; 1458 info->fix = cyblafb_fix; 1459 1460 if (pci_enable_device(dev)) { 1461 output("could not enable device!\n"); 1462 goto errout_enable; 1463 } 1464 // might already be requested by vga console or vesafb, 1465 // so we do care about success 1466 if (!request_region(0x3c0, 0x20, "cyblafb")) { 1467 output("region 0x3c0/0x20 already reserved\n"); 1468 vesafb |= 1; 1469 1470 } 1471 // 1472 // Graphics Engine Registers 1473 // 1474 if (!request_region(GEBase, 0x100, "cyblafb")) { 1475 output("region %#x/0x100 already reserved\n", GEBase); 1476 vesafb |= 2; 1477 } 1478 1479 regdump(par); 1480 1481 enable_mmio(); 1482 1483 // setup MMIO region 1484 info->fix.mmio_start = pci_resource_start(dev, 1); 1485 info->fix.mmio_len = 0x20000; 1486 1487 if (!request_mem_region(info->fix.mmio_start, 1488 info->fix.mmio_len, "cyblafb")) { 1489 output("request_mem_region failed for mmio region!\n"); 1490 goto errout_mmio_reqmem; 1491 } 1492 1493 io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len); 1494 1495 if (!io_virt) { 1496 output("ioremap failed for mmio region\n"); 1497 goto errout_mmio_remap; 1498 } 1499 // setup framebuffer memory ... might already be requested 1500 // by vesafb. Not to fail in case of an unsuccessful request 1501 // is useful if both are loaded. 1502 info->fix.smem_start = pci_resource_start(dev, 0); 1503 info->fix.smem_len = get_memsize(); 1504 1505 if (!request_mem_region(info->fix.smem_start, 1506 info->fix.smem_len, "cyblafb")) { 1507 output("region %#lx/%#x already reserved\n", 1508 info->fix.smem_start, info->fix.smem_len); 1509 vesafb |= 4; 1510 } 1511 1512 info->screen_base = ioremap_nocache(info->fix.smem_start, 1513 info->fix.smem_len); 1514 1515 if (!info->screen_base) { 1516 output("ioremap failed for smem region\n"); 1517 goto errout_smem_remap; 1518 } 1519 1520 displaytype = get_displaytype(); 1521 1522 if (displaytype == DISPLAY_FP) 1523 nativex = get_nativex(); 1524 1525 info->flags = FBINFO_DEFAULT 1526 | FBINFO_HWACCEL_COPYAREA 1527 | FBINFO_HWACCEL_FILLRECT 1528 | FBINFO_HWACCEL_IMAGEBLIT 1529 | FBINFO_READS_FAST 1530// | FBINFO_PARTIAL_PAN_OK 1531 | FBINFO_MISC_ALWAYS_SETPAR; 1532 1533 info->pseudo_palette = par->pseudo_pal; 1534 1535 if (getstartupmode(info)) 1536 goto errout_findmode; 1537 1538 fb_alloc_cmap(&info->cmap, 256, 0); 1539 1540 if (register_framebuffer(info)) { 1541 output("Could not register CyBla framebuffer\n"); 1542 goto errout_register; 1543 } 1544 1545 pci_set_drvdata(dev, info); 1546 1547 // 1548 // normal exit and error paths 1549 // 1550 1551 return 0; 1552 1553 errout_register: 1554 errout_findmode: 1555 iounmap(info->screen_base); 1556 errout_smem_remap: 1557 if (!(vesafb & 4)) 1558 release_mem_region(info->fix.smem_start, info->fix.smem_len); 1559 iounmap(io_virt); 1560 errout_mmio_remap: 1561 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 1562 errout_mmio_reqmem: 1563 if (!(vesafb & 1)) 1564 release_region(0x3c0, 32); 1565 errout_enable: 1566 kfree(info->pixmap.addr); 1567 errout_alloc_pixmap: 1568 framebuffer_release(info); 1569 errout_alloc_info: 1570 output("CyblaFB version %s aborting init.\n", VERSION); 1571 return -ENODEV; 1572} 1573 1574static void __devexit cybla_pci_remove(struct pci_dev *dev) 1575{ 1576 struct fb_info *info = pci_get_drvdata(dev); 1577 1578 unregister_framebuffer(info); 1579 iounmap(io_virt); 1580 iounmap(info->screen_base); 1581 if (!(vesafb & 4)) 1582 release_mem_region(info->fix.smem_start, info->fix.smem_len); 1583 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 1584 fb_dealloc_cmap(&info->cmap); 1585 if (!(vesafb & 2)) 1586 release_region(GEBase, 0x100); 1587 if (!(vesafb & 1)) 1588 release_region(0x3c0, 32); 1589 kfree(info->pixmap.addr); 1590 framebuffer_release(info); 1591 output("CyblaFB version %s normal exit.\n", VERSION); 1592} 1593 1594// 1595// List of boards that we are trying to support 1596// 1597static struct pci_device_id cybla_devices[] = { 1598 {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 1599 {0,} 1600}; 1601 1602MODULE_DEVICE_TABLE(pci, cybla_devices); 1603 1604static struct pci_driver cyblafb_pci_driver = { 1605 .name = "cyblafb", 1606 .id_table = cybla_devices, 1607 .probe = cybla_pci_probe, 1608 .remove = __devexit_p(cybla_pci_remove) 1609}; 1610 1611//============================================================= 1612// 1613// kernel command line example: 1614// 1615// video=cyblafb:1280x1024, bpp=16, ref=50 ... 1616// 1617// modprobe command line example: 1618// 1619// modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ... 1620// 1621//============================================================= 1622 1623static int __devinit cyblafb_init(void) 1624{ 1625#ifndef MODULE 1626 char *options = NULL; 1627 char *opt; 1628 1629 if (fb_get_options("cyblafb", &options)) 1630 return -ENODEV; 1631 1632 if (options && *options) 1633 while ((opt = strsep(&options, ",")) != NULL) { 1634 if (!*opt) 1635 continue; 1636 else if (!strncmp(opt, "bpp=", 4)) 1637 bpp = simple_strtoul(opt + 4, NULL, 0); 1638 else if (!strncmp(opt, "ref=", 4)) 1639 ref = simple_strtoul(opt + 4, NULL, 0); 1640 else if (!strncmp(opt, "fp", 2)) 1641 displaytype = DISPLAY_FP; 1642 else if (!strncmp(opt, "crt", 3)) 1643 displaytype = DISPLAY_CRT; 1644 else if (!strncmp(opt, "nativex=", 8)) 1645 nativex = simple_strtoul(opt + 8, NULL, 0); 1646 else if (!strncmp(opt, "center", 6)) 1647 center = 1; 1648 else if (!strncmp(opt, "stretch", 7)) 1649 stretch = 1; 1650 else if (!strncmp(opt, "pciwb=", 6)) 1651 pciwb = simple_strtoul(opt + 6, NULL, 0); 1652 else if (!strncmp(opt, "pcirb=", 6)) 1653 pcirb = simple_strtoul(opt + 6, NULL, 0); 1654 else if (!strncmp(opt, "pciwr=", 6)) 1655 pciwr = simple_strtoul(opt + 6, NULL, 0); 1656 else if (!strncmp(opt, "pcirr=", 6)) 1657 pcirr = simple_strtoul(opt + 6, NULL, 0); 1658 else if (!strncmp(opt, "memsize=", 8)) 1659 memsize = simple_strtoul(opt + 8, NULL, 0); 1660 else if (!strncmp(opt, "verbosity=", 10)) 1661 verbosity = simple_strtoul(opt + 10, NULL, 0); 1662 else 1663 mode = opt; 1664 } 1665#endif 1666 output("CyblaFB version %s initializing\n", VERSION); 1667 return pci_register_driver(&cyblafb_pci_driver); 1668} 1669 1670static void __exit cyblafb_exit(void) 1671{ 1672 pci_unregister_driver(&cyblafb_pci_driver); 1673} 1674 1675module_init(cyblafb_init); 1676module_exit(cyblafb_exit); 1677 1678MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>"); 1679MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core"); 1680MODULE_LICENSE("GPL");