summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2008-04-15 20:23:55 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2008-04-15 20:23:55 +0000
commit8be43d4c7a17abee04242c588bc6d149c2c59796 (patch)
tree02db355c6ad316abef27f2d5df64ef870e6f1553
parent30f272e9a6ca2cfdd4fb761f0f4c26c2a3b72e6b (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/hardware4
-rw-r--r--distrib/notes/sparc64/hardware4
-rw-r--r--share/man/man4/man4.sparc/mgx.46
-rw-r--r--share/man/man4/man4.sparc64/mgx.46
-rw-r--r--sys/arch/sparc/dev/mgx.c486
-rw-r--r--sys/dev/ic/atxxreg.h209
-rw-r--r--sys/dev/sbus/mgx.c514
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);
+}