1 /* $NetBSD: tcx.c,v 1.2 2000/08/22 21:18:57 pk 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/param.h> 48 #include <sys/systm.h> 49 #include <sys/buf.h> 50 #include <sys/device.h> 51 #include <sys/ioctl.h> 52 #include <sys/malloc.h> 53 #include <sys/mman.h> 54 #include <sys/tty.h> 55 #include <sys/conf.h> 56 57 #ifdef DEBUG 58 #include <sys/proc.h> 59 #include <sys/syslog.h> 60 #endif 61 62 #include <machine/bus.h> 63 #include <machine/autoconf.h> 64 65 #include <dev/sun/fbio.h> 66 #include <dev/sun/fbvar.h> 67 #include <dev/sun/btreg.h> 68 #include <dev/sun/btvar.h> 69 70 #include <dev/sbus/sbusvar.h> 71 #include <dev/sbus/tcxreg.h> 72 73 #include <machine/conf.h> 74 75 /* per-display variables */ 76 struct tcx_softc { 77 struct device sc_dev; /* base device */ 78 struct sbusdev sc_sd; /* sbus device */ 79 struct fbdevice sc_fb; /* frame buffer device */ 80 bus_space_tag_t sc_bustag; 81 struct sbus_reg sc_physadr[TCX_NREG]; /* phys addr of h/w */ 82 83 volatile struct bt_regs *sc_bt; /* Brooktree registers */ 84 volatile struct tcx_thc *sc_thc;/* THC registers */ 85 short sc_blanked; /* true if blanked */ 86 union bt_cmap sc_cmap; /* Brooktree color map */ 87 }; 88 89 /* autoconfiguration driver */ 90 static void tcxattach __P((struct device *, struct device *, void *)); 91 static int tcxmatch __P((struct device *, struct cfdata *, void *)); 92 static void tcx_unblank __P((struct device *)); 93 94 /* cdevsw prototypes */ 95 cdev_decl(tcx); 96 97 struct cfattach tcx_ca = { 98 sizeof(struct tcx_softc), tcxmatch, tcxattach 99 }; 100 101 extern struct cfdriver tcx_cd; 102 103 /* frame buffer generic driver */ 104 static struct fbdriver tcx_fbdriver = { 105 tcx_unblank, tcxopen, tcxclose, tcxioctl, tcxpoll, tcxmmap 106 }; 107 108 static void tcx_reset __P((struct tcx_softc *)); 109 static void tcx_loadcmap __P((struct tcx_softc *, int, int)); 110 111 #define OBPNAME "SUNW,tcx" 112 /* 113 * Match a tcx. 114 */ 115 int 116 tcxmatch(parent, cf, aux) 117 struct device *parent; 118 struct cfdata *cf; 119 void *aux; 120 { 121 struct sbus_attach_args *sa = aux; 122 123 return (strcmp(sa->sa_name, OBPNAME) == 0); 124 } 125 126 /* 127 * Attach a display. 128 */ 129 void 130 tcxattach(parent, self, args) 131 struct device *parent, *self; 132 void *args; 133 { 134 struct tcx_softc *sc = (struct tcx_softc *)self; 135 struct sbus_attach_args *sa = args; 136 int node, ramsize; 137 volatile struct bt_regs *bt; 138 struct fbdevice *fb = &sc->sc_fb; 139 bus_space_handle_t bh; 140 int isconsole; 141 142 sc->sc_bustag = sa->sa_bustag; 143 node = sa->sa_node; 144 145 fb->fb_driver = &tcx_fbdriver; 146 fb->fb_device = &sc->sc_dev; 147 /* Mask out invalid flags from the user. */ 148 fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK; 149 fb->fb_type.fb_depth = node_has_property(node, "tcx-24-bit") 150 ? 24 151 : (node_has_property(node, "tcx-8-bit") 152 ? 8 153 : 8); 154 155 fb_setsize_obp(fb, fb->fb_type.fb_depth, 1152, 900, node); 156 157 ramsize = fb->fb_type.fb_height * fb->fb_linebytes; 158 fb->fb_type.fb_cmsize = 256; 159 fb->fb_type.fb_size = ramsize; 160 printf(": %s, %d x %d", OBPNAME, 161 fb->fb_type.fb_width, 162 fb->fb_type.fb_height); 163 164 /* 165 * XXX - should be set to FBTYPE_TCX. 166 * XXX For CG3 emulation to work in current (96/6) X11 servers, 167 * XXX `fbtype' must point to an "unregocnised" entry. 168 */ 169 fb->fb_type.fb_type = FBTYPE_RESERVED3; 170 171 172 if (sa->sa_nreg != TCX_NREG) { 173 printf("%s: only %d register sets\n", 174 self->dv_xname, sa->sa_nreg); 175 return; 176 } 177 bcopy(sa->sa_reg, sc->sc_physadr, 178 sa->sa_nreg * sizeof(struct sbus_reg)); 179 180 /* XXX - fix THC and TEC offsets */ 181 sc->sc_physadr[TCX_REG_TEC].sbr_offset += 0x1000; 182 sc->sc_physadr[TCX_REG_THC].sbr_offset += 0x1000; 183 184 /* Map the register banks we care about */ 185 if (sbus_bus_map(sa->sa_bustag, 186 (bus_type_t)sc->sc_physadr[TCX_REG_THC].sbr_slot, 187 (bus_addr_t)sc->sc_physadr[TCX_REG_THC].sbr_offset, 188 sizeof (struct tcx_thc), 189 BUS_SPACE_MAP_LINEAR, 190 0, &bh) != 0) { 191 printf("tcxattach: cannot map thc registers\n"); 192 return; 193 } 194 sc->sc_thc = (volatile struct tcx_thc *)bh; 195 196 if (sbus_bus_map(sa->sa_bustag, 197 (bus_type_t)sc->sc_physadr[TCX_REG_CMAP].sbr_slot, 198 (bus_addr_t)sc->sc_physadr[TCX_REG_CMAP].sbr_offset, 199 sizeof (struct bt_regs), 200 BUS_SPACE_MAP_LINEAR, 201 0, &bh) != 0) { 202 printf("tcxattach: cannot map bt registers\n"); 203 return; 204 } 205 sc->sc_bt = bt = (volatile struct bt_regs *)bh; 206 207 isconsole = fb_is_console(node); 208 209 printf(", id %d, rev %d, sense %d", 210 (sc->sc_thc->thc_config & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT, 211 (sc->sc_thc->thc_config & THC_CFG_REV) >> THC_CFG_REV_SHIFT, 212 (sc->sc_thc->thc_config & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT 213 ); 214 215 /* reset cursor & frame buffer controls */ 216 tcx_reset(sc); 217 218 /* Initialize the default color map. */ 219 bt_initcmap(&sc->sc_cmap, 256); 220 tcx_loadcmap(sc, 0, 256); 221 222 /* enable video */ 223 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; 224 225 if (isconsole) { 226 printf(" (console)\n"); 227 } else 228 printf("\n"); 229 230 sbus_establish(&sc->sc_sd, &sc->sc_dev); 231 fb_attach(&sc->sc_fb, isconsole); 232 } 233 234 int 235 tcxopen(dev, flags, mode, p) 236 dev_t dev; 237 int flags, mode; 238 struct proc *p; 239 { 240 int unit = minor(dev); 241 242 if (unit >= tcx_cd.cd_ndevs || tcx_cd.cd_devs[unit] == NULL) 243 return (ENXIO); 244 return (0); 245 } 246 247 int 248 tcxclose(dev, flags, mode, p) 249 dev_t dev; 250 int flags, mode; 251 struct proc *p; 252 { 253 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 254 255 tcx_reset(sc); 256 return (0); 257 } 258 259 int 260 tcxioctl(dev, cmd, data, flags, p) 261 dev_t dev; 262 u_long cmd; 263 caddr_t data; 264 int flags; 265 struct proc *p; 266 { 267 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 268 int error; 269 270 switch (cmd) { 271 272 case FBIOGTYPE: 273 *(struct fbtype *)data = sc->sc_fb.fb_type; 274 break; 275 276 case FBIOGATTR: 277 #define fba ((struct fbgattr *)data) 278 fba->real_type = sc->sc_fb.fb_type.fb_type; 279 fba->owner = 0; /* XXX ??? */ 280 fba->fbtype = sc->sc_fb.fb_type; 281 fba->sattr.flags = 0; 282 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 283 fba->sattr.dev_specific[0] = -1; 284 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 285 fba->emu_types[1] = FBTYPE_SUN3COLOR; 286 fba->emu_types[2] = -1; 287 #undef fba 288 break; 289 290 case FBIOGETCMAP: 291 #define p ((struct fbcmap *)data) 292 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 293 294 case FBIOPUTCMAP: 295 /* copy to software map */ 296 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 297 if (error) 298 return (error); 299 /* now blast them into the chip */ 300 /* XXX should use retrace interrupt */ 301 tcx_loadcmap(sc, p->index, p->count); 302 #undef p 303 break; 304 305 case FBIOGVIDEO: 306 *(int *)data = sc->sc_blanked; 307 break; 308 309 case FBIOSVIDEO: 310 if (*(int *)data) 311 tcx_unblank(&sc->sc_dev); 312 else if (!sc->sc_blanked) { 313 sc->sc_blanked = 1; 314 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VIDEN; 315 /* Put monitor in `power-saving mode' */ 316 sc->sc_thc->thc_hcmisc |= THC_MISC_VSYNC_DISABLE; 317 sc->sc_thc->thc_hcmisc |= THC_MISC_HSYNC_DISABLE; 318 } 319 break; 320 321 default: 322 #ifdef DEBUG 323 log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd, 324 p->p_comm, p->p_pid); 325 #endif 326 return (ENOTTY); 327 } 328 return (0); 329 } 330 331 int 332 tcxpoll(dev, events, p) 333 dev_t dev; 334 int events; 335 struct proc *p; 336 { 337 338 return (seltrue(dev, events, p)); 339 } 340 341 /* 342 * Clean up hardware state (e.g., after bootup or after X crashes). 343 */ 344 static void 345 tcx_reset(sc) 346 struct tcx_softc *sc; 347 { 348 volatile struct bt_regs *bt; 349 350 /* Enable cursor in Brooktree DAC. */ 351 bt = sc->sc_bt; 352 bt->bt_addr = 0x06 << 24; 353 bt->bt_ctrl |= 0x03 << 24; 354 } 355 356 /* 357 * Load a subset of the current (new) colormap into the color DAC. 358 */ 359 static void 360 tcx_loadcmap(sc, start, ncolors) 361 struct tcx_softc *sc; 362 int start, ncolors; 363 { 364 volatile struct bt_regs *bt; 365 u_int *ip, i; 366 int count; 367 368 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 369 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 370 bt = sc->sc_bt; 371 bt->bt_addr = BT_D4M4(start) << 24; 372 while (--count >= 0) { 373 i = *ip++; 374 /* hardware that makes one want to pound boards with hammers */ 375 bt->bt_cmap = i; 376 bt->bt_cmap = i << 8; 377 bt->bt_cmap = i << 16; 378 bt->bt_cmap = i << 24; 379 } 380 } 381 382 static void 383 tcx_unblank(dev) 384 struct device *dev; 385 { 386 struct tcx_softc *sc = (struct tcx_softc *)dev; 387 388 if (sc->sc_blanked) { 389 sc->sc_blanked = 0; 390 sc->sc_thc->thc_hcmisc &= ~THC_MISC_VSYNC_DISABLE; 391 sc->sc_thc->thc_hcmisc &= ~THC_MISC_HSYNC_DISABLE; 392 sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; 393 } 394 } 395 396 /* 397 * Base addresses at which users can mmap() the various pieces of a tcx. 398 */ 399 #define TCX_USER_RAM 0x00000000 400 #define TCX_USER_RAM24 0x01000000 401 #define TCX_USER_RAM_COMPAT 0x04000000 /* cg3 emulation */ 402 #define TCX_USER_STIP 0x10000000 403 #define TCX_USER_BLIT 0x20000000 404 #define TCX_USER_RDFB32 0x28000000 405 #define TCX_USER_RSTIP 0x30000000 406 #define TCX_USER_RBLIT 0x38000000 407 #define TCX_USER_TEC 0x70001000 408 #define TCX_USER_BTREGS 0x70002000 409 #define TCX_USER_THC 0x70004000 410 #define TCX_USER_DHC 0x70008000 411 #define TCX_USER_ALT 0x7000a000 412 #define TCX_USER_UART 0x7000c000 413 #define TCX_USER_VRT 0x7000e000 414 #define TCX_USER_ROM 0x70010000 415 416 struct mmo { 417 u_int mo_uaddr; /* user (virtual) address */ 418 u_int mo_size; /* size, or 0 for video ram size */ 419 u_int mo_bank; /* register bank number */ 420 }; 421 422 /* 423 * Return the address that would map the given device at the given 424 * offset, allowing for the given protection, or return -1 for error. 425 * 426 * XXX needs testing against `demanding' applications (e.g., aviator) 427 */ 428 paddr_t 429 tcxmmap(dev, off, prot) 430 dev_t dev; 431 off_t off; 432 int prot; 433 { 434 struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; 435 bus_space_handle_t bh; 436 struct sbus_reg *rr = sc->sc_physadr; 437 struct mmo *mo; 438 u_int u, sz; 439 static struct mmo mmo[] = { 440 { TCX_USER_RAM, 0, TCX_REG_DFB8 }, 441 { TCX_USER_RAM24, 0, TCX_REG_DFB24 }, 442 { TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 }, 443 444 { TCX_USER_STIP, 1, TCX_REG_STIP }, 445 { TCX_USER_BLIT, 1, TCX_REG_BLIT }, 446 { TCX_USER_RDFB32, 1, TCX_REG_RDFB32 }, 447 { TCX_USER_RSTIP, 1, TCX_REG_RSTIP }, 448 { TCX_USER_RBLIT, 1, TCX_REG_RBLIT }, 449 { TCX_USER_TEC, 1, TCX_REG_TEC }, 450 { TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP }, 451 { TCX_USER_THC, sizeof(struct tcx_thc), TCX_REG_THC }, 452 { TCX_USER_DHC, 1, TCX_REG_DHC }, 453 { TCX_USER_ALT, 1, TCX_REG_ALT }, 454 { TCX_USER_ROM, 65536, TCX_REG_ROM }, 455 }; 456 #define NMMO (sizeof mmo / sizeof *mmo) 457 458 if (off & PGOFSET) 459 panic("tcxmmap"); 460 461 /* 462 * Entries with size 0 map video RAM (i.e., the size in fb data). 463 * 464 * Since we work in pages, the fact that the map offset table's 465 * sizes are sometimes bizarre (e.g., 1) is effectively ignored: 466 * one byte is as good as one page. 467 */ 468 for (mo = mmo; mo < &mmo[NMMO]; mo++) { 469 if ((u_int)off < mo->mo_uaddr) 470 continue; 471 u = off - mo->mo_uaddr; 472 sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; 473 if (u < sz) { 474 bus_type_t t = (bus_type_t)rr[mo->mo_bank].sbr_slot; 475 bus_addr_t a = (bus_addr_t)rr[mo->mo_bank].sbr_offset; 476 477 if (bus_space_mmap(sc->sc_bustag, 478 t, 479 a + u, 480 BUS_SPACE_MAP_LINEAR, &bh)) 481 return (-1); 482 483 return ((paddr_t)bh); 484 } 485 } 486 return (-1); /* not a user-map offset */ 487 } 488