[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     ! 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