Annotation of sys/dev/sbus/mgx.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: mgx.c,v 1.8 2007/02/18 18:38:55 miod Exp $ */
! 2: /*
! 3: * Copyright (c) 2003, 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 Southland Media Systems (now Quantum 3D) MGX and MGXPlus
! 31: * frame buffers.
! 32: *
! 33: * Pretty crude, due to the lack of documentation. Works as a dumb frame
! 34: * buffer in 8 bit mode, although the hardware can run in an 32 bit
! 35: * accelerated mode. Also, interrupts are not handled.
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/buf.h>
! 41: #include <sys/device.h>
! 42: #include <sys/ioctl.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/mman.h>
! 45: #include <sys/tty.h>
! 46: #include <sys/conf.h>
! 47:
! 48: #include <uvm/uvm_extern.h>
! 49:
! 50: #include <machine/autoconf.h>
! 51: #include <machine/pmap.h>
! 52: #include <machine/cpu.h>
! 53: #include <machine/conf.h>
! 54:
! 55: #include <dev/wscons/wsconsio.h>
! 56: #include <dev/wscons/wsdisplayvar.h>
! 57: #include <dev/rasops/rasops.h>
! 58: #include <machine/fbvar.h>
! 59:
! 60: #include <dev/sbus/sbusvar.h>
! 61:
! 62: /*
! 63: * MGX PROM register layout
! 64: */
! 65:
! 66: #define MGX_NREG 9
! 67: #define MGX_REG_CRTC 4 /* video control and ramdac */
! 68: #define MGX_REG_CTRL 5 /* control engine */
! 69: #define MGX_REG_VRAM8 8 /* 8-bit memory space */
! 70:
! 71: /*
! 72: * MGX CRTC empirical constants
! 73: */
! 74: #if _BYTE_ORDER == _LITTLE_ENDIAN
! 75: #define IO_ADDRESS(x) (x)
! 76: #else
! 77: #define IO_ADDRESS(x) ((x) ^ 0x03)
! 78: #endif
! 79: #define CRTC_INDEX IO_ADDRESS(0x03c4)
! 80: #define CRTC_DATA IO_ADDRESS(0x03c5)
! 81: #define CD_DISABLEVIDEO 0x0020
! 82: #define CMAP_READ_INDEX IO_ADDRESS(0x03c7)
! 83: #define CMAP_WRITE_INDEX IO_ADDRESS(0x03c8)
! 84: #define CMAP_DATA IO_ADDRESS(0x03c9)
! 85:
! 86: /* per-display variables */
! 87: struct mgx_softc {
! 88: struct sunfb sc_sunfb; /* common base device */
! 89:
! 90: bus_space_tag_t sc_bustag;
! 91: bus_addr_t sc_paddr;
! 92:
! 93: u_int8_t sc_cmap[256 * 3]; /* shadow colormap */
! 94: volatile u_int8_t *sc_vidc; /* ramdac registers */
! 95:
! 96: int sc_nscreens;
! 97: };
! 98:
! 99: int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 100: int mgx_alloc_screen(void *, const struct wsscreen_descr *, void **,
! 101: int *, int *, long *);
! 102: void mgx_free_screen(void *, void *);
! 103: int mgx_show_screen(void *, void *, int, void (*cb)(void *, int, int),
! 104: void *);
! 105: paddr_t mgx_mmap(void *, off_t, int);
! 106: void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
! 107: int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *);
! 108: int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *);
! 109: void mgx_loadcmap(struct mgx_softc *, int, int);
! 110: void mgx_burner(void *, u_int ,u_int);
! 111:
! 112: struct wsdisplay_accessops mgx_accessops = {
! 113: mgx_ioctl,
! 114: mgx_mmap,
! 115: mgx_alloc_screen,
! 116: mgx_free_screen,
! 117: mgx_show_screen,
! 118: NULL, /* load_font */
! 119: NULL, /* scrollback */
! 120: NULL, /* getchar */
! 121: mgx_burner
! 122: };
! 123:
! 124: int mgxmatch(struct device *, void *, void *);
! 125: void mgxattach(struct device *, struct device *, void *);
! 126:
! 127: struct cfattach mgx_ca = {
! 128: sizeof(struct mgx_softc), mgxmatch, mgxattach
! 129: };
! 130:
! 131: struct cfdriver mgx_cd = {
! 132: NULL, "mgx", DV_DULL
! 133: };
! 134:
! 135: /*
! 136: * Match an MGX or MGX+ card.
! 137: */
! 138: int
! 139: mgxmatch(struct device *parent, void *vcf, void *aux)
! 140: {
! 141: struct sbus_attach_args *sa = aux;
! 142:
! 143: if (strcmp(sa->sa_name, "SMSI,mgx") != 0 &&
! 144: strcmp(sa->sa_name, "mgx") != 0)
! 145: return (0);
! 146:
! 147: return (1);
! 148: }
! 149:
! 150: /*
! 151: * Attach an MGX frame buffer.
! 152: * This will keep the frame buffer in the actual PROM mode, and attach
! 153: * a wsdisplay child device to itself.
! 154: */
! 155: void
! 156: mgxattach(struct device *parent, struct device *self, void *args)
! 157: {
! 158: struct mgx_softc *sc = (struct mgx_softc *)self;
! 159: struct sbus_attach_args *sa = args;
! 160: bus_space_tag_t bt;
! 161: bus_space_handle_t bh;
! 162: int node, fbsize;
! 163: int isconsole;
! 164:
! 165: bt = sa->sa_bustag;
! 166: node = sa->sa_node;
! 167:
! 168: printf(": %s", getpropstring(node, "model"));
! 169:
! 170: isconsole = node == fbnode;
! 171:
! 172: /* Check registers */
! 173: if (sa->sa_nreg < MGX_NREG) {
! 174: printf("\n%s: expected %d registers, got %d\n",
! 175: self->dv_xname, MGX_NREG, sa->sa_nreg);
! 176: return;
! 177: }
! 178:
! 179: sc->sc_bustag = bt;
! 180: if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot,
! 181: sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE,
! 182: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 183: printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
! 184: return;
! 185: }
! 186: sc->sc_vidc = (volatile u_int8_t *)bus_space_vaddr(bt, bh);
! 187:
! 188: /* enable video */
! 189: mgx_burner(sc, 1, 0);
! 190:
! 191: fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
! 192:
! 193: /* Sanity check frame buffer memory */
! 194: fbsize = getpropint(node, "fb_size", 0);
! 195: if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) {
! 196: printf("\n%s: expected at least %d bytes of vram, but card "
! 197: "only provides %d\n",
! 198: self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize);
! 199: return;
! 200: }
! 201:
! 202: /* Map the frame buffer memory area we're interested in */
! 203: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
! 204: sa->sa_reg[MGX_REG_VRAM8].sbr_offset);
! 205: if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
! 206: sa->sa_reg[MGX_REG_VRAM8].sbr_offset,
! 207: round_page(sc->sc_sunfb.sf_fbsize),
! 208: BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 209: printf("\n%s: couldn't map video memory\n", self->dv_xname);
! 210: return;
! 211: }
! 212: sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
! 213: sc->sc_sunfb.sf_ro.ri_hw = sc;
! 214:
! 215: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
! 216:
! 217: bzero(sc->sc_cmap, sizeof(sc->sc_cmap));
! 218: fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor);
! 219:
! 220: printf(", %dx%d\n",
! 221: sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
! 222:
! 223: if (isconsole) {
! 224: fbwscons_console_init(&sc->sc_sunfb, -1);
! 225: }
! 226:
! 227: fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole);
! 228: }
! 229:
! 230: /*
! 231: * wsdisplay operations
! 232: */
! 233:
! 234: int
! 235: mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
! 236: {
! 237: struct mgx_softc *sc = dev;
! 238: struct wsdisplay_cmap *cm;
! 239: struct wsdisplay_fbinfo *wdf;
! 240: int error;
! 241:
! 242: switch (cmd) {
! 243: case WSDISPLAYIO_GTYPE:
! 244: *(u_int *)data = WSDISPLAY_TYPE_MGX;
! 245: break;
! 246: case WSDISPLAYIO_GINFO:
! 247: wdf = (struct wsdisplay_fbinfo *)data;
! 248: wdf->height = sc->sc_sunfb.sf_height;
! 249: wdf->width = sc->sc_sunfb.sf_width;
! 250: wdf->depth = sc->sc_sunfb.sf_depth;
! 251: wdf->cmsize = 256;
! 252: break;
! 253: case WSDISPLAYIO_LINEBYTES:
! 254: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
! 255: break;
! 256:
! 257: case WSDISPLAYIO_GETCMAP:
! 258: cm = (struct wsdisplay_cmap *)data;
! 259: error = mgx_getcmap(sc->sc_cmap, cm);
! 260: if (error != 0)
! 261: return (error);
! 262: break;
! 263: case WSDISPLAYIO_PUTCMAP:
! 264: cm = (struct wsdisplay_cmap *)data;
! 265: error = mgx_putcmap(sc->sc_cmap, cm);
! 266: if (error != 0)
! 267: return (error);
! 268: mgx_loadcmap(sc, cm->index, cm->count);
! 269: break;
! 270:
! 271: case WSDISPLAYIO_SVIDEO:
! 272: case WSDISPLAYIO_GVIDEO:
! 273: break;
! 274:
! 275: default:
! 276: return (-1);
! 277: }
! 278:
! 279: return (0);
! 280: }
! 281:
! 282: paddr_t
! 283: mgx_mmap(void *v, off_t offset, int prot)
! 284: {
! 285: struct mgx_softc *sc = v;
! 286:
! 287: if (offset & PGOFSET)
! 288: return (-1);
! 289:
! 290: /* Allow mapping as a dumb framebuffer from offset 0 */
! 291: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
! 292: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
! 293: offset, prot, BUS_SPACE_MAP_LINEAR));
! 294: }
! 295:
! 296: return (-1);
! 297: }
! 298:
! 299: int
! 300: mgx_alloc_screen(void *v, const struct wsscreen_descr *type,
! 301: void **cookiep, int *curxp, int *curyp, long *attrp)
! 302: {
! 303: struct mgx_softc *sc = v;
! 304:
! 305: if (sc->sc_nscreens > 0)
! 306: return (ENOMEM);
! 307:
! 308: *cookiep = &sc->sc_sunfb.sf_ro;
! 309: *curyp = 0;
! 310: *curxp = 0;
! 311: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
! 312: 0, 0, 0, attrp);
! 313: sc->sc_nscreens++;
! 314: return (0);
! 315: }
! 316:
! 317: void
! 318: mgx_free_screen(void *v, void *cookie)
! 319: {
! 320: struct mgx_softc *sc = v;
! 321:
! 322: sc->sc_nscreens--;
! 323: }
! 324:
! 325: int
! 326: mgx_show_screen(void *v, void *cookie, int waitok,
! 327: void (*cb)(void *, int, int), void *cbarg)
! 328: {
! 329: return (0);
! 330: }
! 331:
! 332: void
! 333: mgx_burner(void *v, u_int on, u_int flags)
! 334: {
! 335: struct mgx_softc *sc = v;
! 336:
! 337: sc->sc_vidc[CRTC_INDEX] = 1; /* TS mode register */
! 338: if (on)
! 339: sc->sc_vidc[CRTC_DATA] &= ~CD_DISABLEVIDEO;
! 340: else
! 341: sc->sc_vidc[CRTC_DATA] |= CD_DISABLEVIDEO;
! 342: }
! 343:
! 344: /*
! 345: * Colormap handling routines
! 346: */
! 347:
! 348: void
! 349: mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
! 350: {
! 351: struct mgx_softc *sc = v;
! 352:
! 353: index *= 3;
! 354: sc->sc_cmap[index++] = r;
! 355: sc->sc_cmap[index++] = g;
! 356: sc->sc_cmap[index] = b;
! 357:
! 358: mgx_loadcmap(sc, index, 1);
! 359: }
! 360:
! 361: void
! 362: mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors)
! 363: {
! 364: u_int8_t *color;
! 365: int i;
! 366:
! 367: #if 0
! 368: sc->sc_vidc[CMAP_WRITE_INDEX] = start;
! 369: color = sc->sc_cmap + start * 3;
! 370: #else
! 371: /*
! 372: * Apparently there is no way to load an incomplete cmap to this
! 373: * DAC. What a waste.
! 374: */
! 375: ncolors = 256;
! 376: color = sc->sc_cmap;
! 377: #endif
! 378: for (i = ncolors * 3; i != 0; i--)
! 379: sc->sc_vidc[CMAP_DATA] = *color++;
! 380: }
! 381:
! 382: int
! 383: mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
! 384: {
! 385: u_int index = rcm->index, count = rcm->count, i;
! 386: int error;
! 387:
! 388: if (index >= 256 || count > 256 - index)
! 389: return (EINVAL);
! 390:
! 391: for (i = 0; i < count; i++) {
! 392: if ((error =
! 393: copyout(cm + (index + i) * 3 + 0, &rcm->red[i], 1)) != 0)
! 394: return (error);
! 395: if ((error =
! 396: copyout(cm + (index + i) * 3 + 1, &rcm->green[i], 1)) != 0)
! 397: return (error);
! 398: if ((error =
! 399: copyout(cm + (index + i) * 3 + 2, &rcm->blue[i], 1)) != 0)
! 400: return (error);
! 401: }
! 402:
! 403: return (0);
! 404: }
! 405:
! 406: int
! 407: mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
! 408: {
! 409: u_int index = rcm->index, count = rcm->count, i;
! 410: int error;
! 411:
! 412: if (index >= 256 || count > 256 - index)
! 413: return (EINVAL);
! 414:
! 415: for (i = 0; i < count; i++) {
! 416: if ((error =
! 417: copyin(&rcm->red[i], cm + (index + i) * 3 + 0, 1)) != 0)
! 418: return (error);
! 419: if ((error =
! 420: copyin(&rcm->green[i], cm + (index + i) * 3 + 1, 1)) != 0)
! 421: return (error);
! 422: if ((error =
! 423: copyin(&rcm->blue[i], cm + (index + i) * 3 + 2, 1)) != 0)
! 424: return (error);
! 425: }
! 426:
! 427: return (0);
! 428: }
CVSweb