1 /* $NetBSD: lcg.c,v 1.4 2018/06/06 01:49:08 maya 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.4 2018/06/06 01:49:08 maya 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/malloc.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 struct device ss_dev; 109 bus_dmamap_t sc_dm; 110 }; 111 112 CFATTACH_DECL_NEW(lcg, sizeof(struct lcg_softc), 113 lcg_match, lcg_attach, NULL, NULL); 114 115 static void lcg_cursor(void *, int, int, int); 116 static int lcg_mapchar(void *, int, unsigned int *); 117 static void lcg_putchar(void *, int, int, u_int, long); 118 static void lcg_copycols(void *, int, int, int,int); 119 static void lcg_erasecols(void *, int, int, int, long); 120 static void lcg_copyrows(void *, int, int, int); 121 static void lcg_eraserows(void *, int, int, long); 122 static int lcg_allocattr(void *, int, int, int, long *); 123 static int lcg_get_cmap(struct wsdisplay_cmap *); 124 static int lcg_set_cmap(struct wsdisplay_cmap *); 125 static void lcg_init_common(struct device *, struct vsbus_attach_args *); 126 127 const struct wsdisplay_emulops lcg_emulops = { 128 lcg_cursor, 129 lcg_mapchar, 130 lcg_putchar, 131 lcg_copycols, 132 lcg_erasecols, 133 lcg_copyrows, 134 lcg_eraserows, 135 lcg_allocattr 136 }; 137 138 static char lcg_stdscreen_name[10] = "160x68"; 139 struct wsscreen_descr lcg_stdscreen = { 140 lcg_stdscreen_name, 160, 68, /* dynamically set */ 141 &lcg_emulops, 142 8, 15, /* dynamically set */ 143 WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS, 144 }; 145 146 const struct wsscreen_descr *_lcg_scrlist[] = { 147 &lcg_stdscreen, 148 }; 149 150 const struct wsscreen_list lcg_screenlist = { 151 sizeof(_lcg_scrlist) / sizeof(struct wsscreen_descr *), 152 _lcg_scrlist, 153 }; 154 155 static char *lcgaddr; 156 static char *lutaddr; 157 static volatile long *regaddr; 158 static volatile long *fifoaddr; 159 #ifndef LCG_NO_ACCEL 160 static char *fontaddr; 161 #endif 162 163 static int lcg_xsize; 164 static int lcg_ysize; 165 static int lcg_depth; 166 static int lcg_cols; 167 static int lcg_rows; 168 static int lcg_onerow; 169 static int lcg_fb_size; 170 static int lcg_glyph_size; /* bitmap size in bits */ 171 172 static char *cursor; 173 174 static int cur_on; 175 176 static int cur_fg, cur_bg; 177 178 179 /* Our current hardware colormap */ 180 static struct hwcmap256 { 181 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 182 u_int8_t r[CMAP_SIZE]; 183 u_int8_t g[CMAP_SIZE]; 184 u_int8_t b[CMAP_SIZE]; 185 } lcg_cmap; 186 187 /* The default colormap */ 188 static struct { 189 u_int8_t r[8]; 190 u_int8_t g[8]; 191 u_int8_t b[8]; 192 } lcg_default_cmap = { 193 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, 194 { 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff }, 195 { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } 196 }; 197 198 struct wsdisplay_font lcg_font; 199 static u_char *qf; 200 static u_short *qf2; 201 202 #define QCHAR(c) (c < lcg_font.firstchar ? 0 : \ 203 (c >= (lcg_font.firstchar + lcg_font.numchars) ? 0 : c - lcg_font.firstchar)) 204 #define QFONT(c,line) ((lcg_font.stride == 2 ? \ 205 qf2[QCHAR(c) * lcg_font.fontheight + line] : \ 206 qf[QCHAR(c) * lcg_font.fontheight + line])) 207 #define LCG_ADDR(row, col, line, dot) \ 208 lcgaddr[((col) * lcg_font.fontwidth) + ((row) * lcg_font.fontheight * lcg_xsize) + \ 209 (line) * lcg_xsize + dot] 210 211 212 static int lcg_ioctl(void *, void *, u_long, void *, int, struct lwp *); 213 static paddr_t lcg_mmap(void *, void *, off_t, int); 214 static int lcg_alloc_screen(void *, const struct wsscreen_descr *, 215 void **, int *, int *, long *); 216 static void lcg_free_screen(void *, void *); 217 static int lcg_show_screen(void *, void *, int, 218 void (*) (void *, int, int), void *); 219 static void lcg_crsr_blink(void *); 220 221 /* LCG HW accel functions */ 222 #ifndef LCG_NO_ACCEL 223 static void fifo_put(long data); 224 static int fifo_fill(int iterations); 225 static u_char fifo_counter = 0; 226 227 static void blkcpy(long source, long dest, int xdim, int ydim); 228 static void blkset(long dest, int xdim, int ydim, char color); 229 static void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg); 230 #endif /* LCG_NO_ACCEL */ 231 232 const struct wsdisplay_accessops lcg_accessops = { 233 lcg_ioctl, 234 lcg_mmap, 235 lcg_alloc_screen, 236 lcg_free_screen, 237 lcg_show_screen, 238 0 /* load_font */ 239 }; 240 241 /* TODO allocate ss_image dynamically for consoles beyond first one */ 242 struct lcg_screen { 243 int ss_curx; 244 int ss_cury; 245 int ss_cur_fg; 246 int ss_cur_bg; 247 struct { 248 u_char data; /* Image character */ 249 u_char attr; /* Attribute: 80/70/08/07 */ 250 } ss_image[160 * 128]; /* allow for maximum possible cell matrix */ 251 }; 252 #define LCG_ATTR_UNDERLINE 0x80 253 #define LCG_BG_MASK 0x70 254 #define LCG_ATTR_REVERSE 0x08 255 #define LCG_FG_MASK 0x07 256 257 static struct lcg_screen lcg_conscreen; 258 static struct lcg_screen *curscr; 259 static struct lcg_screen *savescr; 260 261 static callout_t lcg_cursor_ch; 262 263 #ifndef LCG_NO_ACCEL 264 void fifo_put(long data) 265 { 266 fifo_counter &= 0x3; 267 fifoaddr[fifo_counter] = data; 268 fifo_counter++; 269 } 270 271 int fifo_fill(int iterations) 272 { 273 long status; 274 int counter = 0; 275 276 while (fifo_counter % 4) 277 fifo_put(0); 278 279 #ifdef LCG_SAFE 280 status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS); 281 while ((counter < iterations) && ((status & 0x80000000) == 0x80000000)) { 282 delay(1000); 283 status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS); 284 counter++; 285 } 286 #endif 287 288 if (counter == 0) 289 return 0; 290 else 291 return 1; 292 } 293 294 void blkcpy(long source, long dest, int xdim, int ydim) 295 { 296 int err; 297 298 #ifdef LCG_SAFE 299 if ((source < LCG_FB_ADDR) || (source > LCG_FB_ADDR + lcg_fb_size)) { 300 printf("lcg: blkcpy: invalid source 0x%lx\n", source); 301 return; 302 } 303 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 304 printf("lcg: blkcpy: invalid destination 0x%lx\n", dest); 305 return; 306 } 307 #endif 308 309 #ifdef LCG_SAFE 310 fifo_put(0x0c010000 | (cur_fg & 0xff)); 311 #endif 312 fifo_put(0x01020006); 313 314 fifo_put(0x06800000); 315 fifo_put(source); 316 fifo_put(lcg_xsize); 317 318 fifo_put(0x05800000); 319 fifo_put(dest); 320 fifo_put(lcg_xsize); 321 322 fifo_put(0x03400000); 323 fifo_put(0xff); 324 325 fifo_put(0x02000003); 326 327 #ifdef LCG_SAFE 328 fifo_put(0x04c00000); 329 fifo_put(0); 330 fifo_put(lcg_xsize); 331 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 332 #endif 333 334 fifo_put(0x09c00000); 335 fifo_put(((ydim & 0xffff) << 16) | xdim); 336 fifo_put(0); 337 fifo_put(0); 338 339 err = fifo_fill(200); 340 if (err) 341 printf("lcg: AG still busy after 200 msec\n"); 342 } 343 344 void blkset(long dest, int xdim, int ydim, char color) 345 { 346 int err; 347 348 #ifdef LCG_SAFE 349 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 350 printf("lcg: blkset: invalid destination 0x%lx\n", dest); 351 return; 352 } 353 #endif 354 355 fifo_put(0x0c010000 | (color & 0xff)); 356 357 fifo_put(0x01000000); 358 359 fifo_put(0x05800000); 360 fifo_put(dest); 361 fifo_put(lcg_xsize); 362 363 fifo_put(0x03400000); 364 fifo_put(0xff); 365 366 fifo_put(0x02000003); 367 368 #ifdef LCG_SAFE 369 fifo_put(0x04c00000); 370 fifo_put(0); 371 fifo_put(lcg_xsize); 372 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 373 #endif 374 375 fifo_put(0x09c00000); 376 fifo_put(((ydim & 0xffff) << 16) | xdim); 377 fifo_put(0); 378 fifo_put(0); 379 380 err = fifo_fill(200); 381 if (err) 382 printf("lcg: AG still busy after 200 msec\n"); 383 } 384 385 void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg) 386 { 387 int err; 388 #ifdef LCG_SAFE 389 if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) { 390 printf("lcg: blkset: invalid destination 0x%lx\n", dest); 391 return; 392 } 393 #endif 394 395 fifo_put(0x0c050000 | (bg & 0xff)); 396 fifo_put(0x0c010000 | (fg & 0xff)); 397 398 fifo_put(0x01030008); 399 400 fifo_put(0x06800000); 401 fifo_put(source); 402 //fifo_put(lcg_xsize); 403 fifo_put(lcg_font.stride); 404 405 fifo_put(0x05800000); 406 fifo_put(dest); 407 fifo_put(lcg_xsize); 408 409 fifo_put(0x03400000); 410 fifo_put(0xff); 411 412 fifo_put(0x02000003); 413 414 #ifdef LCG_SAFE 415 fifo_put(0x04c00000); 416 fifo_put(0); 417 fifo_put(lcg_xsize); 418 fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR)); 419 #endif 420 421 fifo_put(0x09c00000); 422 fifo_put(((ydim & 0xffff) << 16) | (xdim & 0xffff)); 423 fifo_put(0); 424 fifo_put(0); 425 426 err = fifo_fill(200); 427 if (err) 428 printf("lcg: AG still busy after 200 msec\n"); 429 } 430 #endif /* LCG_NO_ACCEL */ 431 432 int 433 lcg_match(struct device *parent, struct cfdata *match, void *aux) 434 { 435 struct vsbus_softc *sc = device_private(parent); 436 struct vsbus_attach_args *va = aux; 437 char *ch = (char *)va->va_addr; 438 439 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 440 return 0; 441 442 *ch = 1; 443 if ((*ch & 1) == 0) 444 return 0; 445 *ch = 0; 446 if ((*ch & 1) != 0) 447 return 0; 448 449 /* XXX use vertical interrupt? */ 450 sc->sc_mask = 0x04; /* XXX - should be generated */ 451 scb_fake(0x120, 0x15); 452 return 20; 453 } 454 455 void 456 lcg_attach(struct device *parent, struct device *self, void *aux) 457 { 458 struct vsbus_attach_args *va = aux; 459 struct wsemuldisplaydev_attach_args aa; 460 461 printf("\n"); 462 aa.console = lcgaddr != NULL; 463 464 lcg_init_common(self, va); 465 466 curscr = &lcg_conscreen; 467 468 aa.scrdata = &lcg_screenlist; 469 aa.accessops = &lcg_accessops; 470 471 /* enable software cursor */ 472 callout_init(&lcg_cursor_ch, 0); 473 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 474 475 config_found(self, &aa, wsemuldisplaydevprint); 476 } 477 478 static void 479 lcg_crsr_blink(void *arg) 480 { 481 int dot; 482 483 if (cur_on && curscr != NULL) 484 for (dot = 0; dot < lcg_font.fontwidth; dot++) 485 cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg; 486 487 callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL); 488 } 489 490 void 491 lcg_cursor(void *id, int on, int row, int col) 492 { 493 struct lcg_screen *ss = id; 494 int dot, attr; 495 496 attr = ss->ss_image[row * lcg_cols + col].attr; 497 if (ss == curscr) { 498 if (cursor != NULL) { 499 int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols + 500 ss->ss_curx].data, lcg_font.fontheight - 1); 501 attr = ss->ss_image[ss->ss_cury * lcg_cols + 502 ss->ss_curx].attr; 503 504 if (attr & LCG_ATTR_REVERSE) { 505 cur_bg = attr & LCG_FG_MASK; 506 cur_fg = (attr & LCG_BG_MASK) >> 4; 507 } else { 508 cur_fg = attr & LCG_FG_MASK; 509 cur_bg = (attr & LCG_BG_MASK) >> 4; 510 } 511 for (dot = 0; dot < lcg_font.fontwidth; dot++) 512 cursor[dot] = (ch & (1 << dot)) ? 513 cur_fg : cur_bg; 514 } 515 516 cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 517 cur_on = on; 518 if (attr & LCG_ATTR_REVERSE) { 519 cur_bg = attr & LCG_FG_MASK; 520 cur_fg = (attr & LCG_BG_MASK) >> 4; 521 } else { 522 cur_fg = attr & LCG_FG_MASK; 523 cur_bg = (attr & LCG_BG_MASK) >> 4; 524 } 525 } 526 ss->ss_curx = col; 527 ss->ss_cury = row; 528 if (attr & LCG_ATTR_REVERSE) { 529 ss->ss_cur_bg = attr & LCG_FG_MASK; 530 ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4; 531 } else { 532 ss->ss_cur_fg = attr & LCG_FG_MASK; 533 ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4; 534 } 535 } 536 537 int 538 lcg_mapchar(void *id, int uni, unsigned int *index) 539 { 540 if (uni < 256) { 541 *index = uni; 542 return (5); 543 } 544 *index = ' '; 545 return (0); 546 } 547 548 static void 549 lcg_putchar(void *id, int row, int col, u_int c, long attr) 550 { 551 struct lcg_screen *ss = id; 552 int i; 553 char dot_fg, dot_bg; 554 555 c &= 0xff; 556 557 ss->ss_image[row * lcg_cols + col].data = c; 558 ss->ss_image[row * lcg_cols + col].attr = attr; 559 if (ss != curscr) 560 return; 561 562 dot_fg = attr & LCG_FG_MASK; 563 dot_bg = (attr & LCG_BG_MASK) >> 4; 564 if (attr & LCG_ATTR_REVERSE) { 565 dot_fg = (attr & LCG_BG_MASK) >> 4; 566 dot_bg = attr & LCG_FG_MASK; 567 } 568 569 #ifndef LCG_NO_ACCEL 570 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 571 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 572 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 573 #else 574 for (i = 0; i < lcg_font.fontheight; i++) { 575 unsigned char ch = QFONT(c,i); 576 for (int j = 0; j < lcg_font.fontwidth; j++) { 577 LCG_ADDR(row, col, i, j) = ((ch >> j) & 1) ? dot_fg : dot_bg; 578 } 579 } 580 #endif /* LCG_NO_ACCEL */ 581 if (attr & LCG_ATTR_UNDERLINE) { 582 char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0); 583 for (i = 0; i < lcg_font.fontwidth; i++) 584 p[i] = ~p[i]; 585 } 586 } 587 588 589 590 /* 591 * copies columns inside a row. 592 */ 593 static void 594 lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols) 595 { 596 struct lcg_screen *ss = id; 597 #ifdef LCG_NO_ACCEL 598 int i = 0; 599 #endif 600 601 bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row * 602 lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0])); 603 if (ss != curscr) 604 return; 605 #ifdef LCG_NO_ACCEL 606 for (i = 0; i < lcg_font.fontheight; i++) 607 memcpy(&LCG_ADDR(row, dstcol, i, 0), 608 &LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth); 609 610 #else 611 blkcpy(LCG_FB_ADDR + (row * lcg_onerow) + (srccol * lcg_font.fontwidth), 612 LCG_FB_ADDR + (row * lcg_onerow) + (dstcol * lcg_font.fontwidth), 613 (ncols * lcg_font.fontwidth), lcg_font.fontheight); 614 #endif 615 } 616 617 /* 618 * Erases a bunch of chars inside one row. 619 */ 620 static void 621 lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 622 { 623 struct lcg_screen *ss = id; 624 int i; 625 626 bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0])); 627 for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i) 628 ss->ss_image[i].attr = fillattr; 629 if (ss != curscr) 630 return; 631 #ifdef LCG_NO_ACCEL 632 for (i = 0; i < lcg_font.fontheight; i++) 633 memset(&LCG_ADDR(row, startcol, i, 0), 0, ncols * lcg_font.fontwidth); 634 #else 635 blkset(LCG_FB_ADDR + (row * lcg_onerow) + (startcol * lcg_font.fontwidth), 636 (ncols * lcg_font.fontwidth), lcg_font.fontheight, (fillattr & LCG_BG_MASK) >> 4); 637 #endif 638 } 639 640 static void 641 lcg_copyrows(void *id, int srcrow, int dstrow, int nrows) 642 { 643 struct lcg_screen *ss = id; 644 645 bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols], 646 nrows * lcg_cols * sizeof(ss->ss_image[0])); 647 if (ss != curscr) 648 return; 649 #ifdef LCG_NO_ACCEL 650 memcpy(&lcgaddr[dstrow * lcg_onerow], 651 &lcgaddr[srcrow * lcg_onerow], nrows * lcg_onerow); 652 #else 653 blkcpy(LCG_FB_ADDR + (srcrow * lcg_onerow), LCG_FB_ADDR + (dstrow * lcg_onerow), 654 (lcg_cols * lcg_font.fontwidth), (nrows * lcg_font.fontheight)); 655 #endif 656 } 657 658 static void 659 lcg_eraserows(void *id, int startrow, int nrows, long fillattr) 660 { 661 struct lcg_screen *ss = id; 662 int i; 663 664 bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols * 665 sizeof(ss->ss_image[0])); 666 for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i) 667 ss->ss_image[i].attr = fillattr; 668 if (ss != curscr) 669 return; 670 #ifdef LCG_NO_ACCEL 671 memset(&lcgaddr[startrow * lcg_onerow], 0, nrows * lcg_onerow); 672 #else 673 blkset(LCG_FB_ADDR + (startrow * lcg_onerow), (lcg_cols * lcg_font.fontwidth), 674 (nrows * lcg_font.fontheight), (fillattr & LCG_BG_MASK) >> 4); 675 #endif 676 } 677 678 static int 679 lcg_allocattr(void *id, int fg, int bg, int flags, long *attrp) 680 { 681 long myattr; 682 683 if (flags & WSATTR_WSCOLORS) 684 myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK); 685 else 686 myattr = WSCOL_WHITE << 4; /* XXXX */ 687 if (flags & WSATTR_REVERSE) 688 myattr |= LCG_ATTR_REVERSE; 689 if (flags & WSATTR_UNDERLINE) 690 myattr |= LCG_ATTR_UNDERLINE; 691 *attrp = myattr; 692 return 0; 693 } 694 695 static int 696 lcg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 697 { 698 struct wsdisplay_fbinfo *fb = (void *)data; 699 int i; 700 701 switch (cmd) { 702 case WSDISPLAYIO_GTYPE: 703 *(u_int *)data = WSDISPLAY_TYPE_LCG; 704 break; 705 706 case WSDISPLAYIO_GINFO: 707 fb->height = lcg_ysize; 708 fb->width = lcg_xsize; 709 fb->depth = lcg_depth; 710 fb->cmsize = 1 << lcg_depth; 711 break; 712 713 case WSDISPLAYIO_LINEBYTES: 714 *(u_int *)data = lcg_xsize; 715 break; 716 717 case WSDISPLAYIO_GETCMAP: 718 return lcg_get_cmap((struct wsdisplay_cmap *)data); 719 720 case WSDISPLAYIO_PUTCMAP: 721 return lcg_set_cmap((struct wsdisplay_cmap *)data); 722 723 case WSDISPLAYIO_GMODE: 724 return EPASSTHROUGH; 725 726 case WSDISPLAYIO_SMODE: 727 /* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */ 728 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 729 /* FIXME: if this is meant to reset palette LUT reload has to be triggered too */ 730 bzero(lutaddr, LCG_LUT_SIZE); 731 for (i = 0; i < 8; ++i) { 732 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 733 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 734 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 735 lutaddr[i * 8 + 1] = i; 736 lutaddr[i * 8 + 2] = 1; 737 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 738 lutaddr[i * 8 + 4] = 1; 739 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 740 lutaddr[i * 8 + 6] = 1; 741 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 742 } 743 if (savescr != NULL) 744 lcg_show_screen(NULL, savescr, 0, NULL, NULL); 745 savescr = NULL; 746 } else { /* WSDISPLAYIO_MODE_MAPPED */ 747 savescr = curscr; 748 curscr = NULL; 749 /* clear screen? */ 750 } 751 752 return EPASSTHROUGH; 753 #if 0 754 case WSDISPLAYIO_SVIDEO: 755 if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) { 756 curcmd = curc; 757 } else { 758 curc = curcmd; 759 curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA); 760 curcmd |= CUR_CMD_FOPB; 761 } 762 WRITECUR(CUR_CMD, curcmd); 763 break; 764 765 case WSDISPLAYIO_GVIDEO: 766 *(u_int *)data = (curcmd & CUR_CMD_FOPB ? 767 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON); 768 break; 769 770 #endif 771 default: 772 return EPASSTHROUGH; 773 } 774 return 0; 775 } 776 777 static paddr_t 778 lcg_mmap(void *v, void *vs, off_t offset, int prot) 779 { 780 if (offset >= lcg_fb_size || offset < 0) 781 return -1; 782 return (LCG_FB_ADDR + offset) >> PGSHIFT; 783 } 784 785 int 786 lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 787 int *curxp, int *curyp, long *defattrp) 788 { 789 int i; 790 struct lcg_screen *ss; 791 792 *cookiep = malloc(sizeof(struct lcg_screen), M_DEVBUF, M_WAITOK); 793 bzero(*cookiep, sizeof(struct lcg_screen)); 794 *curxp = *curyp = 0; 795 *defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 796 ss = *cookiep; 797 for (i = 0; i < lcg_cols * lcg_rows; ++i) 798 ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 799 return 0; 800 } 801 802 void 803 lcg_free_screen(void *v, void *cookie) 804 { 805 } 806 807 int 808 lcg_show_screen(void *v, void *cookie, int waitok, 809 void (*cb)(void *, int, int), void *cbarg) 810 { 811 struct lcg_screen *ss = cookie; 812 int row, col, dot_fg, dot_bg, j, attr; 813 #ifdef LCG_NO_ACCEL 814 int iter, jter; 815 unsigned char ch; 816 #endif 817 818 if (ss == curscr) 819 return (0); 820 #ifdef LCG_NO_ACCEL 821 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 822 #endif 823 824 for (row = 0; row < lcg_rows; row++) 825 for (col = 0; col < lcg_cols; col++) { 826 attr = ss->ss_image[row * lcg_cols + col].attr; 827 if (attr & LCG_ATTR_REVERSE) { 828 dot_fg = (attr & LCG_BG_MASK) >> 4; 829 dot_bg = attr & LCG_FG_MASK; 830 } else { 831 dot_fg = attr & LCG_FG_MASK; 832 dot_bg = (attr & LCG_BG_MASK) >> 4; 833 } 834 u_char c = ss->ss_image[row * lcg_cols + col].data; 835 836 if (c < 32) 837 c = 32; 838 #ifndef LCG_NO_ACCEL 839 renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size), 840 LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth), 841 lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg); 842 #else 843 for (iter = 0; iter < lcg_font.fontheight; iter++) { 844 ch = QFONT(c,iter); 845 for (jter = 0; jter < lcg_font.fontwidth; jter++) { 846 LCG_ADDR(row, col, iter, jter) = ((ch >> jter) & 1) ? dot_fg : dot_bg; 847 } 848 } 849 #endif 850 if (attr & LCG_ATTR_UNDERLINE) 851 for (j = 0; j < lcg_font.fontwidth; j++) 852 LCG_ADDR(row, col, 853 lcg_font.fontheight - 1, j) = dot_fg; 854 } 855 856 cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) + 857 ((lcg_font.fontheight - 1) * lcg_xsize) + 858 (ss->ss_curx * lcg_font.fontwidth)]; 859 cur_fg = ss->ss_cur_fg; 860 cur_bg = ss->ss_cur_bg; 861 862 curscr = ss; 863 return (0); 864 } 865 866 static int 867 lcg_get_cmap(struct wsdisplay_cmap *p) 868 { 869 u_int index = p->index, count = p->count; 870 int error; 871 872 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 873 return (EINVAL); 874 875 error = copyout(&lcg_cmap.r[index], p->red, count); 876 if (error) 877 return error; 878 error = copyout(&lcg_cmap.g[index], p->green, count); 879 if (error) 880 return error; 881 error = copyout(&lcg_cmap.b[index], p->blue, count); 882 return error; 883 } 884 885 static int 886 lcg_set_cmap(struct wsdisplay_cmap *p) 887 { 888 u_int index = p->index, count = p->count; 889 int error, s; 890 891 if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index) 892 return (EINVAL); 893 894 error = copyin(p->red, &lcg_cmap.r[index], count); 895 if (error) 896 return error; 897 error = copyin(p->green, &lcg_cmap.g[index], count); 898 if (error) 899 return error; 900 error = copyin(p->blue, &lcg_cmap.b[index], count); 901 if (error) 902 return error; 903 904 s = spltty(); 905 /* FIXME: if this is meant to set palette LUT reload has to be triggered too */ 906 while (count-- > 0) { 907 lutaddr[index * 8 + 0] = 0; 908 lutaddr[index * 8 + 1] = index; 909 lutaddr[index * 8 + 2] = 1; 910 lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7); 911 lutaddr[index * 8 + 4] = 1; 912 lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7); 913 lutaddr[index * 8 + 6] = 1; 914 lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7); 915 ++index; 916 } 917 splx(s); 918 return (0); 919 } 920 921 cons_decl(lcg); 922 923 void 924 lcgcninit(struct consdev *cndev) 925 { 926 int i; 927 /* Clear screen */ 928 memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize); 929 930 curscr = &lcg_conscreen; 931 for (i = 0; i < lcg_cols * lcg_rows; ++i) 932 lcg_conscreen.ss_image[i].attr = 933 (LCG_BG_COLOR << 4) | LCG_FG_COLOR; 934 wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0, 935 (LCG_BG_COLOR << 4) | LCG_FG_COLOR); 936 cn_tab->cn_pri = CN_INTERNAL; 937 938 939 #if NDZKBD > 0 940 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 941 #endif 942 } 943 944 /* 945 * Called very early to setup the glass tty as console. 946 * Because it's called before the VM system is inited, virtual memory 947 * for the framebuffer can be stolen directly without disturbing anything. 948 */ 949 void 950 lcgcnprobe(struct consdev *cndev) 951 { 952 extern const struct cdevsw wsdisplay_cdevsw; 953 954 if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48)) 955 return; /* Only for VS 4000/60 and VLC */ 956 957 if (vax_confdata & 0x100) 958 return; /* Diagnostic console */ 959 960 lcg_init_common(NULL, NULL); 961 962 /* Set up default LUT */ 963 964 cndev->cn_pri = CN_INTERNAL; 965 cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 966 } 967 968 void 969 lcg_init_common(struct device *self, struct vsbus_attach_args *va) 970 { 971 u_int magic, *lcg_config; 972 int i; 973 extern vaddr_t virtual_avail; 974 long video_conf; 975 int cookie; 976 struct wsdisplay_font *wf; 977 978 struct lcg_softc *sc = (void *)self; 979 bus_dma_segment_t seg; 980 int rseg, err; 981 void *fifo_mem_vaddr; 982 #ifndef LCG_NO_ACCEL 983 u_char line; 984 u_int ch, temp; 985 #endif 986 987 if (regaddr != NULL) 988 return; 989 990 /* map LCG registers first */ 991 if (self != NULL) { 992 regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG)); 993 if (regaddr == 0) { 994 printf("%s: Couldn't allocate register memory.\n", self->dv_xname); 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("%s: framebuffer size %dx%d, depth %d (magic 0x%x)\n", 1065 self->dv_xname, lcg_xsize, lcg_ysize, lcg_depth, magic); 1066 1067 wsfont_init(); 1068 cookie = wsfont_find(NULL, 12, 22, 0, WSDISPLAY_FONTORDER_R2L, 1069 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1070 if (cookie == -1) 1071 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0, 1072 WSFONT_FIND_BITMAP); 1073 if (cookie == -1) 1074 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 1075 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 1076 if (cookie == -1 || wsfont_lock(cookie, &wf)) 1077 panic("lcg_common_init: can't load console font"); 1078 lcg_font = *wf; 1079 lcg_cols = lcg_xsize / lcg_font.fontwidth; 1080 lcg_rows = lcg_ysize / lcg_font.fontheight; 1081 if (self != NULL) { 1082 aprint_normal("%s: using font %s (%dx%d), ", self->dv_xname, lcg_font.name, 1083 lcg_font.fontwidth, lcg_font.fontheight); 1084 aprint_normal("console size: %dx%d\n", lcg_cols, lcg_rows); 1085 } 1086 lcg_onerow = lcg_xsize * lcg_font.fontheight; 1087 lcg_fb_size = lcg_xsize * lcg_ysize; 1088 lcg_stdscreen.ncols = lcg_cols; 1089 lcg_stdscreen.nrows = lcg_rows; 1090 lcg_stdscreen.fontwidth = lcg_font.fontwidth; 1091 lcg_stdscreen.fontheight = lcg_font.fontheight; 1092 lcg_glyph_size = lcg_font.stride * lcg_font.fontheight; 1093 snprintf(lcg_stdscreen_name, sizeof(lcg_stdscreen_name), "%dx%d", lcg_cols, lcg_rows); 1094 qf = lcg_font.data; 1095 qf2 = (u_short *)lcg_font.data; 1096 1097 if (self != NULL) { 1098 lcgaddr = (void *)vax_map_physmem(va->va_paddr, 1099 ((lcg_fb_size + LCG_FONT_STORAGE_SIZE)/VAX_NBPG)); 1100 if (lcgaddr == 0) { 1101 printf("%s: unable to allocate framebuffer memory.\n", self->dv_xname); 1102 return; 1103 } 1104 #ifndef LCG_NO_ACCEL 1105 fontaddr = lcgaddr + lcg_fb_size; 1106 1107 /* copy font bitmaps */ 1108 for (ch = 0; ch < 256; ch++) 1109 for (line = 0; line < lcg_font.fontheight; line++) { 1110 temp = QFONT(ch, line); 1111 if (lcg_font.stride == 1) 1112 fontaddr[(ch * lcg_font.fontheight) + line] = temp; 1113 else { 1114 /* stride == 2 */ 1115 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line] = temp & 0xff; 1116 fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line + 1] = (temp >> 16) & 0xff; 1117 } 1118 } 1119 #endif 1120 1121 lutaddr = (void *)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1122 if (lutaddr == 0) { 1123 printf("%s: unable to allocate LUT memory.\n", self->dv_xname); 1124 return; 1125 } 1126 fifoaddr = (long*)vax_map_physmem(LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1127 if (regaddr == 0) { 1128 printf("%s: unable to map FIFO window\n", self->dv_xname); 1129 return; 1130 } 1131 1132 /* allocate contiguous physical memory block for FIFO */ 1133 err = bus_dmamem_alloc(va->va_dmat, LCG_FIFO_SIZE, 1134 LCG_FIFO_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 1135 if (err) { 1136 printf("%s: unable to allocate FIFO memory block, err = %d\n", 1137 self->dv_xname, err); 1138 return; 1139 } 1140 1141 err = bus_dmamem_map(va->va_dmat, &seg, rseg, LCG_FIFO_SIZE, 1142 &fifo_mem_vaddr, BUS_DMA_NOWAIT); 1143 if (err) { 1144 printf("%s: unable to map FIFO memory block, err = %d\n", 1145 self->dv_xname, err); 1146 bus_dmamem_free(va->va_dmat, &seg, rseg); 1147 return; 1148 } 1149 1150 err = bus_dmamap_create(va->va_dmat, LCG_FIFO_SIZE, rseg, 1151 LCG_FIFO_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dm); 1152 if (err) { 1153 printf("%s: unable to create DMA map, err = %d\n", self->dv_xname, err); 1154 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1155 bus_dmamem_free(va->va_dmat, &seg, rseg); 1156 return; 1157 } 1158 1159 err = bus_dmamap_load(va->va_dmat, sc->sc_dm, fifo_mem_vaddr, 1160 LCG_FIFO_SIZE, NULL, BUS_DMA_NOWAIT); 1161 if (err) { 1162 printf("%s: unable to load DMA map, err = %d\n", self->dv_xname, err); 1163 bus_dmamap_destroy(va->va_dmat, sc->sc_dm); 1164 bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE); 1165 bus_dmamem_free(va->va_dmat, &seg, rseg); 1166 return; 1167 } 1168 1169 /* initialize LCG hardware */ 1170 LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0xd8000000; /* gfx reset, FIFO and AG enable */ 1171 // LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = (((LCG_FB_ADDR + lcg_fb_size) & 0xffff0000) | (LCG_FB_ADDR >> 16)); 1172 LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = 0xffff0000; 1173 LCG_REG(LCG_REG_FIFO_BASE) = sc->sc_dm->dm_segs[0].ds_addr; 1174 LCG_REG(LCG_REG_FIFO_BASE2) = sc->sc_dm->dm_segs[0].ds_addr; 1175 LCG_REG(LCG_REG_FIFO_MASKS) = 0xffff; 1176 LCG_REG(LCG_REG_FIFO_SAVE_HEAD_OFFSET) = sc->sc_dm->dm_segs[0].ds_addr; 1177 // LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0; 1178 // LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0x50000000; /* FIFO and AG enable */ 1179 LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0xffffffff; 1180 LCG_REG(LCG_REG_GRAPHICS_INT_SET_ENABLE) = 0; 1181 LCG_REG(LCG_REG_GRAPHICS_INT_CLR_ENABLE) = 0xffffffff; 1182 LCG_REG(LCG_REG_LCG_GO) = 3; /* FIFO and AG go */ 1183 // LCG_REG(LCG_REG_BREAKPT_ADDRESS) = 0x2fffffff; 1184 1185 } else { 1186 lcgaddr = (void *)virtual_avail; 1187 virtual_avail += lcg_fb_size + LCG_FONT_STORAGE_SIZE; 1188 ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG)); 1189 1190 lutaddr = (void *)virtual_avail; 1191 virtual_avail += LCG_LUT_SIZE; 1192 ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG)); 1193 1194 fifoaddr = (long*)virtual_avail; 1195 virtual_avail += LCG_FIFO_WIN_SIZE; 1196 ioaccess((vaddr_t)fifoaddr, LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG)); 1197 } 1198 1199 bzero(lutaddr, LCG_LUT_SIZE); 1200 for (i = 0; i < 8; ++i) { 1201 lcg_cmap.r[i] = lcg_default_cmap.r[i]; 1202 lcg_cmap.g[i] = lcg_default_cmap.g[i]; 1203 lcg_cmap.b[i] = lcg_default_cmap.b[i]; 1204 lutaddr[i * 8 + 1] = i; 1205 lutaddr[i * 8 + 2] = 1; 1206 lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7); 1207 lutaddr[i * 8 + 4] = 1; 1208 lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7); 1209 lutaddr[i * 8 + 6] = 1; 1210 lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7); 1211 } 1212 1213 /* 1214 * 0xf100165b 4000/60 1215 * 1111 0001 0000 0000 0001 0110 0101 1011 1216 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1217 * 3322 2222 2222 1111 1111 11 1218 * 1098 7654 3210 9876 5432 1098 7654 3210 1219 * 1220 * 0xf1001d7b 4000/VLC 1221 * 1111 0001 0000 0000 0001 1101 0111 1011 1222 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv 1223 * 3322 2222 2222 1111 1111 11 1224 * 1098 7654 3210 9876 5432 1098 7654 3210 1225 * 1226 * 31-30 11 Vertical state 1227 * 29-38 11 Horizontal state 1228 * 27-26 00 1229 * 25 0 console LUT select 1230 * 24 1 control LUT select 1231 * 23 0 1232 * 22 0 cursor active 1233 * 21-16 000000 1234 * 15 0 video subsystem reset 1235 * 14 0 1236 * 13 0 LUT load size 2KB 1237 * 12 1 enable H sync 1238 * 11 0 Full LUT load 1 1239 * 10 1 video clock select 1240 * 9- 8 10 memory refresh rate 01 1241 * 7- 6 01 video refresh rate 1242 * 5 0 load select 1 1243 * 4 1 read cursor output 1244 * 3 1 LUT load enable 1245 * 2 0 cursor enable 1246 * 1 1 video enable 1247 * 0 1 refresh clock enable 1248 */ 1249 /* prepare video_config reg for LUT relaod */ 1250 video_conf 1251 = (3 << 30) /* vertical state */ 1252 | (3 << 28) /* horizontal state */ 1253 | (0 << 26) /* unused */ 1254 | (0 << 25) /* console LUT select */ 1255 | (0 << 24) /* control LUT select */ 1256 | (0 << 23) /* unused */ 1257 | (0 << 22) /* cursor active */ 1258 | (0 << 16) /* current cursor scanline showing */ 1259 | (0 << 15) /* video subsystem reset */ 1260 | (0 << 14) /* unused */ 1261 | (1 << 13) /* LUT load size 2 KB */ 1262 | (1 << 12) /* enable horizontal sync */ 1263 | (1 << 10) /* video clock select */ 1264 | (1 << 6) /* video refresh select */ 1265 | (1 << 4) /* read curosr output */ 1266 | (1 << 3) /* LUT load enable */ 1267 | (0 << 2) /* cursor enable */ 1268 | (1 << 1) /* video enable */ 1269 | (1 << 0); /* refresh clock enable */ 1270 /* FIXME needs updating for all supported models */ 1271 if (lcg_xsize == 1280) { /* 4000/60 HR 4PLN */ 1272 video_conf |= (0 << 11); /* split LUT load */ 1273 video_conf |= (2 << 8); /* memory refresh select */ 1274 video_conf |= (0 << 5); /* split shift register load */ 1275 } else { /* 4000/VLC LR 8PLN */ 1276 video_conf |= (1 << 11); /* Full LUT load */ 1277 video_conf |= (1 << 8); /* memory refresh select */ 1278 video_conf |= (1 << 5); /* split shift register load */ 1279 } 1280 1281 LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf; 1282 /* vital !!! */ 1283 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1; 1284 LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET; 1285 1286 delay(1000); 1287 LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0; 1288 1289 #ifdef LCG_DEBUG 1290 if (self != NULL) 1291 printf("%s: video config register set 0x%08lx\n", video_conf, self->dv_xname); 1292 #endif 1293 } 1294