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