1 /* $NetBSD: grf_cv.c,v 1.26 1998/10/06 22:26:42 tron 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, Michael Teske 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 /* 37 * Graphics routines for the CyberVision 64 board, using the S3 Trio64. 38 * 39 * Modified for CV64 from 40 * Kari Mettinen's Cirrus driver by Michael Teske 10/95 41 * 42 * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation. 43 * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy 44 * source to NetBSD style :) 45 * Thanks to Harald Koenig for providing information about undocumented 46 * Trio64 Bugs. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/errno.h> 51 #include <sys/ioctl.h> 52 #include <sys/device.h> 53 #include <sys/malloc.h> 54 #include <sys/systm.h> 55 #include <sys/syslog.h> 56 #include <machine/cpu.h> 57 #include <dev/cons.h> 58 #include <amiga/dev/itevar.h> 59 #include <amiga/amiga/device.h> 60 #include <amiga/amiga/isr.h> 61 #include <amiga/dev/grfioctl.h> 62 #include <amiga/dev/grfvar.h> 63 #include <amiga/dev/grf_cvreg.h> 64 #include <amiga/dev/zbusvar.h> 65 66 int grfcvmatch __P((struct device *, struct cfdata *, void *)); 67 void grfcvattach __P((struct device *, struct device *, void *)); 68 int grfcvprint __P((void *, const char *)); 69 70 int cvintr __P((void *)); 71 static int cv_has_4mb __P((volatile caddr_t)); 72 static unsigned short cv_compute_clock __P((unsigned long)); 73 void cv_boardinit __P((struct grf_softc *)); 74 int cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *)); 75 int cv_setvmode __P((struct grf_softc *, unsigned int)); 76 int cv_blank __P((struct grf_softc *, int *)); 77 int cv_mode __P((register struct grf_softc *, u_long, void *, u_long, int)); 78 int cv_ioctl __P((register struct grf_softc *gp, u_long cmd, void *data)); 79 int cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *)); 80 int cv_getcmap __P((struct grf_softc *, struct grf_colormap *)); 81 int cv_putcmap __P((struct grf_softc *, struct grf_colormap *)); 82 int cv_toggle __P((struct grf_softc *)); 83 int cv_mondefok __P((struct grfvideo_mode *)); 84 int cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *)); 85 void cv_inittextmode __P((struct grf_softc *)); 86 static __inline void cv_write_port __P((unsigned short, volatile caddr_t)); 87 static __inline void cvscreen __P((int, volatile caddr_t)); 88 static __inline void gfx_on_off __P((int, volatile caddr_t)); 89 90 #ifndef CV_NO_HARDWARE_CURSOR 91 int cv_getspritepos __P((struct grf_softc *, struct grf_position *)); 92 int cv_setspritepos __P((struct grf_softc *, struct grf_position *)); 93 int cv_getspriteinfo __P((struct grf_softc *,struct grf_spriteinfo *)); 94 void cv_setup_hwc __P((struct grf_softc *)); 95 int cv_setspriteinfo __P((struct grf_softc *,struct grf_spriteinfo *)); 96 int cv_getspritemax __P((struct grf_softc *,struct grf_position *)); 97 #endif /* !CV_NO_HARDWARE_CURSOR */ 98 99 /* 100 * Extension to grf_softc for interrupt support 101 */ 102 103 struct grf_cv_softc { 104 struct grf_softc gcs_sc; 105 struct isr gcs_isr; 106 }; 107 108 /* Graphics display definitions. 109 * These are filled by 'grfconfig' using GRFIOCSETMON. 110 */ 111 #define monitor_def_max 24 112 static struct grfvideo_mode monitor_def[24] = { 113 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, 114 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, 115 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0} 116 }; 117 static struct grfvideo_mode *monitor_current = &monitor_def[0]; 118 #define MAXPIXELCLOCK 135000000 /* safety */ 119 120 unsigned char cv_pass_toggle; /* passthru status tracker */ 121 122 /* Console display definition. 123 * Default hardcoded text mode. This grf_cv is set up to 124 * use one text mode only, and this is it. You may use 125 * grfconfig to change the mode after boot. 126 */ 127 128 /* Console font */ 129 #ifdef KFONT_8X11 130 #define S3FONT kernel_font_8x11 131 #define S3FONTY 11 132 #else 133 #define S3FONT kernel_font_8x8 134 #define S3FONTY 8 135 #endif 136 extern unsigned char S3FONT[]; 137 138 /* 139 * Define default console mode 140 * (Internally, we still have to use hvalues/8!) 141 */ 142 struct grfcvtext_mode cvconsole_mode = { 143 {255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8, 144 481, 491, 493, 525, 0}, 145 8, S3FONTY, 80, 480 / S3FONTY, S3FONT, 32, 255 146 }; 147 148 /* Console colors */ 149 unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */ 150 /* R G B */ 151 {0x30, 0x30, 0x30}, 152 {0x00, 0x00, 0x00}, 153 {0x80, 0x00, 0x00}, 154 {0x00, 0x80, 0x00}, 155 {0x00, 0x00, 0x80}, 156 {0x80, 0x80, 0x00}, 157 {0x00, 0x80, 0x80}, 158 {0x80, 0x00, 0x80}, 159 {0xff, 0xff, 0xff}, 160 {0x40, 0x40, 0x40}, 161 {0xff, 0x00, 0x00}, 162 {0x00, 0xff, 0x00}, 163 {0x00, 0x00, 0xff}, 164 {0xff, 0xff, 0x00}, 165 {0x00, 0xff, 0xff}, 166 {0x00, 0x00, 0xff} 167 }; 168 169 static unsigned char clocks[]={ 170 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69, 171 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c, 172 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a, 173 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69, 174 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65, 175 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63, 176 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d, 177 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49, 178 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42, 179 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43, 180 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49, 181 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a, 182 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49, 183 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41, 184 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43, 185 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45, 186 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45, 187 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45, 188 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44, 189 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46, 190 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f, 191 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22, 192 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46, 193 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b, 194 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44, 195 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26, 196 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b, 197 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25, 198 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25, 199 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21, 200 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29, 201 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29, 202 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29, 203 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28, 204 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26, 205 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21, 206 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28, 207 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27, 208 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22, 209 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27, 210 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27, 211 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21, 212 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26, 213 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27, 214 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9, 215 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb, 216 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9, 217 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2, 218 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25, 219 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25, 220 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25, 221 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd, 222 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3, 223 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25, 224 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2, 225 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22, 226 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb, 227 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9, 228 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc, 229 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9, 230 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1, 231 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0, 232 }; 233 234 235 /* Board Address of CV64 */ 236 static volatile caddr_t cv_boardaddr; 237 static int cv_fbsize; 238 239 /* 240 * Memory clock (binpatchable). 241 * Let's be defensive: 50 MHz runs on all boards I know of. 242 * 55 MHz runs on most boards. But you should know what you're doing 243 * if you set this flag. Again: This flag may destroy your CV Board. 244 * Use it at your own risk!!! 245 * Anyway, this doesn't imply that I'm responsible if your board breaks 246 * without setting this flag :-). 247 */ 248 #ifdef CV_AGGRESSIVE_TIMING 249 long cv_memclk = 55000000; 250 #else 251 long cv_memclk = 50000000; 252 #endif 253 254 /* standard driver stuff */ 255 struct cfattach grfcv_ca = { 256 sizeof(struct grf_cv_softc), grfcvmatch, grfcvattach 257 }; 258 259 static struct cfdata *cfdata; 260 261 #define CV_INT_NUM 6 /* CV interrupt Level: #2 or #6 */ 262 #define CV_ULCURSOR 1 /* Underlined Cursor in textmode */ 263 264 #ifndef CV_NO_HARDWARE_CURSOR 265 266 #define HWC_OFF (cv_fbsize - 1024*2) 267 #define HWC_SIZE 1024 268 269 static unsigned short cv_cursor_storage[HWC_SIZE/2]; 270 static short curs_update_flag = 0; 271 272 #endif /* !CV_NO_HARDWARE_CURSOR */ 273 274 /* 275 * Interrupt handler 276 * This is used for updating the cursor shape (because it _must not_ 277 * be changed while cursor is displayed) 278 * and maybe later to avoid busy waiting 279 * for Vertical Blank and/or gfx engine busy 280 */ 281 282 int 283 cvintr(arg) 284 void * arg; 285 { 286 #ifndef CV_NO_HARDWARE_CURSOR 287 register unsigned long *csrc, *cdest; 288 int i; 289 #endif 290 struct grf_softc *gp = arg; 291 volatile caddr_t ba = gp->g_regkva; 292 unsigned char test; 293 unsigned char cridx; /* Save the cr Register index */ 294 295 if (gp == NULL) 296 return 0; 297 298 test = vgar(ba, GREG_INPUT_STATUS0_R); 299 300 if (test & 0x80) { /* VR int pending */ 301 /* Save old CR index */ 302 cridx = vgar (ba, CRT_ADDRESS); 303 304 #if 0 305 test = RCrt(ba, CRT_ID_END_VER_RETR); 306 /* Clear int (bit 4) */ 307 test &= ~0x10; 308 WCrt(ba, CRT_ID_END_VER_RETR, test); 309 #else 310 vgaw(ba, CRT_ADDRESS, CRT_ID_END_VER_RETR); 311 asm volatile("bclr #4,%0@(0x3d5);nop" : : "a" (ba)); 312 #endif 313 314 #ifndef CV_NO_HARDWARE_CURSOR 315 /* update the hardware cursor, if necessary */ 316 if (curs_update_flag) { 317 csrc = (unsigned long *)cv_cursor_storage; 318 cdest = (unsigned long *)((volatile char *)gp->g_fbkva 319 + HWC_OFF); 320 for (i = 0; i < HWC_SIZE / sizeof(long); i++) 321 *cdest++ = *csrc++; 322 curs_update_flag = 0; 323 } 324 /* Reenable int */ 325 #if 0 326 test |= 0x10; 327 WCrt(ba, CRT_ID_END_VER_RETR, test); 328 #else 329 /* I don't trust the optimizer here... */ 330 asm volatile("bset #4,%0@(0x3d5);nop" : : "a" (ba)); 331 #endif 332 cv_setspritepos (gp, NULL); 333 334 /* Restore the old CR index */ 335 vgaw(ba, CRT_ADDRESS, cridx); 336 asm volatile("nop"); 337 #endif /* !CV_NO_HARDWARE_CURSOR */ 338 return (1); 339 } 340 return (0); 341 } 342 343 /* 344 * Get frambuffer memory size. 345 * phase5 didn't provide the bit in CR36, 346 * so we have to do it this way. 347 * Return 0 for 2MB, 1 for 4MB 348 */ 349 static int 350 cv_has_4mb(fb) 351 volatile caddr_t fb; 352 { 353 volatile unsigned long *testfbw, *testfbr; 354 355 /* write patterns in memory and test if they can be read */ 356 testfbw = (volatile unsigned long *)fb; 357 testfbr = (volatile unsigned long *)(fb + 0x02000000); 358 *testfbw = 0x87654321; 359 asm volatile("nop"); 360 if (*testfbr != 0x87654321) 361 return (0); 362 363 /* upper memory region */ 364 testfbw = (volatile unsigned long *)(fb + 0x00200000); 365 testfbr = (volatile unsigned long *)(fb + 0x02200000); 366 *testfbw = 0x87654321; 367 asm volatile("nop"); 368 if (*testfbr != 0x87654321) 369 return (0); 370 *testfbw = 0xAAAAAAAA; 371 asm volatile("nop"); 372 if (*testfbr != 0xAAAAAAAA) 373 return (0); 374 *testfbw = 0x55555555; 375 asm volatile("nop"); 376 if (*testfbr != 0x55555555) 377 return (0); 378 return (1); 379 } 380 381 int 382 grfcvmatch(pdp, cfp, auxp) 383 struct device *pdp; 384 struct cfdata *cfp; 385 void *auxp; 386 { 387 #ifdef CV64CONSOLE 388 static int cvcons_unit = -1; 389 #endif 390 struct zbus_args *zap; 391 392 zap = auxp; 393 394 if (amiga_realconfig == 0) 395 #ifdef CV64CONSOLE 396 if (cvcons_unit != -1) 397 #endif 398 return (0); 399 400 /* Lets be Paranoid: Test man and prod id */ 401 if (zap->manid != 8512 || zap->prodid != 34) 402 return (0); 403 404 cv_boardaddr = zap->va; 405 406 #ifdef CV64CONSOLE 407 if (amiga_realconfig == 0) { 408 cvcons_unit = cfp->cf_unit; 409 cfdata = cfp; 410 } 411 #endif 412 413 return (1); 414 } 415 416 void 417 grfcvattach(pdp, dp, auxp) 418 struct device *pdp, *dp; 419 void *auxp; 420 { 421 static struct grf_cv_softc congrf; 422 struct zbus_args *zap; 423 struct grf_softc *gp; 424 struct grf_cv_softc *gcp; 425 static char attachflag = 0; 426 427 zap = auxp; 428 429 /* 430 * This function is called twice, once on console init (dp == NULL) 431 * and once on "normal" grf5 init. 432 */ 433 434 if (dp == NULL) /* console init */ 435 gcp = &congrf; 436 else 437 gcp = (struct grf_cv_softc *)dp; 438 439 gp = &gcp->gcs_sc; 440 441 if (dp != NULL && congrf.gcs_sc.g_regkva != 0) { 442 /* 443 * inited earlier, just copy (not device struct) 444 */ 445 446 printf("\n"); 447 bcopy(&congrf.gcs_sc.g_display, &gp->g_display, 448 (char *) &gcp->gcs_isr - (char *) &gp->g_display); 449 450 /* ... and transfer the isr */ 451 gcp->gcs_isr.isr_ipl = CV_INT_NUM; 452 gcp->gcs_isr.isr_intr = cvintr; 453 gcp->gcs_isr.isr_arg = (void *)gp; 454 455 /* First add new isr */ 456 add_isr(&gcp->gcs_isr); 457 remove_isr(&congrf.gcs_isr); 458 } else { 459 gp->g_regkva = (volatile caddr_t)cv_boardaddr + 0x02000000; 460 gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000; 461 462 gp->g_unit = GRF_CV64_UNIT; 463 gp->g_mode = cv_mode; 464 gp->g_conpri = grfcv_cnprobe(); 465 gp->g_flags = GF_ALIVE; 466 467 /* add Interrupt Handler */ 468 gcp->gcs_isr.isr_ipl = CV_INT_NUM; 469 gcp->gcs_isr.isr_intr = cvintr; 470 gcp->gcs_isr.isr_arg = (void *)gp; 471 add_isr(&gcp->gcs_isr); 472 473 /* wakeup the board */ 474 cv_boardinit(gp); 475 476 #ifdef CV64CONSOLE 477 grfcv_iteinit(gp); 478 (void)cv_load_mon(gp, &cvconsole_mode); 479 #endif 480 } 481 482 /* 483 * attach grf 484 */ 485 if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) { 486 if (dp != NULL) 487 printf("grfcv: CyberVision64 with %dMB being used\n", 488 cv_fbsize/0x100000); 489 attachflag = 1; 490 } else { 491 if (!attachflag) 492 /*printf("grfcv unattached!!\n")*/; 493 } 494 } 495 496 int 497 grfcvprint(auxp, pnp) 498 void *auxp; 499 const char *pnp; 500 { 501 if (pnp) 502 printf("ite at %s: ", pnp); 503 return (UNCONF); 504 } 505 506 507 /* 508 * Computes M, N, and R values from 509 * given input frequency. It uses a table of 510 * precomputed values, to keep CPU time low. 511 * 512 * The return value consist of: 513 * lower byte: Bits 4-0: N Divider Value 514 * Bits 5-6: R Value for e.g. SR10 or SR12 515 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13 516 */ 517 518 static unsigned short 519 cv_compute_clock(freq) 520 unsigned long freq; 521 { 522 static unsigned char *mnr, *save; /* M, N + R vals */ 523 unsigned long work_freq, r; 524 unsigned short erg; 525 long diff, d2; 526 527 if (freq < 12500000 || freq > MAXPIXELCLOCK) { 528 printf("grfcv: Illegal clock frequency: %ldMHz\n", freq/1000000); 529 printf("grfcv: Using default frequency: 25MHz\n"); 530 printf("grfcv: See the manpage of grfconfig for more informations.\n"); 531 freq = 25000000; 532 } 533 534 mnr = clocks; /* there the vals are stored */ 535 d2 = 0x7fffffff; 536 537 while (*mnr) { /* mnr vals are 0-terminated */ 538 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2); 539 540 r = (mnr[1] >> 5) & 0x03; 541 if (r != 0) 542 work_freq=work_freq >> r; /* r is the freq divider */ 543 544 work_freq *= 0x3E8; /* 2nd part of OSC */ 545 546 diff = abs(freq - work_freq); 547 548 if (d2 >= diff) { 549 d2 = diff; 550 /* In save are the vals for minimal diff */ 551 save = mnr; 552 } 553 mnr += 2; 554 } 555 erg = *((unsigned short *)save); 556 557 return (erg); 558 } 559 560 561 void 562 cv_boardinit(gp) 563 struct grf_softc *gp; 564 { 565 volatile caddr_t ba; 566 unsigned char test; 567 unsigned int clockpar; 568 int i; 569 struct grfinfo *gi; 570 571 ba = gp->g_regkva; 572 /* Reset board */ 573 for (i = 0; i < 6; i++) 574 cv_write_port (0xff, ba - 0x02000000); /* Clear all bits */ 575 576 /* Return to operational Mode */ 577 cv_write_port(0x8004, ba - 0x02000000); 578 579 /* Wakeup Chip */ 580 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10); 581 vgaw(ba, SREG_OPTION_SELECT, 0x01); 582 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x08); 583 584 vgaw(ba, GREG_MISC_OUTPUT_W, 0x03); 585 586 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */ 587 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */ 588 589 /* 590 * The default board interrupt is #6. 591 * Set the roxxler register to use interrupt #2, not #6. 592 */ 593 #if CV_INT_NUM == 2 594 cv_write_port(0x8080, ba - 0x02000000); 595 #endif 596 597 /* Enable board interrupts */ 598 cv_write_port(0x8008, ba - 0x02000000); 599 600 test = RCrt(ba, CRT_ID_SYSTEM_CONFIG); 601 test = test | 0x01; /* enable enhaced register access */ 602 test = test & 0xEF; /* clear bit 4, 0 wait state */ 603 WCrt(ba, CRT_ID_SYSTEM_CONFIG, test); 604 605 /* 606 * bit 1=1: enable enhanced mode functions 607 * bit 4=1: enable linear adressing 608 * bit 5=1: enable MMIO 609 */ 610 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31); 611 612 /* enable color mode (bit0), cpu acess (bit1), high 64k page (bit5) */ 613 vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3); 614 615 /* Cpu base addr */ 616 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x00); 617 618 /* Reset. This does nothing, but everyone does it:) */ 619 WSeq(ba, SEQ_ID_RESET, 0x03); 620 621 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01); /* 8 Dot Clock */ 622 WSeq(ba, SEQ_ID_MAP_MASK, 0x0f); /* Enable write planes */ 623 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); /* Character Font */ 624 625 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02); /* Complete mem access */ 626 627 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06); /* Unlock extensions */ 628 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */ 629 630 /* enable 4MB fast Page Mode */ 631 test = test | 1 << 6; 632 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test); 633 /* faster LUT write */ 634 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0); 635 636 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */ 637 638 /* immediately Clkload bit clear */ 639 test = test & 0xDF; 640 641 /* 2 MCLK Memory Write.... */ 642 if (cv_memclk >= 55000000) 643 test |= 0x80; 644 645 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test); 646 647 /* Memory CLK */ 648 clockpar = cv_compute_clock(cv_memclk); 649 test = (clockpar & 0xFF00) >> 8; 650 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */ 651 652 test = clockpar & 0xFF; 653 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */ 654 655 if (RCrt(ba, CRT_ID_REVISION) == 0x10) /* bugfix for new S3 chips */ 656 WSeq(ba, SEQ_ID_MORE_MAGIC, test); 657 658 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */ 659 /* DCLK */ 660 WSeq(ba, SEQ_ID_DCLK_HI, 0x13); 661 WSeq(ba, SEQ_ID_DCLK_LO, 0x41); 662 663 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2); 664 test = test | 0x22; 665 666 /* DCLK + MCLK Clock immediate load! */ 667 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test); 668 669 /* DCLK load */ 670 test = vgar(ba, 0x3cc); 671 test = test | 0x0c; 672 vgaw(ba, 0x3c2, test); 673 674 /* Clear bit 5 again, prevent further loading. */ 675 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02); 676 677 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F); 678 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F); 679 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50); 680 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82); 681 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54); 682 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80); 683 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF); 684 685 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */ 686 687 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00); /* no panning */ 688 689 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */ 690 691 WCrt(ba, CRT_ID_CURSOR_START, 0x00); 692 WCrt(ba, CRT_ID_CURSOR_END, 0x00); 693 694 /* Display start adress */ 695 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00); 696 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00); 697 698 /* Cursor location */ 699 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00); 700 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00); 701 702 /* Vertical retrace */ 703 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C); 704 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E); 705 706 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F); 707 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50); 708 709 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00); 710 711 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96); 712 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9); 713 714 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3); 715 716 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF); 717 718 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */ 719 720 /* Refresh count 1, High speed text font, enhanced color mode */ 721 WCrt(ba, CRT_ID_MISC_1, 0x35); 722 723 /* start fifo position */ 724 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a); 725 726 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70); 727 728 /* address window position */ 729 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40); 730 731 /* N Parameter for Display FIFO */ 732 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF); 733 734 WGfx(ba, GCT_ID_SET_RESET, 0x00); 735 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00); 736 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00); 737 WGfx(ba, GCT_ID_DATA_ROTATE, 0x00); 738 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00); 739 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40); 740 WGfx(ba, GCT_ID_MISC, 0x01); 741 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F); 742 WGfx(ba, GCT_ID_BITMASK, 0xFF); 743 744 /* colors for text mode */ 745 for (i = 0; i <= 0xf; i++) 746 WAttr (ba, i, i); 747 748 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41); 749 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01); 750 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F); 751 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00); 752 WAttr(ba, ACT_ID_COLOR_SELECT, 0x00); 753 754 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */ 755 756 *((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF; 757 *((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0; 758 759 /* colors initially set to greyscale */ 760 761 vgaw(ba, VDAC_ADDRESS_W, 0); 762 for (i = 255; i >= 0 ; i--) { 763 vgaw(ba, VDAC_DATA, i); 764 vgaw(ba, VDAC_DATA, i); 765 vgaw(ba, VDAC_DATA, i); 766 } 767 768 /* GFx hardware cursor off */ 769 WCrt(ba, CRT_ID_HWGC_MODE, 0x00); 770 771 /* Set first to 4 MB, so test will work */ 772 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); 773 774 /* find *correct* fbsize of z3 board */ 775 if (cv_has_4mb((volatile caddr_t)cv_boardaddr + 0x01400000)) { 776 cv_fbsize = 1024 * 1024 * 4; 777 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */ 778 } else { 779 cv_fbsize = 1024 * 1024 * 2; 780 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */ 781 } 782 783 /* Initialize graphics engine */ 784 GfxBusyWait(ba); 785 vgaw16(ba, ECR_FRGD_MIX, 0x27); 786 vgaw16(ba, ECR_BKGD_MIX, 0x07); 787 788 vgaw16(ba, ECR_READ_REG_DATA, 0x1000); 789 delay(200000); 790 vgaw16(ba, ECR_READ_REG_DATA, 0x2000); 791 GfxBusyWait(ba); 792 vgaw16(ba, ECR_READ_REG_DATA, 0x3fff); 793 GfxBusyWait(ba); 794 delay(200000); 795 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff); 796 GfxBusyWait(ba); 797 798 vgaw16(ba, ECR_BITPLANE_WRITE_MASK, ~0); 799 800 GfxBusyWait (ba); 801 vgaw16(ba, ECR_READ_REG_DATA, 0xe000); 802 vgaw16(ba, ECR_CURRENT_Y_POS2, 0x00); 803 vgaw16(ba, ECR_CURRENT_X_POS2, 0x00); 804 vgaw16(ba, ECR_READ_REG_DATA, 0xa000); 805 vgaw16(ba, ECR_DEST_Y__AX_STEP, 0x00); 806 vgaw16(ba, ECR_DEST_Y2__AX_STEP2, 0x00); 807 vgaw16(ba, ECR_DEST_X__DIA_STEP, 0x00); 808 vgaw16(ba, ECR_DEST_X2__DIA_STEP2, 0x00); 809 vgaw16(ba, ECR_SHORT_STROKE, 0x00); 810 vgaw16(ba, ECR_DRAW_CMD, 0x01); 811 GfxBusyWait (ba); 812 813 /* It ain't easy to write here, so let's do it again */ 814 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff); 815 816 vgaw16(ba, ECR_BKGD_COLOR, 0x01); 817 vgaw16(ba, ECR_FRGD_COLOR, 0x00); 818 819 /* Enable Video Display (Set Bit 5) */ 820 WAttr(ba, 0x33, 0); 821 822 gi = &gp->g_display; 823 gi->gd_regaddr = (caddr_t) kvtop (ba); 824 gi->gd_regsize = 64 * 1024; 825 gi->gd_fbaddr = (caddr_t) kvtop (gp->g_fbkva); 826 gi->gd_fbsize = cv_fbsize; 827 } 828 829 830 int 831 cv_getvmode(gp, vm) 832 struct grf_softc *gp; 833 struct grfvideo_mode *vm; 834 { 835 struct grfvideo_mode *gv; 836 837 #ifdef CV64CONSOLE 838 /* Handle grabbing console mode */ 839 if (vm->mode_num == 255) { 840 bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode)); 841 /* XXX so grfconfig can tell us the correct text dimensions. */ 842 vm->depth = cvconsole_mode.fy; 843 } else 844 #endif 845 { 846 if (vm->mode_num == 0) 847 vm->mode_num = (monitor_current - monitor_def) + 1; 848 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max) 849 return (EINVAL); 850 gv = monitor_def + (vm->mode_num - 1); 851 if (gv->mode_num == 0) 852 return (EINVAL); 853 854 bcopy(gv, vm, sizeof(struct grfvideo_mode)); 855 } 856 857 /* adjust internal values to pixel values */ 858 859 vm->hblank_start *= 8; 860 vm->hsync_start *= 8; 861 vm->hsync_stop *= 8; 862 vm->htotal *= 8; 863 864 return (0); 865 } 866 867 868 int 869 cv_setvmode(gp, mode) 870 struct grf_softc *gp; 871 unsigned mode; 872 { 873 874 if (!mode || (mode > monitor_def_max) || 875 monitor_def[mode - 1].mode_num == 0) 876 return (EINVAL); 877 878 monitor_current = monitor_def + (mode - 1); 879 880 return (0); 881 } 882 883 884 int 885 cv_blank(gp, on) 886 struct grf_softc *gp; 887 int *on; 888 { 889 volatile caddr_t ba; 890 891 ba = gp->g_regkva; 892 gfx_on_off(*on > 0 ? 0 : 1, ba); 893 return (0); 894 } 895 896 897 /* 898 * Change the mode of the display. 899 * Return a UNIX error number or 0 for success. 900 */ 901 int 902 cv_mode(gp, cmd, arg, a2, a3) 903 register struct grf_softc *gp; 904 u_long cmd; 905 void *arg; 906 u_long a2; 907 int a3; 908 { 909 int error; 910 911 switch (cmd) { 912 case GM_GRFON: 913 error = cv_load_mon (gp, 914 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL; 915 return (error); 916 917 case GM_GRFOFF: 918 #ifndef CV64CONSOLE 919 cvscreen(1, gp->g_regkva - 0x02000000); 920 #else 921 cv_load_mon(gp, &cvconsole_mode); 922 ite_reinit(gp->g_itedev); 923 #endif 924 return (0); 925 926 case GM_GRFCONFIG: 927 return (0); 928 929 case GM_GRFGETVMODE: 930 return (cv_getvmode (gp, (struct grfvideo_mode *) arg)); 931 932 case GM_GRFSETVMODE: 933 error = cv_setvmode (gp, *(unsigned *) arg); 934 if (!error && (gp->g_flags & GF_GRFON)) 935 cv_load_mon(gp, 936 (struct grfcvtext_mode *) monitor_current); 937 return (error); 938 939 case GM_GRFGETNUMVM: 940 *(int *)arg = monitor_def_max; 941 return (0); 942 943 case GM_GRFIOCTL: 944 return (cv_ioctl (gp, a2, arg)); 945 946 default: 947 break; 948 } 949 950 return (EINVAL); 951 } 952 953 954 int 955 cv_ioctl (gp, cmd, data) 956 register struct grf_softc *gp; 957 u_long cmd; 958 void *data; 959 { 960 switch (cmd) { 961 #ifndef CV_NO_HARDWARE_CURSOR 962 case GRFIOCGSPRITEPOS: 963 return(cv_getspritepos (gp, (struct grf_position *) data)); 964 965 case GRFIOCSSPRITEPOS: 966 return(cv_setspritepos (gp, (struct grf_position *) data)); 967 968 case GRFIOCSSPRITEINF: 969 return(cv_setspriteinfo (gp, (struct grf_spriteinfo *) data)); 970 971 case GRFIOCGSPRITEINF: 972 return(cv_getspriteinfo (gp, (struct grf_spriteinfo *) data)); 973 974 case GRFIOCGSPRITEMAX: 975 return(cv_getspritemax (gp, (struct grf_position *) data)); 976 #else /* !CV_NO_HARDWARE_CURSOR */ 977 case GRFIOCGSPRITEPOS: 978 case GRFIOCSSPRITEPOS: 979 case GRFIOCSSPRITEINF: 980 case GRFIOCGSPRITEINF: 981 case GRFIOCGSPRITEMAX: 982 break; 983 #endif /* !CV_NO_HARDWARE_CURSOR */ 984 985 case GRFIOCGETCMAP: 986 return (cv_getcmap (gp, (struct grf_colormap *) data)); 987 988 case GRFIOCPUTCMAP: 989 return (cv_putcmap (gp, (struct grf_colormap *) data)); 990 991 case GRFIOCBITBLT: 992 break; 993 994 case GRFTOGGLE: 995 return (cv_toggle (gp)); 996 997 case GRFIOCSETMON: 998 return (cv_setmonitor (gp, (struct grfvideo_mode *)data)); 999 1000 case GRFIOCBLANK: 1001 return (cv_blank (gp, (int *)data)); 1002 } 1003 return (EINVAL); 1004 } 1005 1006 1007 int 1008 cv_setmonitor(gp, gv) 1009 struct grf_softc *gp; 1010 struct grfvideo_mode *gv; 1011 { 1012 struct grfvideo_mode *md; 1013 1014 if (!cv_mondefok(gv)) 1015 return (EINVAL); 1016 1017 #ifdef CV64CONSOLE 1018 /* handle interactive setting of console mode */ 1019 if (gv->mode_num == 255) { 1020 bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode)); 1021 cvconsole_mode.gv.hblank_start /= 8; 1022 cvconsole_mode.gv.hsync_start /= 8; 1023 cvconsole_mode.gv.hsync_stop /= 8; 1024 cvconsole_mode.gv.htotal /= 8; 1025 cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy; 1026 cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx; 1027 if (!(gp->g_flags & GF_GRFON)) 1028 cv_load_mon(gp, &cvconsole_mode); 1029 ite_reinit(gp->g_itedev); 1030 return (0); 1031 } 1032 #endif 1033 1034 md = monitor_def + (gv->mode_num - 1); 1035 1036 /* 1037 * Prevent user from crashing the system by using 1038 * grfconfig while in X 1039 */ 1040 if (gp->g_flags & GF_GRFON) 1041 if (md == monitor_current) { 1042 printf("grfcv: Changing the used mode not allowed!\n"); 1043 return (EINVAL); 1044 } 1045 1046 bcopy(gv, md, sizeof(struct grfvideo_mode)); 1047 1048 /* adjust pixel oriented values to internal rep. */ 1049 1050 md->hblank_start /= 8; 1051 md->hsync_start /= 8; 1052 md->hsync_stop /= 8; 1053 md->htotal /= 8; 1054 1055 return (0); 1056 } 1057 1058 1059 int 1060 cv_getcmap(gfp, cmap) 1061 struct grf_softc *gfp; 1062 struct grf_colormap *cmap; 1063 { 1064 volatile caddr_t ba; 1065 u_char red[256], green[256], blue[256], *rp, *gp, *bp; 1066 short x; 1067 int error; 1068 1069 ba = gfp->g_regkva; 1070 if (cmap->count == 0 || cmap->index >= 256) 1071 return (0); 1072 1073 if (cmap->index + cmap->count > 256) 1074 cmap->count = 256 - cmap->index; 1075 1076 /* first read colors out of the chip, then copyout to userspace */ 1077 vgaw (ba, VDAC_ADDRESS_W, cmap->index); 1078 x = cmap->count - 1; 1079 1080 rp = red + cmap->index; 1081 gp = green + cmap->index; 1082 bp = blue + cmap->index; 1083 1084 do { 1085 *rp++ = vgar (ba, VDAC_DATA) << 2; 1086 *gp++ = vgar (ba, VDAC_DATA) << 2; 1087 *bp++ = vgar (ba, VDAC_DATA) << 2; 1088 } while (x-- > 0); 1089 1090 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count)) 1091 && !(error = copyout (green + cmap->index, cmap->green, cmap->count)) 1092 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count))) 1093 return (0); 1094 1095 return (error); 1096 } 1097 1098 1099 int 1100 cv_putcmap(gfp, cmap) 1101 struct grf_softc *gfp; 1102 struct grf_colormap *cmap; 1103 { 1104 volatile caddr_t ba; 1105 u_char red[256], green[256], blue[256], *rp, *gp, *bp; 1106 short x; 1107 int error; 1108 1109 ba = gfp->g_regkva; 1110 if (cmap->count == 0 || cmap->index >= 256) 1111 return (0); 1112 1113 if (cmap->index + cmap->count > 256) 1114 cmap->count = 256 - cmap->index; 1115 1116 /* first copy the colors into kernelspace */ 1117 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count)) 1118 && !(error = copyin (cmap->green, green + cmap->index, cmap->count)) 1119 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) { 1120 vgaw (ba, VDAC_ADDRESS_W, cmap->index); 1121 x = cmap->count - 1; 1122 1123 rp = red + cmap->index; 1124 gp = green + cmap->index; 1125 bp = blue + cmap->index; 1126 1127 do { 1128 vgaw (ba, VDAC_DATA, *rp++ >> 2); 1129 vgaw (ba, VDAC_DATA, *gp++ >> 2); 1130 vgaw (ba, VDAC_DATA, *bp++ >> 2); 1131 } while (x-- > 0); 1132 return (0); 1133 } else 1134 return (error); 1135 } 1136 1137 1138 int 1139 cv_toggle(gp) 1140 struct grf_softc *gp; 1141 { 1142 volatile caddr_t ba; 1143 1144 ba = gp->g_regkva; 1145 #ifndef CV64CONSOLE 1146 cv_pass_toggle = 1; 1147 #endif /* !CV64CONSOLE */ 1148 1149 if (cv_pass_toggle) { 1150 cvscreen(0, ba - 0x02000000); 1151 cv_pass_toggle = 0; 1152 } else { 1153 cvscreen(1, ba - 0x02000000); 1154 cv_pass_toggle = 1; 1155 } 1156 1157 return (0); 1158 } 1159 1160 1161 int 1162 cv_mondefok(gv) 1163 struct grfvideo_mode *gv; 1164 { 1165 unsigned long maxpix; 1166 1167 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) { 1168 if (gv->mode_num != 255 || gv->depth != 4) 1169 return (0); 1170 } 1171 1172 switch(gv->depth) { 1173 case 4: 1174 maxpix = MAXPIXELCLOCK - 55000000; 1175 break; 1176 case 8: 1177 maxpix = MAXPIXELCLOCK; 1178 break; 1179 case 15: 1180 case 16: 1181 #ifdef CV_AGGRESSIVE_TIMING 1182 maxpix = MAXPIXELCLOCK - 35000000; 1183 #else 1184 maxpix = MAXPIXELCLOCK - 55000000; 1185 #endif 1186 break; 1187 case 24: 1188 case 32: 1189 #ifdef CV_AGGRESSIVE_TIMING 1190 maxpix = MAXPIXELCLOCK - 75000000; 1191 #else 1192 maxpix = MAXPIXELCLOCK - 85000000; 1193 #endif 1194 break; 1195 default: 1196 printf("grfcv: Illegal depth in mode %d\n", 1197 (int) gv->mode_num); 1198 return (0); 1199 } 1200 1201 if (gv->pixel_clock > maxpix) { 1202 printf("grfcv: Pixelclock too high in mode %d\n", 1203 (int) gv->mode_num); 1204 return (0); 1205 } 1206 1207 if (gv->mode_num == 255) { /* console mode */ 1208 if ((gv->disp_width / 8) > MAXCOLS) { 1209 printf ("grfcv: Too many columns for console\n"); 1210 return (0); 1211 } else if ((gv->disp_height / S3FONTY) > MAXROWS) { 1212 printf ("grfcv: Too many rows for console\n"); 1213 return (0); 1214 } 1215 } 1216 1217 if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) { 1218 printf("grfcv: sync-on-green is not supported\n"); 1219 return (0); 1220 } 1221 1222 return (1); 1223 } 1224 1225 1226 int 1227 cv_load_mon(gp, md) 1228 struct grf_softc *gp; 1229 struct grfcvtext_mode *md; 1230 { 1231 struct grfvideo_mode *gv; 1232 struct grfinfo *gi; 1233 volatile caddr_t ba, fb; 1234 unsigned short mnr; 1235 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, 1236 VSE, VT; 1237 int cr50, sr15, sr18, clock_mode, test; 1238 int m, n; /* For calc'ing display FIFO */ 1239 int tfillm, temptym; /* FIFO fill and empty mclk's */ 1240 int hmul; /* Multiplier for hor. Values */ 1241 unsigned char hvsync_pulse; 1242 char TEXT, CONSOLE; 1243 1244 /* identity */ 1245 gv = &md->gv; 1246 1247 TEXT = (gv->depth == 4); 1248 CONSOLE = (gv->mode_num == 255); 1249 1250 if (!cv_mondefok(gv)) { 1251 printf("grfcv: Monitor definition not ok\n"); 1252 return (0); 1253 } 1254 1255 ba = gp->g_regkva; 1256 fb = gp->g_fbkva; 1257 1258 /* Disable Interrupts */ 1259 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1); 1260 test &= ~0x10; 1261 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test); 1262 1263 /* turn gfx off, don't mess up the display */ 1264 gfx_on_off(1, ba); 1265 1266 /* provide all needed information in grf device-independant locations */ 1267 gp->g_data = (caddr_t) gv; 1268 gi = &gp->g_display; 1269 gi->gd_colors = 1 << gv->depth; 1270 gi->gd_planes = gv->depth; 1271 gi->gd_fbwidth = gv->disp_width; 1272 gi->gd_fbheight = gv->disp_height; 1273 gi->gd_fbx = 0; 1274 gi->gd_fby = 0; 1275 if (CONSOLE) { 1276 gi->gd_dwidth = md->fx * md->cols; 1277 gi->gd_dheight = md->fy * md->rows; 1278 } else { 1279 gi->gd_dwidth = gv->disp_width; 1280 gi->gd_dheight = gv->disp_height; 1281 } 1282 gi->gd_dx = 0; 1283 gi->gd_dy = 0; 1284 1285 /* get display mode parameters */ 1286 switch (gv->depth) { 1287 case 15: 1288 case 16: 1289 hmul = 2; 1290 break; 1291 default: 1292 hmul = 1; 1293 break; 1294 } 1295 1296 HBS = gv->hblank_start * hmul; 1297 HSS = gv->hsync_start * hmul; 1298 HSE = gv->hsync_stop * hmul; 1299 HBE = gv->htotal * hmul - 6; 1300 HT = gv->htotal * hmul - 5; 1301 VBS = gv->vblank_start - 1; 1302 VSS = gv->vsync_start; 1303 VSE = gv->vsync_stop; 1304 VBE = gv->vtotal - 3; 1305 VT = gv->vtotal - 2; 1306 1307 /* Disable enhanced Mode for text display */ 1308 1309 vgaw(ba, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31)); 1310 1311 if (TEXT) 1312 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1; 1313 else 1314 HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/ 1315 VDE = gv->disp_height - 1; 1316 1317 /* adjustments */ 1318 1319 if (gv->disp_flags & GRF_FLAGS_LACE) { 1320 VDE = VDE / 2; 1321 VBS = VBS / 2; 1322 VSS = VSS / 2; 1323 VSE = VSE / 2; 1324 VBE = VBE / 2; 1325 VT = VT / 2; 1326 } 1327 1328 /* Horizontal/Vertical Sync Pulse */ 1329 /* 1330 * GREG_MISC_OUTPUT_W Register: 1331 * bit description (0/1) 1332 * 0 Monochrome/Color emulation 1333 * 1 Disable/Enable access of the display memory from the CPU 1334 * 5 Select the low/high 64K page of memory 1335 * 6 Select a positive/negative horizontal retrace sync pulse 1336 * 7 Select a positive/negative vertical retrace sync pulse 1337 */ 1338 hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R); 1339 if (gv->disp_flags & GRF_FLAGS_PHSYNC) 1340 hvsync_pulse &= ~0x40; 1341 else 1342 hvsync_pulse |= 0x40; 1343 if (gv->disp_flags & GRF_FLAGS_PVSYNC) 1344 hvsync_pulse &= ~0x80; 1345 else 1346 hvsync_pulse |= 0x80; 1347 vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse); 1348 1349 /* GFX hardware cursor off */ 1350 WCrt(ba, CRT_ID_HWGC_MODE, 0x00); 1351 WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00); 1352 1353 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e); 1354 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00); 1355 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff); 1356 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); 1357 1358 /* Set clock */ 1359 1360 mnr = cv_compute_clock(gv->pixel_clock); 1361 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8)); 1362 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF)); 1363 1364 /* load display parameters into board */ 1365 1366 WCrt(ba, CRT_ID_EXT_HOR_OVF, 1367 ((HT & 0x100) ? 0x01 : 0x00) | 1368 ((HDE & 0x100) ? 0x02 : 0x00) | 1369 ((HBS & 0x100) ? 0x04 : 0x00) | 1370 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */ 1371 ((HSS & 0x100) ? 0x10 : 0x00) | 1372 /* ((HSE & 0x20) ? 0x20 : 0x00) | */ 1373 (((HT-5) & 0x100) ? 0x40 : 0x00) ); 1374 1375 WCrt(ba, CRT_ID_EXT_VER_OVF, 1376 0x40 | /* Line compare */ 1377 ((VT & 0x400) ? 0x01 : 0x00) | 1378 ((VDE & 0x400) ? 0x02 : 0x00) | 1379 ((VBS & 0x400) ? 0x04 : 0x00) | 1380 ((VSS & 0x400) ? 0x10 : 0x00) ); 1381 1382 WCrt(ba, CRT_ID_HOR_TOTAL, HT); 1383 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5); 1384 1385 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE)); 1386 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS); 1387 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80)); 1388 WCrt(ba, CRT_ID_START_HOR_RETR, HSS); 1389 WCrt(ba, CRT_ID_END_HOR_RETR, 1390 (HSE & 0x1f) | 1391 ((HBE & 0x20) ? 0x80 : 0x00) ); 1392 WCrt(ba, CRT_ID_VER_TOTAL, VT); 1393 WCrt(ba, CRT_ID_OVERFLOW, 1394 0x10 | 1395 ((VT & 0x100) ? 0x01 : 0x00) | 1396 ((VDE & 0x100) ? 0x02 : 0x00) | 1397 ((VSS & 0x100) ? 0x04 : 0x00) | 1398 ((VBS & 0x100) ? 0x08 : 0x00) | 1399 ((VT & 0x200) ? 0x20 : 0x00) | 1400 ((VDE & 0x200) ? 0x40 : 0x00) | 1401 ((VSS & 0x200) ? 0x80 : 0x00) ); 1402 1403 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 1404 0x40 | /* TEXT ? 0x00 ??? */ 1405 ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) | 1406 ((VBS & 0x200) ? 0x20 : 0x00) | 1407 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00)); 1408 1409 WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3); 1410 1411 /* text cursor */ 1412 1413 if (TEXT) { 1414 #if CV_ULCURSOR 1415 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2); 1416 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1); 1417 #else 1418 WCrt(ba, CRT_ID_CURSOR_START, 0x00); 1419 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f); 1420 #endif 1421 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f); 1422 1423 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00); 1424 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00); 1425 } 1426 1427 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00); 1428 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00); 1429 1430 WCrt(ba, CRT_ID_START_VER_RETR, VSS); 1431 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f)); 1432 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE); 1433 WCrt(ba, CRT_ID_START_VER_BLANK, VBS); 1434 WCrt(ba, CRT_ID_END_VER_BLANK, VBE); 1435 1436 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff); 1437 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2); 1438 WCrt(ba, CRT_ID_LACE_CONTROL, 1439 ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x20 : 0x00)); 1440 1441 WGfx(ba, GCT_ID_GRAPHICS_MODE, 1442 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40)); 1443 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01)); 1444 1445 WSeq (ba, SEQ_ID_MEMORY_MODE, 1446 ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02)); 1447 1448 vgaw(ba, VDAC_MASK, 0xff); 1449 1450 /* Blank border */ 1451 test = RCrt(ba, CRT_ID_BACKWAD_COMP_2); 1452 WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20)); 1453 1454 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); 1455 sr15 &= ~0x10; 1456 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL); 1457 sr18 &= ~0x80; 1458 clock_mode = 0x00; 1459 cr50 = 0x00; 1460 1461 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2); 1462 test &= 0xd; 1463 1464 /* clear roxxler byte-swapping... */ 1465 cv_write_port(0x0040, cv_boardaddr); 1466 cv_write_port(0x0020, cv_boardaddr); 1467 1468 switch (gv->depth) { 1469 case 1: 1470 case 4: /* text */ 1471 HDE = gv->disp_width / 16; 1472 break; 1473 case 8: 1474 if (gv->pixel_clock > 80000000) { 1475 clock_mode = 0x10 | 0x02; 1476 sr15 |= 0x10; 1477 sr18 |= 0x80; 1478 } 1479 HDE = gv->disp_width / 8; 1480 cr50 |= 0x00; 1481 break; 1482 case 15: 1483 cv_write_port (0x8020, cv_boardaddr); 1484 clock_mode = 0x30; 1485 HDE = gv->disp_width / 4; 1486 cr50 |= 0x10; 1487 break; 1488 case 16: 1489 cv_write_port (0x8020, cv_boardaddr); 1490 clock_mode = 0x50; 1491 HDE = gv->disp_width / 4; 1492 cr50 |= 0x10; 1493 break; 1494 case 24: /* this is really 32 Bit on CV64 */ 1495 case 32: 1496 cv_write_port(0x8040, cv_boardaddr); 1497 clock_mode = 0xd0; 1498 HDE = (gv->disp_width / 2); 1499 cr50 |= 0x30; 1500 break; 1501 } 1502 1503 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test); 1504 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15); 1505 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18); 1506 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE); 1507 1508 WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35)); 1509 1510 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2); 1511 test &= ~0x30; 1512 /* HDE Overflow in bits 4-5 */ 1513 test |= (HDE >> 4) & 0x30; 1514 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test); 1515 1516 /* Set up graphics engine */ 1517 switch (gv->disp_width) { 1518 case 1024: 1519 cr50 |= 0x00; 1520 break; 1521 case 640: 1522 cr50 |= 0x40; 1523 break; 1524 case 800: 1525 cr50 |= 0x80; 1526 break; 1527 case 1280: 1528 cr50 |= 0xc0; 1529 break; 1530 case 1152: 1531 cr50 |= 0x01; 1532 break; 1533 case 1600: 1534 cr50 |= 0x81; 1535 break; 1536 default: /* XXX The Xserver has to handle this */ 1537 break; 1538 } 1539 1540 WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50); 1541 1542 delay(100000); 1543 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41)); 1544 delay(100000); 1545 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 1546 (gv->depth == 1) ? 0x01 : 0x0f); 1547 delay(100000); 1548 1549 /* 1550 * M-Parameter of Display FIFO 1551 * This is dependant on the pixel clock and the memory clock. 1552 * The FIFO filling bandwidth is 240 MHz and the FIFO is 96 Byte wide. 1553 * Then the time to fill the FIFO is tfill = (96/240000000) sec, the time 1554 * to empty the FIFO is tempty = (96/pixelclock) sec. 1555 * Then the M parameter maximum is ((tempty-tfill)*cv_memclk-9)/2. 1556 * This seems to be logical, ain't it? 1557 * Remember: We have to use integer arithmetics :( 1558 * Divide by 1000 to prevent overflows. 1559 */ 1560 1561 tfillm = (96 * (cv_memclk/1000))/240000; 1562 1563 switch(gv->depth) { 1564 case 32: 1565 case 24: 1566 temptym = (24 * (cv_memclk/1000)) / (gv->pixel_clock/1000); 1567 break; 1568 case 15: 1569 case 16: 1570 temptym = (48 * (cv_memclk/1000)) / (gv->pixel_clock/1000); 1571 break; 1572 case 4: 1573 temptym = (192 * (cv_memclk/1000)) / (gv->pixel_clock/1000); 1574 break; 1575 default: 1576 temptym = (96 * (cv_memclk/1000)) / (gv->pixel_clock/1000); 1577 break; 1578 } 1579 1580 m = (temptym - tfillm - 9) / 2; 1581 if (m < 0) 1582 m = 0; /* prevent underflow */ 1583 m = (m & 0x1f) << 3; 1584 if (m < 0x18) 1585 m = 0x18; 1586 n = 0xff; 1587 1588 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m); 1589 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n); 1590 delay(10000); 1591 1592 /* text initialization */ 1593 1594 if (TEXT) { 1595 cv_inittextmode(gp); 1596 } 1597 1598 if (CONSOLE) { 1599 int i; 1600 vgaw(ba, VDAC_ADDRESS_W, 0); 1601 for (i = 0; i < 16; i++) { 1602 vgaw(ba, VDAC_DATA, cvconscolors[i][0]); 1603 vgaw(ba, VDAC_DATA, cvconscolors[i][1]); 1604 vgaw(ba, VDAC_DATA, cvconscolors[i][2]); 1605 } 1606 } 1607 1608 /* Set display enable flag */ 1609 WAttr(ba, 0x33, 0); 1610 1611 /* turn gfx on again */ 1612 gfx_on_off(0, ba); 1613 1614 /* enable interrupts */ 1615 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1); 1616 test |= 0x10; 1617 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test); 1618 1619 test = RCrt(ba, CRT_ID_END_VER_RETR); 1620 test &= ~0x20; 1621 WCrt(ba, CRT_ID_END_VER_RETR, test); 1622 test &= ~0x10; 1623 WCrt(ba, CRT_ID_END_VER_RETR, test); 1624 test |= 0x10; 1625 WCrt(ba, CRT_ID_END_VER_RETR, test); 1626 #ifndef CV_NO_HARDWARE_CURSOR 1627 cv_setup_hwc(gp); 1628 #endif 1629 1630 /* Pass-through */ 1631 cvscreen(0, ba - 0x02000000); 1632 1633 return (1); 1634 } 1635 1636 1637 void 1638 cv_inittextmode(gp) 1639 struct grf_softc *gp; 1640 { 1641 struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data; 1642 volatile caddr_t ba, fb; 1643 unsigned char *c, *f, y; 1644 unsigned short z; 1645 1646 ba = gp->g_regkva; 1647 fb = gp->g_fbkva; 1648 1649 /* load text font into beginning of display memory. 1650 * Each character cell is 32 bytes long (enough for 4 planes) 1651 * In linear adressing text mode, the memory is organized 1652 * so, that the Bytes of all 4 planes are interleaved. 1653 * 1st byte plane 0, 1st byte plane 1, 1st byte plane 2, 1654 * 1st byte plane 3, 2nd byte plane 0, 2nd byte plane 1,... 1655 * The font is loaded in plane 2. 1656 */ 1657 1658 c = (unsigned char *) fb; 1659 1660 /* clear screen */ 1661 for (z = 0; z < tm->cols * tm->rows * 3; z++) { 1662 *c++ = 0x20; 1663 *c++ = 0x07; 1664 *c++ = 0; 1665 *c++ = 0; 1666 } 1667 1668 c = (unsigned char *) (fb) + (32 * tm->fdstart * 4 + 2); 1669 f = tm->fdata; 1670 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy) * 4) 1671 for (y = 0; y < tm->fy; y++) { 1672 *c = *f++; 1673 c += 4; 1674 } 1675 1676 /* print out a little init msg */ 1677 c = (unsigned char *)(fb) + (tm->cols - 6) * 4; 1678 *c++ = 'C'; 1679 *c++ = 0x0a; 1680 c +=2; 1681 *c++ = 'V'; 1682 *c++ = 0x0b; 1683 c +=2; 1684 *c++ = '6'; 1685 *c++ = 0x0c; 1686 c +=2; 1687 *c++ = '4'; 1688 *c++ = 0x0d; 1689 } 1690 1691 1692 static __inline void 1693 cv_write_port(bits, BoardAddr) 1694 unsigned short bits; 1695 volatile caddr_t BoardAddr; 1696 { 1697 volatile caddr_t addr; 1698 static unsigned char CVPortBits = 0; /* mirror port bits here */ 1699 1700 addr = BoardAddr + 0x40001; 1701 if (bits & 0x8000) 1702 CVPortBits |= bits & 0xFF; /* Set bits */ 1703 else { 1704 bits = bits & 0xFF; 1705 bits = (~bits) & 0xFF ; 1706 CVPortBits &= bits; /* Clear bits */ 1707 } 1708 1709 *addr = CVPortBits; 1710 } 1711 1712 1713 /* 1714 * Monitor Switch 1715 * 0 = CyberVision Signal 1716 * 1 = Amiga Signal, 1717 * ba = boardaddr 1718 */ 1719 static __inline void 1720 cvscreen(toggle, ba) 1721 int toggle; 1722 volatile caddr_t ba; 1723 { 1724 1725 if (toggle == 1) 1726 cv_write_port (0x10, ba); 1727 else 1728 cv_write_port (0x8010, ba); 1729 } 1730 1731 1732 /* 0 = on, 1= off */ 1733 /* ba= registerbase */ 1734 static __inline void 1735 gfx_on_off(toggle, ba) 1736 int toggle; 1737 volatile caddr_t ba; 1738 { 1739 int r; 1740 1741 toggle &= 0x1; 1742 toggle = toggle << 5; 1743 1744 r = RSeq(ba, SEQ_ID_CLOCKING_MODE); 1745 r &= ~0x20; /* set Bit 5 to 0 */ 1746 1747 WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle); 1748 } 1749 1750 1751 #ifndef CV_NO_HARDWARE_CURSOR 1752 1753 static unsigned char cv_hotx = 0, cv_hoty = 0; 1754 static char cv_cursor_on = 0; 1755 1756 /* Hardware Cursor handling routines */ 1757 1758 int 1759 cv_getspritepos(gp, pos) 1760 struct grf_softc *gp; 1761 struct grf_position *pos; 1762 { 1763 int hi,lo; 1764 volatile caddr_t ba = gp->g_regkva; 1765 1766 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI); 1767 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO); 1768 1769 pos->y = (hi << 8) + lo; 1770 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI); 1771 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO); 1772 pos->x = (hi << 8) + lo; 1773 return (0); 1774 } 1775 1776 1777 int 1778 cv_setspritepos(gp, pos) 1779 struct grf_softc *gp; 1780 struct grf_position *pos; 1781 { 1782 volatile caddr_t ba = gp->g_regkva; 1783 short x, y; 1784 static short savex, savey; 1785 short xoff, yoff; 1786 1787 if (pos) { 1788 x = pos->x; 1789 y = pos->y; 1790 savex = x; 1791 savey= y; 1792 } else { /* restore cursor */ 1793 x = savex; 1794 y = savey; 1795 } 1796 x -= cv_hotx; 1797 y -= cv_hoty; 1798 if (x < 0) { 1799 xoff = ((-x) & 0xFE); 1800 x = 0; 1801 } else { 1802 xoff = 0; 1803 } 1804 1805 if (y < 0) { 1806 yoff = ((-y) & 0xFE); 1807 y = 0; 1808 } else { 1809 yoff = 0; 1810 } 1811 1812 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8)); 1813 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff)); 1814 1815 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO, (y & 0xff)); 1816 WCrt(ba, CRT_ID_HWGC_DSTART_X, xoff); 1817 WCrt(ba, CRT_ID_HWGC_DSTART_Y, yoff); 1818 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI, (y >> 8)); 1819 1820 return(0); 1821 } 1822 1823 static __inline short 1824 M2I(short val) { 1825 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8)); 1826 } 1827 1828 int 1829 cv_getspriteinfo(gp, info) 1830 struct grf_softc *gp; 1831 struct grf_spriteinfo *info; 1832 { 1833 volatile caddr_t ba, fb; 1834 1835 ba = gp->g_regkva; 1836 fb = gp->g_fbkva; 1837 1838 if (info->set & GRFSPRSET_ENABLE) 1839 info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01; 1840 1841 if (info->set & GRFSPRSET_POS) 1842 cv_getspritepos (gp, &info->pos); 1843 1844 #if 0 /* XXX */ 1845 if (info->set & GRFSPRSET_SHAPE) { 1846 u_char image[512], mask[512]; 1847 volatile u_long *hwp; 1848 u_char *imp, *mp; 1849 short row; 1850 info->size.x = 64; 1851 info->size.y = 64; 1852 for (row = 0, hwp = (u_long *)(fb + HWC_OFF), 1853 mp = mask, imp = image; 1854 row < 64; 1855 row++) { 1856 u_long bp10, bp20, bp11, bp21; 1857 bp10 = *hwp++; 1858 bp20 = *hwp++; 1859 bp11 = *hwp++; 1860 bp21 = *hwp++; 1861 M2I (bp10); 1862 M2I (bp20); 1863 M2I (bp11); 1864 M2I (bp21); 1865 *imp++ = (~bp10) & bp11; 1866 *imp++ = (~bp20) & bp21; 1867 *mp++ = (~bp10) | (bp10 & ~bp11); 1868 *mp++ = (~bp20) & (bp20 & ~bp21); 1869 } 1870 copyout (image, info->image, sizeof (image)); 1871 copyout (mask, info->mask, sizeof (mask)); 1872 } 1873 #endif 1874 return(0); 1875 } 1876 1877 1878 void 1879 cv_setup_hwc(gp) 1880 struct grf_softc *gp; 1881 { 1882 volatile caddr_t ba = gp->g_regkva; 1883 volatile caddr_t hwc; 1884 int test; 1885 1886 if (gp->g_display.gd_planes <= 4) 1887 cv_cursor_on = 0; /* don't enable hwc in text modes */ 1888 if (cv_cursor_on == 0) 1889 return; 1890 1891 /* reset colour stack */ 1892 #if 0 1893 test = RCrt(ba, CRT_ID_HWGC_MODE); 1894 asm volatile("nop"); 1895 #else 1896 /* do it in assembler, the above does't seem to work */ 1897 asm volatile ("moveb #0x45, %1@(0x3d4); \ 1898 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba)); 1899 #endif 1900 1901 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0); 1902 1903 hwc = ba + CRT_ADDRESS_W; 1904 *hwc = 0; 1905 *hwc = 0; 1906 1907 #if 0 1908 test = RCrt(ba, CRT_ID_HWGC_MODE); 1909 asm volatile("nop"); 1910 #else 1911 /* do it in assembler, the above does't seem to work */ 1912 asm volatile ("moveb #0x45, %1@(0x3d4); \ 1913 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba)); 1914 #endif 1915 switch (gp->g_display.gd_planes) { 1916 case 8: 1917 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0x1); 1918 *hwc = 1; 1919 break; 1920 default: 1921 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff); 1922 *hwc = 0xff; 1923 *hwc = 0xff; 1924 } 1925 1926 test = HWC_OFF / HWC_SIZE; 1927 WCrt (ba, CRT_ID_HWGC_START_AD_HI, (test >> 8)); 1928 WCrt (ba, CRT_ID_HWGC_START_AD_LO, (test & 0xff)); 1929 1930 WCrt (ba, CRT_ID_HWGC_DSTART_X , 0); 1931 WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0); 1932 1933 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10); /* Cursor X11 Mode */ 1934 /* 1935 * Put it into Windoze Mode or you'll see sometimes a white stripe 1936 * on the right side (in double clocking modes with a screen bigger 1937 * > 1023 pixels). 1938 */ 1939 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00); /* Cursor Windoze Mode */ 1940 1941 WCrt (ba, CRT_ID_HWGC_MODE, 0x01); 1942 } 1943 1944 1945 /* 1946 * This was the reason why you shouldn't use the HWC in the Kernel:( 1947 * Obsoleted now by use of interrupts :-) 1948 */ 1949 1950 #define VerticalRetraceWait(ba) \ 1951 { \ 1952 while (vgar(ba, GREG_INPUT_STATUS1_R) == 0x00) ; \ 1953 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x08) ; \ 1954 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x00) ; \ 1955 } 1956 1957 1958 int 1959 cv_setspriteinfo (gp, info) 1960 struct grf_softc *gp; 1961 struct grf_spriteinfo *info; 1962 { 1963 volatile caddr_t ba, fb; 1964 int depth = gp->g_display.gd_planes; 1965 1966 ba = gp->g_regkva; 1967 fb = gp->g_fbkva; 1968 1969 if (info->set & GRFSPRSET_SHAPE) { 1970 /* 1971 * For an explanation of these weird actions here, see above 1972 * when reading the shape. We set the shape directly into 1973 * the video memory, there's no reason to keep 1k on the 1974 * kernel stack just as template 1975 */ 1976 u_char *image, *mask; 1977 volatile u_short *hwp; 1978 u_char *imp, *mp; 1979 unsigned short row; 1980 1981 #ifdef CV_NO_INT 1982 /* Cursor off */ 1983 WCrt (ba, CRT_ID_HWGC_MODE, 0x00); 1984 1985 /* 1986 * The Trio64 crashes if the cursor data is written 1987 * while the cursor is displayed. 1988 * Sadly, turning the cursor off is not enough. 1989 * What we have to do is: 1990 * 1. Wait for vertical retrace, to make sure no-one 1991 * has moved the cursor in this sync period (because 1992 * another write then would have no effect, argh!). 1993 * 2. Move the cursor off-screen 1994 * 3. Another wait for v. retrace to make sure the cursor 1995 * is really off. 1996 * 4. Write the data, finally. 1997 * (thanks to Harald Koenig for this tip!) 1998 */ 1999 2000 /* 2001 * Remark 06/06/96: Update in interrupt obsoletes this, 2002 * but the warning should stay there! 2003 */ 2004 2005 VerticalRetraceWait(ba); 2006 2007 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_HI, 0x7); 2008 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_LO, 0xff); 2009 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_LO, 0xff); 2010 WCrt (ba, CRT_ID_HWGC_DSTART_X, 0x3f); 2011 WCrt (ba, CRT_ID_HWGC_DSTART_Y, 0x3f); 2012 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_HI, 0x7); 2013 #endif /* CV_NO_INT */ 2014 2015 if (info->size.y > 64) 2016 info->size.y = 64; 2017 if (info->size.x > 64) 2018 info->size.x = 64; 2019 if (info->size.x < 32) 2020 info->size.x = 32; 2021 2022 image = malloc(HWC_SIZE, M_TEMP, M_WAITOK); 2023 mask = image + HWC_SIZE/2; 2024 2025 copyin(info->image, image, info->size.y * info->size.x / 8); 2026 copyin(info->mask, mask, info->size.y * info->size.x / 8); 2027 2028 #ifdef CV_NO_INT 2029 hwp = (u_short *)(fb +HWC_OFF); 2030 2031 /* This is necessary in order not to crash the board */ 2032 VerticalRetraceWait(ba); 2033 #else /* CV_NO_INT */ 2034 hwp = (u_short *) cv_cursor_storage; 2035 #endif /* CV_NO_INT */ 2036 2037 /* 2038 * setting it is slightly more difficult, because we can't 2039 * force the application to not pass a *smaller* than 2040 * supported bitmap 2041 */ 2042 2043 for (row = 0, mp = mask, imp = image; 2044 row < info->size.y; row++) { 2045 u_short im1, im2, im3, im4, m1, m2, m3, m4; 2046 2047 m1 = ~(*(unsigned short *)mp); 2048 im1 = *(unsigned short *)imp & *(unsigned short *)mp; 2049 mp += 2; 2050 imp += 2; 2051 2052 m2 = ~(*(unsigned short *)mp); 2053 im2 = *(unsigned short *)imp & *(unsigned short *)mp; 2054 mp += 2; 2055 imp += 2; 2056 2057 if (info->size.x > 32) { 2058 m3 = ~(*(unsigned short *)mp); 2059 im3 = *(unsigned short *)imp & *(unsigned short *)mp; 2060 mp += 2; 2061 imp += 2; 2062 m4 = ~(*(unsigned short *)mp); 2063 im4 = *(unsigned short *)imp & *(unsigned short *)mp; 2064 mp += 2; 2065 imp += 2; 2066 } else { 2067 m3 = 0xffff; 2068 im3 = 0; 2069 m4 = 0xffff; 2070 im4 = 0; 2071 } 2072 2073 switch (depth) { 2074 case 8: 2075 *hwp++ = m1; 2076 *hwp++ = im1; 2077 *hwp++ = m2; 2078 *hwp++ = im2; 2079 *hwp++ = m3; 2080 *hwp++ = im3; 2081 *hwp++ = m4; 2082 *hwp++ = im4; 2083 break; 2084 case 15: 2085 case 16: 2086 *hwp++ = M2I(m1); 2087 *hwp++ = M2I(im1); 2088 *hwp++ = M2I(m2); 2089 *hwp++ = M2I(im2); 2090 *hwp++ = M2I(m3); 2091 *hwp++ = M2I(im3); 2092 *hwp++ = M2I(m4); 2093 *hwp++ = M2I(im4); 2094 break; 2095 case 24: 2096 case 32: 2097 *hwp++ = M2I(im1); 2098 *hwp++ = M2I(m1); 2099 *hwp++ = M2I(im2); 2100 *hwp++ = M2I(m2); 2101 *hwp++ = M2I(im3); 2102 *hwp++ = M2I(m3); 2103 *hwp++ = M2I(im4); 2104 *hwp++ = M2I(m4); 2105 break; 2106 } 2107 } 2108 2109 if (depth < 24) { 2110 for (; row < 64; row++) { 2111 *hwp++ = 0xffff; 2112 *hwp++ = 0x0000; 2113 *hwp++ = 0xffff; 2114 *hwp++ = 0x0000; 2115 *hwp++ = 0xffff; 2116 *hwp++ = 0x0000; 2117 *hwp++ = 0xffff; 2118 *hwp++ = 0x0000; 2119 } 2120 } else { 2121 for (; row < 64; row++) { 2122 *hwp++ = 0x0000; 2123 *hwp++ = 0xffff; 2124 *hwp++ = 0x0000; 2125 *hwp++ = 0xffff; 2126 *hwp++ = 0x0000; 2127 *hwp++ = 0xffff; 2128 *hwp++ = 0x0000; 2129 *hwp++ = 0xffff; 2130 } 2131 } 2132 2133 free(image, M_TEMP); 2134 /* cv_setup_hwc(gp); */ 2135 cv_hotx = info->hot.x; 2136 cv_hoty = info->hot.y; 2137 2138 #ifdef CV_NO_INT 2139 /* One must not write twice per vertical blank :-( */ 2140 VerticalRetraceWait(ba); 2141 cv_setspritepos (gp, &info->pos); 2142 #else /* CV_NO_INT */ 2143 cv_setspritepos (gp, &info->pos); 2144 curs_update_flag = 1; 2145 #endif /* CV_NO_INT */ 2146 } 2147 if (info->set & GRFSPRSET_CMAP) { 2148 volatile caddr_t hwc; 2149 int test; 2150 2151 /* reset colour stack */ 2152 test = RCrt(ba, CRT_ID_HWGC_MODE); 2153 asm volatile("nop"); 2154 switch (depth) { 2155 case 8: 2156 case 15: 2157 case 16: 2158 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0); 2159 hwc = ba + CRT_ADDRESS_W; 2160 *hwc = 0; 2161 break; 2162 case 32: 2163 case 24: 2164 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0); 2165 hwc = ba + CRT_ADDRESS_W; 2166 *hwc = 0; 2167 *hwc = 0; 2168 break; 2169 } 2170 2171 test = RCrt(ba, CRT_ID_HWGC_MODE); 2172 asm volatile("nop"); 2173 switch (depth) { 2174 case 8: 2175 WCrt (ba, CRT_ID_HWGC_BG_STACK, 1); 2176 hwc = ba + CRT_ADDRESS_W; 2177 *hwc = 1; 2178 break; 2179 case 15: 2180 case 16: 2181 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff); 2182 hwc = ba + CRT_ADDRESS_W; 2183 *hwc = 0xff; 2184 break; 2185 case 32: 2186 case 24: 2187 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff); 2188 hwc = ba + CRT_ADDRESS_W; 2189 *hwc = 0xff; 2190 *hwc = 0xff; 2191 break; 2192 } 2193 } 2194 2195 if (info->set & GRFSPRSET_ENABLE) { 2196 if (info->enable) { 2197 cv_cursor_on = 1; 2198 cv_setup_hwc(gp); 2199 /* WCrt(ba, CRT_ID_HWGC_MODE, 0x01); */ 2200 } else 2201 WCrt(ba, CRT_ID_HWGC_MODE, 0x00); 2202 } 2203 if (info->set & GRFSPRSET_POS) 2204 cv_setspritepos(gp, &info->pos); 2205 if (info->set & GRFSPRSET_HOT) { 2206 2207 cv_hotx = info->hot.x; 2208 cv_hoty = info->hot.y; 2209 cv_setspritepos (gp, &info->pos); 2210 } 2211 return(0); 2212 } 2213 2214 2215 int 2216 cv_getspritemax (gp, pos) 2217 struct grf_softc *gp; 2218 struct grf_position *pos; 2219 { 2220 2221 pos->x = 64; 2222 pos->y = 64; 2223 return(0); 2224 } 2225 2226 #endif /* !CV_NO_HARDWARE_CURSOR */ 2227 2228 #endif /* NGRFCV */ 2229