xref: /openbsd/sys/dev/sbus/mgx.c (revision 63294167)
1 /*	$OpenBSD: mgx.c,v 1.16 2022/07/15 17:57:27 kettenis 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 	.ioctl = mgx_ioctl,
137 	.mmap = mgx_mmap,
138 	.burn_screen = mgx_burner
139 };
140 
141 int	mgx_getcmap(u_int8_t *, struct wsdisplay_cmap *);
142 void	mgx_loadcmap(struct mgx_softc *, int, int);
143 int	mgx_putcmap(u_int8_t *, struct wsdisplay_cmap *);
144 void	mgx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
145 
146 int	mgx_ras_copycols(void *, int, int, int, int);
147 int	mgx_ras_copyrows(void *, int, int, int);
148 int	mgx_ras_do_cursor(struct rasops_info *);
149 int	mgx_ras_erasecols(void *, int, int, int, uint32_t);
150 int	mgx_ras_eraserows(void *, int, int, uint32_t);
151 void	mgx_ras_init(struct mgx_softc *, uint);
152 
153 uint8_t	mgx_read_1(vaddr_t, uint);
154 uint16_t mgx_read_2(vaddr_t, uint);
155 void	mgx_write_1(vaddr_t, uint, uint8_t);
156 void	mgx_write_4(vaddr_t, uint, uint32_t);
157 
158 int	mgx_wait_engine(struct mgx_softc *);
159 int	mgx_wait_fifo(struct mgx_softc *, uint);
160 
161 /*
162  * Attachment Glue
163  */
164 
165 int mgxmatch(struct device *, void *, void *);
166 void mgxattach(struct device *, struct device *, void *);
167 
168 const struct cfattach mgx_ca = {
169 	sizeof(struct mgx_softc), mgxmatch, mgxattach
170 };
171 
172 struct cfdriver mgx_cd = {
173 	NULL, "mgx", DV_DULL
174 };
175 
176 /*
177  * Match an MGX or MGX+ card.
178  */
179 int
mgxmatch(struct device * parent,void * vcf,void * aux)180 mgxmatch(struct device *parent, void *vcf, void *aux)
181 {
182 	struct sbus_attach_args *sa = aux;
183 
184 	if (strcmp(sa->sa_name, "SMSI,mgx") != 0 &&
185 	    strcmp(sa->sa_name, "mgx") != 0)
186 		return (0);
187 
188 	return (1);
189 }
190 
191 /*
192  * Attach an MGX frame buffer.
193  * This will keep the frame buffer in the actual PROM mode, and attach
194  * a wsdisplay child device to itself.
195  */
196 void
mgxattach(struct device * parent,struct device * self,void * args)197 mgxattach(struct device *parent, struct device *self, void *args)
198 {
199 	struct mgx_softc *sc = (struct mgx_softc *)self;
200 	struct sbus_attach_args *sa = args;
201 	bus_space_tag_t bt;
202 	bus_space_handle_t bh;
203 	int node, fbsize;
204 	int isconsole;
205 	uint16_t chipid;
206 
207 	bt = sa->sa_bustag;
208 	node = sa->sa_node;
209 
210 	printf(": %s", getpropstring(node, "model"));
211 
212 	isconsole = node == fbnode;
213 
214 	/* Check registers */
215 	if (sa->sa_nreg < MGX_NREG) {
216 		printf("\n%s: expected %d registers, got %d\n",
217 		    self->dv_xname, MGX_NREG, sa->sa_nreg);
218 		return;
219 	}
220 
221 	sc->sc_bustag = bt;
222 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_CRTC].sbr_slot,
223 	    sa->sa_reg[MGX_REG_CRTC].sbr_offset, PAGE_SIZE,
224 	    BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
225 		printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
226 		return;
227 	}
228 	sc->sc_vidc = (vaddr_t)bus_space_vaddr(bt, bh);
229 
230 	sc->sc_bustag = bt;
231 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_ATREG].sbr_slot,
232 	    sa->sa_reg[MGX_REG_ATREG].sbr_offset + MGX_REG_ATREG_OFFSET,
233 	    MGX_REG_ATREG_SIZE, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
234 		printf("\n%s: couldn't map crtc registers\n", self->dv_xname);
235 		/* XXX unmap vidc */
236 		return;
237 	}
238 	sc->sc_xreg = (vaddr_t)bus_space_vaddr(bt, bh);
239 
240 	/*
241 	 * Check the chip ID. If it's not an AT24, prefer not to access
242 	 * the extended registers at all.
243 	 */
244 	chipid = mgx_read_2(sc->sc_xreg, ATR_ID);
245 	if (chipid != ID_AT24) {
246 		sc->sc_xreg = (vaddr_t)0;
247 	}
248 
249 	/* enable video */
250 	mgx_burner(sc, 1, 0);
251 
252 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
253 
254 	/* Sanity check frame buffer memory */
255 	fbsize = getpropint(node, "fb_size", 0);
256 	if (fbsize != 0 && sc->sc_sunfb.sf_fbsize > fbsize) {
257 		printf("\n%s: expected at least %d bytes of vram, but card "
258 		    "only provides %d\n",
259 		    self->dv_xname, sc->sc_sunfb.sf_fbsize, fbsize);
260 		return;
261 	}
262 
263 	/* Map the frame buffer memory area we're interested in */
264 	sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
265 	    sa->sa_reg[MGX_REG_VRAM8].sbr_offset);
266 	if (sbus_bus_map(bt, sa->sa_reg[MGX_REG_VRAM8].sbr_slot,
267 	    sa->sa_reg[MGX_REG_VRAM8].sbr_offset,
268 	    round_page(sc->sc_sunfb.sf_fbsize),
269 	    BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
270 		printf("\n%s: couldn't map video memory\n", self->dv_xname);
271 		/* XXX unmap vidc and xreg */
272 		return;
273 	}
274 	sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh);
275 	sc->sc_sunfb.sf_ro.ri_hw = sc;
276 
277 	printf(", %dx%d\n",
278 	    sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
279 
280 	fbwscons_init(&sc->sc_sunfb, 0, isconsole);
281 
282 	bzero(sc->sc_cmap, sizeof(sc->sc_cmap));
283 	fbwscons_setcolormap(&sc->sc_sunfb, mgx_setcolor);
284 
285 	if (chipid != ID_AT24) {
286 		printf("%s: unexpected engine id %04x\n",
287 		    self->dv_xname, chipid);
288 	}
289 
290 	mgx_ras_init(sc, chipid);
291 
292 	if (isconsole)
293 		fbwscons_console_init(&sc->sc_sunfb, -1);
294 
295 	fbwscons_attach(&sc->sc_sunfb, &mgx_accessops, isconsole);
296 }
297 
298 /*
299  * Register Access
300  *
301  * On big-endian systems such as the sparc, it is necessary to flip
302  * the low-order bits of the addresses to reach the right register.
303  */
304 
305 uint8_t
mgx_read_1(vaddr_t regs,uint offs)306 mgx_read_1(vaddr_t regs, uint offs)
307 {
308 #if _BYTE_ORDER == _LITTLE_ENDIAN
309 	return *(volatile uint8_t *)(regs + offs);
310 #else
311 	return *(volatile uint8_t *)(regs + (offs ^ 3));
312 #endif
313 }
314 
315 uint16_t
mgx_read_2(vaddr_t regs,uint offs)316 mgx_read_2(vaddr_t regs, uint offs)
317 {
318 #if _BYTE_ORDER == _LITTLE_ENDIAN
319 	return *(volatile uint16_t *)(regs + offs);
320 #else
321 	return *(volatile uint16_t *)(regs + (offs ^ 2));
322 #endif
323 }
324 
325 void
mgx_write_1(vaddr_t regs,uint offs,uint8_t val)326 mgx_write_1(vaddr_t regs, uint offs, uint8_t val)
327 {
328 #if _BYTE_ORDER == _LITTLE_ENDIAN
329 	*(volatile uint8_t *)(regs + offs) = val;
330 #else
331 	*(volatile uint8_t *)(regs + (offs ^ 3)) = val;
332 #endif
333 }
334 
335 void
mgx_write_4(vaddr_t regs,uint offs,uint32_t val)336 mgx_write_4(vaddr_t regs, uint offs, uint32_t val)
337 {
338 	*(volatile uint32_t *)(regs + offs) = val;
339 }
340 
341 /*
342  * Wsdisplay Operations
343  */
344 
345 int
mgx_ioctl(void * dev,u_long cmd,caddr_t data,int flags,struct proc * p)346 mgx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
347 {
348 	struct mgx_softc *sc = dev;
349 	struct wsdisplay_cmap *cm;
350 	struct wsdisplay_fbinfo *wdf;
351 	int error;
352 
353 	switch (cmd) {
354 	case WSDISPLAYIO_GTYPE:
355 		*(u_int *)data = WSDISPLAY_TYPE_MGX;
356 		break;
357 	case WSDISPLAYIO_GINFO:
358 		wdf = (struct wsdisplay_fbinfo *)data;
359 		wdf->height = sc->sc_sunfb.sf_height;
360 		wdf->width = sc->sc_sunfb.sf_width;
361 		wdf->depth = sc->sc_sunfb.sf_depth;
362 		wdf->stride = sc->sc_sunfb.sf_linebytes;
363 		wdf->offset = 0;
364 		wdf->cmsize = 256;
365 		break;
366 	case WSDISPLAYIO_LINEBYTES:
367 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
368 		break;
369 
370 	case WSDISPLAYIO_GETCMAP:
371 		cm = (struct wsdisplay_cmap *)data;
372 		error = mgx_getcmap(sc->sc_cmap, cm);
373 		if (error != 0)
374 			return (error);
375 		break;
376 	case WSDISPLAYIO_PUTCMAP:
377 		cm = (struct wsdisplay_cmap *)data;
378 		error = mgx_putcmap(sc->sc_cmap, cm);
379 		if (error != 0)
380 			return (error);
381 		mgx_loadcmap(sc, cm->index, cm->count);
382 		break;
383 
384 	case WSDISPLAYIO_SVIDEO:
385 	case WSDISPLAYIO_GVIDEO:
386 		break;
387 
388 	default:
389 		return (-1);
390 	}
391 
392 	return (0);
393 }
394 
395 paddr_t
mgx_mmap(void * v,off_t offset,int prot)396 mgx_mmap(void *v, off_t offset, int prot)
397 {
398 	struct mgx_softc *sc = v;
399 
400 	if (offset & PGOFSET)
401 		return (-1);
402 
403 	/* Allow mapping as a dumb framebuffer from offset 0 */
404 	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
405 		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
406 		    offset, prot, BUS_SPACE_MAP_LINEAR));
407 	}
408 
409 	return (-1);
410 }
411 
412 void
mgx_burner(void * v,u_int on,u_int flags)413 mgx_burner(void *v, u_int on, u_int flags)
414 {
415 	struct mgx_softc *sc = v;
416 	uint mode;
417 
418 #ifdef notyet
419 	if (sc->sc_xreg != 0) {
420 		mode = mgx_read_1(sc->sc_xreg, ATR_DPMS);
421 		if (on)
422 			CLR(mode, DPMS_HSYNC_DISABLE | DPMS_VSYNC_DISABLE);
423 		else {
424 			SET(mode, DPMS_HSYNC_DISABLE);
425 #if 0	/* needs ramdac reprogramming on resume */
426 			if (flags & WSDISPLAY_BURN_VBLANK)
427 				SET(mode, DPMS_VSYNC_DISABLE);
428 #endif
429 		}
430 		mgx_write_1(sc->sc_xreg, ATR_DPMS, mode);
431 		return;
432 	}
433 #endif
434 
435 	mgx_write_1(sc->sc_vidc, TS_INDEX, 1);	/* TS mode register */
436 	mode = mgx_read_1(sc->sc_vidc, TS_DATA);
437 	if (on)
438 		mode &= ~CD_DISABLEVIDEO;
439 	else
440 		mode |= CD_DISABLEVIDEO;
441 	mgx_write_1(sc->sc_vidc, TS_DATA, mode);
442 }
443 
444 /*
445  * Colormap Handling Routines
446  */
447 
448 void
mgx_setcolor(void * v,u_int index,u_int8_t r,u_int8_t g,u_int8_t b)449 mgx_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
450 {
451 	struct mgx_softc *sc = v;
452 	u_int i = index * 3;
453 
454 	sc->sc_cmap[i++] = r;
455 	sc->sc_cmap[i++] = g;
456 	sc->sc_cmap[i] = b;
457 
458 	mgx_loadcmap(sc, index, 1);
459 }
460 
461 void
mgx_loadcmap(struct mgx_softc * sc,int start,int ncolors)462 mgx_loadcmap(struct mgx_softc *sc, int start, int ncolors)
463 {
464 	u_int8_t *color;
465 	int i;
466 
467 	mgx_write_1(sc->sc_vidc, CMAP_WRITE_INDEX, start);
468 	color = sc->sc_cmap + start * 3;
469 	for (i = ncolors * 3; i != 0; i--)
470 		mgx_write_1(sc->sc_vidc, CMAP_DATA, *color++);
471 }
472 
473 int
mgx_getcmap(u_int8_t * cm,struct wsdisplay_cmap * rcm)474 mgx_getcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
475 {
476 	u_int index = rcm->index, count = rcm->count, i;
477 	int error;
478 
479 	if (index >= 256 || count > 256 - index)
480 		return (EINVAL);
481 
482 	index *= 3;
483 	for (i = 0; i < count; i++) {
484 		if ((error =
485 		    copyout(cm + index++, &rcm->red[i], 1)) != 0)
486 			return (error);
487 		if ((error =
488 		    copyout(cm + index++, &rcm->green[i], 1)) != 0)
489 			return (error);
490 		if ((error =
491 		    copyout(cm + index++, &rcm->blue[i], 1)) != 0)
492 			return (error);
493 	}
494 
495 	return (0);
496 }
497 
498 int
mgx_putcmap(u_int8_t * cm,struct wsdisplay_cmap * rcm)499 mgx_putcmap(u_int8_t *cm, struct wsdisplay_cmap *rcm)
500 {
501 	u_int index = rcm->index, count = rcm->count, i;
502 	int error;
503 
504 	if (index >= 256 || count > 256 - index)
505 		return (EINVAL);
506 
507 	index *= 3;
508 	for (i = 0; i < count; i++) {
509 		if ((error =
510 		    copyin(&rcm->red[i], cm + index++, 1)) != 0)
511 			return (error);
512 		if ((error =
513 		    copyin(&rcm->green[i], cm + index++, 1)) != 0)
514 			return (error);
515 		if ((error =
516 		    copyin(&rcm->blue[i], cm + index++, 1)) != 0)
517 			return (error);
518 	}
519 
520 	return (0);
521 }
522 
523 /*
524  * Accelerated Text Console Code
525  *
526  * The X driver makes sure there are at least as many FIFOs available as
527  * registers to write. They can thus be considered as write slots.
528  *
529  * The code below expects to run on at least an AT24 chip, and does not
530  * care for the AP6422 which has fewer FIFOs; some operations would need
531  * to be done in two steps to support this chip.
532  */
533 
534 int
mgx_wait_engine(struct mgx_softc * sc)535 mgx_wait_engine(struct mgx_softc *sc)
536 {
537 	uint i;
538 	uint stat;
539 
540 	for (i = 10000; i != 0; i--) {
541 		stat = mgx_read_1(sc->sc_xreg, ATR_BLT_STATUS);
542 		if (!ISSET(stat, BLT_HOST_BUSY | BLT_ENGINE_BUSY))
543 			break;
544 	}
545 
546 	return i;
547 }
548 
549 int
mgx_wait_fifo(struct mgx_softc * sc,uint nfifo)550 mgx_wait_fifo(struct mgx_softc *sc, uint nfifo)
551 {
552 	uint i;
553 	uint stat;
554 
555 	for (i = 10000; i != 0; i--) {
556 		stat = (mgx_read_1(sc->sc_xreg, ATR_FIFO_STATUS) & FIFO_MASK) >>
557 		    FIFO_SHIFT;
558 		if (stat >= nfifo)
559 			break;
560 		mgx_write_1(sc->sc_xreg, ATR_FIFO_STATUS, 0);
561 	}
562 
563 	return i;
564 }
565 
566 void
mgx_ras_init(struct mgx_softc * sc,uint chipid)567 mgx_ras_init(struct mgx_softc *sc, uint chipid)
568 {
569 	/*
570 	 * Check the chip ID. If it's not a 6424, do not plug the
571 	 * accelerated routines.
572 	 */
573 
574 	if (chipid != ID_AT24)
575 		return;
576 
577 	/*
578 	 * Wait until the chip is completely idle.
579 	 */
580 
581 	if (mgx_wait_engine(sc) == 0)
582 		return;
583 	if (mgx_wait_fifo(sc, FIFO_AT24) == 0)
584 		return;
585 
586 	/*
587 	 * Compute the invariant bits of the DEC register.
588 	 */
589 
590 	switch (sc->sc_sunfb.sf_depth) {
591 	case 8:
592 		sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT;
593 		break;
594 	case 15:
595 	case 16:
596 		sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT;
597 		break;
598 	case 32:
599 		sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT;
600 		break;
601 	default:
602 		return;	/* not supported */
603 	}
604 
605 	switch (sc->sc_sunfb.sf_width) {
606 	case 640:
607 		sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT;
608 		break;
609 	case 800:
610 		sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT;
611 		break;
612 	case 1024:
613 		sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT;
614 		break;
615 	case 1152:
616 		sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT;
617 		break;
618 	case 1280:
619 		sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT;
620 		break;
621 	case 1600:
622 		sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT;
623 		break;
624 	default:
625 		return;	/* not supported */
626 	}
627 
628 	sc->sc_sunfb.sf_ro.ri_ops.copycols = mgx_ras_copycols;
629 	sc->sc_sunfb.sf_ro.ri_ops.copyrows = mgx_ras_copyrows;
630 	sc->sc_sunfb.sf_ro.ri_ops.erasecols = mgx_ras_erasecols;
631 	sc->sc_sunfb.sf_ro.ri_ops.eraserows = mgx_ras_eraserows;
632 	sc->sc_sunfb.sf_ro.ri_do_cursor = mgx_ras_do_cursor;
633 
634 #ifdef notneeded
635 	mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 1);
636 	mgx_write_4(sc->sc_xreg, ATR_CLIP_LEFTTOP, ATR_DUAL(0, 0));
637 	mgx_write_4(sc->sc_xreg, ATR_CLIP_RIGHTBOTTOM,
638 	    ATR_DUAL(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_depth - 1));
639 #else
640 	mgx_write_1(sc->sc_xreg, ATR_CLIP_CONTROL, 0);
641 #endif
642 	mgx_write_1(sc->sc_xreg, ATR_BYTEMASK, 0xff);
643 }
644 
645 int
mgx_ras_copycols(void * v,int row,int src,int dst,int n)646 mgx_ras_copycols(void *v, int row, int src, int dst, int n)
647 {
648 	struct rasops_info *ri = v;
649 	struct mgx_softc *sc = ri->ri_hw;
650 	uint dec = sc->sc_dec;
651 
652 	n *= ri->ri_font->fontwidth;
653 	src *= ri->ri_font->fontwidth;
654 	src += ri->ri_xorigin;
655 	dst *= ri->ri_font->fontwidth;
656 	dst += ri->ri_xorigin;
657 	row *= ri->ri_font->fontheight;
658 	row += ri->ri_yorigin;
659 
660 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
661 	    (DEC_START_DIMX << DEC_START_SHIFT);
662 	if (src < dst) {
663 		src += n - 1;
664 		dst += n - 1;
665 		dec |= DEC_DIR_X_REVERSE;
666 	}
667 	mgx_wait_fifo(sc, 5);
668 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
669 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
670 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, src));
671 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, dst));
672 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n));
673 	mgx_wait_engine(sc);
674 
675 	return 0;
676 }
677 
678 int
mgx_ras_copyrows(void * v,int src,int dst,int n)679 mgx_ras_copyrows(void *v, int src, int dst, int n)
680 {
681 	struct rasops_info *ri = v;
682 	struct mgx_softc *sc = ri->ri_hw;
683 	uint dec = sc->sc_dec;
684 
685 	n *= ri->ri_font->fontheight;
686 	src *= ri->ri_font->fontheight;
687 	src += ri->ri_yorigin;
688 	dst *= ri->ri_font->fontheight;
689 	dst += ri->ri_yorigin;
690 
691 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
692 	    (DEC_START_DIMX << DEC_START_SHIFT);
693 	if (src < dst) {
694 		src += n - 1;
695 		dst += n - 1;
696 		dec |= DEC_DIR_Y_REVERSE;
697 	}
698 	mgx_wait_fifo(sc, 5);
699 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
700 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
701 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(src, ri->ri_xorigin));
702 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(dst, ri->ri_xorigin));
703 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth));
704 	mgx_wait_engine(sc);
705 
706 	return 0;
707 }
708 
709 int
mgx_ras_erasecols(void * v,int row,int col,int n,uint32_t attr)710 mgx_ras_erasecols(void *v, int row, int col, int n, uint32_t attr)
711 {
712 	struct rasops_info *ri = v;
713 	struct mgx_softc *sc = ri->ri_hw;
714 	int fg, bg;
715 	uint dec = sc->sc_dec;
716 
717 	ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
718 	bg = ri->ri_devcmap[bg];
719 
720 	n *= ri->ri_font->fontwidth;
721 	col *= ri->ri_font->fontwidth;
722 	col += ri->ri_xorigin;
723 	row *= ri->ri_font->fontheight;
724 	row += ri->ri_yorigin;
725 
726 	dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
727 	    (DEC_START_DIMX << DEC_START_SHIFT);
728 	mgx_wait_fifo(sc, 5);
729 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
730 	mgx_write_4(sc->sc_xreg, ATR_FG, bg);
731 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
732 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col));
733 	mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(ri->ri_font->fontheight, n));
734 	mgx_wait_engine(sc);
735 
736 	return 0;
737 }
738 
739 int
mgx_ras_eraserows(void * v,int row,int n,uint32_t attr)740 mgx_ras_eraserows(void *v, int row, int n, uint32_t attr)
741 {
742 	struct rasops_info *ri = v;
743 	struct mgx_softc *sc = ri->ri_hw;
744 	int fg, bg;
745 	uint dec = sc->sc_dec;
746 
747 	ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
748 	bg = ri->ri_devcmap[bg];
749 
750 	dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
751 	    (DEC_START_DIMX << DEC_START_SHIFT);
752 	mgx_wait_fifo(sc, 5);
753 	mgx_write_1(sc->sc_xreg, ATR_ROP, ROP_SRC);
754 	mgx_write_4(sc->sc_xreg, ATR_FG, bg);
755 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
756 	if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
757 		mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(0, 0));
758 		mgx_write_4(sc->sc_xreg, ATR_WH,
759 		    ATR_DUAL(ri->ri_height, ri->ri_width));
760 	} else {
761 		n *= ri->ri_font->fontheight;
762 		row *= ri->ri_font->fontheight;
763 		row += ri->ri_yorigin;
764 
765 		mgx_write_4(sc->sc_xreg, ATR_DST_XY,
766 		    ATR_DUAL(row, ri->ri_xorigin));
767 		mgx_write_4(sc->sc_xreg, ATR_WH, ATR_DUAL(n, ri->ri_emuwidth));
768 	}
769 	mgx_wait_engine(sc);
770 
771 	return 0;
772 }
773 
774 int
mgx_ras_do_cursor(struct rasops_info * ri)775 mgx_ras_do_cursor(struct rasops_info *ri)
776 {
777 	struct mgx_softc *sc = ri->ri_hw;
778 	int row, col;
779 	uint dec = sc->sc_dec;
780 
781 	row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
782 	col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
783 
784 	dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
785 	    (DEC_START_DIMX << DEC_START_SHIFT);
786 	mgx_wait_fifo(sc, 5);
787 	mgx_write_1(sc->sc_xreg, ATR_ROP, (uint8_t)~ROP_SRC);
788 	mgx_write_4(sc->sc_xreg, ATR_DEC, dec);
789 	mgx_write_4(sc->sc_xreg, ATR_SRC_XY, ATR_DUAL(row, col));
790 	mgx_write_4(sc->sc_xreg, ATR_DST_XY, ATR_DUAL(row, col));
791 	mgx_write_4(sc->sc_xreg, ATR_WH,
792 	    ATR_DUAL(ri->ri_font->fontheight, ri->ri_font->fontwidth));
793 	mgx_wait_engine(sc);
794 
795 	return 0;
796 }
797