1 /*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ralph Campbell and Rick Macklem. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)xcfb.c 8.2 (Berkeley) 06/02/95 11 */ 12 13 /* 14 * Mach Operating System 15 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 16 * All Rights Reserved. 17 * 18 * Permission to use, copy, modify and distribute this software and its 19 * documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie the 36 * rights to redistribute these changes. 37 */ 38 /* 39 * devGraphics.c -- 40 * 41 * This file contains machine-dependent routines for the graphics device. 42 * 43 * Copyright (C) 1989 Digital Equipment Corporation. 44 * Permission to use, copy, modify, and distribute this software and 45 * its documentation for any purpose and without fee is hereby granted, 46 * provided that the above copyright notice appears in all copies. 47 * Digital Equipment Corporation makes no representations about the 48 * suitability of this software for any purpose. It is provided "as is" 49 * without express or implied warranty. 50 * 51 * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devGraphics.c, 52 * v 9.2 90/02/13 22:16:24 shirriff Exp $ SPRITE (DECWRL)"; 53 */ 54 55 #include <xcfb.h> 56 #include <dtop.h> 57 #if NXCFB > 0 58 #if NDTOP == 0 59 xcfb needs dtop device 60 #else 61 62 #include <sys/param.h> 63 #include <sys/time.h> 64 #include <sys/kernel.h> 65 #include <sys/ioctl.h> 66 #include <sys/file.h> 67 #include <sys/errno.h> 68 #include <sys/proc.h> 69 #include <sys/mman.h> 70 71 #include <vm/vm.h> 72 73 #include <machine/machConst.h> 74 #include <machine/pmioctl.h> 75 76 #include <pmax/pmax/maxine.h> 77 #include <pmax/pmax/cons.h> 78 #include <pmax/pmax/pmaxtype.h> 79 80 #include <pmax/dev/device.h> 81 #include <pmax/dev/xcfbreg.h> 82 #include <pmax/dev/dtopreg.h> 83 #include <pmax/dev/fbreg.h> 84 85 /* 86 * These need to be mapped into user space. 87 */ 88 struct fbuaccess xcfbu; 89 struct pmax_fb xcfbfb; 90 91 /* 92 * Forward references. 93 */ 94 static void xcfbScreenInit(); 95 static void xcfbLoadCursor(); 96 static void xcfbRestoreCursorColor(); 97 static void xcfbCursorColor(); 98 void xcfbPosCursor(); 99 static void xcfbInitColorMap(); 100 static void xcfbLoadColorMap(); 101 static u_int ims332_read_register(); 102 static void ims332_write_register(); 103 static void ims332_load_colormap_entry(); 104 static void ims332_video_off(); 105 static void ims332_video_on(); 106 107 void xcfbKbdEvent(), xcfbMouseEvent(), xcfbMouseButtons(); 108 extern void dtopKBDPutc(); 109 extern void (*dtopDivertXInput)(); 110 extern void (*dtopMouseEvent)(); 111 extern void (*dtopMouseButtons)(); 112 extern int pmax_boardtype; 113 extern u_short defCursor[32]; 114 extern struct consdev cn_tab; 115 116 int xcfbprobe(); 117 struct driver xcfbdriver = { 118 "xcfb", xcfbprobe, 0, 0, 119 }; 120 121 /* 122 * Test to see if device is present. 123 * Return true if found and initialized ok. 124 */ 125 /*ARGSUSED*/ 126 xcfbprobe(cp) 127 register struct pmax_ctlr *cp; 128 { 129 register struct pmax_fb *fp = &xcfbfb; 130 131 if (pmax_boardtype != DS_MAXINE) 132 return (0); 133 if (!fp->initialized && !xcfbinit()) 134 return (0); 135 printf("xcfb0 (color display)\n"); 136 return (1); 137 } 138 139 /*ARGSUSED*/ 140 xcfbopen(dev, flag) 141 dev_t dev; 142 int flag; 143 { 144 register struct pmax_fb *fp = &xcfbfb; 145 int s; 146 147 if (!fp->initialized) 148 return (ENXIO); 149 if (fp->GraphicsOpen) 150 return (EBUSY); 151 152 fp->GraphicsOpen = 1; 153 xcfbInitColorMap(); 154 /* 155 * Set up event queue for later 156 */ 157 fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ; 158 fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0; 159 fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 160 fp->fbu->scrInfo.qe.tcNext = 0; 161 fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time); 162 s = spltty(); 163 dtopDivertXInput = xcfbKbdEvent; 164 dtopMouseEvent = xcfbMouseEvent; 165 dtopMouseButtons = xcfbMouseButtons; 166 splx(s); 167 return (0); 168 } 169 170 /*ARGSUSED*/ 171 xcfbclose(dev, flag) 172 dev_t dev; 173 int flag; 174 { 175 register struct pmax_fb *fp = &xcfbfb; 176 int s; 177 178 if (!fp->GraphicsOpen) 179 return (EBADF); 180 181 fp->GraphicsOpen = 0; 182 xcfbInitColorMap(); 183 s = spltty(); 184 dtopDivertXInput = (void (*)())0; 185 dtopMouseEvent = (void (*)())0; 186 dtopMouseButtons = (void (*)())0; 187 splx(s); 188 xcfbScreenInit(); 189 bzero((caddr_t)fp->fr_addr, 1024 * 768); 190 xcfbPosCursor(fp->col * 8, fp->row * 15); 191 return (0); 192 } 193 194 /*ARGSUSED*/ 195 xcfbioctl(dev, cmd, data, flag, p) 196 dev_t dev; 197 u_long cmd; 198 caddr_t data; 199 struct proc *p; 200 { 201 register struct pmax_fb *fp = &xcfbfb; 202 int s; 203 204 switch (cmd) { 205 case QIOCGINFO: 206 return (fbmmap(fp, dev, data, p)); 207 208 case QIOCPMSTATE: 209 /* 210 * Set mouse state. 211 */ 212 fp->fbu->scrInfo.mouse = *(pmCursor *)data; 213 xcfbPosCursor(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y); 214 break; 215 216 case QIOCINIT: 217 /* 218 * Initialize the screen. 219 */ 220 xcfbScreenInit(); 221 break; 222 223 case QIOCKPCMD: 224 { 225 pmKpCmd *kpCmdPtr; 226 unsigned char *cp; 227 228 kpCmdPtr = (pmKpCmd *)data; 229 if (kpCmdPtr->nbytes == 0) 230 kpCmdPtr->cmd |= 0x80; 231 if (!fp->GraphicsOpen) 232 kpCmdPtr->cmd |= 1; 233 (*fp->KBDPutc)(fp->kbddev, (int)kpCmdPtr->cmd); 234 cp = &kpCmdPtr->par[0]; 235 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 236 if (kpCmdPtr->nbytes == 1) 237 *cp |= 0x80; 238 (*fp->KBDPutc)(fp->kbddev, (int)*cp); 239 } 240 break; 241 } 242 243 case QIOCADDR: 244 *(PM_Info **)data = &fp->fbu->scrInfo; 245 break; 246 247 case QIOWCURSOR: 248 xcfbLoadCursor((unsigned short *)data); 249 break; 250 251 case QIOWCURSORCOLOR: 252 xcfbCursorColor((unsigned int *)data); 253 break; 254 255 case QIOSETCMAP: 256 xcfbLoadColorMap((ColorMap *)data); 257 break; 258 259 case QIOKERNLOOP: 260 s = spltty(); 261 dtopDivertXInput = xcfbKbdEvent; 262 dtopMouseEvent = xcfbMouseEvent; 263 dtopMouseButtons = xcfbMouseButtons; 264 splx(s); 265 break; 266 267 case QIOKERNUNLOOP: 268 s = spltty(); 269 dtopDivertXInput = (void (*)())0; 270 dtopMouseEvent = (void (*)())0; 271 dtopMouseButtons = (void (*)())0; 272 splx(s); 273 break; 274 275 case QIOVIDEOON: 276 xcfbRestoreCursorColor(); 277 ims332_video_on(); 278 break; 279 280 case QIOVIDEOOFF: 281 ims332_video_off(); 282 break; 283 284 default: 285 printf("xcfb0: Unknown ioctl command %x\n", cmd); 286 return (EINVAL); 287 } 288 return (0); 289 } 290 291 /* 292 * Return the physical page number that corresponds to byte offset 'off'. 293 */ 294 /*ARGSUSED*/ 295 xcfbmap(dev, off, prot) 296 dev_t dev; 297 { 298 int len; 299 300 len = pmax_round_page(((vm_offset_t)&xcfbu & PGOFSET) + sizeof(xcfbu)); 301 if (off < len) 302 return pmax_btop(MACH_CACHED_TO_PHYS(&xcfbu) + off); 303 off -= len; 304 if (off >= xcfbfb.fr_size) 305 return (-1); 306 return pmax_btop(MACH_UNCACHED_TO_PHYS(xcfbfb.fr_addr) + off); 307 } 308 309 xcfbselect(dev, flag, p) 310 dev_t dev; 311 int flag; 312 struct proc *p; 313 { 314 struct pmax_fb *fp = &xcfbfb; 315 316 switch (flag) { 317 case FREAD: 318 if (fp->fbu->scrInfo.qe.eHead != fp->fbu->scrInfo.qe.eTail) 319 return (1); 320 selrecord(p, &fp->selp); 321 break; 322 } 323 324 return (0); 325 } 326 327 static u_char cursor_RGB[6]; /* cursor color 2 & 3 */ 328 329 /* 330 * Routines for the Inmos IMS-G332 Colour video controller 331 * Author: Alessandro Forin, Carnegie Mellon University 332 */ 333 static u_int 334 ims332_read_register(regno) 335 { 336 register u_char *regs = (u_char *)IMS332_ADDRESS; 337 unsigned char *rptr; 338 register u_int val, v1; 339 340 /* spec sez: */ 341 rptr = regs + 0x80000 + (regno << 4); 342 val = *((volatile u_short *) rptr ); 343 v1 = *((volatile u_short *) regs ); 344 345 return (val & 0xffff) | ((v1 & 0xff00) << 8); 346 } 347 348 static void 349 ims332_write_register(regno, val) 350 register unsigned int val; 351 { 352 register u_char *regs = (u_char *)IMS332_ADDRESS; 353 u_char *wptr; 354 355 /* spec sez: */ 356 wptr = regs + 0xa0000 + (regno << 4); 357 *((volatile u_int *)(regs)) = (val >> 8) & 0xff00; 358 *((volatile u_short *)(wptr)) = val; 359 } 360 361 #define assert_ims332_reset_bit(r) *r &= ~0x40 362 #define deassert_ims332_reset_bit(r) *r |= 0x40 363 364 /* 365 * Color map 366 */ 367 static void 368 xcfbLoadColorMap(ptr) 369 ColorMap *ptr; 370 { 371 register int i; 372 373 if (ptr->index > 256) 374 return; 375 ims332_load_colormap_entry(ptr->index, ptr); 376 } 377 378 static void 379 ims332_load_colormap_entry(entry, map) 380 ColorMap *map; 381 { 382 /* ?? stop VTG */ 383 ims332_write_register(IMS332_REG_LUT_BASE + (entry & 0xff), 384 (map->Entry.blue << 16) | 385 (map->Entry.green << 8) | 386 (map->Entry.red)); 387 } 388 389 static void 390 xcfbInitColorMap() 391 { 392 register int i; 393 ColorMap m; 394 395 m.Entry.red = m.Entry.green = m.Entry.blue = 0; 396 ims332_load_colormap_entry(0, &m); 397 398 m.Entry.red = m.Entry.green = m.Entry.blue = 0xff; 399 for (i = 1; i < 256; i++) 400 ims332_load_colormap_entry(i, &m); 401 402 for (i = 0; i < 3; i++) { 403 cursor_RGB[i] = 0x00; 404 cursor_RGB[i + 3] = 0xff; 405 } 406 xcfbRestoreCursorColor(); 407 } 408 409 /* 410 * Video on/off 411 * 412 * It is unfortunate that X11 goes backward with white@0 413 * and black@1. So we must stash away the zero-th entry 414 * and fix it while screen is off. Also must remember 415 * it, sigh. 416 */ 417 static struct { 418 u_int save; 419 int off; 420 } xcfb_vstate; 421 422 static void 423 ims332_video_off() 424 { 425 register u_int csr; 426 427 if (xcfb_vstate.off) 428 return; 429 430 xcfb_vstate.save = ims332_read_register(IMS332_REG_LUT_BASE); 431 432 ims332_write_register(IMS332_REG_LUT_BASE, 0); 433 434 ims332_write_register(IMS332_REG_COLOR_MASK, 0); 435 436 /* cursor now */ 437 csr = ims332_read_register(IMS332_REG_CSR_A); 438 csr |= IMS332_CSR_A_DISABLE_CURSOR; 439 ims332_write_register(IMS332_REG_CSR_A, csr); 440 441 xcfb_vstate.off = 1; 442 } 443 444 static void 445 ims332_video_on() 446 { 447 register u_int csr; 448 449 if (!xcfb_vstate.off) 450 return; 451 452 ims332_write_register(IMS332_REG_LUT_BASE, xcfb_vstate.save); 453 454 ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffffff); 455 456 /* cursor now */ 457 csr = ims332_read_register(IMS332_REG_CSR_A); 458 csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 459 ims332_write_register(IMS332_REG_CSR_A, csr); 460 461 xcfb_vstate.off = 0; 462 } 463 464 /* 465 * Cursor 466 */ 467 void 468 xcfbPosCursor(x, y) 469 register int x, y; 470 { 471 register struct pmax_fb *fp = &xcfbfb; 472 473 if (y < fp->fbu->scrInfo.min_cur_y || y > fp->fbu->scrInfo.max_cur_y) 474 y = fp->fbu->scrInfo.max_cur_y; 475 if (x < fp->fbu->scrInfo.min_cur_x || x > fp->fbu->scrInfo.max_cur_x) 476 x = fp->fbu->scrInfo.max_cur_x; 477 fp->fbu->scrInfo.cursor.x = x; /* keep track of real cursor */ 478 fp->fbu->scrInfo.cursor.y = y; /* position, indep. of mouse */ 479 ims332_write_register(IMS332_REG_CURSOR_LOC, 480 ((x & 0xfff) << 12) | (y & 0xfff)); 481 } 482 483 /* 484 * xcfbRestoreCursorColor 485 */ 486 static void 487 xcfbRestoreCursorColor() 488 { 489 490 /* Bg is color[0], Fg is color[1] */ 491 ims332_write_register(IMS332_REG_CURSOR_LUT_0, 492 (cursor_RGB[2] << 16) | 493 (cursor_RGB[1] << 8) | 494 (cursor_RGB[0])); 495 ims332_write_register(IMS332_REG_CURSOR_LUT_1, 0x7f0000); 496 ims332_write_register(IMS332_REG_CURSOR_LUT_2, 497 (cursor_RGB[5] << 16) | 498 (cursor_RGB[4] << 8) | 499 (cursor_RGB[3])); 500 } 501 502 /* 503 * ---------------------------------------------------------------------------- 504 * 505 * xcfbCursorColor -- 506 * 507 * Set the color of the cursor. 508 * 509 * Results: 510 * None. 511 * 512 * Side effects: 513 * None. 514 * 515 * ---------------------------------------------------------------------------- 516 */ 517 static void 518 xcfbCursorColor(color) 519 unsigned int color[]; 520 { 521 register int i, j; 522 523 for (i = 0; i < 6; i++) 524 cursor_RGB[i] = (u_char)(color[i] >> 8); 525 526 xcfbRestoreCursorColor(); 527 } 528 529 static void 530 xcfbLoadCursor(cursor) 531 u_short *cursor; 532 { 533 register int i, j, k, pos; 534 register u_short ap, bp, out; 535 536 /* 537 * Fill in the cursor sprite using the A and B planes, as provided 538 * for the pmax. 539 * XXX This will have to change when the X server knows that this 540 * is not a pmax display. 541 */ 542 pos = 0; 543 for (k = 0; k < 16; k++) { 544 ap = *cursor; 545 bp = *(cursor + 16); 546 j = 0; 547 while (j < 2) { 548 out = 0; 549 for (i = 0; i < 8; i++) { 550 out = ((out >> 2) & 0x3fff) | 551 ((ap & 0x1) << 15) | 552 ((bp & 0x1) << 14); 553 ap >>= 1; 554 bp >>= 1; 555 } 556 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, out); 557 pos++; 558 j++; 559 } 560 while (j < 8) { 561 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0); 562 pos++; 563 j++; 564 } 565 cursor++; 566 } 567 while (pos < 512) { 568 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0); 569 pos++; 570 } 571 } 572 573 /* 574 * Initialization 575 */ 576 int 577 xcfbinit() 578 { 579 register u_int *reset = (u_int *)IMS332_RESET_ADDRESS; 580 register struct pmax_fb *fp = &xcfbfb; 581 582 fp->isMono = 0; 583 584 /* 585 * Or Cached? A comment in the Mach driver suggests that the X server 586 * runs faster in cached address space, but the X server is going 587 * to blow away the data cache whenever it updates the screen, so.. 588 */ 589 fp->fr_addr = (char *) 590 MACH_PHYS_TO_UNCACHED(XINE_PHYS_CFB_START + VRAM_OFFSET); 591 fp->fr_size = 0x100000; 592 /* 593 * Must be in Uncached space since the fbuaccess structure is 594 * mapped into the user's address space uncached. 595 */ 596 fp->fbu = (struct fbuaccess *) 597 MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(&xcfbu)); 598 fp->posCursor = xcfbPosCursor; 599 fp->KBDPutc = dtopKBDPutc; 600 fp->kbddev = makedev(DTOPDEV, DTOPKBD_PORT); 601 602 /* 603 * Initialize the screen. 604 */ 605 #ifdef notdef 606 assert_ims332_reset_bit(reset); 607 DELAY(1); /* specs sez 50ns.. */ 608 deassert_ims332_reset_bit(reset); 609 610 /* CLOCKIN appears to receive a 6.25 Mhz clock --> PLL 12 for 75Mhz monitor */ 611 ims332_write_register(IMS332_REG_BOOT, 12 | IMS332_BOOT_CLOCK_PLL); 612 613 /* initialize VTG */ 614 ims332_write_register(IMS332_REG_CSR_A, 615 IMS332_BPP_8 | IMS332_CSR_A_DISABLE_CURSOR); 616 DELAY(50); /* spec does not say */ 617 618 /* datapath registers (values taken from prom's settings) */ 619 620 ims332_write_register(IMS332_REG_HALF_SYNCH, 0x10); 621 ims332_write_register(IMS332_REG_BACK_PORCH, 0x21); 622 ims332_write_register(IMS332_REG_DISPLAY, 0x100); 623 ims332_write_register(IMS332_REG_SHORT_DIS, 0x5d); 624 ims332_write_register(IMS332_REG_BROAD_PULSE, 0x9f); 625 ims332_write_register(IMS332_REG_V_SYNC, 0xc); 626 ims332_write_register(IMS332_REG_V_PRE_EQUALIZE, 2); 627 ims332_write_register(IMS332_REG_V_POST_EQUALIZE, 2); 628 ims332_write_register(IMS332_REG_V_BLANK, 0x2a); 629 ims332_write_register(IMS332_REG_V_DISPLAY, 0x600); 630 ims332_write_register(IMS332_REG_LINE_TIME, 0x146); 631 ims332_write_register(IMS332_REG_LINE_START, 0x10); 632 ims332_write_register(IMS332_REG_MEM_INIT, 0xa); 633 ims332_write_register(IMS332_REG_XFER_DELAY, 0xa); 634 635 ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffff); 636 #endif 637 638 /* 639 * Initialize screen info. 640 */ 641 fp->fbu->scrInfo.max_row = 50; 642 fp->fbu->scrInfo.max_col = 80; 643 fp->fbu->scrInfo.max_x = 1024; 644 fp->fbu->scrInfo.max_y = 768; 645 fp->fbu->scrInfo.max_cur_x = 1008; 646 fp->fbu->scrInfo.max_cur_y = 752; 647 fp->fbu->scrInfo.version = 11; 648 fp->fbu->scrInfo.mthreshold = 4; 649 fp->fbu->scrInfo.mscale = 2; 650 fp->fbu->scrInfo.min_cur_x = -15; 651 fp->fbu->scrInfo.min_cur_y = -15; 652 fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time); 653 fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ; 654 fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0; 655 fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 656 fp->fbu->scrInfo.qe.tcNext = 0; 657 658 xcfbInitColorMap(); 659 660 ims332_write_register(IMS332_REG_CSR_A, 661 IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE | IMS332_CSR_A_VTG_ENABLE); 662 663 xcfbScreenInit(); 664 fbScroll(fp); 665 666 fp->initialized = 1; 667 if (cn_tab.cn_fb == (struct pmax_fb *)0) 668 cn_tab.cn_fb = fp; 669 return (1); 670 } 671 672 /* 673 * ---------------------------------------------------------------------------- 674 * 675 * xcfbScreenInit -- 676 * 677 * Initialize the screen. 678 * 679 * Results: 680 * None. 681 * 682 * Side effects: 683 * The screen is initialized. 684 * 685 * ---------------------------------------------------------------------------- 686 */ 687 static void 688 xcfbScreenInit() 689 { 690 register struct pmax_fb *fp = &xcfbfb; 691 692 /* 693 * Home the cursor. 694 * We want an LSI terminal emulation. We want the graphics 695 * terminal to scroll from the bottom. So start at the bottom. 696 */ 697 fp->row = 49; 698 fp->col = 0; 699 700 /* 701 * Load the cursor with the default values 702 * 703 */ 704 xcfbLoadCursor(defCursor); 705 } 706 707 /* 708 * xcfb keyboard and mouse input. Just punt to the generic ones in fb.c 709 */ 710 void 711 xcfbKbdEvent(ch) 712 int ch; 713 { 714 fbKbdEvent(ch, &xcfbfb); 715 } 716 717 void 718 xcfbMouseEvent(newRepPtr) 719 MouseReport *newRepPtr; 720 { 721 fbMouseEvent(newRepPtr, &xcfbfb); 722 } 723 724 void 725 xcfbMouseButtons(newRepPtr) 726 MouseReport *newRepPtr; 727 { 728 fbMouseButtons(newRepPtr, &xcfbfb); 729 } 730 #endif /* NDTOP */ 731 #endif /* NXCFB */ 732