diff options
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r-- | sys/arch/sparc/dev/p9100.c | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/sys/arch/sparc/dev/p9100.c b/sys/arch/sparc/dev/p9100.c new file mode 100644 index 00000000000..418f17be99f --- /dev/null +++ b/sys/arch/sparc/dev/p9100.c @@ -0,0 +1,483 @@ +/* $OpenBSD: p9100.c,v 1.1 1999/09/06 03:46:16 jason Exp $ */ + +/* + * Copyright (c) 1999 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * color display (p9100) driver. Based on cgthree.c and the NetBSD + * p9100 driver. + * + * Does not handle interrupts, even though they can occur. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/mman.h> +#include <sys/tty.h> +#include <sys/conf.h> + +#include <vm/vm.h> + +#include <machine/fbio.h> +#include <machine/autoconf.h> +#include <machine/pmap.h> +#include <machine/fbvar.h> +#include <machine/cpu.h> +#include <machine/conf.h> + +#include <sparc/dev/btreg.h> +#include <sparc/dev/btvar.h> +#include <sparc/dev/sbusvar.h> + +/* per-display variables */ +struct p9100_softc { + struct device sc_dev; /* base device */ + struct sbusdev sc_sd; /* sbus device */ + struct fbdevice sc_fb; /* frame buffer device */ + struct rom_reg sc_phys; /* phys address description */ + struct p9100_cmd *sc_cmd; /* command registers (dac, etc) */ + struct p9100_ctl *sc_ctl; /* control registers (draw engine) */ + union bt_cmap sc_cmap; /* Brooktree color map */ + u_int32_t sc_junk; /* throwaway value */ +}; + +/* autoconfiguration driver */ +void p9100attach(struct device *, struct device *, void *); +int p9100match(struct device *, void *, void *); +void p9100unblank(struct device *); + +/* cdevsw prototypes */ +cdev_decl(p9100); + +struct cfattach pnozz_ca = { + sizeof(struct p9100_softc), p9100match, p9100attach +}; + +struct cfdriver pnozz_cd = { + NULL, "pnozz", DV_DULL +}; + +/* frame buffer generic driver */ +struct fbdriver p9100fbdriver = { + p9100unblank, p9100open, p9100close, p9100ioctl, p9100mmap +}; + +extern int fbnode; +extern struct tty *fbconstty; + +void p9100loadcmap __P((struct p9100_softc *, int, int)); +void p9100_set_video __P((struct p9100_softc *, int)); +int p9100_get_video __P((struct p9100_softc *)); + +/* + * System control and command registers + * (IBM RGB528 RamDac, p9100, video coprocessor) + */ +struct p9100_ctl { + /* System control registers: 0x0000 - 0x00ff */ + struct p9100_scr { + volatile u_int32_t unused0; + volatile u_int32_t scr; /* system config reg */ + volatile u_int32_t ir; /* interrupt reg */ + volatile u_int32_t ier; /* interrupt enable */ + volatile u_int32_t arbr; /* alt read bank reg */ + volatile u_int32_t awbr; /* alt write bank reg */ + volatile u_int32_t unused1[58]; + } ctl_scr; + + /* Video control registers: 0x0100 - 0x017f */ + struct p9100_vcr { + volatile u_int32_t unused0; + volatile u_int32_t hcr; /* horizontal cntr */ + volatile u_int32_t htr; /* horizontal total */ + volatile u_int32_t hsre; /* horiz sync rising */ + volatile u_int32_t hbre; /* horiz blank rising */ + volatile u_int32_t hbfe; /* horiz blank fallng */ + volatile u_int32_t hcp; /* horiz cntr preload */ + volatile u_int32_t vcr; /* vertical cntr */ + volatile u_int32_t vl; /* vertical length */ + volatile u_int32_t vsre; /* vert sync rising */ + volatile u_int32_t vbre; /* vert blank rising */ + volatile u_int32_t vbfe; /* vert blank fallng */ + volatile u_int32_t vcp; /* vert cntr preload */ + volatile u_int32_t sra; /* scrn repaint addr */ + volatile u_int32_t srtc1; /* scrn rpnt time 1 */ + volatile u_int32_t qsf; /* qsf counter */ + volatile u_int32_t srtc2; /* scrn rpnt time 2 */ + volatile u_int32_t unused1[15]; + } ctl_vcr; + + /* VRAM control registers: 0x0180 - 0x1ff */ + struct p9100_vram { + volatile u_int32_t unused0; + volatile u_int32_t mc; /* memory config */ + volatile u_int32_t rp; /* refresh period */ + volatile u_int32_t rc; /* refresh count */ + volatile u_int32_t rasmax; /* ras low maximum */ + volatile u_int32_t rascur; /* ras low current */ + volatile u_int32_t unused1[26]; + } ctl_vram; + + /* IBM RGB528 RAMDAC registers: 0x0200 - 0x3ff */ + struct p9100_dac { + volatile u_int32_t pwraddr; /* wr palette address */ + volatile u_int32_t paldata; /* palette data */ + volatile u_int32_t pixmask; /* pixel mask */ + volatile u_int32_t prdaddr; /* rd palette address */ + volatile u_int32_t idxlow; /* reg index low */ + volatile u_int32_t idxhigh; /* reg index high */ + volatile u_int32_t regdata; /* register data */ + volatile u_int32_t idxctrl; /* index control */ + volatile u_int32_t unused1[120]; + } ctl_dac; + + /* Video coprocessor interface: 0x0400 - 0x1fff */ + volatile u_int32_t ctl_vci[768]; +}; + +#define SRTC1_VIDEN 0x00000020 + + +/* + * Select the appropriate register group within the control registers + * (must be done before any write to a register within the group, but + * subsquent writes to the same group do not need to reselect). + */ +#define P9100_SELECT_SCR(sc) ((sc)->sc_junk = (sc)->sc_ctl->ctl_scr.scr) +#define P9100_SELECT_VCR(sc) ((sc)->sc_junk = (sc)->sc_ctl->ctl_vcr.hcr) +#define P9100_SELECT_VRAM(sc) ((sc)->sc_junk = (sc)->sc_ctl->ctl_vram.mc) +#define P9100_SELECT_DAC(sc) ((sc)->sc_junk = (sc)->sc_ctl->ctl_dac.pwraddr) +#define P9100_SELECT_VCI(sc) ((sc)->sc_junk = (sc)->sc_ctl->ctl_vci[0]) + +/* + * Drawing engine + */ +struct p9100_cmd { + volatile u_int32_t cmd_regs[0x800]; +}; + +int +p9100match(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct confargs *ca = aux; + register struct romaux *ra = &ca->ca_ra; + + if (strcmp("p9100", ra->ra_name)) + return (0); + return (1); +} + +/* + * Attach a display. We need to notice if it is the console, too. + */ +void +p9100attach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct p9100_softc *sc = (struct p9100_softc *)self; + struct confargs *ca = args; + int node = 0, i; + int isconsole; + char *cp; + + sc->sc_fb.fb_driver = &p9100fbdriver; + sc->sc_fb.fb_device = &sc->sc_dev; + sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK; + sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; + + sc->sc_phys = ca->ca_ra.ra_reg[2]; + + sc->sc_ctl = mapiodev(&(ca->ca_ra.ra_reg[0]), 0, + ca->ca_ra.ra_reg[0].rr_len); + sc->sc_cmd = mapiodev(&(ca->ca_ra.ra_reg[1]), 0, + ca->ca_ra.ra_reg[1].rr_len); + + /* + * When the ROM has mapped in a p9100 display, the address + * maps only the video RAM, so in any case we have to map the + * registers ourselves. We only need the video RAM if we are + * going to print characters via rconsole. + */ + node = ca->ca_ra.ra_node; + isconsole = node == fbnode && fbconstty != NULL; + if (ca->ca_ra.ra_nvaddrs > 0) + sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddrs[0]; + if (isconsole && sc->sc_fb.fb_pixels == NULL) + sc->sc_fb.fb_pixels = mapiodev(&(ca->ca_ra.ra_reg[2]), 0, + ca->ca_ra.ra_reg[2].rr_len); + + P9100_SELECT_SCR(sc); + i = sc->sc_ctl->ctl_scr.scr; + printf(":%08x", i); + switch ((i >> 26) & 7) { + case 5: + sc->sc_fb.fb_type.fb_depth = 32; + break; + case 7: + sc->sc_fb.fb_type.fb_depth = 24; + break; + case 3: + sc->sc_fb.fb_type.fb_depth = 16; + break; + case 2: + default: + sc->sc_fb.fb_type.fb_depth = 8; + break; + } + fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, 800, 600, + node, ca->ca_bustype); + + sbus_establish(&sc->sc_sd, &sc->sc_dev); + + sc->sc_fb.fb_type.fb_cmsize = getpropint(node, "cmsize", 256); + sc->sc_fb.fb_type.fb_size = + sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; + printf(": rev %x, %d x %d, depth %d", i, + sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height, + sc->sc_fb.fb_type.fb_depth); + + /* initialize color map */ + cp = &sc->sc_cmap.cm_map[0][0]; + cp[0] = cp[1] = cp[2] = 0; + for (i = 1, cp = &sc->sc_cmap.cm_map[i][0]; + i < sc->sc_fb.fb_type.fb_cmsize; cp += 3, i++) + cp[0] = cp[1] = cp[2] = 0xff; + p9100loadcmap(sc, 0, 256); + + /* make sure we are not blanked */ + p9100_set_video(sc, 1); + + if (isconsole) { + printf(" (console)\n"); +#ifdef RASTERCONSOLE + for (i = 0 ; i < sc->sc_fb.fb_type.fb_size; i++) { + if (sc->sc_fb.fb_pixels[i] == 0) { + sc->sc_fb.fb_pixels[i] = 1; + } else if (sc->sc_fb.fb_pixels[i] == (char) 255) { + sc->sc_fb.fb_pixels[i] = 0; + } + } + p9100loadcmap(sc, 255, 1); + fbrcons_init(&sc->sc_fb); +#endif + } else + printf("\n"); + + if (node == fbnode) + fb_attach(&sc->sc_fb, isconsole); +} + +int +p9100open(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + int unit = minor(dev); + + if (unit >= pnozz_cd.cd_ndevs || pnozz_cd.cd_devs[unit] == NULL) + return (ENXIO); + return (0); +} + +int +p9100close(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + return (0); +} + +int +p9100ioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)]; + struct fbgattr *fba; + int error; + + switch (cmd) { + + case FBIOGTYPE: + *(struct fbtype *)data = sc->sc_fb.fb_type; + break; + + case FBIOGATTR: + fba = (struct fbgattr *)data; + fba->real_type = sc->sc_fb.fb_type.fb_type; + fba->owner = 0; /* XXX ??? */ + fba->fbtype = sc->sc_fb.fb_type; + fba->sattr.flags = 0; + fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; + fba->sattr.dev_specific[0] = -1; + fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; + fba->emu_types[1] = -1; + break; + + case FBIOGETCMAP: + return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); + + case FBIOPUTCMAP: + /* copy to software map */ +#define p ((struct fbcmap *)data) + error = bt_putcmap(p, &sc->sc_cmap, 256); + if (error) + return (error); + /* now blast them into the chip */ + /* XXX should use retrace interrupt */ + p9100loadcmap(sc, p->index, p->count); +#undef p + break; + + case FBIOGVIDEO: + *(int *)data = p9100_get_video(sc); + break; + + case FBIOSVIDEO: + p9100_set_video(sc, *(int *)data); + break; + + default: + return (ENOTTY); + } + return (0); +} + +/* + * Undo the effect of an FBIOSVIDEO that turns the video off. + */ +void +p9100unblank(dev) + struct device *dev; +{ + p9100_set_video((struct p9100_softc *)dev, 1); +} + +void +p9100_set_video(sc, enable) + struct p9100_softc *sc; + int enable; +{ + u_int32_t v; + + P9100_SELECT_VCR(sc); + v = sc->sc_ctl->ctl_vcr.srtc1; + if (enable) + v |= SRTC1_VIDEN; + else + v &= ~SRTC1_VIDEN; + sc->sc_ctl->ctl_vcr.srtc1 = v; +} + +int +p9100_get_video(sc) + struct p9100_softc *sc; +{ + return ((sc->sc_ctl->ctl_vcr.srtc1 & SRTC1_VIDEN) != 0); +} + +/* + * Load a subset of the current (new) colormap into the Brooktree DAC. + */ +void +p9100loadcmap(sc, start, ncolors) + struct p9100_softc *sc; + int start, ncolors; +{ + u_char *p; + + P9100_SELECT_VRAM(sc); + P9100_SELECT_VRAM(sc); + sc->sc_junk = sc->sc_ctl->ctl_dac.pwraddr; + sc->sc_ctl->ctl_dac.pwraddr = start << 16; + + for (p = sc->sc_cmap.cm_map[start], ncolors *= 3; ncolors-- > 0; p++) { + /* These generate a short delay between ramdac writes */ + P9100_SELECT_VRAM(sc); + P9100_SELECT_VRAM(sc); + + sc->sc_junk = sc->sc_ctl->ctl_dac.paldata; + sc->sc_ctl->ctl_dac.paldata = (*p) << 16; + } +} + +/* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + * + * The cg3 is mapped starting at 256KB, for pseudo-compatibility with + * the cg4 (which had an overlay plane in the first 128K and an enable + * plane in the next 128K). X11 uses only 256k+ region but tries to + * map the whole thing, so we repeatedly map the first 256K to the + * first page of the color screen. If someone tries to use the overlay + * and enable regions, they will get a surprise.... + * + * As well, mapping at an offset of 0x04000000 causes the cg3 to be + * mapped in flat mode without the cg4 emulation. + */ +int +p9100mmap(dev, off, prot) + dev_t dev; + int off, prot; +{ + struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)]; +#define START (128*1024 + 128*1024) +#define NOOVERLAY (0x04000000) + + if (off & PGOFSET) + panic("p9100mmap"); + + if (off < 0) + return (-1); +#define CG3_MMAP_OFFSET 0x04000000 + /* + * Make Xsun think we are a CG3 (SUN3COLOR) + */ + if ((u_int)off >= CG3_MMAP_OFFSET && + (u_int)off < CG3_MMAP_OFFSET + 0x00200000) { + off -= CG3_MMAP_OFFSET; + return (REG2PHYS(&sc->sc_phys, off | PMAP_NC)); + } + + return (-1); +} |