Annotation of sys/dev/sbus/tvtwo.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: tvtwo.c,v 1.11 2007/03/13 19:40:49 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 2003, 2006, Miodrag Vallat.
! 4: * 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: /*
! 30: * Driver for the Parallax XVideo and PowerVideo graphics boards.
! 31: *
! 32: * Some details about these board are available at:
! 33: * http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html
! 34: */
! 35:
! 36: /*
! 37: * The Parallax XVideo series frame buffers are 8/24-bit accelerated
! 38: * frame buffers, with hardware MPEG capabilities using a CCube chipset.
! 39: */
! 40:
! 41: /*
! 42: * Currently, this driver can only handle the 8-bit and 24-bit planes of the
! 43: * frame buffer, in an unaccelerated mode.
! 44: *
! 45: * TODO:
! 46: * - nvram handling
! 47: * - use the accelerator
! 48: * - interface to the c^3
! 49: */
! 50:
! 51: #include <sys/param.h>
! 52: #include <sys/systm.h>
! 53: #include <sys/buf.h>
! 54: #include <sys/device.h>
! 55: #include <sys/ioctl.h>
! 56: #include <sys/mman.h>
! 57: #include <sys/conf.h>
! 58:
! 59: #include <uvm/uvm_extern.h>
! 60:
! 61: #include <machine/autoconf.h>
! 62: #include <machine/bus.h>
! 63: #include <machine/pmap.h>
! 64: #include <machine/cpu.h>
! 65: #include <machine/conf.h>
! 66:
! 67: #include <dev/wscons/wsconsio.h>
! 68: #include <dev/wscons/wsdisplayvar.h>
! 69: #include <dev/rasops/rasops.h>
! 70: #include <machine/fbvar.h>
! 71:
! 72: #include <dev/sbus/sbusvar.h>
! 73:
! 74: /*
! 75: * The memory layout of the board is as follows:
! 76: *
! 77: * PROM0 000000 - 00ffff
! 78: * overlay plane 010000 - 037fff
! 79: * registers 040000 - 0404d0
! 80: * CCube 050000 - 05ffff
! 81: * 8-bit plane 080000 - 17ffff
! 82: * 24-bit plane 200000 - 6fffff
! 83: * PROM1 7f0000 - 7fffff
! 84: *
! 85: * Older XVideo provide two sets of SBus registers:
! 86: * R0 040000 - 040800
! 87: * R1 080000 - 17d200
! 88: * While the more recent revisions provide only one register:
! 89: * R0 000000 - 7fffff
! 90: *
! 91: * We currently refuse to attach to the old version because mapping
! 92: * things requires us to play with the sbus register ranges, and I
! 93: * don't want to play this game without the hardware at hand -- miod
! 94: */
! 95:
! 96: #define PX_PROM0_OFFSET 0x000000
! 97: #define PX_OVERLAY_OFFSET 0x010000
! 98: #define PX_REG_OFFSET 0x040000
! 99: #define PX_CCUBE_OFFSET 0x050000
! 100: #define PX_PLANE8_OFFSET 0x080000
! 101: #define PX_PLANE24_OFFSET 0x200000
! 102: #define PX_PROM1_OFFSET 0x7f0000
! 103:
! 104: /*
! 105: * Partial registers layout
! 106: */
! 107:
! 108: #define PX_REG_DISPKLUDGE 0x00b8 /* write only */
! 109: #define DISPKLUDGE_DEFAULT 0xc41f
! 110: #define DISPKLUDGE_BLANK (1 << 12)
! 111: #define DISPKLUDGE_SYNC (1 << 13)
! 112:
! 113: #define PX_REG_BT463_RED 0x0480
! 114: #define PX_REG_BT463_GREEN 0x0490
! 115: #define PX_REG_BT463_BLUE 0x04a0
! 116: #define PX_REG_BT463_ALL 0x04b0
! 117:
! 118: #define PX_REG_SIZE 0x04d0
! 119:
! 120:
! 121: /* per-display variables */
! 122: struct tvtwo_softc {
! 123: struct sunfb sc_sunfb; /* common base device */
! 124:
! 125: bus_space_tag_t sc_bustag;
! 126: bus_addr_t sc_paddr;
! 127:
! 128: volatile u_int8_t *sc_m8;
! 129: volatile u_int8_t *sc_m24;
! 130: volatile u_int8_t *sc_regs;
! 131:
! 132: int sc_nscreens;
! 133: };
! 134:
! 135: int tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 136: int tvtwo_alloc_screen(void *, const struct wsscreen_descr *, void **,
! 137: int *, int *, long *);
! 138: void tvtwo_free_screen(void *, void *);
! 139: int tvtwo_show_screen(void *, void *, int, void (*cb)(void *, int, int),
! 140: void *);
! 141: paddr_t tvtwo_mmap(void *, off_t, int);
! 142: void tvtwo_burner(void *, u_int, u_int);
! 143:
! 144: struct wsdisplay_accessops tvtwo_accessops = {
! 145: tvtwo_ioctl,
! 146: tvtwo_mmap,
! 147: tvtwo_alloc_screen,
! 148: tvtwo_free_screen,
! 149: tvtwo_show_screen,
! 150: NULL, /* load_font */
! 151: NULL, /* scrollback */
! 152: NULL, /* getchar */
! 153: tvtwo_burner,
! 154: };
! 155:
! 156: void tvtwo_directcmap(struct tvtwo_softc *);
! 157: static __inline__
! 158: void tvtwo_ramdac_wraddr(struct tvtwo_softc *, u_int32_t);
! 159: void tvtwo_reset(struct tvtwo_softc *, u_int);
! 160: void tvtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
! 161:
! 162: int tvtwomatch(struct device *, void *, void *);
! 163: void tvtwoattach(struct device *, struct device *, void *);
! 164:
! 165: struct cfattach tvtwo_ca = {
! 166: sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach
! 167: };
! 168:
! 169: struct cfdriver tvtwo_cd = {
! 170: NULL, "tvtwo", DV_DULL
! 171: };
! 172:
! 173: /*
! 174: * Default frame buffer resolution, depending upon the "freqcode"
! 175: */
! 176: #define NFREQCODE 5
! 177: const int defwidth[NFREQCODE] = { 1152, 1152, 1152, 1024, 640 };
! 178: const int defheight[NFREQCODE] = { 900, 900, 900, 768, 480 };
! 179:
! 180: /*
! 181: * Match an XVideo or PowerVideo card.
! 182: */
! 183: int
! 184: tvtwomatch(struct device *parent, void *vcf, void *aux)
! 185: {
! 186: struct sbus_attach_args *sa = aux;
! 187:
! 188: if (strcmp(sa->sa_name, "PGI,tvtwo") == 0 ||
! 189: strcmp(sa->sa_name, "PGI,tvthree") == 0)
! 190: return (1);
! 191:
! 192: return (0);
! 193: }
! 194:
! 195: /*
! 196: * Attach a display.
! 197: */
! 198: void
! 199: tvtwoattach(struct device *parent, struct device *self, void *args)
! 200: {
! 201: struct tvtwo_softc *sc = (struct tvtwo_softc *)self;
! 202: struct sbus_attach_args *sa = args;
! 203: bus_space_tag_t bt;
! 204: bus_space_handle_t bh;
! 205: int node, width, height, freqcode;
! 206: int isconsole;
! 207: char *freqstring;
! 208:
! 209: bt = sa->sa_bustag;
! 210: node = sa->sa_node;
! 211:
! 212: printf(": %s", getpropstring(node, "model"));
! 213: printf(", revision %s\n", getpropstring(node, "revision"));
! 214:
! 215: /* We do not handle older boards yet. */
! 216: if (sa->sa_nreg != 1) {
! 217: printf("%s: old-style boards with %d registers are not supported\n"
! 218: "%s: please report this to <sparc@openbsd.org>\n",
! 219: self->dv_xname, sa->sa_nreg,
! 220: self->dv_xname);
! 221: return;
! 222: }
! 223:
! 224: isconsole = node == fbnode;
! 225:
! 226: /* Map registers. */
! 227: sc->sc_bustag = bt;
! 228: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_REG_OFFSET,
! 229: PX_REG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 230: printf("%s: couldn't map registers\n", self->dv_xname);
! 231: return;
! 232: }
! 233: sc->sc_regs = bus_space_vaddr(bt, bh);
! 234:
! 235: /* Compute framebuffer size. */
! 236: freqstring = getpropstring(node, "freqcode");
! 237: freqcode = (int)*freqstring;
! 238: if (freqcode == 'g') {
! 239: width = height = 1024;
! 240: } else {
! 241: if (freqcode < '1' || freqcode > '6')
! 242: freqcode = 0;
! 243: else
! 244: freqcode -= '1';
! 245: width = defwidth[freqcode];
! 246: height = defheight[freqcode];
! 247: }
! 248:
! 249: width = getpropint(node, "hres", width);
! 250: height = getpropint(node, "vres", height);
! 251:
! 252: /*
! 253: * Since the depth property is usually missing, we could do
! 254: * fb_setsize(&sc->sc_sunfb, 8, width, height, node, 0);
! 255: * but for safety in case it would exist and be set to 32, do it
! 256: * manually...
! 257: */
! 258: sc->sc_sunfb.sf_depth = 8;
! 259: sc->sc_sunfb.sf_width = width;
! 260: sc->sc_sunfb.sf_height = height;
! 261: sc->sc_sunfb.sf_linebytes = width >= 1024 ? width : 1024;
! 262: sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_linebytes * height;
! 263:
! 264: /* Map the frame buffer memory area we're interested in. */
! 265: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
! 266: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE8_OFFSET,
! 267: round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
! 268: &bh) != 0) {
! 269: printf("%s: couldn't map 8-bit video plane\n", self->dv_xname);
! 270: return;
! 271: }
! 272: sc->sc_m8 = bus_space_vaddr(bt, bh);
! 273: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE24_OFFSET,
! 274: round_page(4 * sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0,
! 275: &bh) != 0) {
! 276: printf("%s: couldn't map 32-bit video plane\n", self->dv_xname);
! 277: return;
! 278: }
! 279: sc->sc_m24 = bus_space_vaddr(bt, bh);
! 280:
! 281: /* Enable video. */
! 282: tvtwo_burner(sc, 1, 0);
! 283:
! 284: sc->sc_sunfb.sf_ro.ri_hw = sc;
! 285: sc->sc_sunfb.sf_ro.ri_bits = (u_char *)sc->sc_m8;
! 286:
! 287: /*
! 288: * If the framebuffer width is under 1024, we will switch from
! 289: * the PROM font to the more adequate 8x16 font here.
! 290: */
! 291: fbwscons_init(&sc->sc_sunfb,
! 292: isconsole && (width >= 1024) ? RI_CLEARMARGINS : RI_CLEAR);
! 293: fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
! 294:
! 295: if (isconsole) {
! 296: fbwscons_console_init(&sc->sc_sunfb,
! 297: width >= 1024 ? -1 : 0);
! 298: }
! 299:
! 300: printf("%s: %dx%d\n", self->dv_xname,
! 301: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
! 302:
! 303: fbwscons_attach(&sc->sc_sunfb, &tvtwo_accessops, isconsole);
! 304: }
! 305:
! 306: int
! 307: tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
! 308: {
! 309: struct tvtwo_softc *sc = dev;
! 310: struct wsdisplay_fbinfo *wdf;
! 311:
! 312: /*
! 313: * Note that, although the emulation (text) mode is running in a
! 314: * 8-bit plane, we advertize the frame buffer as 32-bit.
! 315: */
! 316: switch (cmd) {
! 317: case WSDISPLAYIO_GTYPE:
! 318: *(u_int *)data = WSDISPLAY_TYPE_SUN24;
! 319: break;
! 320: case WSDISPLAYIO_GINFO:
! 321: wdf = (struct wsdisplay_fbinfo *)data;
! 322: wdf->height = sc->sc_sunfb.sf_height;
! 323: wdf->width = sc->sc_sunfb.sf_width;
! 324: wdf->depth = 32;
! 325: wdf->cmsize = 0;
! 326: break;
! 327: case WSDISPLAYIO_GETSUPPORTEDDEPTH:
! 328: *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
! 329: break;
! 330: case WSDISPLAYIO_LINEBYTES:
! 331: *(u_int *)data = sc->sc_sunfb.sf_linebytes * 4;
! 332: break;
! 333:
! 334: case WSDISPLAYIO_GETCMAP:
! 335: case WSDISPLAYIO_PUTCMAP:
! 336: break;
! 337:
! 338: case WSDISPLAYIO_SMODE:
! 339: if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
! 340: /* Back from X11 to text mode */
! 341: tvtwo_reset(sc, 8);
! 342: } else {
! 343: /* Starting X11, initialize 32-bit mode */
! 344: tvtwo_reset(sc, 32);
! 345: }
! 346: break;
! 347:
! 348: case WSDISPLAYIO_SVIDEO:
! 349: case WSDISPLAYIO_GVIDEO:
! 350: break;
! 351:
! 352: case WSDISPLAYIO_GCURPOS:
! 353: case WSDISPLAYIO_SCURPOS:
! 354: case WSDISPLAYIO_GCURMAX:
! 355: case WSDISPLAYIO_GCURSOR:
! 356: case WSDISPLAYIO_SCURSOR:
! 357: default:
! 358: return (-1);
! 359: }
! 360:
! 361: return (0);
! 362: }
! 363:
! 364: /*
! 365: * Return the address that would map the given device at the given
! 366: * offset, allowing for the given protection, or return -1 for error.
! 367: */
! 368: paddr_t
! 369: tvtwo_mmap(void *v, off_t offset, int prot)
! 370: {
! 371: struct tvtwo_softc *sc = v;
! 372:
! 373: if (offset & PGOFSET)
! 374: return (-1);
! 375:
! 376: /* Allow mapping as a dumb framebuffer from offset 0 */
! 377: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize * 4) {
! 378: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
! 379: PX_PLANE24_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR));
! 380: }
! 381:
! 382: return (-1);
! 383: }
! 384:
! 385: int
! 386: tvtwo_alloc_screen(void *v, const struct wsscreen_descr *type,
! 387: void **cookiep, int *curxp, int *curyp, long *attrp)
! 388: {
! 389: struct tvtwo_softc *sc = v;
! 390:
! 391: if (sc->sc_nscreens > 0)
! 392: return (ENOMEM);
! 393:
! 394: *cookiep = &sc->sc_sunfb.sf_ro;
! 395: *curyp = 0;
! 396: *curxp = 0;
! 397: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
! 398: 0, 0, 0, attrp);
! 399: sc->sc_nscreens++;
! 400: return (0);
! 401: }
! 402:
! 403: void
! 404: tvtwo_free_screen(void *v, void *cookie)
! 405: {
! 406: struct tvtwo_softc *sc = v;
! 407:
! 408: sc->sc_nscreens--;
! 409: }
! 410:
! 411: int
! 412: tvtwo_show_screen(void *v, void *cookie, int waitok,
! 413: void (*cb)(void *, int, int), void *cbarg)
! 414: {
! 415: return (0);
! 416: }
! 417:
! 418: void
! 419: tvtwo_burner(void *v, u_int on, u_int flags)
! 420: {
! 421: struct tvtwo_softc *sc = v;
! 422: u_int32_t dispkludge;
! 423:
! 424: if (on)
! 425: dispkludge = DISPKLUDGE_DEFAULT & ~DISPKLUDGE_BLANK;
! 426: else {
! 427: dispkludge = DISPKLUDGE_DEFAULT | DISPKLUDGE_BLANK;
! 428: if (flags & WSDISPLAY_BURN_VBLANK)
! 429: dispkludge |= DISPKLUDGE_SYNC;
! 430: }
! 431:
! 432: *(volatile u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUDGE) =
! 433: dispkludge;
! 434: }
! 435:
! 436: void
! 437: tvtwo_reset(struct tvtwo_softc *sc, u_int depth)
! 438: {
! 439: if (depth == 32) {
! 440: /* Initialize a direct color map. */
! 441: tvtwo_directcmap(sc);
! 442: } else {
! 443: fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
! 444: }
! 445: }
! 446:
! 447: /*
! 448: * Simple Bt463 programming routines.
! 449: */
! 450:
! 451: static __inline__ void
! 452: tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr)
! 453: {
! 454: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
! 455:
! 456: dac[0] = (addr & 0xff); /* lo addr */
! 457: dac[1] = ((addr >> 8) & 0xff); /* hi addr */
! 458: }
! 459:
! 460: void
! 461: tvtwo_directcmap(struct tvtwo_softc *sc)
! 462: {
! 463: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
! 464: u_int32_t c;
! 465:
! 466: tvtwo_ramdac_wraddr(sc, 0);
! 467: for (c = 0; c < 256; c++) {
! 468: dac[3] = c; /* R */
! 469: dac[3] = c; /* G */
! 470: dac[3] = c; /* B */
! 471: }
! 472: }
! 473:
! 474: void
! 475: tvtwo_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
! 476: {
! 477: struct tvtwo_softc *sc = v;
! 478: volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
! 479:
! 480: tvtwo_ramdac_wraddr(sc, index);
! 481: dac[3] = r;
! 482: dac[3] = g;
! 483: dac[3] = b;
! 484: }
CVSweb