1 /* $NetBSD: lcg.c,v 1.11 2022/12/10 19:50:43 jakllsch 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 Björn Johannesson 33 * rherdware@yahoo.com in December 2014 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: lcg.c,v 1.11 2022/12/10 19:50:43 jakllsch 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 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 439 return 0; 440 441 *ch = 1; 442 if ((*ch & 1) == 0) 443 return 0; 444 *ch = 0; 445 if ((*ch & 1) != 0) 446 return 0; 447 448 /* XXX use vertical interrupt? */ 449 sc->sc_mask = 0x04; /* XXX - should be generated */ 450 scb_fake(0x120, 0x15); 451 return 20; 452 } 453 454 void 455 lcg_attach(struct device *parent, struct device *self, void *aux) 456 { 457 struct vsbus_attach_args *va = aux; 458 struct wsemuldisplaydev_attach_args aa; 459 460 printf("\n"); 461 aa.console = lcgaddr != NULL; 462 463 lcg_init_common(self, va); 464 465 curscr = &lcg_conscreen; 466 467 aa.scrdata = &lcg_screenlist; 468 aa.accessops = &lcg_accessops; 469 470 /* enable software cursor */ 471 callout_init(&lcg_cursor_ch, 0); 472 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 473 474 config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 475 } 476 477 static void 478 lcg_crsr_blink(void *arg) 479 { 480 int dot; 481 482 if (cur_on && curscr != NULL) 483 for (dot = 0; dot < lcg_font.fontwidth; dot++) 484 cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg; 485 486 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 487 } 488 489 void 490 lcg_cursor(void *id, int on, int row, int col) 491 { 492 struct lcg_screen *ss = id; 493 int dot, attr; 494 495 attr = ss->ss_image[row * lcg_cols + col].attr; 496 if (ss == curscr) { 497 if (cursor != NULL) { 498 int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols + 499 ss->ss_curx].data, lcg_font.fontheight - 1); 500 attr = ss->ss_image[ss->ss_cury * lcg_cols + 501 ss->ss_curx].attr; 502 503 if (attr & LCG_ATTR_REVERSE) { 504 cur_bg = attr & LCG_FG_MASK; 505 cur_fg = (attr & LCG_BG_MASK) >> 4; 506 } else { 507 cur_fg = attr & LCG_FG_MASK; 508 cur_bg = (attr & LCG_BG_MASK) >> 4; 509 } 510 for (dot = 0; dot < lcg_font.fontwidth; dot++) 511 cursor[dot] = (ch & (1 << dot)) ? 512 cur_fg : cur_bg; 513 } 514 515 cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 516 cur_on = on; 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 } 525 ss->ss_curx = col; 526 ss->ss_cury = row; 527 if (attr & LCG_ATTR_REVERSE) { 528 ss->ss_cur_bg = attr & LCG_FG_MASK; 529 ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4; 530 } else { 531 ss->ss_cur_fg = attr & LCG_FG_MASK; 532 ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4; 533 } 534 } 535 536 int 537 lcg_mapchar(void *id, int uni, unsigned int *index) 538 { 539 if (uni < 256) { 540 *index = uni; 541 return (5); 542 } 543 *index = ' '; 544 return (0); 545 } 546 547 static void 548 lcg_putchar(void *id, int row, int col, u_int c, long attr) 549 { 550 struct lcg_screen *ss = id; 551 int i; 552 char dot_fg, dot_bg; 553 554 c &= 0xff; 555 556 ss->ss_image[row * lcg_cols + col].data = c; 557 ss->ss_image[row * lcg_cols + col].attr = attr; 558 if (ss != curscr) 559 return; 560 561 dot_fg = attr & LCG_FG_MASK; 562 dot_bg = (attr & LCG_BG_MASK) >> 4; 563 if (attr & LCG_ATTR_REVERSE) { 564 dot_fg = (attr & LCG_BG_MASK) >> 4; 565 dot_bg = attr & LCG_FG_MASK; 566 } 567 568 #ifndef LCG_NO_ACCEL 569 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 570 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 571 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 572 #else 573 for (i = 0; i < lcg_font.fontheight; i++) { 574 unsigned char ch = QFONT(c,i); 575 for (int j = 0; j < lcg_font.fontwidth; j++) { 576 LCG_ADDR(row, col, i, j) = ((ch >> j) & 1) ? dot_fg : dot_bg; 577 } 578 } 579 #endif /* LCG_NO_ACCEL */ 580 if (attr & LCG_ATTR_UNDERLINE) { 581 char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 582 for (i = 0; i < lcg_font.fontwidth; i++) 583 p[i] = ~p[i]; 584 } 585 } 586 587 588 589 /* 590 * copies columns inside a row. 591 */ 592 static void 593 lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols) 594 { 595 struct lcg_screen *ss = id; 596 #ifdef LCG_NO_ACCEL 597 int i = 0; 598 #endif 599 600 bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row * 601 lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0])); 602 if (ss != curscr) 603 return; 604 #ifdef LCG_NO_ACCEL 605 for (i = 0; i < lcg_font.fontheight; i++) 606 memcpy(&LCG_ADDR(row, dstcol, i, 0), 607 &LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth); 608 609 #else 610 blkcpy(LCG_FB_ADDR + (row * lcg_onerow) + (srccol * lcg_font.fontwidth), 611 LCG_FB_ADDR + (row * lcg_onerow) + (dstcol * lcg_font.fontwidth), 612 (ncols * lcg_font.fontwidth), lcg_font.fontheight); 613 #endif 614 } 615 616 /* 617 * Erases a bunch of chars inside one row. 618 */ 619 static void 620 lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 621 { 622 struct lcg_screen *ss = id; 623 int i; 624 625 bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0])); 626 for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i) 627 ss->ss_image[i].attr = fillattr; 628 if (ss != curscr) 629 return; 630 #ifdef LCG_NO_ACCEL 631 for (i = 0; i < lcg_font.fontheight; i++) 632 memset(&LCG_ADDR(row, startcol, i, 0), 0, ncols * lcg_font.fontwidth); 633 #else 634 blkset(LCG_FB_ADDR + (row * lcg_onerow) + (startcol * lcg_font.fontwidth), 635 (ncols * lcg_font.fontwidth), lcg_font.fontheight, (fillattr & LCG_BG_MASK) >> 4); 636 #endif 637 } 638 639 static void 640 lcg_copyrows(void *id, int srcrow, int dstrow, int nrows) 641 { 642 struct lcg_screen *ss = id; 643 644 bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols], 645 nrows * lcg_cols * sizeof(ss->ss_image[0])); 646 if (ss != curscr) 647 return; 648 #ifdef LCG_NO_ACCEL 649 memcpy(&lcgaddr[dstrow * lcg_onerow], 650 &lcgaddr[srcrow * lcg_onerow], nrows * lcg_onerow); 651 #else 652 blkcpy(LCG_FB_ADDR + (srcrow * lcg_onerow), LCG_FB_ADDR + (dstrow * lcg_onerow), 653 (lcg_cols * lcg_font.fontwidth), (nrows * lcg_font.fontheight)); 654 #endif 655 } 656 657 static void 658 lcg_eraserows(void *id, int startrow, int nrows, long fillattr) 659 { 660 struct lcg_screen *ss = id; 661 int i; 662 663 bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols * 664 sizeof(ss->ss_image[0])); 665 for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i) 666 ss->ss_image[i].attr = fillattr; 667 if (ss != curscr) 668 return; 669 #ifdef LCG_NO_ACCEL 670 memset(&lcgaddr[startrow * lcg_onerow], 0, nrows * lcg_onerow); 671 #else 672 blkset(LCG_FB_ADDR + (startrow * lcg_onerow), (lcg_cols * lcg_font.fontwidth), 673 (nrows * lcg_font.fontheight), (fillattr & LCG_BG_MASK) >> 4); 674 #endif 675 } 676 677 static int 678 lcg_allocattr(void *id, int fg, int bg, int flags, long *attrp) 679 { 680 long myattr; 681 682 if (flags & WSATTR_WSCOLORS) 683 myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK); 684 else 685 myattr = WSCOL_WHITE << 4; /* XXXX */ 686 if (flags & WSATTR_REVERSE) 687 myattr |= LCG_ATTR_REVERSE; 688 if (flags & WSATTR_UNDERLINE) 689 myattr |= LCG_ATTR_UNDERLINE; 690 *attrp = myattr; 691 return 0; 692 } 693 694 static int 695 lcg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 696 { 697 struct wsdisplay_fbinfo *fb = (void *)data; 698 int i; 699 700 switch (cmd) { 701 case WSDISPLAYIO_GTYPE: 702 *(u_int *)data = WSDISPLAY_TYPE_LCG; 703 break; 704 705 case WSDISPLAYIO_GINFO: 706 fb->height = lcg_ysize; 707 fb->width = lcg_xsize; 708 fb->depth = lcg_depth; 709 fb->cmsize = 1 << lcg_depth; 710 break; 711 712 case WSDISPLAYIO_LINEBYTES: 713 *(u_int *)data = lcg_xsize; 714 break; 715 716 case WSDISPLAYIO_GETCMAP: 717 return lcg_get_cmap((struct wsdisplay_cmap *)data); 718 719 case WSDISPLAYIO_PUTCMAP: 720 return lcg_set_cmap((struct wsdisplay_cmap *)data); 721 722 case WSDISPLAYIO_GMODE: 723 return EPASSTHROUGH; 724 725 case WSDISPLAYIO_SMODE: 726 /* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */ 727 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 728 /* FIXME: if this is meant to reset palette LUT reload has to be triggered too */ 729 bzero(lutaddr, LCG_LUT_SIZE); 730 for (i = 0; i < 8; ++i) { 731 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 732 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 733 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 734 lutaddr[i * 8 + 1] = i; 735 lutaddr[i * 8 + 2] = 1; 736 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 737 lutaddr[i * 8 + 4] = 1; 738 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 739 lutaddr[i * 8 + 6] = 1; 740 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 741 } 742 if (savescr != NULL) 743 lcg_show_screen(NULL, savescr, 0, NULL, NULL); 744 savescr = NULL; 745 } else { /* WSDISPLAYIO_MODE_MAPPED */ 746 savescr = curscr; 747 curscr = NULL; 748 /* clear screen? */ 749 } 750 751 return EPASSTHROUGH; 752 #if 0 753 case WSDISPLAYIO_SVIDEO: 754 if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) { 755 curcmd = curc; 756 } else { 757 curc = curcmd; 758 curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA); 759 curcmd |= CUR_CMD_FOPB; 760 } 761 WRITECUR(CUR_CMD, curcmd); 762 break; 763 764 case WSDISPLAYIO_GVIDEO: 765 *(u_int *)data = (curcmd & CUR_CMD_FOPB ? 766 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON); 767 break; 768 769 #endif 770 default: 771 return EPASSTHROUGH; 772 } 773 return 0; 774 } 775 776 static paddr_t 777 lcg_mmap(void *v, void *vs, off_t offset, int prot) 778 { 779 if (offset >= lcg_fb_size || offset < 0) 780 return -1; 781 return (LCG_FB_ADDR + offset) >> PGSHIFT; 782 } 783 784 int 785 lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 786 int *curxp, int *curyp, long *defattrp) 787 { 788 int i; 789 struct lcg_screen *ss; 790 791 *cookiep = kmem_alloc(sizeof(struct lcg_screen), KM_SLEEP); 792 bzero(*cookiep, sizeof(struct lcg_screen)); 793 *curxp = *curyp = 0; 794 *defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 795 ss = *cookiep; 796 for (i = 0; i < lcg_cols * lcg_rows; ++i) 797 ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 798 return 0; 799 } 800 801 void 802 lcg_free_screen(void *v, void *cookie) 803 { 804 } 805 806 int 807 lcg_show_screen(void *v, void *cookie, int waitok, 808 void (*cb)(void *, int, int), void *cbarg) 809 { 810 struct lcg_screen *ss = cookie; 811 int row, col, dot_fg, dot_bg, j, attr; 812 #ifdef LCG_NO_ACCEL 813 int iter, jter; 814 unsigned char ch; 815 #endif 816 817 if (ss == curscr) 818 return (0); 819 #ifdef LCG_NO_ACCEL 820 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 821 #endif 822 823 for (row = 0; row < lcg_rows; row++) 824 for (col = 0; col < lcg_cols; col++) { 825 attr = ss->ss_image[row * lcg_cols + col].attr; 826 if (attr & LCG_ATTR_REVERSE) { 827 dot_fg = (attr & LCG_BG_MASK) >> 4; 828 dot_bg = attr & LCG_FG_MASK; 829 } else { 830 dot_fg = attr & LCG_FG_MASK; 831 dot_bg = (attr & LCG_BG_MASK) >> 4; 832 } 833 u_char c = ss->ss_image[row * lcg_cols + col].data; 834 835 if (c < 32) 836 c = 32; 837 #ifndef LCG_NO_ACCEL 838 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 839 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 840 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 841 #else 842 for (iter = 0; iter < lcg_font.fontheight; iter++) { 843 ch = QFONT(c,iter); 844 for (jter = 0; jter < lcg_font.fontwidth; jter++) { 845 LCG_ADDR(row, col, iter, jter) = ((ch >> jter) & 1) ? dot_fg : dot_bg; 846 } 847 } 848 #endif 849 if (attr & LCG_ATTR_UNDERLINE) 850 for (j = 0; j < lcg_font.fontwidth; j++) 851 LCG_ADDR(row, col, 852 lcg_font.fontheight - 1, j) = dot_fg; 853 } 854 855 cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) + 856 ((lcg_font.fontheight - 1) * lcg_xsize) + 857 (ss->ss_curx * lcg_font.fontwidth)]; 858 cur_fg = ss->ss_cur_fg; 859 cur_bg = ss->ss_cur_bg; 860 861 curscr = ss; 862 return (0); 863 } 864 865 static int 866 lcg_get_cmap(struct wsdisplay_cmap *p) 867 { 868 u_int index = p->index, count = p->count; 869 int error; 870 871 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 872 return (EINVAL); 873 874 error = copyout(&lcg_cmap.r[index], p->red, count); 875 if (error) 876 return error; 877 error = copyout(&lcg_cmap.g[index], p->green, count); 878 if (error) 879 return error; 880 error = copyout(&lcg_cmap.b[index], p->blue, count); 881 return error; 882 } 883 884 static int 885 lcg_set_cmap(struct wsdisplay_cmap *p) 886 { 887 u_int index = p->index, count = p->count; 888 int error, s; 889 890 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 891 return (EINVAL); 892 893 error = copyin(p->red, &lcg_cmap.r[index], count); 894 if (error) 895 return error; 896 error = copyin(p->green, &lcg_cmap.g[index], count); 897 if (error) 898 return error; 899 error = copyin(p->blue, &lcg_cmap.b[index], count); 900 if (error) 901 return error; 902 903 s = spltty(); 904 /* FIXME: if this is meant to set palette LUT reload has to be triggered too */ 905 while (count-- > 0) { 906 lutaddr[index * 8 + 0] = 0; 907 lutaddr[index * 8 + 1] = index; 908 lutaddr[index * 8 + 2] = 1; 909 lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7); 910 lutaddr[index * 8 + 4] = 1; 911 lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7); 912 lutaddr[index * 8 + 6] = 1; 913 lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7); 914 ++index; 915 } 916 splx(s); 917 return (0); 918 } 919 920 cons_decl(lcg); 921 922 void 923 lcgcninit(struct consdev *cndev) 924 { 925 int i; 926 /* Clear screen */ 927 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 928 929 curscr = &lcg_conscreen; 930 for (i = 0; i < lcg_cols * lcg_rows; ++i) 931 lcg_conscreen.ss_image[i].attr = 932 (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 933 wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0, 934 (LCG_BG_COLOR << 4) | LCG_FG_COLOR); 935 cn_tab->cn_pri = CN_INTERNAL; 936 937 938 #if NDZKBD > 0 939 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 940 #endif 941 } 942 943 /* 944 * Called very early to setup the glass tty as console. 945 * Because it's called before the VM system is inited, virtual memory 946 * for the framebuffer can be stolen directly without disturbing anything. 947 */ 948 void 949 lcgcnprobe(struct consdev *cndev) 950 { 951 extern const struct cdevsw wsdisplay_cdevsw; 952 953 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 954 return; /* Only for VS 4000/60 and VLC */ 955 956 if (vax_confdata & 0x100) 957 return; /* Diagnostic console */ 958 959 lcg_init_common(NULL, NULL); 960 961 /* Set up default LUT */ 962 963 cndev->cn_pri = CN_INTERNAL; 964 cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 965 } 966 967 void 968 lcg_init_common(struct device *self, struct vsbus_attach_args *va) 969 { 970 u_int magic, *lcg_config; 971 int i; 972 extern vaddr_t virtual_avail; 973 long video_conf; 974 int cookie; 975 struct wsdisplay_font *wf; 976 977 struct lcg_softc *sc = (void *)self; 978 bus_dma_segment_t seg; 979 int rseg, err; 980 void *fifo_mem_vaddr; 981 #ifndef LCG_NO_ACCEL 982 u_char line; 983 u_int ch, temp; 984 #endif 985 986 if (regaddr != NULL) 987 return; 988 989 /* map LCG registers first */ 990 if (self != NULL) { 991 regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG)); 992 if (regaddr == 0) { 993 device_printf(self, 994 "Couldn't allocate register memory.\n"); 995 return; 996 } 997 } else { 998 regaddr = (long*)virtual_avail; 999 virtual_avail += LCG_REG_SIZE; 1000 ioaccess((vaddr_t)regaddr, LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG)); 1001 } 1002 1003 /* 1004 * v = *0x200f0010 & VLC ? 0x07 : 0xf0; 1005 * switch(v) { 1006 * 0x05: 1280x1024 1007 * 0x06: conf & 0x80 ? 1024x768 : 640x480 1008 * 0x07: conf & 0x80 ? 1024x768 ? 1024x864 1009 * 0x20: 1024x864 1010 * 0x40: 1024x768 1011 * 0x60: 1024x864 1012 * 0x80: 1280x1024 4BPN 1013 * 0x90: 1280x1024 8BPN 1014 * 0xb0: 1280x1024 8BPN 2HD 1015 */ 1016 if (self != NULL) { 1017 lcg_config = (u_int *)vax_map_physmem(LCG_CONFIG, 1); 1018 } else { 1019 lcg_config = (u_int *)virtual_avail; 1020 ioaccess((vaddr_t)lcg_config, LCG_CONFIG, 1); 1021 } 1022 magic = *lcg_config & (vax_boardtype == VAX_BTYP_46 ? 0xf0 : 0x07); 1023 if (self != NULL) { 1024 vax_unmap_physmem((vaddr_t)lcg_config, 1); 1025 } else { 1026 iounaccess((vaddr_t)lcg_config, 1); 1027 } 1028 lcg_depth = 8; 1029 switch(magic) { 1030 case 0x80: /* KA46 HR 1280x1024 4BPLN */ 1031 lcg_depth = 4; 1032 case 0x05: /* KA48 HR 1280x1024 8BPLN */ 1033 case 0x90: /* KA46 HR 1280x1024 8BPLN */ 1034 case 0xb0: /* KA46 HR 1280x1024 8BPLN 2HD */ 1035 lcg_xsize = 1280; 1036 lcg_ysize = 1024; 1037 break; 1038 case 0x06: /* KA48 1024x768 or 640x480 */ 1039 if (vax_confdata & 0x80) { 1040 lcg_xsize = 1024; 1041 lcg_ysize = 768; 1042 } else { 1043 lcg_xsize = 640; 1044 lcg_ysize = 480; 1045 } 1046 break; 1047 case 0x07: /* KA48 1024x768 or 1024x864 */ 1048 lcg_xsize = 1024; 1049 lcg_ysize = (vax_confdata & 0x80) ? 768 : 864; 1050 break; 1051 case 0x20: /* KA46 1024x864 */ 1052 case 0x60: /* KA46 1024x864 */ 1053 lcg_xsize = 1024; 1054 lcg_ysize = 864; 1055 break; 1056 case 0x40: /* KA46 1024x768 */ 1057 lcg_xsize = 1024; 1058 lcg_ysize = 768; 1059 break; 1060 default: 1061 panic("LCG model not supported"); 1062 } 1063 if (self != NULL) 1064 aprint_normal_dev(self, 1065 "framebuffer size %dx%d, depth %d (magic 0x%x)\n", 1066 lcg_xsize, lcg_ysize, lcg_depth, magic); 1067 1068 wsfont_init(); 1069 cookie = wsfont_find(NULL, 12, 22, 0, WSDISPLAY_FONTORDER_R2L, 1070 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1071 if (cookie == -1) 1072 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0, 1073 WSFONT_FIND_BITMAP); 1074 if (cookie == -1) 1075 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 1076 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1077 if (cookie == -1 || wsfont_lock(cookie, &wf)) 1078 panic("lcg_common_init: can't load console font"); 1079 lcg_font = *wf; 1080 lcg_cols = lcg_xsize / lcg_font.fontwidth; 1081 lcg_rows = lcg_ysize / lcg_font.fontheight; 1082 if (self != NULL) { 1083 aprint_normal_dev(self, "using font %s (%dx%d), ", 1084 lcg_font.name, 1085 lcg_font.fontwidth, lcg_font.fontheight); 1086 aprint_normal("console size: %dx%d\n", lcg_cols, lcg_rows); 1087 } 1088 lcg_onerow = lcg_xsize * lcg_font.fontheight; 1089 lcg_fb_size = lcg_xsize * lcg_ysize; 1090 lcg_stdscreen.ncols = lcg_cols; 1091 lcg_stdscreen.nrows = lcg_rows; 1092 lcg_stdscreen.fontwidth = lcg_font.fontwidth; 1093 lcg_stdscreen.fontheight = lcg_font.fontheight; 1094 lcg_glyph_size = lcg_font.stride * lcg_font.fontheight; 1095 snprintf(lcg_stdscreen_name, sizeof(lcg_stdscreen_name), "%dx%d", lcg_cols, lcg_rows); 1096 qf = lcg_font.data; 1097 qf2 = (u_short *)lcg_font.data; 1098 1099 if (self != NULL) { 1100 lcgaddr = (void *)vax_map_physmem(va->va_paddr, 1101 ((lcg_fb_size + LCG_FONT_STORAGE_SIZE)/VAX_NBPG)); 1102 if (lcgaddr == 0) { 1103 device_printf(self, 1104 "unable to allocate framebuffer memory.\n"); 1105 return; 1106 } 1107 #ifndef LCG_NO_ACCEL 1108 fontaddr = lcgaddr + lcg_fb_size; 1109 1110 /* copy font bitmaps */ 1111 for (ch = 0; ch < 256; ch++) 1112 for (line = 0; line < lcg_font.fontheight; line++) { 1113 temp = QFONT(ch, line); 1114 if (lcg_font.stride == 1) 1115 fontaddr[(ch * lcg_font.fontheight) + line] = temp; 1116 else { 1117 /* stride == 2 */ 1118 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line] = temp & 0xff; 1119 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line + 1] = (temp >> 16) & 0xff; 1120 } 1121 } 1122 #endif 1123 1124 lutaddr = (void *)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1125 if (lutaddr == 0) { 1126 device_printf(self, 1127 "unable to allocate LUT memory.\n"); 1128 return; 1129 } 1130 fifoaddr = (long*)vax_map_physmem(LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1131 if (regaddr == 0) { 1132 device_printf(self, "unable to map FIFO window\n"); 1133 return; 1134 } 1135 1136 /* allocate contiguous physical memory block for FIFO */ 1137 err = bus_dmamem_alloc(va->va_dmat, LCG_FIFO_SIZE, 1138 LCG_FIFO_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 1139 if (err) { 1140 device_printf(self, 1141 "unable to allocate FIFO memory block, err = %d\n", 1142 err); 1143 return; 1144 } 1145 1146 err = bus_dmamem_map(va->va_dmat, &seg, rseg, LCG_FIFO_SIZE, 1147 &fifo_mem_vaddr, BUS_DMA_NOWAIT); 1148 if (err) { 1149 device_printf(self, 1150 "unable to map FIFO memory block, err = %d\n", 1151 err); 1152 bus_dmamem_free(va->va_dmat, &seg, rseg); 1153 return; 1154 } 1155 1156 err = bus_dmamap_create(va->va_dmat, LCG_FIFO_SIZE, rseg, 1157 LCG_FIFO_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dm); 1158 if (err) { 1159 device_printf(self, 1160 "unable to create DMA map, err = %d\n", 1161 err); 1162 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1163 bus_dmamem_free(va->va_dmat, &seg, rseg); 1164 return; 1165 } 1166 1167 err = bus_dmamap_load(va->va_dmat, sc->sc_dm, fifo_mem_vaddr, 1168 LCG_FIFO_SIZE, NULL, BUS_DMA_NOWAIT); 1169 if (err) { 1170 device_printf(self, 1171 "unable to load DMA map, err = %d\n", 1172 err); 1173 bus_dmamap_destroy(va->va_dmat, sc->sc_dm); 1174 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1175 bus_dmamem_free(va->va_dmat, &seg, rseg); 1176 return; 1177 } 1178 1179 /* initialize LCG hardware */ 1180 LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0xd8000000; /* gfx reset, FIFO and AG enable */ 1181 // LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = (((LCG_FB_ADDR + lcg_fb_size) & 0xffff0000) | (LCG_FB_ADDR >> 16)); 1182 LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = 0xffff0000; 1183 LCG_REG(LCG_REG_FIFO_BASE) = sc->sc_dm->dm_segs[0].ds_addr; 1184 LCG_REG(LCG_REG_FIFO_BASE2) = sc->sc_dm->dm_segs[0].ds_addr; 1185 LCG_REG(LCG_REG_FIFO_MASKS) = 0xffff; 1186 LCG_REG(LCG_REG_FIFO_SAVE_HEAD_OFFSET) = sc->sc_dm->dm_segs[0].ds_addr; 1187 // LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0; 1188 // LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0x50000000; /* FIFO and AG enable */ 1189 LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0xffffffff; 1190 LCG_REG(LCG_REG_GRAPHICS_INT_SET_ENABLE) = 0; 1191 LCG_REG(LCG_REG_GRAPHICS_INT_CLR_ENABLE) = 0xffffffff; 1192 LCG_REG(LCG_REG_LCG_GO) = 3; /* FIFO and AG go */ 1193 // LCG_REG(LCG_REG_BREAKPT_ADDRESS) = 0x2fffffff; 1194 1195 } else { 1196 lcgaddr = (void *)virtual_avail; 1197 virtual_avail += lcg_fb_size + LCG_FONT_STORAGE_SIZE; 1198 ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG)); 1199 1200 lutaddr = (void *)virtual_avail; 1201 virtual_avail += LCG_LUT_SIZE; 1202 ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1203 1204 fifoaddr = (long*)virtual_avail; 1205 virtual_avail += LCG_FIFO_WIN_SIZE; 1206 ioaccess((vaddr_t)fifoaddr, LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1207 } 1208 1209 bzero(lutaddr, LCG_LUT_SIZE); 1210 for (i = 0; i < 8; ++i) { 1211 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 1212 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 1213 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 1214 lutaddr[i * 8 + 1] = i; 1215 lutaddr[i * 8 + 2] = 1; 1216 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 1217 lutaddr[i * 8 + 4] = 1; 1218 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 1219 lutaddr[i * 8 + 6] = 1; 1220 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 1221 } 1222 1223 /* 1224 * 0xf100165b 4000/60 1225 * 1111 0001 0000 0000 0001 0110 0101 1011 1226 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1227 * 3322 2222 2222 1111 1111 11 1228 * 1098 7654 3210 9876 5432 1098 7654 3210 1229 * 1230 * 0xf1001d7b 4000/VLC 1231 * 1111 0001 0000 0000 0001 1101 0111 1011 1232 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1233 * 3322 2222 2222 1111 1111 11 1234 * 1098 7654 3210 9876 5432 1098 7654 3210 1235 * 1236 * 31-30 11 Vertical state 1237 * 29-38 11 Horizontal state 1238 * 27-26 00 1239 * 25 0 console LUT select 1240 * 24 1 control LUT select 1241 * 23 0 1242 * 22 0 cursor active 1243 * 21-16 000000 1244 * 15 0 video subsystem reset 1245 * 14 0 1246 * 13 0 LUT load size 2KB 1247 * 12 1 enable H sync 1248 * 11 0 Full LUT load 1 1249 * 10 1 video clock select 1250 * 9- 8 10 memory refresh rate 01 1251 * 7- 6 01 video refresh rate 1252 * 5 0 load select 1 1253 * 4 1 read cursor output 1254 * 3 1 LUT load enable 1255 * 2 0 cursor enable 1256 * 1 1 video enable 1257 * 0 1 refresh clock enable 1258 */ 1259 /* prepare video_config reg for LUT reload */ 1260 video_conf 1261 = (3 << 30) /* vertical state */ 1262 | (3 << 28) /* horizontal state */ 1263 | (0 << 26) /* unused */ 1264 | (0 << 25) /* console LUT select */ 1265 | (0 << 24) /* control LUT select */ 1266 | (0 << 23) /* unused */ 1267 | (0 << 22) /* cursor active */ 1268 | (0 << 16) /* current cursor scanline showing */ 1269 | (0 << 15) /* video subsystem reset */ 1270 | (0 << 14) /* unused */ 1271 | (1 << 13) /* LUT load size 2 KB */ 1272 | (1 << 12) /* enable horizontal sync */ 1273 | (1 << 10) /* video clock select */ 1274 | (1 << 6) /* video refresh select */ 1275 | (1 << 4) /* read cursor output */ 1276 | (1 << 3) /* LUT load enable */ 1277 | (0 << 2) /* cursor enable */ 1278 | (1 << 1) /* video enable */ 1279 | (1 << 0); /* refresh clock enable */ 1280 /* FIXME needs updating for all supported models */ 1281 if (lcg_xsize == 1280) { /* 4000/60 HR 4PLN */ 1282 video_conf |= (0 << 11); /* split LUT load */ 1283 video_conf |= (2 << 8); /* memory refresh select */ 1284 video_conf |= (0 << 5); /* split shift register load */ 1285 } else { /* 4000/VLC LR 8PLN */ 1286 video_conf |= (1 << 11); /* Full LUT load */ 1287 video_conf |= (1 << 8); /* memory refresh select */ 1288 video_conf |= (1 << 5); /* split shift register load */ 1289 } 1290 1291 LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf; 1292 /* vital !!! */ 1293 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1; 1294 LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET; 1295 1296 delay(1000); 1297 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0; 1298 1299 #ifdef LCG_DEBUG 1300 if (self != NULL) 1301 device_printf(self, "video config register set 0x%08lx\n", 1302 video_conf); 1303 #endif 1304 } 1305