1/* macfb.c: Generic framebuffer for Macs whose colourmaps/modes we 2 don't know how to set */ 3 4/* (c) 1999 David Huggins-Daines <dhd@debian.org> 5 6 Primarily based on vesafb.c, by Gerd Knorr 7 (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> 8 9 Also uses information and code from: 10 11 The original macfb.c from Linux/mac68k 2.0, by Alan Cox, Juergen 12 Mellinger, Mikael Forselius, Michael Schmitz, and others. 13 14 valkyriefb.c, by Martin Costabel, Kevin Schoedel, Barry Nathan, Dan 15 Jacobowitz, Paul Mackerras, Fabio Riccardi, and Geert Uytterhoeven. 16 17 This code is free software. You may copy, modify, and distribute 18 it subject to the terms and conditions of the GNU General Public 19 License, version 2, or any later version, at your convenience. */ 20 21#include <linux/module.h> 22#include <linux/kernel.h> 23#include <linux/sched.h> 24#include <linux/errno.h> 25#include <linux/string.h> 26#include <linux/mm.h> 27#include <linux/tty.h> 28#include <linux/slab.h> 29#include <linux/delay.h> 30#include <linux/nubus.h> 31#include <linux/init.h> 32#include <linux/fb.h> 33 34#include <asm/setup.h> 35#include <asm/bootinfo.h> 36#include <asm/uaccess.h> 37#include <asm/pgtable.h> 38#include <asm/irq.h> 39#include <asm/macintosh.h> 40#include <asm/io.h> 41#include <asm/machw.h> 42 43#include <video/fbcon.h> 44#include <video/fbcon-mfb.h> 45#include <video/fbcon-cfb2.h> 46#include <video/fbcon-cfb4.h> 47#include <video/fbcon-cfb8.h> 48#include <video/fbcon-cfb16.h> 49#include <video/fbcon-cfb24.h> 50#include <video/fbcon-cfb32.h> 51 52#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2) 53 54/* Common DAC base address for the LC, RBV, Valkyrie, and IIvx */ 55#define DAC_BASE 0x50f24000 56 57/* Some addresses for the DAFB */ 58#define DAFB_BASE 0xf9800200 59 60/* Address for the built-in Civic framebuffer in Quadra AVs */ 61#define CIVIC_BASE 0x50f30800 /* Only tested on 660AV! */ 62 63/* GSC (Gray Scale Controller) base address */ 64#define GSC_BASE 0x50F20000 65 66/* CSC (Color Screen Controller) base address */ 67#define CSC_BASE 0x50F20000 68 69static int (*macfb_setpalette) (unsigned int regno, unsigned int red, 70 unsigned int green, unsigned int blue) = NULL; 71static int valkyrie_setpalette (unsigned int regno, unsigned int red, 72 unsigned int green, unsigned int blue); 73static int dafb_setpalette (unsigned int regno, unsigned int red, 74 unsigned int green, unsigned int blue); 75static int rbv_setpalette (unsigned int regno, unsigned int red, 76 unsigned int green, unsigned int blue); 77static int mdc_setpalette (unsigned int regno, unsigned int red, 78 unsigned int green, unsigned int blue); 79static int toby_setpalette (unsigned int regno, unsigned int red, 80 unsigned int green, unsigned int blue); 81static int civic_setpalette (unsigned int regno, unsigned int red, 82 unsigned int green, unsigned int blue); 83static int csc_setpalette (unsigned int regno, unsigned int red, 84 unsigned int green, unsigned int blue); 85 86static volatile struct { 87 unsigned char addr; 88 /* Note: word-aligned */ 89 char pad[3]; 90 unsigned char lut; 91} *valkyrie_cmap_regs; 92 93static volatile struct { 94 unsigned char addr; 95 unsigned char lut; 96} *v8_brazil_cmap_regs; 97 98static volatile struct { 99 unsigned char addr; 100 char pad1[3]; /* word aligned */ 101 unsigned char lut; 102 char pad2[3]; /* word aligned */ 103 unsigned char cntl; /* a guess as to purpose */ 104} *rbv_cmap_regs; 105 106static volatile struct { 107 unsigned long reset; 108 unsigned long pad1[3]; 109 unsigned char pad2[3]; 110 unsigned char lut; 111} *dafb_cmap_regs; 112 113static volatile struct { 114 unsigned char addr; /* OFFSET: 0x00 */ 115 unsigned char pad1[15]; 116 unsigned char lut; /* OFFSET: 0x10 */ 117 unsigned char pad2[15]; 118 unsigned char status; /* OFFSET: 0x20 */ 119 unsigned char pad3[7]; 120 unsigned long vbl_addr; /* OFFSET: 0x28 */ 121 unsigned int status2; /* OFFSET: 0x2C */ 122} *civic_cmap_regs; 123 124static volatile struct { 125 char pad1[0x40]; 126 unsigned char clut_waddr; /* 0x40 */ 127 char pad2; 128 unsigned char clut_data; /* 0x42 */ 129 char pad3[0x3]; 130 unsigned char clut_raddr; /* 0x46 */ 131} *csc_cmap_regs; 132 133/* We will leave these the way they are for the time being */ 134struct mdc_cmap_regs { 135 char pad1[0x200200]; 136 unsigned char addr; 137 char pad2[6]; 138 unsigned char lut; 139}; 140 141struct toby_cmap_regs { 142 char pad1[0x90018]; 143 unsigned char lut; /* TFBClutWDataReg, offset 0x90018 */ 144 char pad2[3]; 145 unsigned char addr; /* TFBClutAddrReg, offset 0x9001C */ 146}; 147 148struct jet_cmap_regs { 149 char pad1[0xe0e000]; 150 unsigned char addr; 151 unsigned char lut; 152}; 153 154#endif 155 156#define PIXEL_TO_MM(a) (((a)*10)/28) /* width in mm at 72 dpi */ 157 158static unsigned long video_base; 159static int video_size; 160static char* video_vbase; /* mapped */ 161 162/* mode */ 163static int video_bpp; 164static int video_width; 165static int video_height; 166static int video_type = FB_TYPE_PACKED_PIXELS; 167static int video_visual; 168static int video_linelength; 169static int video_cmap_len; 170static int video_slot = 0; 171 172static struct fb_var_screeninfo macfb_defined={ 173 0,0,0,0, /* W,H, W, H (virtual) load xres,xres_virtual*/ 174 0,0, /* virtual -> visible no offset */ 175 8, /* depth -> load bits_per_pixel */ 176 0, /* greyscale ? */ 177 {0,0,0}, /* R */ 178 {0,0,0}, /* G */ 179 {0,0,0}, /* B */ 180 {0,0,0}, /* transparency */ 181 0, /* standard pixel format */ 182 FB_ACTIVATE_NOW, 183 -1, -1, 184 FB_ACCEL_NONE, /* The only way to accelerate a mac is .. */ 185 0L,0L,0L,0L,0L, 186 0L,0L,0, /* No sync info */ 187 FB_VMODE_NONINTERLACED, 188 {0,0,0,0,0,0} 189}; 190 191static struct display disp; 192static struct fb_info fb_info; 193static struct { u_short blue, green, red, pad; } palette[256]; 194static union { 195#ifdef FBCON_HAS_CFB16 196 u16 cfb16[16]; 197#endif 198#ifdef FBCON_HAS_CFB24 199 u32 cfb24[16]; 200#endif 201#ifdef FBCON_HAS_CFB32 202 u32 cfb32[16]; 203#endif 204} fbcon_cmap; 205 206static int inverse = 0; 207static int vidtest = 0; 208static int currcon = 0; 209 210static int macfb_update_var(int con, struct fb_info *info) 211{ 212 return 0; 213} 214 215static int macfb_get_fix(struct fb_fix_screeninfo *fix, int con, 216 struct fb_info *info) 217{ 218 memset(fix, 0, sizeof(struct fb_fix_screeninfo)); 219 strcpy(fix->id, "Mac Generic"); 220 221 fix->smem_start = video_base; 222 fix->smem_len = video_size; 223 fix->type = video_type; 224 fix->visual = video_visual; 225 fix->xpanstep = 0; 226 fix->ypanstep = 0; 227 fix->line_length=video_linelength; 228 return 0; 229} 230 231static int macfb_get_var(struct fb_var_screeninfo *var, int con, 232 struct fb_info *info) 233{ 234 if(con==-1) 235 memcpy(var, &macfb_defined, sizeof(struct fb_var_screeninfo)); 236 else 237 *var=fb_display[con].var; 238 return 0; 239} 240 241static void macfb_set_disp(int con) 242{ 243 struct fb_fix_screeninfo fix; 244 struct display *display; 245 246 if (con >= 0) 247 display = &fb_display[con]; 248 else 249 display = &disp; /* used during initialization */ 250 251 macfb_get_fix(&fix, con, &fb_info); 252 253 memset(display, 0, sizeof(struct display)); 254 display->screen_base = video_vbase; 255 display->visual = fix.visual; 256 display->type = fix.type; 257 display->type_aux = fix.type_aux; 258 display->ypanstep = fix.ypanstep; 259 display->ywrapstep = fix.ywrapstep; 260 display->line_length = fix.line_length; 261 display->next_line = fix.line_length; 262 display->can_soft_blank = 0; 263 display->inverse = inverse; 264 display->scrollmode = SCROLL_YREDRAW; 265 macfb_get_var(&display->var, -1, &fb_info); 266 267 switch (video_bpp) { 268#ifdef FBCON_HAS_MFB 269 case 1: 270 display->dispsw = &fbcon_mfb; 271 break; 272#endif 273#ifdef FBCON_HAS_CFB2 274 case 2: 275 display->dispsw = &fbcon_cfb2; 276 break; 277#endif 278#ifdef FBCON_HAS_CFB4 279 case 4: 280 display->dispsw = &fbcon_cfb4; 281 break; 282#endif 283#ifdef FBCON_HAS_CFB8 284 case 8: 285 display->dispsw = &fbcon_cfb8; 286 break; 287#endif 288#ifdef FBCON_HAS_CFB16 289 case 15: 290 case 16: 291 display->dispsw = &fbcon_cfb16; 292 display->dispsw_data = fbcon_cmap.cfb16; 293 break; 294#endif 295#ifdef FBCON_HAS_CFB24 296 case 24: 297 display->dispsw = &fbcon_cfb24; 298 display->dispsw_data = fbcon_cmap.cfb24; 299 break; 300#endif 301#ifdef FBCON_HAS_CFB32 302 case 32: 303 display->dispsw = &fbcon_cfb32; 304 display->dispsw_data = fbcon_cmap.cfb32; 305 break; 306#endif 307 default: 308 display->dispsw = &fbcon_dummy; 309 return; 310 } 311} 312 313static int macfb_set_var(struct fb_var_screeninfo *var, int con, 314 struct fb_info *info) 315{ 316 static int first = 1; 317 318 if (var->xres != macfb_defined.xres || 319 var->yres != macfb_defined.yres || 320 var->xres_virtual != macfb_defined.xres_virtual || 321 var->yres_virtual != macfb_defined.yres || 322 var->xoffset || 323 var->bits_per_pixel != macfb_defined.bits_per_pixel || 324 var->nonstd) { 325 if (first) { 326 printk("macfb does not support changing the video mode\n"); 327 first = 0; 328 } 329 return -EINVAL; 330 } 331 332 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) 333 return 0; 334 335 if (var->yoffset) 336 return -EINVAL; 337 return 0; 338} 339 340#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_CFB2) 341static int valkyrie_setpalette (unsigned int regno, unsigned int red, 342 unsigned int green, unsigned int blue) 343{ 344 unsigned long flags; 345 346 red >>= 8; 347 green >>= 8; 348 blue >>= 8; 349 350 save_flags(flags); 351 cli(); 352 353 /* tell clut which address to fill */ 354 nubus_writeb(regno, &valkyrie_cmap_regs->addr); 355 nop(); 356 357 /* send one color channel at a time */ 358 nubus_writeb(red, &valkyrie_cmap_regs->lut); 359 nop(); 360 nubus_writeb(green, &valkyrie_cmap_regs->lut); 361 nop(); 362 nubus_writeb(blue, &valkyrie_cmap_regs->lut); 363 364 restore_flags(flags); 365 366 return 0; 367} 368 369/* Unlike the Valkyrie, the DAFB cannot set individual colormap 370 registers. Therefore, we do what the MacOS driver does (no 371 kidding!) and simply set them one by one until we hit the one we 372 want. */ 373static int dafb_setpalette (unsigned int regno, unsigned int red, 374 unsigned int green, unsigned int blue) 375{ 376 static int lastreg = -1; 377 unsigned long flags; 378 379 red >>= 8; 380 green >>= 8; 381 blue >>= 8; 382 383 save_flags(flags); 384 cli(); 385 386 /* fbcon will set an entire colourmap, but X won't. Hopefully 387 this should accomodate both of them */ 388 if (regno != lastreg+1) { 389 int i; 390 391 /* Stab in the dark trying to reset the CLUT pointer */ 392 nubus_writel(0, &dafb_cmap_regs->reset); 393 nop(); 394 395 /* Loop until we get to the register we want */ 396 for (i = 0; i < regno; i++) { 397 nubus_writeb(palette[i].red >> 8, &dafb_cmap_regs->lut); 398 nop(); 399 nubus_writeb(palette[i].green >> 8, &dafb_cmap_regs->lut); 400 nop(); 401 nubus_writeb(palette[i].blue >> 8, &dafb_cmap_regs->lut); 402 nop(); 403 } 404 } 405 406 nubus_writeb(red, &dafb_cmap_regs->lut); 407 nop(); 408 nubus_writeb(green, &dafb_cmap_regs->lut); 409 nop(); 410 nubus_writeb(blue, &dafb_cmap_regs->lut); 411 412 restore_flags(flags); 413 414 lastreg = regno; 415 return 0; 416} 417 418/* V8 and Brazil seem to use the same DAC. Sonora does as well. */ 419static int v8_brazil_setpalette (unsigned int regno, unsigned int red, 420 unsigned int green, unsigned int blue) 421{ 422 unsigned char _red =red>>8; 423 unsigned char _green=green>>8; 424 unsigned char _blue =blue>>8; 425 unsigned char _regno; 426 unsigned long flags; 427 428 if (video_bpp>8) return 1; /* failsafe */ 429 430 save_flags(flags); 431 cli(); 432 433 /* On these chips, the CLUT register numbers are spread out 434 across the register space. Thus: 435 436 In 8bpp, all regnos are valid. 437 438 In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc 439 440 In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff */ 441 _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp); 442 nubus_writeb(_regno, &v8_brazil_cmap_regs->addr); nop(); 443 444 /* send one color channel at a time */ 445 nubus_writeb(_red, &v8_brazil_cmap_regs->lut); nop(); 446 nubus_writeb(_green, &v8_brazil_cmap_regs->lut); nop(); 447 nubus_writeb(_blue, &v8_brazil_cmap_regs->lut); 448 449 restore_flags(flags); 450 451 return 0; 452} 453 454static int rbv_setpalette (unsigned int regno, unsigned int red, 455 unsigned int green, unsigned int blue) 456{ 457 /* use MSBs */ 458 unsigned char _red =red>>8; 459 unsigned char _green=green>>8; 460 unsigned char _blue =blue>>8; 461 unsigned char _regno; 462 unsigned long flags; 463 464 if (video_bpp>8) return 1; /* failsafe */ 465 466 save_flags(flags); 467 cli(); 468 469 /* From the VideoToolbox driver. Seems to be saying that 470 * regno #254 and #255 are the important ones for 1-bit color, 471 * regno #252-255 are the important ones for 2-bit color, etc. 472 */ 473 _regno = regno + (256-(1<<video_bpp)); 474 475 /* reset clut? (VideoToolbox sez "not necessary") */ 476 nubus_writeb(0xFF, &rbv_cmap_regs->cntl); nop(); 477 478 /* tell clut which address to use. */ 479 nubus_writeb(_regno, &rbv_cmap_regs->addr); nop(); 480 481 /* send one color channel at a time. */ 482 nubus_writeb(_red, &rbv_cmap_regs->lut); nop(); 483 nubus_writeb(_green, &rbv_cmap_regs->lut); nop(); 484 nubus_writeb(_blue, &rbv_cmap_regs->lut); 485 486 restore_flags(flags); 487 /* done. */ 488 return 0; 489} 490 491/* Macintosh Display Card (8x24) */ 492static int mdc_setpalette(unsigned int regno, unsigned int red, 493 unsigned int green, unsigned int blue) 494{ 495 volatile struct mdc_cmap_regs *cmap_regs = 496 nubus_slot_addr(video_slot); 497 /* use MSBs */ 498 unsigned char _red =red>>8; 499 unsigned char _green=green>>8; 500 unsigned char _blue =blue>>8; 501 unsigned char _regno=regno; 502 unsigned long flags; 503 504 save_flags(flags); 505 cli(); 506 507 /* the nop's are there to order writes. */ 508 nubus_writeb(_regno, &cmap_regs->addr); nop(); 509 nubus_writeb(_red, &cmap_regs->lut); nop(); 510 nubus_writeb(_green, &cmap_regs->lut); nop(); 511 nubus_writeb(_blue, &cmap_regs->lut); 512 513 restore_flags(flags); 514 return 0; 515} 516 517/* Toby frame buffer */ 518static int toby_setpalette(unsigned int regno, unsigned int red, 519 unsigned int green, unsigned int blue) 520{ 521 volatile struct toby_cmap_regs *cmap_regs = 522 nubus_slot_addr(video_slot); 523 /* use MSBs */ 524 unsigned char _red =~(red>>8); 525 unsigned char _green=~(green>>8); 526 unsigned char _blue =~(blue>>8); 527 unsigned char _regno = (regno<<(8-video_bpp)) | (0xFF>>video_bpp); 528 unsigned long flags; 529 530 save_flags(flags); 531 cli(); 532 533 nubus_writeb(_regno, &cmap_regs->addr); nop(); 534 nubus_writeb(_red, &cmap_regs->lut); nop(); 535 nubus_writeb(_green, &cmap_regs->lut); nop(); 536 nubus_writeb(_blue, &cmap_regs->lut); 537 538 restore_flags(flags); 539 return 0; 540} 541 542/* Jet frame buffer */ 543static int jet_setpalette(unsigned int regno, unsigned int red, 544 unsigned int green, unsigned int blue) 545{ 546 volatile struct jet_cmap_regs *cmap_regs = 547 nubus_slot_addr(video_slot); 548 /* use MSBs */ 549 unsigned char _red = (red>>8); 550 unsigned char _green = (green>>8); 551 unsigned char _blue = (blue>>8); 552 unsigned long flags; 553 554 save_flags(flags); 555 cli(); 556 557 nubus_writeb(regno, &cmap_regs->addr); nop(); 558 nubus_writeb(_red, &cmap_regs->lut); nop(); 559 nubus_writeb(_green, &cmap_regs->lut); nop(); 560 nubus_writeb(_blue, &cmap_regs->lut); 561 562 restore_flags(flags); 563 return 0; 564} 565 566static int civic_setpalette (unsigned int regno, unsigned int red, 567 unsigned int green, unsigned int blue) 568{ 569 static int lastreg = -1; 570 unsigned long flags; 571 int clut_status; 572 573 if (video_bpp > 8) return 1; /* failsafe */ 574 575 red >>= 8; 576 green >>= 8; 577 blue >>= 8; 578 579 save_flags(flags); 580 cli(); 581 582 /* 583 * Set the register address 584 */ 585 nubus_writeb(regno, &civic_cmap_regs->addr); nop(); 586 587 /* 588 * Wait for VBL interrupt here; 589 * They're usually not enabled from Penguin, so we won't check 590 */ 591 592 /* 593 * Grab a status word and do some checking; 594 * Then finally write the clut! 595 */ 596 clut_status = nubus_readb(&civic_cmap_regs->status2); 597 598 if ((clut_status & 0x0008) == 0) 599 { 600 601 nubus_writeb( red, &civic_cmap_regs->lut); nop(); 602 nubus_writeb(green, &civic_cmap_regs->lut); nop(); 603 nubus_writeb( blue, &civic_cmap_regs->lut); nop(); 604 nubus_writeb( 0x00, &civic_cmap_regs->lut); nop(); 605 } 606 else 607 { 608 unsigned char junk; 609 610 junk = nubus_readb(&civic_cmap_regs->lut); nop(); 611 junk = nubus_readb(&civic_cmap_regs->lut); nop(); 612 junk = nubus_readb(&civic_cmap_regs->lut); nop(); 613 junk = nubus_readb(&civic_cmap_regs->lut); nop(); 614 615 if ((clut_status & 0x000D) != 0) 616 { 617 nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); 618 nubus_writeb(0x00, &civic_cmap_regs->lut); nop(); 619 } 620 621 nubus_writeb( red, &civic_cmap_regs->lut); nop(); 622 nubus_writeb(green, &civic_cmap_regs->lut); nop(); 623 nubus_writeb( blue, &civic_cmap_regs->lut); nop(); 624 nubus_writeb( junk, &civic_cmap_regs->lut); nop(); 625 } 626 627 restore_flags(flags); 628 629 lastreg = regno; 630 return 0; 631} 632 633/* 634 * The CSC is the framebuffer on the PowerBook 190 series 635 * (and the 5300 too, but that's a PowerMac). This function 636 * brought to you in part by the ECSC driver for MkLinux. 637 */ 638 639static int csc_setpalette (unsigned int regno, unsigned int red, 640 unsigned int green, unsigned int blue) 641{ 642 mdelay(1); 643 csc_cmap_regs->clut_waddr = regno; 644 csc_cmap_regs->clut_data = red; 645 csc_cmap_regs->clut_data = green; 646 csc_cmap_regs->clut_data = blue; 647 return 0; 648} 649 650#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB4 || FBCON_HAS_CFB2 */ 651 652static int macfb_getcolreg(unsigned regno, unsigned *red, unsigned *green, 653 unsigned *blue, unsigned *transp, 654 struct fb_info *fb_info) 655{ 656 /* 657 * Read a single color register and split it into colors/transparent. 658 * Return != 0 for invalid regno. 659 */ 660 661 if (regno >= video_cmap_len) 662 return 1; 663 664 *red = palette[regno].red; 665 *green = palette[regno].green; 666 *blue = palette[regno].blue; 667 *transp = 0; 668 return 0; 669} 670 671static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green, 672 unsigned blue, unsigned transp, 673 struct fb_info *fb_info) 674{ 675 /* 676 * Set a single color register. The values supplied are 677 * already rounded down to the hardware's capabilities 678 * (according to the entries in the `var' structure). Return 679 * != 0 for invalid regno. 680 */ 681 682 if (regno >= video_cmap_len) 683 return 1; 684 685 palette[regno].red = red; 686 palette[regno].green = green; 687 palette[regno].blue = blue; 688 689 switch (video_bpp) { 690#ifdef FBCON_HAS_MFB 691 case 1: 692 /* We shouldn't get here */ 693 break; 694#endif 695#ifdef FBCON_HAS_CFB2 696 case 2: 697 if (macfb_setpalette) 698 macfb_setpalette(regno, red, green, blue); 699 else 700 return 1; 701 break; 702#endif 703#ifdef FBCON_HAS_CFB4 704 case 4: 705 if (macfb_setpalette) 706 macfb_setpalette(regno, red, green, blue); 707 else 708 return 1; 709 break; 710#endif 711#ifdef FBCON_HAS_CFB8 712 case 8: 713 if (macfb_setpalette) 714 macfb_setpalette(regno, red, green, blue); 715 else 716 return 1; 717 break; 718#endif 719#ifdef FBCON_HAS_CFB16 720 case 15: 721 case 16: 722 /* 1:5:5:5 */ 723 fbcon_cmap.cfb16[regno] = 724 ((red & 0xf800) >> 1) | 725 ((green & 0xf800) >> 6) | 726 ((blue & 0xf800) >> 11) | 727 ((transp != 0) << 15); 728 break; 729#endif 730 /* I'm pretty sure that one or the other of these 731 doesn't exist on 68k Macs */ 732#ifdef FBCON_HAS_CFB24 733 case 24: 734 red >>= 8; 735 green >>= 8; 736 blue >>= 8; 737 fbcon_cmap.cfb24[regno] = 738 (red << macfb_defined.red.offset) | 739 (green << macfb_defined.green.offset) | 740 (blue << macfb_defined.blue.offset); 741 break; 742#endif 743#ifdef FBCON_HAS_CFB32 744 case 32: 745 red >>= 8; 746 green >>= 8; 747 blue >>= 8; 748 fbcon_cmap.cfb32[regno] = 749 (red << macfb_defined.red.offset) | 750 (green << macfb_defined.green.offset) | 751 (blue << macfb_defined.blue.offset); 752 break; 753#endif 754 } 755 return 0; 756} 757 758static void do_install_cmap(int con, struct fb_info *info) 759{ 760 if (con != currcon) 761 return; 762 if (fb_display[con].cmap.len) 763 fb_set_cmap(&fb_display[con].cmap, 1, macfb_setcolreg, info); 764 else 765 fb_set_cmap(fb_default_cmap(video_cmap_len), 1, 766 macfb_setcolreg, info); 767} 768 769static int macfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 770 struct fb_info *info) 771{ 772 if (con == currcon) /* current console? */ 773 return fb_get_cmap(cmap, kspc, macfb_getcolreg, info); 774 else if (fb_display[con].cmap.len) /* non default colormap? */ 775 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); 776 else 777 fb_copy_cmap(fb_default_cmap(video_cmap_len), 778 cmap, kspc ? 0 : 2); 779 return 0; 780} 781 782static int macfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 783 struct fb_info *info) 784{ 785 int err; 786 787 if (!fb_display[con].cmap.len) { /* no colormap allocated? */ 788 err = fb_alloc_cmap(&fb_display[con].cmap,video_cmap_len,0); 789 if (err) 790 return err; 791 } 792 if (con == currcon) /* current console? */ 793 return fb_set_cmap(cmap, kspc, macfb_setcolreg, info); 794 else 795 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); 796 return 0; 797} 798 799static struct fb_ops macfb_ops = { 800 owner: THIS_MODULE, 801 fb_get_fix: macfb_get_fix, 802 fb_get_var: macfb_get_var, 803 fb_set_var: macfb_set_var, 804 fb_get_cmap: macfb_get_cmap, 805 fb_set_cmap: macfb_set_cmap, 806}; 807 808void __init macfb_setup(char *options, int *ints) 809{ 810 char *this_opt; 811 812 fb_info.fontname[0] = '\0'; 813 814 if (!options || !*options) 815 return; 816 817 while ((this_opt = strsep(&options, ",")) != NULL) { 818 if (!*this_opt) continue; 819 820 if (! strcmp(this_opt, "inverse")) 821 inverse=1; 822 else if (!strncmp(this_opt, "font:", 5)) 823 strcpy(fb_info.fontname, this_opt+5); 824 /* This means "turn on experimental CLUT code" */ 825 else if (!strcmp(this_opt, "vidtest")) 826 vidtest=1; 827 } 828} 829 830static int macfb_switch(int con, struct fb_info *info) 831{ 832 /* Do we have to save the colormap? */ 833 if (fb_display[currcon].cmap.len) 834 fb_get_cmap(&fb_display[currcon].cmap, 1, macfb_getcolreg, 835 info); 836 837 currcon = con; 838 /* Install new colormap */ 839 do_install_cmap(con, info); 840 macfb_update_var(con, info); 841 return 1; 842} 843 844static void macfb_blank(int blank, struct fb_info *info) 845{ 846 /* Not supported */ 847} 848 849void __init macfb_init(void) 850{ 851 struct nubus_dev* ndev = NULL; 852 int video_is_nubus = 0; 853 854 if (!MACH_IS_MAC) 855 return; 856 857 /* There can only be one internal video controller anyway so 858 we're not too worried about this */ 859 video_width = mac_bi_data.dimensions & 0xFFFF; 860 video_height = mac_bi_data.dimensions >> 16; 861 video_bpp = mac_bi_data.videodepth; 862 video_linelength = mac_bi_data.videorow; 863 video_size = video_linelength * video_height; 864 /* Note: physical address (since 2.1.127) */ 865 video_base = mac_bi_data.videoaddr; 866 /* This is actually redundant with the initial mappings. 867 However, there are some non-obvious aspects to the way 868 those mappings are set up, so this is in fact the safest 869 way to ensure that this driver will work on every possible 870 Mac */ 871 video_vbase = ioremap(mac_bi_data.videoaddr, video_size); 872 873 printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n", 874 video_base, video_vbase, video_size/1024); 875 printk("macfb: mode is %dx%dx%d, linelength=%d\n", 876 video_width, video_height, video_bpp, video_linelength); 877 878 /* 879 * Fill in the available video resolution 880 */ 881 882 macfb_defined.xres = video_width; 883 macfb_defined.yres = video_height; 884 macfb_defined.xres_virtual = video_width; 885 macfb_defined.yres_virtual = video_height; 886 macfb_defined.bits_per_pixel = video_bpp; 887 macfb_defined.height = PIXEL_TO_MM(macfb_defined.yres); 888 macfb_defined.width = PIXEL_TO_MM(macfb_defined.xres); 889 890 printk("macfb: scrolling: redraw\n"); 891 macfb_defined.yres_virtual = video_height; 892 893 /* some dummy values for timing to make fbset happy */ 894 macfb_defined.pixclock = 10000000 / video_width * 1000 / video_height; 895 macfb_defined.left_margin = (video_width / 8) & 0xf8; 896 macfb_defined.right_margin = 32; 897 macfb_defined.upper_margin = 16; 898 macfb_defined.lower_margin = 4; 899 macfb_defined.hsync_len = (video_width / 8) & 0xf8; 900 macfb_defined.vsync_len = 4; 901 902 switch (video_bpp) { 903 case 1: 904 video_cmap_len = 0; 905 video_visual = FB_VISUAL_MONO01; 906 break; 907 case 2: 908 case 4: 909 case 8: 910 macfb_defined.red.length = video_bpp; 911 macfb_defined.green.length = video_bpp; 912 macfb_defined.blue.length = video_bpp; 913 video_cmap_len = 1 << video_bpp; 914 video_visual = FB_VISUAL_PSEUDOCOLOR; 915 break; 916 case 16: 917 macfb_defined.transp.offset = 15; 918 macfb_defined.transp.length = 1; 919 macfb_defined.red.offset = 10; 920 macfb_defined.red.length = 5; 921 macfb_defined.green.offset = 5; 922 macfb_defined.green.length = 5; 923 macfb_defined.blue.offset = 0; 924 macfb_defined.blue.length = 5; 925 printk("macfb: directcolor: " 926 "size=1:5:5:5, shift=15:10:5:0\n"); 927 video_cmap_len = 16; 928 /* Should actually be FB_VISUAL_DIRECTCOLOR, but this 929 works too */ 930 video_visual = FB_VISUAL_TRUECOLOR; 931 break; 932 case 24: 933 case 32: 934 macfb_defined.red.offset = 16; 935 macfb_defined.red.length = 8; 936 macfb_defined.green.offset = 8; 937 macfb_defined.green.length = 8; 938 macfb_defined.blue.offset = 0; 939 macfb_defined.blue.length = 8; 940 printk("macfb: truecolor: " 941 "size=0:8:8:8, shift=0:16:8:0\n"); 942 video_cmap_len = 16; 943 video_visual = FB_VISUAL_TRUECOLOR; 944 default: 945 video_cmap_len = 0; 946 video_visual = FB_VISUAL_MONO01; 947 printk("macfb: unknown or unsupported bit depth: %d\n", video_bpp); 948 break; 949 } 950 951 /* Hardware dependent stuff */ 952 /* We take a wild guess that if the video physical address is 953 * in nubus slot space, that the nubus card is driving video. 954 * Penguin really ought to tell us whether we are using internal 955 * video or not. 956 */ 957 /* Hopefully we only find one of them. Otherwise our NuBus 958 code is really broken :-) */ 959 960 while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev)) 961 != NULL) 962 { 963 if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr 964 && (mac_bi_data.videoaddr < 965 (unsigned long)nubus_slot_addr(ndev->board->slot+1)))) 966 continue; 967 video_is_nubus = 1; 968 /* We should probably just use the slot address... */ 969 video_slot = ndev->board->slot; 970 971 switch(ndev->dr_hw) { 972 case NUBUS_DRHW_APPLE_MDC: 973 strcpy( fb_info.modename, "Macintosh Display Card" ); 974 macfb_setpalette = mdc_setpalette; 975 macfb_defined.activate = FB_ACTIVATE_NOW; 976 break; 977 case NUBUS_DRHW_APPLE_TFB: 978 strcpy( fb_info.modename, "Toby" ); 979 macfb_setpalette = toby_setpalette; 980 macfb_defined.activate = FB_ACTIVATE_NOW; 981 break; 982 case NUBUS_DRHW_APPLE_JET: 983 strcpy(fb_info.modename, "Jet"); 984 macfb_setpalette = jet_setpalette; 985 macfb_defined.activate = FB_ACTIVATE_NOW; 986 break; 987 default: 988 strcpy( fb_info.modename, "Generic NuBus" ); 989 break; 990 } 991 } 992 993 /* If it's not a NuBus card, it must be internal video */ 994 if (!video_is_nubus) 995 switch( mac_bi_data.id ) 996 { 997 /* These don't have onboard video. Eventually, we may 998 be able to write separate framebuffer drivers for 999 them (tobyfb.c, hiresfb.c, etc, etc) */ 1000 case MAC_MODEL_II: 1001 case MAC_MODEL_IIX: 1002 case MAC_MODEL_IICX: 1003 case MAC_MODEL_IIFX: 1004 strcpy( fb_info.modename, "Generic NuBus" ); 1005 break; 1006 1007 /* Valkyrie Quadras */ 1008 case MAC_MODEL_Q630: 1009 /* I'm not sure about this one */ 1010 case MAC_MODEL_P588: 1011 strcpy( fb_info.modename, "Valkyrie built-in" ); 1012 macfb_setpalette = valkyrie_setpalette; 1013 macfb_defined.activate = FB_ACTIVATE_NOW; 1014 valkyrie_cmap_regs = ioremap(DAC_BASE, 0x1000); 1015 break; 1016 1017 /* DAFB Quadras */ 1018 /* Note: these first four have the v7 DAFB, which is 1019 known to be rather unlike the ones used in the 1020 other models */ 1021 case MAC_MODEL_P475: 1022 case MAC_MODEL_P475F: 1023 case MAC_MODEL_P575: 1024 case MAC_MODEL_Q605: 1025 1026 case MAC_MODEL_Q800: 1027 case MAC_MODEL_Q650: 1028 case MAC_MODEL_Q610: 1029 case MAC_MODEL_C650: 1030 case MAC_MODEL_C610: 1031 case MAC_MODEL_Q700: 1032 case MAC_MODEL_Q900: 1033 case MAC_MODEL_Q950: 1034 strcpy( fb_info.modename, "DAFB built-in" ); 1035 macfb_setpalette = dafb_setpalette; 1036 macfb_defined.activate = FB_ACTIVATE_NOW; 1037 dafb_cmap_regs = ioremap(DAFB_BASE, 0x1000); 1038 break; 1039 1040 /* LC II uses the V8 framebuffer */ 1041 case MAC_MODEL_LCII: 1042 strcpy( fb_info.modename, "V8 built-in" ); 1043 macfb_setpalette = v8_brazil_setpalette; 1044 macfb_defined.activate = FB_ACTIVATE_NOW; 1045 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); 1046 break; 1047 1048 /* IIvi, IIvx use the "Brazil" framebuffer (which is 1049 very much like the V8, it seems, and probably uses 1050 the same DAC) */ 1051 case MAC_MODEL_IIVI: 1052 case MAC_MODEL_IIVX: 1053 case MAC_MODEL_P600: 1054 strcpy( fb_info.modename, "Brazil built-in" ); 1055 macfb_setpalette = v8_brazil_setpalette; 1056 macfb_defined.activate = FB_ACTIVATE_NOW; 1057 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); 1058 break; 1059 1060 /* LC III (and friends) use the Sonora framebuffer */ 1061 /* Incidentally this is also used in the non-AV models 1062 of the x100 PowerMacs */ 1063 /* These do in fact seem to use the same DAC interface 1064 as the LC II. */ 1065 case MAC_MODEL_LCIII: 1066 case MAC_MODEL_P520: 1067 case MAC_MODEL_P550: 1068 case MAC_MODEL_P460: 1069 macfb_setpalette = v8_brazil_setpalette; 1070 macfb_defined.activate = FB_ACTIVATE_NOW; 1071 strcpy( fb_info.modename, "Sonora built-in" ); 1072 v8_brazil_cmap_regs = ioremap(DAC_BASE, 0x1000); 1073 break; 1074 1075 /* IIci and IIsi use the infamous RBV chip 1076 (the IIsi is just a rebadged and crippled 1077 IIci in a different case, BTW) */ 1078 case MAC_MODEL_IICI: 1079 case MAC_MODEL_IISI: 1080 macfb_setpalette = rbv_setpalette; 1081 macfb_defined.activate = FB_ACTIVATE_NOW; 1082 strcpy( fb_info.modename, "RBV built-in" ); 1083 rbv_cmap_regs = ioremap(DAC_BASE, 0x1000); 1084 break; 1085 1086 /* AVs use the Civic framebuffer */ 1087 case MAC_MODEL_Q840: 1088 case MAC_MODEL_C660: 1089 macfb_setpalette = civic_setpalette; 1090 macfb_defined.activate = FB_ACTIVATE_NOW; 1091 strcpy( fb_info.modename, "Civic built-in" ); 1092 civic_cmap_regs = ioremap(CIVIC_BASE, 0x1000); 1093 break; 1094 1095 1096 /* Write a setpalette function for your machine, then 1097 you can add something similar here. These are 1098 grouped by classes of video chipsets. Some of this 1099 information is from the VideoToolbox "Bugs" web 1100 page at 1101 http://rajsky.psych.nyu.edu/Tips/VideoBugs.html */ 1102 1103 /* Assorted weirdos */ 1104 /* We think this may be like the LC II */ 1105 case MAC_MODEL_LC: 1106 if (vidtest) { 1107 macfb_setpalette = v8_brazil_setpalette; 1108 macfb_defined.activate = FB_ACTIVATE_NOW; 1109 v8_brazil_cmap_regs = 1110 ioremap(DAC_BASE, 0x1000); 1111 } 1112 strcpy( fb_info.modename, "LC built-in" ); 1113 break; 1114 /* We think this may be like the LC II */ 1115 case MAC_MODEL_CCL: 1116 if (vidtest) { 1117 macfb_setpalette = v8_brazil_setpalette; 1118 macfb_defined.activate = FB_ACTIVATE_NOW; 1119 v8_brazil_cmap_regs = 1120 ioremap(DAC_BASE, 0x1000); 1121 } 1122 strcpy( fb_info.modename, "Color Classic built-in" ); 1123 break; 1124 1125 /* And we *do* mean "weirdos" */ 1126 case MAC_MODEL_TV: 1127 strcpy( fb_info.modename, "Mac TV built-in" ); 1128 break; 1129 1130 /* These don't have colour, so no need to worry */ 1131 case MAC_MODEL_SE30: 1132 case MAC_MODEL_CLII: 1133 strcpy( fb_info.modename, "Monochrome built-in" ); 1134 break; 1135 1136 /* Powerbooks are particularly difficult. Many of 1137 them have separate framebuffers for external and 1138 internal video, which is admittedly pretty cool, 1139 but will be a bit of a headache to support here. 1140 Also, many of them are grayscale, and we don't 1141 really support that. */ 1142 1143 case MAC_MODEL_PB140: 1144 case MAC_MODEL_PB145: 1145 case MAC_MODEL_PB170: 1146 strcpy( fb_info.modename, "DDC built-in" ); 1147 break; 1148 1149 /* Internal is GSC, External (if present) is ViSC */ 1150 case MAC_MODEL_PB150: /* no external video */ 1151 case MAC_MODEL_PB160: 1152 case MAC_MODEL_PB165: 1153 case MAC_MODEL_PB180: 1154 case MAC_MODEL_PB210: 1155 case MAC_MODEL_PB230: 1156 strcpy( fb_info.modename, "GSC built-in" ); 1157 break; 1158 1159 /* Internal is TIM, External is ViSC */ 1160 case MAC_MODEL_PB165C: 1161 case MAC_MODEL_PB180C: 1162 strcpy( fb_info.modename, "TIM built-in" ); 1163 break; 1164 1165 /* Internal is CSC, External is Keystone+Ariel. */ 1166 case MAC_MODEL_PB190: /* external video is optional */ 1167 case MAC_MODEL_PB520: 1168 case MAC_MODEL_PB250: 1169 case MAC_MODEL_PB270C: 1170 case MAC_MODEL_PB280: 1171 case MAC_MODEL_PB280C: 1172 macfb_setpalette = csc_setpalette; 1173 macfb_defined.activate = FB_ACTIVATE_NOW; 1174 strcpy( fb_info.modename, "CSC built-in" ); 1175 csc_cmap_regs = ioremap(CSC_BASE, 0x1000); 1176 break; 1177 1178 default: 1179 strcpy( fb_info.modename, "Unknown/Unsupported built-in" ); 1180 break; 1181 } 1182 1183 fb_info.changevar = NULL; 1184 fb_info.node = -1; 1185 fb_info.fbops = &macfb_ops; 1186 fb_info.disp = &disp; 1187 fb_info.switch_con = &macfb_switch; 1188 fb_info.updatevar = &macfb_update_var; 1189 fb_info.blank = &macfb_blank; 1190 fb_info.flags = FBINFO_FLAG_DEFAULT; 1191 macfb_set_disp(-1); 1192 do_install_cmap(0, &fb_info); 1193 1194 if (register_framebuffer(&fb_info) < 0) 1195 return; 1196 1197 printk("fb%d: %s frame buffer device\n", 1198 GET_FB_IDX(fb_info.node), fb_info.modename); 1199} 1200 1201MODULE_LICENSE("GPL"); 1202