xref: /openbsd-src/sys/arch/sparc64/dev/machfb.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: machfb.c,v 1.7 2011/02/21 07:55:27 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Mark Kettenis.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/pciio.h>
22 #include <sys/systm.h>
23 
24 #include <machine/autoconf.h>
25 #include <machine/bus.h>
26 #include <machine/openfirm.h>
27 
28 #include <dev/pci/pcireg.h>
29 #include <dev/pci/pcivar.h>
30 #include <dev/pci/pcidevs.h>
31 
32 #include <dev/wscons/wsconsio.h>
33 #include <dev/wscons/wsdisplayvar.h>
34 
35 #include <dev/rasops/rasops.h>
36 
37 #include <machine/fbvar.h>
38 
39 #define M64_PCI_MEM		0x10
40 #define M64_PCI_MMIO		0x18
41 
42 #define M64_REG_OFF		0x007ffc00
43 #define M64_REG_SIZE		0x0400
44 
45 #define M64_CRTC_INT_CNTL	0x0018
46 
47 #define M64_BUS_CNTL		0x00a0
48 #define  M64_BUS_FIFO_ERR_ACK	0x00200000
49 #define  M64_BUS_HOST_ERR_ACK	0x00800000
50 #define  M64_BUS_APER_REG_DIS	0x00000010
51 
52 #define M64_DAC_WINDEX		0x00c0
53 #define M64_DAC_DATA		0x00c1
54 #define M64_DAC_MASK		0x00c2
55 #define M64_DAC_RINDEX		0x00c3
56 #define M64_DAC_CNTL		0x00c4
57 #define  M64_DAC_8BIT_EN		0x00000100
58 
59 #define M64_GEN_TEST_CNTL	0x00d0
60 #define  M64_GEN_GUI_EN			0x00000100
61 
62 #define M64_DST_OFF_PITCH	0x0100
63 #define M64_DST_X		0x0104
64 #define M64_DST_Y		0x0108
65 #define M64_DST_Y_X		0x010c
66 #define M64_DST_WIDTH		0x0110
67 #define M64_DST_HEIGHT		0x0114
68 #define M64_DST_HEIGHT_WIDTH	0x0118
69 #define M64_DST_X_WIDTH		0x011c
70 #define M64_DST_BRES_LNTH	0x0120
71 #define M64_DST_BRES_ERR	0x0124
72 #define M64_DST_BRES_INC	0x0128
73 #define M64_DST_BRES_DEC	0x012c
74 #define M64_DST_CNTL		0x0130
75 #define  M64_DST_X_RIGHT_TO_LEFT	0x00000000
76 #define  M64_DST_X_LEFT_TO_RIGHT	0x00000001
77 #define  M64_DST_Y_BOTTOM_TO_TOP	0x00000000
78 #define  M64_DST_Y_TOP_TO_BOTTOM	0x00000002
79 #define  M64_DST_X_MAJOR		0x00000000
80 #define  M64_DST_Y_MAJOR		0x00000004
81 #define  M64_DST_X_TILE			0x00000008
82 #define  M64_DST_Y_TILE			0x00000010
83 #define  M64_DST_LAST_PEL		0x00000020
84 #define  M64_DST_POLYGON_EN		0x00000040
85 #define  M64_DST_24_ROT_EN		0x00000080
86 
87 #define M64_SRC_OFF_PITCH	0x0180
88 #define M64_SRC_X		0x0184
89 #define M64_SRC_Y		0x0188
90 #define M64_SRC_Y_X		0x018c
91 #define M64_SRC_WIDTH1		0x0190
92 #define M64_SRC_HEIGHT1		0x0194
93 #define M64_SRC_HEIGHT1_WIDTH1	0x0198
94 #define M64_SRC_X_START		0x019c
95 #define M64_SRC_Y_START		0x01a0
96 #define M64_SRC_Y_X_START	0x01a4
97 #define M64_SRC_WIDTH2		0x01a8
98 #define M64_SRC_HEIGHT2		0x01ac
99 #define M64_SRC_HEIGHT2_WIDTH2	0x01b0
100 #define M64_SRC_CNTL		0x01b4
101 #define  M64_SRC_PATT_EN		0x00000001
102 #define  M64_SRC_PATT_ROT_EN		0x00000002
103 #define  M64_SRC_LINEAR_EN		0x00000004
104 #define  M64_SRC_BYTE_ALIGN 		0x00000008
105 #define  M64_SRC_LINE_X_RIGHT_TO_LEFT	0x00000000
106 #define  M64_SRC_LINE_X_LEFT_TO_RIGHT	0x00000010
107 
108 #define M64_HOST_CNTL		0x0240
109 
110 #define M64_PAT_REG0		0x0280
111 #define M64_PAT_REG1		0x0284
112 #define M64_PAT_CNTL		0x0288
113 
114 #define M64_SC_LEFT		0x02a0
115 #define M64_SC_RIGHT		0x02a4
116 #define M64_SC_LEFT_RIGHT	0x02a8
117 #define M64_SC_TOP		0x02ac
118 #define M64_SC_BOTTOM		0x02b0
119 #define M64_SC_TOP_BOTTOM	0x02b4
120 
121 #define M64_DP_BKGD_CLR		0x02c0
122 #define M64_DP_FRGD_CLR		0x02c4
123 #define M64_DP_WRITE_MASK	0x02c8
124 
125 #define M64_DP_CHAIN_MASK	0x02cc
126 #define  M64_DP_CHAIN_8BPP		0x00008080
127 #define M64_DP_PIX_WIDTH	0x02d0
128 #define  M64_DST_8BPP			0x00000002
129 #define  M64_SRC_8BPP			0x00000200
130 #define  M64_HOST_8BPP			0x00020000
131 #define M64_DP_MIX		0x02d4
132 #define  M64_MIX_DST			0x00000003
133 #define  M64_MIX_SRC			0x00000007
134 #define M64_DP_SRC           0x02d8
135 #define  M64_BKGD_SRC_BKGD_CLR		0x00000000
136 #define  M64_BKGD_SRC_FRGD_CLR		0x00000001
137 #define  M64_BKGD_SRC_HOST		0x00000002
138 #define  M64_BKGD_SRC_BLIT		0x00000003
139 #define  M64_BKGD_SRC_PATTERN		0x00000004
140 #define  M64_FRGD_SRC_BKGD_CLR		0x00000000
141 #define  M64_FRGD_SRC_FRGD_CLR		0x00000100
142 #define  M64_FRGD_SRC_HOST		0x00000200
143 #define  M64_FRGD_SRC_BLIT		0x00000300
144 #define  M64_FRGD_SRC_PATTERN		0x00000400
145 #define  M64_MONO_SRC_ONE		0x00000000
146 #define  M64_MONO_SRC_PATTERN		0x00010000
147 #define  M64_MONO_SRC_HOST		0x00020000
148 #define  M64_MONO_SRC_BLIT		0x00030000
149 
150 #define M64_CLR_CMP_CLR		0x0300
151 #define M64_CLR_CMP_MASK	0x0304
152 #define M64_CLR_CMP_CNTL	0x0308
153 
154 #define M64_FIFO_STAT		0x0310
155 #define  M64_FIFO_STAT_MASK		0x0000ffff
156 
157 #define M64_CONTEXT_MASK	0x0320
158 
159 #define M64_GUI_TRAJ_CNTL	0x0330
160 #define M64_GUI_STAT		0x0338
161 #define  M64_GUI_ACTIVE		 0x00000001
162 
163 #define M64_COORDS(x, y)	((x << 16) | (y))
164 
165 #ifdef APERTURE
166 extern int allowaperture;
167 #endif
168 
169 struct machfb_softc {
170 	struct sunfb	sc_sunfb;
171 
172 	bus_space_tag_t sc_memt;
173 	bus_space_handle_t sc_memh;
174 	bus_addr_t	sc_membase;
175 	bus_size_t	sc_memsize;
176 
177 	bus_space_tag_t	sc_regt;
178 	bus_space_handle_t sc_regh;
179 
180 	bus_space_tag_t	sc_mmiot;
181 	bus_space_handle_t sc_mmioh;
182 	bus_addr_t	sc_mmiobase;
183 	bus_size_t	sc_mmiosize;
184 
185 	pcitag_t	sc_pcitag;
186 
187 	int		sc_mode;
188 	u_int8_t	sc_cmap_red[256];
189 	u_int8_t	sc_cmap_green[256];
190 	u_int8_t	sc_cmap_blue[256];
191 };
192 
193 int	machfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
194 paddr_t	machfb_mmap(void *, off_t, int);
195 
196 struct wsdisplay_accessops machfb_accessops = {
197 	machfb_ioctl,
198 	machfb_mmap,
199 	NULL,	/* alloc_screen */
200 	NULL,	/* free_screen */
201 	NULL,	/* show_screen */
202 	NULL,	/* load_font */
203 	NULL,	/* scrollback */
204 	NULL,	/* getchar */
205 	NULL,	/* burner */
206 	NULL	/* pollc */
207 };
208 
209 int	machfb_match(struct device *, void *, void *);
210 void	machfb_attach(struct device *, struct device *, void *);
211 
212 struct cfattach machfb_ca = {
213 	sizeof(struct machfb_softc), machfb_match, machfb_attach
214 };
215 
216 struct cfdriver machfb_cd = {
217 	NULL, "machfb", DV_DULL
218 };
219 
220 int	machfb_is_console(int);
221 int	machfb_getcmap(struct machfb_softc *, struct wsdisplay_cmap *);
222 int	machfb_putcmap(struct machfb_softc *, struct wsdisplay_cmap *);
223 void	machfb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
224 
225 int	machfb_copycols(void *, int, int, int, int);
226 int	machfb_erasecols(void *, int, int, int, long);
227 int	machfb_copyrows(void *, int, int, int);
228 int	machfb_eraserows(void *, int, int, long);
229 
230 void	machfb_init(struct machfb_softc *);
231 int	machfb_wait_fifo(struct machfb_softc *, int);
232 int	machfb_wait(struct machfb_softc *);
233 void	machfb_copyrect(struct machfb_softc *, int, int, int, int, int, int);
234 void	machfb_fillrect(struct machfb_softc *, int, int, int, int, int);
235 
236 int
237 machfb_match(struct device *parent, void *cf, void *aux)
238 {
239 	struct pci_attach_args *pa = aux;
240 	char buf[32];
241 	int node;
242 
243 	node = PCITAG_NODE(pa->pa_tag);
244 	OF_getprop(node, "name", buf, sizeof(buf));
245 	if (strcmp(buf, "SUNW,m64B") == 0)
246 		return (10);
247 
248 	if (OF_getprop(node, "compatible", buf, sizeof(buf)) > 0 &&
249 	    strcmp(buf, "SUNW,m64B") == 0)
250 		return (10);
251 
252 	return (0);
253 }
254 
255 void
256 machfb_attach(struct device *parent, struct device *self, void *aux)
257 {
258 	struct machfb_softc *sc = (struct machfb_softc *)self;
259 	struct pci_attach_args *pa = aux;
260 	struct rasops_info *ri;
261 	int node, console;
262 	char *model;
263 
264 	sc->sc_pcitag = pa->pa_tag;
265 
266 	node = PCITAG_NODE(pa->pa_tag);
267 	console = machfb_is_console(node);
268 
269 	printf("\n");
270 
271 	model = getpropstring(node, "model");
272 	printf("%s: %s", self->dv_xname, model);
273 
274 	if (pci_mapreg_map(pa, M64_PCI_MEM, PCI_MAPREG_TYPE_MEM,
275 	    BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
276 	    &sc->sc_membase, &sc->sc_memsize, 0)) {
277 		printf("\n%s: can't map video memory\n", self->dv_xname);
278 		return;
279 	}
280 
281 	sc->sc_regt = sc->sc_memt;
282 	if (bus_space_subregion(sc->sc_memt, sc->sc_memh,
283 	    M64_REG_OFF, M64_REG_SIZE, &sc->sc_regh)) {
284 		printf("\n%s: can't map registers\n", self->dv_xname);
285 		return;
286 	}
287 
288 	if (pci_mapreg_map(pa, M64_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
289 	    &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
290 	    &sc->sc_mmiosize, 0)) {
291 		printf("\n%s: can't map registers\n", self->dv_xname);
292 		return;
293 	}
294 
295 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
296 	if (sc->sc_sunfb.sf_depth == 24) {
297 		sc->sc_sunfb.sf_depth = 32;
298 		sc->sc_sunfb.sf_linebytes =
299 		    (sc->sc_sunfb.sf_depth / 8) * sc->sc_sunfb.sf_width;
300 		sc->sc_sunfb.sf_fbsize =
301 		    sc->sc_sunfb.sf_height * sc->sc_sunfb.sf_linebytes;
302 	}
303 
304 	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
305 
306 	ri = &sc->sc_sunfb.sf_ro;
307 	ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh);
308 	ri->ri_hw = sc;
309 
310 	fbwscons_init(&sc->sc_sunfb, RI_BSWAP, console);
311 	fbwscons_setcolormap(&sc->sc_sunfb, machfb_setcolor);
312 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
313 
314 	machfb_init(sc);
315 	ri->ri_ops.copyrows = machfb_copyrows;
316 	ri->ri_ops.copycols = machfb_copycols;
317 	ri->ri_ops.eraserows = machfb_eraserows;
318 	ri->ri_ops.erasecols = machfb_erasecols;
319 
320 	if (console)
321 		fbwscons_console_init(&sc->sc_sunfb, -1);
322 	fbwscons_attach(&sc->sc_sunfb, &machfb_accessops, console);
323 }
324 
325 int
326 machfb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
327 {
328 	struct machfb_softc *sc = v;
329 	struct wsdisplay_fbinfo *wdf;
330 	struct pcisel *sel;
331 
332 	switch (cmd) {
333 	case WSDISPLAYIO_GTYPE:
334 		*(u_int *)data = WSDISPLAY_TYPE_MACHFB;
335 		break;
336 	case WSDISPLAYIO_SMODE:
337 		sc->sc_mode = *(u_int *)data;
338 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
339 			struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
340 
341 			/* Restore colormap. */
342 			fbwscons_setcolormap(&sc->sc_sunfb, machfb_setcolor);
343 
344 			/* Clear screen. */
345 			machfb_fillrect(sc, 0, 0, ri->ri_width, ri->ri_height,
346 			    ri->ri_devcmap[WSCOL_WHITE]);
347 		}
348 		break;
349 	case WSDISPLAYIO_GINFO:
350 		wdf = (void *)data;
351 		wdf->height = sc->sc_sunfb.sf_height;
352 		wdf->width  = sc->sc_sunfb.sf_width;
353 		wdf->depth  = sc->sc_sunfb.sf_depth;
354 		wdf->cmsize = 256;
355 		break;
356 	case WSDISPLAYIO_LINEBYTES:
357 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
358 		break;
359 
360 	case WSDISPLAYIO_GETCMAP:
361 		return machfb_getcmap(sc, (struct wsdisplay_cmap *)data);
362 	case WSDISPLAYIO_PUTCMAP:
363 		return machfb_putcmap(sc, (struct wsdisplay_cmap *)data);
364 
365 	case WSDISPLAYIO_GPCIID:
366 		sel = (struct pcisel *)data;
367 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
368 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
369 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
370 		break;
371 
372 	case WSDISPLAYIO_SVIDEO:
373 	case WSDISPLAYIO_GVIDEO:
374 		break;
375 
376 	case WSDISPLAYIO_GCURPOS:
377 	case WSDISPLAYIO_SCURPOS:
378 	case WSDISPLAYIO_GCURMAX:
379 	case WSDISPLAYIO_GCURSOR:
380 	case WSDISPLAYIO_SCURSOR:
381 	default:
382 		return -1; /* not supported yet */
383         }
384 
385 	return (0);
386 }
387 
388 paddr_t
389 machfb_mmap(void *v, off_t off, int prot)
390 {
391 	struct machfb_softc *sc = v;
392 
393 	if (off & PGOFSET)
394 		return (-1);
395 
396 	switch (sc->sc_mode) {
397 	case WSDISPLAYIO_MODE_MAPPED:
398 #ifdef APERTURE
399 		if (allowaperture == 0)
400 			return (-1);
401 #endif
402 
403 		if (sc->sc_mmiosize == 0)
404 			return (-1);
405 
406 		if (off >= sc->sc_membase &&
407 		    off < (sc->sc_membase + sc->sc_memsize))
408 			return (bus_space_mmap(sc->sc_memt,
409 			    sc->sc_membase, off - sc->sc_membase,
410 			    prot, BUS_SPACE_MAP_LINEAR));
411 
412 		if (off >= sc->sc_mmiobase &&
413 		    off < (sc->sc_mmiobase + sc->sc_mmiosize))
414 			return (bus_space_mmap(sc->sc_mmiot,
415 			    sc->sc_mmiobase, off - sc->sc_mmiobase,
416 			    prot, BUS_SPACE_MAP_LINEAR));
417 		break;
418 
419 	case WSDISPLAYIO_MODE_DUMBFB:
420 		if (off >= 0 && off < sc->sc_memsize)
421 			return (bus_space_mmap(sc->sc_memt, sc->sc_membase,
422 			    off, prot, BUS_SPACE_MAP_LINEAR));
423 		break;
424 	}
425 
426 	return (-1);
427 }
428 
429 int
430 machfb_is_console(int node)
431 {
432 	extern int fbnode;
433 
434 	return (fbnode == node);
435 }
436 
437 int
438 machfb_getcmap(struct machfb_softc *sc, struct wsdisplay_cmap *cm)
439 {
440 	u_int index = cm->index;
441 	u_int count = cm->count;
442 	int error;
443 
444 	if (index >= 256 || count > 256 - index)
445 		return (EINVAL);
446 
447 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
448 	if (error)
449 		return (error);
450 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
451 	if (error)
452 		return (error);
453 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
454 	if (error)
455 		return (error);
456 	return (0);
457 }
458 
459 int
460 machfb_putcmap(struct machfb_softc *sc, struct wsdisplay_cmap *cm)
461 {
462 	u_int index = cm->index;
463 	u_int count = cm->count;
464 	u_int i;
465 	int error;
466 	u_char *r, *g, *b;
467 
468 	if (index >= 256 || count > 256 - index)
469 		return (EINVAL);
470 
471 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
472 		return (error);
473 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
474 		return (error);
475 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
476 		return (error);
477 
478 	r = &sc->sc_cmap_red[index];
479 	g = &sc->sc_cmap_green[index];
480 	b = &sc->sc_cmap_blue[index];
481 
482 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_MASK, 0xff);
483 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_WINDEX, index);
484 	for (i = 0; i < count; i++) {
485 		bus_space_write_1(sc->sc_regt, sc->sc_regh,
486 		    M64_DAC_DATA, *r);
487 		bus_space_write_1(sc->sc_regt, sc->sc_regh,
488 		    M64_DAC_DATA, *g);
489 		bus_space_write_1(sc->sc_regt, sc->sc_regh,
490 		    M64_DAC_DATA, *b);
491 		r++, g++, b++;
492 	}
493 	return (0);
494 }
495 
496 void
497 machfb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
498 {
499 	struct machfb_softc *sc = v;
500 
501 	sc->sc_cmap_red[index] = r;
502 	sc->sc_cmap_green[index] = g;
503 	sc->sc_cmap_blue[index] = b;
504 
505 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_MASK, 0xff);
506 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_WINDEX, index);
507 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, r);
508 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, g);
509 	bus_space_write_1(sc->sc_regt, sc->sc_regh, M64_DAC_DATA, b);
510 }
511 
512 /*
513  * Accelerated routines.
514  */
515 
516 int
517 machfb_copycols(void *cookie, int row, int src, int dst, int num)
518 {
519 	struct rasops_info *ri = cookie;
520 	struct machfb_softc *sc = ri->ri_hw;
521 
522 	num *= ri->ri_font->fontwidth;
523 	src *= ri->ri_font->fontwidth;
524 	dst *= ri->ri_font->fontwidth;
525 	row *= ri->ri_font->fontheight;
526 
527 	machfb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
528 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
529 	    num, ri->ri_font->fontheight);
530 
531 	return 0;
532 }
533 
534 int
535 machfb_erasecols(void *cookie, int row, int col, int num, long attr)
536 {
537 	struct rasops_info *ri = cookie;
538 	struct machfb_softc *sc = ri->ri_hw;
539 	int bg, fg;
540 
541 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
542 
543 	row *= ri->ri_font->fontheight;
544 	col *= ri->ri_font->fontwidth;
545 	num *= ri->ri_font->fontwidth;
546 
547 	machfb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
548 	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
549 
550 	return 0;
551 }
552 
553 int
554 machfb_copyrows(void *cookie, int src, int dst, int num)
555 {
556 	struct rasops_info *ri = cookie;
557 	struct machfb_softc *sc = ri->ri_hw;
558 
559 	num *= ri->ri_font->fontheight;
560 	src *= ri->ri_font->fontheight;
561 	dst *= ri->ri_font->fontheight;
562 
563 	machfb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
564 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
565 
566 	return 0;
567 }
568 
569 int
570 machfb_eraserows(void *cookie, int row, int num, long attr)
571 {
572 	struct rasops_info *ri = cookie;
573 	struct machfb_softc *sc = ri->ri_hw;
574 	int bg, fg;
575 	int x, y, w;
576 
577 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
578 
579 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
580 		num = ri->ri_height;
581 		x = y = 0;
582 		w = ri->ri_width;
583 	} else {
584 		num *= ri->ri_font->fontheight;
585 		x = ri->ri_xorigin;
586 		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
587 		w = ri->ri_emuwidth;
588 	}
589 	machfb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
590 
591 	return 0;
592 }
593 
594 void
595 machfb_init(struct machfb_softc *sc)
596 {
597 	uint32_t reg;
598 
599         /* Reset engine. */
600 	reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL);
601 	reg &= ~M64_GEN_GUI_EN;
602 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL, reg);
603 
604         /* Enable engine. */
605 	reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL);
606 	reg &= M64_GEN_GUI_EN;
607 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GEN_TEST_CNTL, reg);
608 
609         /* Clearing any FIFO or host errors. */
610 	reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, M64_BUS_CNTL);
611 	reg |= M64_BUS_HOST_ERR_ACK | M64_BUS_FIFO_ERR_ACK;
612 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_BUS_CNTL, reg);
613 
614 	machfb_wait_fifo(sc, 14);
615 
616 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
617 	    M64_CONTEXT_MASK, 0xffffffff);
618 
619 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_OFF_PITCH,
620 	    (sc->sc_sunfb.sf_linebytes / 8) << 22);
621 
622 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_Y_X, 0);
623 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_HEIGHT, 0);
624 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_ERR, 0);
625 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_INC, 0);
626 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_BRES_DEC, 0);
627 
628 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_CNTL,
629 	    M64_DST_LAST_PEL | M64_DST_X_LEFT_TO_RIGHT |
630 	    M64_DST_Y_TOP_TO_BOTTOM);
631 
632 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_OFF_PITCH,
633 	    (sc->sc_sunfb.sf_linebytes / 8) << 22);
634 
635 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_Y_X, 0);
636 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
637 	    M64_SRC_HEIGHT1_WIDTH1, 1);
638 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_Y_X_START, 0);
639 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
640 	    M64_SRC_HEIGHT2_WIDTH2, 1);
641 
642 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_CNTL,
643 	    M64_SRC_LINE_X_LEFT_TO_RIGHT);
644 
645 	machfb_wait_fifo(sc, 13);
646 
647 	/* Host attributes. */
648 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_HOST_CNTL, 0);
649 
650 	/* Pattern attributes. */
651 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_REG0, 0);
652 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_REG1, 0);
653 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_PAT_CNTL, 0);
654 
655 	/* Scissors. */
656 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_LEFT, 0);
657 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_TOP, 0);
658 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_BOTTOM,
659 	    sc->sc_sunfb.sf_height - 1);
660 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SC_RIGHT,
661 	    sc->sc_sunfb.sf_linebytes - 1);
662 
663 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_BKGD_CLR, 0);
664 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
665 	    M64_DP_FRGD_CLR, 0xffffffff);
666 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
667 	    M64_DP_WRITE_MASK, 0xffffffff);
668 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
669 	    M64_DP_MIX, (M64_MIX_SRC << 16) | M64_MIX_DST);
670 
671 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
672 	    M64_DP_SRC, M64_FRGD_SRC_FRGD_CLR);
673 
674 	machfb_wait_fifo(sc, 3);
675 
676 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CLR, 0);
677 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
678 	    M64_CLR_CMP_MASK, 0xffffffff);
679 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
680 
681 	machfb_wait_fifo(sc, 3);
682 
683 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_PIX_WIDTH,
684 	    M64_HOST_8BPP | M64_SRC_8BPP | M64_DST_8BPP);
685 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_CHAIN_MASK,
686 	    M64_DP_CHAIN_8BPP);
687 
688 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_GUI_TRAJ_CNTL,
689 	    M64_DST_X_LEFT_TO_RIGHT | M64_DST_Y_TOP_TO_BOTTOM);
690 
691 	machfb_wait(sc);
692 }
693 
694 int
695 machfb_wait_fifo(struct machfb_softc *sc, int v)
696 {
697 	int i;
698 
699 	for (i = 1000000; i != 0; i--) {
700 		if ((bus_space_read_4(sc->sc_regt, sc->sc_regh,
701 		    M64_FIFO_STAT) & M64_FIFO_STAT_MASK) <= (0x8000 >> v))
702 			break;
703 		DELAY(1);
704 	}
705 
706 	return i;
707 }
708 
709 int
710 machfb_wait(struct machfb_softc *sc)
711 {
712 	int i;
713 
714 	machfb_wait_fifo(sc, 16);
715 	for (i = 1000000; i != 0; i--) {
716 		if ((bus_space_read_4(sc->sc_regt, sc->sc_regh,
717 		    M64_GUI_STAT) & M64_GUI_ACTIVE) == 0)
718 			break;
719 		DELAY(1);
720 	}
721 
722 	return i;
723 }
724 
725 void
726 machfb_copyrect(struct machfb_softc *sc, int sx, int sy, int dx, int dy,
727     int w, int h)
728 {
729 	uint32_t dest_ctl = 0;
730 
731 	machfb_wait_fifo(sc, 10);
732 
733 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
734 	    M64_DP_WRITE_MASK, 0xff);
735 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
736 	    M64_DP_SRC, M64_FRGD_SRC_BLIT);
737 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
738 	    M64_DP_MIX, M64_MIX_SRC << 16);
739 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
740 	if (dy < sy) {
741 		dest_ctl = M64_DST_Y_TOP_TO_BOTTOM;
742 	} else {
743 		sy += h - 1;
744 		dy += h - 1;
745 		dest_ctl = M64_DST_Y_BOTTOM_TO_TOP;
746 	}
747 	if (dx < sx) {
748 		dest_ctl |= M64_DST_X_LEFT_TO_RIGHT;
749 		bus_space_write_4(sc->sc_regt, sc->sc_regh,
750 		    M64_SRC_CNTL, M64_SRC_LINE_X_LEFT_TO_RIGHT);
751 	} else {
752 		dest_ctl |= M64_DST_X_RIGHT_TO_LEFT;
753 		sx += w - 1;
754 		dx += w - 1;
755 		bus_space_write_4(sc->sc_regt, sc->sc_regh,
756 		    M64_SRC_CNTL, M64_SRC_LINE_X_RIGHT_TO_LEFT);
757 	}
758 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DST_CNTL, dest_ctl);
759 
760 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
761 	    M64_SRC_Y_X, M64_COORDS(sx, sy));
762 	bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_WIDTH1, w);
763 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
764 	    M64_DST_Y_X, M64_COORDS(dx, dy));
765 	bus_space_write_4(sc->sc_regt, sc->sc_regh,
766 	    M64_DST_HEIGHT_WIDTH, M64_COORDS(w, h));
767 
768 	machfb_wait(sc);
769 }
770 
771 void
772 machfb_fillrect(struct machfb_softc *sc, int x, int y, int w, int h, int color)
773 {
774 	machfb_wait_fifo(sc, 11);
775 
776         bus_space_write_4(sc->sc_regt, sc->sc_regh,
777 	    M64_DP_WRITE_MASK, 0xff);
778         bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_DP_FRGD_CLR, color);
779         bus_space_write_4(sc->sc_regt, sc->sc_regh,
780 	    M64_DP_SRC, M64_FRGD_SRC_FRGD_CLR);
781         bus_space_write_4(sc->sc_regt, sc->sc_regh,
782 	    M64_DP_MIX, M64_MIX_SRC << 16);
783         bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_CLR_CMP_CNTL, 0);
784         bus_space_write_4(sc->sc_regt, sc->sc_regh,
785 	    M64_SRC_CNTL, M64_SRC_LINE_X_LEFT_TO_RIGHT);
786         bus_space_write_4(sc->sc_regt, sc->sc_regh,
787 	    M64_DST_CNTL, M64_DST_X_LEFT_TO_RIGHT | M64_DST_Y_TOP_TO_BOTTOM);
788 
789         bus_space_write_4(sc->sc_regt, sc->sc_regh,
790 	    M64_SRC_Y_X, M64_COORDS(x, y));
791         bus_space_write_4(sc->sc_regt, sc->sc_regh, M64_SRC_WIDTH1, w);
792         bus_space_write_4(sc->sc_regt, sc->sc_regh,
793 	    M64_DST_Y_X, M64_COORDS(x, y));
794         bus_space_write_4(sc->sc_regt, sc->sc_regh,
795 	    M64_DST_HEIGHT_WIDTH, M64_COORDS(w, h));
796 
797         machfb_wait(sc);
798 }
799