Annotation of sys/arch/sparc/dev/p9100.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: p9100.c,v 1.45 2007/07/13 19:18:18 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2003, 2005, 2006, Miodrag Vallat.
! 5: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! 20: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
! 21: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 22: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 23: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 25: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
! 26: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 27: * POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * color display (p9100) driver.
! 32: * Initially based on cgthree.c and the NetBSD p9100 driver, then hacked
! 33: * beyond recognition.
! 34: */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/buf.h>
! 39: #include <sys/device.h>
! 40: #include <sys/ioctl.h>
! 41: #include <sys/malloc.h>
! 42: #include <sys/mman.h>
! 43: #include <sys/tty.h>
! 44: #include <sys/conf.h>
! 45:
! 46: #include <uvm/uvm_extern.h>
! 47:
! 48: #include <machine/autoconf.h>
! 49: #include <machine/bsd_openprom.h>
! 50: #include <machine/pmap.h>
! 51: #include <machine/cpu.h>
! 52: #include <machine/conf.h>
! 53:
! 54: #include <dev/wscons/wsconsio.h>
! 55: #include <dev/wscons/wsdisplayvar.h>
! 56: #include <dev/rasops/rasops.h>
! 57: #include <dev/wsfont/wsfont.h>
! 58: #include <machine/fbvar.h>
! 59:
! 60: #include <sparc/dev/btreg.h>
! 61: #include <sparc/dev/btvar.h>
! 62: #include <sparc/dev/sbusvar.h>
! 63:
! 64: #include <dev/ic/ibm525reg.h>
! 65: #include <dev/ic/p9000.h>
! 66:
! 67: #include "tctrl.h"
! 68: #if NTCTRL > 0
! 69: #include <sparc/dev/tctrlvar.h>
! 70: #endif
! 71:
! 72: #undef FIDDLE_WITH_PCI_REGISTERS
! 73:
! 74: /*
! 75: * SBus registers mappings
! 76: */
! 77: #define P9100_NREG 4
! 78: #define P9100_REG_CTL 0
! 79: #define P9100_REG_CMD 1
! 80: #define P9100_REG_VRAM 2
! 81: #define P9100_REG_CONFIG 3
! 82:
! 83: #ifdef FIDDLE_WITH_PCI_REGISTERS
! 84: /*
! 85: * This structure, mapped at register address 0x9100, allows non-PCI
! 86: * designs (such as the SPARCbook) to access the PCI configuration space.
! 87: */
! 88: struct p9100_pci {
! 89: volatile u_int32_t address; /* within configuration space */
! 90: volatile u_int32_t data; /* _byte_ to read or write */
! 91: };
! 92: #endif
! 93:
! 94: /* per-display variables */
! 95: struct p9100_softc {
! 96: struct sunfb sc_sunfb; /* common base part */
! 97: struct rom_reg sc_phys[P9100_NREG - 1];
! 98: volatile u_int8_t *sc_cmd; /* command registers (dac, etc) */
! 99: volatile u_int8_t *sc_ctl; /* control registers (draw engine) */
! 100: #ifdef FIDDLE_WITH_PCI_REGISTERS
! 101: struct p9100_pci *sc_pci; /* pci configuration space access */
! 102: #endif
! 103: vsize_t sc_vramsize; /* total VRAM available */
! 104: union bt_cmap sc_cmap; /* Brooktree color map */
! 105: struct intrhand sc_ih;
! 106: int sc_mapmode;
! 107: u_int sc_flags;
! 108: #define SCF_INTERNAL 0x01 /* internal video enabled */
! 109: #define SCF_EXTERNAL 0x02 /* external video enabled */
! 110: #if NTCTRL > 0
! 111: #define SCF_MAPPEDSWITCH 0x04 /* switch mode when leaving emul */
! 112: u_int sc_mapwidth; /* non-emul video mode parameters */
! 113: u_int sc_mapheight;
! 114: u_int sc_mapdepth;
! 115: #endif
! 116: u_int sc_lcdheight; /* LCD panel geometry */
! 117: u_int sc_lcdwidth;
! 118:
! 119: u_int32_t sc_junk; /* throwaway value */
! 120: };
! 121:
! 122: void p9100_burner(void *, u_int, u_int);
! 123: void p9100_external_video(void *, int);
! 124: void p9100_initialize_ramdac(struct p9100_softc *, u_int, u_int);
! 125: int p9100_intr(void *);
! 126: int p9100_ioctl(void *, u_long, caddr_t, int, struct proc *);
! 127: static __inline__
! 128: void p9100_loadcmap_deferred(struct p9100_softc *, u_int, u_int);
! 129: void p9100_loadcmap_immediate(struct p9100_softc *, u_int, u_int);
! 130: paddr_t p9100_mmap(void *, off_t, int);
! 131: int p9100_pick_romfont(struct p9100_softc *);
! 132: void p9100_prom(void *);
! 133: void p9100_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
! 134: u_int p9100_read_ramdac(struct p9100_softc *, u_int);
! 135: void p9100_write_ramdac(struct p9100_softc *, u_int, u_int);
! 136:
! 137: struct wsdisplay_accessops p9100_accessops = {
! 138: p9100_ioctl,
! 139: p9100_mmap,
! 140: NULL, /* alloc_screen */
! 141: NULL, /* free_screen */
! 142: NULL, /* show_screen */
! 143: NULL, /* load_font */
! 144: NULL, /* scrollback */
! 145: NULL, /* getchar */
! 146: p9100_burner,
! 147: NULL /* pollc */
! 148: };
! 149:
! 150: void p9100_ras_copycols(void *, int, int, int, int);
! 151: void p9100_ras_copyrows(void *, int, int, int);
! 152: void p9100_ras_do_cursor(struct rasops_info *);
! 153: void p9100_ras_erasecols(void *, int, int, int, long int);
! 154: void p9100_ras_eraserows(void *, int, int, long int);
! 155: void p9100_ras_init(struct p9100_softc *);
! 156:
! 157: int p9100match(struct device *, void *, void *);
! 158: void p9100attach(struct device *, struct device *, void *);
! 159:
! 160: struct cfattach pnozz_ca = {
! 161: sizeof (struct p9100_softc), p9100match, p9100attach
! 162: };
! 163:
! 164: struct cfdriver pnozz_cd = {
! 165: NULL, "pnozz", DV_DULL
! 166: };
! 167:
! 168: /*
! 169: * IBM RGB525 RAMDAC registers
! 170: */
! 171:
! 172: #define IBM525_WRADDR 0 /* Palette write address */
! 173: #define IBM525_DATA 1 /* Palette data */
! 174: #define IBM525_PIXMASK 2 /* Pixel mask */
! 175: #define IBM525_RDADDR 3 /* Read palette address */
! 176: #define IBM525_IDXLOW 4 /* Register index low */
! 177: #define IBM525_IDXHIGH 5 /* Register index high */
! 178: #define IBM525_REGDATA 6 /* Register data */
! 179: #define IBM525_IDXCONTROL 7 /* Index control */
! 180:
! 181: /*
! 182: * P9100 read/write macros
! 183: */
! 184:
! 185: #define P9100_READ_CTL(sc,reg) \
! 186: *(volatile u_int32_t *)((sc)->sc_ctl + (reg))
! 187: #define P9100_READ_CMD(sc,reg) \
! 188: *(volatile u_int32_t *)((sc)->sc_cmd + (reg))
! 189: #define P9100_READ_RAMDAC(sc,reg) \
! 190: (*(volatile u_int32_t *)((sc)->sc_ctl + P9100_RAMDAC_REGISTER(reg)) \
! 191: >> 16)
! 192:
! 193: #define P9100_WRITE_CTL(sc,reg,value) \
! 194: *(volatile u_int32_t *)((sc)->sc_ctl + (reg)) = (value)
! 195: #define P9100_WRITE_CMD(sc,reg,value) \
! 196: *(volatile u_int32_t *)((sc)->sc_cmd + (reg)) = (value)
! 197: #define P9100_WRITE_RAMDAC(sc,reg,value) \
! 198: *(volatile u_int32_t *)((sc)->sc_ctl + P9100_RAMDAC_REGISTER(reg)) = \
! 199: ((value) << 16)
! 200:
! 201: /*
! 202: * On the Tadpole, the first write to a register group is ignored until
! 203: * the proper group address is latched, which can be done by reading from the
! 204: * register group first.
! 205: *
! 206: * Register groups are 0x80 bytes long (i.e. it is necessary to force a read
! 207: * when writing to an address which upper 25 bit differ from the previous
! 208: * read or write operation).
! 209: *
! 210: * This is specific to the Tadpole design, and not a limitation of the
! 211: * Power 9100 hardware.
! 212: */
! 213: #define P9100_SELECT_SCR(sc) \
! 214: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_SYSTEM_CONFIG)
! 215: #define P9100_SELECT_VCR(sc) \
! 216: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_HCR)
! 217: #define P9100_SELECT_VRAM(sc) \
! 218: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_MCR)
! 219: #define P9100_SELECT_DAC(sc) \
! 220: (sc)->sc_junk = P9100_READ_CTL(sc, P9100_RAMDAC_REGISTER(0))
! 221: #define P9100_SELECT_PE(sc) \
! 222: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_PE_STATUS)
! 223: #define P9100_SELECT_DE_LOW(sc) \
! 224: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_DE_FG_COLOR)
! 225: #define P9100_SELECT_DE_HIGH(sc) \
! 226: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_DE_PATTERN(0))
! 227: #define P9100_SELECT_COORD(sc,field) \
! 228: (sc)->sc_junk = P9100_READ_CMD(sc, field)
! 229:
! 230: /*
! 231: * For some reason, every write to a DAC register needs to be followed by a
! 232: * read from the ``free fifo number'' register, supposedly to have the write
! 233: * take effect faster...
! 234: */
! 235: #define P9100_FLUSH_DAC(sc) \
! 236: do { \
! 237: P9100_SELECT_VRAM(sc); \
! 238: (sc)->sc_junk = P9100_READ_CTL(sc, P9100_FREE_FIFO); \
! 239: } while (0)
! 240:
! 241: int
! 242: p9100match(struct device *parent, void *vcf, void *aux)
! 243: {
! 244: struct confargs *ca = aux;
! 245: struct romaux *ra = &ca->ca_ra;
! 246:
! 247: if (strcmp("p9100", ra->ra_name))
! 248: return (0);
! 249:
! 250: return (1);
! 251: }
! 252:
! 253: /*
! 254: * Attach a display.
! 255: */
! 256: void
! 257: p9100attach(struct device *parent, struct device *self, void *args)
! 258: {
! 259: struct p9100_softc *sc = (struct p9100_softc *)self;
! 260: struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
! 261: struct confargs *ca = args;
! 262: struct romaux *ra = &ca->ca_ra;
! 263: int node, pri, scr, force_reset;
! 264: int isconsole, fontswitch, clear = 0;
! 265:
! 266: pri = ca->ca_ra.ra_intr[0].int_pri;
! 267: printf(" pri %d", pri);
! 268:
! 269: #ifdef DIAGNOSTIC
! 270: if (ra->ra_nreg < P9100_NREG) {
! 271: printf(": expected %d registers, got only %d\n",
! 272: P9100_NREG, ra->ra_nreg);
! 273: return;
! 274: }
! 275: #endif
! 276:
! 277: sc->sc_flags = SCF_INTERNAL;
! 278: sc->sc_mapmode = WSDISPLAYIO_MODE_EMUL;
! 279:
! 280: bcopy(ra->ra_reg, sc->sc_phys, sizeof(sc->sc_phys));
! 281:
! 282: sc->sc_ctl = mapiodev(&ra->ra_reg[P9100_REG_CTL], 0,
! 283: ra->ra_reg[P9100_REG_CTL].rr_len);
! 284: sc->sc_cmd = mapiodev(&ra->ra_reg[P9100_REG_CMD], 0,
! 285: ra->ra_reg[P9100_REG_CMD].rr_len);
! 286: #ifdef FIDDLE_WITH_PCI_REGISTERS
! 287: sc->sc_pci = (struct p9100_pci *)
! 288: mapiodev(&ra->ra_reg[P9100_REG_CONFIG], 0,
! 289: ra->ra_reg[P9100_REG_CONFIG].rr_len);
! 290: #endif
! 291:
! 292: node = ra->ra_node;
! 293: isconsole = node == fbnode;
! 294:
! 295: P9100_SELECT_SCR(sc);
! 296: scr = P9100_READ_CTL(sc, P9000_SYSTEM_CONFIG);
! 297: switch (scr & SCR_PIXEL_MASK) {
! 298: default:
! 299: #ifdef DIAGNOSTIC
! 300: printf(": unknown color depth code 0x%x",
! 301: scr & SCR_PIXEL_MASK);
! 302: #endif
! 303: /* FALLTHROUGH */
! 304: case SCR_PIXEL_32BPP:
! 305: case SCR_PIXEL_24BPP:
! 306: case SCR_PIXEL_16BPP:
! 307: force_reset = 1;
! 308: break;
! 309: case SCR_PIXEL_8BPP:
! 310: force_reset = 0;
! 311: break;
! 312: }
! 313:
! 314: fb_setsize(&sc->sc_sunfb, 8, 800, 600, node, ca->ca_bustype);
! 315:
! 316: /*
! 317: * We expect the PROM to initialize us in the best 8 bit mode
! 318: * supported by the LCD (640x480 on 3XP, 800x600 on 3GS/3GX).
! 319: */
! 320: sc->sc_lcdwidth = sc->sc_sunfb.sf_width;
! 321: sc->sc_lcdheight = sc->sc_sunfb.sf_height;
! 322:
! 323: #if NTCTRL > 0
! 324: /*
! 325: * We want to run the frame buffer in 8bpp mode for the emulation mode,
! 326: * and use a potentially better mode for the mapped (X11) mode.
! 327: * Eventually this will become runtime user-selectable.
! 328: */
! 329:
! 330: sc->sc_mapwidth = sc->sc_lcdwidth;
! 331: sc->sc_mapheight = sc->sc_lcdheight;
! 332: sc->sc_mapdepth = 8;
! 333:
! 334: if (sc->sc_mapwidth != sc->sc_sunfb.sf_width ||
! 335: sc->sc_mapdepth != sc->sc_sunfb.sf_depth)
! 336: SET(sc->sc_flags, SCF_MAPPEDSWITCH);
! 337: #endif
! 338:
! 339: ri->ri_bits = mapiodev(&ra->ra_reg[P9100_REG_VRAM], 0,
! 340: sc->sc_vramsize = round_page(ra->ra_reg[P9100_REG_VRAM].rr_len));
! 341: ri->ri_hw = sc;
! 342:
! 343: printf(": rev %x, %dx%d\n", scr & SCR_ID_MASK,
! 344: sc->sc_lcdwidth, sc->sc_lcdheight);
! 345:
! 346: /* Disable frame buffer interrupts */
! 347: P9100_SELECT_SCR(sc);
! 348: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE, IER_MASTER_ENABLE | 0);
! 349:
! 350: sc->sc_ih.ih_fun = p9100_intr;
! 351: sc->sc_ih.ih_arg = sc;
! 352: intr_establish(pri, &sc->sc_ih, IPL_FB, self->dv_xname);
! 353:
! 354: /*
! 355: * Try to get a copy of the PROM font.
! 356: *
! 357: * If we can, we still need to adjust the visible portion of the
! 358: * display, as the PROM output is offset two chars to the left.
! 359: *
! 360: * If we can't, we'll switch to the 8x16 font, and we'll need to adjust
! 361: * two things:
! 362: * - the display row should be overrided from the current PROM metrics,
! 363: * to prevent us from overwriting the last few lines of text.
! 364: * - if the 80x34 screen would make a large margin appear around it,
! 365: * choose to clear the screen rather than keeping old prom output in
! 366: * the margins.
! 367: * XXX there should be a rasops "clear margins" feature
! 368: */
! 369: fontswitch = p9100_pick_romfont(sc);
! 370:
! 371: /*
! 372: * Register the external video control callback with tctrl; tctrl
! 373: * will invoke it immediately to set the appropriate behaviour.
! 374: * If tctrl is not configured, simply enable external video.
! 375: */
! 376: #if NTCTRL > 0
! 377: tadpole_register_extvideo(p9100_external_video, sc);
! 378: #else
! 379: p9100_external_video(sc, 1);
! 380: #endif
! 381:
! 382: if (isconsole == 0 || fontswitch)
! 383: clear = 1;
! 384: fbwscons_init(&sc->sc_sunfb, clear ? RI_CLEAR : 0);
! 385: if (clear == 0) {
! 386: ri->ri_bits -= 2 * ri->ri_xscale;
! 387: ri->ri_xorigin -= 2 * ri->ri_xscale;
! 388: }
! 389: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
! 390:
! 391: /*
! 392: * Plug-in accelerated console operations.
! 393: */
! 394: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
! 395: sc->sc_sunfb.sf_width == 800)
! 396: p9100_ras_init(sc);
! 397:
! 398: /* enable video */
! 399: p9100_burner(sc, 1, 0);
! 400:
! 401: if (isconsole) {
! 402: fbwscons_console_init(&sc->sc_sunfb, clear ? 0 : -1);
! 403: #if NTCTRL > 0
! 404: shutdownhook_establish(p9100_prom, sc);
! 405: #endif
! 406: }
! 407:
! 408: fbwscons_attach(&sc->sc_sunfb, &p9100_accessops, isconsole);
! 409: }
! 410:
! 411: int
! 412: p9100_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
! 413: {
! 414: struct p9100_softc *sc = v;
! 415: struct wsdisplay_fbinfo *wdf;
! 416: struct wsdisplay_cmap *cm;
! 417: #if NTCTRL > 0
! 418: struct wsdisplay_param *dp;
! 419: #endif
! 420: int error;
! 421:
! 422: switch (cmd) {
! 423:
! 424: case WSDISPLAYIO_GTYPE:
! 425: *(u_int *)data = WSDISPLAY_TYPE_SB_P9100;
! 426: break;
! 427:
! 428: case WSDISPLAYIO_SMODE:
! 429: sc->sc_mapmode = *(u_int *)data;
! 430: switch (sc->sc_mapmode) {
! 431: case WSDISPLAYIO_MODE_DUMBFB:
! 432: case WSDISPLAYIO_MODE_MAPPED:
! 433: #if NTCTRL > 0
! 434: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
! 435: p9100_initialize_ramdac(sc,
! 436: sc->sc_mapwidth, sc->sc_mapdepth);
! 437: #endif
! 438: break;
! 439: case WSDISPLAYIO_MODE_EMUL:
! 440: #if NTCTRL > 0
! 441: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
! 442: p9100_initialize_ramdac(sc, sc->sc_lcdwidth, 8);
! 443: #endif
! 444: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
! 445: /* Restore proper acceleration state as well */
! 446: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
! 447: sc->sc_sunfb.sf_width == 800)
! 448: p9100_ras_init(sc);
! 449: break;
! 450: }
! 451: break;
! 452:
! 453: case WSDISPLAYIO_GINFO:
! 454: wdf = (struct wsdisplay_fbinfo *)data;
! 455: #if NTCTRL > 0
! 456: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH)) {
! 457: wdf->width = sc->sc_mapwidth;
! 458: wdf->height = sc->sc_mapheight;
! 459: wdf->depth = sc->sc_mapdepth;
! 460: wdf->cmsize = sc->sc_mapdepth == 8 ? 256 : 0;
! 461: } else
! 462: #endif
! 463: {
! 464: wdf->width = sc->sc_lcdwidth;
! 465: wdf->height = sc->sc_lcdheight;
! 466: wdf->depth = 8;
! 467: wdf->cmsize = 256;
! 468: }
! 469: break;
! 470:
! 471: case WSDISPLAYIO_LINEBYTES:
! 472: #if NTCTRL > 0
! 473: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
! 474: *(u_int *)data = sc->sc_mapwidth *
! 475: (sc->sc_mapdepth / 8);
! 476: else
! 477: #endif
! 478: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
! 479: break;
! 480:
! 481: case WSDISPLAYIO_GETCMAP:
! 482: cm = (struct wsdisplay_cmap *)data;
! 483: error = bt_getcmap(&sc->sc_cmap, cm);
! 484: if (error)
! 485: return (error);
! 486: break;
! 487:
! 488: case WSDISPLAYIO_PUTCMAP:
! 489: cm = (struct wsdisplay_cmap *)data;
! 490: error = bt_putcmap(&sc->sc_cmap, cm);
! 491: if (error)
! 492: return (error);
! 493: p9100_loadcmap_deferred(sc, cm->index, cm->count);
! 494: break;
! 495:
! 496: #if NTCTRL > 0
! 497: case WSDISPLAYIO_GETPARAM:
! 498: dp = (struct wsdisplay_param *)data;
! 499:
! 500: switch (dp->param) {
! 501: case WSDISPLAYIO_PARAM_BRIGHTNESS:
! 502: dp->min = 0;
! 503: dp->max = 255;
! 504: dp->curval = tadpole_get_brightness();
! 505: break;
! 506: case WSDISPLAYIO_PARAM_BACKLIGHT:
! 507: dp->min = 0;
! 508: dp->max = 1;
! 509: if (ISSET(sc->sc_flags, SCF_INTERNAL))
! 510: dp->curval =
! 511: tadpole_get_video() & TV_ON ? 1 : 0;
! 512: else
! 513: dp->curval = 0;
! 514: break;
! 515: default:
! 516: return (-1);
! 517: }
! 518: break;
! 519:
! 520: case WSDISPLAYIO_SETPARAM:
! 521: dp = (struct wsdisplay_param *)data;
! 522:
! 523: switch (dp->param) {
! 524: case WSDISPLAYIO_PARAM_BRIGHTNESS:
! 525: tadpole_set_brightness(dp->curval);
! 526: break;
! 527: case WSDISPLAYIO_PARAM_BACKLIGHT:
! 528: if (ISSET(sc->sc_flags, SCF_INTERNAL))
! 529: tadpole_set_video(dp->curval);
! 530: break;
! 531: default:
! 532: return (-1);
! 533: }
! 534: break;
! 535: #endif /* NTCTRL > 0 */
! 536:
! 537: case WSDISPLAYIO_SVIDEO:
! 538: case WSDISPLAYIO_GVIDEO:
! 539: break;
! 540:
! 541: case WSDISPLAYIO_GCURPOS:
! 542: case WSDISPLAYIO_SCURPOS:
! 543: case WSDISPLAYIO_GCURMAX:
! 544: case WSDISPLAYIO_GCURSOR:
! 545: case WSDISPLAYIO_SCURSOR:
! 546: default:
! 547: return (-1); /* not supported yet */
! 548: }
! 549:
! 550: return (0);
! 551: }
! 552:
! 553: paddr_t
! 554: p9100_mmap(void *v, off_t offset, int prot)
! 555: {
! 556: struct p9100_softc *sc = v;
! 557: struct rom_reg *rr;
! 558:
! 559: if ((offset & PAGE_MASK) != 0)
! 560: return (-1);
! 561:
! 562: switch (sc->sc_mapmode) {
! 563: case WSDISPLAYIO_MODE_MAPPED:
! 564: /*
! 565: * We provide the following mapping:
! 566: * 000000 - 0000ff control registers
! 567: * 002000 - 003fff command registers
! 568: * 800000 - 9fffff vram
! 569: */
! 570: rr = &sc->sc_phys[P9100_REG_CTL];
! 571: if (offset >= 0 && offset < rr->rr_len)
! 572: break;
! 573: offset -= 0x2000;
! 574: rr = &sc->sc_phys[P9100_REG_CMD];
! 575: if (offset >= 0 && offset < rr->rr_len)
! 576: break;
! 577: offset -= (0x800000 - 0x2000);
! 578: /* FALLTHROUGH */
! 579: case WSDISPLAYIO_MODE_DUMBFB:
! 580: rr = &sc->sc_phys[P9100_REG_VRAM];
! 581: if (offset >= 0 && offset < sc->sc_vramsize)
! 582: break;
! 583: /* FALLTHROUGH */
! 584: default:
! 585: return (-1);
! 586: }
! 587:
! 588: return (REG2PHYS(rr, offset) | PMAP_NC);
! 589: }
! 590:
! 591: void
! 592: p9100_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
! 593: {
! 594: struct p9100_softc *sc = v;
! 595: union bt_cmap *bcm = &sc->sc_cmap;
! 596:
! 597: bcm->cm_map[index][0] = r;
! 598: bcm->cm_map[index][1] = g;
! 599: bcm->cm_map[index][2] = b;
! 600: p9100_loadcmap_immediate(sc, index, 1);
! 601: }
! 602:
! 603: void
! 604: p9100_loadcmap_immediate(struct p9100_softc *sc, u_int start, u_int ncolors)
! 605: {
! 606: u_char *p;
! 607:
! 608: P9100_SELECT_DAC(sc);
! 609: P9100_WRITE_RAMDAC(sc, IBM525_WRADDR, start);
! 610: P9100_FLUSH_DAC(sc);
! 611:
! 612: for (p = sc->sc_cmap.cm_map[start], ncolors *= 3; ncolors-- > 0; p++) {
! 613: P9100_SELECT_DAC(sc);
! 614: P9100_WRITE_RAMDAC(sc, IBM525_DATA, (*p));
! 615: P9100_FLUSH_DAC(sc);
! 616: }
! 617: }
! 618:
! 619: static __inline__ void
! 620: p9100_loadcmap_deferred(struct p9100_softc *sc, u_int start, u_int ncolors)
! 621: {
! 622: /* Schedule an interrupt for next retrace */
! 623: P9100_SELECT_SCR(sc);
! 624: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE,
! 625: IER_MASTER_ENABLE | IER_MASTER_INTERRUPT |
! 626: IER_VBLANK_ENABLE | IER_VBLANK_INTERRUPT);
! 627: }
! 628:
! 629: u_int
! 630: p9100_read_ramdac(struct p9100_softc *sc, u_int reg)
! 631: {
! 632: P9100_SELECT_DAC(sc);
! 633:
! 634: P9100_WRITE_RAMDAC(sc, IBM525_IDXLOW, (reg & 0xff));
! 635: P9100_FLUSH_DAC(sc);
! 636: P9100_WRITE_RAMDAC(sc, IBM525_IDXHIGH, ((reg >> 8) & 0xff));
! 637: P9100_FLUSH_DAC(sc);
! 638: return (P9100_READ_RAMDAC(sc, IBM525_REGDATA));
! 639: }
! 640:
! 641: void
! 642: p9100_write_ramdac(struct p9100_softc *sc, u_int reg, u_int value)
! 643: {
! 644: P9100_SELECT_DAC(sc);
! 645:
! 646: P9100_WRITE_RAMDAC(sc, IBM525_IDXLOW, (reg & 0xff));
! 647: P9100_FLUSH_DAC(sc);
! 648: P9100_WRITE_RAMDAC(sc, IBM525_IDXHIGH, ((reg >> 8) & 0xff));
! 649: P9100_FLUSH_DAC(sc);
! 650: P9100_WRITE_RAMDAC(sc, IBM525_REGDATA, value);
! 651: P9100_FLUSH_DAC(sc);
! 652: }
! 653:
! 654: void
! 655: p9100_burner(void *v, u_int on, u_int flags)
! 656: {
! 657: struct p9100_softc *sc = v;
! 658: u_int32_t vcr;
! 659: int s;
! 660:
! 661: s = splhigh();
! 662: P9100_SELECT_VCR(sc);
! 663: vcr = P9100_READ_CTL(sc, P9000_SRTC1);
! 664: if (on)
! 665: vcr |= SRTC1_VIDEN;
! 666: else
! 667: vcr &= ~SRTC1_VIDEN;
! 668: P9100_WRITE_CTL(sc, P9000_SRTC1, vcr);
! 669: #if NTCTRL > 0
! 670: if (ISSET(sc->sc_flags, SCF_INTERNAL))
! 671: tadpole_set_video(on);
! 672: #endif
! 673: splx(s);
! 674: }
! 675:
! 676: int
! 677: p9100_intr(void *v)
! 678: {
! 679: struct p9100_softc *sc = v;
! 680:
! 681: if (P9100_READ_CTL(sc, P9000_INTERRUPT) & IER_VBLANK_INTERRUPT) {
! 682: p9100_loadcmap_immediate(sc, 0, 256);
! 683:
! 684: /* Disable further interrupts now */
! 685: /* P9100_SELECT_SCR(sc); */
! 686: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE,
! 687: IER_MASTER_ENABLE | 0);
! 688:
! 689: /* Clear interrupt condition */
! 690: P9100_WRITE_CTL(sc, P9000_INTERRUPT,
! 691: IER_VBLANK_ENABLE | 0);
! 692:
! 693: return (1);
! 694: }
! 695:
! 696: return (0);
! 697: }
! 698:
! 699: /*
! 700: * Accelerated text console code
! 701: */
! 702:
! 703: static int p9100_drain(struct p9100_softc *);
! 704:
! 705: static int
! 706: p9100_drain(struct p9100_softc *sc)
! 707: {
! 708: u_int i;
! 709:
! 710: for (i = 10000; i !=0; i--) {
! 711: if ((P9100_READ_CMD(sc, P9000_PE_STATUS) &
! 712: (STATUS_QUAD_BUSY | STATUS_BLIT_BUSY)) == 0)
! 713: break;
! 714: }
! 715:
! 716: return (i);
! 717: }
! 718:
! 719: void
! 720: p9100_ras_init(struct p9100_softc *sc)
! 721: {
! 722:
! 723: if (p9100_drain(sc) == 0)
! 724: return;
! 725:
! 726: sc->sc_sunfb.sf_ro.ri_ops.copycols = p9100_ras_copycols;
! 727: sc->sc_sunfb.sf_ro.ri_ops.copyrows = p9100_ras_copyrows;
! 728: sc->sc_sunfb.sf_ro.ri_ops.erasecols = p9100_ras_erasecols;
! 729: sc->sc_sunfb.sf_ro.ri_ops.eraserows = p9100_ras_eraserows;
! 730: sc->sc_sunfb.sf_ro.ri_do_cursor = p9100_ras_do_cursor;
! 731:
! 732: /*
! 733: * Setup safe defaults for the parameter and drawing engines, in
! 734: * order to minimize the operations to do for ri_ops.
! 735: */
! 736:
! 737: P9100_SELECT_DE_LOW(sc);
! 738: P9100_WRITE_CMD(sc, P9000_DE_DRAWMODE,
! 739: DM_PICK_CONTROL | 0 | DM_BUFFER_CONTROL | DM_BUFFER_ENABLE0);
! 740:
! 741: P9100_WRITE_CMD(sc, P9000_DE_PATTERN_ORIGIN_X, 0);
! 742: P9100_WRITE_CMD(sc, P9000_DE_PATTERN_ORIGIN_Y, 0);
! 743: /* enable all planes */
! 744: P9100_WRITE_CMD(sc, P9000_DE_PLANEMASK, 0xffffffff);
! 745:
! 746: /* Unclip */
! 747: P9100_WRITE_CMD(sc, P9000_DE_WINMIN, 0);
! 748: P9100_WRITE_CMD(sc, P9000_DE_WINMAX,
! 749: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
! 750:
! 751: P9100_SELECT_DE_HIGH(sc);
! 752: P9100_WRITE_CMD(sc, P9100_DE_B_WINMIN, 0);
! 753: P9100_WRITE_CMD(sc, P9100_DE_B_WINMAX,
! 754: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
! 755:
! 756: P9100_SELECT_PE(sc);
! 757: P9100_WRITE_CMD(sc, P9000_PE_WINOFFSET, 0);
! 758: P9100_WRITE_CMD(sc, P9000_PE_INDEX, 0);
! 759: P9100_WRITE_CMD(sc, P9000_PE_WINMIN, 0);
! 760: P9100_WRITE_CMD(sc, P9000_PE_WINMAX,
! 761: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
! 762: }
! 763:
! 764: void
! 765: p9100_ras_copycols(void *v, int row, int src, int dst, int n)
! 766: {
! 767: struct rasops_info *ri = v;
! 768: struct p9100_softc *sc = ri->ri_hw;
! 769:
! 770: n *= ri->ri_font->fontwidth;
! 771: n--;
! 772: src *= ri->ri_font->fontwidth;
! 773: src += ri->ri_xorigin;
! 774: dst *= ri->ri_font->fontwidth;
! 775: dst += ri->ri_xorigin;
! 776: row *= ri->ri_font->fontheight;
! 777: row += ri->ri_yorigin;
! 778:
! 779: p9100_drain(sc);
! 780: P9100_SELECT_DE_LOW(sc);
! 781: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
! 782: P9100_RASTER_SRC & P9100_RASTER_MASK);
! 783:
! 784: P9100_SELECT_COORD(sc, P9000_DC_COORD(0));
! 785: P9100_WRITE_CMD(sc, P9000_DC_COORD(0) + P9000_COORD_XY,
! 786: P9000_COORDS(src, row));
! 787: P9100_WRITE_CMD(sc, P9000_DC_COORD(1) + P9000_COORD_XY,
! 788: P9000_COORDS(src + n, row + ri->ri_font->fontheight - 1));
! 789: P9100_SELECT_COORD(sc, P9000_DC_COORD(2));
! 790: P9100_WRITE_CMD(sc, P9000_DC_COORD(2) + P9000_COORD_XY,
! 791: P9000_COORDS(dst, row));
! 792: P9100_WRITE_CMD(sc, P9000_DC_COORD(3) + P9000_COORD_XY,
! 793: P9000_COORDS(dst + n, row + ri->ri_font->fontheight - 1));
! 794:
! 795: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_BLIT);
! 796:
! 797: p9100_drain(sc);
! 798: }
! 799:
! 800: void
! 801: p9100_ras_copyrows(void *v, int src, int dst, int n)
! 802: {
! 803: struct rasops_info *ri = v;
! 804: struct p9100_softc *sc = ri->ri_hw;
! 805:
! 806: n *= ri->ri_font->fontheight;
! 807: n--;
! 808: src *= ri->ri_font->fontheight;
! 809: src += ri->ri_yorigin;
! 810: dst *= ri->ri_font->fontheight;
! 811: dst += ri->ri_yorigin;
! 812:
! 813: p9100_drain(sc);
! 814: P9100_SELECT_DE_LOW(sc);
! 815: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
! 816: P9100_RASTER_SRC & P9100_RASTER_MASK);
! 817:
! 818: P9100_SELECT_COORD(sc, P9000_DC_COORD(0));
! 819: P9100_WRITE_CMD(sc, P9000_DC_COORD(0) + P9000_COORD_XY,
! 820: P9000_COORDS(ri->ri_xorigin, src));
! 821: P9100_WRITE_CMD(sc, P9000_DC_COORD(1) + P9000_COORD_XY,
! 822: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth - 1, src + n));
! 823: P9100_SELECT_COORD(sc, P9000_DC_COORD(2));
! 824: P9100_WRITE_CMD(sc, P9000_DC_COORD(2) + P9000_COORD_XY,
! 825: P9000_COORDS(ri->ri_xorigin, dst));
! 826: P9100_WRITE_CMD(sc, P9000_DC_COORD(3) + P9000_COORD_XY,
! 827: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth - 1, dst + n));
! 828:
! 829: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_BLIT);
! 830:
! 831: p9100_drain(sc);
! 832: }
! 833:
! 834: void
! 835: p9100_ras_erasecols(void *v, int row, int col, int n, long int attr)
! 836: {
! 837: struct rasops_info *ri = v;
! 838: struct p9100_softc *sc = ri->ri_hw;
! 839: int fg, bg;
! 840:
! 841: ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
! 842: bg = ri->ri_devcmap[bg];
! 843:
! 844: n *= ri->ri_font->fontwidth;
! 845: col *= ri->ri_font->fontwidth;
! 846: col += ri->ri_xorigin;
! 847: row *= ri->ri_font->fontheight;
! 848: row += ri->ri_yorigin;
! 849:
! 850: p9100_drain(sc);
! 851: P9100_SELECT_DE_LOW(sc);
! 852: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
! 853: P9100_RASTER_PATTERN & P9100_RASTER_MASK);
! 854: P9100_WRITE_CMD(sc, P9100_DE_COLOR0, P9100_COLOR8(bg));
! 855:
! 856: P9100_SELECT_COORD(sc, P9000_LC_RECT);
! 857: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 858: P9000_COORDS(col, row));
! 859: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 860: P9000_COORDS(col + n, row + ri->ri_font->fontheight));
! 861:
! 862: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
! 863:
! 864: p9100_drain(sc);
! 865: }
! 866:
! 867: void
! 868: p9100_ras_eraserows(void *v, int row, int n, long int attr)
! 869: {
! 870: struct rasops_info *ri = v;
! 871: struct p9100_softc *sc = ri->ri_hw;
! 872: int fg, bg;
! 873:
! 874: ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
! 875: bg = ri->ri_devcmap[bg];
! 876:
! 877: p9100_drain(sc);
! 878: P9100_SELECT_DE_LOW(sc);
! 879: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
! 880: P9100_RASTER_PATTERN & P9100_RASTER_MASK);
! 881: P9100_WRITE_CMD(sc, P9100_DE_COLOR0, P9100_COLOR8(bg));
! 882:
! 883: P9100_SELECT_COORD(sc, P9000_LC_RECT);
! 884: if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
! 885: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 886: P9000_COORDS(0, 0));
! 887: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 888: P9000_COORDS(ri->ri_width, ri->ri_height));
! 889: } else {
! 890: n *= ri->ri_font->fontheight;
! 891: row *= ri->ri_font->fontheight;
! 892: row += ri->ri_yorigin;
! 893:
! 894: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 895: P9000_COORDS(ri->ri_xorigin, row));
! 896: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 897: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth, row + n));
! 898: }
! 899:
! 900: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
! 901:
! 902: p9100_drain(sc);
! 903: }
! 904:
! 905: void
! 906: p9100_ras_do_cursor(struct rasops_info *ri)
! 907: {
! 908: struct p9100_softc *sc = ri->ri_hw;
! 909: int row, col;
! 910:
! 911: row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
! 912: col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
! 913:
! 914: p9100_drain(sc);
! 915:
! 916: P9100_SELECT_DE_LOW(sc);
! 917: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
! 918: (P9100_RASTER_PATTERN ^ P9100_RASTER_DST) & P9100_RASTER_MASK);
! 919: P9100_WRITE_CMD(sc, P9100_DE_COLOR0,
! 920: P9100_COLOR8(ri->ri_devcmap[WSCOL_BLACK]));
! 921:
! 922: P9100_SELECT_COORD(sc, P9000_LC_RECT);
! 923: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 924: P9000_COORDS(col, row));
! 925: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
! 926: P9000_COORDS(col + ri->ri_font->fontwidth,
! 927: row + ri->ri_font->fontheight));
! 928:
! 929: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
! 930:
! 931: p9100_drain(sc);
! 932: }
! 933:
! 934: /*
! 935: * PROM font managment
! 936: */
! 937:
! 938: #define ROMFONTNAME "p9100_romfont"
! 939: struct wsdisplay_font p9100_romfont = {
! 940: ROMFONTNAME,
! 941: 0,
! 942: 0, 256,
! 943: WSDISPLAY_FONTENC_ISO, /* should check the `character-set' property */
! 944: 0, 0, 0,
! 945: WSDISPLAY_FONTORDER_L2R,
! 946: WSDISPLAY_FONTORDER_L2R,
! 947: NULL,
! 948: NULL
! 949: };
! 950:
! 951: int
! 952: p9100_pick_romfont(struct p9100_softc *sc)
! 953: {
! 954: struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
! 955: int *romwidth, *romheight;
! 956: u_int8_t **romaddr;
! 957: char buf[200];
! 958:
! 959: /*
! 960: * This code currently only works for PROM >= 2.9; see
! 961: * autoconf.c romgetcursoraddr() for details.
! 962: */
! 963: if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
! 964: return (1);
! 965:
! 966: /*
! 967: * Get the PROM font metrics and address
! 968: */
! 969: if (snprintf(buf, sizeof buf, "stdout @ is my-self "
! 970: "addr char-height %lx ! addr char-width %lx ! addr font-base %lx !",
! 971: (vaddr_t)&romheight, (vaddr_t)&romwidth, (vaddr_t)&romaddr) >=
! 972: sizeof buf)
! 973: return (1);
! 974: romheight = romwidth = NULL;
! 975: rominterpret(buf);
! 976:
! 977: if (romheight == NULL || romwidth == NULL || romaddr == NULL ||
! 978: *romheight == 0 || *romwidth == 0 || *romaddr == NULL)
! 979: return (1);
! 980:
! 981: p9100_romfont.fontwidth = *romwidth;
! 982: p9100_romfont.fontheight = *romheight;
! 983: p9100_romfont.stride = howmany(*romwidth, NBBY);
! 984: p9100_romfont.data = *romaddr;
! 985:
! 986: #ifdef DEBUG
! 987: printf("%s: PROM font %dx%d @%p",
! 988: sc->sc_sunfb.sf_dev.dv_xname, *romwidth, *romheight, *romaddr);
! 989: #endif
! 990:
! 991: /*
! 992: * Build and add a wsfont structure
! 993: */
! 994: wsfont_init(); /* if not done before */
! 995: if (wsfont_add(&p9100_romfont, 0) != 0)
! 996: return (1);
! 997:
! 998: /*
! 999: * Select this very font in our rasops structure
! 1000: */
! 1001: ri->ri_wsfcookie = wsfont_find(ROMFONTNAME, 0, 0, 0);
! 1002: if (wsfont_lock(ri->ri_wsfcookie, &ri->ri_font,
! 1003: WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
! 1004: ri->ri_wsfcookie = 0;
! 1005: return (1);
! 1006: }
! 1007:
! 1008: return (0);
! 1009: }
! 1010:
! 1011: /*
! 1012: * External video control
! 1013: */
! 1014:
! 1015: void
! 1016: p9100_external_video(void *v, int on)
! 1017: {
! 1018: struct p9100_softc *sc = v;
! 1019: int s;
! 1020:
! 1021: s = splhigh();
! 1022:
! 1023: if (on) {
! 1024: p9100_write_ramdac(sc, IBM525_POWER,
! 1025: p9100_read_ramdac(sc, IBM525_POWER) & ~P_DAC_PWR_DISABLE);
! 1026: SET(sc->sc_flags, SCF_EXTERNAL);
! 1027: } else {
! 1028: p9100_write_ramdac(sc, IBM525_POWER,
! 1029: p9100_read_ramdac(sc, IBM525_POWER) | P_DAC_PWR_DISABLE);
! 1030: CLR(sc->sc_flags, SCF_EXTERNAL);
! 1031: }
! 1032:
! 1033: splx(s);
! 1034: }
! 1035:
! 1036: /*
! 1037: * Video mode programming
! 1038: *
! 1039: * All magic values come from s3gxtrmb.pdf.
! 1040: */
! 1041:
! 1042: #if NTCTRL > 0
! 1043:
! 1044: /* IBM RGB525 registers and values */
! 1045:
! 1046: static const u_int8_t p9100_dacreg[] = {
! 1047: IBM525_MISC1,
! 1048: IBM525_MISC2,
! 1049: IBM525_MISC3,
! 1050: IBM525_MISC4,
! 1051: IBM525_MISC_CLOCK,
! 1052: IBM525_SYNC,
! 1053: IBM525_HSYNC_POS,
! 1054: IBM525_POWER,
! 1055: IBM525_DAC_OP,
! 1056: IBM525_PALETTE,
! 1057: IBM525_PIXEL,
! 1058: IBM525_PF8,
! 1059: IBM525_PF16,
! 1060: IBM525_PF24,
! 1061: IBM525_PF32,
! 1062: IBM525_PLL1,
! 1063: IBM525_PLL2,
! 1064: IBM525_PLL_FIXED_REF,
! 1065: IBM525_SYSCLK,
! 1066: IBM525_PLL_REF_DIV,
! 1067: IBM525_PLL_VCO_DIV,
! 1068: 0
! 1069: };
! 1070:
! 1071: static u_int8_t p9100_dacval[] = {
! 1072: M1_SENSE_DISABLE | M1_VRAM_64,
! 1073: M2_PCLK_PLL | M2_PALETTE_8 | M2_MODE_VRAM,
! 1074: 0,
! 1075: 0, /* will be computed */
! 1076: MC_B24P_SCLK | MC_PLL_ENABLE, /* will be modified */
! 1077: S_HSYN_NORMAL | S_VSYN_NORMAL,
! 1078: 0,
! 1079: 0, /* will be computed */
! 1080: DO_FAST_SLEW,
! 1081: 0,
! 1082: 0, /* will be computed */
! 1083: PF8_INDIRECT,
! 1084: PF16_DIRECT | PF16_LINEAR | PF16_565,
! 1085: PF24_DIRECT,
! 1086: PF32_DIRECT,
! 1087: P1_CLK_REF | P1_SRC_EXT_F | P1_SRC_DIRECT_F,
! 1088: 0, /* F0, will be set before */
! 1089: 5,
! 1090: SC_ENABLE,
! 1091: 5,
! 1092: MHZ_TO_PLL(50)
! 1093: };
! 1094:
! 1095: /* Power 9100 registers and values */
! 1096:
! 1097: static const u_int32_t p9100_reg[] = {
! 1098: P9000_HTR,
! 1099: P9000_HSRE,
! 1100: P9000_HBRE,
! 1101: P9000_HBFE,
! 1102: P9000_HCP,
! 1103: P9000_VL,
! 1104: P9000_VSRE,
! 1105: P9000_VBRE,
! 1106: P9000_VBFE,
! 1107: P9000_VCP,
! 1108: 0
! 1109: };
! 1110:
! 1111: static const u_int32_t p9100_val_800_32[] = {
! 1112: 0x1f3, 0x023, 0x053, 0x1e3, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
! 1113: };
! 1114: #if 0 /* No X server for this mode, yet */
! 1115: static const u_int32_t p9100_val_800_24[] = {
! 1116: 0x176, 0x01a, 0x03d, 0x169, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
! 1117: };
! 1118: #endif
! 1119: static const u_int32_t p9100_val_800_8[] = {
! 1120: 0x07c, 0x008, 0x011, 0x075, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
! 1121: };
! 1122: #if NTCTRL > 0
! 1123: static const u_int32_t p9100_val_640_32[] = {
! 1124: 0x18f, 0x02f, 0x043, 0x183, 0x000, 0x205, 0x003, 0x022, 0x202, 0x000
! 1125: };
! 1126: static const u_int32_t p9100_val_640_8[] = {
! 1127: 0x063, 0x00b, 0x00d, 0x05d, 0x000, 0x205, 0x003, 0x022, 0x202, 0x000
! 1128: };
! 1129: static const u_int32_t p9100_val_1024_8[] = {
! 1130: 0x0a7, 0x019, 0x022, 0x0a2, 0x000, 0x325, 0x003, 0x023, 0x323, 0x000
! 1131: };
! 1132: #endif
! 1133:
! 1134: void
! 1135: p9100_initialize_ramdac(struct p9100_softc *sc, u_int width, u_int depth)
! 1136: {
! 1137: int s;
! 1138: const u_int8_t *dacregp, *dacvalp;
! 1139: const u_int32_t *p9regp, *p9valp;
! 1140: u_int8_t pllclk, dacval;
! 1141: u_int32_t scr;
! 1142:
! 1143: /*
! 1144: * XXX Switching to a low-res 8bpp mode causes kernel faults
! 1145: * XXX unless coming from an high-res 8bpp mode, and I have
! 1146: * XXX no idea why.
! 1147: */
! 1148: if (depth == 8 && width != 1024)
! 1149: p9100_initialize_ramdac(sc, 1024, 8);
! 1150:
! 1151: switch (width) {
! 1152: case 1024:
! 1153: p9valp = p9100_val_1024_8;
! 1154: pllclk = MHZ_TO_PLL(65);
! 1155: /* 1024 bytes scanline */
! 1156: scr = SCR_SC(0, 0, 0, 1) | SCR_PIXEL_8BPP;
! 1157: break;
! 1158: default:
! 1159: /* FALLTHROUGH */
! 1160: case 800:
! 1161: switch (depth) {
! 1162: case 32:
! 1163: p9valp = p9100_val_800_32;
! 1164: /* 3200 = 128 + 1024 + 2048 bytes scanline */
! 1165: scr = SCR_SC(3, 6, 7, 0) |
! 1166: SCR_PIXEL_32BPP | SCR_SWAP_WORDS | SCR_SWAP_BYTES;
! 1167: break;
! 1168: #if 0
! 1169: case 24:
! 1170: p9valp = p9100_val_800_24;
! 1171: /* 2400 = 32 + 64 + 256 + 2048 bytes scanline */
! 1172: scr = SCR_SC(1, 2, 4, 2) | SCR_PIXEL_24BPP;
! 1173: break;
! 1174: #endif
! 1175: default:
! 1176: case 8:
! 1177: p9valp = p9100_val_800_8;
! 1178: /* 800 = 32 + 256 + 512 bytes scanline */
! 1179: scr = SCR_SC(1, 4, 5, 0) | SCR_PIXEL_8BPP;
! 1180: break;
! 1181: }
! 1182: pllclk = MHZ_TO_PLL(36);
! 1183: break;
! 1184: case 640:
! 1185: switch (depth) {
! 1186: case 32:
! 1187: p9valp = p9100_val_640_32;
! 1188: /* 2560 = 512 + 2048 bytes scanline */
! 1189: scr = SCR_SC(5, 7, 0, 0) |
! 1190: SCR_PIXEL_32BPP | SCR_SWAP_WORDS | SCR_SWAP_BYTES;
! 1191: break;
! 1192: default:
! 1193: case 8:
! 1194: p9valp = p9100_val_640_8;
! 1195: /* 640 = 128 + 512 bytes scanline */
! 1196: scr = SCR_SC(3, 5, 0, 0) | SCR_PIXEL_8BPP;
! 1197: break;
! 1198: }
! 1199: pllclk = MHZ_TO_PLL(25);
! 1200: break;
! 1201: }
! 1202: dacvalp = p9100_dacval;
! 1203:
! 1204: s = splhigh();
! 1205:
! 1206: #ifdef FIDDLE_WITH_PCI_REGISTERS
! 1207: /*
! 1208: * Magical initialization sequence, from s3gxtrmb.pdf.
! 1209: * DANGER! Sometimes freezes the machine solid, cause unknown.
! 1210: */
! 1211: sc->sc_pci->address = 0x13000000;
! 1212: sc->sc_pci->data = 0;
! 1213: sc->sc_pci->address = 0x30000000;
! 1214: sc->sc_pci->data = 0;
! 1215: sc->sc_pci->address = 0x41000000;
! 1216: sc->sc_pci->data = 0; /* No register mapping at a0000 */
! 1217: sc->sc_pci->address = 0x04000000;
! 1218: sc->sc_pci->data = 0xa3000000;
! 1219: #endif
! 1220:
! 1221: /*
! 1222: * Initialize the RAMDAC
! 1223: */
! 1224: P9100_SELECT_DAC(sc);
! 1225: P9100_WRITE_RAMDAC(sc, IBM525_PIXMASK, 0xff);
! 1226: P9100_FLUSH_DAC(sc);
! 1227: P9100_WRITE_RAMDAC(sc, IBM525_IDXCONTROL, 0x00);
! 1228: P9100_FLUSH_DAC(sc);
! 1229:
! 1230: p9100_write_ramdac(sc, IBM525_F(0), pllclk);
! 1231: for (dacregp = p9100_dacreg; *dacregp != 0; dacregp++, dacvalp++) {
! 1232: switch (*dacregp) {
! 1233: case IBM525_MISC4:
! 1234: dacval = pllclk >= MHZ_TO_PLL(50) ?
! 1235: M4_FAST : M4_INVERT_DCLK;
! 1236: break;
! 1237: case IBM525_MISC_CLOCK:
! 1238: dacval = *dacvalp & ~MC_DDOT_DIV_MASK;
! 1239: switch (depth) {
! 1240: case 32:
! 1241: dacval |= MC_DDOT_DIV_2;
! 1242: break;
! 1243: case 16:
! 1244: dacval |= MC_DDOT_DIV_4;
! 1245: break;
! 1246: default:
! 1247: case 24:
! 1248: case 8:
! 1249: dacval |= MC_DDOT_DIV_8;
! 1250: break;
! 1251: }
! 1252: break;
! 1253: case IBM525_POWER:
! 1254: if (depth == 24)
! 1255: dacval = 0;
! 1256: else
! 1257: dacval = P_SCLK_DISABLE;
! 1258: break;
! 1259: case IBM525_PIXEL:
! 1260: switch (depth) {
! 1261: case 32:
! 1262: dacval = PIX_32BPP;
! 1263: break;
! 1264: case 24:
! 1265: dacval = PIX_24BPP;
! 1266: break;
! 1267: case 16:
! 1268: dacval = PIX_16BPP;
! 1269: break;
! 1270: default:
! 1271: case 8:
! 1272: dacval = PIX_8BPP;
! 1273: break;
! 1274: }
! 1275: break;
! 1276: default:
! 1277: dacval = *dacvalp;
! 1278: break;
! 1279: }
! 1280: p9100_write_ramdac(sc, *dacregp, dacval);
! 1281: }
! 1282:
! 1283: /*
! 1284: * Initialize the Power 9100
! 1285: */
! 1286:
! 1287: P9100_SELECT_SCR(sc);
! 1288: P9100_WRITE_CTL(sc, P9000_SYSTEM_CONFIG, scr);
! 1289: P9100_SELECT_VCR(sc);
! 1290: P9100_WRITE_CTL(sc, P9000_SRTC1,
! 1291: SRTC1_VSYNC_INTERNAL | SRTC1_HSYNC_INTERNAL | SRTC1_VIDEN | 0x03);
! 1292: P9100_WRITE_CTL(sc, P9000_SRTC2, 0x05);
! 1293: P9100_SELECT_VRAM(sc);
! 1294: P9100_WRITE_CTL(sc, P9000_MCR, 0xc808007d);
! 1295: delay(3000);
! 1296:
! 1297: P9100_SELECT_VCR(sc);
! 1298: for (p9regp = p9100_reg; *p9regp != 0; p9regp++, p9valp++)
! 1299: P9100_WRITE_CTL(sc, *p9regp, *p9valp);
! 1300:
! 1301: P9100_SELECT_VRAM(sc);
! 1302: P9100_WRITE_CTL(sc, P9000_REFRESH_PERIOD, 0x3ff);
! 1303:
! 1304: /* Disable frame buffer interrupts */
! 1305: P9100_SELECT_SCR(sc);
! 1306: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE, IER_MASTER_ENABLE | 0);
! 1307:
! 1308: /*
! 1309: * Enable internal video... (it's a kind of magic)
! 1310: */
! 1311: p9100_write_ramdac(sc, IBM525_MISC4,
! 1312: p9100_read_ramdac(sc, IBM525_MISC4) | 0xc0);
! 1313:
! 1314: /*
! 1315: * ... unless it does not fit.
! 1316: */
! 1317: if (width != sc->sc_lcdwidth) {
! 1318: CLR(sc->sc_flags, SCF_INTERNAL);
! 1319: tadpole_set_video(0);
! 1320: } else {
! 1321: SET(sc->sc_flags, SCF_INTERNAL);
! 1322: tadpole_set_video(1);
! 1323: }
! 1324:
! 1325: p9100_external_video(sc, ISSET(sc->sc_flags, SCF_EXTERNAL));
! 1326:
! 1327: splx(s);
! 1328: }
! 1329:
! 1330: void
! 1331: p9100_prom(void *v)
! 1332: {
! 1333: struct p9100_softc *sc = v;
! 1334:
! 1335: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH) &&
! 1336: sc->sc_mapmode != WSDISPLAYIO_MODE_EMUL) {
! 1337: p9100_initialize_ramdac(sc, sc->sc_lcdwidth, 8);
! 1338: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
! 1339: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
! 1340: sc->sc_sunfb.sf_width == 800)
! 1341: p9100_ras_init(sc);
! 1342: }
! 1343: }
! 1344: #endif /* NTCTRL > 0 */
CVSweb