1/* $NetBSD: gpx.c,v 1.3 2024/02/03 16:21:25 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 */ 163struct 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 */ 174struct ramdac8 { 175 uint16_t address; 176 uint16_t cmapdata; 177 uint16_t control; 178 uint16_t omapdata; 179}; 180 181struct gpx_screen { 182 struct rasops_info ss_ri; 183 int ss_console; 184 u_int ss_depth; 185 u_int ss_gpr; /* font glyphs per row */ 186 struct adder *ss_adder; 187 void *ss_vdac; 188 uint8_t ss_cmap[256 * 3]; 189#if 0 190 struct dc503reg *ss_cursor; 191 uint16_t ss_curcmd; 192#endif 193}; 194 195struct gpx_softc { 196 device_t sc_dev; 197 struct gpx_screen *sc_scr; 198 int sc_nscreens; 199}; 200 201static int gpx_match(device_t, cfdata_t, void *); 202static void gpx_attach(device_t, device_t, void *); 203 204static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *); 205static paddr_t gpx_mmap(void *, void *, off_t, int); 206static int gpx_alloc_screen(void *, const struct wsscreen_descr *, 207 void **, int *, int *, long *); 208static void gpx_free_screen(void *, void *); 209static int gpx_show_screen(void *, void *, int, 210 void (*) (void *, int, int), void *); 211 212static void gpx_putchar(void *, int, int, u_int, long); 213static void gpx_copycols(void *, int, int, int, int); 214static void gpx_erasecols(void *, int, int, int, long); 215static void gpx_copyrows(void *, int, int, int); 216static void gpx_eraserows(void *, int, int, long); 217static void gpx_do_cursor(struct rasops_info *); 218 219static int gpx_wait(struct gpx_screen *, int); 220static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t); 221static void gpx_reset_viper(struct gpx_screen *); 222static void gpx_clear_screen(struct gpx_screen *); 223static int gpx_setup_screen(struct gpx_screen *); 224static void gpx_upload_font(struct gpx_screen *); 225static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int); 226static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int); 227static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *); 228static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *); 229static void gpx_loadcmap(struct gpx_screen *, int, int); 230static void gpx_resetcmap(struct gpx_screen *); 231 232/* for console */ 233static struct gpx_screen gpx_consscr; 234 235CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc), 236 gpx_match, gpx_attach, NULL, NULL); 237 238static struct wsscreen_descr gpx_stdscreen = { 239 "std", 240}; 241 242static const struct wsscreen_descr *_gpx_scrlist[] = { 243 &gpx_stdscreen, 244}; 245 246static const struct wsscreen_list gpx_screenlist = { 247 sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *), 248 _gpx_scrlist, 249}; 250 251static const struct wsdisplay_accessops gpx_accessops = { 252 .ioctl = gpx_ioctl, 253 .mmap = gpx_mmap, 254 .alloc_screen = gpx_alloc_screen, 255 .free_screen = gpx_free_screen, 256 .show_screen = gpx_show_screen, 257 .load_font = NULL 258}; 259 260/* 261 * Autoconf glue 262 */ 263 264static int 265gpx_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 334static void 335gpx_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 426static int 427gpx_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 475static paddr_t 476gpx_mmap(void *v, void *vs, off_t offset, int prot) 477{ 478 479 return -1; 480} 481 482static int 483gpx_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 501static void 502gpx_free_screen(void *v, void *cookie) 503{ 504 struct gpx_softc *sc = v; 505 506 sc->sc_nscreens--; 507} 508 509static int 510gpx_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 521static void 522gpx_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 continue; 542 gpx_viper_write(ss, SRC1_OCR_B, 543 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 544 gpx_viper_write(ss, DST_OCR_B, 545 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 546 gpx_viper_write(ss, MASK_1, 0xffff); 547 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg); 548 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg); 549 ss->ss_adder->x_clip_min = 0; 550 ss->ss_adder->x_clip_max = GPX_WIDTH; 551 ss->ss_adder->y_clip_min = 0; 552 ss->ss_adder->y_clip_max = GPX_VISHEIGHT; 553 /* load DESTINATION origin and vectors */ 554 ss->ss_adder->fast_dest_dy = 0; 555 ss->ss_adder->slow_dest_dx = 0; 556 ss->ss_adder->error_1 = 0; 557 ss->ss_adder->error_2 = 0; 558 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 559 gpx_wait(ss, RASTEROP_COMPLETE); 560 ss->ss_adder->destination_x = dx; 561 ss->ss_adder->fast_dest_dx = font->fontwidth; 562 ss->ss_adder->destination_y = dy; 563 ss->ss_adder->slow_dest_dy = font->fontheight; 564 /* load SOURCE origin and vectors */ 565 ss->ss_adder->source_1_x = sx; 566 ss->ss_adder->source_1_y = sy; 567 ss->ss_adder->source_1_dx = font->fontwidth; 568 ss->ss_adder->source_1_dy = font->fontheight; 569 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1; 570 571 if (ul != 0) { 572 gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth, 573 1, attr, LF_R3); /* fg fill */ 574 } 575} 576 577static void 578gpx_copycols(void *v, int row, int src, int dst, int cnt) 579{ 580 struct rasops_info *ri = v; 581 struct gpx_screen *ss = ri->ri_hw; 582 struct wsdisplay_font *font = ri->ri_font; 583 int sx, y, dx, w, h; 584 585 sx = ri->ri_xorigin + src * font->fontwidth; 586 dx = ri->ri_xorigin + dst * font->fontwidth; 587 w = cnt * font->fontwidth; 588 y = ri->ri_yorigin + row * font->fontheight; 589 h = font->fontheight; 590 591 gpx_copyrect(ss, sx, y, dx, y, w, h); 592} 593 594static void 595gpx_erasecols(void *v, int row, int col, int cnt, long attr) 596{ 597 struct rasops_info *ri = v; 598 struct gpx_screen *ss = ri->ri_hw; 599 struct wsdisplay_font *font = ri->ri_font; 600 int x, y, dx, dy; 601 602 x = ri->ri_xorigin + col * font->fontwidth; 603 dx = cnt * font->fontwidth; 604 y = ri->ri_yorigin + row * font->fontheight; 605 dy = font->fontheight; 606 607 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */ 608} 609 610static void 611gpx_copyrows(void *v, int src, int dst, int cnt) 612{ 613 struct rasops_info *ri = v; 614 struct gpx_screen *ss = ri->ri_hw; 615 struct wsdisplay_font *font = ri->ri_font; 616 int x, sy, dy, w, h; 617 618 x = ri->ri_xorigin; 619 w = ri->ri_emustride; 620 sy = ri->ri_yorigin + src * font->fontheight; 621 dy = ri->ri_yorigin + dst * font->fontheight; 622 h = cnt * font->fontheight; 623 624 gpx_copyrect(ss, x, sy, x, dy, w, h); 625} 626 627static void 628gpx_eraserows(void *v, int row, int cnt, long attr) 629{ 630 struct rasops_info *ri = v; 631 struct gpx_screen *ss = ri->ri_hw; 632 struct wsdisplay_font *font = ri->ri_font; 633 int x, y, dx, dy; 634 635 x = ri->ri_xorigin; 636 dx = ri->ri_emustride; 637 y = ri->ri_yorigin + row * font->fontheight; 638 dy = cnt * font->fontheight; 639 640 gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */ 641} 642 643static void 644gpx_do_cursor(struct rasops_info *ri) 645{ 646 struct gpx_screen *ss = ri->ri_hw; 647 int x, y, w, h; 648 649 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 650 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 651 w = ri->ri_font->fontwidth; 652 h = ri->ri_font->fontheight; 653 654 gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4); /* invert */ 655} 656 657/* 658 * low-level programming routines 659 */ 660 661static int 662gpx_wait(struct gpx_screen *ss, int bits) 663{ 664 int i; 665 666 ss->ss_adder->status = 0; 667 for (i = 100000; i != 0; i--) { 668 if ((ss->ss_adder->status & bits) == bits) 669 break; 670 DELAY(1); 671 } 672 673 return i == 0; 674} 675 676static int 677gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val) 678{ 679 if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 && 680 gpx_wait(ss, TX_READY) == 0) { 681 ss->ss_adder->id_data = val; 682 ss->ss_adder->command = ID_LOAD | reg; 683 return 0; 684 } 685#ifdef DEBUG 686 if (ss->ss_console == 0) /* don't make things worse! */ 687 printf("gpx_viper_write failure, reg %x val %x\n", reg, val); 688#endif 689 return 1; 690} 691 692/* Initialize the damned beast. Straight from qdss. */ 693static void 694gpx_reset_viper(struct gpx_screen *ss) 695{ 696 int i; 697 698 ss->ss_adder->interrupt_enable = 0; 699 ss->ss_adder->command = CANCEL; 700 /* set monitor timing */ 701 ss->ss_adder->x_scan_count_0 = 0x2800; 702 ss->ss_adder->x_scan_count_1 = 0x1020; 703 ss->ss_adder->x_scan_count_2 = 0x003a; 704 ss->ss_adder->x_scan_count_3 = 0x38f0; 705 ss->ss_adder->x_scan_count_4 = 0x6128; 706 ss->ss_adder->x_scan_count_5 = 0x093a; 707 ss->ss_adder->x_scan_count_6 = 0x313c; 708 ss->ss_adder->sync_phase_adj = 0x0100; 709 ss->ss_adder->x_scan_conf = 0x00c8; 710 /* 711 * got a bug in second pass ADDER! lets take care of it... 712 * 713 * normally, just use the code in the following bug fix code, but to 714 * make repeated demos look pretty, load the registers as if there was 715 * no bug and then test to see if we are getting sync 716 */ 717 ss->ss_adder->y_scan_count_0 = 0x135f; 718 ss->ss_adder->y_scan_count_1 = 0x3363; 719 ss->ss_adder->y_scan_count_2 = 0x2366; 720 ss->ss_adder->y_scan_count_3 = 0x0388; 721 /* 722 * if no sync, do the bug fix code 723 */ 724 if (gpx_wait(ss, FRAME_SYNC) != 0) { 725 /* 726 * First load all Y scan registers with very short frame and 727 * wait for scroll service. This guarantees at least one SYNC 728 * to fix the pass 2 Adder initialization bug (synchronizes 729 * XCINCH with DMSEEDH) 730 */ 731 ss->ss_adder->y_scan_count_0 = 0x01; 732 ss->ss_adder->y_scan_count_1 = 0x01; 733 ss->ss_adder->y_scan_count_2 = 0x01; 734 ss->ss_adder->y_scan_count_3 = 0x01; 735 /* delay at least 1 full frame time */ 736 gpx_wait(ss, FRAME_SYNC); 737 gpx_wait(ss, FRAME_SYNC); 738 /* 739 * now load the REAL sync values (in reverse order just to 740 * be safe). 741 */ 742 ss->ss_adder->y_scan_count_3 = 0x0388; 743 ss->ss_adder->y_scan_count_2 = 0x2366; 744 ss->ss_adder->y_scan_count_1 = 0x3363; 745 ss->ss_adder->y_scan_count_0 = 0x135f; 746 } 747 /* zero the index registers */ 748 ss->ss_adder->x_index_pending = 0; 749 ss->ss_adder->y_index_pending = 0; 750 ss->ss_adder->x_index_new = 0; 751 ss->ss_adder->y_index_new = 0; 752 ss->ss_adder->x_index_old = 0; 753 ss->ss_adder->y_index_old = 0; 754 ss->ss_adder->pause = 0; 755 /* set rasterop mode to normal pen down */ 756 ss->ss_adder->rasterop_mode = 757 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; 758 /* set the rasterop registers to default values */ 759 ss->ss_adder->source_1_dx = 1; 760 ss->ss_adder->source_1_dy = 1; 761 ss->ss_adder->source_1_x = 0; 762 ss->ss_adder->source_1_y = 0; 763 ss->ss_adder->destination_x = 0; 764 ss->ss_adder->destination_y = 0; 765 ss->ss_adder->fast_dest_dx = 1; 766 ss->ss_adder->fast_dest_dy = 0; 767 ss->ss_adder->slow_dest_dx = 0; 768 ss->ss_adder->slow_dest_dy = 1; 769 ss->ss_adder->error_1 = 0; 770 ss->ss_adder->error_2 = 0; 771 /* scale factor = UNITY */ 772 ss->ss_adder->fast_scale = UNITY; 773 ss->ss_adder->slow_scale = UNITY; 774 /* set the source 2 parameters */ 775 ss->ss_adder->source_2_x = 0; 776 ss->ss_adder->source_2_y = 0; 777 ss->ss_adder->source_2_size = 0x0022; 778 /* initialize plane addresses for eight vipers */ 779 for (i = 0; i < 8; i++) { 780 gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i); 781 gpx_viper_write(ss, PLANE_ADDRESS, i); 782 } 783 /* initialize the external registers. */ 784 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff); 785 gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff); 786 /* initialize resolution mode */ 787 gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c); /* bus width = 16 */ 788 gpx_viper_write(ss, RESOLUTION_MODE, 0x0000); /* one bit/pixel */ 789 /* initialize viper registers */ 790 gpx_viper_write(ss, SCROLL_CONSTANT, 791 SCROLL_ENABLE | VIPER_LEFT | VIPER_UP); 792 gpx_viper_write(ss, SCROLL_FILL, 0x0000); 793 /* set clipping and scrolling limits to full screen */ 794 gpx_wait(ss, ADDRESS_COMPLETE); 795 ss->ss_adder->x_clip_min = 0; 796 ss->ss_adder->x_clip_max = GPX_WIDTH; 797 ss->ss_adder->y_clip_min = 0; 798 ss->ss_adder->y_clip_max = GPX_HEIGHT; 799 ss->ss_adder->scroll_x_min = 0; 800 ss->ss_adder->scroll_x_max = GPX_WIDTH; 801 ss->ss_adder->scroll_y_min = 0; 802 ss->ss_adder->scroll_y_max = GPX_HEIGHT; 803 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */ 804 gpx_wait(ss, FRAME_SYNC); 805 ss->ss_adder->x_index_pending = 0; 806 ss->ss_adder->y_index_pending = 0; 807 ss->ss_adder->x_index_new = 0; 808 ss->ss_adder->y_index_new = 0; 809 ss->ss_adder->x_index_old = 0; 810 ss->ss_adder->y_index_old = 0; 811 gpx_wait(ss, ADDRESS_COMPLETE); 812 gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000); 813 gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000); 814 /* set source and the mask register to all ones */ 815 gpx_viper_write(ss, SOURCE, 0xffff); 816 gpx_viper_write(ss, MASK_1, 0xffff); 817 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 818 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 819 /* initialize Operand Control Register banks for fill command */ 820 gpx_viper_write(ss, SRC1_OCR_A, 821 EXT_NONE | INT_M1_M2 | NO_ID | WAIT); 822 gpx_viper_write(ss, SRC2_OCR_A, 823 EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT); 824 gpx_viper_write(ss, DST_OCR_A, 825 EXT_NONE | INT_NONE | NO_ID | NO_WAIT); 826 gpx_viper_write(ss, SRC1_OCR_B, 827 EXT_NONE | INT_SOURCE | NO_ID | WAIT); 828 gpx_viper_write(ss, SRC2_OCR_B, 829 EXT_NONE | INT_M1_M2 | NO_ID | NO_WAIT); 830 gpx_viper_write(ss, DST_OCR_B, 831 EXT_NONE | INT_NONE | NO_ID | NO_WAIT); 832 833 /* 834 * Init Logic Unit Function registers. 835 */ 836 /* putchar */ 837 gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE); 838 /* erase{cols,rows} */ 839 gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS); 840 /* underline */ 841 gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES); 842 /* cursor */ 843 gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D); 844} 845 846/* Clear the whole screen. Straight from qdss. */ 847static void 848gpx_clear_screen(struct gpx_screen *ss) 849{ 850 851 ss->ss_adder->x_limit = GPX_WIDTH; 852 ss->ss_adder->y_limit = GPX_HEIGHT; 853 ss->ss_adder->y_offset_pending = 0; 854 gpx_wait(ss, FRAME_SYNC); /* wait at LEAST 1 full frame */ 855 gpx_wait(ss, FRAME_SYNC); 856 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 857 gpx_wait(ss, FRAME_SYNC); 858 gpx_wait(ss, FRAME_SYNC); 859 ss->ss_adder->y_offset_pending = GPX_VISHEIGHT; 860 gpx_wait(ss, FRAME_SYNC); 861 gpx_wait(ss, FRAME_SYNC); 862 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 863 gpx_wait(ss, FRAME_SYNC); 864 gpx_wait(ss, FRAME_SYNC); 865 ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT; 866 gpx_wait(ss, FRAME_SYNC); 867 gpx_wait(ss, FRAME_SYNC); 868 ss->ss_adder->y_scroll_constant = SCROLL_ERASE; 869 gpx_wait(ss, FRAME_SYNC); 870 gpx_wait(ss, FRAME_SYNC); 871 ss->ss_adder->y_offset_pending = 0; /* back to normal */ 872 gpx_wait(ss, FRAME_SYNC); 873 gpx_wait(ss, FRAME_SYNC); 874 ss->ss_adder->x_limit = GPX_WIDTH; 875 ss->ss_adder->y_limit = GPX_VISHEIGHT; 876} 877 878static int 879gpx_setup_screen(struct gpx_screen *ss) 880{ 881 struct rasops_info *ri = &ss->ss_ri; 882 int cookie; 883 884 memset(ri, 0, sizeof(*ri)); 885 ri->ri_depth = 8; /* masquerade as a 8 bit device for rasops */ 886 ri->ri_width = GPX_WIDTH; 887 ri->ri_height = GPX_VISHEIGHT; 888 ri->ri_stride = GPX_WIDTH; 889 ri->ri_flg = RI_CENTER; /* no RI_CLEAR as ri_bits is NULL! */ 890 ri->ri_hw = ss; 891 if (ss == &gpx_consscr) 892 ri->ri_flg |= RI_NO_AUTO; 893 894 /* 895 * We can not let rasops select our font, because we need to use 896 * a font with right-to-left bit order on this frame buffer. 897 */ 898 wsfont_init(); 899 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L, 900 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 901 if (cookie < 0) 902 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 903 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 904 if (cookie < 0) 905 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 906 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 907 if (cookie < 0) 908 return -1; 909 if (wsfont_lock(cookie, &ri->ri_font) != 0) 910 return -1; 911 ri->ri_wsfcookie = cookie; 912 913 /* 914 * Ask for an unholy big display, rasops will trim this to more 915 * reasonable values. 916 */ 917 if (rasops_init(ri, 160, 160) != 0) 918 return -1; 919 920 /* 921 * Override the rasops emulops. 922 */ 923 ri->ri_ops.copyrows = gpx_copyrows; 924 ri->ri_ops.copycols = gpx_copycols; 925 ri->ri_ops.eraserows = gpx_eraserows; 926 ri->ri_ops.erasecols = gpx_erasecols; 927 ri->ri_ops.putchar = gpx_putchar; 928 ri->ri_do_cursor = gpx_do_cursor; 929 930 gpx_stdscreen.ncols = ri->ri_cols; 931 gpx_stdscreen.nrows = ri->ri_rows; 932 gpx_stdscreen.textops = &ri->ri_ops; 933 gpx_stdscreen.fontwidth = ri->ri_font->fontwidth; 934 gpx_stdscreen.fontheight = ri->ri_font->fontheight; 935 gpx_stdscreen.capabilities = ri->ri_caps; 936 937 /* 938 * Initialize RAMDAC. 939 */ 940 if (ss->ss_depth == 8) { 941 struct ramdac8 *rd = ss->ss_vdac; 942 rd->address = BT_CR; 943 rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4; 944 } else { 945 struct ramdac4 *rd = ss->ss_vdac; 946 rd->control = RAMDAC4_INIT; 947 } 948 949 /* 950 * Put the ADDER and VIPER in a good state. 951 */ 952 gpx_reset_viper(ss); 953 954 /* 955 * Initialize colormap. 956 */ 957 gpx_resetcmap(ss); 958 959 /* 960 * Clear display (including non-visible area), in 864 lines chunks. 961 */ 962 gpx_clear_screen(ss); 963 964 /* 965 * Copy our font to the offscreen area. 966 */ 967 gpx_upload_font(ss); 968 969#if 0 970 ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI; 971#endif 972 973 return 0; 974} 975 976/* 977 * Copy the selected wsfont to non-visible frame buffer area. 978 * This is necessary since the only way to send data to the frame buffer 979 * is through the ID interface, which is slow and needs 16 bit wide data. 980 * Adapted from qdss. 981 */ 982static void 983gpx_upload_font(struct gpx_screen *ss) 984{ 985 struct rasops_info *ri = &ss->ss_ri; 986 struct wsdisplay_font *font = ri->ri_font; 987 uint8_t *fontbits, *fb; 988 u_int remaining, nchars, row; 989 u_int i, j; 990 uint16_t data; 991 992 /* setup VIPER operand control registers */ 993 994 gpx_viper_write(ss, MASK_1, 0xffff); 995 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 996 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 997 998 gpx_viper_write(ss, SRC1_OCR_B, 999 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); 1000 gpx_viper_write(ss, SRC2_OCR_B, 1001 EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY); 1002 gpx_viper_write(ss, DST_OCR_B, 1003 EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 1004 1005 ss->ss_adder->rasterop_mode = 1006 DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL; 1007 gpx_wait(ss, RASTEROP_COMPLETE); 1008 1009 /* 1010 * Load font data. The font is uploaded in 8 or 16 bit wide cells, on 1011 * as many ``lines'' as necessary at the end of the display. 1012 */ 1013 ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars); 1014 if ((ss->ss_gpr & 1) != 0) 1015 ss->ss_gpr--; 1016 fontbits = font->data; 1017 for (row = 1, remaining = font->numchars; remaining != 0; 1018 row++, remaining -= nchars) { 1019 nchars = MIN(ss->ss_gpr, remaining); 1020 1021 ss->ss_adder->destination_x = 0; 1022 ss->ss_adder->destination_y = 1023 GPX_HEIGHT - row * font->fontheight; 1024 ss->ss_adder->fast_dest_dx = nchars * 16; 1025 ss->ss_adder->slow_dest_dy = font->fontheight; 1026 1027 /* setup for processor to bitmap xfer */ 1028 gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff); 1029 ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/ 1030 1031 /* iteratively do the processor to bitmap xfer */ 1032 for (i = font->fontheight; i != 0; i--) { 1033 fb = fontbits; 1034 fontbits += font->stride; 1035 /* PTOB a scan line */ 1036 for (j = nchars; j != 0; j--) { 1037 /* PTOB one scan of a char cell */ 1038 if (font->stride == 1) { 1039 data = *fb; 1040 fb += font->fontheight; 1041 /* 1042 * Do not access past font memory if 1043 * it has an odd number of characters 1044 * and this is the last pair. 1045 */ 1046 if (j != 1 || (nchars & 1) == 0 || 1047 remaining != nchars) { 1048 data |= ((uint16_t)*fb) << 8; 1049 fb += font->fontheight; 1050 } 1051 } else { 1052 data = 1053 fb[0] | (((uint16_t)fb[1]) << 8); 1054 fb += font->fontheight * font->stride; 1055 } 1056 1057 gpx_wait(ss, TX_READY); 1058 ss->ss_adder->id_data = data; 1059 } 1060 } 1061 fontbits += (nchars - 1) * font->stride * font->fontheight; 1062 } 1063} 1064 1065static void 1066gpx_copyrect(struct gpx_screen *ss, 1067 int sx, int sy, int dx, int dy, int w, int h) 1068{ 1069 1070 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff)) 1071 continue; 1072 gpx_viper_write(ss, MASK_1, 0xffff); 1073 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255); 1074 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0); 1075 gpx_viper_write(ss, SRC1_OCR_B, 1076 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 1077 gpx_viper_write(ss, DST_OCR_B, 1078 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 1079 ss->ss_adder->fast_dest_dy = 0; 1080 ss->ss_adder->slow_dest_dx = 0; 1081 ss->ss_adder->error_1 = 0; 1082 ss->ss_adder->error_2 = 0; 1083 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 1084 gpx_wait(ss, RASTEROP_COMPLETE); 1085 ss->ss_adder->destination_x = dx; 1086 ss->ss_adder->fast_dest_dx = w; 1087 ss->ss_adder->destination_y = dy; 1088 ss->ss_adder->slow_dest_dy = h; 1089 ss->ss_adder->source_1_x = sx; 1090 ss->ss_adder->source_1_dx = w; 1091 ss->ss_adder->source_1_y = sy; 1092 ss->ss_adder->source_1_dy = h; 1093 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1; 1094} 1095 1096/* 1097 * Fill a rectangle with the given attribute and function (i.e. rop). 1098 */ 1099static void 1100gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr, 1101 u_int function) 1102{ 1103 int fg, bg; 1104 1105 rasops_unpack_attr(attr, &fg, &bg, NULL); 1106 1107 while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff)) 1108 continue; 1109 gpx_viper_write(ss, MASK_1, 0xffff); 1110 gpx_viper_write(ss, SOURCE, 0xffff); 1111 gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg); 1112 gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg); 1113 gpx_viper_write(ss, SRC1_OCR_B, 1114 EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY); 1115 gpx_viper_write(ss, DST_OCR_B, 1116 EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY); 1117 ss->ss_adder->fast_dest_dx = 0; 1118 ss->ss_adder->fast_dest_dy = 0; 1119 ss->ss_adder->slow_dest_dx = 0; 1120 ss->ss_adder->error_1 = 0; 1121 ss->ss_adder->error_2 = 0; 1122 ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL; 1123 gpx_wait(ss, RASTEROP_COMPLETE); 1124 ss->ss_adder->destination_x = x; 1125 ss->ss_adder->fast_dest_dx = dx; 1126 ss->ss_adder->destination_y = y; 1127 ss->ss_adder->slow_dest_dy = dy; 1128 ss->ss_adder->source_1_x = x; 1129 ss->ss_adder->source_1_dx = dx; 1130 ss->ss_adder->source_1_y = y; 1131 ss->ss_adder->source_1_dy = dy; 1132 ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function; 1133} 1134 1135/* 1136 * Colormap handling routines 1137 */ 1138 1139static int 1140gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) 1141{ 1142 u_int index = cm->index, count = cm->count, i; 1143 u_int colcount = 1 << ss->ss_depth; 1144 int error; 1145 uint8_t ramp[256], *c, *r; 1146 1147 if (index >= colcount || count > colcount - index) 1148 return EINVAL; 1149 1150 /* extract reds */ 1151 c = ss->ss_cmap + 0 + index * 3; 1152 for (i = count, r = ramp; i != 0; i--) 1153 *r++ = *c << (8 - ss->ss_depth), c += 3; 1154 if ((error = copyout(ramp, cm->red, count)) != 0) 1155 return error; 1156 1157 /* extract greens */ 1158 c = ss->ss_cmap + 1 + index * 3; 1159 for (i = count, r = ramp; i != 0; i--) 1160 *r++ = *c << (8 - ss->ss_depth), c += 3; 1161 if ((error = copyout(ramp, cm->green, count)) != 0) 1162 return error; 1163 1164 /* extract blues */ 1165 c = ss->ss_cmap + 2 + index * 3; 1166 for (i = count, r = ramp; i != 0; i--) 1167 *r++ = *c << (8 - ss->ss_depth), c += 3; 1168 if ((error = copyout(ramp, cm->blue, count)) != 0) 1169 return error; 1170 1171 return 0; 1172} 1173 1174static int 1175gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm) 1176{ 1177 u_int index = cm->index, count = cm->count; 1178 u_int colcount = 1 << ss->ss_depth; 1179 int i, error; 1180 uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c; 1181 1182 if (index >= colcount || count > colcount - index) 1183 return EINVAL; 1184 1185 if ((error = copyin(cm->red, r, count)) != 0) 1186 return error; 1187 if ((error = copyin(cm->green, g, count)) != 0) 1188 return error; 1189 if ((error = copyin(cm->blue, b, count)) != 0) 1190 return error; 1191 1192 nr = r, ng = g, nb = b; 1193 c = ss->ss_cmap + index * 3; 1194 for (i = count; i != 0; i--) { 1195 *c++ = *nr++ >> (8 - ss->ss_depth); 1196 *c++ = *ng++ >> (8 - ss->ss_depth); 1197 *c++ = *nb++ >> (8 - ss->ss_depth); 1198 } 1199 1200 return 0; 1201} 1202 1203static void 1204gpx_loadcmap(struct gpx_screen *ss, int from, int count) 1205{ 1206 uint8_t *cmap = ss->ss_cmap; 1207 int i, color12; 1208 1209 gpx_wait(ss, FRAME_SYNC); 1210 if (ss->ss_depth == 8) { 1211 struct ramdac8 *rd = ss->ss_vdac; 1212 1213 cmap += from * 3; 1214 rd->address = from; 1215 for (i = 0; i < count * 3; i++) 1216 rd->cmapdata = *cmap++; 1217 } else { 1218 struct ramdac4 *rd = ss->ss_vdac; 1219 1220 cmap = ss->ss_cmap + from; 1221 for (i = from; i < from + count; i++) { 1222 color12 = (*cmap++ >> 4) << 0; 1223 color12 |= (*cmap++ >> 4) << 8; 1224 color12 |= (*cmap++ >> 4) << 4; 1225 rd->colormap[i] = color12; 1226 } 1227 } 1228} 1229 1230static void 1231gpx_resetcmap(struct gpx_screen *ss) 1232{ 1233 1234 if (ss->ss_depth == 8) 1235 memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap)); 1236 else { 1237 memcpy(ss->ss_cmap, rasops_cmap, 8 * 3); 1238 memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3); 1239 } 1240 gpx_loadcmap(ss, 0, 1 << ss->ss_depth); 1241 1242 /* 1243 * On the 4bit RAMDAC, make the hardware cursor black on black 1244 */ 1245 if (ss->ss_depth != 8) { 1246 struct ramdac4 *rd = ss->ss_vdac; 1247 1248 rd->cursormap[0] = rd->cursormap[1] = 1249 rd->cursormap[2] = rd->cursormap[3] = 0x0000; 1250 } 1251} 1252 1253/* 1254 * Console support code 1255 */ 1256 1257cons_decl(gpx); 1258 1259/* 1260 * Called very early to setup the glass tty as console. 1261 * Because it's called before the VM system is initialized, virtual memory 1262 * for the framebuffer can be stolen directly without disturbing anything. 1263 */ 1264void 1265gpxcnprobe(struct consdev *cndev) 1266{ 1267 extern vaddr_t virtual_avail; 1268 extern const struct cdevsw wsdisplay_cdevsw; 1269 volatile struct adder *adder; 1270 vaddr_t tmp; 1271 int depth; 1272 u_short status; 1273 1274 switch (vax_boardtype) { 1275 case VAX_BTYP_410: 1276 case VAX_BTYP_420: 1277 case VAX_BTYP_43: 1278 if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0) 1279 break; /* doesn't use graphics console */ 1280 1281 if ((vax_confdata & KA420_CFG_VIDOPT) == 0) 1282 break; /* no color option */ 1283 1284 /* Check for hardware */ 1285 tmp = virtual_avail; 1286 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1); 1287 adder = (struct adder *)tmp; 1288 adder->status = 0; 1289 status = adder->status; 1290 iounaccess(tmp, 1); 1291 if (status == offsetof(struct adder, status)) 1292 return; 1293 1294 /* Check for a recognized color depth */ 1295 tmp = virtual_avail; 1296 ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); 1297 depth = *(uint16_t *) 1298 (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0; 1299 iounaccess(tmp, 1); 1300 if (depth != 0x00f0 && depth != 0x0080) 1301 return; 1302 1303 cndev->cn_pri = CN_INTERNAL; 1304 cndev->cn_dev = 1305 makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 1306 break; 1307 1308 default: 1309 break; 1310 } 1311} 1312 1313/* 1314 * Called very early to setup the glass tty as console. 1315 * Because it's called before the VM system is initialized, virtual memory 1316 * for the framebuffer can be stolen directly without disturbing anything. 1317 */ 1318void 1319gpxcninit(struct consdev *cndev) 1320{ 1321 struct gpx_screen *ss = &gpx_consscr; 1322 extern vaddr_t virtual_avail; 1323 vaddr_t ova; 1324 long defattr; 1325 struct rasops_info *ri; 1326 1327 ova = virtual_avail; 1328 1329 ioaccess(virtual_avail, 1330 vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1); 1331 ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail + 1332 (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8; 1333 1334 ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1); 1335 ss->ss_adder = (struct adder *)virtual_avail; 1336 virtual_avail += VAX_NBPG; 1337 1338 ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1); 1339 ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET)); 1340 virtual_avail += VAX_NBPG; 1341 1342#if 0 1343 ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1); 1344 ss->ss_cursor = (struct dc503reg *)virtual_avail; 1345 virtual_avail += VAX_NBPG; 1346#endif 1347 1348 virtual_avail = round_page(virtual_avail); 1349 1350 /* this had better not fail */ 1351 if (gpx_setup_screen(ss) != 0) { 1352#if 0 1353 iounaccess((vaddr_t)ss->ss_cursor, 1); 1354#endif 1355 iounaccess((vaddr_t)ss->ss_vdac, 1); 1356 iounaccess((vaddr_t)ss->ss_adder, 1); 1357 virtual_avail = ova; 1358 return; 1359 } 1360 1361 ri = &ss->ss_ri; 1362 ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr); 1363 wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr); 1364 cn_tab->cn_pri = CN_INTERNAL; 1365 1366#if NDZKBD > 0 1367 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 1368#endif 1369} 1370