xref: /netbsd-src/sys/dev/sbus/mgx.c (revision f89f6560d453f5e37386cc7938c072d2f528b9fa)
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