Module Name: src
Committed By: macallan
Date: Wed Oct 9 01:28:33 UTC 2013
Modified Files:
src/sys/dev/pci: gffb.c
Log Message:
add hardware acceleration
For now this supports only GeForce2 MX cards but most NV1x chips should work
once their PCI iDs are added to gffb_match()
Tested only on macppc.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/pci/gffb.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/pci/gffb.c
diff -u src/sys/dev/pci/gffb.c:1.2 src/sys/dev/pci/gffb.c:1.3
--- src/sys/dev/pci/gffb.c:1.2 Wed Oct 2 16:35:38 2013
+++ src/sys/dev/pci/gffb.c Wed Oct 9 01:28:33 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $ */
+/* $NetBSD: gffb.c,v 1.3 2013/10/09 01:28:33 macallan Exp $ */
/*
* Copyright (c) 2007, 2012 Michael Lorenz
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.2 2013/10/02 16:35:38 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gffb.c,v 1.3 2013/10/09 01:28:33 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -96,6 +96,9 @@ struct gffb_softc {
u_char sc_cmap_green[256];
u_char sc_cmap_blue[256];
int sc_put, sc_current, sc_free;
+ uint32_t sc_rop;
+ void (*sc_putchar)(void *, int, int, u_int, long);
+ kmutex_t sc_lock;
glyphcache sc_gc;
};
@@ -119,22 +122,20 @@ static int gffb_putpalreg(struct gffb_s
static void gffb_init(struct gffb_softc *);
static void gffb_make_room(struct gffb_softc *, int);
+static void gffb_sync(struct gffb_softc *);
-#if notyet
-static void gffb_flush_engine(struct gffb_softc *);
static void gffb_rectfill(struct gffb_softc *, int, int, int, int,
uint32_t);
static void gffb_bitblt(void *, int, int, int, int, int,
int, int);
+static void gffb_rop(struct gffb_softc *, int);
static void gffb_cursor(void *, int, int, int);
static void gffb_putchar(void *, int, int, u_int, long);
-static void gffb_putchar_aa(void *, int, int, u_int, long);
static void gffb_copycols(void *, int, int, int, int);
static void gffb_erasecols(void *, int, int, int, long);
static void gffb_copyrows(void *, int, int, int);
static void gffb_eraserows(void *, int, int, long);
-#endif /* notyet */
struct wsdisplay_accessops gffb_accessops = {
gffb_ioctl,
@@ -198,7 +199,7 @@ gffb_attach(device_t parent, device_t se
#ifdef GLYPHCACHE_DEBUG
/* leave some visible VRAM unused so we can see the glyph cache */
- sc->sc_height -= 200;
+ sc->sc_height -= 300;
#endif
if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) {
@@ -243,54 +244,59 @@ gffb_attach(device_t parent, device_t se
sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
sc->sc_locked = 0;
- vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
- &gffb_accessops);
- sc->vd.init_screen = gffb_init_screen;
-
sc->sc_vramsize = bus_space_read_4(sc->sc_memt, sc->sc_regh,
GFFB_VRAM) & 0xfff00000;
printf("vram: %d MB\n", sc->sc_vramsize >> 20);
+#ifdef GFFB_DEBUG
printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
- /* init engine here */
+#endif
+
+ /*
+ * we don't have hardware synchronization so we need a lock to serialize
+ * access to the DMA buffer between normal and kernel output
+ * actually it might be enough to use atomic ops on sc_current, sc_free
+ * etc. but for now we'll play it safe
+ * XXX we will probably deadlock if we take an interrupt while sc_lock
+ * is held and then try to printf()
+ */
+ mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+
+ /* init engine here */
gffb_init(sc);
- printf("put: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT));
- printf("get: %08x\n", bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET));
+
+ vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
+ &gffb_accessops);
+ sc->vd.init_screen = gffb_init_screen;
+
ri = &sc->sc_console_screen.scr_ri;
-#if notyet
sc->sc_gc.gc_bitblt = gffb_bitblt;
sc->sc_gc.gc_blitcookie = sc;
- sc->sc_gc.gc_rop = R128_ROP3_S;
-#endif
+ sc->sc_gc.gc_rop = 0xcc;
if (is_console) {
vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
&defattr);
sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
-#if notyet
gffb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
- ri->ri_devcmap[(defattr >> 16) & 0xff]);
-#else
- memset(sc->sc_fbaddr + 0x2000,
- ri->ri_devcmap[(defattr >> 16) & 0xff],
- sc->sc_height * sc->sc_stride);
-#endif
+ ri->ri_devcmap[(defattr >> 16) & 0xf]);
+
sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
-#if notyet
+
glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
(0x800000 / sc->sc_stride) - sc->sc_height - 5,
sc->sc_width,
ri->ri_font->fontwidth,
ri->ri_font->fontheight,
defattr);
-#endif
+
wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
defattr);
vcons_replay_msgbuf(&sc->sc_console_screen);
@@ -305,14 +311,13 @@ gffb_attach(device_t parent, device_t se
&defattr);
} else
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
-#if notyet
+
glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
(0x800000 / sc->sc_stride) - sc->sc_height - 5,
sc->sc_width,
ri->ri_font->fontwidth,
ri->ri_font->fontheight,
defattr);
-#endif
}
j = 0;
@@ -334,6 +339,30 @@ gffb_attach(device_t parent, device_t se
aa.accesscookie = &sc->vd;
config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
+
+#ifdef GFFB_DEBUG
+ for (i = 0; i < 40; i++) {
+ for (j = 0; j < 40; j++) {
+ gffb_rectfill(sc, i * 20, j * 20, 20, 20,
+ (i + j ) & 1 ? 0xe0e0e0e0 : 0x03030303);
+ }
+ }
+
+ //gffb_bitblt(sc, 0, 800, 10, 10, 400, 300, 0xcc);
+ gffb_rectfill(sc, 0, 800, 1280, 224, 0x92929292);
+ gffb_bitblt(sc, 0, 10, 10, 810, 200, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 10, 840, 300, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 10, 870, 400, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 10, 900, 500, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 10, 930, 600, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 610, 810, 200, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 610, 840, 300, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 610, 870, 400, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 610, 900, 500, 20, 0xcc);
+ gffb_bitblt(sc, 0, 10, 610, 930, 600, 20, 0xcc);
+ gffb_sync(sc);
+ printf("put %x current %x\n", sc->sc_put, sc->sc_current);
+#endif
}
static int
@@ -389,12 +418,10 @@ gffb_ioctl(void *v, void *vs, u_long cmd
if(new_mode == WSDISPLAYIO_MODE_EMUL) {
gffb_init(sc);
gffb_restore_palette(sc);
-#if notyet
glyphcache_wipe(&sc->sc_gc);
gffb_rectfill(sc, 0, 0, sc->sc_width,
sc->sc_height, ms->scr_ri.ri_devcmap[
- (ms->scr_defattr >> 16) & 0xff]);
-#endif
+ (ms->scr_defattr >> 16) & 0xf]);
vcons_redraw_screen(ms);
}
}
@@ -486,23 +513,22 @@ gffb_init_screen(void *cookie, struct vc
rasops_init(ri, 0, 0);
ri->ri_caps = WSSCREEN_WSCOLORS;
+#if 0
scr->scr_flags |= VCONS_DONT_READ;
+#endif
rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
sc->sc_width / ri->ri_font->fontwidth);
ri->ri_hw = scr;
-#if notyet
+
+ sc->sc_putchar = ri->ri_ops.putchar;
ri->ri_ops.copyrows = gffb_copyrows;
ri->ri_ops.copycols = gffb_copycols;
ri->ri_ops.eraserows = gffb_eraserows;
ri->ri_ops.erasecols = gffb_erasecols;
ri->ri_ops.cursor = gffb_cursor;
- if (FONT_IS_ALPHA(ri->ri_font)) {
- ri->ri_ops.putchar = gffb_putchar_aa;
- } else
- ri->ri_ops.putchar = gffb_putchar;
-#endif
+ ri->ri_ops.putchar = gffb_putchar;
}
static int
@@ -514,7 +540,7 @@ gffb_putcmap(struct gffb_softc *sc, stru
int i, error;
u_char rbuf[256], gbuf[256], bbuf[256];
-#ifdef R128FB_DEBUG
+#ifdef GFFB_DEBUG
aprint_debug("putcmap: %d %d\n",index, count);
#endif
if (cm->index >= 256 || cm->count > 256 ||
@@ -619,6 +645,7 @@ gffb_dma_kickoff(struct gffb_softc *sc)
scratch = *sc->sc_fbaddr;
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_PUT,
sc->sc_put);
+ membar_sync();
}
}
@@ -662,26 +689,26 @@ gffb_make_room(struct gffb_softc *sc, in
sc->sc_free = 0x2000 - sc->sc_current;
if (sc->sc_free < size) {
gffb_dmanext(sc, 0x20000000);
- if(get <= SKIPS) {
- if (sc->sc_put <= SKIPS) {
+ if(get <= (SKIPS << 2)) {
+ if (sc->sc_put <= (SKIPS << 2)) {
/* corner case - will be idle */
bus_space_write_4(sc->sc_memt,
sc->sc_regh, GFFB_FIFO_PUT,
- SKIPS + 1);
+ (SKIPS + 1) << 2);
}
do {
get = bus_space_read_4(
sc->sc_memt, sc->sc_regh,
GFFB_FIFO_GET);
- } while (get <= SKIPS);
+ } while (get <= (SKIPS << 2));
}
bus_space_write_4(sc->sc_memt, sc->sc_regh,
- GFFB_FIFO_PUT, SKIPS);
- sc->sc_current = sc->sc_put = SKIPS;
- sc->sc_free = get - (SKIPS + 1);
+ GFFB_FIFO_PUT, SKIPS << 2);
+ sc->sc_current = sc->sc_put = (SKIPS << 2);
+ sc->sc_free = get - ((SKIPS + 1) << 2);
}
} else
- sc->sc_free = get - sc->sc_current - 1;
+ sc->sc_free = get - sc->sc_current - 4;
}
}
@@ -689,28 +716,41 @@ static void
gffb_sync(struct gffb_softc *sc)
{
int bail;
+ int i;
- bail = 100000;
+ gffb_dma_kickoff(sc); /* just in case */
+
+ bail = 100000000;
while ((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET) !=
sc->sc_put) && (bail > 0)) {
+#if 0
bail--;
- delay(1);
+#endif
}
- if (bail == 0) printf("DMA timed out\n");
+ if (bail == 0) goto crap;
- bail = 100000;
+ bail = 100000000;
while((bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_BUSY) != 0) &&
(bail > 0)) {
+#if 0
bail--;
- delay(1);
+#endif
}
- if (bail == 0) printf("engine timed out\n");
+ if (bail == 0) goto crap;
+ return;
+crap:
+ sc->sc_put = 0;
+ sc->sc_current = 0;
+ for (i = 0; i < 0x2000; i += 4)
+ bus_space_write_stream_4(sc->sc_memt, sc->sc_fbh, i, 0);
+// printf("DMA lockup\n");
}
static void
gffb_init(struct gffb_softc *sc)
{
int i;
+ uint32_t foo;
/* init display start */
bus_space_write_4(sc->sc_memt, sc->sc_regh,
@@ -736,6 +776,14 @@ gffb_init(struct gffb_softc *sc)
bus_space_write_4(sc->sc_memt, sc->sc_regh,
GFFB_PMC + 0x244 + (i * 0x10), sc->sc_vramsize - 1);
}
+
+ for (i = 0; i < 8; i++) {
+ bus_space_write_4(sc->sc_memt, sc->sc_regh,
+ GFFB_PFB + 0x0240 + (i * 0x10), 0);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh,
+ GFFB_PFB + 0x0244 + (i * 0x10), sc->sc_vramsize - 1);
+ }
+
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN, 0x80000010);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x04, 0x80011201);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x08, 0x80000011);
@@ -793,7 +841,19 @@ gffb_init(struct gffb_softc *sc)
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2094, 0x00007fff);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2098, 0x00000002); /* start of command buffer? */
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x209c, 0x00000002);
- /* __BIG_ENDIAN part? */
+#if BYTE_ORDER == BIG_ENDIAN
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2010, 0x01088042);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2020, 0x01088043);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2030, 0x01088044);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2040, 0x01088019);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2050, 0x0108a05c);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2060, 0x0108809f);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2070, 0x0108804a);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2080, 0x01098077);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2034, 0x00000001);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PRAMIN + 0x2074, 0x00000001);
+#endif
+
/* PGRAPH setup */
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0504, 0x00000001);
@@ -826,6 +886,46 @@ gffb_init(struct gffb_softc *sc)
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x1254, 0x00000001);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PFIFO + 0x0500, 0x00000001);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0080, 0xFFFFFFFF);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0080, 0x00000000);
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0140, 0x00000000);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0100, 0xFFFFFFFF);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0144, 0x10010100);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0714, 0xFFFFFFFF);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0720, 0x00000001);
+ foo = bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0710);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0710,
+ foo & 0x0007ff00);
+ foo = bus_space_read_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0710);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0710,
+ foo | 0x00020100);
+
+ /* NV_ARCH_10 */
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0084, 0x00118700);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0088, 0x24E00810);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x008C, 0x55DE0030);
+
+ for(i = 0; i < 128; i += 4) {
+ bus_space_write_4(sc->sc_memt, sc->sc_regh,
+ GFFB_PGRAPH + 0x0B00 + i,
+ bus_space_read_4(sc->sc_memt, sc->sc_regh,
+ GFFB_PFB + 0x0240 + i));
+ }
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x640, 0);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x644, 0);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x684, sc->sc_vramsize - 1);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x688, sc->sc_vramsize - 1);
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0810, 0x00000000);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0608, 0xFFFFFFFF);
+
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x053C, 0);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0540, 0);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0544, 0x00007FFF);
+ bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_PGRAPH + 0x0548, 0x00007FFF);
+
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_CMDSTART, 0x00000002);
bus_space_write_4(sc->sc_memt, sc->sc_regh, GFFB_FIFO_GET, 0);
sc->sc_put = 0;
@@ -856,17 +956,222 @@ gffb_init(struct gffb_softc *sc)
gffb_dmastart(sc, SURFACE_FORMAT, 4);
gffb_dmanext(sc, SURFACE_FORMAT_DEPTH8);
gffb_dmanext(sc, sc->sc_stride | (sc->sc_stride << 16));
- gffb_dmanext(sc, 0);
- gffb_dmanext(sc, 0);
+ gffb_dmanext(sc, 0x2000); /* src offset */
+ gffb_dmanext(sc, 0x2000); /* dst offset */
gffb_dmastart(sc, RECT_FORMAT, 1);
gffb_dmanext(sc, RECT_FORMAT_DEPTH8);
+ gffb_dmastart(sc, PATTERN_FORMAT, 1);
+ gffb_dmanext(sc, PATTERN_FORMAT_DEPTH8);
+
+ gffb_dmastart(sc, PATTERN_COLOR_0, 4);
+ gffb_dmanext(sc, 0xffffffff);
+ gffb_dmanext(sc, 0xffffffff);
+ gffb_dmanext(sc, 0xffffffff);
+ gffb_dmanext(sc, 0xffffffff);
+
gffb_dmastart(sc, ROP_SET, 1);
gffb_dmanext(sc, 0xcc);
+ sc->sc_rop = 0xcc;
gffb_dma_kickoff(sc);
gffb_sync(sc);
printf("put %x current %x\n", sc->sc_put, sc->sc_current);
+
}
+static void
+gffb_rop(struct gffb_softc *sc, int rop)
+{
+ if (rop == sc->sc_rop)
+ return;
+ sc->sc_rop = rop;
+ gffb_dmastart(sc, ROP_SET, 1);
+ gffb_dmanext(sc, rop);
+}
+
+static void
+gffb_rectfill(struct gffb_softc *sc, int x, int y, int wi, int he,
+ uint32_t colour)
+{
+ mutex_enter(&sc->sc_lock);
+ gffb_rop(sc, 0xcc);
+
+ gffb_dmastart(sc, RECT_SOLID_COLOR, 1);
+ gffb_dmanext(sc, colour);
+
+ gffb_dmastart(sc, RECT_SOLID_RECTS(0), 2);
+ gffb_dmanext(sc, (x << 16) | y);
+ gffb_dmanext(sc, (wi << 16) | he);
+ gffb_dma_kickoff(sc);
+ mutex_exit(&sc->sc_lock);
+}
+
+static void
+gffb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
+ int wi, int he, int rop)
+{
+ struct gffb_softc *sc = cookie;
+
+ mutex_enter(&sc->sc_lock);
+
+ gffb_rop(sc, rop);
+
+ gffb_dmastart(sc, BLIT_POINT_SRC, 3);
+ gffb_dmanext(sc, (ys << 16) | xs);
+ gffb_dmanext(sc, (yd << 16) | xd);
+ gffb_dmanext(sc, (he << 16) | wi);
+ gffb_dma_kickoff(sc);
+ mutex_exit(&sc->sc_lock);
+}
+
+static void
+gffb_cursor(void *cookie, int on, int row, int col)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int x, y, wi, he;
+
+ wi = ri->ri_font->fontwidth;
+ he = ri->ri_font->fontheight;
+
+ if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
+ x = ri->ri_ccol * wi + ri->ri_xorigin;
+ y = ri->ri_crow * he + ri->ri_yorigin;
+ if (ri->ri_flg & RI_CURSOR) {
+ gffb_bitblt(sc, x, y, x, y, wi, he, 0x33);
+ ri->ri_flg &= ~RI_CURSOR;
+ }
+ ri->ri_crow = row;
+ ri->ri_ccol = col;
+ if (on) {
+ x = ri->ri_ccol * wi + ri->ri_xorigin;
+ y = ri->ri_crow * he + ri->ri_yorigin;
+ gffb_bitblt(sc, x, y, x, y, wi, he, 0x33);
+ ri->ri_flg |= RI_CURSOR;
+ }
+ } else {
+ scr->scr_ri.ri_crow = row;
+ scr->scr_ri.ri_ccol = col;
+ scr->scr_ri.ri_flg &= ~RI_CURSOR;
+ }
+
+}
+
+static void
+gffb_putchar(void *cookie, int row, int col, u_int c, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct wsdisplay_font *font = PICK_FONT(ri, c);
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int x, y, wi, he, rv = GC_NOPE;
+ uint32_t bg;
+
+ if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
+ return;
+
+ if (!CHAR_IN_FONT(c, font))
+ return;
+
+ wi = font->fontwidth;
+ he = font->fontheight;
+
+ x = ri->ri_xorigin + col * wi;
+ y = ri->ri_yorigin + row * he;
+ bg = ri->ri_devcmap[(attr >> 16) & 0xf];
+
+ if (c == 0x20) {
+ gffb_rectfill(sc, x, y, wi, he, bg);
+ return;
+ }
+ rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
+ if (rv == GC_OK)
+ return;
+
+ mutex_enter(&sc->sc_lock);
+ gffb_sync(sc);
+ sc->sc_putchar(cookie, row, col, c, attr);
+ membar_sync();
+ mutex_exit(&sc->sc_lock);
+
+ if (rv == GC_ADD) {
+ glyphcache_add(&sc->sc_gc, c, x, y);
+ }
+}
+
+static void
+gffb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int32_t xs, xd, y, width, height;
+
+ if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
+ xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
+ xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
+ y = ri->ri_yorigin + ri->ri_font->fontheight * row;
+ width = ri->ri_font->fontwidth * ncols;
+ height = ri->ri_font->fontheight;
+ gffb_bitblt(sc, xs, y, xd, y, width, height, 0xcc);
+ }
+}
+
+static void
+gffb_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int32_t x, y, width, height, fg, bg, ul;
+
+ if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
+ x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
+ y = ri->ri_yorigin + ri->ri_font->fontheight * row;
+ width = ri->ri_font->fontwidth * ncols;
+ height = ri->ri_font->fontheight;
+ rasops_unpack_attr(fillattr, &fg, &bg, &ul);
+
+ gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
+ }
+}
+
+static void
+gffb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int32_t x, ys, yd, width, height;
+
+ if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
+ x = ri->ri_xorigin;
+ ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
+ yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
+ width = ri->ri_emuwidth;
+ height = ri->ri_font->fontheight * nrows;
+ gffb_bitblt(sc, x, ys, x, yd, width, height, 0xcc);
+ }
+}
+
+static void
+gffb_eraserows(void *cookie, int row, int nrows, long fillattr)
+{
+ struct rasops_info *ri = cookie;
+ struct vcons_screen *scr = ri->ri_hw;
+ struct gffb_softc *sc = scr->scr_cookie;
+ int32_t x, y, width, height, fg, bg, ul;
+
+ if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
+ x = ri->ri_xorigin;
+ y = ri->ri_yorigin + ri->ri_font->fontheight * row;
+ width = ri->ri_emuwidth;
+ height = ri->ri_font->fontheight * nrows;
+ rasops_unpack_attr(fillattr, &fg, &bg, &ul);
+
+ gffb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
+ }
+}