summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-06-02 04:12:12 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-06-02 04:12:12 +0000
commit22a00d3c977d7c4f74bfa05966a5def227e6d748 (patch)
tree10912a42f9e05248e61123035b31c02908b43994 /sys/arch/sparc64
parent2d6c4bbf119ecf4fe2007f3a2634ae931cd242e1 (diff)
Initial stab at an accelerated driver for PGX/PGX64 framebuffers.
Inspiration from the NetBSD, Linux and X.org drivers.
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/dev/machfb.c789
1 files changed, 789 insertions, 0 deletions
diff --git a/sys/arch/sparc64/dev/machfb.c b/sys/arch/sparc64/dev/machfb.c
new file mode 100644
index 00000000000..1c69fffad31
--- /dev/null
+++ b/sys/arch/sparc64/dev/machfb.c
@@ -0,0 +1,789 @@
+/* $OpenBSD: machfb.c,v 1.1 2009/06/02 04:12:11 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 M64_PCI_MEM 0x10
+#define M64_PCI_MMIO 0x18
+
+#define M64_REG_OFF 0x007ffc00
+#define M64_REG_SIZE 0x0400
+
+#define M64_CRTC_INT_CNTL 0x0018
+
+#define M64_BUS_CNTL 0x00a0
+#define M64_BUS_FIFO_ERR_ACK 0x00200000
+#define M64_BUS_HOST_ERR_ACK 0x00800000
+#define M64_BUS_APER_REG_DIS 0x00000010
+
+#define M64_DAC_WINDEX 0x00c0
+#define M64_DAC_DATA 0x00c1
+#define M64_DAC_MASK 0x00c2
+#define M64_DAC_RINDEX 0x00c3
+#define M64_DAC_CNTL 0x00c4
+#define M64_DAC_8BIT_EN 0x00000100
+
+#define M64_GEN_TEST_CNTL 0x00d0
+#define M64_GEN_GUI_EN 0x00000100
+
+#define M64_DST_OFF_PITCH 0x0100
+#define M64_DST_X 0x0104
+#define M64_DST_Y 0x0108
+#define M64_DST_Y_X 0x010c
+#define M64_DST_WIDTH 0x0110
+#define M64_DST_HEIGHT 0x0114
+#define M64_DST_HEIGHT_WIDTH 0x0118
+#define M64_DST_X_WIDTH 0x011c
+#define M64_DST_BRES_LNTH 0x0120
+#define M64_DST_BRES_ERR 0x0124
+#define M64_DST_BRES_INC 0x0128
+#define M64_DST_BRES_DEC 0x012c
+#define M64_DST_CNTL 0x0130
+#define M64_DST_X_RIGHT_TO_LEFT 0x00000000
+#define M64_DST_X_LEFT_TO_RIGHT 0x00000001
+#define M64_DST_Y_BOTTOM_TO_TOP 0x00000000
+#define M64_DST_Y_TOP_TO_BOTTOM 0x00000002
+#define M64_DST_X_MAJOR 0x00000000
+#define M64_DST_Y_MAJOR 0x00000004
+#define M64_DST_X_TILE 0x00000008
+#define M64_DST_Y_TILE 0x00000010
+#define M64_DST_LAST_PEL 0x00000020
+#define M64_DST_POLYGON_EN 0x00000040
+#define M64_DST_24_ROT_EN 0x00000080
+
+#define M64_SRC_OFF_PITCH 0x0180
+#define M64_SRC_X 0x0184
+#define M64_SRC_Y 0x0188
+#define M64_SRC_Y_X 0x018c
+#define M64_SRC_WIDTH1 0x0190
+#define M64_SRC_HEIGHT1 0x0194
+#define M64_SRC_HEIGHT1_WIDTH1 0x0198
+#define M64_SRC_X_START 0x019c
+#define M64_SRC_Y_START 0x01a0
+#define M64_SRC_Y_X_START 0x01a4
+#define M64_SRC_WIDTH2 0x01a8
+#define M64_SRC_HEIGHT2 0x01ac
+#define M64_SRC_HEIGHT2_WIDTH2 0x01b0
+#define M64_SRC_CNTL 0x01b4
+#define M64_SRC_PATT_EN 0x00000001
+#define M64_SRC_PATT_ROT_EN 0x00000002
+#define M64_SRC_LINEAR_EN 0x00000004
+#define M64_SRC_BYTE_ALIGN 0x00000008
+#define M64_SRC_LINE_X_RIGHT_TO_LEFT 0x00000000
+#define M64_SRC_LINE_X_LEFT_TO_RIGHT 0x00000010
+
+#define M64_HOST_CNTL 0x0240
+
+#define M64_PAT_REG0 0x0280
+#define M64_PAT_REG1 0x0284
+#define M64_PAT_CNTL 0x0288
+
+#define M64_SC_LEFT 0x02a0
+#define M64_SC_RIGHT 0x02a4
+#define M64_SC_LEFT_RIGHT 0x02a8
+#define M64_SC_TOP 0x02ac
+#define M64_SC_BOTTOM 0x02b0
+#define M64_SC_TOP_BOTTOM 0x02b4
+
+#define M64_DP_BKGD_CLR 0x02c0
+#define M64_DP_FRGD_CLR 0x02c4
+#define M64_DP_WRITE_MASK 0x02c8
+
+#define M64_DP_CHAIN_MASK 0x02cc
+#define M64_DP_CHAIN_8BPP 0x00008080
+#define M64_DP_PIX_WIDTH 0x02d0
+#define M64_DST_8BPP 0x00000002
+#define M64_SRC_8BPP 0x00000200
+#define M64_HOST_8BPP 0x00020000
+#define M64_DP_MIX 0x02d4
+#define M64_MIX_DST 0x00000003
+#define M64_MIX_SRC 0x00000007
+#define M64_DP_SRC 0x02d8
+#define M64_BKGD_SRC_BKGD_CLR 0x00000000
+#define M64_BKGD_SRC_FRGD_CLR 0x00000001
+#define M64_BKGD_SRC_HOST 0x00000002
+#define M64_BKGD_SRC_BLIT 0x00000003
+#define M64_BKGD_SRC_PATTERN 0x00000004
+#define M64_FRGD_SRC_BKGD_CLR 0x00000000
+#define M64_FRGD_SRC_FRGD_CLR 0x00000100
+#define M64_FRGD_SRC_HOST 0x00000200
+#define M64_FRGD_SRC_BLIT 0x00000300
+#define M64_FRGD_SRC_PATTERN 0x00000400
+#define M64_MONO_SRC_ONE 0x00000000
+#define M64_MONO_SRC_PATTERN 0x00010000
+#define M64_MONO_SRC_HOST 0x00020000
+#define M64_MONO_SRC_BLIT 0x00030000
+
+#define M64_CLR_CMP_CLR 0x0300
+#define M64_CLR_CMP_MASK 0x0304
+#define M64_CLR_CMP_CNTL 0x0308
+
+#define M64_FIFO_STAT 0x0310
+#define M64_FIFO_STAT_MASK 0x0000ffff
+
+#define M64_CONTEXT_MASK 0x0320
+
+#define M64_GUI_TRAJ_CNTL 0x0330
+#define M64_GUI_STAT 0x0338
+#define M64_GUI_ACTIVE 0x00000001
+
+#define M64_COORDS(x, y) ((x << 16) | (y))
+
+#ifdef APERTURE
+extern int allowaperture;
+#endif
+
+struct machfb_softc {
+ struct sunfb sc_sunfb;
+
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+ bus_addr_t sc_membase;
+ bus_size_t sc_memsize;
+
+ bus_space_tag_t sc_regt;
+ bus_space_handle_t sc_regh;
+
+ bus_space_tag_t sc_mmiot;
+ bus_space_handle_t sc_mmioh;
+ bus_addr_t sc_mmiobase;
+ bus_size_t sc_mmiosize;
+
+ pcitag_t sc_pcitag;
+
+ int sc_mode;
+ u_int8_t sc_cmap_red[256];
+ u_int8_t sc_cmap_green[256];
+ u_int8_t sc_cmap_blue[256];
+
+ int sc_ofhandle;
+};
+
+int machfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t machfb_mmap(void *, off_t, int);
+
+struct wsdisplay_accessops machfb_accessops = {
+ machfb_ioctl,
+ machfb_mmap,
+ NULL, /* alloc_screen */
+ NULL, /* free_screen */
+ NULL, /* show_screen */
+ NULL, /* load_font */
+ NULL, /* scrollback */
+ NULL, /* getchar */
+ NULL, /* burner */
+ NULL /* pollc */
+};
+
+int machfb_match(struct device *, void *, void *);
+void machfb_attach(struct device *, struct device *, void *);
+
+struct cfattach machfb_ca = {
+ sizeof(struct machfb_softc), machfb_match, machfb_attach
+};
+
+struct cfdriver machfb_cd = {
+ NULL, "machfb", DV_DULL
+};
+
+int machfb_is_console(int);
+int machfb_getcmap(struct machfb_softc *, struct wsdisplay_cmap *);
+int machfb_putcmap(struct machfb_softc *, struct wsdisplay_cmap *);
+void machfb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
+
+void machfb_copycols(void *, int, int, int, int);
+void machfb_erasecols(void *, int, int, int, long);
+void machfb_copyrows(void *, int, int, int);
+void machfb_eraserows(void *, int, int, long);
+
+void machfb_init(struct machfb_softc *);
+int machfb_wait_fifo(struct machfb_softc *, int);
+int machfb_wait(struct machfb_softc *);
+void machfb_copyrect(struct machfb_softc *, int, int, int, int, int, int);
+void machfb_fillrect(struct machfb_softc *, int, int, int, int, int);
+
+int
+machfb_match(struct device *parent, void *cf, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+ char buf[32];
+ int node;
+
+ node = PCITAG_NODE(pa->pa_tag);
+ OF_getprop(node, "name", buf, sizeof(buf));
+ if (strcmp(buf, "SUNW,m64B") == 0)
+ return (10);
+
+ if (OF_getprop(node, "compatible", buf, sizeof(buf)) > 0 &&
+ strcmp(buf, "SUNW,m64B") == 0)
+ return (10);
+
+ return (0);
+}
+
+void
+machfb_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct machfb_softc *sc = (struct machfb_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 = machfb_is_console(node);
+
+ printf("\n");
+
+ model = getpropstring(node, "model");
+ printf("%s: %s", self->dv_xname, model);
+
+ if (pci_mapreg_map(pa, M64_PCI_MEM, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
+ &sc->sc_membase, &sc->sc_memsize, 0)) {
+ printf("\n%s: can't map video memory\n", self->dv_xname);
+ return;
+ }
+
+ sc->sc_regt = sc->sc_memt;
+ if (bus_space_subregion(sc->sc_memt, sc->sc_memh,
+ M64_REG_OFF, M64_REG_SIZE, &sc->sc_regh)) {
+ printf("\n%s: can't map registers\n", self->dv_xname);
+ return;
+ }
+
+ if (pci_mapreg_map(pa, M64_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
+ &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
+ &sc->sc_mmiosize, 0)) {
+ printf("\n%s: can't map registers\n", self->dv_xname);
+ return;
+ }
+
+ fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
+ if (sc->sc_sunfb.sf_depth == 24) {
+ sc->sc_sunfb.sf_depth = 32;
+ sc->sc_sunfb.sf_linebytes =
+ (sc->sc_sunfb.sf_depth / 8) * sc->sc_sunfb.sf_width;
+ sc->sc_sunfb.sf_fbsize =
+ sc->sc_sunfb.sf_height * sc->sc_sunfb.sf_linebytes;
+ }
+
+ 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;
+
+ fbwscons_init(&sc->sc_sunfb, RI_BSWAP, console);
+
+ if (console) {
+ sc->sc_ofhandle = OF_stdout();
+ fbwscons_setcolormap(&sc->sc_sunfb, machfb_setcolor);
+ }
+
+ sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
+
+ machfb_init(sc);
+ ri->ri_ops.copyrows = machfb_copyrows;
+ ri->ri_ops.copycols = machfb_copycols;
+ ri->ri_ops.eraserows = machfb_eraserows;
+ ri->ri_ops.erasecols = machfb_erasecols;
+
+ if (console)
+ fbwscons_console_init(&sc->sc_sunfb, -1);
+ fbwscons_attach(&sc->sc_sunfb, &machfb_accessops, console);
+}
+
+int
+machfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct machfb_softc *sc = v;
+ struct wsdisplay_fbinfo *wdf;
+ struct pcisel *sel;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
+ break;
+ case WSDISPLAYIO_SMODE:
+ sc->sc_mode = *(u_int *)data;
+ if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)
+ fbwscons_setcolormap(&sc->sc_sunfb, machfb_setcolor);
+ 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 = 256;
+ break;
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = sc->sc_sunfb.sf_linebytes;
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ return machfb_getcmap(sc, (struct wsdisplay_cmap *)data);
+ case WSDISPLAYIO_PUTCMAP:
+ return machfb_putcmap(sc, (struct wsdisplay_cmap *)data);
+
+ 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:
+ default:
+ return -1; /* not supported yet */
+ }
+
+ return (0);
+}
+
+paddr_t
+machfb_mmap(void *v, off_t off, int prot)
+{
+ struct machfb_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 &&
+ off < (sc->sc_membase + sc->sc_memsize))
+ return (bus_space_mmap(sc->sc_memt,
+ sc->sc_membase, off - sc->sc_membase,
+ 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)
+ return (bus_space_mmap(sc->sc_memt, sc->sc_membase,
+ off, prot, BUS_SPACE_MAP_LINEAR));
+ break;
+ }
+
+ return (-1);
+}
+
+int
+machfb_is_console(int node)
+{
+ extern int fbnode;
+
+ return (fbnode == node);
+}
+
+int
+machfb_getcmap(struct machfb_softc *sc, struct wsdisplay_cmap *cm)
+{
+ u_int index = cm->index;
+ u_int count = cm->count;
+ int error;
+
+ if (index >= 256 || count > 256 - index)
+ return (EINVAL);
+
+ error = copyout(&sc->sc_cmap_red[index], cm->red, count);
+ if (error)
+ return (error);
+ error = copyout(&sc->sc_cmap_green[index], cm->green, count);
+ if (error)
+ return (error);
+ error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
+ if (error)
+ return (error);
+ return (0);
+}
+
+int
+machfb_putcmap(struct machfb_softc *sc, struct wsdisplay_cmap *cm)
+{
+ u_int index = cm->index;
+ u_int count = cm->count;
+ u_int i;
+ int error;
+ u_char *r, *g, *b;
+
+ if (index >= 256 || count > 256 - index)
+ return (EINVAL);
+
+ if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
+ return (error);
+ if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
+ return (error);
+ if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
+ return (error);
+
+ r = &sc->sc_cmap_red[index];
+ g = &sc->sc_cmap_green[index];
+ b = &sc->sc_cmap_blue[index];
+
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_MASK, 0xff);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_WINDEX, 0);
+ for (i = 0; i < count; i++) {
+ bus_space_write_1(sc->sc_regt, sc->sc_regh,
+ M64_DAC_DATA, *r);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh,
+ M64_DAC_DATA, *g);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh,
+ M64_DAC_DATA, *b);
+ r++, g++, b++, index++;
+ }
+ return (0);
+}
+
+void
+machfb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
+{
+ struct machfb_softc *sc = v;
+
+ sc->sc_cmap_red[index] = r;
+ sc->sc_cmap_green[index] = g;
+ sc->sc_cmap_blue[index] = b;
+
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_MASK, 0xff);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_WINDEX, index);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, r);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, g);
+ bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, b);
+}
+
+/*
+ * Accelerated routines.
+ */
+
+void
+machfb_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct machfb_softc *sc = ri->ri_hw;
+
+ num *= ri->ri_font->fontwidth;
+ src *= ri->ri_font->fontwidth;
+ dst *= ri->ri_font->fontwidth;
+ row *= ri->ri_font->fontheight;
+
+ machfb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
+ ri->ri_xorigin + dst, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight);
+}
+
+void
+machfb_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct machfb_softc *sc = ri->ri_hw;
+ int bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ row *= ri->ri_font->fontheight;
+ col *= ri->ri_font->fontwidth;
+ num *= ri->ri_font->fontwidth;
+
+ machfb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
+}
+
+void
+machfb_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct machfb_softc *sc = ri->ri_hw;
+
+ num *= ri->ri_font->fontheight;
+ src *= ri->ri_font->fontheight;
+ dst *= ri->ri_font->fontheight;
+
+ machfb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
+ ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
+}
+
+void
+machfb_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct machfb_softc *sc = ri->ri_hw;
+ int bg, fg;
+ int x, y, w;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
+ num = ri->ri_height;
+ x = y = 0;
+ w = ri->ri_width;
+ } else {
+ num *= ri->ri_font->fontheight;
+ x = ri->ri_xorigin;
+ y = ri->ri_yorigin + row * ri->ri_font->fontheight;
+ w = ri->ri_emuwidth;
+ }
+ machfb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
+}
+
+void
+machfb_init(struct machfb_softc *sc)
+{
+ uint32_t reg;
+
+ /* Reset engine. */
+ reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL);
+ reg &= ~M64_GEN_GUI_EN;
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL, reg);
+
+ /* Enable engine. */
+ reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL);
+ reg &= M64_GEN_GUI_EN;
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL, reg);
+
+ /* Clearing any FIFO or host errors. */
+ reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_BUS_CNTL);
+ reg |= M64_BUS_HOST_ERR_ACK | M64_BUS_FIFO_ERR_ACK;
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_BUS_CNTL, reg);
+
+ machfb_wait_fifo(sc, 14);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_CONTEXT_MASK, 0xffffffff);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_OFF_PITCH,
+ (sc->sc_sunfb.sf_linebytes / 8) << 22);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_Y_X, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_HEIGHT, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_ERR, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_INC, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_DEC, 0);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_CNTL,
+ M64_DST_LAST_PEL | M64_DST_X_LEFT_TO_RIGHT |
+ M64_DST_Y_TOP_TO_BOTTOM);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_OFF_PITCH,
+ (sc->sc_sunfb.sf_linebytes / 8) << 22);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_Y_X, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_HEIGHT1_WIDTH1, 1);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_Y_X_START, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_HEIGHT2_WIDTH2, 1);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_CNTL,
+ M64_SRC_LINE_X_LEFT_TO_RIGHT);
+
+ machfb_wait_fifo(sc, 13);
+
+ /* Host attributes. */
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_HOST_CNTL, 0);
+
+ /* Pattern attributes. */
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_REG0, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_REG1, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_CNTL, 0);
+
+ /* Scissors. */
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_LEFT, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_TOP, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_BOTTOM,
+ sc->sc_sunfb.sf_height - 1);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_RIGHT,
+ sc->sc_sunfb.sf_linebytes - 1);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_BKGD_CLR, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_FRGD_CLR, 0xffffffff);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_WRITE_MASK, 0xffffffff);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_MIX, (M64_MIX_SRC << 16) | M64_MIX_DST);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_SRC, M64_FRGD_SRC_FRGD_CLR);
+
+ machfb_wait_fifo(sc, 3);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CLR, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_CLR_CMP_MASK, 0xffffffff);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
+
+ machfb_wait_fifo(sc, 3);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_PIX_WIDTH,
+ M64_HOST_8BPP | M64_SRC_8BPP | M64_DST_8BPP);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_CHAIN_MASK,
+ M64_DP_CHAIN_8BPP);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GUI_TRAJ_CNTL,
+ M64_DST_X_LEFT_TO_RIGHT | M64_DST_Y_TOP_TO_BOTTOM);
+
+ machfb_wait(sc);
+}
+
+int
+machfb_wait_fifo(struct machfb_softc *sc, int v)
+{
+ int i;
+
+ for (i = 1000000; i != 0; i--) {
+ if ((bus_space_read_4(sc->sc_regt, sc->sc_regh,
+ M64_FIFO_STAT) & M64_FIFO_STAT_MASK) <= (0x8000 >> v))
+ break;
+ DELAY(1);
+ }
+
+ return i;
+}
+
+int
+machfb_wait(struct machfb_softc *sc)
+{
+ int i;
+
+ machfb_wait_fifo(sc, 16);
+ for (i = 1000000; i != 0; i--) {
+ if ((bus_space_read_4(sc->sc_regt, sc->sc_regh,
+ M64_GUI_STAT) & M64_GUI_ACTIVE) == 0)
+ break;
+ DELAY(1);
+ }
+
+ return i;
+}
+
+void
+machfb_copyrect(struct machfb_softc *sc, int sx, int sy, int dx, int dy,
+ int w, int h)
+{
+ uint32_t dest_ctl = 0;
+
+ machfb_wait_fifo(sc, 10);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_WRITE_MASK, 0xff);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_SRC, M64_FRGD_SRC_BLIT);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_MIX, M64_MIX_SRC << 16);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
+ if (dy < sy) {
+ dest_ctl = M64_DST_Y_TOP_TO_BOTTOM;
+ } else {
+ sy += h - 1;
+ dy += h - 1;
+ dest_ctl = M64_DST_Y_BOTTOM_TO_TOP;
+ }
+ if (dx < sx) {
+ dest_ctl |= M64_DST_X_LEFT_TO_RIGHT;
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_CNTL, M64_SRC_LINE_X_LEFT_TO_RIGHT);
+ } else {
+ dest_ctl |= M64_DST_X_RIGHT_TO_LEFT;
+ sx += w - 1;
+ dx += w - 1;
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_CNTL, M64_SRC_LINE_X_RIGHT_TO_LEFT);
+ }
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_CNTL, dest_ctl);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_Y_X, M64_COORDS(sx, sy));
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_WIDTH1, w);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DST_Y_X, M64_COORDS(dx, dy));
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DST_HEIGHT_WIDTH, M64_COORDS(w, h));
+
+ machfb_wait(sc);
+}
+
+void
+machfb_fillrect(struct machfb_softc *sc, int x, int y, int w, int h, int color)
+{
+ machfb_wait_fifo(sc, 11);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_WRITE_MASK, 0xff);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_FRGD_CLR, color);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_SRC, M64_FRGD_SRC_FRGD_CLR);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DP_MIX, M64_MIX_SRC << 16);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_CNTL, M64_SRC_LINE_X_LEFT_TO_RIGHT);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DST_CNTL, M64_DST_X_LEFT_TO_RIGHT | M64_DST_Y_TOP_TO_BOTTOM);
+
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_SRC_Y_X, M64_COORDS(x, y));
+ bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_WIDTH1, w);
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DST_Y_X, M64_COORDS(x, y));
+ bus_space_write_4(sc->sc_regt, sc->sc_regh,
+ M64_DST_HEIGHT_WIDTH, M64_COORDS(w, h));
+
+ machfb_wait(sc);
+}