diff options
Diffstat (limited to 'sys/dev/sbus/tvtwo.c')
-rw-r--r-- | sys/dev/sbus/tvtwo.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/sys/dev/sbus/tvtwo.c b/sys/dev/sbus/tvtwo.c new file mode 100644 index 00000000000..09953b6445c --- /dev/null +++ b/sys/dev/sbus/tvtwo.c @@ -0,0 +1,420 @@ +/* $OpenBSD: tvtwo.c,v 1.1 2004/11/29 18:12:51 miod Exp $ */ +/* + * Copyright (c) 2003, Miodrag Vallat. + * 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. + * + * 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. + * + */ + +/* + * Driver for the Parallax XVideo and PowerVideo graphics boards. + * + * Some details about these board are available at: + * http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html + */ + +/* + * The Parallax XVideo series frame buffers are 8/24-bit accelerated + * frame buffers, with hardware MPEG capabilities using a CCube chipset. + */ + +/* + * Currently, this driver can only handle the 24-bit plane of the frame + * buffer, in an unaccelerated mode. + * + * TODO: + * - nvram handling + * - use the accelerator + * - interface to the c^3 + */ + +#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 <uvm/uvm_extern.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/pmap.h> +#include <machine/cpu.h> +#include <machine/conf.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + +#include <dev/sbus/sbusvar.h> + +/* + * The memory layout of the board is as follows: + * + * PROM0 000000 - 00ffff + * overlay plane 010000 - 037fff + * registers 040000 - 0404d0 + * CCube 050000 - 05ffff + * 8-bit plane 080000 - 17ffff + * 24-bit plane 200000 - 6fffff + * PROM1 7f0000 - 7fffff + * + * All of this is mapped using only one register (except for older models + * which are not currently supported). + * At PROM initialization, the board will be in 24-bit mode, so no specific + * initialization is necessary. + */ + +#define PX_PROM0_OFFSET 0x000000 +#define PX_OVERAY_OFFSET 0x010000 +#define PX_REG_OFFSET 0x040000 +#define PX_CCUBE_OFFSET 0x050000 +#define PX_PLANE8_OFFSET 0x080000 +#define PX_PLANE24_OFFSET 0x200000 +#define PX_PROM1_OFFSET 0x7f0000 + +/* + * Partial registers layout + */ + +#define PX_REG_DISPKLUDGE 0x00b8 /* write only */ +#define DISPKLUDGE_DEFAULT 0xc41f +#define DISPKLUDGE_BLANK (1 << 12) + +#define PX_REG_BT463 0x0480 + +#define PX_REG_SIZE 0x04d0 + + +/* per-display variables */ +struct tvtwo_softc { + struct sunfb sc_sunfb; /* common base device */ + struct sbusdev sc_sd; /* sbus device */ + + bus_space_tag_t sc_bustag; + bus_addr_t sc_paddr; + + volatile u_int8_t *sc_regs; + + int sc_nscreens; +}; + +struct wsscreen_descr tvtwo_stdscreen = { + "std", +}; + +const struct wsscreen_descr *tvtwo_scrlist[] = { + &tvtwo_stdscreen, +}; + +struct wsscreen_list tvtwo_screenlist = { + sizeof(tvtwo_scrlist) / sizeof(struct wsscreen_descr *), + tvtwo_scrlist +}; + +int tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *); +int tvtwo_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void tvtwo_free_screen(void *, void *); +int tvtwo_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t tvtwo_mmap(void *, off_t, int); +void tvtwo_burner(void *, u_int, u_int); + +static __inline__ void tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, + u_int32_t addr); +void tvtwo_initcmap(struct tvtwo_softc *); + +struct wsdisplay_accessops tvtwo_accessops = { + tvtwo_ioctl, + tvtwo_mmap, + tvtwo_alloc_screen, + tvtwo_free_screen, + tvtwo_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + tvtwo_burner, +}; + +int tvtwomatch(struct device *, void *, void *); +void tvtwoattach(struct device *, struct device *, void *); + +struct cfattach tvtwo_ca = { + sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach +}; + +struct cfdriver tvtwo_cd = { + NULL, "tvtwo", DV_DULL +}; + +/* + * Default frame buffer resolution, depending upon the "freqcode" + */ +const int defwidth[] = { 1152, 1152, 1152, 1024, 640, 1024 }; +const int defheight[] = { 900, 900, 900, 768, 480, 1024 }; + +/* + * Match an XVideo or PowerVideo card. + */ +int +tvtwomatch(struct device *parent, void *vcf, void *aux) +{ + struct sbus_attach_args *sa = aux; + + if (strcmp(sa->sa_name, "PGI,tvtwo") != 0) + return (0); + + return (1); +} + +/* + * Attach a display. + */ +void +tvtwoattach(struct device *parent, struct device *self, void *args) +{ + struct tvtwo_softc *sc = (struct tvtwo_softc *)self; + struct sbus_attach_args *sa = args; + struct wsemuldisplaydev_attach_args waa; + bus_space_tag_t bt; + bus_space_handle_t bh; + int node, width, height, freqcode; + int isconsole; + char *freqstring; + + bt = sa->sa_bustag; + node = sa->sa_node; + + printf(": %s", getpropstring(node, "model")); + printf(", revision %s\n", getpropstring(node, "revision")); + + /* We do not know how to handle older boards. */ + if (sa->sa_nreg != 1) { + printf("%s: old-style boards with %d registers are not supported\n", + self->dv_xname, sa->sa_nreg); + return; + } + + isconsole = node == fbnode; + + /* Map registers. */ + sc->sc_bustag = bt; + if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_REG_OFFSET, + PX_REG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { + printf("%s: couldn't map registers\n", self->dv_xname); + return; + } + sc->sc_regs = bus_space_vaddr(bt, bh); + + /* Compute framebuffer size. */ + freqstring = getpropstring(node, "freqcode"); + freqcode = (int)*freqstring; + if (freqcode == 'g') + freqcode = '6'; + if (freqcode < '1' || freqcode > '6') + freqcode = 0; + else + freqcode -= '1'; + + width = getpropint(node, "hres", defwidth[freqcode]); + height = getpropint(node, "vres", defheight[freqcode]); + fb_setsize(&sc->sc_sunfb, 32, width, height, + node, 0); + + /* Map the frame buffer memory area we're interested in. */ + sc->sc_paddr = sbus_bus_addr(bt, sa->sa_slot, sa->sa_offset); + if (sbus_bus_map(bt, sa->sa_slot, sa->sa_offset + PX_PLANE24_OFFSET, + round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0, + &bh) != 0) { + printf("%s: couldn't map video memory\n", self->dv_xname); + return; + } + sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); + + /* Initialize a direct color map. */ + tvtwo_initcmap(sc); + + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole ? 0 : RI_CLEAR); + + tvtwo_stdscreen.capabilities = sc->sc_sunfb.sf_ro.ri_caps; + tvtwo_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + tvtwo_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + tvtwo_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; + + printf("%s: %dx%d\n", self->dv_xname, + sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, + &tvtwo_stdscreen, -1, NULL); + } + + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); + + waa.console = isconsole; + waa.scrdata = &tvtwo_screenlist; + waa.accessops = &tvtwo_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); +} + +int +tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p) +{ + struct tvtwo_softc *sc = dev; + struct wsdisplay_fbinfo *wdf; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_SUN24; + break; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 0; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; + break; + + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: + break; + + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); + } + + return (0); +} + +/* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + */ +paddr_t +tvtwo_mmap(void *v, off_t offset, int prot) +{ + struct tvtwo_softc *sc = v; + + if (offset & PGOFSET) + return (-1); + + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, + PX_PLANE24_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR)); + } + + return (-1); +} + +int +tvtwo_alloc_screen(void *v, const struct wsscreen_descr *type, + void **cookiep, int *curxp, int *curyp, long *attrp) +{ + struct tvtwo_softc *sc = v; + + if (sc->sc_nscreens > 0) + return (ENOMEM); + + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + sc->sc_nscreens++; + return (0); +} + +void +tvtwo_free_screen(void *v, void *cookie) +{ + struct tvtwo_softc *sc = v; + + sc->sc_nscreens--; +} + +int +tvtwo_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + return (0); +} + +/* + * Simple Bt463 programming routines. + */ + +static __inline__ void +tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr) +{ + volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463); + + dac[0] = (addr & 0xff); /* lo addr */ + dac[1] = ((addr >> 8) & 0xff); /* hi addr */ +} + +void +tvtwo_initcmap(struct tvtwo_softc *sc) +{ + volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463); + u_int32_t c; + + tvtwo_ramdac_wraddr(sc, 0); + for (c = 0; c < 256; c++) { + dac[3] = c; /* R */ + dac[3] = c; /* G */ + dac[3] = c; /* B */ + } +} + +void +tvtwo_burner(void *v, u_int on, u_int flags) +{ + struct tvtwo_softc *sc = v; + volatile u_int32_t *dispkludge = + (u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUDGE); + + if (on) + *dispkludge = DISPKLUDGE_DEFAULT & ~DISPKLUDGE_BLANK; + else + *dispkludge = DISPKLUDGE_DEFAULT | DISPKLUDGE_BLANK; +} |