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.1 (Berkeley) 06/10/93 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 caddr_t data; 198 struct proc *p; 199 { 200 register struct pmax_fb *fp = &xcfbfb; 201 int s; 202 203 switch (cmd) { 204 case QIOCGINFO: 205 return (fbmmap(fp, dev, data, p)); 206 207 case QIOCPMSTATE: 208 /* 209 * Set mouse state. 210 */ 211 fp->fbu->scrInfo.mouse = *(pmCursor *)data; 212 xcfbPosCursor(fp->fbu->scrInfo.mouse.x, fp->fbu->scrInfo.mouse.y); 213 break; 214 215 case QIOCINIT: 216 /* 217 * Initialize the screen. 218 */ 219 xcfbScreenInit(); 220 break; 221 222 case QIOCKPCMD: 223 { 224 pmKpCmd *kpCmdPtr; 225 unsigned char *cp; 226 227 kpCmdPtr = (pmKpCmd *)data; 228 if (kpCmdPtr->nbytes == 0) 229 kpCmdPtr->cmd |= 0x80; 230 if (!fp->GraphicsOpen) 231 kpCmdPtr->cmd |= 1; 232 (*fp->KBDPutc)(fp->kbddev, (int)kpCmdPtr->cmd); 233 cp = &kpCmdPtr->par[0]; 234 for (; kpCmdPtr->nbytes > 0; cp++, kpCmdPtr->nbytes--) { 235 if (kpCmdPtr->nbytes == 1) 236 *cp |= 0x80; 237 (*fp->KBDPutc)(fp->kbddev, (int)*cp); 238 } 239 break; 240 } 241 242 case QIOCADDR: 243 *(PM_Info **)data = &fp->fbu->scrInfo; 244 break; 245 246 case QIOWCURSOR: 247 xcfbLoadCursor((unsigned short *)data); 248 break; 249 250 case QIOWCURSORCOLOR: 251 xcfbCursorColor((unsigned int *)data); 252 break; 253 254 case QIOSETCMAP: 255 xcfbLoadColorMap((ColorMap *)data); 256 break; 257 258 case QIOKERNLOOP: 259 s = spltty(); 260 dtopDivertXInput = xcfbKbdEvent; 261 dtopMouseEvent = xcfbMouseEvent; 262 dtopMouseButtons = xcfbMouseButtons; 263 splx(s); 264 break; 265 266 case QIOKERNUNLOOP: 267 s = spltty(); 268 dtopDivertXInput = (void (*)())0; 269 dtopMouseEvent = (void (*)())0; 270 dtopMouseButtons = (void (*)())0; 271 splx(s); 272 break; 273 274 case QIOVIDEOON: 275 xcfbRestoreCursorColor(); 276 ims332_video_on(); 277 break; 278 279 case QIOVIDEOOFF: 280 ims332_video_off(); 281 break; 282 283 default: 284 printf("xcfb0: Unknown ioctl command %x\n", cmd); 285 return (EINVAL); 286 } 287 return (0); 288 } 289 290 /* 291 * Return the physical page number that corresponds to byte offset 'off'. 292 */ 293 /*ARGSUSED*/ 294 xcfbmap(dev, off, prot) 295 dev_t dev; 296 { 297 int len; 298 299 len = pmax_round_page(((vm_offset_t)&xcfbu & PGOFSET) + sizeof(xcfbu)); 300 if (off < len) 301 return pmax_btop(MACH_CACHED_TO_PHYS(&xcfbu) + off); 302 off -= len; 303 if (off >= xcfbfb.fr_size) 304 return (-1); 305 return pmax_btop(MACH_UNCACHED_TO_PHYS(xcfbfb.fr_addr) + off); 306 } 307 308 xcfbselect(dev, flag, p) 309 dev_t dev; 310 int flag; 311 struct proc *p; 312 { 313 struct pmax_fb *fp = &xcfbfb; 314 315 switch (flag) { 316 case FREAD: 317 if (fp->fbu->scrInfo.qe.eHead != fp->fbu->scrInfo.qe.eTail) 318 return (1); 319 selrecord(p, &fp->selp); 320 break; 321 } 322 323 return (0); 324 } 325 326 static u_char cursor_RGB[6]; /* cursor color 2 & 3 */ 327 328 /* 329 * Routines for the Inmos IMS-G332 Colour video controller 330 * Author: Alessandro Forin, Carnegie Mellon University 331 */ 332 static u_int 333 ims332_read_register(regno) 334 { 335 register u_char *regs = (u_char *)IMS332_ADDRESS; 336 unsigned char *rptr; 337 register u_int val, v1; 338 339 /* spec sez: */ 340 rptr = regs + 0x80000 + (regno << 4); 341 val = *((volatile u_short *) rptr ); 342 v1 = *((volatile u_short *) regs ); 343 344 return (val & 0xffff) | ((v1 & 0xff00) << 8); 345 } 346 347 static void 348 ims332_write_register(regno, val) 349 register unsigned int val; 350 { 351 register u_char *regs = (u_char *)IMS332_ADDRESS; 352 u_char *wptr; 353 354 /* spec sez: */ 355 wptr = regs + 0xa0000 + (regno << 4); 356 *((volatile u_int *)(regs)) = (val >> 8) & 0xff00; 357 *((volatile u_short *)(wptr)) = val; 358 } 359 360 #define assert_ims332_reset_bit(r) *r &= ~0x40 361 #define deassert_ims332_reset_bit(r) *r |= 0x40 362 363 /* 364 * Color map 365 */ 366 static void 367 xcfbLoadColorMap(ptr) 368 ColorMap *ptr; 369 { 370 register int i; 371 372 if (ptr->index > 256) 373 return; 374 ims332_load_colormap_entry(ptr->index, ptr); 375 } 376 377 static void 378 ims332_load_colormap_entry(entry, map) 379 ColorMap *map; 380 { 381 /* ?? stop VTG */ 382 ims332_write_register(IMS332_REG_LUT_BASE + (entry & 0xff), 383 (map->Entry.blue << 16) | 384 (map->Entry.green << 8) | 385 (map->Entry.red)); 386 } 387 388 static void 389 xcfbInitColorMap() 390 { 391 register int i; 392 ColorMap m; 393 394 m.Entry.red = m.Entry.green = m.Entry.blue = 0; 395 ims332_load_colormap_entry(0, &m); 396 397 m.Entry.red = m.Entry.green = m.Entry.blue = 0xff; 398 for (i = 1; i < 256; i++) 399 ims332_load_colormap_entry(i, &m); 400 401 for (i = 0; i < 3; i++) { 402 cursor_RGB[i] = 0x00; 403 cursor_RGB[i + 3] = 0xff; 404 } 405 xcfbRestoreCursorColor(); 406 } 407 408 /* 409 * Video on/off 410 * 411 * It is unfortunate that X11 goes backward with white@0 412 * and black@1. So we must stash away the zero-th entry 413 * and fix it while screen is off. Also must remember 414 * it, sigh. 415 */ 416 static struct { 417 u_int save; 418 int off; 419 } xcfb_vstate; 420 421 static void 422 ims332_video_off() 423 { 424 register u_int csr; 425 426 if (xcfb_vstate.off) 427 return; 428 429 xcfb_vstate.save = ims332_read_register(IMS332_REG_LUT_BASE); 430 431 ims332_write_register(IMS332_REG_LUT_BASE, 0); 432 433 ims332_write_register(IMS332_REG_COLOR_MASK, 0); 434 435 /* cursor now */ 436 csr = ims332_read_register(IMS332_REG_CSR_A); 437 csr |= IMS332_CSR_A_DISABLE_CURSOR; 438 ims332_write_register(IMS332_REG_CSR_A, csr); 439 440 xcfb_vstate.off = 1; 441 } 442 443 static void 444 ims332_video_on() 445 { 446 register u_int csr; 447 448 if (!xcfb_vstate.off) 449 return; 450 451 ims332_write_register(IMS332_REG_LUT_BASE, xcfb_vstate.save); 452 453 ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffffff); 454 455 /* cursor now */ 456 csr = ims332_read_register(IMS332_REG_CSR_A); 457 csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 458 ims332_write_register(IMS332_REG_CSR_A, csr); 459 460 xcfb_vstate.off = 0; 461 } 462 463 /* 464 * Cursor 465 */ 466 void 467 xcfbPosCursor(x, y) 468 register int x, y; 469 { 470 register struct pmax_fb *fp = &xcfbfb; 471 472 if (y < fp->fbu->scrInfo.min_cur_y || y > fp->fbu->scrInfo.max_cur_y) 473 y = fp->fbu->scrInfo.max_cur_y; 474 if (x < fp->fbu->scrInfo.min_cur_x || x > fp->fbu->scrInfo.max_cur_x) 475 x = fp->fbu->scrInfo.max_cur_x; 476 fp->fbu->scrInfo.cursor.x = x; /* keep track of real cursor */ 477 fp->fbu->scrInfo.cursor.y = y; /* position, indep. of mouse */ 478 ims332_write_register(IMS332_REG_CURSOR_LOC, 479 ((x & 0xfff) << 12) | (y & 0xfff)); 480 } 481 482 /* 483 * xcfbRestoreCursorColor 484 */ 485 static void 486 xcfbRestoreCursorColor() 487 { 488 489 /* Bg is color[0], Fg is color[1] */ 490 ims332_write_register(IMS332_REG_CURSOR_LUT_0, 491 (cursor_RGB[2] << 16) | 492 (cursor_RGB[1] << 8) | 493 (cursor_RGB[0])); 494 ims332_write_register(IMS332_REG_CURSOR_LUT_1, 0x7f0000); 495 ims332_write_register(IMS332_REG_CURSOR_LUT_2, 496 (cursor_RGB[5] << 16) | 497 (cursor_RGB[4] << 8) | 498 (cursor_RGB[3])); 499 } 500 501 /* 502 * ---------------------------------------------------------------------------- 503 * 504 * xcfbCursorColor -- 505 * 506 * Set the color of the cursor. 507 * 508 * Results: 509 * None. 510 * 511 * Side effects: 512 * None. 513 * 514 * ---------------------------------------------------------------------------- 515 */ 516 static void 517 xcfbCursorColor(color) 518 unsigned int color[]; 519 { 520 register int i, j; 521 522 for (i = 0; i < 6; i++) 523 cursor_RGB[i] = (u_char)(color[i] >> 8); 524 525 xcfbRestoreCursorColor(); 526 } 527 528 static void 529 xcfbLoadCursor(cursor) 530 u_short *cursor; 531 { 532 register int i, j, k, pos; 533 register u_short ap, bp, out; 534 535 /* 536 * Fill in the cursor sprite using the A and B planes, as provided 537 * for the pmax. 538 * XXX This will have to change when the X server knows that this 539 * is not a pmax display. 540 */ 541 pos = 0; 542 for (k = 0; k < 16; k++) { 543 ap = *cursor; 544 bp = *(cursor + 16); 545 j = 0; 546 while (j < 2) { 547 out = 0; 548 for (i = 0; i < 8; i++) { 549 out = ((out >> 2) & 0x3fff) | 550 ((ap & 0x1) << 15) | 551 ((bp & 0x1) << 14); 552 ap >>= 1; 553 bp >>= 1; 554 } 555 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, out); 556 pos++; 557 j++; 558 } 559 while (j < 8) { 560 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0); 561 pos++; 562 j++; 563 } 564 cursor++; 565 } 566 while (pos < 512) { 567 ims332_write_register(IMS332_REG_CURSOR_RAM + pos, 0); 568 pos++; 569 } 570 } 571 572 /* 573 * Initialization 574 */ 575 int 576 xcfbinit() 577 { 578 register u_int *reset = (u_int *)IMS332_RESET_ADDRESS; 579 register struct pmax_fb *fp = &xcfbfb; 580 581 fp->isMono = 0; 582 583 /* 584 * Or Cached? A comment in the Mach driver suggests that the X server 585 * runs faster in cached address space, but the X server is going 586 * to blow away the data cache whenever it updates the screen, so.. 587 */ 588 fp->fr_addr = (char *) 589 MACH_PHYS_TO_UNCACHED(XINE_PHYS_CFB_START + VRAM_OFFSET); 590 fp->fr_size = 0x100000; 591 /* 592 * Must be in Uncached space since the fbuaccess structure is 593 * mapped into the user's address space uncached. 594 */ 595 fp->fbu = (struct fbuaccess *) 596 MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(&xcfbu)); 597 fp->posCursor = xcfbPosCursor; 598 fp->KBDPutc = dtopKBDPutc; 599 fp->kbddev = makedev(DTOPDEV, DTOPKBD_PORT); 600 601 /* 602 * Initialize the screen. 603 */ 604 #ifdef notdef 605 assert_ims332_reset_bit(reset); 606 DELAY(1); /* specs sez 50ns.. */ 607 deassert_ims332_reset_bit(reset); 608 609 /* CLOCKIN appears to receive a 6.25 Mhz clock --> PLL 12 for 75Mhz monitor */ 610 ims332_write_register(IMS332_REG_BOOT, 12 | IMS332_BOOT_CLOCK_PLL); 611 612 /* initialize VTG */ 613 ims332_write_register(IMS332_REG_CSR_A, 614 IMS332_BPP_8 | IMS332_CSR_A_DISABLE_CURSOR); 615 DELAY(50); /* spec does not say */ 616 617 /* datapath registers (values taken from prom's settings) */ 618 619 ims332_write_register(IMS332_REG_HALF_SYNCH, 0x10); 620 ims332_write_register(IMS332_REG_BACK_PORCH, 0x21); 621 ims332_write_register(IMS332_REG_DISPLAY, 0x100); 622 ims332_write_register(IMS332_REG_SHORT_DIS, 0x5d); 623 ims332_write_register(IMS332_REG_BROAD_PULSE, 0x9f); 624 ims332_write_register(IMS332_REG_V_SYNC, 0xc); 625 ims332_write_register(IMS332_REG_V_PRE_EQUALIZE, 2); 626 ims332_write_register(IMS332_REG_V_POST_EQUALIZE, 2); 627 ims332_write_register(IMS332_REG_V_BLANK, 0x2a); 628 ims332_write_register(IMS332_REG_V_DISPLAY, 0x600); 629 ims332_write_register(IMS332_REG_LINE_TIME, 0x146); 630 ims332_write_register(IMS332_REG_LINE_START, 0x10); 631 ims332_write_register(IMS332_REG_MEM_INIT, 0xa); 632 ims332_write_register(IMS332_REG_XFER_DELAY, 0xa); 633 634 ims332_write_register(IMS332_REG_COLOR_MASK, 0xffffff); 635 #endif 636 637 /* 638 * Initialize screen info. 639 */ 640 fp->fbu->scrInfo.max_row = 50; 641 fp->fbu->scrInfo.max_col = 80; 642 fp->fbu->scrInfo.max_x = 1024; 643 fp->fbu->scrInfo.max_y = 768; 644 fp->fbu->scrInfo.max_cur_x = 1008; 645 fp->fbu->scrInfo.max_cur_y = 752; 646 fp->fbu->scrInfo.version = 11; 647 fp->fbu->scrInfo.mthreshold = 4; 648 fp->fbu->scrInfo.mscale = 2; 649 fp->fbu->scrInfo.min_cur_x = -15; 650 fp->fbu->scrInfo.min_cur_y = -15; 651 fp->fbu->scrInfo.qe.timestamp_ms = TO_MS(time); 652 fp->fbu->scrInfo.qe.eSize = PM_MAXEVQ; 653 fp->fbu->scrInfo.qe.eHead = fp->fbu->scrInfo.qe.eTail = 0; 654 fp->fbu->scrInfo.qe.tcSize = MOTION_BUFFER_SIZE; 655 fp->fbu->scrInfo.qe.tcNext = 0; 656 657 xcfbInitColorMap(); 658 659 ims332_write_register(IMS332_REG_CSR_A, 660 IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE | IMS332_CSR_A_VTG_ENABLE); 661 662 xcfbScreenInit(); 663 fbScroll(fp); 664 665 fp->initialized = 1; 666 if (cn_tab.cn_fb == (struct pmax_fb *)0) 667 cn_tab.cn_fb = fp; 668 return (1); 669 } 670 671 /* 672 * ---------------------------------------------------------------------------- 673 * 674 * xcfbScreenInit -- 675 * 676 * Initialize the screen. 677 * 678 * Results: 679 * None. 680 * 681 * Side effects: 682 * The screen is initialized. 683 * 684 * ---------------------------------------------------------------------------- 685 */ 686 static void 687 xcfbScreenInit() 688 { 689 register struct pmax_fb *fp = &xcfbfb; 690 691 /* 692 * Home the cursor. 693 * We want an LSI terminal emulation. We want the graphics 694 * terminal to scroll from the bottom. So start at the bottom. 695 */ 696 fp->row = 49; 697 fp->col = 0; 698 699 /* 700 * Load the cursor with the default values 701 * 702 */ 703 xcfbLoadCursor(defCursor); 704 } 705 706 /* 707 * xcfb keyboard and mouse input. Just punt to the generic ones in fb.c 708 */ 709 void 710 xcfbKbdEvent(ch) 711 int ch; 712 { 713 fbKbdEvent(ch, &xcfbfb); 714 } 715 716 void 717 xcfbMouseEvent(newRepPtr) 718 MouseReport *newRepPtr; 719 { 720 fbMouseEvent(newRepPtr, &xcfbfb); 721 } 722 723 void 724 xcfbMouseButtons(newRepPtr) 725 MouseReport *newRepPtr; 726 { 727 fbMouseButtons(newRepPtr, &xcfbfb); 728 } 729 #endif /* NDTOP */ 730 #endif /* NXCFB */ 731