1 /* $NetBSD: tfb.c,v 1.63 2019/11/10 21:16:37 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: tfb.c,v 1.63 2019/11/10 21:16:37 chs Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/buf.h> 41 #include <sys/ioctl.h> 42 43 #include <sys/bus.h> 44 #include <sys/intr.h> 45 46 #include <dev/wscons/wsconsio.h> 47 #include <dev/wscons/wsdisplayvar.h> 48 49 #include <dev/rasops/rasops.h> 50 #include <dev/wsfont/wsfont.h> 51 52 #include <dev/tc/tcvar.h> 53 #include <dev/ic/bt463reg.h> 54 #include <dev/ic/bt431reg.h> 55 56 #if defined(pmax) 57 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x)) 58 #endif 59 60 #if defined(alpha) 61 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x)) 62 #endif 63 64 /* 65 * struct bt463reg { 66 * uint8_t bt_lo; 67 * unsigned : 24; 68 * uint8_t bt_hi; 69 * unsigned : 24; 70 * uint8_t bt_reg; 71 * unsigned : 24; 72 * uint8_t bt_cmap; 73 * }; 74 * 75 * N.B. a pair of Bt431s are located adjascently. 76 * struct bt431twin { 77 * struct { 78 * uint8_t u0; for sprite mask 79 * uint8_t u1; for sprite image 80 * unsigned :16; 81 * } bt_lo; 82 * ... 83 * 84 * struct bt431reg { 85 * uint16_t bt_lo; 86 * unsigned : 16; 87 * uint16_t bt_hi; 88 * unsigned : 16; 89 * uint16_t bt_ram; 90 * unsigned : 16; 91 * uint16_t bt_ctl; 92 * }; 93 */ 94 95 /* Bt463 hardware registers, memory-mapped in 32bit stride */ 96 #define bt_lo 0x0 97 #define bt_hi 0x4 98 #define bt_reg 0x8 99 #define bt_cmap 0xc 100 101 /* Bt431 hardware registers, memory-mapped in 32bit stride */ 102 #define bt_ram 0x8 103 #define bt_ctl 0xc 104 105 #define REGWRITE32(p,i,v) do { \ 106 *(volatile uint32_t *)((p) + (i)) = (v); tc_wmb(); \ 107 } while (0) 108 109 #define SELECT463(p,r) do { \ 110 REGWRITE32((p), bt_lo, 0xff & (r)); \ 111 REGWRITE32((p), bt_hi, 0xff & ((r)>>8)); \ 112 } while (0) 113 114 #define TWIN(x) ((x) | ((x) << 8)) 115 #define TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin) 116 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8)) 117 118 #define SELECT431(p,r) do { \ 119 REGWRITE32((p), bt_lo, TWIN(r)); \ 120 REGWRITE32((p), bt_hi, 0); \ 121 } while (0) 122 123 struct hwcmap256 { 124 #define CMAP_SIZE 256 /* R/G/B entries */ 125 uint8_t r[CMAP_SIZE]; 126 uint8_t g[CMAP_SIZE]; 127 uint8_t b[CMAP_SIZE]; 128 }; 129 130 struct hwcursor64 { 131 struct wsdisplay_curpos cc_pos; 132 struct wsdisplay_curpos cc_hot; 133 struct wsdisplay_curpos cc_size; 134 struct wsdisplay_curpos cc_magic; 135 #define CURSOR_MAX_SIZE 64 136 uint8_t cc_color[6]; 137 uint64_t cc_image[CURSOR_MAX_SIZE]; 138 uint64_t cc_mask[CURSOR_MAX_SIZE]; 139 }; 140 141 struct tfb_softc { 142 vaddr_t sc_vaddr; 143 size_t sc_size; 144 struct rasops_info *sc_ri; 145 struct hwcmap256 sc_cmap; /* software copy of colormap */ 146 struct hwcursor64 sc_cursor; /* software copy of cursor */ 147 int sc_blanked; /* video visibility disabled */ 148 int sc_curenb; /* cursor sprite enabled */ 149 int sc_changed; /* need update of hardware */ 150 #define WSDISPLAY_CMAP_DOLUT 0x20 151 int nscreens; 152 }; 153 154 #define TX_MAGIC_X 360 155 #define TX_MAGIC_Y 36 156 157 #define TX_BT463_OFFSET 0x040000 158 #define TX_BT431_OFFSET 0x040010 159 #define TX_CONTROL 0x040030 160 #define TX_MAP_REGISTER 0x040030 161 #define TX_PIP_OFFSET 0x0800c0 162 #define TX_SELECTION 0x100000 163 #define TX_8BPP_OFFSET 0x200000 164 #define TX_8BPP_SIZE 0x200000 165 #define TX_24BPP_OFFSET 0x400000 166 #define TX_24BPP_SIZE 0x600000 167 #define TX_VIDEO_ENABLE 0xa00000 168 169 #define TX_CTL_VIDEO_ON 0x80 170 #define TX_CTL_INT_ENA 0x40 171 #define TX_CTL_INT_PEND 0x20 172 #define TX_CTL_SEG_ENA 0x10 173 #define TX_CTL_SEG 0x0f 174 175 static int tfbmatch(device_t, cfdata_t, void *); 176 static void tfbattach(device_t, device_t, void *); 177 178 CFATTACH_DECL_NEW(tfb, sizeof(struct tfb_softc), 179 tfbmatch, tfbattach, NULL, NULL); 180 181 static void tfb_common_init(struct rasops_info *); 182 static void tfb_cmap_init(struct tfb_softc *); 183 static struct rasops_info tfb_console_ri; 184 static tc_addr_t tfb_consaddr; 185 186 static struct wsscreen_descr tfb_stdscreen = { 187 "std", 0, 0, 188 0, /* textops */ 189 0, 0, 190 WSSCREEN_REVERSE 191 }; 192 193 static const struct wsscreen_descr *_tfb_scrlist[] = { 194 &tfb_stdscreen, 195 }; 196 197 static const struct wsscreen_list tfb_screenlist = { 198 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist 199 }; 200 201 static int tfbioctl(void *, void *, u_long, void *, int, struct lwp *); 202 static paddr_t tfbmmap(void *, void *, off_t, int); 203 204 static int tfb_alloc_screen(void *, const struct wsscreen_descr *, 205 void **, int *, int *, long *); 206 static void tfb_free_screen(void *, void *); 207 static int tfb_show_screen(void *, void *, int, 208 void (*) (void *, int, int), void *); 209 210 static const struct wsdisplay_accessops tfb_accessops = { 211 tfbioctl, 212 tfbmmap, 213 tfb_alloc_screen, 214 tfb_free_screen, 215 tfb_show_screen, 216 0 /* load_font */ 217 }; 218 219 int tfb_cnattach(tc_addr_t); 220 static int tfbintr(void *); 221 static void tfbhwinit(void *); 222 223 static int get_cmap(struct tfb_softc *, struct wsdisplay_cmap *); 224 static int set_cmap(struct tfb_softc *, struct wsdisplay_cmap *); 225 static int set_cursor(struct tfb_softc *, struct wsdisplay_cursor *); 226 static int get_cursor(struct tfb_softc *, struct wsdisplay_cursor *); 227 static void set_curpos(struct tfb_softc *, struct wsdisplay_curpos *); 228 229 /* bit order reverse */ 230 static const uint8_t flip[256] = { 231 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 232 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 233 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 234 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 235 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 236 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 237 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 238 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 239 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 240 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 241 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 242 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 243 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 244 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 245 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 246 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 247 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 248 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 249 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 250 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 251 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 252 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 253 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 254 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 255 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 256 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 257 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 258 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 259 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 260 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 261 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 262 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 263 }; 264 265 static int 266 tfbmatch(device_t parent, cfdata_t match, void *aux) 267 { 268 struct tc_attach_args *ta = aux; 269 270 if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0 271 && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0) 272 return (0); 273 274 return (1); 275 } 276 277 278 static void 279 tfbattach(device_t parent, device_t self, void *aux) 280 { 281 struct tfb_softc *sc = device_private(self); 282 struct tc_attach_args *ta = aux; 283 struct rasops_info *ri; 284 struct wsemuldisplaydev_attach_args waa; 285 int console; 286 287 console = (ta->ta_addr == tfb_consaddr); 288 if (console) { 289 sc->sc_ri = ri = &tfb_console_ri; 290 ri->ri_flg &= ~RI_NO_AUTO; 291 sc->nscreens = 1; 292 } 293 else { 294 ri = malloc(sizeof(struct rasops_info), 295 M_DEVBUF, M_WAITOK | M_ZERO); 296 ri->ri_hw = (void *)ta->ta_addr; 297 tfb_common_init(ri); 298 sc->sc_ri = ri; 299 } 300 printf(": %dx%d, 8,24bpp\n", ri->ri_width, ri->ri_height); 301 302 tfb_cmap_init(sc); 303 304 sc->sc_vaddr = ta->ta_addr; 305 sc->sc_cursor.cc_magic.x = TX_MAGIC_X; 306 sc->sc_cursor.cc_magic.y = TX_MAGIC_Y; 307 sc->sc_blanked = sc->sc_curenb = 0; 308 309 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc); 310 311 *(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) &= ~0x40; 312 *(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) |= 0x40; 313 314 waa.console = console; 315 waa.scrdata = &tfb_screenlist; 316 waa.accessops = &tfb_accessops; 317 waa.accesscookie = sc; 318 319 config_found(self, &waa, wsemuldisplaydevprint); 320 } 321 322 static void 323 tfb_common_init(struct rasops_info *ri) 324 { 325 char *base; 326 int cookie; 327 328 base = (void *)ri->ri_hw; 329 330 /* initialize colormap and cursor hardware */ 331 tfbhwinit(base); 332 333 ri->ri_flg = RI_CENTER; 334 if (ri == &tfb_console_ri) 335 ri->ri_flg |= RI_NO_AUTO; 336 ri->ri_depth = 8; 337 ri->ri_width = 1280; 338 ri->ri_height = 1024; 339 ri->ri_stride = 1280; 340 ri->ri_bits = base + TX_8BPP_OFFSET; 341 342 /* clear the screen */ 343 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 344 345 wsfont_init(); 346 /* prefer 12 pixel wide font */ 347 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 348 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 349 if (cookie <= 0) 350 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 351 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 352 if (cookie <= 0) { 353 printf("tfb: font table is empty\n"); 354 return; 355 } 356 357 if (wsfont_lock(cookie, &ri->ri_font)) { 358 printf("tfb: couldn't lock font\n"); 359 return; 360 } 361 ri->ri_wsfcookie = cookie; 362 363 rasops_init(ri, 34, 80); 364 365 /* XXX shouldn't be global */ 366 tfb_stdscreen.nrows = ri->ri_rows; 367 tfb_stdscreen.ncols = ri->ri_cols; 368 tfb_stdscreen.textops = &ri->ri_ops; 369 tfb_stdscreen.capabilities = ri->ri_caps; 370 } 371 372 static void 373 tfb_cmap_init(struct tfb_softc *sc) 374 { 375 struct hwcmap256 *cm; 376 const uint8_t *p; 377 int index; 378 379 cm = &sc->sc_cmap; 380 p = rasops_cmap; 381 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 382 cm->r[index] = p[0]; 383 cm->g[index] = p[1]; 384 cm->b[index] = p[2]; 385 } 386 } 387 388 static int 389 tfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 390 { 391 struct tfb_softc *sc = v; 392 struct rasops_info *ri = sc->sc_ri; 393 int turnoff, s; 394 395 switch (cmd) { 396 case WSDISPLAYIO_GTYPE: 397 *(u_int *)data = WSDISPLAY_TYPE_TX; 398 return (0); 399 400 case WSDISPLAYIO_GINFO: 401 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 402 wsd_fbip->height = ri->ri_height; 403 wsd_fbip->width = ri->ri_width; 404 wsd_fbip->depth = ri->ri_depth; 405 wsd_fbip->cmsize = CMAP_SIZE; 406 #undef fbt 407 return (0); 408 409 case WSDISPLAYIO_GETCMAP: 410 return get_cmap(sc, (struct wsdisplay_cmap *)data); 411 412 case WSDISPLAYIO_PUTCMAP: 413 return set_cmap(sc, (struct wsdisplay_cmap *)data); 414 415 case WSDISPLAYIO_SVIDEO: 416 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 417 if (sc->sc_blanked != turnoff) { 418 sc->sc_blanked = turnoff; 419 #if 0 /* XXX later XXX */ 420 To turn off; 421 - clear the MSB of TX control register; &= ~0x80, 422 - assign Bt431 register #0 with value 0x4 to hide sprite cursor. 423 #endif /* XXX XXX XXX */ 424 } 425 return (0); 426 427 case WSDISPLAYIO_GVIDEO: 428 *(u_int *)data = sc->sc_blanked ? 429 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 430 return (0); 431 432 case WSDISPLAYIO_GCURPOS: 433 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 434 return (0); 435 436 case WSDISPLAYIO_SCURPOS: 437 s = spltty(); 438 set_curpos(sc, (struct wsdisplay_curpos *)data); 439 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS; 440 splx(s); 441 return (0); 442 443 case WSDISPLAYIO_GCURMAX: 444 ((struct wsdisplay_curpos *)data)->x = 445 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 446 return (0); 447 448 case WSDISPLAYIO_GCURSOR: 449 return get_cursor(sc, (struct wsdisplay_cursor *)data); 450 451 case WSDISPLAYIO_SCURSOR: 452 return set_cursor(sc, (struct wsdisplay_cursor *)data); 453 454 case WSDISPLAYIO_SMODE: 455 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 456 s = spltty(); 457 tfb_cmap_init(sc); 458 sc->sc_curenb = 0; 459 sc->sc_blanked = 0; 460 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR | 461 WSDISPLAY_CMAP_DOLUT); 462 splx(s); 463 } 464 return (0); 465 } 466 return (EPASSTHROUGH); 467 } 468 469 static paddr_t 470 tfbmmap(void *v, void *vs, off_t offset, int prot) 471 { 472 struct tfb_softc *sc = v; 473 474 if (offset >= TX_8BPP_SIZE || offset < 0) /* XXX 24bpp XXX */ 475 return (-1); 476 return machine_btop(sc->sc_vaddr + TX_8BPP_OFFSET + offset); 477 } 478 479 static int 480 tfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 481 int *curxp, int *curyp, long *attrp) 482 { 483 struct tfb_softc *sc = v; 484 struct rasops_info *ri = sc->sc_ri; 485 long defattr; 486 487 if (sc->nscreens > 0) 488 return (ENOMEM); 489 490 *cookiep = ri; /* one and only for now */ 491 *curxp = 0; 492 *curyp = 0; 493 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 494 *attrp = defattr; 495 sc->nscreens++; 496 return (0); 497 } 498 499 static void 500 tfb_free_screen(void *v, void *cookie) 501 { 502 struct tfb_softc *sc = v; 503 504 if (sc->sc_ri == &tfb_console_ri) 505 panic("tfb_free_screen: console"); 506 507 sc->nscreens--; 508 } 509 510 static int 511 tfb_show_screen(void *v, void *cookie, int waitok, 512 void (*cb)(void *, int, int), void *cbarg) 513 { 514 515 return (0); 516 } 517 518 /* EXPORT */ int 519 tfb_cnattach(tc_addr_t addr) 520 { 521 struct rasops_info *ri; 522 long defattr; 523 524 ri = &tfb_console_ri; 525 ri->ri_hw = (void *)addr; 526 tfb_common_init(ri); 527 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 528 wsdisplay_cnattach(&tfb_stdscreen, ri, 0, 0, defattr); 529 tfb_consaddr = addr; 530 return (0); 531 } 532 533 static int 534 tfbintr(void *arg) 535 { 536 struct tfb_softc *sc = arg; 537 char *base, *vdac, *curs; 538 int v; 539 540 base = (void *)sc->sc_ri->ri_hw; 541 *(uint8_t *)(base + TX_CONTROL) &= ~0x40; 542 if (sc->sc_changed == 0) 543 goto done; 544 545 vdac = base + TX_BT463_OFFSET; 546 curs = base + TX_BT431_OFFSET; 547 v = sc->sc_changed; 548 if (v & WSDISPLAY_CURSOR_DOCUR) { 549 int onoff; 550 551 onoff = (sc->sc_curenb) ? 0x4444 : 0x0404; 552 SELECT431(curs, BT431_REG_COMMAND); 553 REGWRITE32(curs, bt_ctl, onoff); 554 } 555 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 556 int x, y; 557 uint32_t twin; 558 559 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 560 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 561 562 x += sc->sc_cursor.cc_magic.x; 563 y += sc->sc_cursor.cc_magic.y; 564 565 SELECT431(curs, BT431_REG_CURSOR_X_LOW); 566 REGWRITE32(curs, bt_ctl, TWIN_LO(x)); 567 REGWRITE32(curs, bt_ctl, TWIN_HI(x)); 568 REGWRITE32(curs, bt_ctl, TWIN_LO(y)); 569 REGWRITE32(curs, bt_ctl, TWIN_HI(y)); 570 } 571 if (v & WSDISPLAY_CURSOR_DOCMAP) { 572 uint8_t *cp = sc->sc_cursor.cc_color; 573 574 SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0); 575 REGWRITE32(vdac, bt_reg, cp[1]); 576 REGWRITE32(vdac, bt_reg, cp[3]); 577 REGWRITE32(vdac, bt_reg, cp[5]); 578 579 REGWRITE32(vdac, bt_reg, cp[0]); 580 REGWRITE32(vdac, bt_reg, cp[2]); 581 REGWRITE32(vdac, bt_reg, cp[4]); 582 583 REGWRITE32(vdac, bt_reg, cp[1]); 584 REGWRITE32(vdac, bt_reg, cp[3]); 585 REGWRITE32(vdac, bt_reg, cp[5]); 586 587 REGWRITE32(vdac, bt_reg, cp[1]); 588 REGWRITE32(vdac, bt_reg, cp[3]); 589 REGWRITE32(vdac, bt_reg, cp[5]); 590 } 591 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 592 uint8_t *ip, *mp, img, msk; 593 int bcnt; 594 595 ip = (uint8_t *)sc->sc_cursor.cc_image; 596 mp = (uint8_t *)sc->sc_cursor.cc_mask; 597 bcnt = 0; 598 SELECT431(curs, BT431_REG_CRAM_BASE); 599 600 /* 64 pixel scan line is consisted with 16 byte cursor ram */ 601 while (bcnt < sc->sc_cursor.cc_size.y * 16) { 602 /* pad right half 32 pixel when smaller than 33 */ 603 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) { 604 REGWRITE32(curs, bt_ram, 0); 605 } 606 else { 607 int half; 608 img = *ip++; 609 msk = *mp++; 610 img &= msk; /* cookie off image */ 611 half = (flip[img] << 8) | flip[msk]; 612 REGWRITE32(curs, bt_ram, half); 613 } 614 bcnt += 2; 615 } 616 /* pad unoccupied scan lines */ 617 while (bcnt < CURSOR_MAX_SIZE * 16) { 618 REGWRITE32(curs, bt_ram, 0); 619 bcnt += 2; 620 } 621 } 622 if (v & WSDISPLAY_CMAP_DOLUT) { 623 struct hwcmap256 *cm = &sc->sc_cmap; 624 int index; 625 626 SELECT463(vdac, BT463_IREG_CPALETTE_RAM); 627 for (index = 0; index < CMAP_SIZE; index++) { 628 REGWRITE32(vdac, bt_cmap, cm->r[index]); 629 REGWRITE32(vdac, bt_cmap, cm->g[index]); 630 REGWRITE32(vdac, bt_cmap, cm->b[index]); 631 } 632 } 633 sc->sc_changed = 0; 634 done: 635 *(uint8_t *)(base + TX_CONTROL) &= ~0x40; /* !? Eeeh !? */ 636 *(uint8_t *)(base + TX_CONTROL) |= 0x40; 637 return (1); 638 } 639 640 static void 641 tfbhwinit(void *tfbbase) 642 { 643 char *vdac, *curs; 644 const uint8_t *p; 645 int i; 646 647 vdac = (char *)tfbbase + TX_BT463_OFFSET; 648 curs = (char *)tfbbase + TX_BT431_OFFSET; 649 SELECT463(vdac, BT463_IREG_COMMAND_0); 650 REGWRITE32(vdac, bt_reg, 0x40); /* CMD 0 */ 651 REGWRITE32(vdac, bt_reg, 0x46); /* CMD 1 */ 652 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD 2 */ 653 REGWRITE32(vdac, bt_reg, 0); /* !? 204 !? */ 654 REGWRITE32(vdac, bt_reg, 0xff); /* plane 0:7 */ 655 REGWRITE32(vdac, bt_reg, 0xff); /* plane 8:15 */ 656 REGWRITE32(vdac, bt_reg, 0xff); /* plane 16:23 */ 657 REGWRITE32(vdac, bt_reg, 0xff); /* plane 24:27 */ 658 REGWRITE32(vdac, bt_reg, 0x00); /* blink 0:7 */ 659 REGWRITE32(vdac, bt_reg, 0x00); /* blink 8:15 */ 660 REGWRITE32(vdac, bt_reg, 0x00); /* blink 16:23 */ 661 REGWRITE32(vdac, bt_reg, 0x00); /* blink 24:27 */ 662 REGWRITE32(vdac, bt_reg, 0x00); 663 664 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */ 665 { 666 static uint32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = { 667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 668 }; 669 670 SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE); 671 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) { 672 BYTE(vdac, bt_reg) = windowtype[i]; /* 0:7 */ 673 BYTE(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */ 674 BYTE(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */ 675 } 676 } 677 #endif 678 679 SELECT463(vdac, BT463_IREG_CPALETTE_RAM); 680 p = rasops_cmap; 681 for (i = 0; i < 256; i++, p += 3) { 682 REGWRITE32(vdac, bt_cmap, p[0]); 683 REGWRITE32(vdac, bt_cmap, p[1]); 684 REGWRITE32(vdac, bt_cmap, p[2]); 685 } 686 687 /* !? Eeeh !? */ 688 SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */); 689 for (i = 0; i < 256; i++) { 690 REGWRITE32(vdac, bt_cmap, i); 691 REGWRITE32(vdac, bt_cmap, i); 692 REGWRITE32(vdac, bt_cmap, i); 693 } 694 695 SELECT431(curs, BT431_REG_COMMAND); 696 REGWRITE32(curs, bt_ctl, 0x0404); 697 REGWRITE32(curs, bt_ctl, 0); /* XLO */ 698 REGWRITE32(curs, bt_ctl, 0); /* XHI */ 699 REGWRITE32(curs, bt_ctl, 0); /* YLO */ 700 REGWRITE32(curs, bt_ctl, 0); /* YHI */ 701 REGWRITE32(curs, bt_ctl, 0); /* XWLO */ 702 REGWRITE32(curs, bt_ctl, 0); /* XWHI */ 703 REGWRITE32(curs, bt_ctl, 0); /* WYLO */ 704 REGWRITE32(curs, bt_ctl, 0); /* WYLO */ 705 REGWRITE32(curs, bt_ctl, 0); /* WWLO */ 706 REGWRITE32(curs, bt_ctl, 0); /* WWHI */ 707 REGWRITE32(curs, bt_ctl, 0); /* WHLO */ 708 REGWRITE32(curs, bt_ctl, 0); /* WHHI */ 709 710 SELECT431(curs, BT431_REG_CRAM_BASE); 711 for (i = 0; i < 512; i++) { 712 REGWRITE32(curs, bt_ram, 0); 713 } 714 } 715 716 static int 717 get_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p) 718 { 719 u_int index = p->index, count = p->count; 720 int error; 721 722 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 723 return (EINVAL); 724 725 error = copyout(&sc->sc_cmap.r[index], p->red, count); 726 if (error) 727 return error; 728 error = copyout(&sc->sc_cmap.g[index], p->green, count); 729 if (error) 730 return error; 731 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 732 return error; 733 } 734 735 static int 736 set_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p) 737 { 738 struct hwcmap256 cmap; 739 u_int index = p->index, count = p->count; 740 int error, s; 741 742 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 743 return (EINVAL); 744 745 error = copyin(p->red, &cmap.r[index], count); 746 if (error) 747 return error; 748 error = copyin(p->green, &cmap.g[index], count); 749 if (error) 750 return error; 751 error = copyin(p->blue, &cmap.b[index], count); 752 if (error) 753 return error; 754 s = spltty(); 755 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 756 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 757 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 758 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 759 splx(s); 760 return (0); 761 } 762 763 static int 764 set_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p) 765 { 766 #define cc (&sc->sc_cursor) 767 u_int v, index = 0, count = 0, icount = 0; 768 uint8_t r[2], g[2], b[2], image[512], mask[512]; 769 int error, s; 770 771 v = p->which; 772 if (v & WSDISPLAY_CURSOR_DOCMAP) { 773 index = p->cmap.index; 774 count = p->cmap.count; 775 if (index >= 2 || count > 2 - index) 776 return (EINVAL); 777 error = copyin(p->cmap.red, &r[index], count); 778 if (error) 779 return error; 780 error = copyin(p->cmap.green, &g[index], count); 781 if (error) 782 return error; 783 error = copyin(p->cmap.blue, &b[index], count); 784 if (error) 785 return error; 786 } 787 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 788 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 789 return (EINVAL); 790 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 791 error = copyin(p->image, image, icount); 792 if (error) 793 return error; 794 error = copyin(p->mask, mask, icount); 795 if (error) 796 return error; 797 } 798 799 s = spltty(); 800 if (v & WSDISPLAY_CURSOR_DOCUR) 801 sc->sc_curenb = p->enable; 802 if (v & WSDISPLAY_CURSOR_DOPOS) 803 set_curpos(sc, &p->pos); 804 if (v & WSDISPLAY_CURSOR_DOHOT) 805 cc->cc_hot = p->hot; 806 if (v & WSDISPLAY_CURSOR_DOCMAP) { 807 memcpy(&cc->cc_color[index], &r[index], count); 808 memcpy(&cc->cc_color[index + 2], &g[index], count); 809 memcpy(&cc->cc_color[index + 4], &b[index], count); 810 } 811 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 812 cc->cc_size = p->size; 813 memset(cc->cc_image, 0, sizeof cc->cc_image); 814 memcpy(cc->cc_image, image, icount); 815 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 816 memcpy(cc->cc_mask, mask, icount); 817 } 818 sc->sc_changed |= v; 819 splx(s); 820 821 return (0); 822 #undef cc 823 } 824 825 static int 826 get_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p) 827 { 828 return (EPASSTHROUGH); /* XXX */ 829 } 830 831 static void 832 set_curpos(struct tfb_softc *sc, struct wsdisplay_curpos *curpos) 833 { 834 struct rasops_info *ri = sc->sc_ri; 835 int x = curpos->x, y = curpos->y; 836 837 if (y < 0) 838 y = 0; 839 else if (y > ri->ri_height) 840 y = ri->ri_height; 841 if (x < 0) 842 x = 0; 843 else if (x > ri->ri_width) 844 x = ri->ri_width; 845 sc->sc_cursor.cc_pos.x = x; 846 sc->sc_cursor.cc_pos.y = y; 847 } 848