1 /* $NetBSD: tcx.c,v 1.13 2002/10/23 09:13:43 jdolecek Exp $ */ 2 3 /* 4 * Copyright (c) 1996,1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * color display (TCX) driver. 41 * 42 * Does not handle interrupts, even though they can occur. 43 * 44 * XXX should defer colormap updates to vertical retrace interrupts 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: tcx.c,v 1.13 2002/10/23 09:13:43 jdolecek Exp $"); 49 50 /* 51 * define for cg8 emulation on S24 (24-bit version of tcx) for the SS5; 52 * it is bypassed on the 8-bit version (onboard framebuffer for SS4) 53 */ 54 #undef TCX_CG8 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/buf.h> 59 #include <sys/device.h> 60 #include <sys/ioctl.h> 61 #include <sys/malloc.h> 62 #include <sys/mman.h> 63 #include <sys/tty.h> 64 #include <sys/conf.h> 65 66 #ifdef DEBUG 67 #include <sys/proc.h> 68 #include <sys/syslog.h> 69 #endif 70 71 #include <machine/bus.h> 72 #include <machine/autoconf.h> 73 74 #include <dev/sun/fbio.h> 75 #include <dev/sun/fbvar.h> 76 #include <dev/sun/btreg.h> 77 #include <dev/sun/btvar.h> 78 79 #include <dev/sbus/sbusvar.h> 80 #include <dev/sbus/tcxreg.h> 81 82 /* per-display variables */ 83 struct tcx_softc { 84 struct device sc_dev; /* base device */ 85 struct sbusdev sc_sd; /* sbus device */ 86 struct fbdevice sc_fb; /* frame buffer device */ 87 bus_space_tag_t sc_bustag; 88 struct openprom_addr sc_physadr[TCX_NREG];/* phys addr of h/w */ 89 90 volatile struct bt_regs *sc_bt; /* Brooktree registers */ 91 volatile struct tcx_thc *sc_thc;/* THC registers */ 92 #ifdef TCX_CG8 93 volatile ulong *sc_cplane; /* framebuffer with control planes */ 94 #endif 95 short sc_8bit; /* true if 8-bit hardware */ 96 short sc_blanked; /* true if blanked */ 97 union bt_cmap sc_cmap; /* Brooktree color map */ 98 }; 99 100 /* 101 * The S24 provides the framebuffer RAM mapped in three ways: 102 * 26 bits per pixel, in 32-bit words; the low-order 24 bits are 103 * blue, green, and red values, and the other two bits select the 104 * display modes, per pixel); 105 * 24 bits per pixel, in 32-bit words; the high-order byte reads as 106 * zero, and is ignored on writes (so the mode bits cannot be altered); 107 * 8 bits per pixel, unpadded; writes to this space do not modify the 108 * other 18 bits. 109 */ 110 #define TCX_CTL_8_MAPPED 0x00000000 /* 8 bits, uses color map */ 111 #define TCX_CTL_24_MAPPED 0x01000000 /* 24 bits, uses color map */ 112 #define TCX_CTL_24_LEVEL 0x03000000 /* 24 bits, ignores color map */ 113 #define TCX_CTL_PIXELMASK 0x00FFFFFF /* mask for index/level */ 114 115 /* autoconfiguration driver */ 116 static void tcxattach __P((struct device *, struct device *, void *)); 117 static int tcxmatch __P((struct device *, struct cfdata *, void *)); 118 static void tcx_unblank __P((struct device *)); 119 120 CFATTACH_DECL(tcx, sizeof(struct tcx_softc), 121 tcxmatch, tcxattach, NULL, NULL); 122 123 extern struct cfdriver tcx_cd; 124 125 dev_type_open(tcxopen); 126 dev_type_close(tcxclose); 127 dev_type_ioctl(tcxioctl); 128 dev_type_mmap(tcxmmap); 129 130 const struct cdevsw tcx_cdevsw = { 131 tcxopen, tcxclose, noread, nowrite, tcxioctl, 132 nostop, notty, nopoll, tcxmmap, nokqfilter, 133 }; 134 135 /* frame buffer generic driver */ 136 static struct fbdriver tcx_fbdriver = { 137 tcx_unblank, tcxopen, tcxclose, tcxioctl, nopoll, tcxmmap, 138 nokqfilter 139 }; 140 141 static void tcx_reset __P((struct tcx_softc *)); 142 static void tcx_loadcmap __P((struct tcx_softc *, int, int)); 143 144 #define OBPNAME "SUNW,tcx" 145 146 #ifdef TCX_CG8 147 /* 148 * For CG8 emulation, we map the 32-bit-deep framebuffer at an offset of 149 * 256K; the cg8 space begins with a mono overlay plane and an overlay 150 * enable plane (128K bytes each, 1 bit per pixel), immediately followed 151 * by the color planes, 32 bits per pixel. We also map just the 32-bit 152 * framebuffer at 0x04000000 (TCX_USER_RAM_COMPAT), for compatibility 153 * with the cg8 driver. 154 */ 155 #define TCX_CG8OVERLAY (256 * 1024) 156 #define TCX_SIZE_DFB32 (1152 * 900 * 4) /* max size of the framebuffer */ 157 #endif 158 159 /* 160 * Match a tcx. 161 */ 162 int 163 tcxmatch(parent, cf, aux) 164 struct device *parent; 165 struct cfdata *cf; 166 void *aux; 167 { 168 struct sbus_attach_args *sa = aux; 169 170 return (strcmp(sa->sa_name, OBPNAME) == 0); 171 } 172 173 /* 174 * Attach a display. 175 */ 176 void 177 tcxattach(parent, self, args) 178 struct device *parent, *self; 179 void *args; 180 { 181 struct tcx_softc *sc = (struct tcx_softc *)self; 182 struct sbus_attach_args *sa = args; 183 int node, ramsize; 184 volatile struct bt_regs *bt; 185 struct fbdevice *fb = &sc->sc_fb; 186 bus_space_handle_t bh; 187 int isconsole; 188 189 sc->sc_bustag = sa->sa_bustag; 190 node = sa->sa_node; 191 192 fb->fb_driver = &tcx_fbdriver; 193 fb->fb_device = &sc->sc_dev; 194 /* Mask out invalid flags from the user. */ 195 fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK; 196 /* 197 * The onboard framebuffer on the SS4 supports only 8-bit mode; 198 * it can be distinguished from the S24 card for the SS5 by the 199 * presence of the "tcx-8-bit" attribute on the SS4 version. 200 */ 201 sc->sc_8bit = node_has_property(node, "tcx-8-bit"); 202 #ifdef TCX_CG8 203 if (sc->sc_8bit) { 204 #endif 205 /* 206 * cg8 emulation is either not compiled in or not supported 207 * on this hardware. Report values for the 8-bit framebuffer 208 * so cg3 emulation works. (If this hardware supports 209 * 24-bit mode, the 24-bit framebuffer will also be available) 210 */ 211 fb->fb_type.fb_depth = 8; 212 fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node); 213 214 ramsize = fb->fb_type.fb_height * fb->fb_linebytes; 215 #ifdef TCX_CG8 216 } else { 217 /* 218 * for cg8 emulation, unconditionally report the depth as 219 * 32 bits, but use the height and width reported by the 220 * boot prom. cg8 users want to see the full size of 221 * overlay planes plus color planes included in the 222 * reported framebuffer size. 223 */ 224 fb->fb_type.fb_depth = 32; 225 fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node); 226 fb->fb_linebytes = 227 (fb->fb_type.fb_width * fb->fb_type.fb_depth) / 8; 228 ramsize = TCX_CG8OVERLAY + 229 (fb->fb_type.fb_height * fb->fb_linebytes); 230 } 231 #endif 232 fb->fb_type.fb_cmsize = 256; 233 fb->fb_type.fb_size = ramsize; 234 printf(": %s, %d x %d", OBPNAME, 235 fb->fb_type.fb_width, 236 fb->fb_type.fb_height); 237 #ifdef TCX_CG8 238 /* 239 * if cg8 emulation is enabled, say so; but if hardware can't 240 * emulate cg8, explain that instead 241 */ 242 printf( (sc->sc_8bit)? 243 " (8-bit only)" : 244 " (emulating cg8)"); 245 #endif 246 247 /* 248 * XXX - should be set to FBTYPE_TCX. 249 * XXX For CG3 emulation to work in current (96/6) X11 servers, 250 * XXX `fbtype' must point to an "unregocnised" entry. 251 */ 252 #ifdef TCX_CG8 253 if (sc->sc_8bit) { 254 fb->fb_type.fb_type = FBTYPE_RESERVED3; 255 } else { 256 fb->fb_type.fb_type = FBTYPE_MEMCOLOR; 257 } 258 #else 259 fb->fb_type.fb_type = FBTYPE_RESERVED3; 260 #endif 261 262 263 if (sa->sa_nreg != TCX_NREG) { 264 printf("%s: only %d register sets\n", 265 self->dv_xname, sa->sa_nreg); 266 return; 267 } 268 bcopy(sa->sa_reg, sc->sc_physadr, 269 sa->sa_nreg * sizeof(struct openprom_addr)); 270 271 /* XXX - fix THC and TEC offsets */ 272 sc->sc_physadr[TCX_REG_TEC].oa_base += 0x1000; 273 sc->sc_physadr[TCX_REG_THC].oa_base += 0x1000; 274 275 /* Map the register banks we care about */ 276 if (sbus_bus_map(sa->sa_bustag, 277 sc->sc_physadr[TCX_REG_THC].oa_space, 278 sc->sc_physadr[TCX_REG_THC].oa_base, 279 sizeof (struct tcx_thc), 280 BUS_SPACE_MAP_LINEAR, &bh) != 0) { 281 printf("tcxattach: cannot map thc registers\n"); 282 return; 283 } 284 sc->sc_thc = (volatile struct tcx_thc *) 285 bus_space_vaddr(sa->sa_bustag, bh); 286 287 if (sbus_bus_map(sa->sa_bustag, 288 sc->sc_physadr[TCX_REG_CMAP].oa_space, 289 sc->sc_physadr[TCX_REG_CMAP].oa_base, 290 sizeof (struct bt_regs), 291 BUS_SPACE_MAP_LINEAR, &bh) != 0) { 292 printf("tcxattach: cannot map bt registers\n"); 293 return; 294 } 295 sc->sc_bt = bt = (volatile struct bt_regs *) 296 bus_space_vaddr(sa->sa_bustag, bh); 297 298 #ifdef TCX_CG8 299 if (!sc->sc_8bit) { 300 if (sbus_bus_map(sa->sa_bustag, 301 (bus_type_t)sc->sc_physadr[TCX_REG_RDFB32].oa_space, 302 (bus_addr_t)sc->sc_physadr[TCX_REG_RDFB32].oa_base, 303 TCX_SIZE_DFB32, 304 BUS_SPACE_MAP_LINEAR, 305 0, &bh) != 0) { 306 printf("tcxattach: cannot map control planes\n"); 307 return; 308 } 309 sc->sc_cplane = (volatile ulong *)bh; 310 } 311 #endif 312 313 isconsole = fb_is_console(node); 314 315 printf(", id %d, rev %d, sense %d", 316 (sc->sc_thc->thc_config & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT, 317 (sc->sc_thc->thc_config & THC_CFG_REV) >> THC_CFG_REV_SHIFT, 318 (sc->sc_thc->thc_config & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT 319 ); 320 321 /* reset cursor & frame buffer controls */ 322 tcx_reset(sc); 323 324 /* Initialize the default color map. */ 325 bt_initcmap(&sc->sc_cmap, 256); 326 tcx_loadcmap(sc, 0, 256); 327 328 /* enable video */ 329 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; 330 331 if (isconsole) { 332 printf(" (console)\n"); 333 } else 334 printf("\n"); 335 336 sbus_establish(&sc->sc_sd, &sc->sc_dev); 337 fb_attach(&sc->sc_fb, isconsole); 338 } 339 340 #ifdef TCX_CG8 341 /* 342 * keep track of the number of opens, so we can switch to 24-bit mode 343 * when the device is first opened, and return to 8-bit mode on the 344 * last close. (stolen from cgfourteen driver...) There can only be 345 * one TCX per system, so we only need one flag. 346 */ 347 static int tcx_opens = 0; 348 #endif 349 350 int 351 tcxopen(dev, flags, mode, p) 352 dev_t dev; 353 int flags, mode; 354 struct proc *p; 355 { 356 int unit = minor(dev); 357 #ifdef TCX_CG8 358 struct tcx_softc *sc; 359 int i, s, oldopens; 360 volatile ulong *cptr; 361 struct fbdevice *fb; 362 #endif 363 364 if (unit >= tcx_cd.cd_ndevs || tcx_cd.cd_devs[unit] == NULL) 365 return (ENXIO); 366 #ifdef TCX_CG8 367 sc = tcx_cd.cd_devs[unit]; 368 if (!sc->sc_8bit) { 369 s = splhigh(); 370 oldopens = tcx_opens++; 371 splx(s); 372 if (oldopens == 0) { 373 /* 374 * rewrite the control planes to select 24-bit mode 375 * and clear the screen 376 */ 377 fb = &sc->sc_fb; 378 i = fb->fb_type.fb_height * fb->fb_type.fb_width; 379 cptr = sc->sc_cplane; 380 while (--i >= 0) 381 *cptr++ = TCX_CTL_24_LEVEL; 382 } 383 } 384 #endif 385 return (0); 386 } 387 388 int 389 tcxclose(dev, flags, mode, p) 390 dev_t dev; 391 int flags, mode; 392 struct proc *p; 393 { 394 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 395 #ifdef TCX_CG8 396 int i, s, opens; 397 volatile ulong *cptr; 398 struct fbdevice *fb; 399 #endif 400 401 tcx_reset(sc); 402 #ifdef TCX_CG8 403 if (!sc->sc_8bit) { 404 s = splhigh(); 405 opens = --tcx_opens; 406 if (tcx_opens <= 0) 407 opens = tcx_opens = 0; 408 splx(s); 409 if (opens == 0) { 410 /* 411 * rewrite the control planes to select 8-bit mode, 412 * preserving the contents of the screen. 413 * (or we could just bzero the whole thing...) 414 */ 415 fb = &sc->sc_fb; 416 i = fb->fb_type.fb_height * fb->fb_type.fb_width; 417 cptr = sc->sc_cplane; 418 while (--i >= 0) 419 *cptr++ &= TCX_CTL_PIXELMASK; 420 } 421 } 422 #endif 423 return (0); 424 } 425 426 int 427 tcxioctl(dev, cmd, data, flags, p) 428 dev_t dev; 429 u_long cmd; 430 caddr_t data; 431 int flags; 432 struct proc *p; 433 { 434 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 435 int error; 436 437 switch (cmd) { 438 439 case FBIOGTYPE: 440 *(struct fbtype *)data = sc->sc_fb.fb_type; 441 break; 442 443 case FBIOGATTR: 444 #define fba ((struct fbgattr *)data) 445 fba->real_type = sc->sc_fb.fb_type.fb_type; 446 fba->owner = 0; /* XXX ??? */ 447 fba->fbtype = sc->sc_fb.fb_type; 448 fba->sattr.flags = 0; 449 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 450 fba->sattr.dev_specific[0] = -1; 451 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 452 fba->emu_types[1] = FBTYPE_SUN3COLOR; 453 fba->emu_types[2] = -1; 454 #undef fba 455 break; 456 457 case FBIOGETCMAP: 458 #define p ((struct fbcmap *)data) 459 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 460 461 case FBIOPUTCMAP: 462 /* copy to software map */ 463 #ifdef TCX_CG8 464 if (!sc->sc_8bit) { 465 /* 466 * cg8 has extra bits in high-order byte of the index 467 * that bt_putcmap doesn't recognize 468 */ 469 p->index &= 0xffffff; 470 } 471 #endif 472 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 473 if (error) 474 return (error); 475 /* now blast them into the chip */ 476 /* XXX should use retrace interrupt */ 477 tcx_loadcmap(sc, p->index, p->count); 478 #undef p 479 break; 480 481 case FBIOGVIDEO: 482 *(int *)data = sc->sc_blanked; 483 break; 484 485 case FBIOSVIDEO: 486 if (*(int *)data) 487 tcx_unblank(&sc->sc_dev); 488 else if (!sc->sc_blanked) { 489 sc->sc_blanked = 1; 490 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VIDEN; 491 /* Put monitor in `power-saving mode' */ 492 sc->sc_thc->thc_hcmisc |= THC_MISC_VSYNC_DISABLE; 493 sc->sc_thc->thc_hcmisc |= THC_MISC_HSYNC_DISABLE; 494 } 495 break; 496 497 default: 498 #ifdef DEBUG 499 log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd, 500 p->p_comm, p->p_pid); 501 #endif 502 return (ENOTTY); 503 } 504 return (0); 505 } 506 507 /* 508 * Clean up hardware state (e.g., after bootup or after X crashes). 509 */ 510 static void 511 tcx_reset(sc) 512 struct tcx_softc *sc; 513 { 514 volatile struct bt_regs *bt; 515 516 /* Enable cursor in Brooktree DAC. */ 517 bt = sc->sc_bt; 518 bt->bt_addr = 0x06 << 24; 519 bt->bt_ctrl |= 0x03 << 24; 520 } 521 522 /* 523 * Load a subset of the current (new) colormap into the color DAC. 524 */ 525 static void 526 tcx_loadcmap(sc, start, ncolors) 527 struct tcx_softc *sc; 528 int start, ncolors; 529 { 530 volatile struct bt_regs *bt; 531 u_int *ip, i; 532 int count; 533 534 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 535 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 536 bt = sc->sc_bt; 537 bt->bt_addr = BT_D4M4(start) << 24; 538 while (--count >= 0) { 539 i = *ip++; 540 /* hardware that makes one want to pound boards with hammers */ 541 bt->bt_cmap = i; 542 bt->bt_cmap = i << 8; 543 bt->bt_cmap = i << 16; 544 bt->bt_cmap = i << 24; 545 } 546 } 547 548 static void 549 tcx_unblank(dev) 550 struct device *dev; 551 { 552 struct tcx_softc *sc = (struct tcx_softc *)dev; 553 554 if (sc->sc_blanked) { 555 sc->sc_blanked = 0; 556 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VSYNC_DISABLE; 557 sc->sc_thc->thc_hcmisc &= ~THC_MISC_HSYNC_DISABLE; 558 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; 559 } 560 } 561 562 /* 563 * Base addresses at which users can mmap() the various pieces of a tcx. 564 */ 565 #define TCX_USER_RAM 0x00000000 566 #define TCX_USER_RAM24 0x01000000 567 #define TCX_USER_RAM_COMPAT 0x04000000 /* cg3 emulation */ 568 #define TCX_USER_STIP 0x10000000 569 #define TCX_USER_BLIT 0x20000000 570 #define TCX_USER_RDFB32 0x28000000 571 #define TCX_USER_RSTIP 0x30000000 572 #define TCX_USER_RBLIT 0x38000000 573 #define TCX_USER_TEC 0x70001000 574 #define TCX_USER_BTREGS 0x70002000 575 #define TCX_USER_THC 0x70004000 576 #define TCX_USER_DHC 0x70008000 577 #define TCX_USER_ALT 0x7000a000 578 #define TCX_USER_UART 0x7000c000 579 #define TCX_USER_VRT 0x7000e000 580 #define TCX_USER_ROM 0x70010000 581 582 struct mmo { 583 u_int mo_uaddr; /* user (virtual) address */ 584 u_int mo_size; /* size, or 0 for video ram size */ 585 u_int mo_bank; /* register bank number */ 586 }; 587 588 /* 589 * Return the address that would map the given device at the given 590 * offset, allowing for the given protection, or return -1 for error. 591 * 592 * XXX needs testing against `demanding' applications (e.g., aviator) 593 */ 594 paddr_t 595 tcxmmap(dev, off, prot) 596 dev_t dev; 597 off_t off; 598 int prot; 599 { 600 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 601 struct openprom_addr *rr = sc->sc_physadr; 602 struct mmo *mo, *mo_end; 603 u_int u, sz; 604 static struct mmo mmo[] = { 605 { TCX_USER_RAM, 0, TCX_REG_DFB8 }, 606 { TCX_USER_RAM24, 0, TCX_REG_DFB24 }, 607 { TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 }, 608 609 { TCX_USER_STIP, 1, TCX_REG_STIP }, 610 { TCX_USER_BLIT, 1, TCX_REG_BLIT }, 611 { TCX_USER_RDFB32, 0, TCX_REG_RDFB32 }, 612 { TCX_USER_RSTIP, 1, TCX_REG_RSTIP }, 613 { TCX_USER_RBLIT, 1, TCX_REG_RBLIT }, 614 { TCX_USER_TEC, 1, TCX_REG_TEC }, 615 { TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP }, 616 { TCX_USER_THC, sizeof(struct tcx_thc), TCX_REG_THC }, 617 { TCX_USER_DHC, 1, TCX_REG_DHC }, 618 { TCX_USER_ALT, 1, TCX_REG_ALT }, 619 { TCX_USER_ROM, 65536, TCX_REG_ROM }, 620 }; 621 #define NMMO (sizeof mmo / sizeof *mmo) 622 #ifdef TCX_CG8 623 /* 624 * alternate mapping for CG8 emulation: 625 * map part of the 8-bit-deep framebuffer into the cg8 overlay 626 * space, just so there's something there, and map the 32-bit-deep 627 * framebuffer where cg8 users expect to find it. 628 */ 629 static struct mmo mmo_cg8[] = { 630 { TCX_USER_RAM, TCX_CG8OVERLAY, TCX_REG_DFB8 }, 631 { TCX_CG8OVERLAY, TCX_SIZE_DFB32, TCX_REG_DFB24 }, 632 { TCX_USER_RAM_COMPAT, TCX_SIZE_DFB32, TCX_REG_DFB24 } 633 }; 634 #define NMMO_CG8 (sizeof mmo_cg8 / sizeof *mmo_cg8) 635 #endif 636 637 if (off & PGOFSET) 638 panic("tcxmmap"); 639 640 /* 641 * Entries with size 0 map video RAM (i.e., the size in fb data). 642 * Entries that map 32-bit deep regions are adjusted for their 643 * depth (fb_size gives the size of the 8-bit-deep region). 644 * 645 * Since we work in pages, the fact that the map offset table's 646 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 647 * one byte is as good as one page. 648 */ 649 #ifdef TCX_CG8 650 if (sc->sc_8bit) { 651 mo = mmo; 652 mo_end = &mmo[NMMO]; 653 } else { 654 mo = mmo_cg8; 655 mo_end = &mmo_cg8[NMMO_CG8]; 656 } 657 #else 658 mo = mmo; 659 mo_end = &mmo[NMMO]; 660 #endif 661 for (; mo < mo_end; mo++) { 662 if ((u_int)off < mo->mo_uaddr) 663 continue; 664 u = off - mo->mo_uaddr; 665 sz = mo->mo_size; 666 if (sz == 0) { 667 sz = sc->sc_fb.fb_type.fb_size; 668 /* 669 * check for the 32-bit-deep regions and adjust 670 * accordingly 671 */ 672 if (mo->mo_uaddr == TCX_USER_RAM24 || 673 mo->mo_uaddr == TCX_USER_RDFB32) { 674 if (sc->sc_8bit) { 675 /* 676 * not present on 8-bit hardware 677 */ 678 continue; 679 } 680 sz *= 4; 681 } 682 } 683 if (u < sz) { 684 return (bus_space_mmap(sc->sc_bustag, 685 BUS_ADDR(rr[mo->mo_bank].oa_space, 686 rr[mo->mo_bank].oa_base), 687 u, 688 prot, 689 BUS_SPACE_MAP_LINEAR)); 690 } 691 } 692 return (-1); 693 } 694