1 /* $NetBSD: lcg.c,v 1.13 2025/02/28 13:13:41 hans Exp $ */ 2 /* 3 * LCG accelerated framebuffer driver 4 * Copyright (c) 2003, 2004 Blaz Antonic 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the abovementioned copyrights 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Resurrection and dumb framebuffer mode by Bjrn Johannesson 33 * rherdware (at) yahoo.com in December 2014 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: lcg.c,v 1.13 2025/02/28 13:13:41 hans Exp $"); 38 39 #define LCG_NO_ACCEL 40 41 #include <sys/param.h> 42 #include <sys/device.h> 43 #include <sys/systm.h> 44 #include <sys/callout.h> 45 #include <sys/time.h> 46 #include <sys/kmem.h> 47 #include <sys/conf.h> 48 #include <sys/kernel.h> 49 #include <sys/systm.h> 50 51 #include <machine/vsbus.h> 52 #include <machine/sid.h> 53 #include <machine/cpu.h> 54 #include <machine/lcgreg.h> 55 56 #include <dev/cons.h> 57 58 #include <dev/dec/dzreg.h> 59 #include <dev/dec/dzvar.h> 60 #include <dev/dec/dzkbdvar.h> 61 62 #include <dev/wscons/wsdisplayvar.h> 63 #include <dev/wscons/wsconsio.h> 64 #include <dev/wscons/wscons_callbacks.h> 65 #include <dev/wsfont/wsfont.h> 66 67 #include "machine/scb.h" 68 69 #include "dzkbd.h" 70 71 /* Screen hardware defs */ 72 73 #define LCG_FB_ADDR 0x21801000 /* Frame buffer */ 74 75 /* FIFO defines */ 76 #define LCG_FIFO_SIZE 0x10000 /* 64 KB */ 77 #define LCG_FIFO_WIN_ADDR 0x20180000 78 #define LCG_FIFO_WIN_SIZE VAX_NBPG 79 #define LCG_FIFO_ALIGN 0x10000 80 81 /* font rendering defines */ 82 #define LCG_FONT_ADDR (LCG_FB_ADDR + lcg_fb_size) 83 #define LCG_FONT_STORAGE_SIZE 0x40000 /* 16 KB, enough to accommodate 16x32 font bitmaps */ 84 85 /* register space defines */ 86 #define LCG_REG_ADDR 0x20100000 /* LCG registers */ 87 #define LCG_REG_SIZE 0x4000 /* 16384 bytes */ 88 #define LCG_REG(reg) regaddr[(reg / 4)] 89 90 /* LUT defines */ 91 #define LCG_LUT_ADDR 0x21800800 /* LUT right before onscreen FB */ 92 #define LCG_LUT_OFFSET 0x00000800 93 #define LCG_LUT_SIZE 0x800 /* 2048 bytes */ 94 95 #define LCG_BG_COLOR WSCOL_BLACK 96 #define LCG_FG_COLOR WSCOL_WHITE 97 98 #define LCG_CONFIG 0x200f0010 /* LCG model information */ 99 100 /* implement sanity checks at certain points to ensure safer operation */ 101 #define LCG_SAFE 102 //#define LCG_DEBUG 103 104 static int lcg_match(struct device *, struct cfdata *, void *); 105 static void lcg_attach(struct device *, struct device *, void *); 106 107 struct lcg_softc { 108 bus_dmamap_t sc_dm; 109 }; 110 111 CFATTACH_DECL_NEW(lcg, sizeof(struct lcg_softc), 112 lcg_match, lcg_attach, NULL, NULL); 113 114 static void lcg_cursor(void *, int, int, int); 115 static int lcg_mapchar(void *, int, unsigned int *); 116 static void lcg_putchar(void *, int, int, u_int, long); 117 static void lcg_copycols(void *, int, int, int,int); 118 static void lcg_erasecols(void *, int, int, int, long); 119 static void lcg_copyrows(void *, int, int, int); 120 static void lcg_eraserows(void *, int, int, long); 121 static int lcg_allocattr(void *, int, int, int, long *); 122 static int lcg_get_cmap(struct wsdisplay_cmap *); 123 static int lcg_set_cmap(struct wsdisplay_cmap *); 124 static void lcg_init_common(struct device *, struct vsbus_attach_args *); 125 126 const struct wsdisplay_emulops lcg_emulops = { 127 lcg_cursor, 128 lcg_mapchar, 129 lcg_putchar, 130 lcg_copycols, 131 lcg_erasecols, 132 lcg_copyrows, 133 lcg_eraserows, 134 lcg_allocattr 135 }; 136 137 static char lcg_stdscreen_name[10] = "160x68"; 138 struct wsscreen_descr lcg_stdscreen = { 139 lcg_stdscreen_name, 160, 68, /* dynamically set */ 140 &lcg_emulops, 141 8, 15, /* dynamically set */ 142 WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS, 143 }; 144 145 const struct wsscreen_descr *_lcg_scrlist[] = { 146 &lcg_stdscreen, 147 }; 148 149 const struct wsscreen_list lcg_screenlist = { 150 sizeof(_lcg_scrlist) / sizeof(struct wsscreen_descr *), 151 _lcg_scrlist, 152 }; 153 154 static char *lcgaddr; 155 static char *lutaddr; 156 static volatile long *regaddr; 157 static volatile long *fifoaddr; 158 #ifndef LCG_NO_ACCEL 159 static char *fontaddr; 160 #endif 161 162 static int lcg_xsize; 163 static int lcg_ysize; 164 static int lcg_depth; 165 static int lcg_cols; 166 static int lcg_rows; 167 static int lcg_onerow; 168 static int lcg_fb_size; 169 static int lcg_glyph_size; /* bitmap size in bits */ 170 171 static char *cursor; 172 173 static int cur_on; 174 175 static int cur_fg, cur_bg; 176 177 178 /* Our current hardware colormap */ 179 static struct hwcmap256 { 180 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 181 u_int8_t r[CMAP_SIZE]; 182 u_int8_t g[CMAP_SIZE]; 183 u_int8_t b[CMAP_SIZE]; 184 } lcg_cmap; 185 186 /* The default colormap */ 187 static struct { 188 u_int8_t r[8]; 189 u_int8_t g[8]; 190 u_int8_t b[8]; 191 } lcg_default_cmap = { 192 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, 193 { 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff }, 194 { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } 195 }; 196 197 struct wsdisplay_font lcg_font; 198 static u_char *qf; 199 static u_short *qf2; 200 201 #define QCHAR(c) (c < lcg_font.firstchar ? 0 : \ 202 (c >= (lcg_font.firstchar + lcg_font.numchars) ? 0 : c - lcg_font.firstchar)) 203 #define QFONT(c,line) ((lcg_font.stride == 2 ? \ 204 qf2[QCHAR(c) * lcg_font.fontheight + line] : \ 205 qf[QCHAR(c) * lcg_font.fontheight + line])) 206 #define LCG_ADDR(row, col, line, dot) \ 207 lcgaddr[((col) * lcg_font.fontwidth) + ((row) * lcg_font.fontheight * lcg_xsize) + \ 208 (line) * lcg_xsize + dot] 209 210 211 static int lcg_ioctl(void *, void *, u_long, void *, int, struct lwp *); 212 static paddr_t lcg_mmap(void *, void *, off_t, int); 213 static int lcg_alloc_screen(void *, const struct wsscreen_descr *, 214 void **, int *, int *, long *); 215 static void lcg_free_screen(void *, void *); 216 static int lcg_show_screen(void *, void *, int, 217 void (*) (void *, int, int), void *); 218 static void lcg_crsr_blink(void *); 219 220 /* LCG HW accel functions */ 221 #ifndef LCG_NO_ACCEL 222 static void fifo_put(long data); 223 static int fifo_fill(int iterations); 224 static u_char fifo_counter = 0; 225 226 static void blkcpy(long source, long dest, int xdim, int ydim); 227 static void blkset(long dest, int xdim, int ydim, char color); 228 static void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg); 229 #endif /* LCG_NO_ACCEL */ 230 231 const struct wsdisplay_accessops lcg_accessops = { 232 lcg_ioctl, 233 lcg_mmap, 234 lcg_alloc_screen, 235 lcg_free_screen, 236 lcg_show_screen, 237 0 /* load_font */ 238 }; 239 240 /* TODO allocate ss_image dynamically for consoles beyond first one */ 241 struct lcg_screen { 242 int ss_curx; 243 int ss_cury; 244 int ss_cur_fg; 245 int ss_cur_bg; 246 struct { 247 u_char data; /* Image character */ 248 u_char attr; /* Attribute: 80/70/08/07 */ 249 } ss_image[160 * 128]; /* allow for maximum possible cell matrix */ 250 }; 251 #define LCG_ATTR_UNDERLINE 0x80 252 #define LCG_BG_MASK 0x70 253 #define LCG_ATTR_REVERSE 0x08 254 #define LCG_FG_MASK 0x07 255 256 static struct lcg_screen lcg_conscreen; 257 static struct lcg_screen *curscr; 258 static struct lcg_screen *savescr; 259 260 static callout_t lcg_cursor_ch; 261 262 #ifndef LCG_NO_ACCEL 263 void fifo_put(long data) 264 { 265 fifo_counter &= 0x3; 266 fifoaddr[fifo_counter] = data; 267 fifo_counter++; 268 } 269 270 int fifo_fill(int iterations) 271 { 272 long status; 273 int counter = 0; 274 275 while (fifo_counter % 4) 276 fifo_put(0); 277 278 #ifdef LCG_SAFE 279 status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS); 280 while ((counter < iterations) && ((status & 0x80000000) == 0x80000000)) { 281 delay(1000); 282 status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS); 283 counter++; 284 } 285 #endif 286 287 if (counter == 0) 288 return 0; 289 else 290 return 1; 291 } 292 293 void blkcpy(long source, long dest, int xdim, int ydim) 294 { 295 int err; 296 297 #ifdef LCG_SAFE 298 if ((source < LCG_FB_ADDR) || (source > LCG_FB_ADDR + lcg_fb_size)) { 299 printf("lcg: blkcpy: invalid source 0x%lx\n", source); 300 return; 301 } 302 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 303 printf("lcg: blkcpy: invalid destination 0x%lx\n", dest); 304 return; 305 } 306 #endif 307 308 #ifdef LCG_SAFE 309 fifo_put(0x0c010000 | (cur_fg & 0xff)); 310 #endif 311 fifo_put(0x01020006); 312 313 fifo_put(0x06800000); 314 fifo_put(source); 315 fifo_put(lcg_xsize); 316 317 fifo_put(0x05800000); 318 fifo_put(dest); 319 fifo_put(lcg_xsize); 320 321 fifo_put(0x03400000); 322 fifo_put(0xff); 323 324 fifo_put(0x02000003); 325 326 #ifdef LCG_SAFE 327 fifo_put(0x04c00000); 328 fifo_put(0); 329 fifo_put(lcg_xsize); 330 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 331 #endif 332 333 fifo_put(0x09c00000); 334 fifo_put(((ydim & 0xffff) << 16) | xdim); 335 fifo_put(0); 336 fifo_put(0); 337 338 err = fifo_fill(200); 339 if (err) 340 printf("lcg: AG still busy after 200 msec\n"); 341 } 342 343 void blkset(long dest, int xdim, int ydim, char color) 344 { 345 int err; 346 347 #ifdef LCG_SAFE 348 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 349 printf("lcg: blkset: invalid destination 0x%lx\n", dest); 350 return; 351 } 352 #endif 353 354 fifo_put(0x0c010000 | (color & 0xff)); 355 356 fifo_put(0x01000000); 357 358 fifo_put(0x05800000); 359 fifo_put(dest); 360 fifo_put(lcg_xsize); 361 362 fifo_put(0x03400000); 363 fifo_put(0xff); 364 365 fifo_put(0x02000003); 366 367 #ifdef LCG_SAFE 368 fifo_put(0x04c00000); 369 fifo_put(0); 370 fifo_put(lcg_xsize); 371 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 372 #endif 373 374 fifo_put(0x09c00000); 375 fifo_put(((ydim & 0xffff) << 16) | xdim); 376 fifo_put(0); 377 fifo_put(0); 378 379 err = fifo_fill(200); 380 if (err) 381 printf("lcg: AG still busy after 200 msec\n"); 382 } 383 384 void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg) 385 { 386 int err; 387 #ifdef LCG_SAFE 388 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 389 printf("lcg: blkset: invalid destination 0x%lx\n", dest); 390 return; 391 } 392 #endif 393 394 fifo_put(0x0c050000 | (bg & 0xff)); 395 fifo_put(0x0c010000 | (fg & 0xff)); 396 397 fifo_put(0x01030008); 398 399 fifo_put(0x06800000); 400 fifo_put(source); 401 //fifo_put(lcg_xsize); 402 fifo_put(lcg_font.stride); 403 404 fifo_put(0x05800000); 405 fifo_put(dest); 406 fifo_put(lcg_xsize); 407 408 fifo_put(0x03400000); 409 fifo_put(0xff); 410 411 fifo_put(0x02000003); 412 413 #ifdef LCG_SAFE 414 fifo_put(0x04c00000); 415 fifo_put(0); 416 fifo_put(lcg_xsize); 417 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 418 #endif 419 420 fifo_put(0x09c00000); 421 fifo_put(((ydim & 0xffff) << 16) | (xdim & 0xffff)); 422 fifo_put(0); 423 fifo_put(0); 424 425 err = fifo_fill(200); 426 if (err) 427 printf("lcg: AG still busy after 200 msec\n"); 428 } 429 #endif /* LCG_NO_ACCEL */ 430 431 int 432 lcg_match(struct device *parent, struct cfdata *match, void *aux) 433 { 434 struct vsbus_softc *sc = device_private(parent); 435 struct vsbus_attach_args *va = aux; 436 volatile char * const ch = (char *)va->va_addr; 437 438 /* 439 * Check the VAX board type. LCG can exist on two board types: 440 * - KA46 (VAXstation 4000/60 or MicroVAX 3100/80) 441 * - KA48 (VAXstation 4000 VLC or MicroVAX 3100/m{30,40} 442 */ 443 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 444 return 0; 445 446 /* 447 * LCG supposedly only exists on VAXstations, not the MicroVAXen using 448 * the same board type. 449 * 450 * These are "magic values", taken from vax/locore.c 451 */ 452 if ((vax_siedata & 0x3) != 2) 453 return 0; 454 455 *ch = 1; 456 if ((*ch & 1) == 0) 457 return 0; 458 *ch = 0; 459 if ((*ch & 1) != 0) 460 return 0; 461 462 /* XXX use vertical interrupt? */ 463 sc->sc_mask = 0x04; /* XXX - should be generated */ 464 scb_fake(0x120, 0x15); 465 return 20; 466 } 467 468 void 469 lcg_attach(struct device *parent, struct device *self, void *aux) 470 { 471 struct vsbus_attach_args *va = aux; 472 struct wsemuldisplaydev_attach_args aa; 473 474 printf("\n"); 475 aa.console = lcgaddr != NULL; 476 477 lcg_init_common(self, va); 478 479 curscr = &lcg_conscreen; 480 481 aa.scrdata = &lcg_screenlist; 482 aa.accessops = &lcg_accessops; 483 484 /* enable software cursor */ 485 callout_init(&lcg_cursor_ch, 0); 486 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 487 488 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 489 } 490 491 static void 492 lcg_crsr_blink(void *arg) 493 { 494 int dot; 495 496 if (cur_on && curscr != NULL) 497 for (dot = 0; dot < lcg_font.fontwidth; dot++) 498 cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg; 499 500 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 501 } 502 503 void 504 lcg_cursor(void *id, int on, int row, int col) 505 { 506 struct lcg_screen *ss = id; 507 int dot, attr; 508 509 attr = ss->ss_image[row * lcg_cols + col].attr; 510 if (ss == curscr) { 511 if (cursor != NULL) { 512 int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols + 513 ss->ss_curx].data, lcg_font.fontheight - 1); 514 attr = ss->ss_image[ss->ss_cury * lcg_cols + 515 ss->ss_curx].attr; 516 517 if (attr & LCG_ATTR_REVERSE) { 518 cur_bg = attr & LCG_FG_MASK; 519 cur_fg = (attr & LCG_BG_MASK) >> 4; 520 } else { 521 cur_fg = attr & LCG_FG_MASK; 522 cur_bg = (attr & LCG_BG_MASK) >> 4; 523 } 524 for (dot = 0; dot < lcg_font.fontwidth; dot++) 525 cursor[dot] = (ch & (1 << dot)) ? 526 cur_fg : cur_bg; 527 } 528 529 cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 530 cur_on = on; 531 if (attr & LCG_ATTR_REVERSE) { 532 cur_bg = attr & LCG_FG_MASK; 533 cur_fg = (attr & LCG_BG_MASK) >> 4; 534 } else { 535 cur_fg = attr & LCG_FG_MASK; 536 cur_bg = (attr & LCG_BG_MASK) >> 4; 537 } 538 } 539 ss->ss_curx = col; 540 ss->ss_cury = row; 541 if (attr & LCG_ATTR_REVERSE) { 542 ss->ss_cur_bg = attr & LCG_FG_MASK; 543 ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4; 544 } else { 545 ss->ss_cur_fg = attr & LCG_FG_MASK; 546 ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4; 547 } 548 } 549 550 int 551 lcg_mapchar(void *id, int uni, unsigned int *index) 552 { 553 if (uni < 256) { 554 *index = uni; 555 return (5); 556 } 557 *index = ' '; 558 return (0); 559 } 560 561 static void 562 lcg_putchar(void *id, int row, int col, u_int c, long attr) 563 { 564 struct lcg_screen *ss = id; 565 int i; 566 char dot_fg, dot_bg; 567 568 c &= 0xff; 569 570 ss->ss_image[row * lcg_cols + col].data = c; 571 ss->ss_image[row * lcg_cols + col].attr = attr; 572 if (ss != curscr) 573 return; 574 575 dot_fg = attr & LCG_FG_MASK; 576 dot_bg = (attr & LCG_BG_MASK) >> 4; 577 if (attr & LCG_ATTR_REVERSE) { 578 dot_fg = (attr & LCG_BG_MASK) >> 4; 579 dot_bg = attr & LCG_FG_MASK; 580 } 581 582 #ifndef LCG_NO_ACCEL 583 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 584 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 585 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 586 #else 587 for (i = 0; i < lcg_font.fontheight; i++) { 588 unsigned char ch = QFONT(c,i); 589 for (int j = 0; j < lcg_font.fontwidth; j++) { 590 LCG_ADDR(row, col, i, j) = ((ch >> j) & 1) ? dot_fg : dot_bg; 591 } 592 } 593 #endif /* LCG_NO_ACCEL */ 594 if (attr & LCG_ATTR_UNDERLINE) { 595 char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 596 for (i = 0; i < lcg_font.fontwidth; i++) 597 p[i] = ~p[i]; 598 } 599 } 600 601 602 603 /* 604 * copies columns inside a row. 605 */ 606 static void 607 lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols) 608 { 609 struct lcg_screen *ss = id; 610 #ifdef LCG_NO_ACCEL 611 int i = 0; 612 #endif 613 614 bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row * 615 lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0])); 616 if (ss != curscr) 617 return; 618 #ifdef LCG_NO_ACCEL 619 for (i = 0; i < lcg_font.fontheight; i++) 620 memcpy(&LCG_ADDR(row, dstcol, i, 0), 621 &LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth); 622 623 #else 624 blkcpy(LCG_FB_ADDR + (row * lcg_onerow) + (srccol * lcg_font.fontwidth), 625 LCG_FB_ADDR + (row * lcg_onerow) + (dstcol * lcg_font.fontwidth), 626 (ncols * lcg_font.fontwidth), lcg_font.fontheight); 627 #endif 628 } 629 630 /* 631 * Erases a bunch of chars inside one row. 632 */ 633 static void 634 lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 635 { 636 struct lcg_screen *ss = id; 637 int i; 638 639 bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0])); 640 for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i) 641 ss->ss_image[i].attr = fillattr; 642 if (ss != curscr) 643 return; 644 #ifdef LCG_NO_ACCEL 645 for (i = 0; i < lcg_font.fontheight; i++) 646 memset(&LCG_ADDR(row, startcol, i, 0), 0, ncols * lcg_font.fontwidth); 647 #else 648 blkset(LCG_FB_ADDR + (row * lcg_onerow) + (startcol * lcg_font.fontwidth), 649 (ncols * lcg_font.fontwidth), lcg_font.fontheight, (fillattr & LCG_BG_MASK) >> 4); 650 #endif 651 } 652 653 static void 654 lcg_copyrows(void *id, int srcrow, int dstrow, int nrows) 655 { 656 struct lcg_screen *ss = id; 657 658 bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols], 659 nrows * lcg_cols * sizeof(ss->ss_image[0])); 660 if (ss != curscr) 661 return; 662 #ifdef LCG_NO_ACCEL 663 memcpy(&lcgaddr[dstrow * lcg_onerow], 664 &lcgaddr[srcrow * lcg_onerow], nrows * lcg_onerow); 665 #else 666 blkcpy(LCG_FB_ADDR + (srcrow * lcg_onerow), LCG_FB_ADDR + (dstrow * lcg_onerow), 667 (lcg_cols * lcg_font.fontwidth), (nrows * lcg_font.fontheight)); 668 #endif 669 } 670 671 static void 672 lcg_eraserows(void *id, int startrow, int nrows, long fillattr) 673 { 674 struct lcg_screen *ss = id; 675 int i; 676 677 bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols * 678 sizeof(ss->ss_image[0])); 679 for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i) 680 ss->ss_image[i].attr = fillattr; 681 if (ss != curscr) 682 return; 683 #ifdef LCG_NO_ACCEL 684 memset(&lcgaddr[startrow * lcg_onerow], 0, nrows * lcg_onerow); 685 #else 686 blkset(LCG_FB_ADDR + (startrow * lcg_onerow), (lcg_cols * lcg_font.fontwidth), 687 (nrows * lcg_font.fontheight), (fillattr & LCG_BG_MASK) >> 4); 688 #endif 689 } 690 691 static int 692 lcg_allocattr(void *id, int fg, int bg, int flags, long *attrp) 693 { 694 long myattr; 695 696 if (flags & WSATTR_WSCOLORS) 697 myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK); 698 else 699 myattr = WSCOL_WHITE << 4; /* XXXX */ 700 if (flags & WSATTR_REVERSE) 701 myattr |= LCG_ATTR_REVERSE; 702 if (flags & WSATTR_UNDERLINE) 703 myattr |= LCG_ATTR_UNDERLINE; 704 *attrp = myattr; 705 return 0; 706 } 707 708 static int 709 lcg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 710 { 711 struct wsdisplay_fbinfo *fb = (void *)data; 712 int i; 713 714 switch (cmd) { 715 case WSDISPLAYIO_GTYPE: 716 *(u_int *)data = WSDISPLAY_TYPE_LCG; 717 break; 718 719 case WSDISPLAYIO_GINFO: 720 fb->height = lcg_ysize; 721 fb->width = lcg_xsize; 722 fb->depth = lcg_depth; 723 fb->cmsize = 1 << lcg_depth; 724 break; 725 726 case WSDISPLAYIO_LINEBYTES: 727 *(u_int *)data = lcg_xsize; 728 break; 729 730 case WSDISPLAYIO_GETCMAP: 731 return lcg_get_cmap((struct wsdisplay_cmap *)data); 732 733 case WSDISPLAYIO_PUTCMAP: 734 return lcg_set_cmap((struct wsdisplay_cmap *)data); 735 736 case WSDISPLAYIO_GMODE: 737 return EPASSTHROUGH; 738 739 case WSDISPLAYIO_SMODE: 740 /* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */ 741 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 742 /* FIXME: if this is meant to reset palette LUT reload has to be triggered too */ 743 bzero(lutaddr, LCG_LUT_SIZE); 744 for (i = 0; i < 8; ++i) { 745 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 746 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 747 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 748 lutaddr[i * 8 + 1] = i; 749 lutaddr[i * 8 + 2] = 1; 750 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 751 lutaddr[i * 8 + 4] = 1; 752 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 753 lutaddr[i * 8 + 6] = 1; 754 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 755 } 756 if (savescr != NULL) 757 lcg_show_screen(NULL, savescr, 0, NULL, NULL); 758 savescr = NULL; 759 } else { /* WSDISPLAYIO_MODE_MAPPED */ 760 savescr = curscr; 761 curscr = NULL; 762 /* clear screen? */ 763 } 764 765 return EPASSTHROUGH; 766 #if 0 767 case WSDISPLAYIO_SVIDEO: 768 if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) { 769 curcmd = curc; 770 } else { 771 curc = curcmd; 772 curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA); 773 curcmd |= CUR_CMD_FOPB; 774 } 775 WRITECUR(CUR_CMD, curcmd); 776 break; 777 778 case WSDISPLAYIO_GVIDEO: 779 *(u_int *)data = (curcmd & CUR_CMD_FOPB ? 780 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON); 781 break; 782 783 #endif 784 default: 785 return EPASSTHROUGH; 786 } 787 return 0; 788 } 789 790 static paddr_t 791 lcg_mmap(void *v, void *vs, off_t offset, int prot) 792 { 793 if (offset >= lcg_fb_size || offset < 0) 794 return -1; 795 return (LCG_FB_ADDR + offset) >> PGSHIFT; 796 } 797 798 int 799 lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 800 int *curxp, int *curyp, long *defattrp) 801 { 802 int i; 803 struct lcg_screen *ss; 804 805 *cookiep = kmem_alloc(sizeof(struct lcg_screen), KM_SLEEP); 806 bzero(*cookiep, sizeof(struct lcg_screen)); 807 *curxp = *curyp = 0; 808 *defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 809 ss = *cookiep; 810 for (i = 0; i < lcg_cols * lcg_rows; ++i) 811 ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 812 return 0; 813 } 814 815 void 816 lcg_free_screen(void *v, void *cookie) 817 { 818 } 819 820 int 821 lcg_show_screen(void *v, void *cookie, int waitok, 822 void (*cb)(void *, int, int), void *cbarg) 823 { 824 struct lcg_screen *ss = cookie; 825 int row, col, dot_fg, dot_bg, j, attr; 826 #ifdef LCG_NO_ACCEL 827 int iter, jter; 828 unsigned char ch; 829 #endif 830 831 if (ss == curscr) 832 return (0); 833 #ifdef LCG_NO_ACCEL 834 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 835 #endif 836 837 for (row = 0; row < lcg_rows; row++) 838 for (col = 0; col < lcg_cols; col++) { 839 attr = ss->ss_image[row * lcg_cols + col].attr; 840 if (attr & LCG_ATTR_REVERSE) { 841 dot_fg = (attr & LCG_BG_MASK) >> 4; 842 dot_bg = attr & LCG_FG_MASK; 843 } else { 844 dot_fg = attr & LCG_FG_MASK; 845 dot_bg = (attr & LCG_BG_MASK) >> 4; 846 } 847 u_char c = ss->ss_image[row * lcg_cols + col].data; 848 849 if (c < 32) 850 c = 32; 851 #ifndef LCG_NO_ACCEL 852 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 853 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 854 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 855 #else 856 for (iter = 0; iter < lcg_font.fontheight; iter++) { 857 ch = QFONT(c,iter); 858 for (jter = 0; jter < lcg_font.fontwidth; jter++) { 859 LCG_ADDR(row, col, iter, jter) = ((ch >> jter) & 1) ? dot_fg : dot_bg; 860 } 861 } 862 #endif 863 if (attr & LCG_ATTR_UNDERLINE) 864 for (j = 0; j < lcg_font.fontwidth; j++) 865 LCG_ADDR(row, col, 866 lcg_font.fontheight - 1, j) = dot_fg; 867 } 868 869 cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) + 870 ((lcg_font.fontheight - 1) * lcg_xsize) + 871 (ss->ss_curx * lcg_font.fontwidth)]; 872 cur_fg = ss->ss_cur_fg; 873 cur_bg = ss->ss_cur_bg; 874 875 curscr = ss; 876 return (0); 877 } 878 879 static int 880 lcg_get_cmap(struct wsdisplay_cmap *p) 881 { 882 u_int index = p->index, count = p->count; 883 int error; 884 885 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 886 return (EINVAL); 887 888 error = copyout(&lcg_cmap.r[index], p->red, count); 889 if (error) 890 return error; 891 error = copyout(&lcg_cmap.g[index], p->green, count); 892 if (error) 893 return error; 894 error = copyout(&lcg_cmap.b[index], p->blue, count); 895 return error; 896 } 897 898 static int 899 lcg_set_cmap(struct wsdisplay_cmap *p) 900 { 901 u_int index = p->index, count = p->count; 902 int error, s; 903 904 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 905 return (EINVAL); 906 907 error = copyin(p->red, &lcg_cmap.r[index], count); 908 if (error) 909 return error; 910 error = copyin(p->green, &lcg_cmap.g[index], count); 911 if (error) 912 return error; 913 error = copyin(p->blue, &lcg_cmap.b[index], count); 914 if (error) 915 return error; 916 917 s = spltty(); 918 /* FIXME: if this is meant to set palette LUT reload has to be triggered too */ 919 while (count-- > 0) { 920 lutaddr[index * 8 + 0] = 0; 921 lutaddr[index * 8 + 1] = index; 922 lutaddr[index * 8 + 2] = 1; 923 lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7); 924 lutaddr[index * 8 + 4] = 1; 925 lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7); 926 lutaddr[index * 8 + 6] = 1; 927 lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7); 928 ++index; 929 } 930 splx(s); 931 return (0); 932 } 933 934 cons_decl(lcg); 935 936 void 937 lcgcninit(struct consdev *cndev) 938 { 939 int i; 940 /* Clear screen */ 941 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 942 943 curscr = &lcg_conscreen; 944 for (i = 0; i < lcg_cols * lcg_rows; ++i) 945 lcg_conscreen.ss_image[i].attr = 946 (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 947 wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0, 948 (LCG_BG_COLOR << 4) | LCG_FG_COLOR); 949 cn_tab->cn_pri = CN_INTERNAL; 950 951 952 #if NDZKBD > 0 953 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 954 #endif 955 } 956 957 /* 958 * Called very early to setup the glass tty as console. 959 * Because it's called before the VM system is inited, virtual memory 960 * for the framebuffer can be stolen directly without disturbing anything. 961 */ 962 void 963 lcgcnprobe(struct consdev *cndev) 964 { 965 extern const struct cdevsw wsdisplay_cdevsw; 966 967 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 968 return; /* Only for VS 4000/60 and VLC */ 969 970 if ((vax_siedata & 0x3) != 2) 971 return; /* VAXstation only */ 972 973 if (vax_confdata & 0x100) 974 return; /* Diagnostic console */ 975 976 lcg_init_common(NULL, NULL); 977 978 /* Set up default LUT */ 979 980 cndev->cn_pri = CN_INTERNAL; 981 cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 982 } 983 984 void 985 lcg_init_common(struct device *self, struct vsbus_attach_args *va) 986 { 987 u_int magic, *lcg_config; 988 int i; 989 extern vaddr_t virtual_avail; 990 long video_conf; 991 int cookie; 992 struct wsdisplay_font *wf; 993 994 struct lcg_softc *sc = device_private(self); 995 bus_dma_segment_t seg; 996 int rseg, err; 997 void *fifo_mem_vaddr; 998 #ifndef LCG_NO_ACCEL 999 u_char line; 1000 u_int ch, temp; 1001 #endif 1002 1003 if (regaddr != NULL) 1004 return; 1005 1006 /* map LCG registers first */ 1007 if (self != NULL) { 1008 regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG)); 1009 if (regaddr == 0) { 1010 device_printf(self, 1011 "Couldn't allocate register memory.\n"); 1012 return; 1013 } 1014 } else { 1015 regaddr = (long*)virtual_avail; 1016 virtual_avail += LCG_REG_SIZE; 1017 ioaccess((vaddr_t)regaddr, LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG)); 1018 } 1019 1020 /* 1021 * v = *0x200f0010 & VLC ? 0x07 : 0xf0; 1022 * switch(v) { 1023 * 0x05: 1280x1024 1024 * 0x06: conf & 0x80 ? 1024x768 : 640x480 1025 * 0x07: conf & 0x80 ? 1024x768 ? 1024x864 1026 * 0x20: 1024x864 1027 * 0x40: 1024x768 1028 * 0x60: 1024x864 1029 * 0x80: 1280x1024 4BPN 1030 * 0x90: 1280x1024 8BPN 1031 * 0xb0: 1280x1024 8BPN 2HD 1032 */ 1033 if (self != NULL) { 1034 lcg_config = (u_int *)vax_map_physmem(LCG_CONFIG, 1); 1035 } else { 1036 lcg_config = (u_int *)virtual_avail; 1037 ioaccess((vaddr_t)lcg_config, LCG_CONFIG, 1); 1038 } 1039 magic = *lcg_config & (vax_boardtype == VAX_BTYP_46 ? 0xf0 : 0x07); 1040 if (self != NULL) { 1041 vax_unmap_physmem((vaddr_t)lcg_config, 1); 1042 } else { 1043 iounaccess((vaddr_t)lcg_config, 1); 1044 } 1045 lcg_depth = 8; 1046 switch(magic) { 1047 case 0x80: /* KA46 HR 1280x1024 4BPLN */ 1048 lcg_depth = 4; 1049 case 0x05: /* KA48 HR 1280x1024 8BPLN */ 1050 case 0x90: /* KA46 HR 1280x1024 8BPLN */ 1051 case 0xb0: /* KA46 HR 1280x1024 8BPLN 2HD */ 1052 lcg_xsize = 1280; 1053 lcg_ysize = 1024; 1054 break; 1055 case 0x06: /* KA48 1024x768 or 640x480 */ 1056 if (vax_confdata & 0x80) { 1057 lcg_xsize = 1024; 1058 lcg_ysize = 768; 1059 } else { 1060 lcg_xsize = 640; 1061 lcg_ysize = 480; 1062 } 1063 break; 1064 case 0x07: /* KA48 1024x768 or 1024x864 */ 1065 lcg_xsize = 1024; 1066 lcg_ysize = (vax_confdata & 0x80) ? 768 : 864; 1067 break; 1068 case 0x20: /* KA46 1024x864 */ 1069 case 0x60: /* KA46 1024x864 */ 1070 lcg_xsize = 1024; 1071 lcg_ysize = 864; 1072 break; 1073 case 0x40: /* KA46 1024x768 */ 1074 lcg_xsize = 1024; 1075 lcg_ysize = 768; 1076 break; 1077 default: 1078 panic("LCG model not supported"); 1079 } 1080 if (self != NULL) 1081 aprint_normal_dev(self, 1082 "framebuffer size %dx%d, depth %d (magic 0x%x)\n", 1083 lcg_xsize, lcg_ysize, lcg_depth, magic); 1084 1085 wsfont_init(); 1086 cookie = wsfont_find(NULL, 12, 22, 0, WSDISPLAY_FONTORDER_R2L, 1087 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1088 if (cookie == -1) 1089 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0, 1090 WSFONT_FIND_BITMAP); 1091 if (cookie == -1) 1092 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 1093 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1094 if (cookie == -1 || wsfont_lock(cookie, &wf)) 1095 panic("lcg_common_init: can't load console font"); 1096 lcg_font = *wf; 1097 lcg_cols = lcg_xsize / lcg_font.fontwidth; 1098 lcg_rows = lcg_ysize / lcg_font.fontheight; 1099 if (self != NULL) { 1100 aprint_normal_dev(self, "using font %s (%dx%d), ", 1101 lcg_font.name, 1102 lcg_font.fontwidth, lcg_font.fontheight); 1103 aprint_normal("console size: %dx%d\n", lcg_cols, lcg_rows); 1104 } 1105 lcg_onerow = lcg_xsize * lcg_font.fontheight; 1106 lcg_fb_size = lcg_xsize * lcg_ysize; 1107 lcg_stdscreen.ncols = lcg_cols; 1108 lcg_stdscreen.nrows = lcg_rows; 1109 lcg_stdscreen.fontwidth = lcg_font.fontwidth; 1110 lcg_stdscreen.fontheight = lcg_font.fontheight; 1111 lcg_glyph_size = lcg_font.stride * lcg_font.fontheight; 1112 snprintf(lcg_stdscreen_name, sizeof(lcg_stdscreen_name), "%dx%d", lcg_cols, lcg_rows); 1113 qf = lcg_font.data; 1114 qf2 = (u_short *)lcg_font.data; 1115 1116 if (self != NULL) { 1117 lcgaddr = (void *)vax_map_physmem(va->va_paddr, 1118 ((lcg_fb_size + LCG_FONT_STORAGE_SIZE)/VAX_NBPG)); 1119 if (lcgaddr == 0) { 1120 device_printf(self, 1121 "unable to allocate framebuffer memory.\n"); 1122 return; 1123 } 1124 #ifndef LCG_NO_ACCEL 1125 fontaddr = lcgaddr + lcg_fb_size; 1126 1127 /* copy font bitmaps */ 1128 for (ch = 0; ch < 256; ch++) 1129 for (line = 0; line < lcg_font.fontheight; line++) { 1130 temp = QFONT(ch, line); 1131 if (lcg_font.stride == 1) 1132 fontaddr[(ch * lcg_font.fontheight) + line] = temp; 1133 else { 1134 /* stride == 2 */ 1135 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line] = temp & 0xff; 1136 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line + 1] = (temp >> 16) & 0xff; 1137 } 1138 } 1139 #endif 1140 1141 lutaddr = (void *)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1142 if (lutaddr == 0) { 1143 device_printf(self, 1144 "unable to allocate LUT memory.\n"); 1145 return; 1146 } 1147 fifoaddr = (long*)vax_map_physmem(LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1148 if (regaddr == 0) { 1149 device_printf(self, "unable to map FIFO window\n"); 1150 return; 1151 } 1152 1153 /* allocate contiguous physical memory block for FIFO */ 1154 err = bus_dmamem_alloc(va->va_dmat, LCG_FIFO_SIZE, 1155 LCG_FIFO_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 1156 if (err) { 1157 device_printf(self, 1158 "unable to allocate FIFO memory block, err = %d\n", 1159 err); 1160 return; 1161 } 1162 1163 err = bus_dmamem_map(va->va_dmat, &seg, rseg, LCG_FIFO_SIZE, 1164 &fifo_mem_vaddr, BUS_DMA_NOWAIT); 1165 if (err) { 1166 device_printf(self, 1167 "unable to map FIFO memory block, err = %d\n", 1168 err); 1169 bus_dmamem_free(va->va_dmat, &seg, rseg); 1170 return; 1171 } 1172 1173 err = bus_dmamap_create(va->va_dmat, LCG_FIFO_SIZE, rseg, 1174 LCG_FIFO_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dm); 1175 if (err) { 1176 device_printf(self, 1177 "unable to create DMA map, err = %d\n", 1178 err); 1179 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1180 bus_dmamem_free(va->va_dmat, &seg, rseg); 1181 return; 1182 } 1183 1184 err = bus_dmamap_load(va->va_dmat, sc->sc_dm, fifo_mem_vaddr, 1185 LCG_FIFO_SIZE, NULL, BUS_DMA_NOWAIT); 1186 if (err) { 1187 device_printf(self, 1188 "unable to load DMA map, err = %d\n", 1189 err); 1190 bus_dmamap_destroy(va->va_dmat, sc->sc_dm); 1191 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1192 bus_dmamem_free(va->va_dmat, &seg, rseg); 1193 return; 1194 } 1195 1196 /* initialize LCG hardware */ 1197 LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0xd8000000; /* gfx reset, FIFO and AG enable */ 1198 // LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = (((LCG_FB_ADDR + lcg_fb_size) & 0xffff0000) | (LCG_FB_ADDR >> 16)); 1199 LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = 0xffff0000; 1200 LCG_REG(LCG_REG_FIFO_BASE) = sc->sc_dm->dm_segs[0].ds_addr; 1201 LCG_REG(LCG_REG_FIFO_BASE2) = sc->sc_dm->dm_segs[0].ds_addr; 1202 LCG_REG(LCG_REG_FIFO_MASKS) = 0xffff; 1203 LCG_REG(LCG_REG_FIFO_SAVE_HEAD_OFFSET) = sc->sc_dm->dm_segs[0].ds_addr; 1204 // LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0; 1205 // LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0x50000000; /* FIFO and AG enable */ 1206 LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0xffffffff; 1207 LCG_REG(LCG_REG_GRAPHICS_INT_SET_ENABLE) = 0; 1208 LCG_REG(LCG_REG_GRAPHICS_INT_CLR_ENABLE) = 0xffffffff; 1209 LCG_REG(LCG_REG_LCG_GO) = 3; /* FIFO and AG go */ 1210 // LCG_REG(LCG_REG_BREAKPT_ADDRESS) = 0x2fffffff; 1211 1212 } else { 1213 lcgaddr = (void *)virtual_avail; 1214 virtual_avail += lcg_fb_size + LCG_FONT_STORAGE_SIZE; 1215 ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG)); 1216 1217 lutaddr = (void *)virtual_avail; 1218 virtual_avail += LCG_LUT_SIZE; 1219 ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1220 1221 fifoaddr = (long*)virtual_avail; 1222 virtual_avail += LCG_FIFO_WIN_SIZE; 1223 ioaccess((vaddr_t)fifoaddr, LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1224 } 1225 1226 bzero(lutaddr, LCG_LUT_SIZE); 1227 for (i = 0; i < 8; ++i) { 1228 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 1229 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 1230 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 1231 lutaddr[i * 8 + 1] = i; 1232 lutaddr[i * 8 + 2] = 1; 1233 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 1234 lutaddr[i * 8 + 4] = 1; 1235 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 1236 lutaddr[i * 8 + 6] = 1; 1237 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 1238 } 1239 1240 /* 1241 * 0xf100165b 4000/60 1242 * 1111 0001 0000 0000 0001 0110 0101 1011 1243 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1244 * 3322 2222 2222 1111 1111 11 1245 * 1098 7654 3210 9876 5432 1098 7654 3210 1246 * 1247 * 0xf1001d7b 4000/VLC 1248 * 1111 0001 0000 0000 0001 1101 0111 1011 1249 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1250 * 3322 2222 2222 1111 1111 11 1251 * 1098 7654 3210 9876 5432 1098 7654 3210 1252 * 1253 * 31-30 11 Vertical state 1254 * 29-38 11 Horizontal state 1255 * 27-26 00 1256 * 25 0 console LUT select 1257 * 24 1 control LUT select 1258 * 23 0 1259 * 22 0 cursor active 1260 * 21-16 000000 1261 * 15 0 video subsystem reset 1262 * 14 0 1263 * 13 0 LUT load size 2KB 1264 * 12 1 enable H sync 1265 * 11 0 Full LUT load 1 1266 * 10 1 video clock select 1267 * 9- 8 10 memory refresh rate 01 1268 * 7- 6 01 video refresh rate 1269 * 5 0 load select 1 1270 * 4 1 read cursor output 1271 * 3 1 LUT load enable 1272 * 2 0 cursor enable 1273 * 1 1 video enable 1274 * 0 1 refresh clock enable 1275 */ 1276 /* prepare video_config reg for LUT reload */ 1277 video_conf 1278 = (3 << 30) /* vertical state */ 1279 | (3 << 28) /* horizontal state */ 1280 | (0 << 26) /* unused */ 1281 | (0 << 25) /* console LUT select */ 1282 | (0 << 24) /* control LUT select */ 1283 | (0 << 23) /* unused */ 1284 | (0 << 22) /* cursor active */ 1285 | (0 << 16) /* current cursor scanline showing */ 1286 | (0 << 15) /* video subsystem reset */ 1287 | (0 << 14) /* unused */ 1288 | (1 << 13) /* LUT load size 2 KB */ 1289 | (1 << 12) /* enable horizontal sync */ 1290 | (1 << 10) /* video clock select */ 1291 | (1 << 6) /* video refresh select */ 1292 | (1 << 4) /* read cursor output */ 1293 | (1 << 3) /* LUT load enable */ 1294 | (0 << 2) /* cursor enable */ 1295 | (1 << 1) /* video enable */ 1296 | (1 << 0); /* refresh clock enable */ 1297 /* FIXME needs updating for all supported models */ 1298 if (lcg_xsize == 1280) { /* 4000/60 HR 4PLN */ 1299 video_conf |= (0 << 11); /* split LUT load */ 1300 video_conf |= (2 << 8); /* memory refresh select */ 1301 video_conf |= (0 << 5); /* split shift register load */ 1302 } else { /* 4000/VLC LR 8PLN */ 1303 video_conf |= (1 << 11); /* Full LUT load */ 1304 video_conf |= (1 << 8); /* memory refresh select */ 1305 video_conf |= (1 << 5); /* split shift register load */ 1306 } 1307 1308 LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf; 1309 /* vital !!! */ 1310 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1; 1311 LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET; 1312 1313 delay(1000); 1314 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0; 1315 1316 #ifdef LCG_DEBUG 1317 if (self != NULL) 1318 device_printf(self, "video config register set 0x%08lx\n", 1319 video_conf); 1320 #endif 1321 } 1322