xref: /openbsd-src/sys/dev/sbus/mgx.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: mgx.c,v 1.12 2009/09/05 14:09:35 miod Exp $	*/
2 /*
3  * Copyright (c) 2003, Miodrag Vallat.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*
30  * Driver for the Southland Media Systems (now Quantum 3D) MGX and MGXPlus
31  * frame buffers.
32  *
33  * This board is built of an Alliance Promotion AT24 chip, and a simple
34  * SBus-PCI glue logic. It also sports an EEPROM to store configuration
35  * parameters, which can be controlled from SunOS or Solaris with the
36  * mgxconfig utility.
37  *
38  * We currently don't reprogram the video mode at all, so only the resolution
39  * and depth set by the PROM (or mgxconfig) will be used.
40  *
41  * Also, interrupts are not handled.
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/buf.h>
47 #include <sys/device.h>
48 #include <sys/ioctl.h>
49 #include <sys/malloc.h>
50 #include <sys/mman.h>
51 #include <sys/tty.h>
52 #include <sys/conf.h>
53 
54 #include <uvm/uvm_extern.h>
55 
56 #include <machine/autoconf.h>
57 #include <machine/pmap.h>
58 #include <machine/cpu.h>
59 #include <machine/conf.h>
60 
61 #include <dev/wscons/wsconsio.h>
62 #include <dev/wscons/wsdisplayvar.h>
63 #include <dev/rasops/rasops.h>
64 #include <machine/fbvar.h>
65 
66 #include <dev/ic/vgareg.h>
67 #include <dev/ic/atxxreg.h>
68 
69 #include <dev/sbus/sbusvar.h>
70 
71 /*
72  * MGX PROM register layout
73  *
74  * The cards FCode registers 9 regions:
75  *
76  * region  offset     size    description
77  *      0 00000000  00010000  FCode (32KB only)
78  *      1 00100000  00010000  FCode, repeated
79  *      2 00200000  00001000  unknown, repeats every 0x100
80  *                            with little differences, could be the EEPROM image
81  *      3 00400000  00001000  PCI configuration space
82  *      4 00500000  00001000  CRTC
83  *      5 00600000  00001000  AT24 registers (offset 0xb0000)
84  *      6 00700000  00010000  unknown
85  *      7 00800000  00800000  unknown
86  *      8 01000000  00400000  video memory
87  */
88 
89 #define	MGX_NREG			9
90 #define	MGX_REG_CRTC			4	/* video control and ramdac */
91 #define	MGX_REG_ATREG			5	/* AT24 registers */
92 #define	MGX_REG_ATREG_OFFSET	0x000b0000
93 #define	MGX_REG_ATREG_SIZE	0x00000400
94 #define	MGX_REG_VRAM8			8	/* 8-bit memory space */
95 
96 /*
97  * MGX CRTC access
98  *
99  * The CRTC only answers to the following ``port'' locations:
100  * - a subset of the VGA registers:
101  *   3c0, 3c1 (ATC)
102  *   3c4, 3c5 (TS sequencer)
103  *   3c6-3c9 (DAC)
104  *   3c2, 3cc (Misc)
105  *   3ce, 3cf (GDC)
106  *
107  * - the CRTC (6845-style) registers:
108  *   3d4 index register
109  *   3d5 data register
110  */
111 
112 #define	VGA_BASE		0x03c0
113 #define	TS_INDEX		(VGA_BASE + VGA_TS_INDEX)
114 #define	TS_DATA			(VGA_BASE + VGA_TS_DATA)
115 #define	CD_DISABLEVIDEO	0x0020
116 #define	CMAP_WRITE_INDEX	(VGA_BASE + 0x08)
117 #define	CMAP_DATA		(VGA_BASE + 0x09)
118 
119 /* per-display variables */
120 struct mgx_softc {
121 	struct	sunfb	sc_sunfb;		/* common base device */
122 	bus_space_tag_t	sc_bustag;
123 	bus_addr_t	sc_paddr;		/* for mmap() */
124 	u_int8_t	sc_cmap[256 * 3];	/* shadow colormap */
125 	vaddr_t		sc_vidc;		/* ramdac registers */
126 	vaddr_t		sc_xreg;		/* AT24 registers */
127 	uint32_t	sc_dec;			/* dec register template */
128 	int		sc_nscreens;
129 };
130 
131 void	mgx_burner(void *, u_int ,u_int);
132 int	mgx_ioctl(void *, u_long, caddr_t, int, struct proc *);
133 paddr_t	mgx_mmap(void *, off_t, int);
134 
135 struct wsdisplay_accessops mgx_accessops = {
136 	mgx_ioctl,
137 	mgx_mmap,
138 	NULL,	/* alloc_screen */
139 	NULL,	/* free_screen */
140 	NULL,	/* show_screen */
141 	NULL,	/* load_font */
142 	NULL,	/* scrollback */
143 	NULL,	/* getchar */
144 	mgx_burner
145 };
146 
147 int	mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *);
148 void	mgx_loadcmap(struct mgx_softc *, int, int);
149 int	mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *);
150 void	mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
151 
152 int	mgx_ras_copycols(void *, int, int, int, int);
153 int	mgx_ras_copyrows(void *, int, int, int);
154 int	mgx_ras_do_cursor(struct rasops_info *);
155 int	mgx_ras_erasecols(void *, int, int, int, long int);
156 int	mgx_ras_eraserows(void *, int, int, long int);
157 void	mgx_ras_init(struct mgx_softc *, uint);
158 
159 uint8_t	mgx_read_1(vaddr_t, uint);
160 uint16_t mgx_read_2(vaddr_t, uint);
161 void	mgx_write_1(vaddr_t, uint, uint8_t);
162 void	mgx_write_4(vaddr_t, uint, uint32_t);
163 
164 int	mgx_wait_engine(struct mgx_softc *);
165 int	mgx_wait_fifo(struct mgx_softc *, uint);
166 
167 /*
168  * Attachment Glue
169  */
170 
171 int mgxmatch(struct device *, void *, void *);
172 void mgxattach(struct device *, struct device *, void *);
173 
174 struct cfattach mgx_ca = {
175 	sizeof(struct mgx_softc), mgxmatch, mgxattach
176 };
177 
178 struct cfdriver mgx_cd = {
179 	NULL, "mgx", DV_DULL
180 };
181 
182 /*
183  * Match an MGX or MGX+ card.
184  */
185 int
186 mgxmatch(struct device *parent, void *vcf, void *aux)
187 {
188 	struct sbus_attach_args *sa = aux;
189 
190 	if (strcmp(sa->sa_name, "SMSI,mgx") != 0 &&
191 	    strcmp(sa->sa_name, "mgx") != 0)
192 		return (0);
193 
194 	return (1);
195 }
196 
197 /*
198  * Attach an MGX frame buffer.
199  * This will keep the frame buffer in the actual PROM mode, and attach
200  * a wsdisplay child device to itself.
201  */
202 void
203 mgxattach(struct device *parent, struct device *self, void *args)
204 {
205 	struct mgx_softc *sc = (struct mgx_softc *)self;
206 	struct sbus_attach_args *sa = args;
207 	bus_space_tag_t bt;
208 	bus_space_handle_t bh;
209 	int node, fbsize;
210 	int isconsole;
211 	uint16_t chipid;
212 
213 	bt = sa->sa_bustag;
214 	node = sa->sa_node;
215 
216 	printf(": %s", getpropstring(node, "model"));
217 
218 	isconsole = node == fbnode;
219 
220 	/* Check registers */
221 	if (sa->sa_nreg < MGX_NREG) {
222 		printf("\n%s: expected %d registers, got %d\n",
223 		    self->dv_xname, MGX_NREG, sa->sa_nreg);
224 		return;
225 	}
226 
227 	sc->sc_bustag = bt;
228 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot,
229 	    sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE,
230 	    BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
231 		printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
232 		return;
233 	}
234 	sc->sc_vidc = (vaddr_t)bus_space_vaddr(bt, bh);
235 
236 	sc->sc_bustag = bt;
237 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_ATREG].sbr_slot,
238 	    sa->sa_reg[MGX_REG_ATREG].sbr_offset + MGX_REG_ATREG_OFFSET,
239 	    MGX_REG_ATREG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
240 		printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
241 		/* XXX unmap vidc */
242 		return;
243 	}
244 	sc->sc_xreg = (vaddr_t)bus_space_vaddr(bt, bh);
245 
246 	/*
247 	 * Check the chip ID. If it's not an AT24, prefer not to access
248 	 * the extended registers at all.
249 	 */
250 	chipid = mgx_read_2(sc->sc_xreg, ATR_ID);
251 	if (chipid != ID_AT24) {
252 		sc->sc_xreg = (vaddr_t)0;
253 	}
254 
255 	/* enable video */
256 	mgx_burner(sc, 1, 0);
257 
258 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
259 
260 	/* Sanity check frame buffer memory */
261 	fbsize = getpropint(node, "fb_size", 0);
262 	if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) {
263 		printf("\n%s: expected at least %d bytes of vram, but card "
264 		    "only provides %d\n",
265 		    self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize);
266 		return;
267 	}
268 
269 	/* Map the frame buffer memory area we're interested in */
270 	sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
271 	    sa->sa_reg[MGX_REG_VRAM8].sbr_offset);
272 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
273 	    sa->sa_reg[MGX_REG_VRAM8].sbr_offset,
274 	    round_page(sc->sc_sunfb.sf_fbsize),
275 	    BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
276 		printf("\n%s: couldn't map video memory\n", self->dv_xname);
277 		/* XXX unmap vidc and xreg */
278 		return;
279 	}
280 	sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
281 	sc->sc_sunfb.sf_ro.ri_hw = sc;
282 
283 	printf(", %dx%d\n",
284 	    sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
285 
286 	fbwscons_init(&sc->sc_sunfb, 0, isconsole);
287 
288 	bzero(sc->sc_cmap, sizeof(sc->sc_cmap));
289 	fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor);
290 
291 	if (chipid != ID_AT24) {
292 		printf("%s: unexpected engine id %04x\n",
293 		    self->dv_xname, chipid);
294 	}
295 
296 	mgx_ras_init(sc, chipid);
297 
298 	if (isconsole)
299 		fbwscons_console_init(&sc->sc_sunfb, -1);
300 
301 	fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole);
302 }
303 
304 /*
305  * Register Access
306  *
307  * On big-endian systems such as the sparc, it is necessary to flip
308  * the low-order bits of the addresses to reach the right register.
309  */
310 
311 uint8_t
312 mgx_read_1(vaddr_t regs, uint offs)
313 {
314 #if _BYTE_ORDER == _LITTLE_ENDIAN
315 	return *(volatile uint8_t *)(regs + offs);
316 #else
317 	return *(volatile uint8_t *)(regs + (offs ^ 3));
318 #endif
319 }
320 
321 uint16_t
322 mgx_read_2(vaddr_t regs, uint offs)
323 {
324 #if _BYTE_ORDER == _LITTLE_ENDIAN
325 	return *(volatile uint16_t *)(regs + offs);
326 #else
327 	return *(volatile uint16_t *)(regs + (offs ^ 2));
328 #endif
329 }
330 
331 void
332 mgx_write_1(vaddr_t regs, uint offs, uint8_t val)
333 {
334 #if _BYTE_ORDER == _LITTLE_ENDIAN
335 	*(volatile uint8_t *)(regs + offs) = val;
336 #else
337 	*(volatile uint8_t *)(regs + (offs ^ 3)) = val;
338 #endif
339 }
340 
341 void
342 mgx_write_4(vaddr_t regs, uint offs, uint32_t val)
343 {
344 	*(volatile uint32_t *)(regs + offs) = val;
345 }
346 
347 /*
348  * Wsdisplay Operations
349  */
350 
351 int
352 mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
353 {
354 	struct mgx_softc *sc = dev;
355 	struct wsdisplay_cmap *cm;
356 	struct wsdisplay_fbinfo *wdf;
357 	int error;
358 
359 	switch (cmd) {
360 	case WSDISPLAYIO_GTYPE:
361 		*(u_int *)data = WSDISPLAY_TYPE_MGX;
362 		break;
363 	case WSDISPLAYIO_GINFO:
364 		wdf = (struct wsdisplay_fbinfo *)data;
365 		wdf->height = sc->sc_sunfb.sf_height;
366 		wdf->width = sc->sc_sunfb.sf_width;
367 		wdf->depth = sc->sc_sunfb.sf_depth;
368 		wdf->cmsize = 256;
369 		break;
370 	case WSDISPLAYIO_LINEBYTES:
371 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
372 		break;
373 
374 	case WSDISPLAYIO_GETCMAP:
375 		cm = (struct wsdisplay_cmap *)data;
376 		error = mgx_getcmap(sc->sc_cmap, cm);
377 		if (error != 0)
378 			return (error);
379 		break;
380 	case WSDISPLAYIO_PUTCMAP:
381 		cm = (struct wsdisplay_cmap *)data;
382 		error = mgx_putcmap(sc->sc_cmap, cm);
383 		if (error != 0)
384 			return (error);
385 		mgx_loadcmap(sc, cm->index, cm->count);
386 		break;
387 
388 	case WSDISPLAYIO_SVIDEO:
389 	case WSDISPLAYIO_GVIDEO:
390 		break;
391 
392 	default:
393 		return (-1);
394 	}
395 
396 	return (0);
397 }
398 
399 paddr_t
400 mgx_mmap(void *v, off_t offset, int prot)
401 {
402 	struct mgx_softc *sc = v;
403 
404 	if (offset & PGOFSET)
405 		return (-1);
406 
407 	/* Allow mapping as a dumb framebuffer from offset 0 */
408 	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
409 		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
410 		    offset, prot, BUS_SPACE_MAP_LINEAR));
411 	}
412 
413 	return (-1);
414 }
415 
416 void
417 mgx_burner(void *v, u_int on, u_int flags)
418 {
419 	struct mgx_softc *sc = v;
420 	uint mode;
421 
422 #ifdef notyet
423 	if (sc->sc_xreg != 0) {
424 		mode = mgx_read_1(sc->sc_xreg, ATR_DPMS);
425 		if (on)
426 			CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE);
427 		else {
428 			SET(mode, DPMS_HSYNC_DISABLE);
429 #if 0	/* needs ramdac reprogramming on resume */
430 			if (flags & WSDISPLAY_BURN_VBLANK)
431 				SET(mode, DPMS_VSYNC_DISABLE);
432 #endif
433 		}
434 		mgx_write_1(sc->sc_xreg, ATR_DPMS, mode);
435 		return;
436 	}
437 #endif
438 
439 	mgx_write_1(sc->sc_vidc, TS_INDEX, 1);	/* TS mode register */
440 	mode = mgx_read_1(sc->sc_vidc, TS_DATA);
441 	if (on)
442 		mode &= ~CD_DISABLEVIDEO;
443 	else
444 		mode |= CD_DISABLEVIDEO;
445 	mgx_write_1(sc->sc_vidc, TS_DATA, mode);
446 }
447 
448 /*
449  * Colormap Handling Routines
450  */
451 
452 void
453 mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
454 {
455 	struct mgx_softc *sc = v;
456 	u_int i = index * 3;
457 
458 	sc->sc_cmap[i++] = r;
459 	sc->sc_cmap[i++] = g;
460 	sc->sc_cmap[i] = b;
461 
462 	mgx_loadcmap(sc, index, 1);
463 }
464 
465 void
466 mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors)
467 {
468 	u_int8_t *color;
469 	int i;
470 
471 	mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start);
472 	color = sc->sc_cmap + start * 3;
473 	for (i = ncolors * 3; i != 0; i--)
474 		mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++);
475 }
476 
477 int
478 mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
479 {
480 	u_int index = rcm->index, count = rcm->count, i;
481 	int error;
482 
483 	if (index >= 256 || count > 256 - index)
484 		return (EINVAL);
485 
486 	index *= 3;
487 	for (i = 0; i < count; i++) {
488 		if ((error =
489 		    copyout(cm + index++, &rcm->red[i], 1)) != 0)
490 			return (error);
491 		if ((error =
492 		    copyout(cm + index++, &rcm->green[i], 1)) != 0)
493 			return (error);
494 		if ((error =
495 		    copyout(cm + index++, &rcm->blue[i], 1)) != 0)
496 			return (error);
497 	}
498 
499 	return (0);
500 }
501 
502 int
503 mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
504 {
505 	u_int index = rcm->index, count = rcm->count, i;
506 	int error;
507 
508 	if (index >= 256 || count > 256 - index)
509 		return (EINVAL);
510 
511 	index *= 3;
512 	for (i = 0; i < count; i++) {
513 		if ((error =
514 		    copyin(&rcm->red[i], cm + index++, 1)) != 0)
515 			return (error);
516 		if ((error =
517 		    copyin(&rcm->green[i], cm + index++, 1)) != 0)
518 			return (error);
519 		if ((error =
520 		    copyin(&rcm->blue[i], cm + index++, 1)) != 0)
521 			return (error);
522 	}
523 
524 	return (0);
525 }
526 
527 /*
528  * Accelerated Text Console Code
529  *
530  * The X driver makes sure there are at least as many FIFOs available as
531  * registers to write. They can thus be considered as write slots.
532  *
533  * The code below expects to run on at least an AT24 chip, and does not
534  * care for the AP6422 which has fewer FIFOs; some operations would need
535  * to be done in two steps to support this chip.
536  */
537 
538 int
539 mgx_wait_engine(struct mgx_softc *sc)
540 {
541 	uint i;
542 	uint stat;
543 
544 	for (i = 10000; i != 0; i--) {
545 		stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS);
546 		if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY))
547 			break;
548 	}
549 
550 	return i;
551 }
552 
553 int
554 mgx_wait_fifo(struct mgx_softc *sc, uint nfifo)
555 {
556 	uint i;
557 	uint stat;
558 
559 	for (i = 10000; i != 0; i--) {
560 		stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >>
561 		    FIFO_SHIFT;
562 		if (stat >= nfifo)
563 			break;
564 		mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0);
565 	}
566 
567 	return i;
568 }
569 
570 void
571 mgx_ras_init(struct mgx_softc *sc, uint chipid)
572 {
573 	/*
574 	 * Check the chip ID. If it's not a 6424, do not plug the
575 	 * accelerated routines.
576 	 */
577 
578 	if (chipid != ID_AT24)
579 		return;
580 
581 	/*
582 	 * Wait until the chip is completely idle.
583 	 */
584 
585 	if (mgx_wait_engine(sc) == 0)
586 		return;
587 	if (mgx_wait_fifo(sc, FIFO_AT24) == 0)
588 		return;
589 
590 	/*
591 	 * Compute the invariant bits of the DEC register.
592 	 */
593 
594 	switch (sc->sc_sunfb.sf_depth) {
595 	case 8:
596 		sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT;
597 		break;
598 	case 15:
599 	case 16:
600 		sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT;
601 		break;
602 	case 32:
603 		sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT;
604 		break;
605 	default:
606 		return;	/* not supported */
607 	}
608 
609 	switch (sc->sc_sunfb.sf_width) {
610 	case 640:
611 		sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT;
612 		break;
613 	case 800:
614 		sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT;
615 		break;
616 	case 1024:
617 		sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT;
618 		break;
619 	case 1152:
620 		sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT;
621 		break;
622 	case 1280:
623 		sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT;
624 		break;
625 	case 1600:
626 		sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT;
627 		break;
628 	default:
629 		return;	/* not supported */
630 	}
631 
632 	sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols;
633 	sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows;
634 	sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols;
635 	sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows;
636 	sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor;
637 
638 #ifdef notneeded
639 	mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1);
640 	mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0));
641 	mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM,
642 	    ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1));
643 #else
644 	mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0);
645 #endif
646 	mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff);
647 }
648 
649 int
650 mgx_ras_copycols(void *v, int row, int src, int dst, int n)
651 {
652 	struct rasops_info *ri = v;
653 	struct mgx_softc *sc = ri->ri_hw;
654 	uint dec = sc->sc_dec;
655 
656 	n *= ri->ri_font->fontwidth;
657 	src *= ri->ri_font->fontwidth;
658 	src += ri->ri_xorigin;
659 	dst *= ri->ri_font->fontwidth;
660 	dst += ri->ri_xorigin;
661 	row *= ri->ri_font->fontheight;
662 	row += ri->ri_yorigin;
663 
664 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
665 	    (DEC_START_DIMX << DEC_START_SHIFT);
666 	if (src < dst) {
667 		src += n - 1;
668 		dst += n - 1;
669 		dec |= DEC_DIR_X_REVERSE;
670 	}
671 	mgx_wait_fifo(sc, 5);
672 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
673 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
674 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src));
675 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst));
676 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n));
677 	mgx_wait_engine(sc);
678 
679 	return 0;
680 }
681 
682 int
683 mgx_ras_copyrows(void *v, int src, int dst, int n)
684 {
685 	struct rasops_info *ri = v;
686 	struct mgx_softc *sc = ri->ri_hw;
687 	uint dec = sc->sc_dec;
688 
689 	n *= ri->ri_font->fontheight;
690 	src *= ri->ri_font->fontheight;
691 	src += ri->ri_yorigin;
692 	dst *= ri->ri_font->fontheight;
693 	dst += ri->ri_yorigin;
694 
695 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
696 	    (DEC_START_DIMX << DEC_START_SHIFT);
697 	if (src < dst) {
698 		src += n - 1;
699 		dst += n - 1;
700 		dec |= DEC_DIR_Y_REVERSE;
701 	}
702 	mgx_wait_fifo(sc, 5);
703 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
704 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
705 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin));
706 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin));
707 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth));
708 	mgx_wait_engine(sc);
709 
710 	return 0;
711 }
712 
713 int
714 mgx_ras_erasecols(void *v, int row, int col, int n, long int attr)
715 {
716 	struct rasops_info *ri = v;
717 	struct mgx_softc *sc = ri->ri_hw;
718 	int fg, bg;
719 	uint dec = sc->sc_dec;
720 
721 	ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
722 	bg = ri->ri_devcmap[bg];
723 
724 	n *= ri->ri_font->fontwidth;
725 	col *= ri->ri_font->fontwidth;
726 	col += ri->ri_xorigin;
727 	row *= ri->ri_font->fontheight;
728 	row += ri->ri_yorigin;
729 
730 	dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
731 	    (DEC_START_DIMX << DEC_START_SHIFT);
732 	mgx_wait_fifo(sc, 5);
733 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
734 	mgx_write_4(sc->sc_xreg, ATR_FG, bg);
735 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
736 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col));
737 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n));
738 	mgx_wait_engine(sc);
739 
740 	return 0;
741 }
742 
743 int
744 mgx_ras_eraserows(void *v, int row, int n, long int attr)
745 {
746 	struct rasops_info *ri = v;
747 	struct mgx_softc *sc = ri->ri_hw;
748 	int fg, bg;
749 	uint dec = sc->sc_dec;
750 
751 	ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
752 	bg = ri->ri_devcmap[bg];
753 
754 	dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
755 	    (DEC_START_DIMX << DEC_START_SHIFT);
756 	mgx_wait_fifo(sc, 5);
757 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
758 	mgx_write_4(sc->sc_xreg, ATR_FG, bg);
759 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
760 	if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
761 		mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0));
762 		mgx_write_4(sc->sc_xreg, ATR_WH,
763 		    ATR_DUAL(ri->ri_height, ri->ri_width));
764 	} else {
765 		n *= ri->ri_font->fontheight;
766 		row *= ri->ri_font->fontheight;
767 		row += ri->ri_yorigin;
768 
769 		mgx_write_4(sc->sc_xreg, ATR_DST_XY,
770 		    ATR_DUAL(row, ri->ri_xorigin));
771 		mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth));
772 	}
773 	mgx_wait_engine(sc);
774 
775 	return 0;
776 }
777 
778 int
779 mgx_ras_do_cursor(struct rasops_info *ri)
780 {
781 	struct mgx_softc *sc = ri->ri_hw;
782 	int row, col;
783 	uint dec = sc->sc_dec;
784 
785 	row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
786 	col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
787 
788 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
789 	    (DEC_START_DIMX << DEC_START_SHIFT);
790 	mgx_wait_fifo(sc, 5);
791 	mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC);
792 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
793 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col));
794 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col));
795 	mgx_write_4(sc->sc_xreg, ATR_WH,
796 	    ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth));
797 	mgx_wait_engine(sc);
798 
799 	return 0;
800 }
801