[BACK]Return to p9100.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc / dev

Annotation of sys/arch/sparc/dev/p9100.c, Revision 1.1.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