diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-06-02 04:12:12 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-06-02 04:12:12 +0000 |
commit | 22a00d3c977d7c4f74bfa05966a5def227e6d748 (patch) | |
tree | 10912a42f9e05248e61123035b31c02908b43994 /sys/arch/sparc64 | |
parent | 2d6c4bbf119ecf4fe2007f3a2634ae931cd242e1 (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.c | 789 |
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); +} |