Annotation of sys/dev/sbus/rfx.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: rfx.c,v 1.7 2006/12/17 22:18:16 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2004, Miodrag Vallat.
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 26: * POSSIBILITY OF SUCH DAMAGE.
! 27: *
! 28: */
! 29:
! 30: /*
! 31: * Driver for the Vitec RasterFlex family of frame buffers.
! 32: * It should support RasterFlex-24, RasterFlex-32 and RasterFlex-HR.
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/buf.h>
! 38: #include <sys/device.h>
! 39: #include <sys/ioctl.h>
! 40: #include <sys/malloc.h>
! 41: #include <sys/mman.h>
! 42: #include <sys/tty.h>
! 43: #include <sys/conf.h>
! 44:
! 45: #include <uvm/uvm_extern.h>
! 46:
! 47: #include <machine/autoconf.h>
! 48: #include <machine/pmap.h>
! 49: #include <machine/cpu.h>
! 50: #include <machine/conf.h>
! 51: #include <machine/openfirm.h>
! 52:
! 53: #include <dev/wscons/wsconsio.h>
! 54: #include <dev/wscons/wsdisplayvar.h>
! 55: #include <dev/rasops/rasops.h>
! 56: #include <machine/fbvar.h>
! 57:
! 58: #include <dev/sbus/sbusvar.h>
! 59:
! 60: #include <dev/ic/bt463reg.h>
! 61:
! 62: /*
! 63: * Configuration structure
! 64: */
! 65: struct rfx_config {
! 66: u_int16_t unknown;
! 67: u_int16_t version;
! 68: u_int32_t scanline;
! 69: u_int32_t maxwidth; /* unsure */
! 70: u_int32_t maxheight; /* unsure */
! 71: u_int32_t width;
! 72: u_int32_t height;
! 73: };
! 74:
! 75: /*
! 76: * In-memory offsets
! 77: */
! 78:
! 79: #define RFX_RAMDAC_ADDR 0x00020000
! 80: #define RFX_RAMDAC_SIZE 0x00000004
! 81:
! 82: #define RFX_CONTROL_ADDR 0x00040000
! 83: #define RFX_CONTROL_SIZE 0x000000e0
! 84:
! 85: #define RFX_INIT_ADDR 0x00018000
! 86: #define RFX_INIT_OFFSET 0x0000001c
! 87: #define RFX_INIT_SIZE 0x00008000
! 88:
! 89: #define RFX_VRAM_ADDR 0x00100000
! 90:
! 91: /*
! 92: * Control registers
! 93: */
! 94:
! 95: #define RFX_VIDCTRL_REG 0x10
! 96: #define RFX_VSYNC_ENABLE 0x00000001
! 97: #define RFX_VIDEO_DISABLE 0x00000002
! 98:
! 99: /*
! 100: * Shadow colormap
! 101: */
! 102: struct rfx_cmap {
! 103: u_int8_t red[256];
! 104: u_int8_t green[256];
! 105: u_int8_t blue[256];
! 106: };
! 107:
! 108: struct rfx_softc {
! 109: struct sunfb sc_sunfb;
! 110:
! 111: bus_space_tag_t sc_bustag;
! 112: bus_addr_t sc_paddr;
! 113:
! 114: struct intrhand sc_ih;
! 115:
! 116: struct rfx_cmap sc_cmap;
! 117: volatile u_int8_t *sc_ramdac;
! 118: volatile u_int32_t *sc_ctrl;
! 119:
! 120: int sc_nscreens;
! 121: };
! 122:
! 123: int rfx_alloc_screen(void *, const struct wsscreen_descr *, void **,
! 124: int *, int *, long *);
! 125: void rfx_burner(void *, u_int, u_int);
! 126: void rfx_free_screen(void *, void *);
! 127: int rfx_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 128: int rfx_show_screen(void *, void *, int, void (*cb)(void *, int, int),
! 129: void *);
! 130: paddr_t rfx_mmap(void *, off_t, int);
! 131:
! 132: int rfx_getcmap(struct rfx_cmap *, struct wsdisplay_cmap *);
! 133: int rfx_initialize(struct rfx_softc *, struct sbus_attach_args *,
! 134: struct rfx_config *);
! 135: int rfx_intr(void *);
! 136: void rfx_loadcmap(struct rfx_softc *, int, int);
! 137: int rfx_putcmap(struct rfx_cmap *, struct wsdisplay_cmap *);
! 138: void rfx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
! 139:
! 140: struct wsdisplay_accessops rfx_accessops = {
! 141: rfx_ioctl,
! 142: rfx_mmap,
! 143: rfx_alloc_screen,
! 144: rfx_free_screen,
! 145: rfx_show_screen,
! 146: NULL, /* load_font */
! 147: NULL, /* scrollback */
! 148: NULL, /* getchar */
! 149: rfx_burner,
! 150: };
! 151:
! 152: int rfxmatch(struct device *, void *, void *);
! 153: void rfxattach(struct device *, struct device *, void *);
! 154:
! 155: #if defined(OpenBSD)
! 156: struct cfattach rfx_ca = {
! 157: sizeof (struct rfx_softc), rfxmatch, rfxattach
! 158: };
! 159:
! 160: struct cfdriver rfx_cd = {
! 161: NULL, "rfx", DV_DULL
! 162: };
! 163: #else
! 164: CFATTACH_DECL(rfx, sizeof (struct rfx_softc), rfxmatch, rfxattach, NULL, NULL);
! 165: #endif
! 166:
! 167: /*
! 168: * Match a supported RasterFlex card.
! 169: */
! 170: int
! 171: rfxmatch(struct device *parent, void *vcf, void *aux)
! 172: {
! 173: struct sbus_attach_args *sa = aux;
! 174: const char *device = sa->sa_name;
! 175:
! 176: /* skip vendor name (could be CWARE, VITec, ...) */
! 177: while (*device != ',' && *device != '\0')
! 178: device++;
! 179: if (*device == '\0')
! 180: device = sa->sa_name;
! 181: else
! 182: device++;
! 183:
! 184: if (strncmp(device, "RasterFLEX", strlen("RasterFLEX")) != 0)
! 185: return (0);
! 186:
! 187: /* RasterVideo and RasterFlex-TV are frame grabbers */
! 188: if (strcmp(device, "RasterFLEX-TV") == 0)
! 189: return (0);
! 190:
! 191: return (1);
! 192: }
! 193:
! 194: /*
! 195: * Attach and initialize a rfx display, as well as a child wsdisplay.
! 196: */
! 197: void
! 198: rfxattach(struct device *parent, struct device *self, void *args)
! 199: {
! 200: struct rfx_softc *sc = (struct rfx_softc *)self;
! 201: struct sbus_attach_args *sa = args;
! 202: const char *device = sa->sa_name;
! 203: struct rfx_config cf;
! 204: bus_space_tag_t bt;
! 205: bus_space_handle_t bh;
! 206: int node, cflen, isconsole = 0;
! 207:
! 208: /* skip vendor name (could be CWARE, VITec, ...) */
! 209: while (*device != ',' && *device != '\0')
! 210: device++;
! 211: if (*device == '\0')
! 212: device = sa->sa_name;
! 213: else
! 214: device++;
! 215:
! 216: printf(": %s", device);
! 217:
! 218: if (sa->sa_nreg == 0) {
! 219: printf("\n%s: no SBus registers!\n", self->dv_xname);
! 220: return;
! 221: }
! 222:
! 223: bt = sa->sa_bustag;
! 224: node = sa->sa_node;
! 225: isconsole = node == fbnode;
! 226:
! 227: /*
! 228: * Parse configuration structure
! 229: */
! 230: cflen = getproplen(node, "configuration");
! 231: if (cflen != sizeof cf) {
! 232: printf(", unknown %d bytes conf. structure", cflen);
! 233: /* fill in default values */
! 234: cf.version = 0;
! 235: cf.scanline = 2048;
! 236: cf.width = 1152;
! 237: cf.height = 900;
! 238: } else {
! 239: OF_getprop(node, "configuration", &cf, cflen);
! 240: printf(", revision %d", cf.version);
! 241: }
! 242:
! 243: /*
! 244: * Map registers
! 245: */
! 246:
! 247: sc->sc_bustag = bt;
! 248: sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset);
! 249:
! 250: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_RAMDAC_ADDR,
! 251: RFX_RAMDAC_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 252: printf("\n%s: couldn't map ramdac registers\n", self->dv_xname);
! 253: return;
! 254: }
! 255: sc->sc_ramdac = (u_int8_t *)bus_space_vaddr(bt, bh);
! 256:
! 257: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_CONTROL_ADDR,
! 258: RFX_CONTROL_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
! 259: printf("\n%s: couldn't map control registers\n", self->dv_xname);
! 260: return;
! 261: }
! 262: sc->sc_ctrl = (u_int32_t *)bus_space_vaddr(bt, bh);
! 263:
! 264: #if 0 /* not yet */
! 265: sc->sc_ih.ih_fun = rfx_intr;
! 266: sc->sc_ih.ih_arg = sc;
! 267: intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB);
! 268: #endif
! 269:
! 270: /*
! 271: * The following is an equivalent for
! 272: * fb_setsize(&sc->sc_sunfb, 8, cf.width, cf.height,
! 273: * node, ca->ca_bustype);
! 274: * forcing the correct scan line value. Since the usual frame buffer
! 275: * properties are missing on this card, no need to go through
! 276: * fb_setsize()...
! 277: */
! 278: sc->sc_sunfb.sf_depth = 8;
! 279: sc->sc_sunfb.sf_width = cf.width;
! 280: sc->sc_sunfb.sf_height = cf.height;
! 281: sc->sc_sunfb.sf_linebytes = cf.scanline;
! 282: sc->sc_sunfb.sf_fbsize = cf.height * cf.scanline;
! 283:
! 284: printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
! 285:
! 286: if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + RFX_VRAM_ADDR,
! 287: round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR,
! 288: 0, &bh) != 0) {
! 289: printf("\n%s: couldn't map video memory\n", self->dv_xname);
! 290: return;
! 291: }
! 292: sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
! 293: sc->sc_sunfb.sf_ro.ri_hw = sc;
! 294:
! 295: /*
! 296: * If we are not the console, the frame buffer has not been
! 297: * initalized by the PROM - do this ourselves.
! 298: */
! 299: if (!isconsole) {
! 300: if (rfx_initialize(sc, sa, &cf) != 0)
! 301: return;
! 302: }
! 303:
! 304: fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR);
! 305:
! 306: bzero(&sc->sc_cmap, sizeof(sc->sc_cmap));
! 307: fbwscons_setcolormap(&sc->sc_sunfb, rfx_setcolor);
! 308:
! 309: if (isconsole) {
! 310: fbwscons_console_init(&sc->sc_sunfb, -1);
! 311: }
! 312:
! 313: /* enable video */
! 314: rfx_burner(sc, 1, 0);
! 315:
! 316: fbwscons_attach(&sc->sc_sunfb, &rfx_accessops, isconsole);
! 317: }
! 318:
! 319: /*
! 320: * Common wsdisplay operations
! 321: */
! 322:
! 323: int
! 324: rfx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
! 325: {
! 326: struct rfx_softc *sc = v;
! 327: struct wsdisplay_cmap *cm;
! 328: struct wsdisplay_fbinfo *wdf;
! 329: int error;
! 330:
! 331: switch (cmd) {
! 332: case WSDISPLAYIO_GTYPE:
! 333: *(u_int *)data = WSDISPLAY_TYPE_RFLEX;
! 334: break;
! 335: case WSDISPLAYIO_GINFO:
! 336: wdf = (struct wsdisplay_fbinfo *)data;
! 337: wdf->height = sc->sc_sunfb.sf_height;
! 338: wdf->width = sc->sc_sunfb.sf_width;
! 339: wdf->depth = sc->sc_sunfb.sf_depth;
! 340: wdf->cmsize = 256;
! 341: break;
! 342: case WSDISPLAYIO_LINEBYTES:
! 343: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
! 344: break;
! 345:
! 346: case WSDISPLAYIO_GETCMAP:
! 347: cm = (struct wsdisplay_cmap *)data;
! 348: error = rfx_getcmap(&sc->sc_cmap, cm);
! 349: if (error != 0)
! 350: return (error);
! 351: break;
! 352: case WSDISPLAYIO_PUTCMAP:
! 353: cm = (struct wsdisplay_cmap *)data;
! 354: error = rfx_putcmap(&sc->sc_cmap, cm);
! 355: if (error != 0)
! 356: return (error);
! 357: rfx_loadcmap(sc, cm->index, cm->count);
! 358: break;
! 359:
! 360: case WSDISPLAYIO_SVIDEO:
! 361: case WSDISPLAYIO_GVIDEO:
! 362: break;
! 363:
! 364: default:
! 365: return (-1);
! 366: }
! 367:
! 368: return (0);
! 369: }
! 370:
! 371: paddr_t
! 372: rfx_mmap(void *v, off_t offset, int prot)
! 373: {
! 374: struct rfx_softc *sc = v;
! 375:
! 376: if (offset & PGOFSET)
! 377: return (-1);
! 378:
! 379: if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
! 380: return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
! 381: RFX_VRAM_ADDR + offset, prot, BUS_SPACE_MAP_LINEAR));
! 382: }
! 383:
! 384: return (-1);
! 385: }
! 386:
! 387: int
! 388: rfx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
! 389: int *curxp, int *curyp, long *attrp)
! 390: {
! 391: struct rfx_softc *sc = v;
! 392:
! 393: if (sc->sc_nscreens > 0)
! 394: return (ENOMEM);
! 395:
! 396: *cookiep = &sc->sc_sunfb.sf_ro;
! 397: *curyp = 0;
! 398: *curxp = 0;
! 399: sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
! 400: WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
! 401: sc->sc_nscreens++;
! 402: return (0);
! 403: }
! 404:
! 405: void
! 406: rfx_free_screen(void *v, void *cookie)
! 407: {
! 408: struct rfx_softc *sc = v;
! 409:
! 410: sc->sc_nscreens--;
! 411: }
! 412:
! 413: int
! 414: rfx_show_screen(void *v, void *cookie, int waitok,
! 415: void (*cb)(void *, int, int), void *cbarg)
! 416: {
! 417: return (0);
! 418: }
! 419:
! 420: void
! 421: rfx_burner(void *v, u_int on, u_int flags)
! 422: {
! 423: struct rfx_softc *sc = v;
! 424:
! 425: if (on) {
! 426: sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VIDEO_DISABLE;
! 427: sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VSYNC_ENABLE;
! 428: } else {
! 429: sc->sc_ctrl[RFX_VIDCTRL_REG] |= RFX_VIDEO_DISABLE;
! 430: if (flags & WSDISPLAY_BURN_VBLANK)
! 431: sc->sc_ctrl[RFX_VIDCTRL_REG] &= ~RFX_VSYNC_ENABLE;
! 432: }
! 433: }
! 434:
! 435: /*
! 436: * Colormap helper functions
! 437: */
! 438:
! 439: void
! 440: rfx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
! 441: {
! 442: struct rfx_softc *sc = v;
! 443:
! 444: sc->sc_cmap.red[index] = r;
! 445: sc->sc_cmap.green[index] = g;
! 446: sc->sc_cmap.blue[index] = b;
! 447:
! 448: rfx_loadcmap(sc, index, 1);
! 449: }
! 450:
! 451: int
! 452: rfx_getcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm)
! 453: {
! 454: u_int index = rcm->index, count = rcm->count;
! 455: int error;
! 456:
! 457: if (index >= 256 || count > 256 - index)
! 458: return (EINVAL);
! 459:
! 460: if ((error = copyout(cm->red + index, rcm->red, count)) != 0)
! 461: return (error);
! 462: if ((error = copyout(cm->green + index, rcm->green, count)) != 0)
! 463: return (error);
! 464: if ((error = copyout(cm->blue + index, rcm->blue, count)) != 0)
! 465: return (error);
! 466:
! 467: return (0);
! 468: }
! 469:
! 470: int
! 471: rfx_putcmap(struct rfx_cmap *cm, struct wsdisplay_cmap *rcm)
! 472: {
! 473: u_int index = rcm->index, count = rcm->count;
! 474: u_int8_t red[256], green[256], blue[256];
! 475: int error;
! 476:
! 477: if (index >= 256 || count > 256 - index)
! 478: return (EINVAL);
! 479:
! 480: if ((error = copyin(rcm->red, red, count)) != 0)
! 481: return (error);
! 482: if ((error = copyin(rcm->green, green, count)) != 0)
! 483: return (error);
! 484: if ((error = copyin(rcm->blue, blue, count)) != 0)
! 485: return (error);
! 486:
! 487: bcopy(red, cm->red + index, count);
! 488: bcopy(green, cm->green + index, count);
! 489: bcopy(blue, cm->blue + index, count);
! 490:
! 491: return (0);
! 492: }
! 493:
! 494: void
! 495: rfx_loadcmap(struct rfx_softc *sc, int start, int ncolors)
! 496: {
! 497: u_int8_t *r, *g, *b;
! 498:
! 499: r = sc->sc_cmap.red + start;
! 500: g = sc->sc_cmap.green + start;
! 501: b = sc->sc_cmap.blue + start;
! 502:
! 503: start += BT463_IREG_CPALETTE_RAM;
! 504: sc->sc_ramdac[BT463_REG_ADDR_LOW] = start & 0xff;
! 505: sc->sc_ramdac[BT463_REG_ADDR_HIGH] = (start >> 8) & 0xff;
! 506:
! 507: while (ncolors-- != 0) {
! 508: sc->sc_ramdac[BT463_REG_CMAP_DATA] = *r++;
! 509: sc->sc_ramdac[BT463_REG_CMAP_DATA] = *g++;
! 510: sc->sc_ramdac[BT463_REG_CMAP_DATA] = *b++;
! 511: }
! 512: }
! 513:
! 514: /*
! 515: * Initialization code parser
! 516: */
! 517:
! 518: int
! 519: rfx_initialize(struct rfx_softc *sc, struct sbus_attach_args *sa,
! 520: struct rfx_config *cf)
! 521: {
! 522: u_int32_t *data, offset, value;
! 523: size_t cnt;
! 524: bus_space_handle_t bh;
! 525: int error;
! 526:
! 527: /*
! 528: * Map the initialization data
! 529: */
! 530: if ((error = sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset +
! 531: RFX_INIT_ADDR, RFX_INIT_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh)) != 0) {
! 532: printf("\n%s: couldn't map initialization data\n",
! 533: sc->sc_sunfb.sf_dev.dv_xname);
! 534: return error;
! 535: }
! 536: data = (u_int32_t *)bus_space_vaddr(sa->sa_bustag, bh);
! 537:
! 538: /*
! 539: * Skip copyright notice
! 540: */
! 541: data += RFX_INIT_OFFSET / sizeof(u_int32_t);
! 542: cnt = (RFX_INIT_SIZE - RFX_INIT_OFFSET) / sizeof(u_int32_t);
! 543: cnt >>= 1;
! 544:
! 545: /*
! 546: * Parse and apply settings
! 547: */
! 548: while (cnt != 0) {
! 549: offset = *data++;
! 550: value = *data++;
! 551:
! 552: if (offset == (u_int32_t)-1 && value == (u_int32_t)-1)
! 553: break;
! 554:
! 555: /* Old PROM are little-endian */
! 556: if (cf->version <= 1) {
! 557: offset = letoh32(offset);
! 558: value = letoh32(offset);
! 559: }
! 560:
! 561: if (offset & (1 << 31)) {
! 562: offset = (offset & ~(1 << 31)) - RFX_RAMDAC_ADDR;
! 563: if (offset < RFX_RAMDAC_SIZE)
! 564: sc->sc_ramdac[offset] = value >> 24;
! 565: } else {
! 566: offset -= RFX_CONTROL_ADDR;
! 567: if (offset < RFX_CONTROL_SIZE)
! 568: sc->sc_ctrl[offset >> 2] = value;
! 569: }
! 570:
! 571: cnt--;
! 572: }
! 573:
! 574: #ifdef DEBUG
! 575: if (cnt != 0)
! 576: printf("%s: incoherent initialization data!\n");
! 577: #endif
! 578:
! 579: bus_space_unmap(sa->sa_bustag, bh, RFX_INIT_SIZE);
! 580:
! 581: return 0;
! 582: }
CVSweb