1 /* $NetBSD: gpx.c,v 1.1 2023/02/06 13:13:05 tsutsui Exp $ */ 2 /* $OpenBSD: gpx.c,v 1.25 2014/12/23 21:39:12 miod Exp $ */ 3 /* 4 * Copyright (c) 2006 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice, this permission notice, and the disclaimer below 9 * appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 /*- 20 * Copyright (c) 1988 Regents of the University of California. 21 * All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. Neither the name of the University nor the names of its contributors 32 * may be used to endorse or promote products derived from this software 33 * without specific prior written permission. 34 * 35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 45 * SUCH DAMAGE. 46 * 47 * @(#)qd.c 7.1 (Berkeley) 6/28/91 48 */ 49 50 /************************************************************************ 51 * * 52 * Copyright (c) 1985-1988 by * 53 * Digital Equipment Corporation, Maynard, MA * 54 * All rights reserved. * 55 * * 56 * This software is furnished under a license and may be used and * 57 * copied only in accordance with the terms of such license and * 58 * with the inclusion of the above copyright notice. This * 59 * software or any other copies thereof may not be provided or * 60 * otherwise made available to any other person. No title to and * 61 * ownership of the software is hereby transferred. * 62 * * 63 * The information in this software is subject to change without * 64 * notice and should not be construed as a commitment by Digital * 65 * Equipment Corporation. * 66 * * 67 * Digital assumes no responsibility for the use or reliability * 68 * of its software on equipment which is not supplied by Digital. * 69 * * 70 *************************************************************************/ 71 72 /* 73 * Driver for the GPX color option on VAXstation 3100, based on the 74 * MicroVAX II qdss driver. 75 * 76 * The frame buffer memory itself is not directly accessible (unlike 77 * the on-board monochrome smg frame buffer), and writes through the 78 * Dragon chip can only happen in multiples of 16 pixels, horizontally. 79 * 80 * Because of this limitation, the font image is copied to offscreen 81 * memory (which there is plenty of), and screen to screen blt operations 82 * are done for everything. 83 */ 84 85 #include "dzkbd.h" 86 #include "wsdisplay.h" 87 88 #include <sys/param.h> 89 #include <sys/device.h> 90 #include <sys/systm.h> 91 #include <sys/kmem.h> 92 #include <sys/conf.h> 93 94 #include <machine/sid.h> 95 #include <machine/cpu.h> 96 #include <machine/ka420.h> 97 #include <machine/scb.h> 98 #include <machine/vsbus.h> 99 #include <machine/qdreg.h> 100 101 #include <dev/cons.h> 102 103 #include <dev/dec/dzreg.h> 104 #include <dev/dec/dzvar.h> 105 #include <dev/dec/dzkbdvar.h> 106 107 #include <dev/wscons/wsconsio.h> 108 #include <dev/wscons/wscons_callbacks.h> 109 #include <dev/wscons/wsdisplayvar.h> 110 #include <dev/rasops/rasops.h> 111 #include <dev/wsfont/wsfont.h> 112 113 #if 0 114 #include <dev/ic/bt458reg.h> 115 #include <dev/ic/dc503reg.h> 116 #endif 117 118 #define GPXADDR 0x3c000000 /* base address on VAXstation 3100 */ 119 120 #define GPX_ADDER_OFFSET 0x0000 121 #define GPX_VDAC_OFFSET 0x0300 122 #define GPX_CURSOR_OFFSET 0x0400 /* DC503 */ 123 #define GPX_READBACK_OFFSET 0x0500 124 125 #define GPX_WIDTH 1024 126 #define GPX_VISHEIGHT 864 127 #define GPX_HEIGHT 2048 128 129 /* XXX these should be in <dev/ic/bt458reg.h> */ 130 /* 131 * Brooktree Bt451, Bt457, Bt458 register definitions 132 */ 133 #define BT_OV0 0x00 /* overlay 0 */ 134 #define BT_OV1 0x01 /* overlay 1 */ 135 #define BT_OV2 0x02 /* overlay 2 */ 136 #define BT_OV3 0x03 /* overlay 3 */ 137 #define BT_RMR 0x04 /* read mask */ 138 #define BT_BMR 0x05 /* blink mask */ 139 #define BT_CR 0x06 /* control */ 140 #define BT_CTR 0x07 /* control/test */ 141 142 #define BTCR_MPLX_5 0x80 /* multiplex select, 5:1 */ 143 #define BTCR_MPLX_4 0x00 /* multiplex select, 4:1 */ 144 #define BTCR_RAMENA 0x40 /* use color palette RAM */ 145 #define BTCR_BLINK_M 0x30 /* blink mask */ 146 #define BTCR_BLINK_1648 0x00 /* 16 on, 48 off */ 147 #define BTCR_BLINK_1616 0x10 /* 16 on, 16 off */ 148 #define BTCR_BLINK_3232 0x20 /* 32 on, 32 off */ 149 #define BTCR_BLINK_6464 0x30 /* 64 on, 64 off */ 150 #define BTCR_BLINKENA_OV1 0x08 /* OV1 blink enable */ 151 #define BTCR_BLINKENA_OV0 0x04 /* OV0 blink enable */ 152 #define BTCR_DISPENA_OV1 0x02 /* OV1 display enable */ 153 #define BTCR_DISPENA_OV0 0x01 /* OV0 display enable */ 154 155 #define BTCTR_R_ENA 0x01 /* red channel enable */ 156 #define BTCTR_G_ENA 0x02 /* green channel enable */ 157 #define BTCTR_B_ENA 0x04 /* blue channel enable */ 158 #define BTCTR_NIB_M 0x08 /* nibble mask: */ 159 #define BTCTR_NIB_LOW 0x08 /* low */ 160 #define BTCTR_NIB_HIGH 0x00 /* high */ 161 162 /* 4 plane option RAMDAC */ 163 struct ramdac4 { 164 uint16_t colormap[16]; 165 uint8_t unknown[0x20]; 166 uint16_t cursormap[4]; 167 uint8_t unknown2[0x18]; 168 uint16_t control; 169 #define RAMDAC4_INIT 0x0047 170 #define RAMDAC4_ENABLE 0x0002 171 }; 172 173 /* 8 plane option RAMDAC - Bt458 or compatible */ 174 struct ramdac8 { 175 uint16_t address; 176 uint16_t cmapdata; 177 uint16_t control; 178 uint16_t omapdata; 179 }; 180 181 static int gpx_match(device_t, cfdata_t, void *); 182 static void gpx_attach(device_t, device_t, void *); 183 184 struct gpx_screen { 185 struct rasops_info ss_ri; 186 int ss_console; 187 u_int ss_depth; 188 u_int ss_gpr; /* font glyphs per row */ 189 struct adder *ss_adder; 190 void *ss_vdac; 191 uint8_t ss_cmap[256 * 3]; 192 #if 0 193 struct dc503reg *ss_cursor; 194 uint16_t ss_curcmd; 195 #endif 196 }; 197 198 /* for console */ 199 struct gpx_screen gpx_consscr; 200 201 struct gpx_softc { 202 device_t sc_dev; 203 struct gpx_screen *sc_scr; 204 int sc_nscreens; 205 }; 206 207 CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc), 208 gpx_match, gpx_attach, NULL, NULL); 209 210 struct wsscreen_descr gpx_stdscreen = { 211 "std", 212 }; 213 214 const struct wsscreen_descr *_gpx_scrlist[] = { 215 &gpx_stdscreen, 216 }; 217 218 const struct wsscreen_list gpx_screenlist = { 219 sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *), 220 _gpx_scrlist, 221 }; 222 223 static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *); 224 static paddr_t gpx_mmap(void *, void *, off_t, int); 225 static int gpx_alloc_screen(void *, const struct wsscreen_descr *, 226 void **, int *, int *, long *); 227 static void gpx_free_screen(void *, void *); 228 static int gpx_show_screen(void *, void *, int, 229 void (*) (void *, int, int), void *); 230 231 const struct wsdisplay_accessops gpx_accessops = { 232 .ioctl = gpx_ioctl, 233 .mmap = gpx_mmap, 234 .alloc_screen = gpx_alloc_screen, 235 .free_screen = gpx_free_screen, 236 .show_screen = gpx_show_screen, 237 .load_font = NULL 238 }; 239 240 static void gpx_clear_screen(struct gpx_screen *); 241 static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int); 242 static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int); 243 static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *); 244 static void gpx_loadcmap(struct gpx_screen *, int, int); 245 static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *); 246 static void gpx_resetcmap(struct gpx_screen *); 247 static void gpx_reset_viper(struct gpx_screen *); 248 static int gpx_setup_screen(struct gpx_screen *); 249 static void gpx_upload_font(struct gpx_screen *); 250 static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t); 251 static int gpx_wait(struct gpx_screen *, int); 252 253 static void gpx_copycols(void *, int, int, int, int); 254 static void gpx_copyrows(void *, int, int, int); 255 static void gpx_do_cursor(struct rasops_info *); 256 static void gpx_erasecols(void *, int, int, int, long); 257 static void gpx_eraserows(void *, int, int, long); 258 static void gpx_putchar(void *, int, int, u_int, long); 259 260 /* 261 * Autoconf glue 262 */ 263 264 int 265 gpx_match(device_t parent, cfdata_t match, void *aux) 266 { 267 struct vsbus_attach_args *va = aux; 268 volatile struct adder *adder; 269 vaddr_t tmp; 270 u_int depth; 271 u_short status; 272 273 switch (vax_boardtype) { 274 default: 275 return 0; 276 277 case VAX_BTYP_410: 278 case VAX_BTYP_420: 279 case VAX_BTYP_43: 280 if (va->va_paddr != GPXADDR) 281 return 0; 282 283 /* not present on microvaxes */ 284 if ((vax_confdata & KA420_CFG_MULTU) != 0) 285 return 0; 286 287 if ((vax_confdata & KA420_CFG_VIDOPT) == 0) 288 return 0; 289 break; 290 } 291 292 /* Check for hardware */ 293 adder = (volatile struct adder *) 294 vax_map_physmem(va->va_paddr + GPX_ADDER_OFFSET, 1); 295 if (adder == NULL) 296 return 0; 297 adder->status = 0; 298 status = adder->status; 299 vax_unmap_physmem((vaddr_t)adder, 1); 300 if (status == offsetof(struct adder, status)) 301 return 0; 302 303 /* Check for a recognized color depth */ 304 tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1); 305 if (tmp == 0L) 306 return 0; 307 depth = (*(volatile uint16_t *)tmp) & 0x00f0; 308 vax_unmap_physmem(tmp, 1); 309 if (depth != 0x00f0 && depth != 0x0080) 310 return 0; 311 312 /* when already running as console, always fake things */ 313 if ((vax_confdata & KA420_CFG_L3CON) == 0 314 #if NWSDISPLAY > 0 315 && cn_tab->cn_putc == wsdisplay_cnputc 316 #endif 317 ) { 318 struct vsbus_softc *sc = device_private(parent); 319 sc->sc_mask = 0x08; 320 scb_fake(0x44, 0x15); 321 } else { 322 adder = (struct adder *)vax_map_physmem(va->va_paddr + 323 GPX_ADDER_OFFSET, 1); 324 if (adder == NULL) 325 return 0; 326 adder->interrupt_enable = FRAME_SYNC; 327 DELAY(100000); /* enough to get a retrace interrupt */ 328 adder->interrupt_enable = 0; 329 vax_unmap_physmem((vaddr_t)adder, 1); 330 } 331 return 20; 332 } 333 334 void 335 gpx_attach(device_t parent, device_t self, void *aux) 336 { 337 struct gpx_softc *sc = device_private(self); 338 struct vsbus_attach_args *va = aux; 339 struct gpx_screen *scr; 340 struct wsemuldisplaydev_attach_args aa; 341 int console; 342 vaddr_t tmp; 343 344 sc->sc_dev = self; 345 console = 346 #if NWSDISPLAY > 0 347 (vax_confdata & KA420_CFG_L3CON) == 0 && 348 cn_tab->cn_putc == wsdisplay_cnputc; 349 #else 350 (vax_confdata & KA420_CFG_L3CON) == 0; 351 #endif 352 if (console) { 353 scr = &gpx_consscr; 354 sc->sc_nscreens = 1; 355 } else { 356 scr = kmem_zalloc(sizeof(*scr), KM_SLEEP); 357 358 tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1); 359 if (tmp == 0L) { 360 printf(": can not probe depth\n"); 361 goto bad1; 362 } 363 scr->ss_depth = (*(uint16_t *)tmp & 0x00f0) == 0x00f0 ? 4 : 8; 364 vax_unmap_physmem(tmp, 1); 365 366 scr->ss_adder = (struct adder *)vax_map_physmem(va->va_paddr + 367 GPX_ADDER_OFFSET, 1); 368 if (scr->ss_adder == NULL) { 369 aprint_error(": can not map frame buffer registers\n"); 370 goto bad1; 371 } 372 373 scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr + 374 GPX_VDAC_OFFSET, 1); 375 if (scr->ss_vdac == NULL) { 376 aprint_error(": can not map RAMDAC\n"); 377 goto bad2; 378 } 379 380 #if 0 381 scr->ss_cursor = 382 (struct dc503reg *)vax_map_physmem(va->va_paddr + 383 GPX_CURSOR_OFFSET, 1); 384 if (scr->ss_cursor == NULL) { 385 aprint_error(": can not map cursor chip\n"); 386 goto bad3; 387 } 388 #endif 389 390 if (gpx_setup_screen(scr) != 0) { 391 aprint_error(": initialization failed\n"); 392 goto bad4; 393 } 394 } 395 sc->sc_scr = scr; 396 397 aprint_normal("\n"); 398 aprint_normal_dev(self, "%dx%d %d plane color framebuffer\n", 399 GPX_WIDTH, GPX_VISHEIGHT, scr->ss_depth); 400 401 aa.console = console; 402 aa.scrdata = &gpx_screenlist; 403 aa.accessops = &gpx_accessops; 404 aa.accesscookie = sc; 405 406 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 407 408 return; 409 410 bad4: 411 #if 0 412 vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1); 413 bad3: 414 #endif 415 vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1); 416 bad2: 417 vax_unmap_physmem((vaddr_t)scr->ss_adder, 1); 418 bad1: 419 kmem_free(scr, sizeof(*scr)); 420 } 421 422 /* 423 * wsdisplay accessops 424 */ 425 426 int 427 gpx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 428 { 429 struct gpx_softc *sc = v; 430 struct gpx_screen *ss = sc->sc_scr; 431 struct wsdisplay_fbinfo *wdf; 432 struct wsdisplay_cmap *cm; 433 int error; 434 435 switch (cmd) { 436 case WSDISPLAYIO_GTYPE: 437 *(u_int *)data = WSDISPLAY_TYPE_GPX; 438 break; 439 440 case WSDISPLAYIO_GINFO: 441 wdf = (struct wsdisplay_fbinfo *)data; 442 wdf->height = ss->ss_ri.ri_height; 443 wdf->width = ss->ss_ri.ri_width; 444 wdf->depth = ss->ss_depth; 445 wdf->cmsize = 1 << ss->ss_depth; 446 break; 447 448 case WSDISPLAYIO_GETCMAP: 449 cm = (struct wsdisplay_cmap *)data; 450 error = gpx_getcmap(ss, cm); 451 if (error != 0) 452 return error; 453 break; 454 case WSDISPLAYIO_PUTCMAP: 455 cm = (struct wsdisplay_cmap *)data; 456 error = gpx_putcmap(ss, cm); 457 if (error != 0) 458 return error; 459 gpx_loadcmap(ss, cm->index, cm->count); 460 break; 461 462 case WSDISPLAYIO_GVIDEO: 463 case WSDISPLAYIO_SVIDEO: 464 break; 465 466 case WSDISPLAYIO_LINEBYTES: /* no linear mapping */ 467 return -1; 468 469 default: 470 return EPASSTHROUGH; 471 } 472 return 0; 473 } 474 475 paddr_t 476 gpx_mmap(void *v, void *vs, off_t offset, int prot) 477 { 478 479 return -1; 480 } 481 482 int 483 gpx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 484 int *curxp, int *curyp, long *defattrp) 485 { 486 struct gpx_softc *sc = v; 487 struct gpx_screen *ss = sc->sc_scr; 488 struct rasops_info *ri = &ss->ss_ri; 489 490 if (sc->sc_nscreens > 0) 491 return ENOMEM; 492 493 *cookiep = ri; 494 *curxp = *curyp = 0; 495 ri->ri_ops.allocattr(ri, 0, 0, 0, defattrp); 496 sc->sc_nscreens++; 497 498 return 0; 499 } 500 501 void 502 gpx_free_screen(void *v, void *cookie) 503 { 504 struct gpx_softc *sc = v; 505 506 sc->sc_nscreens--; 507 } 508 509 int 510 gpx_show_screen(void *v, void *cookie, int waitok, 511 void (*cb)(void *, int, int), void *cbarg) 512 { 513 514 return 0; 515 } 516 517 /* 518 * wsdisplay emulops 519 */ 520 521 void 522 gpx_putchar(void *v, int row, int col, u_int uc, long attr) 523 { 524 struct rasops_info *ri = v; 525 struct gpx_screen *ss = ri->ri_hw; 526 struct wsdisplay_font *font = ri->ri_font; 527 int dx, dy, sx, sy, fg, bg, ul; 528 529 rasops_unpack_attr(attr, &fg, &bg, &ul); 530 531 /* find where to output the glyph... */ 532 dx = col * font->fontwidth + ri->ri_xorigin; 533 dy = row * font->fontheight + ri->ri_yorigin; 534 /* ... and where to pick it from */ 535 uc -= font->firstchar; 536 sx = (uc % ss->ss_gpr) * font->stride * NBBY; 537 sy = GPX_HEIGHT - (1 + uc / ss->ss_gpr) * font->fontheight; 538 539 /* setup VIPER operand control registers */ 540 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff)); 541 gpx_viper_write(ss, SRC1_OCR_B, 542 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 543 gpx_viper_write(ss, DST_OCR_B, 544 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 545 gpx_viper_write(ss, MASK_1, 0xffff); 546 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg); 547 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg); 548 ss->ss_adder->x_clip_min = 0; 549 ss->ss_adder->x_clip_max = GPX_WIDTH; 550 ss->ss_adder->y_clip_min = 0; 551 ss->ss_adder->y_clip_max = GPX_VISHEIGHT; 552 /* load DESTINATION origin and vectors */ 553 ss->ss_adder->fast_dest_dy = 0; 554 ss->ss_adder->slow_dest_dx = 0; 555 ss->ss_adder->error_1 = 0; 556 ss->ss_adder->error_2 = 0; 557 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 558 gpx_wait(ss, RASTEROP_COMPLETE); 559 ss->ss_adder->destination_x = dx; 560 ss->ss_adder->fast_dest_dx = font->fontwidth; 561 ss->ss_adder->destination_y = dy; 562 ss->ss_adder->slow_dest_dy = font->fontheight; 563 /* load SOURCE origin and vectors */ 564 ss->ss_adder->source_1_x = sx; 565 ss->ss_adder->source_1_y = sy; 566 ss->ss_adder->source_1_dx = font->fontwidth; 567 ss->ss_adder->source_1_dy = font->fontheight; 568 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1; 569 570 if (ul != 0) { 571 gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth, 572 1, attr, LF_R3); /* fg fill */ 573 } 574 } 575 576 void 577 gpx_copycols(void *v, int row, int src, int dst, int cnt) 578 { 579 struct rasops_info *ri = v; 580 struct gpx_screen *ss = ri->ri_hw; 581 struct wsdisplay_font *font = ri->ri_font; 582 int sx, y, dx, w, h; 583 584 sx = ri->ri_xorigin + src * font->fontwidth; 585 dx = ri->ri_xorigin + dst * font->fontwidth; 586 w = cnt * font->fontwidth; 587 y = ri->ri_yorigin + row * font->fontheight; 588 h = font->fontheight; 589 590 gpx_copyrect(ss, sx, y, dx, y, w, h); 591 } 592 593 void 594 gpx_erasecols(void *v, int row, int col, int cnt, long attr) 595 { 596 struct rasops_info *ri = v; 597 struct gpx_screen *ss = ri->ri_hw; 598 struct wsdisplay_font *font = ri->ri_font; 599 int x, y, dx, dy; 600 601 x = ri->ri_xorigin + col * font->fontwidth; 602 dx = cnt * font->fontwidth; 603 y = ri->ri_yorigin + row * font->fontheight; 604 dy = font->fontheight; 605 606 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */ 607 } 608 609 void 610 gpx_copyrows(void *v, int src, int dst, int cnt) 611 { 612 struct rasops_info *ri = v; 613 struct gpx_screen *ss = ri->ri_hw; 614 struct wsdisplay_font *font = ri->ri_font; 615 int x, sy, dy, w, h; 616 617 x = ri->ri_xorigin; 618 w = ri->ri_emustride; 619 sy = ri->ri_yorigin + src * font->fontheight; 620 dy = ri->ri_yorigin + dst * font->fontheight; 621 h = cnt * font->fontheight; 622 623 gpx_copyrect(ss, x, sy, x, dy, w, h); 624 } 625 626 void 627 gpx_eraserows(void *v, int row, int cnt, long attr) 628 { 629 struct rasops_info *ri = v; 630 struct gpx_screen *ss = ri->ri_hw; 631 struct wsdisplay_font *font = ri->ri_font; 632 int x, y, dx, dy; 633 634 x = ri->ri_xorigin; 635 dx = ri->ri_emustride; 636 y = ri->ri_yorigin + row * font->fontheight; 637 dy = cnt * font->fontheight; 638 639 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */ 640 } 641 642 void 643 gpx_do_cursor(struct rasops_info *ri) 644 { 645 struct gpx_screen *ss = ri->ri_hw; 646 int x, y, w, h; 647 648 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 649 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 650 w = ri->ri_font->fontwidth; 651 h = ri->ri_font->fontheight; 652 653 gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4); /* invert */ 654 } 655 656 /* 657 * low-level programming routines 658 */ 659 660 int 661 gpx_wait(struct gpx_screen *ss, int bits) 662 { 663 int i; 664 665 ss->ss_adder->status = 0; 666 for (i = 100000; i != 0; i--) { 667 if ((ss->ss_adder->status & bits) == bits) 668 break; 669 DELAY(1); 670 } 671 672 return i == 0; 673 } 674 675 int 676 gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val) 677 { 678 if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 && 679 gpx_wait(ss, TX_READY) == 0) { 680 ss->ss_adder->id_data = val; 681 ss->ss_adder->command = ID_LOAD | reg; 682 return 0; 683 } 684 #ifdef DEBUG 685 if (ss->ss_console == 0) /* don't make things worse! */ 686 printf("gpx_viper_write failure, reg %x val %x\n", reg, val); 687 #endif 688 return 1; 689 } 690 691 /* Initialize the damned beast. Straight from qdss. */ 692 void 693 gpx_reset_viper(struct gpx_screen *ss) 694 { 695 int i; 696 697 ss->ss_adder->interrupt_enable = 0; 698 ss->ss_adder->command = CANCEL; 699 /* set monitor timing */ 700 ss->ss_adder->x_scan_count_0 = 0x2800; 701 ss->ss_adder->x_scan_count_1 = 0x1020; 702 ss->ss_adder->x_scan_count_2 = 0x003a; 703 ss->ss_adder->x_scan_count_3 = 0x38f0; 704 ss->ss_adder->x_scan_count_4 = 0x6128; 705 ss->ss_adder->x_scan_count_5 = 0x093a; 706 ss->ss_adder->x_scan_count_6 = 0x313c; 707 ss->ss_adder->sync_phase_adj = 0x0100; 708 ss->ss_adder->x_scan_conf = 0x00c8; 709 /* 710 * got a bug in second pass ADDER! lets take care of it... 711 * 712 * normally, just use the code in the following bug fix code, but to 713 * make repeated demos look pretty, load the registers as if there was 714 * no bug and then test to see if we are getting sync 715 */ 716 ss->ss_adder->y_scan_count_0 = 0x135f; 717 ss->ss_adder->y_scan_count_1 = 0x3363; 718 ss->ss_adder->y_scan_count_2 = 0x2366; 719 ss->ss_adder->y_scan_count_3 = 0x0388; 720 /* 721 * if no sync, do the bug fix code 722 */ 723 if (gpx_wait(ss, FRAME_SYNC) != 0) { 724 /* 725 * First load all Y scan registers with very short frame and 726 * wait for scroll service. This guarantees at least one SYNC 727 * to fix the pass 2 Adder initialization bug (synchronizes 728 * XCINCH with DMSEEDH) 729 */ 730 ss->ss_adder->y_scan_count_0 = 0x01; 731 ss->ss_adder->y_scan_count_1 = 0x01; 732 ss->ss_adder->y_scan_count_2 = 0x01; 733 ss->ss_adder->y_scan_count_3 = 0x01; 734 /* delay at least 1 full frame time */ 735 gpx_wait(ss, FRAME_SYNC); 736 gpx_wait(ss, FRAME_SYNC); 737 /* 738 * now load the REAL sync values (in reverse order just to 739 * be safe). 740 */ 741 ss->ss_adder->y_scan_count_3 = 0x0388; 742 ss->ss_adder->y_scan_count_2 = 0x2366; 743 ss->ss_adder->y_scan_count_1 = 0x3363; 744 ss->ss_adder->y_scan_count_0 = 0x135f; 745 } 746 /* zero the index registers */ 747 ss->ss_adder->x_index_pending = 0; 748 ss->ss_adder->y_index_pending = 0; 749 ss->ss_adder->x_index_new = 0; 750 ss->ss_adder->y_index_new = 0; 751 ss->ss_adder->x_index_old = 0; 752 ss->ss_adder->y_index_old = 0; 753 ss->ss_adder->pause = 0; 754 /* set rasterop mode to normal pen down */ 755 ss->ss_adder->rasterop_mode = 756 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; 757 /* set the rasterop registers to default values */ 758 ss->ss_adder->source_1_dx = 1; 759 ss->ss_adder->source_1_dy = 1; 760 ss->ss_adder->source_1_x = 0; 761 ss->ss_adder->source_1_y = 0; 762 ss->ss_adder->destination_x = 0; 763 ss->ss_adder->destination_y = 0; 764 ss->ss_adder->fast_dest_dx = 1; 765 ss->ss_adder->fast_dest_dy = 0; 766 ss->ss_adder->slow_dest_dx = 0; 767 ss->ss_adder->slow_dest_dy = 1; 768 ss->ss_adder->error_1 = 0; 769 ss->ss_adder->error_2 = 0; 770 /* scale factor = UNITY */ 771 ss->ss_adder->fast_scale = UNITY; 772 ss->ss_adder->slow_scale = UNITY; 773 /* set the source 2 parameters */ 774 ss->ss_adder->source_2_x = 0; 775 ss->ss_adder->source_2_y = 0; 776 ss->ss_adder->source_2_size = 0x0022; 777 /* initialize plane addresses for eight vipers */ 778 for (i = 0; i < 8; i++) { 779 gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i); 780 gpx_viper_write(ss, PLANE_ADDRESS, i); 781 } 782 /* initialize the external registers. */ 783 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff); 784 gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff); 785 /* initialize resolution mode */ 786 gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c); /* bus width = 16 */ 787 gpx_viper_write(ss, RESOLUTION_MODE, 0x0000); /* one bit/pixel */ 788 /* initialize viper registers */ 789 gpx_viper_write(ss, SCROLL_CONSTANT, 790 SCROLL_ENABLE | VIPER_LEFT | VIPER_UP); 791 gpx_viper_write(ss, SCROLL_FILL, 0x0000); 792 /* set clipping and scrolling limits to full screen */ 793 gpx_wait(ss, ADDRESS_COMPLETE); 794 ss->ss_adder->x_clip_min = 0; 795 ss->ss_adder->x_clip_max = GPX_WIDTH; 796 ss->ss_adder->y_clip_min = 0; 797 ss->ss_adder->y_clip_max = GPX_HEIGHT; 798 ss->ss_adder->scroll_x_min = 0; 799 ss->ss_adder->scroll_x_max = GPX_WIDTH; 800 ss->ss_adder->scroll_y_min = 0; 801 ss->ss_adder->scroll_y_max = GPX_HEIGHT; 802 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */ 803 gpx_wait(ss, FRAME_SYNC); 804 ss->ss_adder->x_index_pending = 0; 805 ss->ss_adder->y_index_pending = 0; 806 ss->ss_adder->x_index_new = 0; 807 ss->ss_adder->y_index_new = 0; 808 ss->ss_adder->x_index_old = 0; 809 ss->ss_adder->y_index_old = 0; 810 gpx_wait(ss, ADDRESS_COMPLETE); 811 gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000); 812 gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000); 813 /* set source and the mask register to all ones */ 814 gpx_viper_write(ss, SOURCE, 0xffff); 815 gpx_viper_write(ss, MASK_1, 0xffff); 816 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 817 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 818 /* initialize Operand Control Register banks for fill command */ 819 gpx_viper_write(ss, SRC1_OCR_A, EXT_NONE | INT_M1_M2 | NO_ID | WAIT); 820 gpx_viper_write(ss, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT); 821 gpx_viper_write(ss, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT); 822 gpx_viper_write(ss, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT); 823 gpx_viper_write(ss, SRC2_OCR_B, EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT); 824 gpx_viper_write(ss, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT); 825 826 /* 827 * Init Logic Unit Function registers. 828 */ 829 /* putchar */ 830 gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE); 831 /* erase{cols,rows} */ 832 gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS); 833 /* underline */ 834 gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES); 835 /* cursor */ 836 gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D); 837 } 838 839 /* Clear the whole screen. Straight from qdss. */ 840 void 841 gpx_clear_screen(struct gpx_screen *ss) 842 { 843 844 ss->ss_adder->x_limit = GPX_WIDTH; 845 ss->ss_adder->y_limit = GPX_HEIGHT; 846 ss->ss_adder->y_offset_pending = 0; 847 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */ 848 gpx_wait(ss, FRAME_SYNC); 849 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 850 gpx_wait(ss, FRAME_SYNC); 851 gpx_wait(ss, FRAME_SYNC); 852 ss->ss_adder->y_offset_pending = GPX_VISHEIGHT; 853 gpx_wait(ss, FRAME_SYNC); 854 gpx_wait(ss, FRAME_SYNC); 855 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 856 gpx_wait(ss, FRAME_SYNC); 857 gpx_wait(ss, FRAME_SYNC); 858 ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT; 859 gpx_wait(ss, FRAME_SYNC); 860 gpx_wait(ss, FRAME_SYNC); 861 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 862 gpx_wait(ss, FRAME_SYNC); 863 gpx_wait(ss, FRAME_SYNC); 864 ss->ss_adder->y_offset_pending = 0; /* back to normal */ 865 gpx_wait(ss, FRAME_SYNC); 866 gpx_wait(ss, FRAME_SYNC); 867 ss->ss_adder->x_limit = GPX_WIDTH; 868 ss->ss_adder->y_limit = GPX_VISHEIGHT; 869 } 870 871 int 872 gpx_setup_screen(struct gpx_screen *ss) 873 { 874 struct rasops_info *ri = &ss->ss_ri; 875 int cookie; 876 877 memset(ri, 0, sizeof(*ri)); 878 ri->ri_depth = 8; /* masquerade as a 8 bit device for rasops */ 879 ri->ri_width = GPX_WIDTH; 880 ri->ri_height = GPX_VISHEIGHT; 881 ri->ri_stride = GPX_WIDTH; 882 ri->ri_flg = RI_CENTER; /* no RI_CLEAR as ri_bits is NULL! */ 883 ri->ri_hw = ss; 884 if (ss == &gpx_consscr) 885 ri->ri_flg |= RI_NO_AUTO; 886 887 /* 888 * We can not let rasops select our font, because we need to use 889 * a font with right-to-left bit order on this frame buffer. 890 */ 891 wsfont_init(); 892 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L, 893 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 894 if (cookie < 0) 895 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 896 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 897 if (cookie < 0) 898 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 899 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 900 if (cookie < 0) 901 return -1; 902 if (wsfont_lock(cookie, &ri->ri_font) != 0) 903 return -1; 904 ri->ri_wsfcookie = cookie; 905 906 /* 907 * Ask for an unholy big display, rasops will trim this to more 908 * reasonable values. 909 */ 910 if (rasops_init(ri, 160, 160) != 0) 911 return -1; 912 913 /* 914 * Override the rasops emulops. 915 */ 916 ri->ri_ops.copyrows = gpx_copyrows; 917 ri->ri_ops.copycols = gpx_copycols; 918 ri->ri_ops.eraserows = gpx_eraserows; 919 ri->ri_ops.erasecols = gpx_erasecols; 920 ri->ri_ops.putchar = gpx_putchar; 921 ri->ri_do_cursor = gpx_do_cursor; 922 923 gpx_stdscreen.ncols = ri->ri_cols; 924 gpx_stdscreen.nrows = ri->ri_rows; 925 gpx_stdscreen.textops = &ri->ri_ops; 926 gpx_stdscreen.fontwidth = ri->ri_font->fontwidth; 927 gpx_stdscreen.fontheight = ri->ri_font->fontheight; 928 gpx_stdscreen.capabilities = ri->ri_caps; 929 930 /* 931 * Initialize RAMDAC. 932 */ 933 if (ss->ss_depth == 8) { 934 struct ramdac8 *rd = ss->ss_vdac; 935 rd->address = BT_CR; 936 rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4; 937 } else { 938 struct ramdac4 *rd = ss->ss_vdac; 939 rd->control = RAMDAC4_INIT; 940 } 941 942 /* 943 * Put the ADDER and VIPER in a good state. 944 */ 945 gpx_reset_viper(ss); 946 947 /* 948 * Initialize colormap. 949 */ 950 gpx_resetcmap(ss); 951 952 /* 953 * Clear display (including non-visible area), in 864 lines chunks. 954 */ 955 gpx_clear_screen(ss); 956 957 /* 958 * Copy our font to the offscreen area. 959 */ 960 gpx_upload_font(ss); 961 962 #if 0 963 ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI; 964 #endif 965 966 return 0; 967 } 968 969 /* 970 * Copy the selected wsfont to non-visible frame buffer area. 971 * This is necessary since the only way to send data to the frame buffer 972 * is through the ID interface, which is slow and needs 16 bit wide data. 973 * Adapted from qdss. 974 */ 975 void 976 gpx_upload_font(struct gpx_screen *ss) 977 { 978 struct rasops_info *ri = &ss->ss_ri; 979 struct wsdisplay_font *font = ri->ri_font; 980 uint8_t *fontbits, *fb; 981 u_int remaining, nchars, row; 982 u_int i, j; 983 uint16_t data; 984 985 /* setup VIPER operand control registers */ 986 987 gpx_viper_write(ss, MASK_1, 0xffff); 988 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 989 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 990 991 gpx_viper_write(ss, SRC1_OCR_B, 992 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); 993 gpx_viper_write(ss, SRC2_OCR_B, 994 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); 995 gpx_viper_write(ss, DST_OCR_B, 996 EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 997 998 ss->ss_adder->rasterop_mode = 999 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; 1000 gpx_wait(ss, RASTEROP_COMPLETE); 1001 1002 /* 1003 * Load font data. The font is uploaded in 8 or 16 bit wide cells, on 1004 * as many ``lines'' as necessary at the end of the display. 1005 */ 1006 ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars); 1007 if (ss->ss_gpr & 1) 1008 ss->ss_gpr--; 1009 fontbits = font->data; 1010 for (row = 1, remaining = font->numchars; remaining != 0; 1011 row++, remaining -= nchars) { 1012 nchars = MIN(ss->ss_gpr, remaining); 1013 1014 ss->ss_adder->destination_x = 0; 1015 ss->ss_adder->destination_y = 1016 GPX_HEIGHT - row * font->fontheight; 1017 ss->ss_adder->fast_dest_dx = nchars * 16; 1018 ss->ss_adder->slow_dest_dy = font->fontheight; 1019 1020 /* setup for processor to bitmap xfer */ 1021 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff); 1022 ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/ 1023 1024 /* iteratively do the processor to bitmap xfer */ 1025 for (i = font->fontheight; i != 0; i--) { 1026 fb = fontbits; 1027 fontbits += font->stride; 1028 /* PTOB a scan line */ 1029 for (j = nchars; j != 0; j--) { 1030 /* PTOB one scan of a char cell */ 1031 if (font->stride == 1) { 1032 data = *fb; 1033 fb += font->fontheight; 1034 /* 1035 * Do not access past font memory if 1036 * it has an odd number of characters 1037 * and this is the last pair. 1038 */ 1039 if (j != 1 || (nchars & 1) == 0 || 1040 remaining != nchars) { 1041 data |= ((uint16_t)*fb) << 8; 1042 fb += font->fontheight; 1043 } 1044 } else { 1045 data = 1046 fb[0] | (((uint16_t)fb[1]) << 8); 1047 fb += font->fontheight * font->stride; 1048 } 1049 1050 gpx_wait(ss, TX_READY); 1051 ss->ss_adder->id_data = data; 1052 } 1053 } 1054 fontbits += (nchars - 1) * font->stride * font->fontheight; 1055 } 1056 } 1057 1058 void 1059 gpx_copyrect(struct gpx_screen *ss, 1060 int sx, int sy, int dx, int dy, int w, int h) 1061 { 1062 1063 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff)) 1064 continue; 1065 gpx_viper_write(ss, MASK_1, 0xffff); 1066 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 1067 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 1068 gpx_viper_write(ss, SRC1_OCR_B, 1069 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 1070 gpx_viper_write(ss, DST_OCR_B, 1071 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 1072 ss->ss_adder->fast_dest_dy = 0; 1073 ss->ss_adder->slow_dest_dx = 0; 1074 ss->ss_adder->error_1 = 0; 1075 ss->ss_adder->error_2 = 0; 1076 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 1077 gpx_wait(ss, RASTEROP_COMPLETE); 1078 ss->ss_adder->destination_x = dx; 1079 ss->ss_adder->fast_dest_dx = w; 1080 ss->ss_adder->destination_y = dy; 1081 ss->ss_adder->slow_dest_dy = h; 1082 ss->ss_adder->source_1_x = sx; 1083 ss->ss_adder->source_1_dx = w; 1084 ss->ss_adder->source_1_y = sy; 1085 ss->ss_adder->source_1_dy = h; 1086 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1; 1087 } 1088 1089 /* 1090 * Fill a rectangle with the given attribute and function (i.e. rop). 1091 */ 1092 void 1093 gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr, 1094 u_int function) 1095 { 1096 int fg, bg; 1097 1098 rasops_unpack_attr(attr, &fg, &bg, NULL); 1099 1100 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff)); 1101 gpx_viper_write(ss, MASK_1, 0xffff); 1102 gpx_viper_write(ss, SOURCE, 0xffff); 1103 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg); 1104 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg); 1105 gpx_viper_write(ss, SRC1_OCR_B, 1106 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 1107 gpx_viper_write(ss, DST_OCR_B, 1108 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 1109 ss->ss_adder->fast_dest_dx = 0; 1110 ss->ss_adder->fast_dest_dy = 0; 1111 ss->ss_adder->slow_dest_dx = 0; 1112 ss->ss_adder->error_1 = 0; 1113 ss->ss_adder->error_2 = 0; 1114 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 1115 gpx_wait(ss, RASTEROP_COMPLETE); 1116 ss->ss_adder->destination_x = x; 1117 ss->ss_adder->fast_dest_dx = dx; 1118 ss->ss_adder->destination_y = y; 1119 ss->ss_adder->slow_dest_dy = dy; 1120 ss->ss_adder->source_1_x = x; 1121 ss->ss_adder->source_1_dx = dx; 1122 ss->ss_adder->source_1_y = y; 1123 ss->ss_adder->source_1_dy = dy; 1124 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function; 1125 } 1126 1127 /* 1128 * Colormap handling routines 1129 */ 1130 1131 int 1132 gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) 1133 { 1134 u_int index = cm->index, count = cm->count, i; 1135 u_int colcount = 1 << ss->ss_depth; 1136 int error; 1137 uint8_t ramp[256], *c, *r; 1138 1139 if (index >= colcount || count > colcount - index) 1140 return EINVAL; 1141 1142 /* extract reds */ 1143 c = ss->ss_cmap + 0 + index * 3; 1144 for (i = count, r = ramp; i != 0; i--) 1145 *r++ = *c << (8 - ss->ss_depth), c += 3; 1146 if ((error = copyout(ramp, cm->red, count)) != 0) 1147 return error; 1148 1149 /* extract greens */ 1150 c = ss->ss_cmap + 1 + index * 3; 1151 for (i = count, r = ramp; i != 0; i--) 1152 *r++ = *c << (8 - ss->ss_depth), c += 3; 1153 if ((error = copyout(ramp, cm->green, count)) != 0) 1154 return error; 1155 1156 /* extract blues */ 1157 c = ss->ss_cmap + 2 + index * 3; 1158 for (i = count, r = ramp; i != 0; i--) 1159 *r++ = *c << (8 - ss->ss_depth), c += 3; 1160 if ((error = copyout(ramp, cm->blue, count)) != 0) 1161 return error; 1162 1163 return 0; 1164 } 1165 1166 int 1167 gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) 1168 { 1169 u_int index = cm->index, count = cm->count; 1170 u_int colcount = 1 << ss->ss_depth; 1171 int i, error; 1172 uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c; 1173 1174 if (index >= colcount || count > colcount - index) 1175 return EINVAL; 1176 1177 if ((error = copyin(cm->red, r, count)) != 0) 1178 return error; 1179 if ((error = copyin(cm->green, g, count)) != 0) 1180 return error; 1181 if ((error = copyin(cm->blue, b, count)) != 0) 1182 return error; 1183 1184 nr = r, ng = g, nb = b; 1185 c = ss->ss_cmap + index * 3; 1186 for (i = count; i != 0; i--) { 1187 *c++ = *nr++ >> (8 - ss->ss_depth); 1188 *c++ = *ng++ >> (8 - ss->ss_depth); 1189 *c++ = *nb++ >> (8 - ss->ss_depth); 1190 } 1191 1192 return 0; 1193 } 1194 1195 void 1196 gpx_loadcmap(struct gpx_screen *ss, int from, int count) 1197 { 1198 uint8_t *cmap = ss->ss_cmap; 1199 int i, color12; 1200 1201 gpx_wait(ss, FRAME_SYNC); 1202 if (ss->ss_depth == 8) { 1203 struct ramdac8 *rd = ss->ss_vdac; 1204 1205 cmap += from * 3; 1206 rd->address = from; 1207 for (i = 0; i < count * 3; i++) 1208 rd->cmapdata = *cmap++; 1209 } else { 1210 struct ramdac4 *rd = ss->ss_vdac; 1211 1212 cmap = ss->ss_cmap + from; 1213 for (i = from; i < from + count; i++) { 1214 color12 = (*cmap++ >> 4) << 0; 1215 color12 |= (*cmap++ >> 4) << 8; 1216 color12 |= (*cmap++ >> 4) << 4; 1217 rd->colormap[i] = color12; 1218 } 1219 } 1220 } 1221 1222 void 1223 gpx_resetcmap(struct gpx_screen *ss) 1224 { 1225 1226 if (ss->ss_depth == 8) 1227 memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap)); 1228 else { 1229 memcpy(ss->ss_cmap, rasops_cmap, 8 * 3); 1230 memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3); 1231 } 1232 gpx_loadcmap(ss, 0, 1 << ss->ss_depth); 1233 1234 /* 1235 * On the 4bit RAMDAC, make the hardware cursor black on black 1236 */ 1237 if (ss->ss_depth != 8) { 1238 struct ramdac4 *rd = ss->ss_vdac; 1239 1240 rd->cursormap[0] = rd->cursormap[1] = 1241 rd->cursormap[2] = rd->cursormap[3] = 0x0000; 1242 } 1243 } 1244 1245 /* 1246 * Console support code 1247 */ 1248 1249 cons_decl(gpx); 1250 1251 /* 1252 * Called very early to setup the glass tty as console. 1253 * Because it's called before the VM system is initialized, virtual memory 1254 * for the framebuffer can be stolen directly without disturbing anything. 1255 */ 1256 void 1257 gpxcnprobe(struct consdev *cndev) 1258 { 1259 extern vaddr_t virtual_avail; 1260 extern const struct cdevsw wsdisplay_cdevsw; 1261 volatile struct adder *adder; 1262 vaddr_t tmp; 1263 int depth; 1264 u_short status; 1265 1266 switch (vax_boardtype) { 1267 case VAX_BTYP_410: 1268 case VAX_BTYP_420: 1269 case VAX_BTYP_43: 1270 if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0) 1271 break; /* doesn't use graphics console */ 1272 1273 if ((vax_confdata & KA420_CFG_VIDOPT) == 0) 1274 break; /* no color option */ 1275 1276 /* Check for hardware */ 1277 tmp = virtual_avail; 1278 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1); 1279 adder = (struct adder *)tmp; 1280 adder->status = 0; 1281 status = adder->status; 1282 iounaccess(tmp, 1); 1283 if (status == offsetof(struct adder, status)) 1284 return; 1285 1286 /* Check for a recognized color depth */ 1287 tmp = virtual_avail; 1288 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); 1289 depth = *(uint16_t *) 1290 (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0; 1291 iounaccess(tmp, 1); 1292 if (depth != 0x00f0 && depth != 0x0080) 1293 return; 1294 1295 cndev->cn_pri = CN_INTERNAL; 1296 cndev->cn_dev = 1297 makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 1298 break; 1299 1300 default: 1301 break; 1302 } 1303 } 1304 1305 /* 1306 * Called very early to setup the glass tty as console. 1307 * Because it's called before the VM system is initialized, virtual memory 1308 * for the framebuffer can be stolen directly without disturbing anything. 1309 */ 1310 void 1311 gpxcninit(struct consdev *cndev) 1312 { 1313 struct gpx_screen *ss = &gpx_consscr; 1314 extern vaddr_t virtual_avail; 1315 vaddr_t ova; 1316 long defattr; 1317 struct rasops_info *ri; 1318 1319 ova = virtual_avail; 1320 1321 ioaccess(virtual_avail, 1322 vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); 1323 ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail + 1324 (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8; 1325 1326 ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1); 1327 ss->ss_adder = (struct adder *)virtual_avail; 1328 virtual_avail += VAX_NBPG; 1329 1330 ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1); 1331 ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET)); 1332 virtual_avail += VAX_NBPG; 1333 1334 #if 0 1335 ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1); 1336 ss->ss_cursor = (struct dc503reg *)virtual_avail; 1337 virtual_avail += VAX_NBPG; 1338 #endif 1339 1340 virtual_avail = round_page(virtual_avail); 1341 1342 /* this had better not fail */ 1343 if (gpx_setup_screen(ss) != 0) { 1344 #if 0 1345 iounaccess((vaddr_t)ss->ss_cursor, 1); 1346 #endif 1347 iounaccess((vaddr_t)ss->ss_vdac, 1); 1348 iounaccess((vaddr_t)ss->ss_adder, 1); 1349 virtual_avail = ova; 1350 return; 1351 } 1352 1353 ri = &ss->ss_ri; 1354 ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr); 1355 wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr); 1356 cn_tab->cn_pri = CN_INTERNAL; 1357 1358 #if NDZKBD > 0 1359 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 1360 #endif 1361 } 1362