1 /* $NetBSD: grf_cv.c,v 1.4 1995/11/30 00:56:57 jtc Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Michael Teske 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Ezra Story, by Kari 18 * Mettinen and by Bernd Ernesti. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include "grfcv.h" 34 #if NGRFCV > 0 35 36 #undef CV64CONSOLE /* DO NOT REMOVE THIS till ite5 is ready */ 37 38 /* 39 * Graphics routines for the CyberVision 64 board, using the S3 Trio64. 40 * 41 * Modified for CV64 from 42 * Kari Mettinen's Cirrus driver by Michael Teske 10/95 43 * For questions mail me at teske@dice2.desy.de 44 * 45 * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation. 46 * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy 47 * source to NetBSD style :) 48 * 49 * TODO: 50 * Hardware Cursor support 51 * Blitter support 52 * 53 * BUGS: 54 * Xamiag24 and grf_cv can crash when you use fvwm with xterm's, you can 55 * avoid this by starting the xterm with '-ah', see the manpage of xterm 56 * for more informations about this switch. 57 * There is a bug in the Trio64 which produce a small (1 or 2 pixel) white 58 * vertical bar on the right side of an 8bit-Screen (only when you use more 59 * then 80MHz pixelclock). This has to be fixed in the Xserver. 60 * 61 */ 62 63 #include <sys/param.h> 64 #include <sys/errno.h> 65 #include <sys/ioctl.h> 66 #include <sys/device.h> 67 #include <sys/malloc.h> 68 #include <sys/systm.h> 69 #include <machine/cpu.h> 70 #include <dev/cons.h> 71 #include <amiga/amiga/device.h> 72 #include <amiga/dev/grfioctl.h> 73 #include <amiga/dev/grfvar.h> 74 #include <amiga/dev/grf_cvreg.h> 75 #include <amiga/dev/zbusvar.h> 76 77 int grfcvmatch __P((struct device *, struct cfdata *, void *)); 78 void grfcvattach __P((struct device *, struct device *, void *)); 79 int grfcvprint __P((void *, char *)); 80 81 static int cv_has_4mb __P((volatile char *)); 82 static unsigned short compute_clock __P((unsigned long)); 83 void cv_boardinit __P((struct grf_softc *)); 84 int cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *)); 85 int cv_setvmode __P((struct grf_softc *, unsigned int)); 86 int cv_blank __P((struct grf_softc *, int *)); 87 int cv_mode __P((register struct grf_softc *, int, void *, int, int)); 88 int cv_ioctl __P((register struct grf_softc *gp, int cmd, void *data)); 89 int cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *)); 90 int cv_getcmap __P((struct grf_softc *, struct grf_colormap *)); 91 int cv_putcmap __P((struct grf_softc *, struct grf_colormap *)); 92 int cv_toggle __P((struct grf_softc *)); 93 int cv_mondefok __P((struct grfvideo_mode *)); 94 int cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *)); 95 void cv_inittextmode __P((struct grf_softc *)); 96 void cv_memset __P((unsigned char *, unsigned char, int)); 97 98 #ifdef CV64CONSOLE 99 extern void grfcv_iteinit __P((struct grf_softc *)); 100 #endif 101 102 /* Graphics display definitions. 103 * These are filled by 'grfconfig' using GRFIOCSETMON. 104 */ 105 #define monitor_def_max 8 106 static struct grfvideo_mode monitor_def[8] = { 107 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0} 108 }; 109 static struct grfvideo_mode *monitor_current = &monitor_def[0]; 110 #define MAXPIXELCLOCK 135000000 /* safety */ 111 112 113 /* Console display definition. 114 * Default hardcoded text mode. This grf_cv is set up to 115 * use one text mode only, and this is it. You may use 116 * grfconfig to change the mode after boot. 117 */ 118 119 /* Console font */ 120 #define S3FONT kernel_font_8x8 121 #define S3FONTX 8 122 #define S3FONTY 8 123 extern unsigned char S3FONT[]; 124 125 struct grfcvtext_mode cvconsole_mode = { 126 {255, "", 25000000, 640, 400, 4, 640, 656, 672, 720, 760, 406, 127 441, 412, 426, 447}, 128 S3FONTX, S3FONTY, 80, 506/S3FONTY, S3FONT, 32, 255 129 }; 130 131 /* Console colors */ 132 unsigned char cvconscolors[3][3] = { /* background, foreground, hilite */ 133 {0,0x40,0x50}, {152,152,152}, {255,255,255} 134 }; 135 136 137 /* Board Address of CV64 */ 138 139 static volatile caddr_t cv_boardaddr; 140 static int cv_fbsize; 141 142 int 143 grfcv_cnprobe() 144 { 145 int rv; 146 rv = CN_DEAD; 147 return (rv); 148 } 149 150 /* standard driver stuff */ 151 struct cfdriver grfcvcd = { 152 NULL, "grfcv", (cfmatch_t)grfcvmatch, grfcvattach, 153 DV_DULL, sizeof(struct grf_softc), NULL, 0 154 }; 155 static struct cfdata *cfdata; 156 157 158 /* Reads from the fb must be done at addr + 0x02000000 */ 159 #define READ_OFFSET 0x02000000 160 161 /* 162 * Get frambuffer memory size. 163 * phase5 didn't provide the bit in CR36, 164 * so we have to do it this way. 165 * Return 0 for 2MB, 1 for 4MB 166 */ 167 168 static int 169 cv_has_4mb (volatile char *fb) 170 { 171 volatile unsigned long *testfbw, *testfbr; 172 173 /* write patterns in memory and test if they can be read */ 174 testfbw = (volatile unsigned long *) fb; 175 *testfbw = 0x87654321; 176 testfbr = (volatile unsigned long *)(fb + READ_OFFSET); 177 if (*testfbr != 0x87654321) 178 return (0); 179 /* upper memory region */ 180 testfbw = (volatile unsigned long *)(fb + 0x00200000); 181 testfbr = (volatile unsigned long *)(fb + 0x00200000 + READ_OFFSET); 182 *testfbw = 0x87654321; 183 if (*testfbr != 0x87654321) 184 return (0); 185 *testfbw = 0xAAAAAAAA; 186 if (*testfbr != 0xAAAAAAAA) 187 return (0); 188 *testfbw = 0x55555555; 189 if (*testfbr != 0x55555555) 190 return (0); 191 return (1); 192 } 193 194 int 195 grfcvmatch(pdp, cfp, auxp) 196 struct device *pdp; 197 struct cfdata *cfp; 198 void *auxp; 199 { 200 struct zbus_args *zap; 201 202 zap = auxp; 203 204 #ifndef CV64CONSOLE 205 if (amiga_realconfig == 0) 206 return (0); 207 #endif 208 209 /* Lets be Paranoid: Test man and prod id */ 210 if (zap->manid != 8512 || zap->prodid != 34) 211 return (0); 212 213 cv_boardaddr = zap->va; 214 215 #ifdef CV64CONSOLE 216 if (amiga_realconfig == 0) { 217 cfdata = cfp; 218 } 219 #endif 220 221 return (1); 222 } 223 224 void 225 grfcvattach(pdp, dp, auxp) 226 struct device *pdp, *dp; 227 void *auxp; 228 { 229 struct zbus_args *zap; 230 struct grf_softc *gp; 231 232 zap = auxp; 233 234 printf("\n"); 235 236 gp = (struct grf_softc *)dp; 237 238 gp->g_regkva = (volatile caddr_t)cv_boardaddr + READ_OFFSET; 239 gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000; 240 241 gp->g_unit = GRF_CV64_UNIT; 242 gp->g_mode = cv_mode; 243 gp->g_conpri = grfcv_cnprobe(); 244 gp->g_flags = GF_ALIVE; 245 246 /* wakeup the board */ 247 cv_boardinit(gp); 248 249 #ifdef CV64CONSOLE 250 grfcv_iteinit(gp); 251 (void)cv_load_mon(gp, &cvconsole_mode); 252 #endif 253 254 /* 255 * attach grf 256 */ 257 if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) 258 printf("grfcv: CyberVision64 with %dMB being used\n", cv_fbsize/0x100000); 259 } 260 261 int 262 grfcvprint(auxp, pnp) 263 void *auxp; 264 char *pnp; 265 { 266 if (pnp) 267 printf("ite at %s: ", pnp); 268 return (UNCONF); 269 } 270 271 272 /* 273 * Computes M, N, and R values from 274 * given input frequency. It uses a table of 275 * precomputed values, to keep CPU time low. 276 * 277 * The return value consist of: 278 * lower byte: Bits 4-0: N Divider Value 279 * Bits 5-6: R Value for e.g. SR10 or SR12 280 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13 281 */ 282 283 static unsigned short 284 compute_clock(freq) 285 unsigned long freq; 286 { 287 288 static unsigned char *mnr, *save; /* M, N + R vals */ 289 unsigned long work_freq, r; 290 unsigned short erg; 291 long diff, d2; 292 293 /* 0xBEBC20 = 12.5M */ 294 /* 0x080BEFC0 = 135M */ 295 if (freq < 0x00BEBC20 || freq > 0x080BEFC0) { 296 printf("grfcv: Wrong clock frequency: %dMHz", freq/1000000); 297 printf("grfcv: Using default frequency: 25MHz"); 298 freq = 0x017D7840; 299 } 300 301 mnr = clocks; /* there the vals are stored */ 302 d2 = 0x7fffffff; 303 304 while (*mnr) { /* mnr vals are 0-terminated */ 305 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2); 306 307 r = (mnr[1] >> 5) & 0x03; 308 if (r != 0) 309 work_freq=work_freq >> r; /* r is the freq divider */ 310 311 work_freq *= 0x3E8; /* 2nd part of OSC */ 312 313 diff = abs(freq - work_freq); 314 315 if (d2 >= diff) { 316 d2 = diff; 317 /* In save are the vals for minimal diff */ 318 save = mnr; 319 } 320 mnr += 2; 321 } 322 erg = *((unsigned short *)save); 323 324 return (erg); 325 } 326 327 328 void 329 cv_boardinit(gp) 330 struct grf_softc *gp; 331 { 332 volatile caddr_t ba = gp->g_regkva; 333 unsigned char test; 334 unsigned int clockpar; 335 int i; 336 struct grfinfo *gi; 337 338 /* Reset board */ 339 for (i = 0; i < 6; i++) 340 cv_write_port (0xff, ba - READ_OFFSET); /* Clear all bits */ 341 342 /* Return to operational Mode */ 343 cv_write_port(0x8004, ba - READ_OFFSET); 344 345 /* Wakeup Chip */ 346 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10); 347 vgaw(ba, SREG_OPTION_SELECT, 0x1); 348 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x8); 349 350 vgaw(ba, GREG_MISC_OUTPUT_W, 0x23); 351 352 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */ 353 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */ 354 355 test = RCrt(ba, CRT_ID_SYSTEM_CONFIG); 356 test = test | 0x01; /* enable enhaced register access */ 357 test = test & 0xEF; /* clear bit 4, 0 wait state */ 358 WCrt(ba, CRT_ID_SYSTEM_CONFIG, test); 359 360 /* 361 * bit 1=1: enable enhanced mode functions 362 * bit 4=1: enable linear adressing 363 */ 364 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x11); 365 366 /* enable cpu acess, color mode, high 64k page */ 367 vgaw(ba, GREG_MISC_OUTPUT_W, 0x23); 368 369 /* Cpu base addr */ 370 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x0); 371 372 /* Reset. This does nothing, but everyone does it:) */ 373 WSeq(ba, SEQ_ID_RESET, 0x3); 374 375 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x1); /* 8 Dot Clock */ 376 WSeq(ba, SEQ_ID_MAP_MASK, 0xF); /* Enable write planes */ 377 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x0); /* Character Font */ 378 379 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x2); /* Complete mem access */ 380 381 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x6); /* Unlock extensions */ 382 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */ 383 384 /* enable 4MB fast Page Mode */ 385 test = test | 1 << 6; 386 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test); 387 /* faster LUT write */ 388 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0x40); 389 390 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */ 391 392 /* immediately Clkload bit clear */ 393 test = test & 0xDF; 394 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test); 395 396 clockpar = compute_clock(0x3473BC0); 397 test = (clockpar & 0xFF00) >> 8; 398 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */ 399 400 test = clockpar & 0xFF; 401 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */ 402 403 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */ 404 /* DCLK */ 405 WSeq(ba, SEQ_ID_DCLK_HI, 0x13); 406 WSeq(ba, SEQ_ID_DCLK_LO, 0x41); 407 408 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2); 409 test = test | 0x22; 410 411 /* DCLK + MCLK Clock immediate load! */ 412 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test); 413 414 /* DCLK load */ 415 test = vgar(ba, 0x3cc); 416 test = test | 0x0c; 417 vgaw(ba, 0x3c2, test); 418 419 /* Clear bit 5 again, prevent further loading. */ 420 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x2); 421 422 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F); 423 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F); 424 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50); 425 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82); 426 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54); 427 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80); 428 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF); 429 430 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */ 431 432 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x0); /* no panning */ 433 434 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */ 435 436 WCrt(ba, CRT_ID_CURSOR_START, 0x00); 437 WCrt(ba, CRT_ID_CURSOR_END, 0x00); 438 439 /* Display start adress */ 440 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00); 441 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00); 442 443 /* Cursor location */ 444 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00); 445 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00); 446 447 /* Vertical retrace */ 448 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C); 449 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E); 450 451 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F); 452 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50); 453 454 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00); 455 456 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96); 457 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9); 458 459 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3); 460 461 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF); 462 463 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */ 464 465 /* Refresh count 1, High speed text font, enhanced color mode */ 466 WCrt(ba, CRT_ID_MISC_1, 0x35); 467 468 /* start fifo position */ 469 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a); 470 471 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70); 472 473 /* address window position */ 474 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40); 475 476 /* N Parameter for Display FIFO */ 477 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF); 478 479 WGfx(ba, GCT_ID_SET_RESET, 0x0); 480 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x0); 481 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x0); 482 WGfx(ba, GCT_ID_DATA_ROTATE, 0x0); 483 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x0); 484 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40); 485 WGfx(ba, GCT_ID_MISC, 0x01); 486 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F); 487 WGfx(ba, GCT_ID_BITMASK, 0xFF); 488 489 /* colors for text mode */ 490 for (i = 0; i <= 0xf; i++) 491 WAttr (ba, i, i); 492 493 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41); 494 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01); 495 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F); 496 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x0); 497 WAttr(ba, ACT_ID_COLOR_SELECT, 0x0); 498 499 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */ 500 501 *((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF; 502 *((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0; 503 504 /* colors initially set to greyscale */ 505 506 vgaw(ba, VDAC_ADDRESS_W, 0); 507 for (i = 255; i >= 0 ; i--) { 508 vgaw(ba, VDAC_DATA, i); 509 vgaw(ba, VDAC_DATA, i); 510 vgaw(ba, VDAC_DATA, i); 511 } 512 513 /* GFx hardware cursor off */ 514 WCrt(ba, CRT_ID_HWGC_MODE, 0x00); 515 516 /* Set first to 4 MB, so test will work */ 517 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); 518 519 /* find *correct* fbsize of z3 board */ 520 if (cv_has_4mb((volatile char *)cv_boardaddr + 0x01400000)) { 521 cv_fbsize = 1024 * 1024 * 4; 522 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */ 523 } else { 524 cv_fbsize = 1024 * 1024 * 2; 525 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */ 526 } 527 528 /* If I knew what this really does... but it _is_ necessary 529 to get any gfx on the screen!! Undocumented register? */ 530 WAttr(ba, 0x33, 0); 531 532 gi = &gp->g_display; 533 gi->gd_regaddr = (caddr_t) kvtop (ba); 534 gi->gd_regsize = 64 * 1024; 535 gi->gd_fbaddr = (caddr_t) kvtop (gp->g_fbkva); 536 gi->gd_fbsize = cv_fbsize; 537 } 538 539 540 int 541 cv_getvmode(gp, vm) 542 struct grf_softc *gp; 543 struct grfvideo_mode *vm; 544 { 545 struct grfvideo_mode *gv; 546 547 #ifdef CV64CONSOLE 548 /* Handle grabbing console mode */ 549 if (vm->mode_num == 255) { 550 bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode)); 551 /* XXX so grfconfig can tell us the correct text dimensions. */ 552 vm->depth = cvconsole_mode.fy; 553 } else 554 #endif 555 { 556 if (vm->mode_num == 0) 557 vm->mode_num = (monitor_current - monitor_def) + 1; 558 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max) 559 return (EINVAL); 560 gv = monitor_def + (vm->mode_num - 1); 561 if (gv->mode_num == 0) 562 return (EINVAL); 563 564 bcopy(gv, vm, sizeof(struct grfvideo_mode)); 565 } 566 567 /* adjust internal values to pixel values */ 568 569 vm->hblank_start *= 8; 570 vm->hblank_stop *= 8; 571 vm->hsync_start *= 8; 572 vm->hsync_stop *= 8; 573 vm->htotal *= 8; 574 575 return (0); 576 } 577 578 579 int 580 cv_setvmode(gp, mode) 581 struct grf_softc *gp; 582 unsigned mode; 583 { 584 if (!mode || (mode > monitor_def_max) || 585 monitor_def[mode - 1].mode_num == 0) 586 return (EINVAL); 587 588 monitor_current = monitor_def + (mode - 1); 589 590 return (0); 591 } 592 593 594 int 595 cv_blank(gp, on) 596 struct grf_softc *gp; 597 int *on; 598 { 599 volatile caddr_t ba = gp->g_regkva; 600 601 gfx_on_off(*on ? 1 : 0, ba); 602 return (0); 603 } 604 605 606 /* 607 * Change the mode of the display. 608 * Return a UNIX error number or 0 for success. 609 */ 610 int 611 cv_mode(gp, cmd, arg, a2, a3) 612 register struct grf_softc *gp; 613 int cmd; 614 void *arg; 615 int a2, a3; 616 { 617 int error; 618 619 switch (cmd) { 620 case GM_GRFON: 621 error = cv_load_mon (gp, 622 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL; 623 return (error); 624 625 case GM_GRFOFF: 626 #ifndef CV64CONSOLE 627 (void)cv_toggle(gp); 628 #else 629 cv_load_mon(gp, &cvconsole_mode); 630 #endif 631 return (0); 632 633 case GM_GRFCONFIG: 634 return (0); 635 636 case GM_GRFGETVMODE: 637 return (cv_getvmode (gp, (struct grfvideo_mode *) arg)); 638 639 case GM_GRFSETVMODE: 640 error = cv_setvmode (gp, *(unsigned *) arg); 641 if (!error && (gp->g_flags & GF_GRFON)) 642 cv_load_mon(gp, 643 (struct grfcvtext_mode *) monitor_current); 644 return (error); 645 646 case GM_GRFGETNUMVM: 647 *(int *)arg = monitor_def_max; 648 return (0); 649 650 case GM_GRFIOCTL: 651 return (cv_ioctl (gp, (int) arg, (caddr_t) a2)); 652 653 default: 654 break; 655 } 656 657 return (EINVAL); 658 } 659 660 int 661 cv_ioctl (gp, cmd, data) 662 register struct grf_softc *gp; 663 int cmd; 664 void *data; 665 { 666 switch (cmd) { 667 case GRFIOCGSPRITEPOS: 668 case GRFIOCSSPRITEPOS: 669 case GRFIOCSSPRITEINF: 670 case GRFIOCGSPRITEINF: 671 case GRFIOCGSPRITEMAX: 672 break; 673 674 case GRFIOCGETCMAP: 675 return (cv_getcmap (gp, (struct grf_colormap *) data)); 676 677 case GRFIOCPUTCMAP: 678 return (cv_putcmap (gp, (struct grf_colormap *) data)); 679 680 case GRFIOCBITBLT: 681 break; 682 683 case GRFTOGGLE: 684 return (cv_toggle (gp)); 685 686 case GRFIOCSETMON: 687 return (cv_setmonitor (gp, (struct grfvideo_mode *)data)); 688 689 case GRFIOCBLANK: 690 return (cv_blank (gp, (int *)data)); 691 } 692 return (EINVAL); 693 } 694 695 int 696 cv_setmonitor(gp, gv) 697 struct grf_softc *gp; 698 struct grfvideo_mode *gv; 699 { 700 struct grfvideo_mode *md; 701 702 if (!cv_mondefok(gv)) 703 return (EINVAL); 704 705 #ifdef CV64CONSOLE 706 /* handle interactive setting of console mode */ 707 if (gv->mode_num == 255) { 708 bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode)); 709 cvconsole_mode.gv.hblank_start /= 8; 710 cvconsole_mode.gv.hblank_stop /= 8; 711 cvconsole_mode.gv.hsync_start /= 8; 712 cvconsole_mode.gv.hsync_stop /= 8; 713 cvconsole_mode.gv.htotal /= 8; 714 cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy; 715 cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx; 716 if (!(gp->g_flags & GF_GRFON)) 717 cv_load_mon(gp, &cvconsole_mode); 718 ite_reinit(gp->g_itedev); 719 return (0); 720 } 721 #endif 722 723 md = monitor_def + (gv->mode_num - 1); 724 bcopy(gv, md, sizeof(struct grfvideo_mode)); 725 726 /* adjust pixel oriented values to internal rep. */ 727 728 md->hblank_start /= 8; 729 md->hblank_stop /= 8; 730 md->hsync_start /= 8; 731 md->hsync_stop /= 8; 732 md->htotal /= 8; 733 734 return (0); 735 } 736 737 int 738 cv_getcmap(gfp, cmap) 739 struct grf_softc *gfp; 740 struct grf_colormap *cmap; 741 { 742 volatile caddr_t ba; 743 u_char red[256], green[256], blue[256], *rp, *gp, *bp; 744 short x; 745 int error; 746 747 if (cmap->count == 0 || cmap->index >= 256) 748 return (0); 749 750 if (cmap->index + cmap->count > 256) 751 cmap->count = 256 - cmap->index; 752 753 ba = gfp->g_regkva; 754 /* first read colors out of the chip, then copyout to userspace */ 755 vgaw (ba, VDAC_ADDRESS_W, cmap->index); 756 x = cmap->count - 1; 757 758 rp = red + cmap->index; 759 gp = green + cmap->index; 760 bp = blue + cmap->index; 761 762 do { 763 *rp++ = vgar (ba, VDAC_DATA) << 2; 764 *gp++ = vgar (ba, VDAC_DATA) << 2; 765 *bp++ = vgar (ba, VDAC_DATA) << 2; 766 } while (x-- > 0); 767 768 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count)) 769 && !(error = copyout (green + cmap->index, cmap->green, cmap->count)) 770 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count))) 771 return (0); 772 773 return (error); 774 } 775 776 int 777 cv_putcmap(gfp, cmap) 778 struct grf_softc *gfp; 779 struct grf_colormap *cmap; 780 { 781 volatile caddr_t ba; 782 u_char red[256], green[256], blue[256], *rp, *gp, *bp; 783 short x; 784 int error; 785 786 if (cmap->count == 0 || cmap->index >= 256) 787 return (0); 788 789 if (cmap->index + cmap->count > 256) 790 cmap->count = 256 - cmap->index; 791 792 /* first copy the colors into kernelspace */ 793 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count)) 794 && !(error = copyin (cmap->green, green + cmap->index, cmap->count)) 795 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) { 796 ba = gfp->g_regkva; 797 vgaw (ba, VDAC_ADDRESS_W, cmap->index); 798 x = cmap->count - 1; 799 800 rp = red + cmap->index; 801 gp = green + cmap->index; 802 bp = blue + cmap->index; 803 804 do { 805 vgaw (ba, VDAC_DATA, *rp++ >> 2); 806 vgaw (ba, VDAC_DATA, *gp++ >> 2); 807 vgaw (ba, VDAC_DATA, *bp++ >> 2); 808 } while (x-- > 0); 809 return (0); 810 } else 811 return (error); 812 } 813 814 815 int 816 cv_toggle(gp) 817 struct grf_softc *gp; 818 { 819 volatile caddr_t ba; 820 821 ba = gp->g_regkva; 822 cvscreen(1, ba - READ_OFFSET); 823 824 return (0); 825 } 826 827 828 int 829 cv_mondefok(gv) 830 struct grfvideo_mode *gv; 831 { 832 unsigned long maxpix; 833 834 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) 835 if (gv->mode_num != 255 || gv->depth != 4) 836 return (0); 837 838 switch(gv->depth) { 839 case 1: 840 case 4: 841 /* Remove this comment when ite5 is ready */ 842 /* if (gv->mode_num != 255) */ 843 return (0); 844 case 8: 845 maxpix = MAXPIXELCLOCK; 846 break; 847 case 15: 848 case 16: 849 maxpix = MAXPIXELCLOCK - 55000000; 850 break; 851 case 24: 852 maxpix = MAXPIXELCLOCK - 85000000; 853 break; 854 default: 855 return (0); 856 } 857 858 if (gv->pixel_clock > maxpix) 859 return (0); 860 return (1); 861 } 862 863 int 864 cv_load_mon(gp, md) 865 struct grf_softc *gp; 866 struct grfcvtext_mode *md; 867 { 868 struct grfvideo_mode *gv; 869 struct grfinfo *gi; 870 volatile caddr_t ba, fb; 871 unsigned short mnr; 872 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, 873 VSE, VT; 874 char LACE, DBLSCAN, TEXT; 875 int uplim, lowlim; 876 int cr33, sr15, sr18, clock_mode, test; 877 int m, n, clock; /* For calc'ing display FIFO */ 878 879 /* identity */ 880 gv = &md->gv; 881 TEXT = (gv->depth == 4); 882 883 if (!cv_mondefok(gv)) { 884 printf("mondef not ok\n"); 885 return (0); 886 } 887 ba = gp->g_regkva; 888 fb = gp->g_fbkva; 889 890 /* turn gfx off, don't mess up the display */ 891 gfx_on_off(1, ba); 892 893 /* provide all needed information in grf device-independant locations */ 894 gp->g_data = (caddr_t) gv; 895 gi = &gp->g_display; 896 gi->gd_colors = 1 << gv->depth; 897 gi->gd_planes = gv->depth; 898 gi->gd_fbwidth = gv->disp_width; 899 gi->gd_fbheight = gv->disp_height; 900 gi->gd_fbx = 0; 901 gi->gd_fby = 0; 902 if (TEXT) { 903 gi->gd_dwidth = md->fx * md->cols; 904 gi->gd_dheight = md->fy * md->rows; 905 } else { 906 gi->gd_dwidth = gv->disp_width; 907 gi->gd_dheight = gv->disp_height; 908 } 909 gi->gd_dx = 0; 910 gi->gd_dy = 0; 911 912 /* get display mode parameters */ 913 914 HBS = gv->hblank_start; 915 HBE = gv->hblank_stop; 916 HSS = gv->hsync_start; 917 HSE = gv->hsync_stop; 918 HT = gv->htotal - 5; 919 VBS = gv->vblank_start - 1; 920 VSS = gv->vsync_start; 921 VSE = gv->vsync_stop; 922 VBE = gv->vblank_stop; 923 VT = gv->vtotal - 2; 924 925 if (TEXT) 926 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1; 927 else 928 HDE = (gv->disp_width + 3) / 8 - 1; /*HBS;*/ 929 VDE = gv->disp_height - 1; 930 931 /* figure out whether lace or dblscan is needed */ 932 933 uplim = gv->disp_height + (gv->disp_height / 4); 934 lowlim = gv->disp_height - (gv->disp_height / 4); 935 LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0; 936 DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0; 937 938 /* adjustments */ 939 940 if (LACE) 941 VDE /= 2; 942 943 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e); 944 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00); 945 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff); 946 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); 947 948 /* Set clock */ 949 950 switch (gv->depth) { 951 case 15: 952 case 16: 953 mnr = compute_clock(gv->pixel_clock * 2); 954 break; 955 case 24: 956 mnr = compute_clock(gv->pixel_clock * 3); 957 break; 958 default: 959 mnr = compute_clock(gv->pixel_clock); 960 break; 961 } 962 963 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8) ); 964 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF)); 965 966 /* load display parameters into board */ 967 968 WCrt(ba, CRT_ID_EXT_HOR_OVF, 969 ((HT & 0x100) ? 0x01 : 0x00) | 970 ((HDE & 0x100) ? 0x02 : 0x00) | 971 ((HBS & 0x100) ? 0x04 : 0x00) | 972 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */ 973 ((HSS & 0x100) ? 0x10 : 0x00) | 974 /* ((HSE & 0x20) ? 0x20 : 0x00) | */ 975 (((HT-5) & 0x100) ? 0x40 : 0x00) ); 976 977 WCrt(ba, CRT_ID_EXT_VER_OVF, 978 0x40 | /* Line compare */ 979 ((VT & 0x400) ? 0x01 : 0x00) | 980 ((VDE & 0x400) ? 0x02 : 0x00) | 981 ((VBS & 0x400) ? 0x04 : 0x00) | 982 ((VSS & 0x400) ? 0x10 : 0x00) ); 983 984 WCrt(ba, CRT_ID_HOR_TOTAL, HT); 985 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5); 986 987 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE)); 988 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS); 989 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80)); 990 WCrt(ba, CRT_ID_START_HOR_RETR, HSS); 991 WCrt(ba, CRT_ID_END_HOR_RETR, 992 (HSE & 0x1f) | 993 ((HBE & 0x20) ? 0x80 : 0x00) ); 994 WCrt(ba, CRT_ID_VER_TOTAL, VT); 995 WCrt(ba, CRT_ID_OVERFLOW, 996 0x10 | 997 ((VT & 0x100) ? 0x01 : 0x00) | 998 ((VDE & 0x100) ? 0x02 : 0x00) | 999 ((VSS & 0x100) ? 0x04 : 0x00) | 1000 ((VBS & 0x100) ? 0x08 : 0x00) | 1001 ((VT & 0x200) ? 0x20 : 0x00) | 1002 ((VDE & 0x200) ? 0x40 : 0x00) | 1003 ((VSS & 0x200) ? 0x80 : 0x00) ); 1004 1005 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 1006 0x40 | /* TEXT ? 0x00 ??? */ 1007 (DBLSCAN ? 0x80 : 0x00) | 1008 ((VBS & 0x200) ? 0x20 : 0x00) | 1009 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00)); 1010 1011 WCrt(ba, CRT_ID_MODE_CONTROL, 1012 ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xe3)); 1013 1014 /* text cursor */ 1015 1016 if (TEXT) { 1017 #if 1 1018 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2); 1019 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1); 1020 #else 1021 WCrt(ba, CRT_ID_CURSOR_START, 0x00); 1022 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f); 1023 #endif 1024 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f); 1025 1026 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00); 1027 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00); 1028 } 1029 1030 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00); 1031 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00); 1032 1033 WCrt(ba, CRT_ID_START_VER_RETR, VSS); 1034 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f)); 1035 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE); 1036 WCrt(ba, CRT_ID_START_VER_BLANK, VBS); 1037 WCrt(ba, CRT_ID_END_VER_BLANK, VBE); 1038 1039 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff); 1040 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2); 1041 WCrt(ba, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00)); 1042 1043 WGfx(ba, GCT_ID_GRAPHICS_MODE, 1044 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40)); 1045 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01)); 1046 1047 WSeq (ba, SEQ_ID_MEMORY_MODE, 1048 ((TEXT || (gv->depth == 1)) ? 0x6 : 0x02)); 1049 1050 vgaw(ba, VDAC_MASK, 0xff); 1051 1052 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); 1053 sr15 &= 0xef; 1054 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL); 1055 sr18 &= 0x7f; 1056 cr33 = RCrt(ba, CRT_ID_BACKWAD_COMP_2); 1057 cr33 &= 0xdf; 1058 clock_mode = 0x00; 1059 1060 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2); 1061 test &= 0xd; 1062 1063 switch (gv->depth) { 1064 case 1: 1065 case 4: /* text */ 1066 HDE = gv->disp_width / 16; 1067 break; 1068 case 8: 1069 if (gv->pixel_clock > 80000000) { 1070 clock_mode = 0x10 | 0x02; 1071 sr15 |= 0x10; 1072 sr18 |= 0x80; 1073 cr33 |= 0x20; 1074 } 1075 HDE = gv->disp_width / 8; 1076 break; 1077 case 15: 1078 clock_mode = 0x30; 1079 HDE = gv->disp_width / 4; 1080 break; 1081 case 16: 1082 clock_mode = 0x50; 1083 HDE = gv->disp_width / 4; 1084 break; 1085 case 24: 1086 clock_mode = 0xd0; 1087 HDE = (gv->disp_width / 8) * 3; 1088 break; 1089 } 1090 1091 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test); 1092 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15); 1093 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18); 1094 WCrt(ba, CRT_ID_BACKWAD_COMP_2, cr33); 1095 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE); 1096 1097 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2); 1098 /* HDE Overflow in bits 4-5 */ 1099 test |= (HDE >> 4) & 0x30; 1100 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test); 1101 1102 delay(100000); 1103 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x41)); 1104 delay(100000); 1105 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 1106 (gv->depth == 1) ? 0x01 : 0x0f); 1107 delay(100000); 1108 1109 /* 1110 * Calc. display fifo m and n parameters 1111 * Dont't ask me what the hell these values mean. 1112 */ 1113 1114 n = 0xff; 1115 if (gv->depth < 9) 1116 clock = gv->pixel_clock / 500000.0; 1117 else if (gv->depth == 15) 1118 clock = gv->pixel_clock / 250000.0; 1119 else 1120 clock = (gv->pixel_clock * (gv->depth / 8)) / 500000.0; 1121 1122 m = ((int)((55 * .72 + 16.867) * 89.736 / (clock + 39) - 21.1543) / 2) - 1; 1123 1124 if (m > 31) 1125 m = 31; 1126 else if (m <= 0) { 1127 m = 0; 1128 n = 16; 1129 } 1130 1131 m = m << 3; 1132 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m); 1133 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n); 1134 delay(10000); 1135 1136 /* text initialization */ 1137 1138 if (TEXT) { 1139 cv_inittextmode(gp); 1140 } 1141 1142 /* Some kind of Magic */ 1143 WAttr(ba, 0x33, 0); 1144 1145 /* turn gfx on again */ 1146 gfx_on_off(0, ba); 1147 1148 /* Pass-through */ 1149 cvscreen(0, ba - READ_OFFSET); 1150 1151 return (1); 1152 } 1153 1154 void 1155 cv_inittextmode(gp) 1156 struct grf_softc *gp; 1157 { 1158 struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data; 1159 volatile caddr_t ba = gp->g_regkva; 1160 volatile caddr_t fb = gp->g_fbkva; 1161 unsigned char *c, *f, y; 1162 unsigned short z; 1163 1164 1165 /* load text font into beginning of display memory. 1166 * Each character cell is 32 bytes long (enough for 4 planes) 1167 */ 1168 1169 SetTextPlane(ba, 0x02); 1170 cv_memset(fb, 0, 256 * 32); 1171 c = (unsigned char *) (fb) + (32 * tm->fdstart); 1172 f = tm->fdata; 1173 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy)) 1174 for (y = 0; y < tm->fy; y++) 1175 *c++ = *f++; 1176 1177 /* clear out text/attr planes (three screens worth) */ 1178 1179 SetTextPlane(ba, 0x01); 1180 cv_memset(fb, 0x07, tm->cols * tm->rows * 3); 1181 SetTextPlane(ba, 0x00); 1182 cv_memset(fb, 0x20, tm->cols * tm->rows * 3); 1183 1184 /* print out a little init msg */ 1185 1186 c = (unsigned char *)(fb) + (tm->cols-16); 1187 strcpy(c, "CV64"); 1188 c[6] = 0x20; 1189 1190 /* set colors (B&W) */ 1191 1192 vgaw(ba, VDAC_ADDRESS_W, 0); 1193 for (z=0; z<256; z++) { 1194 unsigned char r, g, b; 1195 1196 y = (z & 1) ? ((z > 7) ? 2 : 1) : 0; 1197 1198 r = cvconscolors[y][0]; 1199 g = cvconscolors[y][1]; 1200 b = cvconscolors[y][2]; 1201 vgaw(ba, VDAC_DATA, r >> 2); 1202 vgaw(ba, VDAC_DATA, g >> 2); 1203 vgaw(ba, VDAC_DATA, b >> 2); 1204 } 1205 } 1206 1207 void 1208 cv_memset(d, c, l) 1209 unsigned char *d; 1210 unsigned char c; 1211 int l; 1212 { 1213 for(; l > 0; l--) 1214 *d++ = c; 1215 } 1216 1217 #endif /* NGRFCV */ 1218