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.18-rc2 1586 lines 40 kB view raw
1/* 2 * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device 3 * 4 * Copyright (C) 1997 Jes Sorensen 5 * 6 * This file is based on the CyberVision64 frame buffer device and 7 * the generic Cirrus Logic driver. 8 * 9 * cyberfb.c: Copyright (C) 1996 Martin Apel, 10 * Geert Uytterhoeven 11 * clgen.c: Copyright (C) 1996 Frank Neumann 12 * 13 * History: 14 * - 22 Jan 97: Initial work 15 * - 14 Feb 97: Screen initialization works somewhat, still only 16 * 8-bit packed pixel is supported. 17 * 18 * This file is subject to the terms and conditions of the GNU General Public 19 * License. See the file COPYING in the main directory of this archive 20 * for more details. 21 */ 22 23#include <linux/module.h> 24#include <linux/kernel.h> 25#include <linux/errno.h> 26#include <linux/string.h> 27#include <linux/mm.h> 28#include <linux/slab.h> 29#include <linux/delay.h> 30#include <linux/fb.h> 31#include <linux/zorro.h> 32#include <linux/init.h> 33 34#include <asm/uaccess.h> 35#include <asm/system.h> 36#include <asm/irq.h> 37#include <asm/pgtable.h> 38#include <asm/io.h> 39 40#include <video/fbcon.h> 41#include <video/fbcon-cfb8.h> 42#include <video/fbcon-cfb16.h> 43 44#include "retz3fb.h" 45 46/* #define DEBUG if(1) */ 47#define DEBUG if(0) 48 49/* 50 * Reserve space for one pattern line. 51 * 52 * For the time being we only support 4MB boards! 53 */ 54 55#define PAT_MEM_SIZE 16*3 56#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE) 57 58struct retz3fb_par { 59 int xres; 60 int yres; 61 int xres_vir; 62 int yres_vir; 63 int xoffset; 64 int yoffset; 65 int bpp; 66 67 struct fb_bitfield red; 68 struct fb_bitfield green; 69 struct fb_bitfield blue; 70 struct fb_bitfield transp; 71 72 int pixclock; 73 int left_margin; /* time from sync to picture */ 74 int right_margin; /* time from picture to sync */ 75 int upper_margin; /* time from sync to picture */ 76 int lower_margin; 77 int hsync_len; /* length of horizontal sync */ 78 int vsync_len; /* length of vertical sync */ 79 int vmode; 80 81 int accel; 82}; 83 84struct display_data { 85 long h_total; /* Horizontal Total */ 86 long h_sstart; /* Horizontal Sync Start */ 87 long h_sstop; /* Horizontal Sync Stop */ 88 long h_bstart; /* Horizontal Blank Start */ 89 long h_bstop; /* Horizontal Blank Stop */ 90 long h_dispend; /* Horizontal Display End */ 91 long v_total; /* Vertical Total */ 92 long v_sstart; /* Vertical Sync Start */ 93 long v_sstop; /* Vertical Sync Stop */ 94 long v_bstart; /* Vertical Blank Start */ 95 long v_bstop; /* Vertical Blank Stop */ 96 long v_dispend; /* Horizontal Display End */ 97}; 98 99struct retz3_fb_info { 100 struct fb_info info; 101 unsigned char *base; 102 unsigned char *fbmem; 103 unsigned long fbsize; 104 volatile unsigned char *regs; 105 unsigned long physfbmem; 106 unsigned long physregs; 107 int current_par_valid; /* set to 0 by memset */ 108 int blitbusy; 109 struct display disp; 110 struct retz3fb_par current_par; 111 unsigned char color_table [256][3]; 112}; 113 114 115static char fontname[40] __initdata = { 0 }; 116 117#define retz3info(info) ((struct retz3_fb_info *)(info)) 118#define fbinfo(info) ((struct fb_info *)(info)) 119 120 121/* 122 * Frame Buffer Name 123 */ 124 125static char retz3fb_name[16] = "RetinaZ3"; 126 127 128/* 129 * A small info on how to convert XFree86 timing values into fb 130 * timings - by Frank Neumann: 131 * 132An XFree86 mode line consists of the following fields: 133 "800x600" 50 800 856 976 1040 600 637 643 666 134 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL 135 136The fields in the fb_var_screeninfo structure are: 137 unsigned long pixclock; * pixel clock in ps (pico seconds) * 138 unsigned long left_margin; * time from sync to picture * 139 unsigned long right_margin; * time from picture to sync * 140 unsigned long upper_margin; * time from sync to picture * 141 unsigned long lower_margin; 142 unsigned long hsync_len; * length of horizontal sync * 143 unsigned long vsync_len; * length of vertical sync * 144 1451) Pixelclock: 146 xfree: in MHz 147 fb: In Picoseconds (ps) 148 149 pixclock = 1000000 / DCF 150 1512) horizontal timings: 152 left_margin = HFL - SH2 153 right_margin = SH1 - HR 154 hsync_len = SH2 - SH1 155 1563) vertical timings: 157 upper_margin = VFL - SV2 158 lower_margin = SV1 - VR 159 vsync_len = SV2 - SV1 160 161Good examples for VESA timings can be found in the XFree86 source tree, 162under "programs/Xserver/hw/xfree86/doc/modeDB.txt". 163*/ 164 165/* 166 * Predefined Video Modes 167 */ 168 169static struct { 170 const char *name; 171 struct fb_var_screeninfo var; 172} retz3fb_predefined[] __initdata = { 173 /* 174 * NB: it is very important to adjust the pixel-clock to the color-depth. 175 */ 176 177 { 178 "640x480", { /* 640x480, 8 bpp */ 179 640, 480, 640, 480, 0, 0, 8, 0, 180 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 181 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2, 182 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED 183 } 184 }, 185 /* 186 ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 187 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL 188 */ 189 { 190 "800x600", { /* 800x600, 8 bpp */ 191 800, 600, 800, 600, 0, 0, 8, 0, 192 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 193 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2, 194 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 195 } 196 }, 197 { 198 "800x600-60", { /* 800x600, 8 bpp */ 199 800, 600, 800, 600, 0, 0, 8, 0, 200 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 201 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4, 202 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 203 } 204 }, 205 { 206 "800x600-70", { /* 800x600, 8 bpp */ 207 800, 600, 800, 600, 0, 0, 8, 0, 208 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 209 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12, 210 FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED 211 } 212 }, 213 /* 214 ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace 215 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL 216 */ 217 { 218 "1024x768i", { /* 1024x768, 8 bpp, interlaced */ 219 1024, 768, 1024, 768, 0, 0, 8, 0, 220 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 221 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8, 222 FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED 223 } 224 }, 225 { 226 "1024x768", { 227 1024, 768, 1024, 768, 0, 0, 8, 0, 228 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 229 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4, 230 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 231 } 232 }, 233 { 234 "640x480-16", { /* 640x480, 16 bpp */ 235 640, 480, 640, 480, 0, 0, 16, 0, 236 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 237 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2, 238 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED 239 } 240 }, 241 { 242 "640x480-24", { /* 640x480, 24 bpp */ 243 640, 480, 640, 480, 0, 0, 24, 0, 244 {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, 245 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2, 246 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED 247 } 248 }, 249}; 250 251 252#define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined) 253 254static struct fb_var_screeninfo retz3fb_default; 255 256static int z3fb_inverse = 0; 257static int z3fb_mode __initdata = 0; 258 259 260/* 261 * Interface used by the world 262 */ 263 264int retz3fb_setup(char *options); 265 266static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, 267 struct fb_info *info); 268static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, 269 struct fb_info *info); 270static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, 271 struct fb_info *info); 272static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 273 struct fb_info *info); 274static int retz3fb_setcolreg(unsigned int regno, unsigned int red, 275 unsigned int green, unsigned int blue, 276 unsigned int transp, struct fb_info *info); 277static int retz3fb_blank(int blank, struct fb_info *info); 278 279 280/* 281 * Interface to the low level console driver 282 */ 283 284int retz3fb_init(void); 285static int z3fb_switch(int con, struct fb_info *info); 286static int z3fb_updatevar(int con, struct fb_info *info); 287 288 289/* 290 * Text console acceleration 291 */ 292 293#ifdef FBCON_HAS_CFB8 294static struct display_switch fbcon_retz3_8; 295#endif 296 297 298/* 299 * Accelerated Functions used by the low level console driver 300 */ 301 302static void retz3_bitblt(struct display *p, 303 unsigned short curx, unsigned short cury, unsigned 304 short destx, unsigned short desty, unsigned short 305 width, unsigned short height, unsigned short cmd, 306 unsigned short mask); 307 308/* 309 * Hardware Specific Routines 310 */ 311 312static int retz3_encode_fix(struct fb_info *info, 313 struct fb_fix_screeninfo *fix, 314 struct retz3fb_par *par); 315static int retz3_decode_var(struct fb_var_screeninfo *var, 316 struct retz3fb_par *par); 317static int retz3_encode_var(struct fb_var_screeninfo *var, 318 struct retz3fb_par *par); 319static int retz3_getcolreg(unsigned int regno, unsigned int *red, 320 unsigned int *green, unsigned int *blue, 321 unsigned int *transp, struct fb_info *info); 322 323/* 324 * Internal routines 325 */ 326 327static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par); 328static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par); 329static int do_fb_set_var(struct fb_info *info, 330 struct fb_var_screeninfo *var, int isactive); 331static void retz3fb_set_disp(int con, struct fb_info *info); 332static int get_video_mode(const char *name); 333 334 335/* -------------------- Hardware specific routines ------------------------- */ 336 337static unsigned short find_fq(unsigned int freq) 338{ 339 unsigned long f; 340 long tmp; 341 long prev = 0x7fffffff; 342 long n2, n1 = 3; 343 unsigned long m; 344 unsigned short res = 0; 345 346 if (freq <= 31250000) 347 n2 = 3; 348 else if (freq <= 62500000) 349 n2 = 2; 350 else if (freq <= 125000000) 351 n2 = 1; 352 else if (freq <= 250000000) 353 n2 = 0; 354 else 355 return 0; 356 357 358 do { 359 f = freq >> (10 - n2); 360 361 m = (f * n1) / (14318180/1024); 362 363 if (m > 129) 364 break; 365 366 tmp = (((m * 14318180) >> n2) / n1) - freq; 367 if (tmp < 0) 368 tmp = -tmp; 369 370 if (tmp < prev) { 371 prev = tmp; 372 res = (((n2 << 5) | (n1-2)) << 8) | (m-2); 373 } 374 375 } while ( (++n1) <= 21); 376 377 return res; 378} 379 380 381static int retz3_set_video(struct fb_info *info, 382 struct fb_var_screeninfo *var, 383 struct retz3fb_par *par) 384{ 385 volatile unsigned char *regs = retz3info(info)->regs; 386 unsigned int freq; 387 388 int xres, hfront, hsync, hback; 389 int yres, vfront, vsync, vback; 390 unsigned char tmp; 391 unsigned short best_freq; 392 struct display_data data; 393 394 short clocksel = 0; /* Apparantly this is always zero */ 395 396 int bpp = var->bits_per_pixel; 397 398 /* 399 * XXX 400 */ 401 if (bpp == 24) 402 return 0; 403 404 if ((bpp != 8) && (bpp != 16) && (bpp != 24)) 405 return -EFAULT; 406 407 par->xoffset = 0; 408 par->yoffset = 0; 409 410 xres = var->xres * bpp / 4; 411 hfront = var->right_margin * bpp / 4; 412 hsync = var->hsync_len * bpp / 4; 413 hback = var->left_margin * bpp / 4; 414 415 if (var->vmode & FB_VMODE_DOUBLE) 416 { 417 yres = var->yres * 2; 418 vfront = var->lower_margin * 2; 419 vsync = var->vsync_len * 2; 420 vback = var->upper_margin * 2; 421 } 422 else if (var->vmode & FB_VMODE_INTERLACED) 423 { 424 yres = (var->yres + 1) / 2; 425 vfront = (var->lower_margin + 1) / 2; 426 vsync = (var->vsync_len + 1) / 2; 427 vback = (var->upper_margin + 1) / 2; 428 } 429 else 430 { 431 yres = var->yres; /* -1 ? */ 432 vfront = var->lower_margin; 433 vsync = var->vsync_len; 434 vback = var->upper_margin; 435 } 436 437 data.h_total = (hback / 8) + (xres / 8) 438 + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; 439 data.h_dispend = ((xres + bpp - 1)/ 8) - 1; 440 data.h_bstart = xres / 8 - 1 /* + 1 */; 441 442 data.h_bstop = data.h_total+1 + 2 + 1; 443 data.h_sstart = (xres / 8) + (hfront / 8) + 1; 444 data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; 445 446 data.v_total = yres + vfront + vsync + vback - 1; 447 448 data.v_dispend = yres - 1; 449 data.v_bstart = yres - 1; 450 451 data.v_bstop = data.v_total; 452 data.v_sstart = yres + vfront - 1 - 2; 453 data.v_sstop = yres + vfront + vsync - 1; 454 455#if 0 /* testing */ 456 457 printk("HBS: %i\n", data.h_bstart); 458 printk("HSS: %i\n", data.h_sstart); 459 printk("HSE: %i\n", data.h_sstop); 460 printk("HBE: %i\n", data.h_bstop); 461 printk("HT: %i\n", data.h_total); 462 463 printk("hsync: %i\n", hsync); 464 printk("hfront: %i\n", hfront); 465 printk("hback: %i\n", hback); 466 467 printk("VBS: %i\n", data.v_bstart); 468 printk("VSS: %i\n", data.v_sstart); 469 printk("VSE: %i\n", data.v_sstop); 470 printk("VBE: %i\n", data.v_bstop); 471 printk("VT: %i\n", data.v_total); 472 473 printk("vsync: %i\n", vsync); 474 printk("vfront: %i\n", vfront); 475 printk("vback: %i\n", vback); 476#endif 477 478 if (data.v_total >= 1024) 479 printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n"); 480 481 reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); 482 reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00); 483 484 seq_w(regs, SEQ_RESET, 0x00); 485 seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */ 486 487 /* 488 * CLOCKING_MODE bits: 489 * 2: This one is only set for certain text-modes, wonder if 490 * it may be for EGA-lines? (it was referred to as CLKDIV2) 491 * (The CL drivers sets it to 0x21 with the comment: 492 * FullBandwidth (video off) and 8/9 dot clock) 493 */ 494 seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); 495 496 seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ 497 seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ 498 seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ 499 seq_w(regs, SEQ_RESET, 0x01); 500 seq_w(regs, SEQ_RESET, 0x03); 501 502 seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05); 503 504 seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ 505 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); 506 seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); 507 seq_w(regs, SEQ_LINEAR_0, 0x4a); 508 seq_w(regs, SEQ_LINEAR_1, 0x00); 509 510 seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00); 511 seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00); 512 seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); 513 514 /* 515 * The lower 4 bits (0-3) are used to set the font-width for 516 * text-mode - DON'T try to set this for gfx-mode. 517 */ 518 seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10); 519 seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03); 520 521 /* 522 * Extended Pixel Control: 523 * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) 524 * bit 1: (Packed/Nibble Pixel Format ?) 525 * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp 526 */ 527 seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); 528 529 seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04); 530 seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01); 531 seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00); 532 seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00); 533 seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); 534 seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40); 535 seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00); 536 seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00); 537 seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00); 538 seq_w(regs, SEQ_CRC_CONTROL, 0x00); 539 seq_w(regs, SEQ_PERF_SELECT, 0x10); 540 seq_w(regs, SEQ_ACM_APERTURE_1, 0x00); 541 seq_w(regs, SEQ_ACM_APERTURE_2, 0x30); 542 seq_w(regs, SEQ_ACM_APERTURE_3, 0x00); 543 seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03); 544 545 546 /* unlock register CRT0..CRT7 */ 547 crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20); 548 549 /* Zuerst zu schreibende Werte nur per printk ausgeben */ 550 DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total); 551 crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff); 552 553 DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend); 554 crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff); 555 556 DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart); 557 crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff); 558 559 DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32); 560 crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f)); 561 562 DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart); 563 crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff); 564 565 tmp = (data.h_sstop & 0x1f); 566 if (data.h_bstop & 0x20) 567 tmp |= 0x80; 568 DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp); 569 crt_w(regs, CRT_END_HOR_RETR, tmp); 570 571 DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff); 572 crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff)); 573 574 tmp = 0x10; /* LineCompare bit #9 */ 575 if (data.v_total & 256) 576 tmp |= 0x01; 577 if (data.v_dispend & 256) 578 tmp |= 0x02; 579 if (data.v_sstart & 256) 580 tmp |= 0x04; 581 if (data.v_bstart & 256) 582 tmp |= 0x08; 583 if (data.v_total & 512) 584 tmp |= 0x20; 585 if (data.v_dispend & 512) 586 tmp |= 0x40; 587 if (data.v_sstart & 512) 588 tmp |= 0x80; 589 DEBUG printk("CRT_OVERFLOW: %d\n", tmp); 590 crt_w(regs, CRT_OVERFLOW, tmp); 591 592 crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */ 593 594 tmp = 0x40; /* LineCompare bit #8 */ 595 if (data.v_bstart & 512) 596 tmp |= 0x20; 597 if (var->vmode & FB_VMODE_DOUBLE) 598 tmp |= 0x80; 599 DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp); 600 crt_w(regs, CRT_MAX_SCAN_LINE, tmp); 601 602 crt_w(regs, CRT_CURSOR_START, 0x00); 603 crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */ 604 605 crt_w(regs, CRT_START_ADDR_HIGH, 0x00); 606 crt_w(regs, CRT_START_ADDR_LOW, 0x00); 607 608 crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00); 609 crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00); 610 611 DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff); 612 crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff)); 613 614#if 1 615 /* 5 refresh cycles per scanline */ 616 DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16); 617 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20)); 618#else 619 DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16); 620 crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32)); 621#endif 622 DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff); 623 crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff)); 624 625 DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff); 626 crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff)); 627 628 DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff); 629 crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff)); 630 631 DEBUG printk("CRT_MODE_CONTROL: 0xe3\n"); 632 crt_w(regs, CRT_MODE_CONTROL, 0xe3); 633 634 DEBUG printk("CRT_LINE_COMPARE: 0xff\n"); 635 crt_w(regs, CRT_LINE_COMPARE, 0xff); 636 637 tmp = (var->xres_virtual / 8) * (bpp / 8); 638 crt_w(regs, CRT_OFFSET, tmp); 639 640 crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */ 641 642 tmp = 0x20; /* Enable extended end bits */ 643 if (data.h_total & 0x100) 644 tmp |= 0x01; 645 if ((data.h_dispend) & 0x100) 646 tmp |= 0x02; 647 if (data.h_bstart & 0x100) 648 tmp |= 0x04; 649 if (data.h_sstart & 0x100) 650 tmp |= 0x08; 651 if (var->vmode & FB_VMODE_INTERLACED) 652 tmp |= 0x10; 653 DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp); 654 crt_w(regs, CRT_EXT_HOR_TIMING1, tmp); 655 656 tmp = 0x00; 657 if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100) 658 tmp |= 0x10; 659 crt_w(regs, CRT_EXT_START_ADDR, tmp); 660 661 tmp = 0x00; 662 if (data.h_total & 0x200) 663 tmp |= 0x01; 664 if ((data.h_dispend) & 0x200) 665 tmp |= 0x02; 666 if (data.h_bstart & 0x200) 667 tmp |= 0x04; 668 if (data.h_sstart & 0x200) 669 tmp |= 0x08; 670 tmp |= ((data.h_bstop & 0xc0) >> 2); 671 tmp |= ((data.h_sstop & 0x60) << 1); 672 crt_w(regs, CRT_EXT_HOR_TIMING2, tmp); 673 DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp); 674 675 tmp = 0x10; /* Line compare bit 10 */ 676 if (data.v_total & 0x400) 677 tmp |= 0x01; 678 if ((data.v_dispend) & 0x400) 679 tmp |= 0x02; 680 if (data.v_bstart & 0x400) 681 tmp |= 0x04; 682 if (data.v_sstart & 0x400) 683 tmp |= 0x08; 684 tmp |= ((data.v_bstop & 0x300) >> 3); 685 if (data.v_sstop & 0x10) 686 tmp |= 0x80; 687 crt_w(regs, CRT_EXT_VER_TIMING, tmp); 688 DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp); 689 690 crt_w(regs, CRT_MONITOR_POWER, 0x00); 691 692 /* 693 * Convert from ps to Hz. 694 */ 695 freq = 2000000000 / var->pixclock; 696 freq = freq * 500; 697 698 best_freq = find_fq(freq); 699 pll_w(regs, 0x02, best_freq); 700 best_freq = find_fq(61000000); 701 pll_w(regs, 0x0a, best_freq); 702 pll_w(regs, 0x0e, 0x22); 703 704 gfx_w(regs, GFX_SET_RESET, 0x00); 705 gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00); 706 gfx_w(regs, GFX_COLOR_COMPARE, 0x00); 707 gfx_w(regs, GFX_DATA_ROTATE, 0x00); 708 gfx_w(regs, GFX_READ_MAP_SELECT, 0x00); 709 gfx_w(regs, GFX_GRAPHICS_MODE, 0x00); 710 gfx_w(regs, GFX_MISC, 0x05); 711 gfx_w(regs, GFX_COLOR_XCARE, 0x0f); 712 gfx_w(regs, GFX_BITMASK, 0xff); 713 714 reg_r(regs, ACT_ADDRESS_RESET); 715 attr_w(regs, ACT_PALETTE0 , 0x00); 716 attr_w(regs, ACT_PALETTE1 , 0x01); 717 attr_w(regs, ACT_PALETTE2 , 0x02); 718 attr_w(regs, ACT_PALETTE3 , 0x03); 719 attr_w(regs, ACT_PALETTE4 , 0x04); 720 attr_w(regs, ACT_PALETTE5 , 0x05); 721 attr_w(regs, ACT_PALETTE6 , 0x06); 722 attr_w(regs, ACT_PALETTE7 , 0x07); 723 attr_w(regs, ACT_PALETTE8 , 0x08); 724 attr_w(regs, ACT_PALETTE9 , 0x09); 725 attr_w(regs, ACT_PALETTE10, 0x0a); 726 attr_w(regs, ACT_PALETTE11, 0x0b); 727 attr_w(regs, ACT_PALETTE12, 0x0c); 728 attr_w(regs, ACT_PALETTE13, 0x0d); 729 attr_w(regs, ACT_PALETTE14, 0x0e); 730 attr_w(regs, ACT_PALETTE15, 0x0f); 731 reg_r(regs, ACT_ADDRESS_RESET); 732 733 attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */ 734 735 attr_w(regs, ACT_OVERSCAN_COLOR, 0x00); 736 attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f); 737 attr_w(regs, ACT_HOR_PEL_PANNING, 0x00); 738 attr_w(regs, ACT_COLOR_SELECT, 0x00); 739 740 reg_r(regs, ACT_ADDRESS_RESET); 741 reg_w(regs, ACT_DATA, 0x20); 742 743 reg_w(regs, VDAC_MASK, 0xff); 744 745 /* 746 * Extended palette addressing ??? 747 */ 748 switch (bpp){ 749 case 8: 750 reg_w(regs, 0x83c6, 0x00); 751 break; 752 case 16: 753 reg_w(regs, 0x83c6, 0x60); 754 break; 755 case 24: 756 reg_w(regs, 0x83c6, 0xe0); 757 break; 758 default: 759 printk(KERN_INFO "Illegal color-depth: %i\n", bpp); 760 } 761 762 reg_w(regs, VDAC_ADDRESS, 0x00); 763 764 seq_w(regs, SEQ_MAP_MASK, 0x0f ); 765 766 return 0; 767} 768 769 770/* 771 * This function should fill in the `fix' structure based on the 772 * values in the `par' structure. 773 */ 774 775static int retz3_encode_fix(struct fb_info *info, 776 struct fb_fix_screeninfo *fix, 777 struct retz3fb_par *par) 778{ 779 struct retz3_fb_info *zinfo = retz3info(info); 780 781 memset(fix, 0, sizeof(struct fb_fix_screeninfo)); 782 strcpy(fix->id, retz3fb_name); 783 fix->smem_start = zinfo->physfbmem; 784 fix->smem_len = zinfo->fbsize; 785 fix->mmio_start = zinfo->physregs; 786 fix->mmio_len = 0x00c00000; 787 788 fix->type = FB_TYPE_PACKED_PIXELS; 789 fix->type_aux = 0; 790 if (par->bpp == 8) 791 fix->visual = FB_VISUAL_PSEUDOCOLOR; 792 else 793 fix->visual = FB_VISUAL_TRUECOLOR; 794 795 fix->xpanstep = 0; 796 fix->ypanstep = 0; 797 fix->ywrapstep = 0; 798 fix->line_length = 0; 799 800 fix->accel = FB_ACCEL_NCR_77C32BLT; 801 802 return 0; 803} 804 805 806/* 807 * Get the video params out of `var'. If a value doesn't fit, round 808 * it up, if it's too big, return -EINVAL. 809 */ 810 811static int retz3_decode_var(struct fb_var_screeninfo *var, 812 struct retz3fb_par *par) 813{ 814 par->xres = var->xres; 815 par->yres = var->yres; 816 par->xres_vir = var->xres_virtual; 817 par->yres_vir = var->yres_virtual; 818 par->bpp = var->bits_per_pixel; 819 par->pixclock = var->pixclock; 820 par->vmode = var->vmode; 821 822 par->red = var->red; 823 par->green = var->green; 824 par->blue = var->blue; 825 par->transp = var->transp; 826 827 par->left_margin = var->left_margin; 828 par->right_margin = var->right_margin; 829 par->upper_margin = var->upper_margin; 830 par->lower_margin = var->lower_margin; 831 par->hsync_len = var->hsync_len; 832 par->vsync_len = var->vsync_len; 833 834 if (var->accel_flags & FB_ACCELF_TEXT) 835 par->accel = FB_ACCELF_TEXT; 836 else 837 par->accel = 0; 838 839 return 0; 840} 841 842 843/* 844 * Fill the `var' structure based on the values in `par' and maybe 845 * other values read out of the hardware. 846 */ 847 848static int retz3_encode_var(struct fb_var_screeninfo *var, 849 struct retz3fb_par *par) 850{ 851 memset(var, 0, sizeof(struct fb_var_screeninfo)); 852 var->xres = par->xres; 853 var->yres = par->yres; 854 var->xres_virtual = par->xres_vir; 855 var->yres_virtual = par->yres_vir; 856 var->xoffset = 0; 857 var->yoffset = 0; 858 859 var->bits_per_pixel = par->bpp; 860 var->grayscale = 0; 861 862 var->red = par->red; 863 var->green = par->green; 864 var->blue = par->blue; 865 var->transp = par->transp; 866 867 var->nonstd = 0; 868 var->activate = 0; 869 870 var->height = -1; 871 var->width = -1; 872 873 var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0; 874 875 var->pixclock = par->pixclock; 876 877 var->sync = 0; /* ??? */ 878 var->left_margin = par->left_margin; 879 var->right_margin = par->right_margin; 880 var->upper_margin = par->upper_margin; 881 var->lower_margin = par->lower_margin; 882 var->hsync_len = par->hsync_len; 883 var->vsync_len = par->vsync_len; 884 885 var->vmode = par->vmode; 886 return 0; 887} 888 889 890/* 891 * Set a single color register. Return != 0 for invalid regno. 892 */ 893 894static int retz3fb_setcolreg(unsigned int regno, unsigned int red, 895 unsigned int green, unsigned int blue, 896 unsigned int transp, struct fb_info *info) 897{ 898 struct retz3_fb_info *zinfo = retz3info(info); 899 volatile unsigned char *regs = zinfo->regs; 900 901 /* We'll get to this */ 902 903 if (regno > 255) 904 return 1; 905 906 red >>= 10; 907 green >>= 10; 908 blue >>= 10; 909 910 zinfo->color_table[regno][0] = red; 911 zinfo->color_table[regno][1] = green; 912 zinfo->color_table[regno][2] = blue; 913 914 reg_w(regs, VDAC_ADDRESS_W, regno); 915 reg_w(regs, VDAC_DATA, red); 916 reg_w(regs, VDAC_DATA, green); 917 reg_w(regs, VDAC_DATA, blue); 918 919 return 0; 920} 921 922 923/* 924 * Read a single color register and split it into 925 * colors/transparent. Return != 0 for invalid regno. 926 */ 927 928static int retz3_getcolreg(unsigned int regno, unsigned int *red, 929 unsigned int *green, unsigned int *blue, 930 unsigned int *transp, struct fb_info *info) 931{ 932 struct retz3_fb_info *zinfo = retz3info(info); 933 int t; 934 935 if (regno > 255) 936 return 1; 937 t = zinfo->color_table[regno][0]; 938 *red = (t<<10) | (t<<4) | (t>>2); 939 t = zinfo->color_table[regno][1]; 940 *green = (t<<10) | (t<<4) | (t>>2); 941 t = zinfo->color_table[regno][2]; 942 *blue = (t<<10) | (t<<4) | (t>>2); 943 *transp = 0; 944 return 0; 945} 946 947 948static inline void retz3_busy(struct display *p) 949{ 950 struct retz3_fb_info *zinfo = retz3info(p->fb_info); 951 volatile unsigned char *acm = zinfo->base + ACM_OFFSET; 952 unsigned char blt_status; 953 954 if (zinfo->blitbusy) { 955 do{ 956 blt_status = *((acm) + (ACM_START_STATUS + 2)); 957 }while ((blt_status & 1) == 0); 958 zinfo->blitbusy = 0; 959 } 960} 961 962 963static void retz3_bitblt (struct display *p, 964 unsigned short srcx, unsigned short srcy, 965 unsigned short destx, unsigned short desty, 966 unsigned short width, unsigned short height, 967 unsigned short cmd, unsigned short mask) 968{ 969 struct fb_var_screeninfo *var = &p->var; 970 struct retz3_fb_info *zinfo = retz3info(p->fb_info); 971 volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET); 972 unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF); 973 974 unsigned short mod; 975 unsigned long tmp; 976 unsigned long pat, src, dst; 977 978 int i, xres_virtual = var->xres_virtual; 979 short bpp = (var->bits_per_pixel & 0xff); 980 981 if (bpp < 8) 982 bpp = 8; 983 984 tmp = mask | (mask << 16); 985 986 retz3_busy(p); 987 988 i = 0; 989 do{ 990 *pattern++ = tmp; 991 }while(i++ < bpp/4); 992 993 tmp = cmd << 8; 994 *(acm + ACM_RASTEROP_ROTATION/4) = tmp; 995 996 mod = 0xc0c2; 997 998 pat = 8 * PAT_MEM_OFF; 999 dst = bpp * (destx + desty * xres_virtual); 1000 1001 /* 1002 * Source is not set for clear. 1003 */ 1004 if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) { 1005 src = bpp * (srcx + srcy * xres_virtual); 1006 1007 if (destx > srcx) { 1008 mod &= ~0x8000; 1009 src += bpp * (width - 1); 1010 dst += bpp * (width - 1); 1011 pat += bpp * 2; 1012 } 1013 if (desty > srcy) { 1014 mod &= ~0x4000; 1015 src += bpp * (height - 1) * xres_virtual; 1016 dst += bpp * (height - 1) * xres_virtual; 1017 pat += bpp * 4; 1018 } 1019 1020 *(acm + ACM_SOURCE/4) = cpu_to_le32(src); 1021 } 1022 1023 *(acm + ACM_PATTERN/4) = cpu_to_le32(pat); 1024 1025 *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst); 1026 1027 tmp = mod << 16; 1028 *(acm + ACM_CONTROL/4) = tmp; 1029 1030 tmp = width | (height << 16); 1031 1032 *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp); 1033 1034 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00; 1035 *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01; 1036 zinfo->blitbusy = 1; 1037} 1038 1039#if 0 1040/* 1041 * Move cursor to x, y 1042 */ 1043static void retz3_MoveCursor (unsigned short x, unsigned short y) 1044{ 1045 /* Guess we gotta deal with the cursor at some point */ 1046} 1047#endif 1048 1049 1050/* 1051 * Fill the hardware's `par' structure. 1052 */ 1053 1054static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par) 1055{ 1056 struct retz3_fb_info *zinfo = retz3info(info); 1057 1058 if (zinfo->current_par_valid) 1059 *par = zinfo->current_par; 1060 else 1061 retz3_decode_var(&retz3fb_default, par); 1062} 1063 1064 1065static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par) 1066{ 1067 struct retz3_fb_info *zinfo = retz3info(info); 1068 1069 zinfo->current_par = *par; 1070 zinfo->current_par_valid = 1; 1071} 1072 1073 1074static int do_fb_set_var(struct fb_info *info, 1075 struct fb_var_screeninfo *var, int isactive) 1076{ 1077 int err, activate; 1078 struct retz3fb_par par; 1079 struct retz3_fb_info *zinfo = retz3info(info); 1080 1081 if ((err = retz3_decode_var(var, &par))) 1082 return err; 1083 activate = var->activate; 1084 1085 /* XXX ... what to do about isactive ? */ 1086 1087 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive) 1088 retz3fb_set_par(info, &par); 1089 retz3_encode_var(var, &par); 1090 var->activate = activate; 1091 1092 retz3_set_video(info, var, &zinfo->current_par); 1093 1094 return 0; 1095} 1096 1097/* 1098 * Get the Fixed Part of the Display 1099 */ 1100 1101static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, 1102 struct fb_info *info) 1103{ 1104 struct retz3fb_par par; 1105 int error = 0; 1106 1107 if (con == -1) 1108 retz3fb_get_par(info, &par); 1109 else 1110 error = retz3_decode_var(&fb_display[con].var, &par); 1111 return(error ? error : retz3_encode_fix(info, fix, &par)); 1112} 1113 1114 1115/* 1116 * Get the User Defined Part of the Display 1117 */ 1118 1119static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, 1120 struct fb_info *info) 1121{ 1122 struct retz3fb_par par; 1123 int error = 0; 1124 1125 if (con == -1) { 1126 retz3fb_get_par(info, &par); 1127 error = retz3_encode_var(var, &par); 1128 } else 1129 *var = fb_display[con].var; 1130 return error; 1131} 1132 1133 1134static void retz3fb_set_disp(int con, struct fb_info *info) 1135{ 1136 struct fb_fix_screeninfo fix; 1137 struct display *display; 1138 struct retz3_fb_info *zinfo = retz3info(info); 1139 1140 if (con >= 0) 1141 display = &fb_display[con]; 1142 else 1143 display = &zinfo->disp; /* used during initialization */ 1144 1145 retz3fb_get_fix(&fix, con, info); 1146 1147 if (con == -1) 1148 con = 0; 1149 1150 display->visual = fix.visual; 1151 display->type = fix.type; 1152 display->type_aux = fix.type_aux; 1153 display->ypanstep = fix.ypanstep; 1154 display->ywrapstep = fix.ywrapstep; 1155 display->can_soft_blank = 1; 1156 display->inverse = z3fb_inverse; 1157 1158 /* 1159 * This seems to be about 20% faster. 1160 */ 1161 display->scrollmode = SCROLL_YREDRAW; 1162 1163 switch (display->var.bits_per_pixel) { 1164#ifdef FBCON_HAS_CFB8 1165 case 8: 1166 if (display->var.accel_flags & FB_ACCELF_TEXT) { 1167 display->dispsw = &fbcon_retz3_8; 1168 retz3_set_video(info, &display->var, &zinfo->current_par); 1169 } else 1170 display->dispsw = &fbcon_cfb8; 1171 break; 1172#endif 1173#ifdef FBCON_HAS_CFB16 1174 case 16: 1175 display->dispsw = &fbcon_cfb16; 1176 break; 1177#endif 1178 default: 1179 display->dispsw = &fbcon_dummy; 1180 break; 1181 } 1182} 1183 1184 1185/* 1186 * Set the User Defined Part of the Display 1187 */ 1188 1189static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, 1190 struct fb_info *info) 1191{ 1192 int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel; 1193 struct display *display; 1194 struct retz3_fb_info *zinfo = retz3info(info); 1195 1196 if (con >= 0) 1197 display = &fb_display[con]; 1198 else 1199 display = &zinfo->disp; /* used during initialization */ 1200 1201 if ((err = do_fb_set_var(info, var, con == info->currcon))) 1202 return err; 1203 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 1204 oldxres = display->var.xres; 1205 oldyres = display->var.yres; 1206 oldvxres = display->var.xres_virtual; 1207 oldvyres = display->var.yres_virtual; 1208 oldbpp = display->var.bits_per_pixel; 1209 oldaccel = display->var.accel_flags; 1210 display->var = *var; 1211 1212 if (oldxres != var->xres || oldyres != var->yres || 1213 oldvxres != var->xres_virtual || 1214 oldvyres != var->yres_virtual || 1215 oldbpp != var->bits_per_pixel || 1216 oldaccel != var->accel_flags) { 1217 1218 struct fb_fix_screeninfo fix; 1219 retz3fb_get_fix(&fix, con, info); 1220 1221 display->visual = fix.visual; 1222 display->type = fix.type; 1223 display->type_aux = fix.type_aux; 1224 display->ypanstep = fix.ypanstep; 1225 display->ywrapstep = fix.ywrapstep; 1226 display->line_length = fix.line_length; 1227 display->can_soft_blank = 1; 1228 display->inverse = z3fb_inverse; 1229 switch (display->var.bits_per_pixel) { 1230#ifdef FBCON_HAS_CFB8 1231 case 8: 1232 if (var->accel_flags & FB_ACCELF_TEXT) { 1233 display->dispsw = &fbcon_retz3_8; 1234 } else 1235 display->dispsw = &fbcon_cfb8; 1236 break; 1237#endif 1238#ifdef FBCON_HAS_CFB16 1239 case 16: 1240 display->dispsw = &fbcon_cfb16; 1241 break; 1242#endif 1243 default: 1244 display->dispsw = &fbcon_dummy; 1245 break; 1246 } 1247 /* 1248 * We still need to find a way to tell the X 1249 * server that the video mem has been fiddled with 1250 * so it redraws the entire screen when switching 1251 * between X and a text console. 1252 */ 1253 retz3_set_video(info, var, &zinfo->current_par); 1254 1255 if (info->changevar) 1256 (*info->changevar)(con); 1257 } 1258 1259 if (oldbpp != var->bits_per_pixel) { 1260 if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) 1261 return err; 1262 do_install_cmap(con, info); 1263 } 1264 } 1265 return 0; 1266} 1267 1268 1269/* 1270 * Get the Colormap 1271 */ 1272 1273static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 1274 struct fb_info *info) 1275{ 1276 if (con == info->currcon) /* current console? */ 1277 return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info)); 1278 else if (fb_display[con].cmap.len) /* non default colormap? */ 1279 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); 1280 else 1281 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1282 cmap, kspc ? 0 : 2); 1283 return 0; 1284} 1285 1286/* 1287 * Blank the display. 1288 */ 1289 1290static int retz3fb_blank(int blank, struct fb_info *info) 1291{ 1292 struct retz3_fb_info *zinfo = retz3info(info); 1293 volatile unsigned char *regs = retz3info(info)->regs; 1294 short i; 1295 1296 if (blank) 1297 for (i = 0; i < 256; i++){ 1298 reg_w(regs, VDAC_ADDRESS_W, i); 1299 reg_w(regs, VDAC_DATA, 0); 1300 reg_w(regs, VDAC_DATA, 0); 1301 reg_w(regs, VDAC_DATA, 0); 1302 } 1303 else 1304 for (i = 0; i < 256; i++){ 1305 reg_w(regs, VDAC_ADDRESS_W, i); 1306 reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]); 1307 reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]); 1308 reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]); 1309 } 1310 return 0; 1311} 1312 1313static struct fb_ops retz3fb_ops = { 1314 .owner = THIS_MODULE, 1315 .fb_get_fix = retz3fb_get_fix, 1316 .fb_get_var = retz3fb_get_var, 1317 .fb_set_var = retz3fb_set_var, 1318 .fb_get_cmap = retz3fb_get_cmap, 1319 .fb_set_cmap = gen_set_cmap, 1320 .fb_setcolreg = retz3fb_setcolreg, 1321 .fb_blank = retz3fb_blank, 1322}; 1323 1324int __init retz3fb_setup(char *options) 1325{ 1326 char *this_opt; 1327 1328 if (!options || !*options) 1329 return 0; 1330 1331 while ((this_opt = strsep(&options, ",")) != NULL) { 1332 if (!*this_opt) 1333 continue; 1334 if (!strcmp(this_opt, "inverse")) { 1335 z3fb_inverse = 1; 1336 fb_invert_cmaps(); 1337 } else if (!strncmp(this_opt, "font:", 5)) { 1338 strlcpy(fontname, this_opt+5, sizeof(fontname)); 1339 } else 1340 z3fb_mode = get_video_mode(this_opt); 1341 } 1342 return 0; 1343} 1344 1345 1346/* 1347 * Initialization 1348 */ 1349 1350int __init retz3fb_init(void) 1351{ 1352 unsigned long board_addr, board_size; 1353 struct zorro_dev *z = NULL; 1354 volatile unsigned char *regs; 1355 struct retz3fb_par par; 1356 struct retz3_fb_info *zinfo; 1357 struct fb_info *fb_info; 1358 short i; 1359 int res = -ENXIO; 1360 1361 while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) { 1362 board_addr = z->resource.start; 1363 board_size = z->resource.end-z->resource.start+1; 1364 if (!request_mem_region(board_addr, 0x0c00000, 1365 "ncr77c32blt")) { 1366 continue; 1367 if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET, 1368 0x00400000, "RAM")) 1369 release_mem_region(board_addr, 0x00c00000); 1370 continue; 1371 } 1372 if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info), 1373 GFP_KERNEL))) 1374 return -ENOMEM; 1375 memset(zinfo, 0, sizeof(struct retz3_fb_info)); 1376 1377 zinfo->base = ioremap(board_addr, board_size); 1378 zinfo->regs = zinfo->base; 1379 zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET; 1380 /* Get memory size - for now we asume it's a 4MB board */ 1381 zinfo->fbsize = 0x00400000; /* 4 MB */ 1382 zinfo->physregs = board_addr; 1383 zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET; 1384 1385 fb_info = fbinfo(zinfo); 1386 1387 for (i = 0; i < 256; i++){ 1388 for (i = 0; i < 256; i++){ 1389 zinfo->color_table[i][0] = i; 1390 zinfo->color_table[i][1] = i; 1391 zinfo->color_table[i][2] = i; 1392 } 1393 } 1394 1395 regs = zinfo->regs; 1396 /* Disable hardware cursor */ 1397 seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00); 1398 1399 retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info); 1400 retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info); 1401 1402 strcpy(fb_info->modename, retz3fb_name); 1403 fb_info->changevar = NULL; 1404 fb_info->fbops = &retz3fb_ops; 1405 fb_info->screen_base = zinfo->fbmem; 1406 fb_info->disp = &zinfo->disp; 1407 fb_info->currcon = -1; 1408 fb_info->switch_con = &z3fb_switch; 1409 fb_info->updatevar = &z3fb_updatevar; 1410 fb_info->flags = FBINFO_FLAG_DEFAULT; 1411 strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname)); 1412 1413 if (z3fb_mode == -1) 1414 retz3fb_default = retz3fb_predefined[0].var; 1415 1416 retz3_decode_var(&retz3fb_default, &par); 1417 retz3_encode_var(&retz3fb_default, &par); 1418 1419 do_fb_set_var(fb_info, &retz3fb_default, 0); 1420 retz3fb_get_var(&zinfo->disp.var, -1, fb_info); 1421 1422 retz3fb_set_disp(-1, fb_info); 1423 1424 do_install_cmap(0, fb_info); 1425 1426 if (register_framebuffer(fb_info) < 0) 1427 return -EINVAL; 1428 1429 printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of " 1430 "video memory\n", fb_info->node, 1431 fb_info->modename, zinfo->fbsize>>10); 1432 1433 /* FIXME: This driver cannot be unloaded yet */ 1434 res = 0; 1435 } 1436 return res; 1437} 1438 1439 1440static int z3fb_switch(int con, struct fb_info *info) 1441{ 1442 /* Do we have to save the colormap? */ 1443 if (fb_display[info->currcon].cmap.len) 1444 fb_get_cmap(&fb_display[info->currcon].cmap, 1, 1445 retz3_getcolreg, info); 1446 1447 do_fb_set_var(info, &fb_display[con].var, 1); 1448 info->currcon = con; 1449 /* Install new colormap */ 1450 do_install_cmap(con, info); 1451 return 0; 1452} 1453 1454 1455/* 1456 * Update the `var' structure (called by fbcon.c) 1457 * 1458 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. 1459 * Since it's called by a kernel driver, no range checking is done. 1460 */ 1461 1462static int z3fb_updatevar(int con, struct fb_info *info) 1463{ 1464 return 0; 1465} 1466 1467/* 1468 * Get a Video Mode 1469 */ 1470 1471static int __init get_video_mode(const char *name) 1472{ 1473 short i; 1474 1475 for (i = 0; i < NUM_TOTAL_MODES; i++) 1476 if (!strcmp(name, retz3fb_predefined[i].name)){ 1477 retz3fb_default = retz3fb_predefined[i].var; 1478 return i; 1479 } 1480 return -1; 1481} 1482 1483 1484#ifdef MODULE 1485MODULE_LICENSE("GPL"); 1486 1487int init_module(void) 1488{ 1489 return retz3fb_init(); 1490} 1491#endif 1492 1493 1494/* 1495 * Text console acceleration 1496 */ 1497 1498#ifdef FBCON_HAS_CFB8 1499static void retz3_8_bmove(struct display *p, int sy, int sx, 1500 int dy, int dx, int height, int width) 1501{ 1502 int fontwidth = fontwidth(p); 1503 1504 sx *= fontwidth; 1505 dx *= fontwidth; 1506 width *= fontwidth; 1507 1508 retz3_bitblt(p, 1509 (unsigned short)sx, 1510 (unsigned short)(sy*fontheight(p)), 1511 (unsigned short)dx, 1512 (unsigned short)(dy*fontheight(p)), 1513 (unsigned short)width, 1514 (unsigned short)(height*fontheight(p)), 1515 Z3BLTcopy, 1516 0xffff); 1517} 1518 1519static void retz3_8_clear(struct vc_data *conp, struct display *p, 1520 int sy, int sx, int height, int width) 1521{ 1522 unsigned short col; 1523 int fontwidth = fontwidth(p); 1524 1525 sx *= fontwidth; 1526 width *= fontwidth; 1527 1528 col = attr_bgcol_ec(p, conp); 1529 col &= 0xff; 1530 col |= (col << 8); 1531 1532 retz3_bitblt(p, 1533 (unsigned short)sx, 1534 (unsigned short)(sy*fontheight(p)), 1535 (unsigned short)sx, 1536 (unsigned short)(sy*fontheight(p)), 1537 (unsigned short)width, 1538 (unsigned short)(height*fontheight(p)), 1539 Z3BLTset, 1540 col); 1541} 1542 1543 1544static void retz3_putc(struct vc_data *conp, struct display *p, int c, 1545 int yy, int xx) 1546{ 1547 retz3_busy(p); 1548 fbcon_cfb8_putc(conp, p, c, yy, xx); 1549} 1550 1551 1552static void retz3_putcs(struct vc_data *conp, struct display *p, 1553 const unsigned short *s, int count, 1554 int yy, int xx) 1555{ 1556 retz3_busy(p); 1557 fbcon_cfb8_putcs(conp, p, s, count, yy, xx); 1558} 1559 1560 1561static void retz3_revc(struct display *p, int xx, int yy) 1562{ 1563 retz3_busy(p); 1564 fbcon_cfb8_revc(p, xx, yy); 1565} 1566 1567 1568static void retz3_clear_margins(struct vc_data* conp, struct display* p, 1569 int bottom_only) 1570{ 1571 retz3_busy(p); 1572 fbcon_cfb8_clear_margins(conp, p, bottom_only); 1573} 1574 1575 1576static struct display_switch fbcon_retz3_8 = { 1577 .setup = fbcon_cfb8_setup, 1578 .bmove = retz3_8_bmove, 1579 .clear = retz3_8_clear, 1580 .putc = retz3_putc, 1581 .putcs = retz3_putcs, 1582 .revc = retz3_revc, 1583 .clear_margins = retz3_clear_margins, 1584 .fontwidthmask = FONTWIDTH(8) 1585}; 1586#endif