summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64/dev/gfxp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sparc64/dev/gfxp.c')
-rw-r--r--sys/arch/sparc64/dev/gfxp.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/sys/arch/sparc64/dev/gfxp.c b/sys/arch/sparc64/dev/gfxp.c
new file mode 100644
index 00000000000..771c7542afa
--- /dev/null
+++ b/sys/arch/sparc64/dev/gfxp.c
@@ -0,0 +1,324 @@
+/* $OpenBSD: gfxp.c,v 1.1 2009/06/03 21:35:28 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2009 Mark Kettenis.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/pciio.h>
+#include <sys/systm.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/openfirm.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+
+#include <dev/rasops/rasops.h>
+
+#include <machine/fbvar.h>
+
+#define PM2_PCI_MMIO 0x10 /* Registers */
+#define PM2_PCI_MEM_LE 0x14 /* Framebuffer (little-endian) */
+#define PM2_PCI_MEM_BE 0x18 /* Framebuffer (big-endian) */
+
+/*
+ * The Permedia 2 provides two views into its 64k register file. The
+ * first view is little-endian, the second is big-endian and
+ * immediately follows the little-endian view.
+*/
+#define PM2_REG_SIZE 0x10000
+#define PM2_REG_OFF PM2_REG_SIZE
+
+#define PM2_IN_FIFO_SPACE 0x0018
+
+
+#ifdef APERTURE
+extern int allowaperture;
+#endif
+
+struct gfxp_softc {
+ struct sunfb sc_sunfb;
+
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+ bus_addr_t sc_membase_le;
+ bus_size_t sc_memsize_le;
+ bus_addr_t sc_membase_be;
+ bus_size_t sc_memsize_be;
+
+ bus_space_tag_t sc_mmiot;
+ bus_space_handle_t sc_mmioh;
+ bus_addr_t sc_mmiobase;
+ bus_size_t sc_mmiosize;
+
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
+ pcitag_t sc_pcitag;
+
+ int sc_mode;
+};
+
+int gfxp_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t gfxp_mmap(void *, off_t, int);
+
+struct wsdisplay_accessops gfxp_accessops = {
+ gfxp_ioctl,
+ gfxp_mmap,
+ NULL, /* alloc_screen */
+ NULL, /* free_screen */
+ NULL, /* show_screen */
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ NULL, /* burner */
+ NULL /* pollc */
+};
+
+int gfxp_match(struct device *, void *, void *);
+void gfxp_attach(struct device *, struct device *, void *);
+
+struct cfattach gfxp_ca = {
+ sizeof(struct gfxp_softc), gfxp_match, gfxp_attach
+};
+
+struct cfdriver gfxp_cd = {
+ NULL, "gfxp", DV_DULL
+};
+
+int gfxp_is_console(int);
+
+void gfxp_copycols(void *, int, int, int, int);
+void gfxp_erasecols(void *, int, int, int, long);
+void gfxp_copyrows(void *, int, int, int);
+void gfxp_eraserows(void *, int, int, long);
+
+void gfxp_init(struct gfxp_softc *);
+int gfxp_wait(struct gfxp_softc *);
+int gfxp_wait_fifo(struct gfxp_softc *, int);
+void gfxp_copyrect(struct gfxp_softc *, int, int, int, int, int, int);
+void gfxp_fillrect(struct gfxp_softc *, int, int, int, int, int);
+
+int
+gfxp_match(struct device *parent, void *cf, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+ int node;
+ char *name;
+
+ node = PCITAG_NODE(pa->pa_tag);
+ name = getpropstring(node, "name");
+ if (strcmp(name, "TECH-SOURCE,gfxp") == 0 ||
+ strcmp(name, "TSI,gfxp") == 0)
+ return (10);
+
+ return (0);
+}
+
+void
+gfxp_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct gfxp_softc *sc = (struct gfxp_softc *)self;
+ struct pci_attach_args *pa = aux;
+ struct rasops_info *ri;
+ int node, console;
+ char *model;
+
+ sc->sc_pcitag = pa->pa_tag;
+
+ node = PCITAG_NODE(pa->pa_tag);
+ console = gfxp_is_console(node);
+
+ printf("\n");
+
+ model = getpropstring(node, "model");
+ printf("%s: %s", self->dv_xname, model);
+
+ if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PM2_PCI_MEM_LE,
+ PCI_MAPREG_TYPE_MEM, &sc->sc_membase_le, &sc->sc_memsize_le, NULL))
+ sc->sc_memsize_le = 0;
+
+ if (pci_mapreg_map(pa, PM2_PCI_MEM_BE, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
+ &sc->sc_membase_be, &sc->sc_memsize_be, 0)) {
+ printf("\n%s: can't map video memory\n", self->dv_xname);
+ return;
+ }
+
+ if (pci_mapreg_map(pa, PM2_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
+ &sc->sc_mmiosize, 0)) {
+ bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize_be);
+ printf("\n%s: can't map mmio\n", self->dv_xname);
+ return;
+ }
+
+ sc->sc_regt = sc->sc_mmiot;
+#if 1
+ sc->sc_regh = sc->sc_mmioh;
+#else
+ if (bus_space_subregion(sc->sc_mmiot, sc->sc_mmioh,
+ PM2_REG_OFF, PM2_REG_SIZE, &sc->sc_regh)) {
+ printf("\n%s: can't map registers\n", self->dv_xname);
+ return;
+ }
+#endif
+
+ fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
+
+ printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
+
+ ri = &sc->sc_sunfb.sf_ro;
+ ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh);
+ ri->ri_hw = sc;
+
+ ri->ri_rnum = 8;
+ ri->ri_rpos = 16;
+ ri->ri_gnum = 8;
+ ri->ri_gpos = 8;
+ ri->ri_bnum = 8;
+ ri->ri_bpos = 0;
+
+ fbwscons_init(&sc->sc_sunfb, 0, console);
+ sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
+
+ if (console)
+ fbwscons_console_init(&sc->sc_sunfb, -1);
+ fbwscons_attach(&sc->sc_sunfb, &gfxp_accessops, console);
+}
+
+int
+gfxp_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct gfxp_softc *sc = v;
+ struct wsdisplay_fbinfo *wdf;
+ struct pcisel *sel;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_GFXP;
+ break;
+ case WSDISPLAYIO_SMODE:
+ sc->sc_mode = *(u_int *)data;
+ break;
+ case WSDISPLAYIO_GINFO:
+ wdf = (void *)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_GETSUPPORTEDDEPTH:
+ *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
+ break;
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = sc->sc_sunfb.sf_linebytes;
+ break;
+
+ case WSDISPLAYIO_GPCIID:
+ sel = (struct pcisel *)data;
+ sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
+ sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
+ sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
+ break;
+
+ case WSDISPLAYIO_SVIDEO:
+ case WSDISPLAYIO_GVIDEO:
+ break;
+
+ case WSDISPLAYIO_GCURPOS:
+ case WSDISPLAYIO_SCURPOS:
+ case WSDISPLAYIO_GCURMAX:
+ case WSDISPLAYIO_GCURSOR:
+ case WSDISPLAYIO_SCURSOR:
+ case WSDISPLAYIO_GETCMAP:
+ case WSDISPLAYIO_PUTCMAP:
+ default:
+ return -1; /* not supported yet */
+ }
+
+ return (0);
+}
+
+paddr_t
+gfxp_mmap(void *v, off_t off, int prot)
+{
+ struct gfxp_softc *sc = v;
+
+ if (off & PGOFSET)
+ return (-1);
+
+ switch (sc->sc_mode) {
+ case WSDISPLAYIO_MODE_MAPPED:
+#ifdef APERTURE
+ if (allowaperture == 0)
+ return (-1);
+#endif
+
+ if (sc->sc_mmiosize == 0)
+ return (-1);
+
+ if (off >= sc->sc_membase_be &&
+ off < (sc->sc_membase_be + sc->sc_memsize_be))
+ return (bus_space_mmap(sc->sc_memt,
+ sc->sc_membase_be, off - sc->sc_membase_be,
+ prot, BUS_SPACE_MAP_LINEAR));
+
+ if (off >= sc->sc_mmiobase &&
+ off < (sc->sc_mmiobase + sc->sc_mmiosize))
+ return (bus_space_mmap(sc->sc_mmiot,
+ sc->sc_mmiobase, off - sc->sc_mmiobase,
+ prot, BUS_SPACE_MAP_LINEAR));
+ break;
+
+ case WSDISPLAYIO_MODE_DUMBFB:
+ if (off >= 0 && off < sc->sc_memsize_le)
+ return (bus_space_mmap(sc->sc_memt, sc->sc_membase_le,
+ off, prot, BUS_SPACE_MAP_LINEAR));
+ break;
+ }
+
+ return (-1);
+}
+
+int
+gfxp_is_console(int node)
+{
+ extern int fbnode;
+
+ return (fbnode == node);
+}
+
+int
+gfxp_wait_fifo(struct gfxp_softc *sc, int n)
+{
+ int i;
+
+ for (i = 1000000; i != 0; i--) {
+ if (bus_space_read_4(sc->sc_regt, sc->sc_regh,
+ PM2_IN_FIFO_SPACE) >= n)
+ break;
+ DELAY(1);
+ }
+
+ return i;
+}