Home | History | Annotate | Line # | Download | only in sbus
mgx.c revision 1.4
      1 /*	$NetBSD: mgx.c,v 1.4 2015/01/06 17:41:30 macallan Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2014 Michael Lorenz
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /* a console driver for the SSB 4096V-MGX graphics card */
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: mgx.c,v 1.4 2015/01/06 17:41:30 macallan Exp $");
     33 
     34 #include <sys/param.h>
     35 #include <sys/systm.h>
     36 #include <sys/buf.h>
     37 #include <sys/device.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/conf.h>
     40 #include <sys/kmem.h>
     41 
     42 #include <sys/bus.h>
     43 #include <machine/autoconf.h>
     44 
     45 #include <dev/sbus/sbusvar.h>
     46 #include <dev/sun/fbio.h>
     47 #include <dev/sun/fbvar.h>
     48 
     49 #include <dev/wscons/wsdisplayvar.h>
     50 #include <dev/wscons/wsconsio.h>
     51 #include <dev/wsfont/wsfont.h>
     52 #include <dev/rasops/rasops.h>
     53 
     54 #include <dev/wscons/wsdisplay_vconsvar.h>
     55 #include <dev/wscons/wsdisplay_glyphcachevar.h>
     56 
     57 #include <dev/ic/vgareg.h>
     58 #include <dev/sbus/mgxreg.h>
     59 
     60 #include "opt_wsemul.h"
     61 
     62 
     63 struct mgx_softc {
     64 	device_t	sc_dev;
     65 	bus_space_tag_t sc_tag;
     66 	bus_space_handle_t sc_blith;
     67 	bus_space_handle_t sc_vgah;
     68 	bus_addr_t	sc_paddr;
     69 	void		*sc_fbaddr;
     70 	int		sc_width;
     71 	int		sc_height;
     72 	int		sc_stride;
     73 	int		sc_fbsize;
     74 	int		sc_mode;
     75 	uint32_t	sc_dec;
     76 	u_char		sc_cmap_red[256];
     77 	u_char		sc_cmap_green[256];
     78 	u_char		sc_cmap_blue[256];
     79 	void (*sc_putchar)(void *, int, int, u_int, long);
     80 	struct vcons_screen sc_console_screen;
     81 	struct wsscreen_descr sc_defaultscreen_descr;
     82 	const struct wsscreen_descr *sc_screens[1];
     83 	struct wsscreen_list sc_screenlist;
     84 	struct vcons_data vd;
     85 	glyphcache 	sc_gc;
     86 };
     87 
     88 static int	mgx_match(device_t, cfdata_t, void *);
     89 static void	mgx_attach(device_t, device_t, void *);
     90 static int	mgx_ioctl(void *, void *, u_long, void *, int,
     91 				 struct lwp*);
     92 static paddr_t	mgx_mmap(void *, void *, off_t, int);
     93 static void	mgx_init_screen(void *, struct vcons_screen *, int,
     94 				 long *);
     95 static void	mgx_write_dac(struct mgx_softc *, int, int, int, int);
     96 static void	mgx_setup(struct mgx_softc *, int);
     97 static void	mgx_init_palette(struct mgx_softc *);
     98 static int	mgx_putcmap(struct mgx_softc *, struct wsdisplay_cmap *);
     99 static int 	mgx_getcmap(struct mgx_softc *, struct wsdisplay_cmap *);
    100 static int	mgx_wait_engine(struct mgx_softc *);
    101 static int	mgx_wait_fifo(struct mgx_softc *, unsigned int);
    102 
    103 static void	mgx_bitblt(void *, int, int, int, int, int, int, int);
    104 static void 	mgx_rectfill(void *, int, int, int, int, long);
    105 
    106 static void	mgx_putchar(void *, int, int, u_int, long);
    107 static void	mgx_cursor(void *, int, int, int);
    108 static void	mgx_copycols(void *, int, int, int, int);
    109 static void	mgx_erasecols(void *, int, int, int, long);
    110 static void	mgx_copyrows(void *, int, int, int);
    111 static void	mgx_eraserows(void *, int, int, long);
    112 
    113 CFATTACH_DECL_NEW(mgx, sizeof(struct mgx_softc),
    114     mgx_match, mgx_attach, NULL, NULL);
    115 
    116 struct wsdisplay_accessops mgx_accessops = {
    117 	mgx_ioctl,
    118 	mgx_mmap,
    119 	NULL,	/* vcons_alloc_screen */
    120 	NULL,	/* vcons_free_screen */
    121 	NULL,	/* vcons_show_screen */
    122 	NULL,	/* load_font */
    123 	NULL,	/* polls */
    124 	NULL,	/* scroll */
    125 };
    126 
    127 static int
    128 mgx_match(device_t parent, cfdata_t cf, void *aux)
    129 {
    130 	struct sbus_attach_args *sa = aux;
    131 
    132 	if (strcmp("SMSI,mgx", sa->sa_name) == 0)
    133 		return 100;
    134 	return 0;
    135 }
    136 
    137 /*
    138  * Attach a display.  We need to notice if it is the console, too.
    139  */
    140 static void
    141 mgx_attach(device_t parent, device_t self, void *args)
    142 {
    143 	struct mgx_softc *sc = device_private(self);
    144 	struct sbus_attach_args *sa = args;
    145 	struct wsemuldisplaydev_attach_args aa;
    146 	struct rasops_info *ri;
    147 	unsigned long defattr;
    148 	bus_space_handle_t bh;
    149 	int node = sa->sa_node;
    150 	int isconsole;
    151 
    152 	aprint_normal("\n");
    153 	sc->sc_dev = self;
    154 	sc->sc_tag = sa->sa_bustag;
    155 
    156 	sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot,
    157 	    sa->sa_reg[8].oa_base);
    158 
    159 	/* read geometry information from the device tree */
    160 	sc->sc_width = prom_getpropint(sa->sa_node, "width", 1152);
    161 	sc->sc_height = prom_getpropint(sa->sa_node, "height", 900);
    162 	sc->sc_stride = prom_getpropint(sa->sa_node, "linebytes", 900);
    163 	sc->sc_fbsize = sc->sc_height * sc->sc_stride;
    164 	sc->sc_fbaddr = NULL;
    165 	if (sc->sc_fbaddr == NULL) {
    166 		if (sbus_bus_map(sa->sa_bustag,
    167 			 sa->sa_slot,
    168 			 sa->sa_reg[8].oa_base,
    169 			 sc->sc_fbsize,
    170 			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
    171 			 &bh) != 0) {
    172 			aprint_error_dev(self, "cannot map framebuffer\n");
    173 			return;
    174 		}
    175 		sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh);
    176 	}
    177 
    178 	aprint_normal_dev(self, "%d x %d\n", sc->sc_width, sc->sc_height);
    179 
    180 	if (sbus_bus_map(sa->sa_bustag,
    181 			 sa->sa_slot,
    182 			 sa->sa_reg[4].oa_base, 0x1000, 0,
    183 			 &sc->sc_vgah) != 0) {
    184 		aprint_error("%s: couldn't map VGA registers\n",
    185 		    device_xname(sc->sc_dev));
    186 		return;
    187 	}
    188 
    189 	if (sbus_bus_map(sa->sa_bustag,
    190 			 sa->sa_slot,
    191 			 sa->sa_reg[5].oa_base + MGX_REG_ATREG_OFFSET, 0x1000,
    192 			 0, &sc->sc_blith) != 0) {
    193 		aprint_error("%s: couldn't map blitter registers\n",
    194 		    device_xname(sc->sc_dev));
    195 		return;
    196 	}
    197 
    198 	mgx_setup(sc, 8);
    199 
    200 	sc->sc_defaultscreen_descr = (struct wsscreen_descr) {
    201 		"default",
    202 		0, 0,
    203 		NULL,
    204 		8, 16,
    205 		WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
    206 		NULL
    207 	};
    208 	sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
    209 	sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
    210 
    211 	isconsole = fb_is_console(node);
    212 
    213 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
    214 	wsfont_init();
    215 
    216 	vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, &mgx_accessops);
    217 	sc->vd.init_screen = mgx_init_screen;
    218 
    219 	vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr);
    220 	sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
    221 
    222 	ri = &sc->sc_console_screen.scr_ri;
    223 
    224 	sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
    225 	sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
    226 	sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
    227 	sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
    228 
    229 	sc->sc_gc.gc_bitblt = mgx_bitblt;
    230 	sc->sc_gc.gc_rectfill = mgx_rectfill;
    231 	sc->sc_gc.gc_blitcookie = sc;
    232 	sc->sc_gc.gc_rop = ROP_SRC;
    233 
    234 	glyphcache_init(&sc->sc_gc,
    235 	    sc->sc_height + 5,
    236 	    (0x400000 / sc->sc_stride) - sc->sc_height - 5,
    237 	    sc->sc_width,
    238 	    ri->ri_font->fontwidth,
    239 	    ri->ri_font->fontheight,
    240 	    defattr);
    241 
    242 	mgx_init_palette(sc);
    243 
    244 	if(isconsole) {
    245 		wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
    246 		    defattr);
    247 		vcons_replay_msgbuf(&sc->sc_console_screen);
    248 	}
    249 
    250 	aa.console = isconsole;
    251 	aa.scrdata = &sc->sc_screenlist;
    252 	aa.accessops = &mgx_accessops;
    253 	aa.accesscookie = &sc->vd;
    254 
    255 	config_found(self, &aa, wsemuldisplaydevprint);
    256 }
    257 
    258 static inline void
    259 mgx_write_vga(struct mgx_softc *sc, uint32_t reg, uint8_t val)
    260 {
    261 	bus_space_write_1(sc->sc_tag, sc->sc_vgah, reg ^ 3, val);
    262 }
    263 
    264 static inline void
    265 mgx_write_1(struct mgx_softc *sc, uint32_t reg, uint8_t val)
    266 {
    267 	bus_space_write_1(sc->sc_tag, sc->sc_blith, reg ^ 3, val);
    268 }
    269 
    270 static inline uint8_t
    271 mgx_read_1(struct mgx_softc *sc, uint32_t reg)
    272 {
    273 	return bus_space_read_1(sc->sc_tag, sc->sc_blith, reg ^ 3);
    274 }
    275 
    276 static inline void
    277 mgx_write_4(struct mgx_softc *sc, uint32_t reg, uint32_t val)
    278 {
    279 	bus_space_write_4(sc->sc_tag, sc->sc_blith, reg, val);
    280 }
    281 
    282 
    283 static void
    284 mgx_write_dac(struct mgx_softc *sc, int idx, int r, int g, int b)
    285 {
    286 	mgx_write_vga(sc, VGA_BASE + VGA_DAC_ADDRW, idx);
    287 	mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, r);
    288 	mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, g);
    289 	mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, b);
    290 }
    291 
    292 static void
    293 mgx_init_palette(struct mgx_softc *sc)
    294 {
    295 	struct rasops_info *ri = &sc->sc_console_screen.scr_ri;
    296 	int i, j = 0;
    297 	uint8_t cmap[768];
    298 
    299 	rasops_get_cmap(ri, cmap, sizeof(cmap));
    300 	for (i = 0; i < 256; i++) {
    301 		sc->sc_cmap_red[i] = cmap[j];
    302 		sc->sc_cmap_green[i] = cmap[j + 1];
    303 		sc->sc_cmap_blue[i] = cmap[j + 2];
    304 		mgx_write_dac(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
    305 		j += 3;
    306 	}
    307 }
    308 
    309 static int
    310 mgx_putcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm)
    311 {
    312 	u_char *r, *g, *b;
    313 	u_int index = cm->index;
    314 	u_int count = cm->count;
    315 	int i, error;
    316 	u_char rbuf[256], gbuf[256], bbuf[256];
    317 
    318 	if (cm->index >= 256 || cm->count > 256 ||
    319 	    (cm->index + cm->count) > 256)
    320 		return EINVAL;
    321 	error = copyin(cm->red, &rbuf[index], count);
    322 	if (error)
    323 		return error;
    324 	error = copyin(cm->green, &gbuf[index], count);
    325 	if (error)
    326 		return error;
    327 	error = copyin(cm->blue, &bbuf[index], count);
    328 	if (error)
    329 		return error;
    330 
    331 	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
    332 	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
    333 	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
    334 
    335 	r = &sc->sc_cmap_red[index];
    336 	g = &sc->sc_cmap_green[index];
    337 	b = &sc->sc_cmap_blue[index];
    338 
    339 	for (i = 0; i < count; i++) {
    340 		mgx_write_dac(sc, index, *r, *g, *b);
    341 		index++;
    342 		r++, g++, b++;
    343 	}
    344 	return 0;
    345 }
    346 
    347 static int
    348 mgx_getcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm)
    349 {
    350 	u_int index = cm->index;
    351 	u_int count = cm->count;
    352 	int error;
    353 
    354 	if (index >= 255 || count > 256 || index + count > 256)
    355 		return EINVAL;
    356 
    357 	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
    358 	if (error)
    359 		return error;
    360 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
    361 	if (error)
    362 		return error;
    363 	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
    364 	if (error)
    365 		return error;
    366 
    367 	return 0;
    368 }
    369 
    370 static int
    371 mgx_wait_engine(struct mgx_softc *sc)
    372 {
    373 	unsigned int i;
    374 	uint8_t stat;
    375 
    376 	for (i = 100000; i != 0; i--) {
    377 		stat = mgx_read_1(sc, ATR_BLT_STATUS);
    378 		if ((stat & (BLT_HOST_BUSY | BLT_ENGINE_BUSY)) == 0)
    379 			break;
    380 	}
    381 
    382 	return i;
    383 }
    384 
    385 static int
    386 mgx_wait_fifo(struct mgx_softc *sc, unsigned int nfifo)
    387 {
    388 	unsigned int i;
    389 	uint8_t stat;
    390 
    391 	for (i = 100000; i != 0; i--) {
    392 		stat = mgx_read_1(sc, ATR_FIFO_STATUS);
    393 		stat = (stat & FIFO_MASK) >> FIFO_SHIFT;
    394 		if (stat >= nfifo)
    395 			break;
    396 		mgx_write_1(sc, ATR_FIFO_STATUS, 0);
    397 	}
    398 
    399 	return i;
    400 }
    401 
    402 static void
    403 mgx_setup(struct mgx_softc *sc, int depth)
    404 {
    405 	/* wait for everything to go idle */
    406 	if (mgx_wait_engine(sc) == 0)
    407 		return;
    408 	if (mgx_wait_fifo(sc, FIFO_AT24) == 0)
    409 		return;
    410 	/*
    411 	 * Compute the invariant bits of the DEC register.
    412 	 */
    413 
    414 	switch (depth) {
    415 		case 8:
    416 			sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT;
    417 			break;
    418 		case 15:
    419 		case 16:
    420 			sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT;
    421 			break;
    422 		case 32:
    423 			sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT;
    424 			break;
    425 		default:
    426 			return; /* not supported */
    427 	}
    428 
    429 	switch (sc->sc_stride) {
    430 		case 640:
    431 			sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT;
    432 			break;
    433 		case 800:
    434 			sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT;
    435 			break;
    436 		case 1024:
    437 			sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT;
    438 			break;
    439 		case 1152:
    440 			sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT;
    441 			break;
    442 		case 1280:
    443 			sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT;
    444 			break;
    445 		case 1600:
    446 			sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT;
    447 			break;
    448 		default:
    449 			return; /* not supported */
    450 	}
    451 	mgx_write_1(sc, ATR_CLIP_CONTROL, 0);
    452 	mgx_write_1(sc, ATR_BYTEMASK, 0xff);
    453 }
    454 
    455 static void
    456 mgx_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he,
    457              int rop)
    458 {
    459 	struct mgx_softc *sc = cookie;
    460 	uint32_t dec = sc->sc_dec;
    461 
    462         dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
    463 	       (DEC_START_DIMX << DEC_START_SHIFT);
    464 	if (xs < xd) {
    465 		xs += wi - 1;
    466 		xd += wi - 1;
    467 		dec |= DEC_DIR_X_REVERSE;
    468 	}
    469 	if (ys < yd) {
    470 		ys += he - 1;
    471 		yd += he - 1;
    472 		dec |= DEC_DIR_Y_REVERSE;
    473 	}
    474 	mgx_wait_fifo(sc, 5);
    475 	mgx_write_1(sc, ATR_ROP, rop);
    476 	mgx_write_4(sc, ATR_DEC, dec);
    477 	mgx_write_4(sc, ATR_SRC_XY, (ys << 16) | xs);
    478 	mgx_write_4(sc, ATR_DST_XY, (yd << 16) | xd);
    479 	mgx_write_4(sc, ATR_WH, (he << 16) | wi);
    480 }
    481 
    482 static void
    483 mgx_rectfill(void *cookie, int x, int y, int wi, int he, long fg)
    484 {
    485 	struct mgx_softc *sc = cookie;
    486 	struct vcons_screen *scr = sc->vd.active;
    487 	uint32_t dec = sc->sc_dec;
    488 	uint32_t col;
    489 
    490 	if (scr == NULL)
    491 		return;
    492 	col = scr->scr_ri.ri_devcmap[fg];
    493 
    494 	dec = sc->sc_dec;
    495 	dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
    496 	       (DEC_START_DIMX << DEC_START_SHIFT);
    497 	mgx_wait_fifo(sc, 5);
    498 	mgx_write_1(sc, ATR_ROP, ROP_SRC);
    499 	mgx_write_4(sc, ATR_FG, col);
    500 	mgx_write_4(sc, ATR_DEC, dec);
    501 	mgx_write_4(sc, ATR_DST_XY, (y << 16) | x);
    502 	mgx_write_4(sc, ATR_WH, (he << 16) | wi);
    503 }
    504 
    505 static void
    506 mgx_putchar(void *cookie, int row, int col, u_int c, long attr)
    507 {
    508 	struct rasops_info *ri = cookie;
    509 	struct wsdisplay_font *font = PICK_FONT(ri, c);
    510 	struct vcons_screen *scr = ri->ri_hw;
    511 	struct mgx_softc *sc = scr->scr_cookie;
    512 	uint32_t fg, bg;
    513 	int x, y, wi, he, rv;
    514 
    515 	wi = font->fontwidth;
    516 	he = font->fontheight;
    517 
    518 	bg = (attr >> 16) & 0xf;
    519 	fg = (attr >> 24) & 0xf;
    520 
    521 	x = ri->ri_xorigin + col * wi;
    522 	y = ri->ri_yorigin + row * he;
    523 
    524 	if (c == 0x20) {
    525 		mgx_rectfill(sc, x, y, wi, he, bg);
    526 		if (attr & 1)
    527 			mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
    528 		return;
    529 	}
    530 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
    531 	if (rv != GC_OK) {
    532 		volatile uint32_t junk;
    533 
    534 		mgx_wait_engine(sc);
    535 		sc->sc_putchar(cookie, row, col, c, attr & ~1);
    536 		junk = *(uint32_t *)sc->sc_fbaddr;
    537 		__USE(junk);
    538 		if (rv == GC_ADD)
    539 			glyphcache_add(&sc->sc_gc, c, x, y);
    540 	}
    541 	if (attr & 1)
    542 		mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
    543 }
    544 
    545 static void
    546 mgx_cursor(void *cookie, int on, int row, int col)
    547 {
    548 	struct rasops_info *ri = cookie;
    549 	struct vcons_screen *scr = ri->ri_hw;
    550 	struct mgx_softc *sc = scr->scr_cookie;
    551 	int x, y, wi,he;
    552 
    553 	wi = ri->ri_font->fontwidth;
    554 	he = ri->ri_font->fontheight;
    555 
    556 	if (ri->ri_flg & RI_CURSOR) {
    557 		x = ri->ri_ccol * wi + ri->ri_xorigin;
    558 		y = ri->ri_crow * he + ri->ri_yorigin;
    559 		mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV);
    560 		ri->ri_flg &= ~RI_CURSOR;
    561 	}
    562 
    563 	ri->ri_crow = row;
    564 	ri->ri_ccol = col;
    565 
    566 	if (on)
    567 	{
    568 		x = ri->ri_ccol * wi + ri->ri_xorigin;
    569 		y = ri->ri_crow * he + ri->ri_yorigin;
    570 		mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV);
    571 		ri->ri_flg |= RI_CURSOR;
    572 	}
    573 }
    574 
    575 static void
    576 mgx_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
    577 {
    578 	struct rasops_info *ri = cookie;
    579 	struct vcons_screen *scr = ri->ri_hw;
    580 	struct mgx_softc *sc = scr->scr_cookie;
    581 	int32_t xs, xd, y, width, height;
    582 
    583 	xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
    584 	xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
    585 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    586 	width = ri->ri_font->fontwidth * ncols;
    587 	height = ri->ri_font->fontheight;
    588 	mgx_bitblt(sc, xs, y, xd, y, width, height, ROP_SRC);
    589 }
    590 
    591 static void
    592 mgx_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
    593 {
    594 	struct rasops_info *ri = cookie;
    595 	struct vcons_screen *scr = ri->ri_hw;
    596 	struct mgx_softc *sc = scr->scr_cookie;
    597 	int32_t x, y, width, height, bg;
    598 
    599 	x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
    600 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    601 	width = ri->ri_font->fontwidth * ncols;
    602 	height = ri->ri_font->fontheight;
    603 	bg = (fillattr >> 16) & 0xff;
    604 	mgx_rectfill(sc, x, y, width, height, bg);
    605 }
    606 
    607 static void
    608 mgx_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
    609 {
    610 	struct rasops_info *ri = cookie;
    611 	struct vcons_screen *scr = ri->ri_hw;
    612 	struct mgx_softc *sc = scr->scr_cookie;
    613 	int32_t x, ys, yd, width, height;
    614 
    615 	x = ri->ri_xorigin;
    616 	ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
    617 	yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
    618 	width = ri->ri_emuwidth;
    619 	height = ri->ri_font->fontheight * nrows;
    620 	mgx_bitblt(sc, x, ys, x, yd, width, height, ROP_SRC);
    621 }
    622 
    623 static void
    624 mgx_eraserows(void *cookie, int row, int nrows, long fillattr)
    625 {
    626 	struct rasops_info *ri = cookie;
    627 	struct vcons_screen *scr = ri->ri_hw;
    628 	struct mgx_softc *sc = scr->scr_cookie;
    629 	int32_t x, y, width, height, bg;
    630 
    631 	if ((row == 0) && (nrows == ri->ri_rows)) {
    632 		x = y = 0;
    633 		width = ri->ri_width;
    634 		height = ri->ri_height;
    635 	} else {
    636 		x = ri->ri_xorigin;
    637 		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
    638 		width = ri->ri_emuwidth;
    639 		height = ri->ri_font->fontheight * nrows;
    640 	}
    641 	bg = (fillattr >> 16) & 0xff;
    642 	mgx_rectfill(sc, x, y, width, height, bg);
    643 }
    644 
    645 static void
    646 mgx_init_screen(void *cookie, struct vcons_screen *scr,
    647     int existing, long *defattr)
    648 {
    649 	struct mgx_softc *sc = cookie;
    650 	struct rasops_info *ri = &scr->scr_ri;
    651 
    652 	ri->ri_depth = 8;
    653 	ri->ri_width = sc->sc_width;
    654 	ri->ri_height = sc->sc_height;
    655 	ri->ri_stride = sc->sc_stride;
    656 	ri->ri_flg = RI_CENTER | RI_ENABLE_ALPHA;
    657 
    658 	if (ri->ri_depth == 8)
    659 		ri->ri_flg |= RI_8BIT_IS_RGB;
    660 
    661 	ri->ri_bits = sc->sc_fbaddr;
    662 
    663 	rasops_init(ri, 0, 0);
    664 	sc->sc_putchar = ri->ri_ops.putchar;
    665 
    666 	ri->ri_caps = WSSCREEN_REVERSE | WSSCREEN_WSCOLORS;
    667 
    668 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
    669 		    ri->ri_width / ri->ri_font->fontwidth);
    670 
    671 	ri->ri_hw = scr;
    672 	ri->ri_ops.putchar   = mgx_putchar;
    673 	ri->ri_ops.cursor    = mgx_cursor;
    674 	ri->ri_ops.copyrows  = mgx_copyrows;
    675 	ri->ri_ops.eraserows = mgx_eraserows;
    676 	ri->ri_ops.copycols  = mgx_copycols;
    677 	ri->ri_ops.erasecols = mgx_erasecols;
    678 }
    679 
    680 static int
    681 mgx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
    682     struct lwp *l)
    683 {
    684 	struct vcons_data *vd = v;
    685 	struct mgx_softc *sc = vd->cookie;
    686 	struct wsdisplay_fbinfo *wdf;
    687 	struct vcons_screen *ms = vd->active;
    688 
    689 	switch (cmd) {
    690 		case WSDISPLAYIO_GTYPE:
    691 			*(u_int *)data = WSDISPLAY_TYPE_MGX;
    692 			return 0;
    693 
    694 		case WSDISPLAYIO_GINFO:
    695 			wdf = (void *)data;
    696 			wdf->height = sc->sc_height;
    697 			wdf->width = sc->sc_width;
    698 			wdf->depth = 8;
    699 			wdf->cmsize = 256;
    700 			return 0;
    701 
    702 		case FBIOGVIDEO:
    703 		case WSDISPLAYIO_GVIDEO:
    704 			*(int *)data = 1;
    705 			return 0;
    706 
    707 		case WSDISPLAYIO_SVIDEO:
    708 		case FBIOSVIDEO:
    709 			return 0;
    710 
    711 		case WSDISPLAYIO_LINEBYTES:
    712 			{
    713 				int *ret = (int *)data;
    714 				*ret = sc->sc_stride;
    715 			}
    716 			return 0;
    717 
    718 		case WSDISPLAYIO_SMODE:
    719 			{
    720 				int new_mode = *(int*)data;
    721 				if (new_mode != sc->sc_mode)
    722 				{
    723 					sc->sc_mode = new_mode;
    724 					if (new_mode == WSDISPLAYIO_MODE_EMUL)
    725 					{
    726 						mgx_setup(sc, 8);
    727 						glyphcache_wipe(&sc->sc_gc);
    728 						mgx_init_palette(sc);
    729 						vcons_redraw_screen(ms);
    730 					} else {
    731 						mgx_setup(sc, 32);
    732 					}
    733 				}
    734 			}
    735 			return 0;
    736 
    737 		case WSDISPLAYIO_GETCMAP:
    738 			return mgx_getcmap(sc, (struct wsdisplay_cmap *)data);
    739 
    740 		case WSDISPLAYIO_PUTCMAP:
    741 			return mgx_putcmap(sc, (struct wsdisplay_cmap *)data);
    742 
    743 		case WSDISPLAYIO_GET_FBINFO:
    744 			{
    745 				struct wsdisplayio_fbinfo *fbi = data;
    746 				int ret;
    747 
    748 				ret = wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
    749 				fbi->fbi_fbsize = 0x400000;
    750 				return ret;
    751 			}
    752 	}
    753 	return EPASSTHROUGH;
    754 }
    755 
    756 static paddr_t
    757 mgx_mmap(void *v, void *vs, off_t offset, int prot)
    758 {
    759 	struct vcons_data *vd = v;
    760 	struct mgx_softc *sc = vd->cookie;
    761 
    762 	/* regular fb mapping at 0 */
    763 	if ((offset >= 0) && (offset < 0x400000)) {
    764 		return bus_space_mmap(sc->sc_tag, sc->sc_paddr,
    765 		    offset, prot, BUS_SPACE_MAP_LINEAR);
    766 	}
    767 
    768 	return -1;
    769 }
    770