1 /* $NetBSD: spx.c,v 1.2 2009/03/18 16:00:16 cegger Exp $ */ 2 /* 3 * SPX/LCSPX/SPXg/SPXgt accelerated framebuffer driver for NetBSD/VAX 4 * Copyright (c) 2005 Blaz Antonic 5 * All rights reserved. 6 * 7 * This software contains code written by Michael L. Hitch. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the abovementioned copyrights 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: spx.c,v 1.2 2009/03/18 16:00:16 cegger Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/device.h> 39 #include <sys/systm.h> 40 #include <sys/callout.h> 41 #include <sys/time.h> 42 #include <sys/malloc.h> 43 #include <sys/conf.h> 44 #include <sys/kernel.h> 45 46 #include <uvm/uvm.h> 47 48 #include <machine/vsbus.h> 49 #include <machine/sid.h> 50 #include <machine/cpu.h> 51 #include <machine/ka420.h> 52 53 #include <dev/cons.h> 54 55 #include <dev/dec/dzreg.h> 56 #include <dev/dec/dzvar.h> 57 #include <dev/dec/dzkbdvar.h> 58 59 #include <dev/wscons/wsdisplayvar.h> 60 #include <dev/wscons/wsconsio.h> 61 #include <dev/wscons/wscons_callbacks.h> 62 #include <dev/wsfont/wsfont.h> 63 64 #include "machine/scb.h" 65 66 #include "dzkbd.h" 67 68 #define CONF_LCSPX 0x02 69 #define CONF_SPXg 0x10 70 71 #define FB_IS_SPX 1 72 #define FB_IS_SPXg 2 73 74 /* Screen hardware defs */ 75 #define SPX_FB_ADDR 0x38000000 /* Frame buffer */ 76 #define SPXg_FB_ADDR_KA46 0x22200000 77 #define SPXg_FB_ADDR_KA49 0x28200000 78 #define SPXg_FB_ADDR ((vax_boardtype == VAX_BTYP_46) ? \ 79 SPXg_FB_ADDR_KA46 : SPXg_FB_ADDR_KA49) 80 81 #define SPXg_WIN_SIZE 0x00100000 /* Window size */ 82 /* # of pixels that fit into single window */ 83 #define SPXg_WIN_LINEAR (SPXg_WIN_SIZE / 2) 84 85 #define SPXg_DELAY 5 86 87 /* 88 * off-screen font storage space 89 * 32x16 glyphs, 256 regular and underliend chars 90 */ 91 #define FONT_STORAGE_START (spx_xsize * spx_ysize) 92 #define FONT_STORAGE_SIZE (32 * 16 * 256 * 2) 93 94 /* register space defines */ 95 #define SPX_REG_SIZE 0x00002000 96 #define SPX_REG_ADDR 0x39302000 /* 1st set of SPX registers */ 97 98 #define SPXg_REG_SIZE 0x00004000 99 #define SPXg_REG_ADDR_KA46 0x22004000 100 #define SPXg_REG_ADDR_KA49 0x28004000 101 #define SPXg_REG_ADDR ((vax_boardtype == VAX_BTYP_46) ? \ 102 SPXg_REG_ADDR_KA46 : SPXg_REG_ADDR_KA49) 103 104 #define SPX_REG1_SIZE 0x00001000 105 #define SPX_REG1_ADDR 0x39b00000 /* 2nd set of SPX registers */ 106 107 #define SPXg_REG1_SIZE 0x00001000 108 #define SPXg_REG1_ADDR_KA46 0x22100000 109 #define SPXg_REG1_ADDR_KA49 0x28100000 110 #define SPXg_REG1_ADDR ((vax_boardtype == VAX_BTYP_46) ? \ 111 SPXg_REG1_ADDR_KA46 : SPXg_REG1_ADDR_KA49) 112 #define SPX_REG(reg) regaddr[(reg - 0x2000) / 4] 113 #define SPXg_REG(reg) regaddr[(reg - 0x2000) / 2] 114 115 #define SPX_REG1(reg) regaddr1[(reg) / 4] 116 #define SPXg_REG1(reg) regaddr1[(reg) / 4] 117 118 /* few SPX register names */ 119 #define SPX_COMMAND 0x21ec 120 #define SPX_XSTART 0x21d0 121 #define SPX_YSTART 0x21d4 122 #define SPX_XEND 0x21d8 123 #define SPX_YEND 0x21dc 124 #define SPX_DSTPIX 0x21e0 125 #define SPX_DSTPIX1 0x20e0 126 #define SPX_SRCPIX 0x21e4 127 #define SPX_SRCPIX1 0x20e4 128 #define SPX_MAIN3 0x219c 129 #define SPX_STRIDE 0x21e8 /* SRC | DST */ 130 #define SPX_SRCMASK 0x21f0 131 #define SPX_DSTMASK 0x21f4 132 #define SPX_FG 0x2260 133 #define SPX_BG 0x2264 134 #define SPX_DESTLOOP 0x2270 135 #define SPX_MPC 0x21fc 136 137 /* few SPX opcodes (microcode entry points); rasterop # = opcode ? */ 138 #define SPX_OP_FILLRECT 0x19 139 #define SPX_OP_COPYRECT 0x1a 140 141 /* bt459 locations */ 142 #define SPX_BT459_ADDRL 0x39b10000 143 #define SPX_BT459_ADDRH 0x39b14000 144 #define SPX_BT459_REG 0x39b18000 145 #define SPX_BT459_CMAP 0x39b1c000 146 147 /* bt460 locations */ 148 #define SPXg_BT460_BASE_KA46 0x200f0000 149 #define SPXg_BT460_BASE_KA49 0x2a000000 150 #define SPXg_BT460_BASE ((vax_boardtype == VAX_BTYP_46) ? \ 151 SPXg_BT460_BASE_KA46 : SPXg_BT460_BASE_KA49) 152 153 #define SPX_BG_COLOR WS_DEFAULT_BG 154 #define SPX_FG_COLOR WS_DEFAULT_FG 155 156 /* 157 * cursor X = 0, Y = 0 on-screen bias 158 * FIXME: BIAS for various HW types 159 */ 160 #define CUR_XBIAS 360 161 #define CUR_YBIAS 37 162 163 /* few BT459 & BT460 indirect register defines */ 164 #define SPXDAC_REG_CCOLOR_1 0x181 165 #define SPXDAC_REG_CCOLOR_2 0x182 166 #define SPXDAC_REG_CCOLOR_3 0x183 167 #define SPXDAC_REG_ID 0x200 168 #define SPXDAC_REG_CMD0 0x201 169 #define SPXDAC_REG_CMD1 0x202 170 #define SPXDAC_REG_CMD2 0x203 171 #define SPXDAC_REG_PRM 0x204 172 #define SPXDAC_REG_CCR 0x300 173 #define SPXDAC_REG_CXLO 0x301 174 #define SPXDAC_REG_CXHI 0x302 175 #define SPXDAC_REG_CYLO 0x303 176 #define SPXDAC_REG_CYHI 0x304 177 #define SPXDAC_REG_WXLO 0x305 178 #define SPXDAC_REG_WXHI 0x306 179 #define SPXDAC_REG_WYLO 0x307 180 #define SPXDAC_REG_WYHI 0x308 181 #define SPXDAC_REG_WWLO 0x309 182 #define SPXDAC_REG_WWHI 0x30a 183 #define SPXDAC_REG_WHLO 0x30b 184 #define SPXDAC_REG_WHHI 0x30c 185 #define SPXDAC_REG_CRAM_BASE 0x400 186 187 /* 188 * used to access top/bottom 8 bits of a 16-bit argument for split RAMDAC 189 * addressing 190 */ 191 #define HI(x) (((x) >> 8) & 0xff) 192 #define LO(x) ((x) & 0xff) 193 194 static int spx_match(device_t, cfdata_t, void *); 195 static void spx_attach(device_t, device_t, void *); 196 197 struct spx_softc { 198 device_t ss_dev; 199 }; 200 201 CFATTACH_DECL_NEW(spx, sizeof(struct spx_softc), 202 spx_match, spx_attach, NULL, NULL); 203 204 static void spx_cursor(void *, int, int, int); 205 static int spx_mapchar(void *, int, unsigned int *); 206 static void spx_putchar(void *, int, int, u_int, long); 207 static void spx_copycols(void *, int, int, int,int); 208 static void spx_erasecols(void *, int, int, int, long); 209 static void spx_copyrows(void *, int, int, int); 210 static void spx_eraserows(void *, int, int, long); 211 static int spx_allocattr(void *, int, int, int, long *); 212 static int spx_get_cmap(struct wsdisplay_cmap *); 213 static int spx_set_cmap(struct wsdisplay_cmap *); 214 215 static int spx_map_regs(device_t, u_int, u_int, u_int, u_int); 216 static void SPX_render_font(void); 217 static void SPXg_render_font(void); 218 static int SPX_map_fb(device_t, struct vsbus_attach_args *); 219 static int SPXg_map_fb(device_t, struct vsbus_attach_args *); 220 static void spx_init_common(device_t, struct vsbus_attach_args *); 221 222 #define SPX_MAP_FB(self, va, type) if (! type ## _map_fb(self, va)) return 223 #define SPX_MAP_REGS(self, type) if (!spx_map_regs(self, \ 224 type ## _REG_ADDR, \ 225 type ## _REG_SIZE, \ 226 type ## _REG1_ADDR, \ 227 type ## _REG1_SIZE)) \ 228 return 229 230 const struct wsdisplay_emulops spx_emulops = { 231 spx_cursor, 232 spx_mapchar, 233 spx_putchar, 234 spx_copycols, 235 spx_erasecols, 236 spx_copyrows, 237 spx_eraserows, 238 spx_allocattr 239 }; 240 241 static char spx_stdscreen_name[10] = "160x128"; 242 struct wsscreen_descr spx_stdscreen = { 243 spx_stdscreen_name, 160, 128, /* dynamically set */ 244 &spx_emulops, 245 8, 15, /* dynamically set */ 246 WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS, 247 }; 248 249 const struct wsscreen_descr *_spx_scrlist[] = { 250 &spx_stdscreen, 251 }; 252 253 const struct wsscreen_list spx_screenlist = { 254 sizeof(_spx_scrlist) / sizeof(struct wsscreen_descr *), 255 _spx_scrlist, 256 }; 257 258 static volatile char *spxaddr; 259 static volatile long *regaddr; 260 static volatile long *regaddr1; 261 262 static volatile char *bt_addrl; 263 static volatile char *bt_addrh; 264 static volatile char *bt_reg; 265 static volatile char *bt_cmap; 266 static volatile char *bt_wait; /* SPXg/gt only */ 267 268 static int spx_xsize; 269 static int spx_ysize; 270 static int spx_depth; 271 static int spx_cols; 272 static int spx_rows; 273 static long spx_fb_size; 274 275 /* Our current hardware colormap */ 276 static struct hwcmap256 { 277 #define CMAP_SIZE 256 /* 256 R/G/B entries */ 278 u_int8_t r[CMAP_SIZE]; 279 u_int8_t g[CMAP_SIZE]; 280 u_int8_t b[CMAP_SIZE]; 281 } spx_cmap; 282 283 /* The default colormap */ 284 static struct { 285 u_int8_t r[8]; 286 u_int8_t g[8]; 287 u_int8_t b[8]; 288 } spx_default_cmap = { 289 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, 290 { 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff }, 291 { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } 292 }; 293 294 static char fb_type = 0; 295 static char spxg_current_page = 0; 296 #define spxg_switch_page(nr) (SPXg_REG1(0x20) = ((1 << (nr) & 0xff)) << 16) 297 298 struct wsdisplay_font spx_font; 299 static u_char *qf; 300 static u_short *qf2; 301 302 #define QCHAR_INVALID(c) (((c) < spx_font.firstchar) || \ 303 ((c) >= spx_font.firstchar + spx_font.numchars)) 304 #define QCHAR(c) (QCHAR_INVALID(c) ? 0 : (c) - spx_font.firstchar) 305 306 #define QFONT_INDEX(c, line) (QCHAR(c) * spx_font.fontheight + line) 307 #define QFONT_QF(c, line) qf[QFONT_INDEX(c, line)] 308 #define QFONT_QF2(c, line) qf2[QFONT_INDEX(c, line)] 309 #define QFONT(c, line) (spx_font.stride == 2 ? \ 310 QFONT_QF2(c, line) : \ 311 QFONT_QF(c, line)) 312 313 /* replicate color value */ 314 #define COLOR(x) (((x) << 24) | ((x) << 16) | ((x) << 8) | (x)) 315 316 /* convert coordinates into linear offset */ 317 #define LINEAR(x, y) ((y * spx_xsize) + x) 318 319 /* Linear pixel address */ 320 #define SPX_POS(row, col, line, dot) \ 321 ((col) * spx_font.fontwidth + \ 322 (row) * spx_font.fontheight * spx_xsize + \ 323 (line) * spx_xsize + dot) 324 325 #define SPX_ADDR(row, col, line, dot) spxaddr[SPX_POS(row, col, line, dot)] 326 327 /* Recalculate absolute pixel address from linear address */ 328 #define SPXg_ADDR(linear) spxaddr[((((linear) % SPXg_WIN_LINEAR) / 4) * 8) + \ 329 (((linear) % SPXg_WIN_LINEAR) % 4)] 330 331 332 static int spx_ioctl(void *, void *, u_long, void *, int, struct lwp *); 333 static paddr_t spx_mmap(void *, void *, off_t, int); 334 static int spx_alloc_screen(void *, const struct wsscreen_descr *, 335 void **, int *, int *, long *); 336 static void spx_free_screen(void *, void *); 337 static int spx_show_screen(void *, void *, int, void (*) (void *, int, int), 338 void *); 339 340 static void spx_update_cmap(int entry, char red, char green, char blue); 341 static void set_btreg(u_int addr, u_char value); 342 static u_char get_btreg(u_int addr); 343 344 /* SPXg/gt delay */ 345 static void spxg_delay(void); 346 347 /* 348 * SPX HW accelerated block copy 349 * common code in spx_blkcpy, 350 * HW-specific code accessed through spx_blkcpy_func pointer 351 */ 352 static void spx_blkcpy(u_int sxpos, u_int sypos, 353 u_int dxpos, u_int dypos, 354 u_int xdim, u_int ydim); 355 356 static void SPX_blkcpy(u_int sxpos, u_int sypos, 357 u_int dxpos, u_int dypos, 358 u_int xdim, u_int ydim, 359 char direction); 360 static void SPXg_blkcpy(u_int sxpos, u_int sypos, 361 u_int dxpos, u_int dypos, 362 u_int xdim, u_int ydim, 363 char direction); 364 static void (*spx_blkcpy_func)(u_int, u_int, 365 u_int, u_int, 366 u_int, u_int, 367 char); 368 369 /* SPX HW accelerated block set, no common code */ 370 static void SPX_blkset(u_int xpos, u_int ypos, 371 u_int xdim, u_int ydim, char color); 372 static void SPXg_blkset(u_int xpos, u_int ypos, 373 u_int xdim, u_int ydim, char color); 374 static void (*spx_blkset_func)(u_int, u_int, u_int, u_int, char); 375 #define spx_blkset(x, y, xd, yd, c) spx_blkset_func(x, y, xd, yd, c) 376 377 /* SPX HW accelerated part of spx_putchar */ 378 static void SPX_putchar(int, int, u_int, char, char); 379 static void SPXg_putchar(int, int, u_int, char, char); 380 static void (*spx_putchar_func)(int, int, u_int, char, char); 381 382 const struct wsdisplay_accessops spx_accessops = { 383 spx_ioctl, 384 spx_mmap, 385 spx_alloc_screen, 386 spx_free_screen, 387 spx_show_screen, 388 0 /* load_font */ 389 }; 390 391 /* TODO allocate ss_image dynamically for consoles beyond first one */ 392 struct spx_screen { 393 int ss_curx; 394 int ss_cury; 395 int ss_cur_fg; 396 int ss_cur_bg; 397 struct { 398 u_char data; /* Image character */ 399 u_char attr; /* Attribute: 80/70/08/07 */ 400 } ss_image[160 * 128]; /* allow for maximum possible cell matrix */ 401 }; 402 403 #define SPX_ATTR_UNDERLINE 0x80 404 #define SPX_BG_MASK 0x70 405 #define SPX_ATTR_REVERSE 0x08 406 #define SPX_FG_MASK 0x07 407 408 static struct spx_screen spx_conscreen; 409 static struct spx_screen *prevscr, *curscr; 410 static struct spx_screen *savescr; 411 412 static int cur_fg, cur_bg; 413 static int spx_off = 1; 414 415 static void 416 spx_update_cmap(int entry, char red, char green, char blue) 417 { 418 *bt_addrl = LO(entry); 419 *bt_addrh = HI(entry); 420 if ((entry >= 0x181) && (entry <= 0x183)) { 421 *bt_reg = red; 422 *bt_reg = green; 423 *bt_reg = blue; 424 } else { 425 *bt_cmap = red; 426 *bt_cmap = green; 427 *bt_cmap = blue; 428 } 429 } 430 431 static void 432 set_btreg(u_int addr, u_char value) 433 { 434 *bt_addrl = LO(addr); 435 *bt_addrh = HI(addr); 436 *bt_reg = value; 437 } 438 439 static u_char 440 get_btreg(u_int addr) 441 { 442 *bt_addrl = LO(addr); 443 *bt_addrh = HI(addr); 444 return *bt_reg & 0xff; 445 } 446 447 static void 448 spxg_delay(void) 449 { 450 char i; 451 452 for (i = 0; i <= SPXg_DELAY; i++) 453 *bt_wait = *bt_wait + i; 454 } 455 456 static void 457 SPX_blkcpy(u_int sxpos, u_int sypos, 458 u_int dxpos, u_int dypos, 459 u_int xdim, u_int ydim, 460 char direction) 461 { 462 u_int counter = 0xffffe; 463 long temp = 0; 464 465 SPX_REG(SPX_COMMAND) = 0x84884648 | direction; /* 0x848c4648? */ 466 SPX_REG(SPX_XSTART) = dxpos << 16; 467 SPX_REG(SPX_YSTART) = dypos << 16; 468 SPX_REG(SPX_XEND) = (dxpos + xdim) << 16; 469 SPX_REG(SPX_YEND) = (dypos + ydim) << 16; 470 471 temp = ((SPX_REG1(0x10) & 0xc0) << (30 - 6)) | \ 472 ((SPX_REG1(0x10) & 0x3f) << 24); 473 474 SPX_REG(SPX_DSTPIX) = temp + LINEAR(dxpos, dypos); 475 SPX_REG(SPX_SRCPIX) = temp + LINEAR(sxpos, sypos); 476 SPX_REG(SPX_SRCPIX1) = 0; 477 SPX_REG(SPX_STRIDE) = (spx_xsize << 16) | spx_xsize; 478 SPX_REG(SPX_SRCMASK) = 0xff; 479 SPX_REG(SPX_DSTMASK) = 0xff; 480 481 SPX_REG(SPX_DESTLOOP) = 0x00112003; 482 SPX_REG(SPX_MPC) = 0x2000 | SPX_OP_COPYRECT; 483 484 SPX_REG1(0x18) = 0xffffffff; 485 while ((counter) && ((SPX_REG1(0x18) & 2) == 0)) 486 counter--; 487 } 488 489 static void 490 SPXg_blkcpy(u_int sxpos, u_int sypos, 491 u_int dxpos, u_int dypos, 492 u_int xdim, u_int ydim, 493 char direction) 494 { 495 u_int counter = 0xffffe; 496 long temp = 0; 497 498 SPXg_REG(SPX_COMMAND) = 0x84884648 | direction; spxg_delay(); 499 SPXg_REG(SPX_XSTART) = dxpos << 16; spxg_delay(); 500 SPXg_REG(SPX_YSTART) = dypos << 16; spxg_delay(); 501 SPXg_REG(SPX_XEND) = (dxpos + xdim) << 16; spxg_delay(); 502 SPXg_REG(SPX_YEND) = (dypos + ydim) << 16; spxg_delay(); 503 504 temp = 0x3f << 24; 505 506 SPXg_REG(SPX_DSTPIX) = temp + LINEAR(dxpos, dypos); spxg_delay(); 507 SPXg_REG(SPX_DSTPIX1) = 0xff000000; spxg_delay(); 508 SPXg_REG(SPX_SRCPIX) = temp + LINEAR(sxpos, sypos); spxg_delay(); 509 SPXg_REG(SPX_SRCPIX1) = 0; spxg_delay(); 510 SPXg_REG(SPX_STRIDE) = (spx_xsize << 16) | spx_xsize; spxg_delay(); 511 SPXg_REG(SPX_SRCMASK) = 0xffffffff; spxg_delay(); 512 SPXg_REG(SPX_DSTMASK) = 0xffffffff; spxg_delay(); 513 514 SPXg_REG(SPX_DESTLOOP) = 0x00112003; spxg_delay(); 515 SPXg_REG(SPX_MPC) = 0x2000 | SPX_OP_COPYRECT; spxg_delay(); 516 517 while ((counter) && ((SPXg_REG1(0x0) & 0x8000) == 0)) 518 counter--; 519 } 520 521 static void 522 spx_blkcpy(u_int sxpos, u_int sypos, 523 u_int dxpos, u_int dypos, 524 u_int xdim, u_int ydim) 525 { 526 char direction = 0; 527 528 /* don't waste time checking whether src and dest actually overlap */ 529 if (sxpos < dxpos) { 530 direction |= 0x01; /* X decrement */ 531 sxpos += xdim; 532 dxpos += xdim; 533 xdim = -xdim; 534 } 535 if (sypos < dypos) { 536 direction |= 0x02; /* Y decrement */ 537 sypos += ydim; 538 dypos += ydim; 539 ydim = -ydim; 540 } 541 542 spx_blkcpy_func(sxpos, sypos, dxpos, dypos, xdim, ydim, direction); 543 } 544 545 static void 546 SPX_blkset(u_int xpos, u_int ypos, u_int xdim, u_int ydim, char color) 547 { 548 u_int counter = 0xfffe; 549 long temp = 0; 550 551 SPX_REG(SPX_COMMAND) = 0x84884608; 552 SPX_REG(SPX_XSTART) = xpos << 16; 553 SPX_REG(SPX_YSTART) = ypos << 16; 554 SPX_REG(SPX_XEND) = (xpos + xdim) << 16; 555 SPX_REG(SPX_YEND) = (ypos + ydim) << 16; 556 SPX_REG(SPX_STRIDE) = (spx_xsize << 16) | spx_xsize; 557 SPX_REG(SPX_DESTLOOP) = 0x20102003; 558 559 temp = ((SPX_REG1(0x10) & 0xc0) << (30 - 6)) | 560 ((SPX_REG1(0x10) & 0x3f) << 24); 561 SPX_REG(SPX_DSTPIX) = temp + LINEAR(xpos, ypos); 562 563 SPX_REG(SPX_FG) = COLOR(color); 564 565 SPX_REG(SPX_MPC) = 0x2000 | SPX_OP_FILLRECT; 566 567 SPX_REG1(0x18) = 0xffffffff; 568 while ((counter) && ((SPX_REG1(0x18) & 2) == 0)) 569 counter--; 570 } 571 572 static void 573 SPXg_blkset(u_int xpos, u_int ypos, u_int xdim, u_int ydim, char color) 574 { 575 u_int counter = 0xfffe; 576 long temp = 0; 577 578 SPXg_REG(SPX_COMMAND) = 0x84884608; spxg_delay(); 579 SPXg_REG(SPX_XSTART) = xpos << 16; spxg_delay(); 580 SPXg_REG(SPX_YSTART) = ypos << 16; spxg_delay(); 581 SPXg_REG(SPX_XEND) = (xpos + xdim) << 16; spxg_delay(); 582 SPXg_REG(SPX_YEND) = (ypos + ydim) << 16; spxg_delay(); 583 SPXg_REG(SPX_STRIDE) = (spx_xsize << 16) | spx_xsize; spxg_delay(); 584 585 temp = 0x3f << 24; 586 SPXg_REG(SPX_DSTPIX) = temp + LINEAR(xpos, ypos); spxg_delay(); 587 SPXg_REG(SPX_DSTPIX1) = 0xff000000; spxg_delay(); 588 589 SPXg_REG(SPX_FG) = COLOR(color); spxg_delay(); 590 591 SPXg_REG(SPX_DESTLOOP) = 0x20102003; spxg_delay(); 592 SPXg_REG(SPX_MPC) = 0x2000 | SPX_OP_FILLRECT; spxg_delay(); 593 594 while ((counter) && ((SPXg_REG1(0x0) & 0x8000) == 0)) 595 counter--; 596 } 597 598 int spx_match(device_t parent, cfdata_t match, void *aux) 599 { 600 struct vsbus_softc *sc = device_private(parent); 601 #if 0 602 struct vsbus_attach_args *va = aux; 603 char *ch = (char *)va->va_addr; 604 #endif 605 606 /* 607 * FIXME: 608 * add KA46 when/if ever somebody reports SPXg vax_confdata ID on VS 4000/60 609 * Ditto for SPX ID on KA42 & KA43 610 */ 611 if (vax_boardtype != VAX_BTYP_49) 612 return 0; 613 614 /* KA49: Identify framebuffer type */ 615 switch (vax_confdata & (CONF_LCSPX | CONF_SPXg)) { 616 case CONF_LCSPX: 617 fb_type = FB_IS_SPX; 618 spx_blkcpy_func = SPX_blkcpy; 619 spx_blkset_func = SPX_blkset; 620 spx_putchar_func = SPX_putchar; 621 break; 622 case CONF_SPXg: 623 fb_type = FB_IS_SPXg; 624 spx_blkcpy_func = SPXg_blkcpy; 625 spx_blkset_func = SPXg_blkset; 626 spx_putchar_func = SPXg_putchar; 627 break; 628 case 0: 629 aprint_error("spx_match: no framebuffer found\n"); 630 break; 631 case CONF_LCSPX | CONF_SPXg: 632 panic("spx_match: incorrect FB configuration\n"); 633 break; 634 } 635 636 /* FIXME add RAMDAC ID code ??? */ 637 #if 0 638 /* 639 * FIXME: 640 * are memory addresses besides va->va_addr off limits at this time ? 641 * RAMDAC ID register test, should read 0x4a for LCSPX, 0x4b for SPXg 642 */ 643 if (get_btreg(SPXDAC_REG_ID) != 0x4a) 644 return 0; 645 #endif 646 647 sc->sc_mask = 0x04; /* XXX - should be generated */ 648 scb_fake(0x14c, 0x15); 649 650 return 20; 651 } 652 653 static void 654 spx_attach(device_t parent, device_t self, void *aux) 655 { 656 struct spx_softc *sc = device_private(self); 657 struct vsbus_attach_args *va = aux; 658 struct wsemuldisplaydev_attach_args aa; 659 660 sc->ss_dev = self; 661 662 aprint_normal("\n"); 663 aa.console = spxaddr != NULL; 664 665 spx_init_common(self, va); 666 667 curscr = &spx_conscreen; 668 prevscr = curscr; 669 670 aa.scrdata = &spx_screenlist; 671 aa.accessops = &spx_accessops; 672 673 /* enable cursor */ 674 set_btreg(SPXDAC_REG_CCR, 0xc1); 675 676 config_found(self, &aa, wsemuldisplaydevprint); 677 } 678 679 static int cur_on; 680 681 static void 682 spx_cursor(void *id, int on, int row, int col) 683 { 684 struct spx_screen *ss = id; 685 int attr, data; 686 687 attr = ss->ss_image[row * spx_cols + col].attr; 688 data = ss->ss_image[row * spx_cols + col].data; 689 690 if (attr & SPX_ATTR_REVERSE) { 691 cur_bg = attr & SPX_FG_MASK; 692 cur_fg = (attr & SPX_BG_MASK) >> 4; 693 } else { 694 cur_fg = attr & SPX_FG_MASK; 695 cur_bg = (attr & SPX_BG_MASK) >> 4; 696 } 697 698 if (ss == curscr) { 699 #ifdef SOFTCURSOR 700 if ((cur_on = on)) 701 spx_putchar_func(row, col, data, cur_bg, cur_fg); 702 else 703 spx_putchar_func(row, col, data, cur_fg, cur_bg); 704 #else 705 /* change cursor foreground color colormap entry */ 706 spx_update_cmap(SPXDAC_REG_CCOLOR_3, 707 spx_cmap.r[cur_fg], 708 spx_cmap.g[cur_fg], 709 spx_cmap.b[cur_fg]); 710 711 /* update cursor position registers */ 712 set_btreg(SPXDAC_REG_CXLO, 713 LO(col * spx_font.fontwidth + CUR_XBIAS)); 714 set_btreg(SPXDAC_REG_CXHI, 715 HI(col * spx_font.fontwidth + CUR_XBIAS)); 716 set_btreg(SPXDAC_REG_CYLO, 717 LO(row * spx_font.fontheight + CUR_YBIAS)); 718 set_btreg(SPXDAC_REG_CYHI, 719 HI(row * spx_font.fontheight + CUR_YBIAS)); 720 721 if ((cur_on = on)) 722 /* enable cursor */ 723 set_btreg(SPXDAC_REG_CCR, 0xc1); 724 else 725 /* disable cursor */ 726 set_btreg(SPXDAC_REG_CCR, 0x01); 727 #endif 728 } 729 730 ss->ss_curx = col; 731 ss->ss_cury = row; 732 ss->ss_cur_bg = cur_bg; 733 ss->ss_cur_fg = cur_fg; 734 } 735 736 static int 737 spx_mapchar(void *id, int uni, unsigned int *index) 738 { 739 if (uni < 256) { 740 *index = uni; 741 return (5); 742 } 743 *index = ' '; 744 return (0); 745 } 746 747 static void 748 SPX_putchar(int row, int col, u_int c, char dot_fg, char dot_bg) 749 { 750 u_int counter = 0xffffe; 751 long temp = 0; 752 753 SPX_REG(SPX_FG) = COLOR(dot_fg); 754 SPX_REG(SPX_BG) = COLOR(dot_bg); 755 SPX_REG(SPX_MAIN3) = 0x01010101; 756 SPX_REG(SPX_COMMAND) = 0x84884648; 757 SPX_REG(SPX_XSTART) = (col * spx_font.fontwidth) << 16; 758 SPX_REG(SPX_YSTART) = (row * spx_font.fontheight) << 16; 759 SPX_REG(SPX_XEND) = ((col + 1) * spx_font.fontwidth) << 16; 760 SPX_REG(SPX_YEND) = ((row + 1) * spx_font.fontheight) << 16; 761 762 temp = ((SPX_REG1(0x10) & 0xc0) << (30 - 6)) | \ 763 ((SPX_REG1(0x10) & 0x3f) << 24); 764 765 SPX_REG(SPX_DSTPIX) = temp + LINEAR(col * spx_font.fontwidth, 766 row * spx_font.fontheight); 767 SPX_REG(SPX_SRCPIX) = temp + FONT_STORAGE_START 768 + (c * spx_font.fontheight * spx_font.fontwidth); 769 SPX_REG(SPX_SRCPIX1) = 0; 770 SPX_REG(SPX_STRIDE) = (spx_font.fontwidth << 16) | spx_xsize; 771 SPX_REG(SPX_SRCMASK) = 0xff; 772 SPX_REG(SPX_DSTMASK) = 0xff; 773 774 SPX_REG(SPX_DESTLOOP) = 0x20142003; 775 SPX_REG(SPX_MPC) = 0x2000 | SPX_OP_COPYRECT; 776 777 SPX_REG1(0x18) = 0xffffffff; 778 779 while ((counter) && ((SPX_REG1(0x18) & 2) == 0)) 780 counter--; 781 } 782 783 static void 784 SPXg_putchar(int row, int col, u_int c, char dot_fg, char dot_bg) 785 { 786 u_int counter = 0xffffe; 787 long temp = 0; 788 789 SPXg_REG(SPX_FG) = COLOR(dot_fg); 790 spxg_delay(); 791 SPXg_REG(SPX_BG) = COLOR(dot_bg); 792 spxg_delay(); 793 SPXg_REG(SPX_MAIN3) = 0x01010101; 794 spxg_delay(); 795 SPXg_REG(SPX_COMMAND) = 0x84884648; 796 spxg_delay(); 797 SPXg_REG(SPX_XSTART) = (col * spx_font.fontwidth) << 16; 798 spxg_delay(); 799 SPXg_REG(SPX_YSTART) = (row * spx_font.fontheight) << 16; 800 spxg_delay(); 801 SPXg_REG(SPX_XEND) = ((col + 1) * spx_font.fontwidth) << 16; 802 spxg_delay(); 803 SPXg_REG(SPX_YEND) = ((row + 1) * spx_font.fontheight) << 16; 804 spxg_delay(); 805 806 temp = 0x3f << 24; 807 808 SPXg_REG(SPX_DSTPIX) = temp + LINEAR(col * spx_font.fontwidth, 809 row * spx_font.fontheight); 810 spxg_delay(); 811 SPXg_REG(SPX_DSTPIX1) = 0xff000000; 812 spxg_delay(); 813 SPXg_REG(SPX_SRCPIX) = temp + FONT_STORAGE_START + 814 (c * spx_font.fontheight * spx_font.fontwidth); 815 spxg_delay(); 816 SPXg_REG(SPX_SRCPIX1) = 0; 817 spxg_delay(); 818 SPXg_REG(SPX_STRIDE) = (spx_font.fontwidth << 16) | spx_xsize; 819 spxg_delay(); 820 SPXg_REG(SPX_SRCMASK) = 0xffffffff; 821 spxg_delay(); 822 SPXg_REG(SPX_DSTMASK) = 0xffffffff; 823 spxg_delay(); 824 825 SPXg_REG(SPX_DESTLOOP) = 0x20142003; 826 spxg_delay(); 827 SPXg_REG(SPX_MPC) = 0x2000 | SPX_OP_COPYRECT; 828 spxg_delay(); 829 830 while ((counter) && ((SPXg_REG1(0x0) & 0x8000) == 0)) 831 counter--; 832 } 833 834 static void 835 spx_putchar(void *id, int row, int col, u_int c, long attr) 836 { 837 struct spx_screen *ss = id; 838 char dot_fg, dot_bg; 839 840 c &= 0xff; 841 842 ss->ss_image[row * spx_cols + col].data = c; 843 ss->ss_image[row * spx_cols + col].attr = attr; 844 if (ss != curscr) 845 return; 846 847 dot_fg = attr & SPX_FG_MASK; 848 dot_bg = (attr & SPX_BG_MASK) >> 4; 849 if (attr & SPX_ATTR_REVERSE) { 850 dot_fg = (attr & SPX_BG_MASK) >> 4; 851 dot_bg = attr & SPX_FG_MASK; 852 } 853 854 /* adjust glyph index for underlined text */ 855 if (attr & SPX_ATTR_UNDERLINE) 856 c += 0x100; 857 858 spx_putchar_func(row, col, c, dot_fg, dot_bg); 859 } 860 861 /* 862 * copies columns inside a row. 863 */ 864 static void 865 spx_copycols(void *id, int row, int srccol, int dstcol, int ncols) 866 { 867 struct spx_screen *ss = id; 868 869 bcopy(&ss->ss_image[row * spx_cols + srccol], 870 &ss->ss_image[row * spx_cols + dstcol], 871 ncols * sizeof(ss->ss_image[0])); 872 873 if (ss == curscr) 874 spx_blkcpy(srccol * spx_font.fontwidth, 875 row * spx_font.fontheight, 876 dstcol * spx_font.fontwidth, 877 row * spx_font.fontheight, 878 ncols * spx_font.fontwidth, 879 spx_font.fontheight); 880 } 881 882 /* 883 * Erases a bunch of chars inside one row. 884 */ 885 static void 886 spx_erasecols(void *id, int row, int startcol, int ncols, long fillattr) 887 { 888 struct spx_screen *ss = id; 889 int offset = row * spx_cols + startcol; 890 int i; 891 892 memset(&ss->ss_image[row * spx_cols + startcol], 0, 893 ncols * sizeof(ss->ss_image[0])); 894 895 for (i = offset; i < offset + ncols; ++i) 896 ss->ss_image[i].attr = fillattr; 897 898 if (ss == curscr) 899 spx_blkset(startcol * spx_font.fontwidth, 900 row * spx_font.fontheight, 901 ncols * spx_font.fontwidth, 902 spx_font.fontheight, 903 (fillattr & SPX_BG_MASK) >> 4); 904 } 905 906 static void 907 spx_copyrows(void *id, int srcrow, int dstrow, int nrows) 908 { 909 struct spx_screen *ss = id; 910 911 bcopy(&ss->ss_image[srcrow * spx_cols], 912 &ss->ss_image[dstrow * spx_cols], 913 nrows * spx_cols * sizeof(ss->ss_image[0])); 914 915 if (ss == curscr) 916 spx_blkcpy(0, (srcrow * spx_font.fontheight), 917 0, (dstrow * spx_font.fontheight), 918 spx_xsize, (nrows * spx_font.fontheight)); 919 } 920 921 static void 922 spx_eraserows(void *id, int startrow, int nrows, long fillattr) 923 { 924 struct spx_screen *ss = id; 925 int i; 926 927 memset(&ss->ss_image[startrow * spx_cols], 0, 928 nrows * spx_cols * sizeof(ss->ss_image[0])); 929 930 for (i = startrow * spx_cols; i < startrow + nrows * spx_cols; ++i) 931 ss->ss_image[i].attr = fillattr; 932 933 if (ss == curscr) 934 spx_blkset(0, (startrow * spx_font.fontheight), 935 spx_xsize, (nrows * spx_font.fontheight), 936 (fillattr & SPX_BG_MASK) >> 4); 937 } 938 939 static int 940 spx_allocattr(void *id, int fg, int bg, int flags, long *attrp) 941 { 942 long myattr; 943 944 if (flags & WSATTR_WSCOLORS) 945 myattr = (fg & SPX_FG_MASK) | ((bg << 4) & SPX_BG_MASK); 946 else 947 myattr = WSCOL_WHITE << 4; /* XXXX */ 948 if (flags & WSATTR_REVERSE) 949 myattr |= SPX_ATTR_REVERSE; 950 if (flags & WSATTR_UNDERLINE) 951 myattr |= SPX_ATTR_UNDERLINE; 952 *attrp = myattr; 953 return 0; 954 } 955 956 static int 957 spx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 958 { 959 struct wsdisplay_fbinfo *fb = data; 960 int i; 961 962 switch (cmd) { 963 case WSDISPLAYIO_GTYPE: 964 *(u_int *)data = WSDISPLAY_TYPE_SPX; 965 break; 966 967 case WSDISPLAYIO_GINFO: 968 fb->height = spx_ysize; 969 fb->width = spx_xsize; 970 fb->depth = spx_depth; 971 fb->cmsize = 1 << spx_depth; 972 break; 973 974 case WSDISPLAYIO_GETCMAP: 975 return spx_get_cmap((struct wsdisplay_cmap *)data); 976 977 case WSDISPLAYIO_PUTCMAP: 978 return spx_set_cmap((struct wsdisplay_cmap *)data); 979 980 case WSDISPLAYIO_GMODE: 981 return EPASSTHROUGH; 982 983 case WSDISPLAYIO_SMODE: 984 /* 985 * if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, 986 * current screen 987 */ 988 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 989 for (i = 0; i < 8; i++) { 990 spx_cmap.r[i] = spx_default_cmap.r[i]; 991 spx_cmap.g[i] = spx_default_cmap.g[i]; 992 spx_cmap.b[i] = spx_default_cmap.b[i]; 993 spx_update_cmap(i, spx_cmap.r[i], spx_cmap.g[i], 994 spx_cmap.b[i]); 995 } 996 if (savescr != NULL) 997 spx_show_screen(NULL, savescr, 0, NULL, NULL); 998 savescr = NULL; 999 } else { /* WSDISPLAYIO_MODE_MAPPED */ 1000 savescr = curscr; 1001 curscr = NULL; 1002 /* clear screen? */ 1003 } 1004 1005 return EPASSTHROUGH; 1006 1007 case WSDISPLAYIO_SVIDEO: 1008 if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON && spx_off) { 1009 /* Unblank video */ 1010 set_btreg(SPXDAC_REG_CMD0, 0x48); 1011 1012 /* Enable sync */ 1013 set_btreg(SPXDAC_REG_CMD2, 0xc0); 1014 1015 spx_off = 0; 1016 } else if (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF && !spx_off) { 1017 /* Blank video */ 1018 set_btreg(SPXDAC_REG_CMD0, 68); 1019 1020 /* Disable sync */ 1021 set_btreg(SPXDAC_REG_CMD2, 0x40); 1022 spx_off = 1; 1023 } 1024 break; 1025 1026 case WSDISPLAYIO_GVIDEO: 1027 *(u_int *)data = spx_off == 0 ? 1028 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 1029 break; 1030 1031 default: 1032 return EPASSTHROUGH; 1033 } 1034 return 0; 1035 } 1036 1037 /* 1038 * Bad idea on SPXg/gt due to windowed framebuffer access 1039 */ 1040 static paddr_t 1041 spx_mmap(void *v, void *vs, off_t offset, int prot) 1042 { 1043 if (fb_type != FB_IS_SPX) 1044 return -1; 1045 1046 if (offset >= spx_fb_size || offset < 0) 1047 return -1; 1048 1049 return (SPX_FB_ADDR + offset) >> PGSHIFT; 1050 } 1051 1052 static int 1053 spx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 1054 int *curxp, int *curyp, long *defattrp) 1055 { 1056 int i; 1057 struct spx_screen *ss; 1058 1059 ss = malloc(sizeof(struct spx_screen), M_DEVBUF, M_WAITOK | M_ZERO); 1060 1061 *cookiep = ss; 1062 *curxp = *curyp = 0; 1063 *defattrp = (SPX_BG_COLOR << 4) | SPX_FG_COLOR; 1064 1065 for (i = 0; i < spx_cols * spx_rows; ++i) 1066 ss->ss_image[i].attr = *defattrp; 1067 1068 return 0; 1069 } 1070 1071 static void 1072 spx_free_screen(void *v, void *cookie) 1073 { 1074 /* FIXME add something to actually free malloc()ed screen ? */ 1075 } 1076 1077 static int 1078 spx_show_screen(void *v, void *cookie, int waitok, 1079 void (*cb)(void *, int, int), void *cbarg) 1080 { 1081 struct spx_screen *ss = cookie; 1082 u_int row, col, attr; 1083 u_char c; 1084 1085 if (ss == curscr) 1086 return (0); 1087 1088 prevscr = curscr; 1089 curscr = ss; 1090 1091 for (row = 0; row < spx_rows; row++) { 1092 for (col = 0; col < spx_cols; col++) { 1093 u_int idx = row * spx_cols + col; 1094 attr = ss->ss_image[idx].attr; 1095 c = ss->ss_image[idx].data; 1096 1097 /* check if cell requires updating */ 1098 if ((c != prevscr->ss_image[idx].data) || 1099 (attr != prevscr->ss_image[idx].attr)) { 1100 if (c < 32) c = 32; 1101 spx_putchar(ss, row, col, c, attr); 1102 } 1103 } 1104 } 1105 1106 row = ss->ss_cury; col = ss->ss_curx; 1107 1108 spx_cursor(ss, cur_on, row, col); 1109 1110 cur_fg = ss->ss_cur_fg; 1111 cur_bg = ss->ss_cur_bg; 1112 1113 return (0); 1114 } 1115 1116 static int 1117 spx_get_cmap(struct wsdisplay_cmap *p) 1118 { 1119 u_int index = p->index, count = p->count; 1120 int error; 1121 1122 if (index >= (1 << spx_depth) || count > (1 << spx_depth) - index) 1123 return (EINVAL); 1124 1125 error = copyout(&spx_cmap.r[index], p->red, count); 1126 if (error) 1127 return error; 1128 1129 error = copyout(&spx_cmap.g[index], p->green, count); 1130 if (error) 1131 return error; 1132 1133 error = copyout(&spx_cmap.b[index], p->blue, count); 1134 return error; 1135 } 1136 1137 static int 1138 spx_set_cmap(struct wsdisplay_cmap *p) 1139 { 1140 u_int index = p->index, count = p->count; 1141 int error, s; 1142 1143 if (index >= (1 << spx_depth) || count > (1 << spx_depth) - index) 1144 return (EINVAL); 1145 1146 error = copyin(p->red, &spx_cmap.r[index], count); 1147 if (error) 1148 return error; 1149 1150 error = copyin(p->green, &spx_cmap.g[index], count); 1151 if (error) 1152 return error; 1153 1154 error = copyin(p->blue, &spx_cmap.b[index], count); 1155 1156 if (error) 1157 return error; 1158 1159 s = spltty(); 1160 while (count-- > 0) { 1161 spx_update_cmap(index, 1162 spx_cmap.r[index], 1163 spx_cmap.g[index], 1164 spx_cmap.b[index]); 1165 index++; 1166 } 1167 splx(s); 1168 return (0); 1169 } 1170 1171 cons_decl(spx); 1172 1173 void 1174 spxcninit(struct consdev *cndev) 1175 { 1176 int i; 1177 1178 spx_blkset(0, 0, spx_xsize, spx_ysize, SPX_BG_COLOR); 1179 1180 curscr = &spx_conscreen; 1181 1182 for (i = 0; i < spx_cols * spx_rows; i++) 1183 spx_conscreen.ss_image[i].attr = 1184 (SPX_BG_COLOR << 4) | SPX_FG_COLOR; 1185 wsdisplay_cnattach(&spx_stdscreen, &spx_conscreen, 0, 0, 1186 (SPX_BG_COLOR << 4) | SPX_FG_COLOR); 1187 cn_tab->cn_pri = CN_INTERNAL; 1188 1189 #if NDZKBD > 0 1190 dzkbd_cnattach(0); /* Connect keyboard and screen together */ 1191 #endif 1192 } 1193 1194 /* 1195 * Called very early to setup the glass tty as console. 1196 * Because it's called before the VM system is inited, virtual memory 1197 * for the framebuffer can be stolen directly without disturbing anything. 1198 */ 1199 void 1200 spxcnprobe(struct consdev *cndev) 1201 { 1202 extern const struct cdevsw wsdisplay_cdevsw; 1203 1204 /* Only for VS 4000/90, 90A and 96 with LCSPX or SPXg/gt*/ 1205 if ((vax_boardtype != VAX_BTYP_49) || 1206 ((vax_confdata & (CONF_LCSPX | CONF_SPXg)) != 0)) 1207 return; 1208 1209 if (((vax_confdata & 8) && (vax_boardtype == VAX_BTYP_49)) || 1210 (((vax_confdata & KA420_CFG_L3CON) || 1211 (vax_confdata & KA420_CFG_MULTU)) && 1212 ((vax_boardtype == VAX_BTYP_420) || 1213 (vax_boardtype == VAX_BTYP_43)))) { 1214 aprint_normal("spxcnprobe: Diagnostic console\n"); 1215 return; /* Diagnostic console */ 1216 } 1217 1218 /* KA49: Identify framebuffer type */ 1219 switch (vax_confdata & (CONF_LCSPX | CONF_SPXg)) { 1220 case CONF_LCSPX: 1221 fb_type = FB_IS_SPX; 1222 spx_blkcpy_func = SPX_blkcpy; 1223 spx_blkset_func = SPX_blkset; 1224 break; 1225 case CONF_SPXg: 1226 fb_type = FB_IS_SPXg; 1227 spx_blkcpy_func = SPXg_blkcpy; 1228 spx_blkset_func = SPXg_blkset; 1229 break; 1230 case 0: 1231 aprint_error("spxcnprobe: no framebuffer found\n"); 1232 break; 1233 case CONF_LCSPX | CONF_SPXg: 1234 panic("spxcnprobe: incorrect FB configuration\n"); break; 1235 } 1236 1237 spx_init_common(NULL, NULL); 1238 1239 cndev->cn_pri = CN_INTERNAL; 1240 cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0); 1241 } 1242 1243 static int 1244 spx_map_regs(device_t self, 1245 u_int raddr, u_int rsize, u_int r1addr, u_int r1size) 1246 { 1247 extern vaddr_t virtual_avail; 1248 1249 if (!self) { 1250 regaddr = (long*)virtual_avail; 1251 virtual_avail += rsize; 1252 ioaccess((vaddr_t)regaddr, raddr, rsize/VAX_NBPG); 1253 1254 regaddr1 = (long*)virtual_avail; 1255 virtual_avail += r1size; 1256 ioaccess((vaddr_t)regaddr1, r1addr, r1size/VAX_NBPG); 1257 1258 return 1; 1259 } 1260 1261 regaddr = (long*)vax_map_physmem(raddr, rsize/VAX_NBPG); 1262 if (regaddr == 0) { 1263 aprint_error_dev(self, 1264 "unable to allocate register memory (1).\n"); 1265 return 0; 1266 } 1267 1268 regaddr1 = (long*)vax_map_physmem(r1addr, r1size/VAX_NBPG); 1269 if (regaddr1 == 0) { 1270 aprint_error_dev(self, 1271 "unable to allocate register memory (2).\n"); 1272 return 0; 1273 } 1274 1275 return 1; 1276 } 1277 1278 static int 1279 SPX_map_fb(device_t self, struct vsbus_attach_args *va) 1280 { 1281 int fbsize = (spx_fb_size + FONT_STORAGE_SIZE)/VAX_NBPG; 1282 extern vaddr_t virtual_avail; 1283 1284 if (!self) { 1285 spxaddr = (char *)virtual_avail; 1286 virtual_avail += (spx_fb_size + FONT_STORAGE_SIZE); 1287 ioaccess((vaddr_t)spxaddr, SPX_FB_ADDR, fbsize); 1288 1289 bt_addrl = (char *)virtual_avail; 1290 virtual_avail += VAX_NBPG; 1291 ioaccess((vaddr_t)bt_addrl, SPX_BT459_ADDRL, 1); 1292 1293 bt_addrh = (char *)virtual_avail; 1294 virtual_avail += VAX_NBPG; 1295 ioaccess((vaddr_t)bt_addrh, SPX_BT459_ADDRH, 1); 1296 1297 bt_reg = (char *)virtual_avail; 1298 virtual_avail += VAX_NBPG; 1299 ioaccess((vaddr_t)bt_reg, SPX_BT459_REG, 1); 1300 1301 bt_cmap = (char *)virtual_avail; 1302 virtual_avail += VAX_NBPG; 1303 ioaccess((vaddr_t)bt_cmap, SPX_BT459_CMAP, 1); 1304 1305 return 1; 1306 } 1307 1308 spxaddr = (char *)vax_map_physmem(va->va_paddr, fbsize); 1309 if (spxaddr == 0) { 1310 aprint_error_dev(self, "unable to map framebuffer memory.\n"); 1311 return 0; 1312 } 1313 1314 /* map all four RAMDAC registers */ 1315 bt_addrl = (char *)vax_map_physmem(SPX_BT459_ADDRL, 1); 1316 if (bt_addrl == 0) { 1317 aprint_error_dev(self, 1318 "unable to map BT459 Low Address register.\n"); 1319 return 0; 1320 } 1321 1322 bt_addrh = (char *)vax_map_physmem(SPX_BT459_ADDRH, 1); 1323 if (bt_addrh == 0) { 1324 aprint_error_dev(self, 1325 "unable to map BT459 High Address register.\n"); 1326 return 0; 1327 } 1328 1329 bt_reg = (char *)vax_map_physmem(SPX_BT459_REG, 1); 1330 if (bt_reg == 0) { 1331 aprint_error_dev(self, 1332 "unable to map BT459 I/O Register.\n"); 1333 return 0; 1334 } 1335 1336 bt_cmap = (char *)vax_map_physmem(SPX_BT459_CMAP, 1); 1337 if (bt_cmap == 0) { 1338 aprint_error_dev(self, 1339 "unable to map BT459 Color Map register.\n"); 1340 return 0; 1341 } 1342 1343 return 1; 1344 } 1345 1346 static int 1347 SPXg_map_fb(device_t self, struct vsbus_attach_args *va) 1348 { 1349 int fbsize = SPXg_WIN_SIZE/VAX_NBPG; 1350 extern vaddr_t virtual_avail; 1351 1352 if (!self) { 1353 spxaddr = (char *)virtual_avail; 1354 virtual_avail += SPXg_WIN_SIZE; 1355 ioaccess((vaddr_t)spxaddr, SPXg_FB_ADDR, fbsize); 1356 1357 bt_addrl = (char *)virtual_avail; 1358 virtual_avail += VAX_NBPG; 1359 ioaccess((vaddr_t)bt_addrl, SPXg_BT460_BASE, 1); 1360 1361 bt_addrh = bt_addrl + 0x04; 1362 bt_reg = bt_addrl + 0x08; 1363 bt_cmap = bt_addrl + 0x0c; 1364 bt_wait = bt_addrl + 0x34; 1365 1366 return 1; 1367 } 1368 1369 spxaddr = (char *)vax_map_physmem(va->va_paddr, fbsize); 1370 if (spxaddr == 0) { 1371 aprint_error_dev(self, 1372 "unable to map framebuffer memory window.\n"); 1373 return 0; 1374 } 1375 1376 bt_addrl = (char *)vax_map_physmem(SPXg_BT460_BASE, 1); 1377 if (bt_addrl == 0) { 1378 aprint_error_dev(self, 1379 "unable to map BT460 Low Address register.\n"); 1380 return 0; 1381 } 1382 bt_addrh = bt_addrl + 0x04; 1383 bt_reg = bt_addrl + 0x08; 1384 bt_cmap = bt_addrl + 0x0c; 1385 bt_wait = bt_addrl + 0x34; 1386 1387 return 1; 1388 } 1389 1390 static void 1391 SPX_render_font(void) 1392 { 1393 volatile char *fontaddr = spxaddr + FONT_STORAGE_START; 1394 int i, j, k, ch, pixel; 1395 1396 for (i = 0; i < 256; i++) for (j = 0; j < spx_font.fontheight; j++) { 1397 ch = QFONT(i, j); 1398 1399 /* regular characters */ 1400 pixel = ((i * spx_font.fontheight)+ j) * spx_font.fontwidth; 1401 for (k = 0; k < spx_font.fontwidth; k++) 1402 if (ch & (1 << k)) 1403 fontaddr[pixel++] = 0xff; 1404 else 1405 fontaddr[pixel++] = 0x00; 1406 1407 /* underlined characters */ 1408 pixel = (((i + 256) * spx_font.fontheight) + j) 1409 * spx_font.fontwidth; 1410 for (k = 0; k < spx_font.fontwidth; k++) 1411 if ((ch & (1 << k)) || (j == (spx_font.fontheight - 1))) 1412 fontaddr[pixel++] = 0xff; 1413 else 1414 fontaddr[pixel++] = 0x00; 1415 } 1416 } 1417 1418 static void 1419 SPXg_render_font(void) 1420 { 1421 int i, j, k, ch, pixel; 1422 1423 for (i = 0; i < 256; i++) for (j = 0; j < spx_font.fontheight; j++) { 1424 ch = QFONT(i, j); 1425 /* regular characters */ 1426 for (k = 0; k < spx_font.fontwidth; k++) { 1427 pixel = FONT_STORAGE_START 1428 + (((i * spx_font.fontheight) + j) 1429 * spx_font.fontwidth) + k; 1430 if ((pixel / SPXg_WIN_LINEAR) != spxg_current_page) { 1431 spxg_switch_page(pixel / SPXg_WIN_LINEAR); 1432 spxg_current_page = (pixel / SPXg_WIN_LINEAR); 1433 } 1434 SPXg_ADDR(pixel) = ch & (1 << k) ? 0xff : 0x00; 1435 spxg_delay(); 1436 } 1437 1438 /* underlined characters */ 1439 for (k = 0; k < spx_font.fontwidth; k++) { 1440 pixel = FONT_STORAGE_START 1441 + ((((i + 256) * spx_font.fontheight) + j) 1442 * spx_font.fontwidth) + k; 1443 if ((pixel / SPXg_WIN_LINEAR) != spxg_current_page) { 1444 spxg_switch_page(pixel / SPXg_WIN_LINEAR); 1445 spxg_current_page = (pixel / SPXg_WIN_LINEAR); 1446 } 1447 if ((ch & (1 << k)) || (j == (spx_font.fontheight - 1))) 1448 SPXg_ADDR(pixel) = 0xff; 1449 else 1450 SPXg_ADDR(pixel) = 0x00; 1451 spxg_delay(); 1452 } 1453 } 1454 } 1455 1456 static void 1457 spx_init_common(device_t self, struct vsbus_attach_args *va) 1458 { 1459 u_int i, j, k; 1460 int cookie; 1461 struct wsdisplay_font *wf; 1462 1463 /* map SPX registers first */ 1464 if (fb_type == FB_IS_SPX) { 1465 SPX_MAP_REGS(self, SPX); 1466 } else if(fb_type == FB_IS_SPXg) { 1467 SPX_MAP_REGS(self, SPXg); 1468 } 1469 1470 if (fb_type == FB_IS_SPXg) 1471 spxg_switch_page(0); 1472 1473 /* any KA42/43 SPX resolution detection code should be placed here */ 1474 spx_depth = 8; 1475 spx_xsize = 1280; 1476 spx_ysize = 1024; 1477 1478 wsfont_init(); 1479 1480 cookie = wsfont_find(NULL, 12, 21, 0, WSDISPLAY_FONTORDER_R2L, 1481 WSDISPLAY_FONTORDER_L2R); 1482 if (cookie == -1) 1483 cookie = wsfont_find(NULL, 16, 0, 0, WSDISPLAY_FONTORDER_R2L, 0); 1484 if (cookie == -1) 1485 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L, 0); 1486 if (cookie == -1) 1487 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0); 1488 if (cookie == -1) 1489 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 1490 WSDISPLAY_FONTORDER_L2R); 1491 1492 if (cookie == -1) 1493 aprint_error_dev(self, "spx_common_init: cookie = -1\n"); 1494 1495 if (cookie == -1 || wsfont_lock(cookie, &wf)) 1496 panic("spx_common_init: unable to load console font"); 1497 1498 spx_font = *wf; 1499 1500 if (self != NULL) { 1501 aprint_normal_dev(self, "Using %s %dx%d font\n", wf->name, 1502 spx_font.fontwidth, spx_font.fontheight); 1503 } 1504 1505 spx_cols = spx_xsize / spx_font.fontwidth; 1506 spx_rows = spx_ysize / spx_font.fontheight; 1507 spx_fb_size = spx_xsize * spx_ysize; 1508 spx_stdscreen.ncols = spx_cols; 1509 spx_stdscreen.nrows = spx_rows; 1510 spx_stdscreen.fontwidth = spx_font.fontwidth; 1511 spx_stdscreen.fontheight = spx_font.fontheight; 1512 sprintf(spx_stdscreen_name, "%dx%d", spx_cols, spx_rows); 1513 1514 /* for SPXg spx_fb_size represents FB window size, not FB length */ 1515 if (fb_type == FB_IS_SPXg) 1516 spx_fb_size = SPXg_WIN_SIZE; 1517 1518 qf = spx_font.data; 1519 qf2 = (u_short *)spx_font.data; 1520 1521 if (fb_type == FB_IS_SPX) { 1522 SPX_MAP_FB(self, va, SPX); 1523 } else if (fb_type == FB_IS_SPXg) { 1524 SPX_MAP_FB(self, va, SPXg); 1525 } 1526 1527 /* display FB type based on RAMDAC ID */ 1528 switch (get_btreg(SPXDAC_REG_ID) & 0xff) { 1529 case 0x4a: 1530 aprint_normal_dev( 1531 self, "RAMDAC ID: 0x%x, Bt459 (SPX/LCSPX) RAMDAC type\n", 1532 get_btreg(SPXDAC_REG_ID) & 0xff); 1533 break; 1534 1535 case 0x4b: 1536 aprint_normal_dev( 1537 self, "RAMDAC ID: 0x%x, Bt460 (SPXg) RAMDAC type\n", 1538 get_btreg(SPXDAC_REG_ID) & 0xff); 1539 break; 1540 default: 1541 aprint_error_dev(self, "unknown RAMDAC type 0x%x\n", 1542 get_btreg(SPXDAC_REG_ID) & 0xff); 1543 } 1544 1545 /* render font glyphs to off-screen memory */ 1546 if (fb_type == FB_IS_SPX) 1547 SPX_render_font(); 1548 else if (fb_type == FB_IS_SPXg) 1549 SPXg_render_font(); 1550 1551 /* set up default console color palette */ 1552 for (i = 0; i < 8; i++) { 1553 spx_cmap.r[i] = spx_default_cmap.r[i]; 1554 spx_cmap.g[i] = spx_default_cmap.g[i]; 1555 spx_cmap.b[i] = spx_default_cmap.b[i]; 1556 spx_update_cmap(i, spx_cmap.r[i], spx_cmap.g[i], spx_cmap.b[i]); 1557 } 1558 1559 /* 1560 * Build 64x64 console cursor bitmap based on font dimensions. 1561 * Palette colors are not used, but 4 pixels 2bpp of cursor sprite, 1562 * fg/bg respectively. 1563 */ 1564 for (i = 0; i < 1024; i++) 1565 set_btreg(SPXDAC_REG_CRAM_BASE + i, 0); 1566 1567 /* build cursor line, 1 to 3 pixels high depending on font height */ 1568 if (spx_font.fontheight > 26) 1569 i = spx_font.fontheight - 3; 1570 else if (spx_font.fontheight > 16) 1571 i = spx_font.fontheight - 2; 1572 else 1573 i = spx_font.fontheight - 1; 1574 1575 for (; i <= spx_font.fontheight - 1; i++) { 1576 for (j = 0; j < (spx_font.fontwidth >> 2); j++) 1577 set_btreg(SPXDAC_REG_CRAM_BASE + i*16 + j, 0xff); 1578 k = (spx_font.fontwidth & 3) << 1; 1579 set_btreg(SPXDAC_REG_CRAM_BASE + i*16 + j, (1 << k) - 1); 1580 } 1581 1582 if (fb_type == FB_IS_SPX) { 1583 /* set SPX write/read plane masks */ 1584 SPX_REG(0x3170) = 0xffffffff; 1585 SPX_REG(0x3174) = 0xffffffff; 1586 } 1587 1588 /* RAMDAC type-specific configuration */ 1589 if (fb_type == FB_IS_SPX) 1590 set_btreg(SPXDAC_REG_CMD2, 0xc0); 1591 1592 /* common configuration */ 1593 set_btreg(SPXDAC_REG_CMD0, 0x48); 1594 set_btreg(SPXDAC_REG_CMD1, 0x00); 1595 set_btreg(SPXDAC_REG_PRM, 0xff); 1596 1597 set_btreg(SPXDAC_REG_CXLO, 0); 1598 set_btreg(SPXDAC_REG_CXHI, 0); 1599 set_btreg(SPXDAC_REG_CYLO, 0); 1600 set_btreg(SPXDAC_REG_CYHI, 0); 1601 1602 set_btreg(SPXDAC_REG_WXLO, 0); 1603 set_btreg(SPXDAC_REG_WXHI, 0); 1604 set_btreg(SPXDAC_REG_WYLO, 0); 1605 set_btreg(SPXDAC_REG_WYHI, 0); 1606 1607 set_btreg(SPXDAC_REG_WWLO, 0); 1608 set_btreg(SPXDAC_REG_WWHI, 0); 1609 set_btreg(SPXDAC_REG_WHLO, 0); 1610 set_btreg(SPXDAC_REG_WHHI, 0); 1611 } 1612