diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2008-04-15 20:23:55 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2008-04-15 20:23:55 +0000 |
commit | 8be43d4c7a17abee04242c588bc6d149c2c59796 (patch) | |
tree | 02db355c6ad316abef27f2d5df64ef870e6f1553 | |
parent | 30f272e9a6ca2cfdd4fb761f0f4c26c2a3b72e6b (diff) |
It turns out the mysterious chip with the heatsink glued on, found on mgx
video boards, is a known entity, so add support for 2d acceleration with
the help of the X code (which makes baby Jesus cry).
The blitter is fast enough to make a cgsix feel as slow as a cgthree in
comparison.
-rw-r--r-- | distrib/notes/sparc/hardware | 4 | ||||
-rw-r--r-- | distrib/notes/sparc64/hardware | 4 | ||||
-rw-r--r-- | share/man/man4/man4.sparc/mgx.4 | 6 | ||||
-rw-r--r-- | share/man/man4/man4.sparc64/mgx.4 | 6 | ||||
-rw-r--r-- | sys/arch/sparc/dev/mgx.c | 486 | ||||
-rw-r--r-- | sys/dev/ic/atxxreg.h | 209 | ||||
-rw-r--r-- | sys/dev/sbus/mgx.c | 514 |
7 files changed, 1126 insertions, 103 deletions
diff --git a/distrib/notes/sparc/hardware b/distrib/notes/sparc/hardware index 70f676d13ef..84a353c9a44 100644 --- a/distrib/notes/sparc/hardware +++ b/distrib/notes/sparc/hardware @@ -1,4 +1,4 @@ -dnl $OpenBSD: hardware,v 1.73 2008/02/23 10:36:27 jmc Exp $ +dnl $OpenBSD: hardware,v 1.74 2008/04/15 20:23:51 miod Exp $ OpenBSD/MACHINE OSREV runs on the following classes of machines: * sun4: the VME series - 4/100: Original SPARC with VME. Many hardware bugs. @@ -116,7 +116,7 @@ Supported devices {:-include-:}: + RasterFlex series (rfx) - 8/24-bit color, accelerated (currently only supported in 8-bit unaccelerated mode) + Southland Media Systems MGX and MGXPlus (mgx) - 24-bit color, - accelerated (currently only supported in 8-bit unaccelerated mode) + accelerated (currently only supported in 8-bit accelerated mode) + TCX - 8/24-bit color + Vigra VS10, VS11 and VS12 framebuffers (8-bit color, selectable VGA-compatible modes and connector) diff --git a/distrib/notes/sparc64/hardware b/distrib/notes/sparc64/hardware index 7d8f052feb3..84a340f235f 100644 --- a/distrib/notes/sparc64/hardware +++ b/distrib/notes/sparc64/hardware @@ -1,4 +1,4 @@ -dnl $OpenBSD: hardware,v 1.131 2008/04/01 14:40:58 jmc Exp $ +dnl $OpenBSD: hardware,v 1.132 2008/04/15 20:23:53 miod Exp $ OpenBSD/MACHINE OSREV runs on the following classes of machines: Ultra 1/1E Ultra 2 @@ -795,7 +795,7 @@ Supported devices {:-include-:}: unaccelerated mode) Southland Media Systems MGX and MGXPlus (mgx) - 24-bit color, accelerated (currently only - supported in 8-bit unaccelerated mode) + supported in 8-bit accelerated mode) Vigra VS10, VS11 and VS12 framebuffers (8-bit color, selectable VGA-compatible modes and connector) ZX (aka Leo) - 8/24-bit color, overlay planes, diff --git a/share/man/man4/man4.sparc/mgx.4 b/share/man/man4/man4.sparc/mgx.4 index 48678c59b67..f49d58040c3 100644 --- a/share/man/man4/man4.sparc/mgx.4 +++ b/share/man/man4/man4.sparc/mgx.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: mgx.4,v 1.10 2008/03/31 07:44:30 jmc Exp $ +.\" $OpenBSD: mgx.4,v 1.11 2008/04/15 20:23:53 miod Exp $ .\" .\" Copyright (c) 2003, 2005 Miodrag Vallat .\" @@ -23,7 +23,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: March 31 2008 $ +.Dd $Mdocdate: April 15 2008 $ .Dt MGX 4 sparc .Os .Sh NAME @@ -90,5 +90,5 @@ All other combinations are unsupported and may damage the hardware. .Xr wscons 4 , .Xr wsdisplay 4 .Sh CAVEATS -This driver does not support any acceleration features at the moment, and +This driver does not support mode switching at the moment, and drives the card in PROM-compatible, 8 bit, mode only. diff --git a/share/man/man4/man4.sparc64/mgx.4 b/share/man/man4/man4.sparc64/mgx.4 index a58510a4e18..3634624eb1f 100644 --- a/share/man/man4/man4.sparc64/mgx.4 +++ b/share/man/man4/man4.sparc64/mgx.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: mgx.4,v 1.11 2008/03/31 08:12:22 jmc Exp $ +.\" $OpenBSD: mgx.4,v 1.12 2008/04/15 20:23:53 miod Exp $ .\" .\" Copyright (c) 2003, 2005 Miodrag Vallat .\" @@ -23,7 +23,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: March 31 2008 $ +.Dd $Mdocdate: April 15 2008 $ .Dt MGX 4 sparc64 .Os .Sh NAME @@ -90,5 +90,5 @@ All other combinations are unsupported and may damage the hardware. .Xr wscons 4 , .Xr wsdisplay 4 .Sh CAVEATS -This driver does not support any acceleration features at the moment, and +This driver does not support mode switching at the moment, and drives the card in PROM-compatible, 8 bit, mode only. diff --git a/sys/arch/sparc/dev/mgx.c b/sys/arch/sparc/dev/mgx.c index 198c548dd7d..8159a33f42a 100644 --- a/sys/arch/sparc/dev/mgx.c +++ b/sys/arch/sparc/dev/mgx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mgx.c,v 1.13 2008/04/15 16:03:08 miod Exp $ */ +/* $OpenBSD: mgx.c,v 1.14 2008/04/15 20:23:54 miod Exp $ */ /* * Copyright (c) 2003, Miodrag Vallat. * All rights reserved. @@ -30,9 +30,15 @@ * Driver for the Southland Media Systems (now Quantum 3D) MGX and MGXPlus * frame buffers. * - * Pretty crude, due to the lack of documentation. Works as a dumb frame - * buffer in 8 bit mode, although the hardware can run in an 32 bit - * accelerated mode. Also, interrupts are not handled. + * This board is built of an Alliance Promotion AT24 chip, and a simple + * SBus-PCI glue logic. It also sports an EEPROM to store configuration + * parameters, which can be controlled from SunOS or Solaris with the + * mgxconfig utility. + * + * We currently don't reprogram the video mode at all, so only the resolution + * and depth set by the PROM (or mgxconfig) will be used. + * + * Also, interrupts are not handled. */ #include <sys/param.h> @@ -57,47 +63,72 @@ #include <dev/rasops/rasops.h> #include <machine/fbvar.h> +#include <dev/ic/vgareg.h> +#include <dev/ic/atxxreg.h> + #include <sparc/dev/sbusvar.h> /* * MGX PROM register layout + * + * The cards FCode registers 9 regions: + * + * region offset size description + * 0 00000000 00010000 FCode (32KB only) + * 1 00100000 00010000 FCode, repeated + * 2 00200000 00001000 unknown, repeats every 0x100 + * with little differences, could be the EEPROM image + * 3 00400000 00001000 PCI configuration space + * 4 00500000 00001000 CRTC + * 5 00600000 00001000 AT24 registers (offset 0xb0000) + * 6 00700000 00010000 unknown + * 7 00800000 00800000 unknown + * 8 01000000 00400000 video memory */ -#define MGX_NREG 9 -#define MGX_REG_CRTC 4 /* video control and ramdac */ -#define MGX_REG_CTRL 5 /* control engine */ -#define MGX_REG_VRAM8 8 /* 8-bit memory space */ +#define MGX_NREG 9 +#define MGX_REG_CRTC 4 /* video control and ramdac */ +#define MGX_REG_ATREG 5 /* AT24 registers */ +#define MGX_REG_ATREG_OFFSET 0x000b0000 +#define MGX_REG_ATREG_SIZE 0x00000400 +#define MGX_REG_VRAM8 8 /* 8-bit memory space */ /* - * MGX CRTC empirical constants + * MGX CRTC access + * + * The CRTC only answers to the following ``port'' locations: + * - a subset of the VGA registers: + * 3c0, 3c1 (ATC) + * 3c4, 3c5 (TS sequencer) + * 3c6-3c9 (DAC) + * 3c2, 3cc (Misc) + * 3ce, 3cf (GDC) + * + * - the CRTC (6845-style) registers: + * 3d4 index register + * 3d5 data register */ -#if _BYTE_ORDER == _LITTLE_ENDIAN -#define IO_ADDRESS(x) (x) -#else -#define IO_ADDRESS(x) ((x) ^ 0x03) -#endif -#define CRTC_INDEX IO_ADDRESS(0x03c4) -#define CRTC_DATA IO_ADDRESS(0x03c5) + +#define VGA_BASE 0x03c0 +#define TS_INDEX (VGA_BASE + VGA_TS_INDEX) +#define TS_DATA (VGA_BASE + VGA_TS_DATA) #define CD_DISABLEVIDEO 0x0020 -#define CMAP_READ_INDEX IO_ADDRESS(0x03c7) -#define CMAP_WRITE_INDEX IO_ADDRESS(0x03c8) -#define CMAP_DATA IO_ADDRESS(0x03c9) +#define CMAP_WRITE_INDEX (VGA_BASE + 0x08) +#define CMAP_DATA (VGA_BASE + 0x09) /* per-display variables */ struct mgx_softc { - struct sunfb sc_sunfb; /* common base device */ - struct rom_reg sc_phys; + struct sunfb sc_sunfb; /* common base device */ + struct rom_reg sc_phys; /* for mmap() */ u_int8_t sc_cmap[256 * 3]; /* shadow colormap */ - volatile u_int8_t *sc_vidc; /* ramdac registers */ + vaddr_t sc_vidc; /* ramdac registers */ + vaddr_t sc_xreg; /* AT24 registers */ + uint32_t sc_dec; /* dec register template */ }; void mgx_burner(void *, u_int ,u_int); -int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *); -void mgx_loadcmap(struct mgx_softc *, int, int); paddr_t mgx_mmap(void *, off_t, int); -int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); -void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); struct wsdisplay_accessops mgx_accessops = { mgx_ioctl, @@ -112,6 +143,30 @@ struct wsdisplay_accessops mgx_accessops = { NULL /* pollc */ }; +int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); +void mgx_loadcmap(struct mgx_softc *, int, int); +int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); +void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); + +void mgx_ras_copycols(void *, int, int, int, int); +void mgx_ras_copyrows(void *, int, int, int); +void mgx_ras_do_cursor(struct rasops_info *); +void mgx_ras_erasecols(void *, int, int, int, long int); +void mgx_ras_eraserows(void *, int, int, long int); +void mgx_ras_init(struct mgx_softc *, uint); + +uint8_t mgx_read_1(vaddr_t, uint); +uint16_t mgx_read_2(vaddr_t, uint); +void mgx_write_1(vaddr_t, uint, uint8_t); +void mgx_write_4(vaddr_t, uint, uint32_t); + +int mgx_wait_engine(struct mgx_softc *); +int mgx_wait_fifo(struct mgx_softc *, uint); + +/* + * Attachment Glue + */ + int mgxmatch(struct device *, void *, void *); void mgxattach(struct device *, struct device *, void *); @@ -151,6 +206,7 @@ mgxattach(struct device *parent, struct device *self, void *args) struct confargs *ca = args; int node, fbsize; int isconsole; + uint16_t chipid; node = ca->ca_ra.ra_node; @@ -165,8 +221,19 @@ mgxattach(struct device *parent, struct device *self, void *args) return; } - sc->sc_vidc = (volatile u_int8_t *)mapiodev( - &ca->ca_ra.ra_reg[MGX_REG_CRTC], 0, PAGE_SIZE); + sc->sc_vidc = (vaddr_t)mapiodev(&ca->ca_ra.ra_reg[MGX_REG_CRTC], + 0, PAGE_SIZE); + sc->sc_xreg = (vaddr_t)mapiodev(&ca->ca_ra.ra_reg[MGX_REG_ATREG], + MGX_REG_ATREG_OFFSET, MGX_REG_ATREG_SIZE); + + /* + * Check the chip ID. If it's not an AT24, prefer not to access + * the extended registers at all. + */ + chipid = mgx_read_2(sc->sc_xreg, ATR_ID); + if (chipid != ID_AT24) { + sc->sc_xreg = (vaddr_t)0; + } /* enable video */ mgx_burner(sc, 1, 0); @@ -196,6 +263,13 @@ mgxattach(struct device *parent, struct device *self, void *args) printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + if (chipid != ID_AT24) { + printf("%s: unexpected engine id %04x\n", + self->dv_xname, chipid); + } + + mgx_ras_init(sc, chipid); + if (isconsole) { fbwscons_console_init(&sc->sc_sunfb, -1); } @@ -204,7 +278,50 @@ mgxattach(struct device *parent, struct device *self, void *args) } /* - * wsdisplay operations + * Register Access + * + * On big-endian systems such as the sparc, it is necessary to flip + * the low-order bits of the addresses to reach the right register. + */ + +uint8_t +mgx_read_1(vaddr_t regs, uint offs) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + return *(volatile uint8_t *)(regs + offs); +#else + return *(volatile uint8_t *)(regs + (offs ^ 3)); +#endif +} + +uint16_t +mgx_read_2(vaddr_t regs, uint offs) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + return *(volatile uint16_t *)(regs + offs); +#else + return *(volatile uint16_t *)(regs + (offs ^ 2)); +#endif +} + +void +mgx_write_1(vaddr_t regs, uint offs, uint8_t val) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + *(volatile uint8_t *)(regs + offs) = val; +#else + *(volatile uint8_t *)(regs + (offs ^ 3)) = val; +#endif +} + +void +mgx_write_4(vaddr_t regs, uint offs, uint32_t val) +{ + *(volatile uint32_t *)(regs + offs) = val; +} + +/* + * Wsdisplay Operations */ int @@ -275,16 +392,36 @@ void mgx_burner(void *v, u_int on, u_int flags) { struct mgx_softc *sc = v; + uint mode; + +#ifdef notyet + if (sc->sc_xreg != 0) { + mode = mgx_read_1(sc->sc_xreg, ATR_DPMS); + if (on) + CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE); + else { + SET(mode, DPMS_HSYNC_DISABLE); +#if 0 /* needs ramdac reprogramming on resume */ + if (flags & WSDISPLAY_BURN_VBLANK) + SET(mode, DPMS_VSYNC_DISABLE); +#endif + } + mgx_write_1(sc->sc_xreg, ATR_DPMS, mode); + return; + } +#endif - sc->sc_vidc[CRTC_INDEX] = 1; /* TS mode register */ + mgx_write_1(sc->sc_vidc, TS_INDEX, 1); /* TS mode register */ + mode = mgx_read_1(sc->sc_vidc, TS_DATA); if (on) - sc->sc_vidc[CRTC_DATA] &= ~CD_DISABLEVIDEO; + mode &= ~CD_DISABLEVIDEO; else - sc->sc_vidc[CRTC_DATA] |= CD_DISABLEVIDEO; + mode |= CD_DISABLEVIDEO; + mgx_write_1(sc->sc_vidc, TS_DATA, mode); } /* - * Colormap handling routines + * Colormap Handling Routines */ void @@ -306,10 +443,10 @@ mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors) u_int8_t *color; int i; - sc->sc_vidc[CMAP_WRITE_INDEX] = start; + mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start); color = sc->sc_cmap + start * 3; for (i = ncolors * 3; i != 0; i--) - sc->sc_vidc[CMAP_DATA] = *color++; + mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++); } int @@ -321,15 +458,16 @@ mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) if (index >= 256 || count > 256 - index) return (EINVAL); + index *= 3; for (i = 0; i < count; i++) { if ((error = - copyout(cm + (index + i) * 3 + 0, &rcm->red[i], 1)) != 0) + copyout(cm + index++, &rcm->red[i], 1)) != 0) return (error); if ((error = - copyout(cm + (index + i) * 3 + 1, &rcm->green[i], 1)) != 0) + copyout(cm + index++, &rcm->green[i], 1)) != 0) return (error); if ((error = - copyout(cm + (index + i) * 3 + 2, &rcm->blue[i], 1)) != 0) + copyout(cm + index++, &rcm->blue[i], 1)) != 0) return (error); } @@ -345,17 +483,283 @@ mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) if (index >= 256 || count > 256 - index) return (EINVAL); + index *= 3; for (i = 0; i < count; i++) { if ((error = - copyin(&rcm->red[i], cm + (index + i) * 3 + 0, 1)) != 0) + copyin(&rcm->red[i], cm + index++, 1)) != 0) return (error); if ((error = - copyin(&rcm->green[i], cm + (index + i) * 3 + 1, 1)) != 0) + copyin(&rcm->green[i], cm + index++, 1)) != 0) return (error); if ((error = - copyin(&rcm->blue[i], cm + (index + i) * 3 + 2, 1)) != 0) + copyin(&rcm->blue[i], cm + index++, 1)) != 0) return (error); } return (0); } + +/* + * Accelerated Text Console Code + * + * The X driver makes sure there are at least as many FIFOs available as + * registers to write. They can thus be considered as write slots. + * + * The code below expects to run on at least an AT24 chip, and does not + * care for the AP6422 which has fewer FIFOs; some operations would need + * to be done in two steps to support this chip. + */ + +int +mgx_wait_engine(struct mgx_softc *sc) +{ + uint i; + uint stat; + + for (i = 10000; i != 0; i--) { + stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS); + if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY)) + break; + } + + return i; +} + +int +mgx_wait_fifo(struct mgx_softc *sc, uint nfifo) +{ + uint i; + uint stat; + + for (i = 10000; i != 0; i--) { + stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >> + FIFO_SHIFT; + if (stat >= nfifo) + break; + mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0); + } + + return i; +} + +void +mgx_ras_init(struct mgx_softc *sc, uint chipid) +{ + /* + * Check the chip ID. If it's not a 6424, do not plug the + * accelerated routines. + */ + + if (chipid != ID_AT24) + return; + + /* + * Wait until the chip is completely idle. + */ + + if (mgx_wait_engine(sc) == 0) + return; + if (mgx_wait_fifo(sc, FIFO_AT24) == 0) + return; + + /* + * Compute the invariant bits of the DEC register. + */ + + switch (sc->sc_sunfb.sf_depth) { + case 8: + sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; + break; + case 15: + case 16: + sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; + break; + case 32: + sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; + break; + default: + return; /* not supported */ + } + + switch (sc->sc_sunfb.sf_width) { + case 640: + sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; + break; + case 800: + sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; + break; + case 1024: + sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; + break; + case 1152: + sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; + break; + case 1280: + sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; + break; + case 1600: + sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; + break; + default: + return; /* not supported */ + } + + sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols; + sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows; + sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols; + sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows; + sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor; + +#ifdef notneeded + mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1); + mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0)); + mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM, + ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1)); +#else + mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0); +#endif + mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff); +} + +void +mgx_ras_copycols(void *v, int row, int src, int dst, int n) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + uint dec = sc->sc_dec; + + n *= ri->ri_font->fontwidth; + src *= ri->ri_font->fontwidth; + src += ri->ri_xorigin; + dst *= ri->ri_font->fontwidth; + dst += ri->ri_xorigin; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + if (src < dst) { + src += n - 1; + dst += n - 1; + dec |= DEC_DIR_X_REVERSE; + } + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); + mgx_wait_engine(sc); +} + +void +mgx_ras_copyrows(void *v, int src, int dst, int n) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + uint dec = sc->sc_dec; + + n *= ri->ri_font->fontheight; + src *= ri->ri_font->fontheight; + src += ri->ri_yorigin; + dst *= ri->ri_font->fontheight; + dst += ri->ri_yorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + if (src < dst) { + src += n - 1; + dst += n - 1; + dec |= DEC_DIR_Y_REVERSE; + } + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); + mgx_wait_engine(sc); +} + +void +mgx_ras_erasecols(void *v, int row, int col, int n, long int attr) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + int fg, bg; + uint dec = sc->sc_dec; + + ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); + bg = ri->ri_devcmap[bg]; + + n *= ri->ri_font->fontwidth; + col *= ri->ri_font->fontwidth; + col += ri->ri_xorigin; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_FG, bg); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); + mgx_wait_engine(sc); +} + +void +mgx_ras_eraserows(void *v, int row, int n, long int attr) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + int fg, bg; + uint dec = sc->sc_dec; + + ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); + bg = ri->ri_devcmap[bg]; + + dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_FG, bg); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) { + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0)); + mgx_write_4(sc->sc_xreg, ATR_WH, + ATR_DUAL(ri->ri_height, ri->ri_width)); + } else { + n *= ri->ri_font->fontheight; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + mgx_write_4(sc->sc_xreg, ATR_DST_XY, + ATR_DUAL(row, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); + } + mgx_wait_engine(sc); +} + +void +mgx_ras_do_cursor(struct rasops_info *ri) +{ + struct mgx_softc *sc = ri->ri_hw; + int row, col; + uint dec = sc->sc_dec; + + row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; + col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_WH, + ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth)); + mgx_wait_engine(sc); +} diff --git a/sys/dev/ic/atxxreg.h b/sys/dev/ic/atxxreg.h new file mode 100644 index 00000000000..e8c909212ec --- /dev/null +++ b/sys/dev/ic/atxxreg.h @@ -0,0 +1,209 @@ +/* $OpenBSD: atxxreg.h,v 1.1 2008/04/15 20:23:54 miod Exp $ */ + +/* + * Copyright (c) 2008 Miodrag Vallat. + * + * 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. + */ + +/* + * Alliance Promotion AP6422, AT24 and AT3D extended register set definitions. + * + * This has been reconstructed from XFree86 ``apm'' driver, whose authors + * apparently do not believe in meaningful constants for numbers. See + * apm_regs.h for more madness. + */ + +/* + * Dual coordinates encoding + */ + +#define ATR_DUAL(y,x) (((y) << 16) | (x)) + +/* + * Clipping Control + */ + +#define ATR_CLIP_CONTROL 0x0030 /* byte access */ +#define ATR_CLIP_LEFT 0x0038 +#define ATR_CLIP_TOP 0x003a +#define ATR_CLIP_LEFTTOP 0x0038 +#define ATR_CLIP_RIGHT 0x003c +#define ATR_CLIP_BOTTOM 0x003e +#define ATR_CLIP_RIGHTBOTTOM 0x003c + +/* + * Drawing Engine + */ + +#define ATR_DEC 0x0040 +#define ATR_ROP 0x0046 +#define ATR_BYTEMASK 0x0047 +#define ATR_PATTERN1 0x0048 +#define ATR_PATTERN2 0x004c +#define ATR_SRC_X 0x0050 +#define ATR_SRC_Y 0x0052 +#define ATR_SRC_XY 0x0050 +#define ATR_DST_X 0x0054 +#define ATR_DST_Y 0x0056 +#define ATR_DST_XY 0x0054 +#define ATR_W 0x0058 +#define ATR_H 0x005a +#define ATR_WH 0x0058 +#define ATR_OFFSET 0x005c +#define ATR_SRC_OFFSET 0x005e +#define ATR_FG 0x0060 +#define ATR_BG 0x0064 + +/* DEC layout */ +#define DEC_COMMAND_MASK 0x0000003f +#define DEC_COMMAND_SHIFT 0 +#define DEC_DIR_X_REVERSE 0x00000040 +#define DEC_DIR_Y_REVERSE 0x00000080 +#define DEC_DIR_Y_MAJOR 0x00000100 +#define DEC_SRC_LINEAR 0x00000200 +#define DEC_SRC_CONTIGUOUS 0x00000800 +#define DEC_MONOCHROME 0x00001000 +#define DEC_SRC_TRANSPARENT 0x00002000 +#define DEC_DEPTH_MASK 0x0001c000 +#define DEC_DEPTH_SHIFT 14 +#define DEC_DST_LINEAR 0x00040000 +#define DEC_DST_CONTIGUOUS 0x00080000 +#define DEC_DST_TRANSPARENT 0x00100000 +#define DEC_DST_TRANSPARENT_POLARITY 0x00200000 +#define DEC_PATTERN_MASK 0x00c00000 +#define DEC_PATTERN_SHIFT 22 +#define DEC_WIDTH_MASK 0x07000000 +#define DEC_WIDTH_SHIFT 24 +#define DEC_UPDATE_MASK 0x18000000 +#define DEC_UPDATE_SHIFT 27 +#define DEC_START_MASK 0x60000000 +#define DEC_START_SHIFT 29 +#define DEC_START 0x80000000 + +/* DEC commands */ +#define DEC_COMMAND_NOP 0x00 +#define DEC_COMMAND_BLT 0x01 /* screen to screen blt */ +#define DEC_COMMAND_RECT 0x02 /* rectangle fill */ +#define DEC_COMMAND_BLT_STRETCH 0x03 /* blt and stretch */ +#define DEC_COMMAND_STRIP 0x04 /* strip pattern */ +#define DEC_COMMAND_HOST_BLT 0x08 /* host to screen blt */ +#define DEC_COMMAND_SCREEN_BLT 0x09 /* screen to host blt */ +#define DEC_COMMAND_VECT_ENDP 0x0c /* vector with end point */ +#define DEC_COMMAND_VECT_NO_ENDP 0x0d /* vector without end point */ + +/* depth */ +#define DEC_DEPTH_8 0x01 +#define DEC_DEPTH_16 0x02 +#define DEC_DEPTH_32 0x03 +#define DEC_DEPTH_24 0x04 + +/* width */ +#define DEC_WIDTH_LINEAR 0x00 +#define DEC_WIDTH_640 0x01 +#define DEC_WIDTH_800 0x02 +#define DEC_WIDTH_1024 0x04 +#define DEC_WIDTH_1152 0x05 +#define DEC_WIDTH_1280 0x06 +#define DEC_WIDTH_1600 0x07 + +/* update mode */ +#define DEC_UPDATE_NONE 0x00 +#define DEC_UPDATE_TOP_RIGHT 0x01 +#define DEC_UPDATE_BOTTOM_LEFT 0x02 +#define DEC_UPDATE_LASTPIX 0x03 + +/* quickstart mode - operation starts as soon as given register is written to */ +#define DEC_START_DIMX 0x01 +#define DEC_START_SRC 0x02 +#define DEC_START_DST 0x03 + +/* ROP */ +#define ROP_DST 0x66 +#define ROP_SRC 0xcc +#define ROP_PATTERN 0xf0 + +/* + * Configuration Registers + */ + +#define ATR_PIXEL 0x0080 /* byte access */ +#define PIXEL_DEPTH_MASK 0x0f +#define PIXEL_DEPTH_SHIFT 0 + +/* pixel depth */ +#define PIXEL_4 0x01 +#define PIXEL_8 0x02 +#define PIXEL_15 0x0c +#define PIXEL_16 0x0d +#define PIXEL_24 0x0e +#define PIXEL_32 0x0f + +#define ATR_APERTURE 0x00c0 /* short access */ + +/* + * DPMS Control + */ + +#define ATR_DPMS 0x00d0 /* byte access */ + +#define DPMS_HSYNC_DISABLE 0x01 +#define DPMS_VSYNC_DISABLE 0x02 + +/* + * RAMDAC + */ + +#define ATR_COLOR_CORRECTION 0x00e0 +#define ATR_MCLK 0x00e8 +#define ATR_PCLK 0x00ec + +/* + * Hardware Cursor + * + * The position can not become negative; the offset register, encoded as + * (signed y delta << 8) | signed x delta, allow the cursor image to + * cross the upper-left corner. + */ + +#define ATR_CURSOR_ENABLE 0x0140 +#define ATR_CURSOR_FG 0x0141 /* 3:3:2 */ +#define ATR_CURSOR_BG 0x0142 /* 3:3:2 */ +#define ATR_CURSOR_ADDRESS 0x0144 /* in KB from vram */ +#define ATR_CURSOR_POSITION 0x0148 +#define ATR_CURSOR_OFFSET 0x014c /* short access */ + +/* + * Identification Register + */ + +#define ATR_ID 0x0182 + +#define ID_AP6422 0x6422 +#define ID_AT24 0x6424 +#define ID_AT3D 0x643d + +/* + * Status Registers + */ + +#define ATR_FIFO_STATUS 0x01fc +#define ATR_BLT_STATUS 0x01fd + +#define FIFO_MASK 0x0f +#define FIFO_SHIFT 0 +#define FIFO_AP6422 4 +#define FIFO_AT24 8 + +#define BLT_HOST_BUSY 0x01 +#define BLT_ENGINE_BUSY 0x04 diff --git a/sys/dev/sbus/mgx.c b/sys/dev/sbus/mgx.c index 44284254bab..bad4475b9fa 100644 --- a/sys/dev/sbus/mgx.c +++ b/sys/dev/sbus/mgx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mgx.c,v 1.9 2008/04/15 16:03:12 miod Exp $ */ +/* $OpenBSD: mgx.c,v 1.10 2008/04/15 20:23:54 miod Exp $ */ /* * Copyright (c) 2003, Miodrag Vallat. * All rights reserved. @@ -30,9 +30,15 @@ * Driver for the Southland Media Systems (now Quantum 3D) MGX and MGXPlus * frame buffers. * - * Pretty crude, due to the lack of documentation. Works as a dumb frame - * buffer in 8 bit mode, although the hardware can run in an 32 bit - * accelerated mode. Also, interrupts are not handled. + * This board is built of an Alliance Promotion AT24 chip, and a simple + * SBus-PCI glue logic. It also sports an EEPROM to store configuration + * parameters, which can be controlled from SunOS or Solaris with the + * mgxconfig utility. + * + * We currently don't reprogram the video mode at all, so only the resolution + * and depth set by the PROM (or mgxconfig) will be used. + * + * Also, interrupts are not handled. */ #include <sys/param.h> @@ -57,57 +63,79 @@ #include <dev/rasops/rasops.h> #include <machine/fbvar.h> +#include <dev/ic/vgareg.h> +#include <dev/ic/atxxreg.h> + #include <dev/sbus/sbusvar.h> /* * MGX PROM register layout + * + * The cards FCode registers 9 regions: + * + * region offset size description + * 0 00000000 00010000 FCode (32KB only) + * 1 00100000 00010000 FCode, repeated + * 2 00200000 00001000 unknown, repeats every 0x100 + * with little differences, could be the EEPROM image + * 3 00400000 00001000 PCI configuration space + * 4 00500000 00001000 CRTC + * 5 00600000 00001000 AT24 registers (offset 0xb0000) + * 6 00700000 00010000 unknown + * 7 00800000 00800000 unknown + * 8 01000000 00400000 video memory */ -#define MGX_NREG 9 -#define MGX_REG_CRTC 4 /* video control and ramdac */ -#define MGX_REG_CTRL 5 /* control engine */ -#define MGX_REG_VRAM8 8 /* 8-bit memory space */ +#define MGX_NREG 9 +#define MGX_REG_CRTC 4 /* video control and ramdac */ +#define MGX_REG_ATREG 5 /* AT24 registers */ +#define MGX_REG_ATREG_OFFSET 0x000b0000 +#define MGX_REG_ATREG_SIZE 0x00000400 +#define MGX_REG_VRAM8 8 /* 8-bit memory space */ /* - * MGX CRTC empirical constants + * MGX CRTC access + * + * The CRTC only answers to the following ``port'' locations: + * - a subset of the VGA registers: + * 3c0, 3c1 (ATC) + * 3c4, 3c5 (TS sequencer) + * 3c6-3c9 (DAC) + * 3c2, 3cc (Misc) + * 3ce, 3cf (GDC) + * + * - the CRTC (6845-style) registers: + * 3d4 index register + * 3d5 data register */ -#if _BYTE_ORDER == _LITTLE_ENDIAN -#define IO_ADDRESS(x) (x) -#else -#define IO_ADDRESS(x) ((x) ^ 0x03) -#endif -#define CRTC_INDEX IO_ADDRESS(0x03c4) -#define CRTC_DATA IO_ADDRESS(0x03c5) + +#define VGA_BASE 0x03c0 +#define TS_INDEX (VGA_BASE + VGA_TS_INDEX) +#define TS_DATA (VGA_BASE + VGA_TS_DATA) #define CD_DISABLEVIDEO 0x0020 -#define CMAP_READ_INDEX IO_ADDRESS(0x03c7) -#define CMAP_WRITE_INDEX IO_ADDRESS(0x03c8) -#define CMAP_DATA IO_ADDRESS(0x03c9) +#define CMAP_WRITE_INDEX (VGA_BASE + 0x08) +#define CMAP_DATA (VGA_BASE + 0x09) /* per-display variables */ struct mgx_softc { - struct sunfb sc_sunfb; /* common base device */ - + struct sunfb sc_sunfb; /* common base device */ bus_space_tag_t sc_bustag; - bus_addr_t sc_paddr; - + bus_addr_t sc_paddr; /* for mmap() */ u_int8_t sc_cmap[256 * 3]; /* shadow colormap */ - volatile u_int8_t *sc_vidc; /* ramdac registers */ - - int sc_nscreens; + vaddr_t sc_vidc; /* ramdac registers */ + vaddr_t sc_xreg; /* AT24 registers */ + uint32_t sc_dec; /* dec register template */ + int sc_nscreens; }; -int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *); -int mgx_alloc_screen(void *, const struct wsscreen_descr *, void **, - int *, int *, long *); -void mgx_free_screen(void *, void *); -int mgx_show_screen(void *, void *, int, void (*cb)(void *, int, int), - void *); -paddr_t mgx_mmap(void *, off_t, int); -void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); -int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); -int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); -void mgx_loadcmap(struct mgx_softc *, int, int); -void mgx_burner(void *, u_int ,u_int); +int mgx_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void mgx_burner(void *, u_int ,u_int); +void mgx_free_screen(void *, void *); +int mgx_ioctl(void *, u_long, caddr_t, int, struct proc *); +paddr_t mgx_mmap(void *, off_t, int); +int mgx_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); struct wsdisplay_accessops mgx_accessops = { mgx_ioctl, @@ -121,6 +149,30 @@ struct wsdisplay_accessops mgx_accessops = { mgx_burner }; +int mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *); +void mgx_loadcmap(struct mgx_softc *, int, int); +int mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *); +void mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); + +void mgx_ras_copycols(void *, int, int, int, int); +void mgx_ras_copyrows(void *, int, int, int); +void mgx_ras_do_cursor(struct rasops_info *); +void mgx_ras_erasecols(void *, int, int, int, long int); +void mgx_ras_eraserows(void *, int, int, long int); +void mgx_ras_init(struct mgx_softc *, uint); + +uint8_t mgx_read_1(vaddr_t, uint); +uint16_t mgx_read_2(vaddr_t, uint); +void mgx_write_1(vaddr_t, uint, uint8_t); +void mgx_write_4(vaddr_t, uint, uint32_t); + +int mgx_wait_engine(struct mgx_softc *); +int mgx_wait_fifo(struct mgx_softc *, uint); + +/* + * Attachment Glue + */ + int mgxmatch(struct device *, void *, void *); void mgxattach(struct device *, struct device *, void *); @@ -161,6 +213,7 @@ mgxattach(struct device *parent, struct device *self, void *args) bus_space_handle_t bh; int node, fbsize; int isconsole; + uint16_t chipid; bt = sa->sa_bustag; node = sa->sa_node; @@ -183,7 +236,26 @@ mgxattach(struct device *parent, struct device *self, void *args) printf("\n%s: couldn't map crtc registers\n", self->dv_xname); return; } - sc->sc_vidc = (volatile u_int8_t *)bus_space_vaddr(bt, bh); + sc->sc_vidc = (vaddr_t)bus_space_vaddr(bt, bh); + + sc->sc_bustag = bt; + if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_ATREG].sbr_slot, + sa->sa_reg[MGX_REG_ATREG].sbr_offset + MGX_REG_ATREG_OFFSET, + MGX_REG_ATREG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { + printf("\n%s: couldn't map crtc registers\n", self->dv_xname); + /* XXX unmap vidc */ + return; + } + sc->sc_xreg = (vaddr_t)bus_space_vaddr(bt, bh); + + /* + * Check the chip ID. If it's not an AT24, prefer not to access + * the extended registers at all. + */ + chipid = mgx_read_2(sc->sc_xreg, ATR_ID); + if (chipid != ID_AT24) { + sc->sc_xreg = (vaddr_t)0; + } /* enable video */ mgx_burner(sc, 1, 0); @@ -207,6 +279,7 @@ mgxattach(struct device *parent, struct device *self, void *args) round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { printf("\n%s: couldn't map video memory\n", self->dv_xname); + /* XXX unmap vidc and xreg */ return; } sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); @@ -220,6 +293,13 @@ mgxattach(struct device *parent, struct device *self, void *args) printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + if (chipid != ID_AT24) { + printf("%s: unexpected engine id %04x\n", + self->dv_xname, chipid); + } + + mgx_ras_init(sc, chipid); + if (isconsole) { fbwscons_console_init(&sc->sc_sunfb, -1); } @@ -228,7 +308,50 @@ mgxattach(struct device *parent, struct device *self, void *args) } /* - * wsdisplay operations + * Register Access + * + * On big-endian systems such as the sparc, it is necessary to flip + * the low-order bits of the addresses to reach the right register. + */ + +uint8_t +mgx_read_1(vaddr_t regs, uint offs) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + return *(volatile uint8_t *)(regs + offs); +#else + return *(volatile uint8_t *)(regs + (offs ^ 3)); +#endif +} + +uint16_t +mgx_read_2(vaddr_t regs, uint offs) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + return *(volatile uint16_t *)(regs + offs); +#else + return *(volatile uint16_t *)(regs + (offs ^ 2)); +#endif +} + +void +mgx_write_1(vaddr_t regs, uint offs, uint8_t val) +{ +#if _BYTE_ORDER == _LITTLE_ENDIAN + *(volatile uint8_t *)(regs + offs) = val; +#else + *(volatile uint8_t *)(regs + (offs ^ 3)) = val; +#endif +} + +void +mgx_write_4(vaddr_t regs, uint offs, uint32_t val) +{ + *(volatile uint32_t *)(regs + offs) = val; +} + +/* + * Wsdisplay Operations */ int @@ -333,16 +456,36 @@ void mgx_burner(void *v, u_int on, u_int flags) { struct mgx_softc *sc = v; + uint mode; + +#ifdef notyet + if (sc->sc_xreg != 0) { + mode = mgx_read_1(sc->sc_xreg, ATR_DPMS); + if (on) + CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE); + else { + SET(mode, DPMS_HSYNC_DISABLE); +#if 0 /* needs ramdac reprogramming on resume */ + if (flags & WSDISPLAY_BURN_VBLANK) + SET(mode, DPMS_VSYNC_DISABLE); +#endif + } + mgx_write_1(sc->sc_xreg, ATR_DPMS, mode); + return; + } +#endif - sc->sc_vidc[CRTC_INDEX] = 1; /* TS mode register */ + mgx_write_1(sc->sc_vidc, TS_INDEX, 1); /* TS mode register */ + mode = mgx_read_1(sc->sc_vidc, TS_DATA); if (on) - sc->sc_vidc[CRTC_DATA] &= ~CD_DISABLEVIDEO; + mode &= ~CD_DISABLEVIDEO; else - sc->sc_vidc[CRTC_DATA] |= CD_DISABLEVIDEO; + mode |= CD_DISABLEVIDEO; + mgx_write_1(sc->sc_vidc, TS_DATA, mode); } /* - * Colormap handling routines + * Colormap Handling Routines */ void @@ -364,10 +507,10 @@ mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors) u_int8_t *color; int i; - sc->sc_vidc[CMAP_WRITE_INDEX] = start; + mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start); color = sc->sc_cmap + start * 3; for (i = ncolors * 3; i != 0; i--) - sc->sc_vidc[CMAP_DATA] = *color++; + mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++); } int @@ -379,15 +522,16 @@ mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) if (index >= 256 || count > 256 - index) return (EINVAL); + index *= 3; for (i = 0; i < count; i++) { if ((error = - copyout(cm + (index + i) * 3 + 0, &rcm->red[i], 1)) != 0) + copyout(cm + index++, &rcm->red[i], 1)) != 0) return (error); if ((error = - copyout(cm + (index + i) * 3 + 1, &rcm->green[i], 1)) != 0) + copyout(cm + index++, &rcm->green[i], 1)) != 0) return (error); if ((error = - copyout(cm + (index + i) * 3 + 2, &rcm->blue[i], 1)) != 0) + copyout(cm + index++, &rcm->blue[i], 1)) != 0) return (error); } @@ -403,17 +547,283 @@ mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm) if (index >= 256 || count > 256 - index) return (EINVAL); + index *= 3; for (i = 0; i < count; i++) { if ((error = - copyin(&rcm->red[i], cm + (index + i) * 3 + 0, 1)) != 0) + copyin(&rcm->red[i], cm + index++, 1)) != 0) return (error); if ((error = - copyin(&rcm->green[i], cm + (index + i) * 3 + 1, 1)) != 0) + copyin(&rcm->green[i], cm + index++, 1)) != 0) return (error); if ((error = - copyin(&rcm->blue[i], cm + (index + i) * 3 + 2, 1)) != 0) + copyin(&rcm->blue[i], cm + index++, 1)) != 0) return (error); } return (0); } + +/* + * Accelerated Text Console Code + * + * The X driver makes sure there are at least as many FIFOs available as + * registers to write. They can thus be considered as write slots. + * + * The code below expects to run on at least an AT24 chip, and does not + * care for the AP6422 which has fewer FIFOs; some operations would need + * to be done in two steps to support this chip. + */ + +int +mgx_wait_engine(struct mgx_softc *sc) +{ + uint i; + uint stat; + + for (i = 10000; i != 0; i--) { + stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS); + if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY)) + break; + } + + return i; +} + +int +mgx_wait_fifo(struct mgx_softc *sc, uint nfifo) +{ + uint i; + uint stat; + + for (i = 10000; i != 0; i--) { + stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >> + FIFO_SHIFT; + if (stat >= nfifo) + break; + mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0); + } + + return i; +} + +void +mgx_ras_init(struct mgx_softc *sc, uint chipid) +{ + /* + * Check the chip ID. If it's not a 6424, do not plug the + * accelerated routines. + */ + + if (chipid != ID_AT24) + return; + + /* + * Wait until the chip is completely idle. + */ + + if (mgx_wait_engine(sc) == 0) + return; + if (mgx_wait_fifo(sc, FIFO_AT24) == 0) + return; + + /* + * Compute the invariant bits of the DEC register. + */ + + switch (sc->sc_sunfb.sf_depth) { + case 8: + sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT; + break; + case 15: + case 16: + sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT; + break; + case 32: + sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT; + break; + default: + return; /* not supported */ + } + + switch (sc->sc_sunfb.sf_width) { + case 640: + sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT; + break; + case 800: + sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT; + break; + case 1024: + sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT; + break; + case 1152: + sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT; + break; + case 1280: + sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT; + break; + case 1600: + sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT; + break; + default: + return; /* not supported */ + } + + sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols; + sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows; + sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols; + sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows; + sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor; + +#ifdef notneeded + mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1); + mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0)); + mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM, + ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1)); +#else + mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0); +#endif + mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff); +} + +void +mgx_ras_copycols(void *v, int row, int src, int dst, int n) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + uint dec = sc->sc_dec; + + n *= ri->ri_font->fontwidth; + src *= ri->ri_font->fontwidth; + src += ri->ri_xorigin; + dst *= ri->ri_font->fontwidth; + dst += ri->ri_xorigin; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + if (src < dst) { + src += n - 1; + dst += n - 1; + dec |= DEC_DIR_X_REVERSE; + } + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); + mgx_wait_engine(sc); +} + +void +mgx_ras_copyrows(void *v, int src, int dst, int n) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + uint dec = sc->sc_dec; + + n *= ri->ri_font->fontheight; + src *= ri->ri_font->fontheight; + src += ri->ri_yorigin; + dst *= ri->ri_font->fontheight; + dst += ri->ri_yorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + if (src < dst) { + src += n - 1; + dst += n - 1; + dec |= DEC_DIR_Y_REVERSE; + } + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); + mgx_wait_engine(sc); +} + +void +mgx_ras_erasecols(void *v, int row, int col, int n, long int attr) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + int fg, bg; + uint dec = sc->sc_dec; + + ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); + bg = ri->ri_devcmap[bg]; + + n *= ri->ri_font->fontwidth; + col *= ri->ri_font->fontwidth; + col += ri->ri_xorigin; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_FG, bg); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n)); + mgx_wait_engine(sc); +} + +void +mgx_ras_eraserows(void *v, int row, int n, long int attr) +{ + struct rasops_info *ri = v; + struct mgx_softc *sc = ri->ri_hw; + int fg, bg; + uint dec = sc->sc_dec; + + ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL); + bg = ri->ri_devcmap[bg]; + + dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_FG, bg); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) { + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0)); + mgx_write_4(sc->sc_xreg, ATR_WH, + ATR_DUAL(ri->ri_height, ri->ri_width)); + } else { + n *= ri->ri_font->fontheight; + row *= ri->ri_font->fontheight; + row += ri->ri_yorigin; + + mgx_write_4(sc->sc_xreg, ATR_DST_XY, + ATR_DUAL(row, ri->ri_xorigin)); + mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth)); + } + mgx_wait_engine(sc); +} + +void +mgx_ras_do_cursor(struct rasops_info *ri) +{ + struct mgx_softc *sc = ri->ri_hw; + int row, col; + uint dec = sc->sc_dec; + + row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; + col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; + + dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) | + (DEC_START_DIMX << DEC_START_SHIFT); + mgx_wait_fifo(sc, 5); + mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC); + mgx_write_4(sc->sc_xreg, ATR_DEC, dec); + mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col)); + mgx_write_4(sc->sc_xreg, ATR_WH, + ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth)); + mgx_wait_engine(sc); +} |