Annotation of sys/dev/sbus/cgtwelve.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cgtwelve.c,v 1.5 2007/03/13 19:40:49 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2002, 2003 Miodrag Vallat. 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: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 25: * POSSIBILITY OF SUCH DAMAGE.
! 26: */
! 27:
! 28: /*
! 29: * cgtwelve (GS) accelerated 24-bit framebuffer driver.
! 30: *
! 31: * Enough experiments and SMI's cg12reg.h made this possible.
! 32: */
! 33:
! 34: /*
! 35: * The cgtwelve framebuffer is a 3-slot SBUS card, that will fit only in
! 36: * SPARCstation 1, 1+, 2 and 5, or in an xbox SBUS extension.
! 37: *
! 38: * It is a 24-bit 3D accelerated framebuffer made by Matrox, featuring 4MB
! 39: * (regular model) or 8MB (high-res model) of video memory, a complex
! 40: * windowing engine, double buffering modes, three video planes (overlay,
! 41: * 8 bit and 24 bit color), and a lot of colormap combinations.
! 42: *
! 43: * All of this is driven by a set of three Bt462 ramdacs (latched unless
! 44: * explicitely programmed), and a couple of other Matrox-specific chips.
! 45: *
! 46: * XXX The high res card is untested.
! 47: */
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/buf.h>
! 52: #include <sys/device.h>
! 53: #include <sys/ioctl.h>
! 54: #include <sys/conf.h>
! 55:
! 56: #include <uvm/uvm_extern.h>
! 57:
! 58: #include <machine/autoconf.h>
! 59: #include <machine/bus.h>
! 60: #include <machine/pmap.h>
! 61: #include <machine/cpu.h>
! 62: #include <machine/conf.h>
! 63:
! 64: #include <dev/wscons/wsconsio.h>
! 65: #include <dev/wscons/wsdisplayvar.h>
! 66: #include <dev/rasops/rasops.h>
! 67: #include <machine/fbvar.h>
! 68:
! 69: #include <dev/sbus/sbusvar.h>
! 70:
! 71: #include <dev/sbus/cgtwelvereg.h>
! 72:
! 73: #include <dev/cons.h> /* for prom console hook */
! 74:
! 75: /* per-display variables */
! 76: struct cgtwelve_softc {
! 77: struct sunfb sc_sunfb; /* common base device */
! 78: bus_space_tag_t sc_bustag;
! 79: bus_addr_t sc_paddr;
! 80:
! 81: volatile struct cgtwelve_dpu *sc_dpu;
! 82: volatile struct cgtwelve_apu *sc_apu;
! 83: volatile struct cgtwelve_dac *sc_ramdac; /* RAMDAC registers */
! 84: volatile u_char *sc_overlay; /* overlay or enable plane */
! 85: volatile u_long *sc_inten; /* true color plane */
! 86:
! 87: int sc_highres;
! 88: int sc_nscreens;
! 89: };
! 90:
! 91: int cgtwelve_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 92: int cgtwelve_alloc_screen(void *, const struct wsscreen_descr *, void **,
! 93: int *, int *, long *);
! 94: void cgtwelve_free_screen(void *, void *);
! 95: int cgtwelve_show_screen(void *, void *, int, void (*cb)(void *, int, int),
! 96: void *);
! 97: paddr_t cgtwelve_mmap(void *, off_t, int);
! 98: void cgtwelve_reset(struct cgtwelve_softc *, int);
! 99: void cgtwelve_prom(void *);
! 100:
! 101: static __inline__ void cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc,
! 102: u_int32_t addr);
! 103:
! 104: struct wsdisplay_accessops cgtwelve_accessops = {
! 105: cgtwelve_ioctl,
! 106: cgtwelve_mmap,
! 107: cgtwelve_alloc_screen,
! 108: cgtwelve_free_screen,
! 109: cgtwelve_show_screen,
! 110: NULL, /* load_font */
! 111: NULL, /* scrollback */
! 112: NULL, /* getchar */
! 113: NULL /* burner */
! 114: };
! 115:
! 116: int cgtwelvematch(struct device *, void *, void *);
! 117: void cgtwelveattach(struct device *, struct device *, void *);
! 118:
! 119: struct cfattach cgtwelve_ca = {
! 120: sizeof(struct cgtwelve_softc), cgtwelvematch, cgtwelveattach
! 121: };
! 122:
! 123: struct cfdriver cgtwelve_cd = {
! 124: NULL, "cgtwelve", DV_DULL
! 125: };
! 126:
! 127:
! 128: /*
! 129: * Match a cgtwelve.
! 130: */
! 131: int
! 132: cgtwelvematch(struct device *parent, void *vcf, void *aux)
! 133: {
! 134: struct cfdata *cf = vcf;
! 135: struct sbus_attach_args *sa = aux;
! 136:
! 137: if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0)
! 138: return (0);
! 139:
! 140: return (1);
! 141: }
! 142:
! 143: /*
! 144: * Attach and initialize a cgtwelve.
! 145: */
! 146: void
! 147: cgtwelveattach(struct device *parent, struct device *self, void *args)
! 148: {
! 149: struct cgtwelve_softc *sc = (struct cgtwelve_softc *)self;
! 150: struct sbus_attach_args *sa = args;
! 151: bus_space_tag_t bt;
! 152: bus_space_handle_t bh;
! 153: int node, isconsole = 0;
! 154: char *ps;
! 155:
! 156: bt = sa->sa_bustag;
! 157: node = sa->sa_node;
! 158:
! 159: printf(": %s", getpropstring(node, "model"));
! 160: ps = getpropstring(node, "dev_id");
! 161: if (*ps != '\0')
! 162: printf(" (%s)", ps);
! 163: printf("\n");
! 164:
! 165: isconsole = node == fbnode;
! 166:
! 167: if (sa->sa_nreg == 0) {
! 168: printf("%s: no SBus registers!\n", self->dv_xname);
! 169: return;
! 170: }
! 171:
! 172: sc->sc_bustag = bt;
! 173:
! 174: /*
! 175: * Map registers
! 176: */
! 177: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
! 178: CG12_OFF_DPU, sizeof(struct cgtwelve_dpu),
! 179: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 180: printf("%s: can't map DPU registers\n", self->dv_xname);
! 181: return;
! 182: }
! 183: sc->sc_dpu = bus_space_vaddr(bt, bh);
! 184: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
! 185: CG12_OFF_APU, sizeof(struct cgtwelve_apu),
! 186: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 187: printf("%s: can't map APU registers\n", self->dv_xname);
! 188: return;
! 189: }
! 190: sc->sc_apu = bus_space_vaddr(bt, bh);
! 191: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
! 192: CG12_OFF_DAC, sizeof(struct cgtwelve_dac),
! 193: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 194: printf("%s: can't map RAMDAC registers\n", self->dv_xname);
! 195: return;
! 196: }
! 197: sc->sc_ramdac = bus_space_vaddr(bt, bh);
! 198:
! 199: /*
! 200: * The console is using the 1-bit overlay plane, while the prom
! 201: * will correctly report 32 bit depth.
! 202: */
! 203: fb_setsize(&sc->sc_sunfb, 1, CG12_WIDTH, CG12_HEIGHT,
! 204: node, 0);
! 205: sc->sc_sunfb.sf_depth = 1;
! 206: sc->sc_sunfb.sf_linebytes = sc->sc_sunfb.sf_width / 8;
! 207: sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height *
! 208: sc->sc_sunfb.sf_linebytes;
! 209:
! 210: sc->sc_highres = sc->sc_sunfb.sf_width == CG12_WIDTH_HR;
! 211:
! 212: /*
! 213: * Map planes
! 214: */
! 215: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
! 216: (sc->sc_highres ? CG12_OFF_OVERLAY0_HR : CG12_OFF_OVERLAY0),
! 217: round_page(sc->sc_highres ? CG12_SIZE_OVERLAY_HR :
! 218: CG12_SIZE_OVERLAY), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 219: printf("%s: can't map overlay plane\n", self->dv_xname);
! 220: return;
! 221: }
! 222: sc->sc_overlay = bus_space_vaddr(bt, bh);
! 223: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset +
! 224: (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN),
! 225: round_page(sc->sc_highres ? CG12_SIZE_COLOR24_HR :
! 226: CG12_SIZE_COLOR24), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 227: printf("%s: can't map color plane\n", self->dv_xname);
! 228: return;
! 229: }
! 230: sc->sc_inten = bus_space_vaddr(bt, bh);
! 231: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset +
! 232: (sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN));
! 233:
! 234: /* reset cursor & frame buffer controls */
! 235: sc->sc_sunfb.sf_depth = 0; /* force action */
! 236: cgtwelve_reset(sc, 1);
! 237:
! 238: sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_overlay;
! 239: sc->sc_sunfb.sf_ro.ri_hw = sc;
! 240: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
! 241:
! 242: if (isconsole) {
! 243: fbwscons_console_init(&sc->sc_sunfb, -1);
! 244: shutdownhook_establish(cgtwelve_prom, sc);
! 245: }
! 246:
! 247: printf("%s: %dx%d", self->dv_xname,
! 248: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
! 249: ps = getpropstring(node, "ucoderev");
! 250: if (*ps != '\0')
! 251: printf(", microcode rev. %s", ps);
! 252: printf("\n");
! 253:
! 254: fbwscons_attach(&sc->sc_sunfb, &cgtwelve_accessops, isconsole);
! 255: }
! 256:
! 257: int
! 258: cgtwelve_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
! 259: {
! 260: struct cgtwelve_softc *sc = dev;
! 261: struct wsdisplay_fbinfo *wdf;
! 262:
! 263: /*
! 264: * Note that, although the emulation (text) mode is running in the
! 265: * overlay plane, we advertize the frame buffer as the full-blown
! 266: * 32-bit beast it is.
! 267: */
! 268: switch (cmd) {
! 269: case WSDISPLAYIO_GTYPE:
! 270: *(u_int *)data = WSDISPLAY_TYPE_SUNCG12;
! 271: break;
! 272: case WSDISPLAYIO_GINFO:
! 273: wdf = (struct wsdisplay_fbinfo *)data;
! 274: wdf->height = sc->sc_sunfb.sf_height;
! 275: wdf->width = sc->sc_sunfb.sf_width;
! 276: wdf->depth = 32;
! 277: wdf->cmsize = 0;
! 278: break;
! 279: case WSDISPLAYIO_GETSUPPORTEDDEPTH:
! 280: *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
! 281: break;
! 282: case WSDISPLAYIO_LINEBYTES:
! 283: *(u_int *)data = sc->sc_sunfb.sf_linebytes * 32;
! 284: break;
! 285:
! 286: case WSDISPLAYIO_GETCMAP:
! 287: case WSDISPLAYIO_PUTCMAP:
! 288: break;
! 289:
! 290: case WSDISPLAYIO_SMODE:
! 291: if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
! 292: /* Back from X11 to text mode */
! 293: cgtwelve_reset(sc, 1);
! 294: } else {
! 295: /* Starting X11, switch to 32 bit mode */
! 296: cgtwelve_reset(sc, 32);
! 297: }
! 298: break;
! 299:
! 300: case WSDISPLAYIO_SVIDEO:
! 301: case WSDISPLAYIO_GVIDEO:
! 302: break;
! 303:
! 304: default:
! 305: return (-1); /* not supported yet */
! 306: }
! 307:
! 308: return (0);
! 309: }
! 310:
! 311: /*
! 312: * Clean up hardware state (e.g., after bootup or after X crashes).
! 313: */
! 314: void
! 315: cgtwelve_reset(struct cgtwelve_softc *sc, int depth)
! 316: {
! 317: u_int32_t c;
! 318:
! 319: if (sc->sc_sunfb.sf_depth != depth) {
! 320: if (depth == 1) {
! 321: /*
! 322: * Select the enable plane as sc_overlay, and fill it.
! 323: */
! 324: sc->sc_apu->hpage = sc->sc_highres ?
! 325: CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
! 326: sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
! 327: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
! 328: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
! 329: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
! 330:
! 331: memset((void *)sc->sc_overlay, 0xff, sc->sc_highres ?
! 332: CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
! 333:
! 334: /*
! 335: * Select the overlay plane as sc_overlay.
! 336: */
! 337: sc->sc_apu->hpage = sc->sc_highres ?
! 338: CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
! 339: sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
! 340: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
! 341: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
! 342: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
! 343:
! 344: /*
! 345: * Upload a strict mono colormap, or the text
! 346: * upon returning from 32 bit mode would appear
! 347: * as (slightly dark) white on white.
! 348: */
! 349: cgtwelve_ramdac_wraddr(sc, 0);
! 350: sc->sc_ramdac->color = 0x00000000;
! 351: for (c = 1; c < 256; c++)
! 352: sc->sc_ramdac->color = 0x00ffffff;
! 353: } else {
! 354: /*
! 355: * Select the overlay plane as sc_overlay.
! 356: */
! 357: sc->sc_apu->hpage = sc->sc_highres ?
! 358: CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY;
! 359: sc->sc_apu->haccess = CG12_HACCESS_OVERLAY;
! 360: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY;
! 361: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY;
! 362: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY;
! 363:
! 364: /*
! 365: * Do not attempt to somewhat preserve screen
! 366: * contents - reading the overlay plane and writing
! 367: * to the color plane at the same time is not
! 368: * reliable, and allocating memory to save a copy
! 369: * of the overlay plane would be awful.
! 370: */
! 371: bzero((void *)sc->sc_overlay, sc->sc_highres ?
! 372: CG12_SIZE_OVERLAY_HR : CG12_SIZE_OVERLAY);
! 373:
! 374: /*
! 375: * Select the enable plane as sc_overlay, and clear it.
! 376: */
! 377: sc->sc_apu->hpage = sc->sc_highres ?
! 378: CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE;
! 379: sc->sc_apu->haccess = CG12_HACCESS_ENABLE;
! 380: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE;
! 381: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE;
! 382: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE;
! 383:
! 384: bzero((void *)sc->sc_overlay, sc->sc_highres ?
! 385: CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE);
! 386:
! 387: /*
! 388: * Select the intensity (color) plane, and clear it.
! 389: */
! 390: sc->sc_apu->hpage = sc->sc_highres ?
! 391: CG12_HPAGE_24BIT_HR : CG12_HPAGE_24BIT;
! 392: sc->sc_apu->haccess = CG12_HACCESS_24BIT;
! 393: sc->sc_dpu->pln_sl_host = CG12_PLN_SL_24BIT;
! 394: sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_24BIT;
! 395: sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_24BIT;
! 396:
! 397: memset((void *)sc->sc_inten, 0x00ffffff,
! 398: sc->sc_highres ?
! 399: CG12_SIZE_COLOR24_HR : CG12_SIZE_COLOR24);
! 400:
! 401: /*
! 402: * Use a direct colormap (ramp)
! 403: */
! 404: cgtwelve_ramdac_wraddr(sc, 0);
! 405: for (c = 0; c < 256; c++)
! 406: sc->sc_ramdac->color = c | (c << 8) | (c << 16);
! 407: }
! 408: }
! 409:
! 410: sc->sc_sunfb.sf_depth = depth;
! 411: }
! 412:
! 413: /*
! 414: * Return the address that would map the given device at the given
! 415: * offset, allowing for the given protection, or return -1 for error.
! 416: */
! 417: paddr_t
! 418: cgtwelve_mmap(void *v, off_t offset, int prot)
! 419: {
! 420: struct cgtwelve_softc *sc = v;
! 421:
! 422: if (offset & PGOFSET || offset < 0)
! 423: return (-1);
! 424:
! 425: /*
! 426: * Note that mmap() will invoke this function only if we are NOT
! 427: * in emulation mode, so we can assume 32 bit mode safely here.
! 428: */
! 429: if (offset < sc->sc_sunfb.sf_fbsize * 32) {
! 430: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, offset,
! 431: prot, BUS_SPACE_MAP_LINEAR));
! 432: }
! 433:
! 434: return (-1);
! 435: }
! 436:
! 437: int
! 438: cgtwelve_alloc_screen(void *v, const struct wsscreen_descr *type,
! 439: void **cookiep, int *curxp, int *curyp, long *attrp)
! 440: {
! 441: struct cgtwelve_softc *sc = v;
! 442:
! 443: if (sc->sc_nscreens > 0)
! 444: return (ENOMEM);
! 445:
! 446: *cookiep = &sc->sc_sunfb.sf_ro;
! 447: *curyp = 0;
! 448: *curxp = 0;
! 449: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
! 450: 0, 0, 0, attrp);
! 451: sc->sc_nscreens++;
! 452: return (0);
! 453: }
! 454:
! 455: void
! 456: cgtwelve_free_screen(void *v, void *cookie)
! 457: {
! 458: struct cgtwelve_softc *sc = v;
! 459:
! 460: sc->sc_nscreens--;
! 461: }
! 462:
! 463: int
! 464: cgtwelve_show_screen(void *v, void *cookie, int waitok,
! 465: void (*cb)(void *, int, int), void *cbarg)
! 466: {
! 467: return (0);
! 468: }
! 469:
! 470: /*
! 471: * Simple Bt462 programming routines.
! 472: */
! 473:
! 474: static __inline__ void
! 475: cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc, u_int32_t addr)
! 476: {
! 477: sc->sc_ramdac->addr_lo = (addr & 0xff);
! 478: sc->sc_ramdac->addr_hi = ((addr >> 8) & 0xff);
! 479: }
! 480:
! 481: /*
! 482: * Shutdown hook used to restore PROM-compatible video mode on shutdown,
! 483: * so that the PROM prompt is visible again.
! 484: */
! 485: void
! 486: cgtwelve_prom(void *v)
! 487: {
! 488: struct cgtwelve_softc *sc = v;
! 489: extern struct consdev consdev_prom;
! 490:
! 491: if (sc->sc_sunfb.sf_depth != 1) {
! 492: cgtwelve_reset(sc, 1);
! 493:
! 494: /*
! 495: * Go back to prom output for the last few messages, so they
! 496: * will be displayed correctly.
! 497: */
! 498: cn_tab = &consdev_prom;
! 499: }
! 500: }
CVSweb