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