xref: /openbsd/sys/arch/sparc64/dev/gfxp.c (revision 8932bfb7)
1 /*	$OpenBSD: gfxp.c,v 1.12 2010/11/26 21:03:36 miod 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 /*
40  * The Permedia 2 provides two views into its 64k register file.  The
41  * first view is little-endian, the second is big-endian and
42  * immediately follows the little-endian view.  Since bus_space(9)
43  * already does the byte order conversion for us, we use the
44  * little-endian view.
45  *
46  * There are also little-endian and big-endian views into the
47  * framebuffer.  These are made available through separate BARs.  We
48  * use the big-endian view in this driver to avoid unnecessary byte
49  * swapping in rasops(9).
50  */
51 #define PM2_PCI_MMIO		0x10 	/* Registers */
52 #define PM2_PCI_MEM_LE		0x14 	/* Framebuffer (little-endian) */
53 #define PM2_PCI_MEM_BE		0x18	/* Framebuffer (big-endian) */
54 
55 #define PM2_IN_FIFO_SPACE	0x0018
56 #define PM2_OUT_FIFO_SPACE	0x0020
57 #define PM2_DMA_COUNT		0x0030
58 
59 #define PM2_OUT_FIFO		0x2000
60 #define  PM2_SYNC_TAG			0x00000188
61 
62 #define PM2_PALETTE_WRITE_ADDR	0x4000
63 #define PM2_PALETTE_DATA	0x4008
64 
65 #define PM2V_INDEX_LOW		0x4020
66 #define PM2V_INDEX_HIGH		0x4028
67 #define PM2V_INDEX_DATA		0x4030
68 #define  PM2V_CURSOR_MODE		0x0005
69 #define  PM2V_CURSOR_PATTERN		0x0400
70 
71 #define PM2_RENDER		0x8038
72 #define  PM2_RENDER_FASTFILL		0x00000008
73 #define  PM2_RENDER_RECT		0x000000c0
74 #define  PM2_INCREASE_X			0x00200000
75 #define  PM2_INCREASE_Y			0x00400000
76 #define PM2_RECT_ORIG		0x80d0
77 #define PM2_RECT_SIZE		0x80d8
78 
79 #define PM2_FB_READ_MODE	0x8a80
80 #define PM2_FB_BLOCK_COLOR	0x8ac8
81 #define PM2_FB_READ_PIXEL	0x8ad0
82 
83 #define PM2_FILTER_MODE		0x8c00
84 #define  PM2_FM_PASS_SYNC_TAG		0x00000400
85 #define PM2_SYNC		0x8c40
86 
87 #define PM2_FB_SRC_DELTA	0x8d88
88 #define PM2_CONFIG		0x8d90
89 #define  PM2_CONFIG_FB_READ_SRC_EN	0x00000001
90 #define  PM2_CONFIG_FB_WRITE_EN		0x00000008
91 
92 #define PM2_COORDS(x, y)	((y) << 16 | (x))
93 
94 
95 #ifdef APERTURE
96 extern int allowaperture;
97 #endif
98 
99 struct gfxp_softc {
100 	struct sunfb	sc_sunfb;
101 
102 	bus_space_tag_t sc_memt;
103 	bus_space_handle_t sc_memh;
104 	bus_addr_t	sc_membase_le;
105 	bus_size_t	sc_memsize_le;
106 	bus_addr_t	sc_membase_be;
107 	bus_size_t	sc_memsize_be;
108 
109 	bus_space_tag_t	sc_mmiot;
110 	bus_space_handle_t sc_mmioh;
111 	bus_addr_t	sc_mmiobase;
112 	bus_size_t	sc_mmiosize;
113 
114 	pcitag_t	sc_pcitag;
115 
116 	int		sc_mode;
117 	u_int8_t	sc_cmap_red[256];
118 	u_int8_t	sc_cmap_green[256];
119 	u_int8_t	sc_cmap_blue[256];
120 
121 	/* Saved state to clean up after X11. */
122 	uint32_t	sc_read_mode;
123 	uint32_t	sc_read_pixel;
124 };
125 
126 int	gfxp_ioctl(void *, u_long, caddr_t, int, struct proc *);
127 paddr_t	gfxp_mmap(void *, off_t, int);
128 
129 struct wsdisplay_accessops gfxp_accessops = {
130 	gfxp_ioctl,
131 	gfxp_mmap,
132 	NULL,	/* alloc_screen */
133 	NULL,	/* free_screen */
134 	NULL,	/* show_screen */
135 	NULL,	/* load_font */
136 	NULL,	/* scrollback */
137 	NULL,	/* getchar */
138 	NULL,	/* burner */
139 	NULL	/* pollc */
140 };
141 
142 int	gfxp_match(struct device *, void *, void *);
143 void	gfxp_attach(struct device *, struct device *, void *);
144 
145 struct cfattach gfxp_ca = {
146 	sizeof(struct gfxp_softc), gfxp_match, gfxp_attach
147 };
148 
149 struct cfdriver gfxp_cd = {
150 	NULL, "gfxp", DV_DULL
151 };
152 
153 int	gfxp_is_console(int);
154 int	gfxp_getcmap(struct gfxp_softc *, struct wsdisplay_cmap *);
155 int	gfxp_putcmap(struct gfxp_softc *, struct wsdisplay_cmap *);
156 void	gfxp_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
157 
158 int	gfxp_copycols(void *, int, int, int, int);
159 int	gfxp_erasecols(void *, int, int, int, long);
160 int	gfxp_copyrows(void *, int, int, int);
161 int	gfxp_eraserows(void *, int, int, long);
162 
163 void	gfxp_init(struct gfxp_softc *);
164 void	gfxp_reinit(struct gfxp_softc *);
165 
166 void	gfxp_indexed_write(struct gfxp_softc *, bus_size_t, uint32_t);
167 int	gfxp_wait(struct gfxp_softc *);
168 int	gfxp_wait_fifo(struct gfxp_softc *, int);
169 void	gfxp_copyrect(struct gfxp_softc *, int, int, int, int, int, int);
170 void	gfxp_fillrect(struct gfxp_softc *, int, int, int, int, int);
171 
172 int
173 gfxp_match(struct device *parent, void *cf, void *aux)
174 {
175 	struct pci_attach_args *pa = aux;
176 	int node;
177 	char *name;
178 
179 	node = PCITAG_NODE(pa->pa_tag);
180 	name = getpropstring(node, "name");
181 	if (strcmp(name, "TECH-SOURCE,gfxp") == 0 ||
182 	    strcmp(name, "TSI,gfxp") == 0)
183 		return (10);
184 
185 	return (0);
186 }
187 
188 void
189 gfxp_attach(struct device *parent, struct device *self, void *aux)
190 {
191 	struct gfxp_softc *sc = (struct gfxp_softc *)self;
192 	struct pci_attach_args *pa = aux;
193 	struct rasops_info *ri;
194 	int node, console, flags;
195 	char *model;
196 
197 	sc->sc_pcitag = pa->pa_tag;
198 
199 	node = PCITAG_NODE(pa->pa_tag);
200 	console = gfxp_is_console(node);
201 
202 	printf("\n");
203 
204 	model = getpropstring(node, "model");
205 	printf("%s: %s", self->dv_xname, model);
206 
207 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, PM2_PCI_MEM_LE,
208 	    PCI_MAPREG_TYPE_MEM, &sc->sc_membase_le, &sc->sc_memsize_le, NULL))
209 		sc->sc_memsize_le = 0;
210 
211 	if (pci_mapreg_map(pa, PM2_PCI_MEM_BE, PCI_MAPREG_TYPE_MEM,
212 	    BUS_SPACE_MAP_LINEAR, &sc->sc_memt, &sc->sc_memh,
213 	    &sc->sc_membase_be, &sc->sc_memsize_be, 0)) {
214 		printf("\n%s: can't map video memory\n", self->dv_xname);
215 		return;
216 	}
217 
218 	if (pci_mapreg_map(pa, PM2_PCI_MMIO, PCI_MAPREG_TYPE_MEM, 0,
219 	    &sc->sc_mmiot, &sc->sc_mmioh, &sc->sc_mmiobase,
220 	    &sc->sc_mmiosize, 0)) {
221 		bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize_be);
222 		printf("\n%s: can't map mmio\n", self->dv_xname);
223 		return;
224 	}
225 
226 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
227 
228 	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
229 
230 	ri = &sc->sc_sunfb.sf_ro;
231 	ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_memh);
232 	ri->ri_hw = sc;
233 
234 	flags = RI_BSWAP;
235 	if (sc->sc_sunfb.sf_depth == 32) {
236 		ri->ri_rnum = 8;
237 		ri->ri_rpos = 16;
238 		ri->ri_gnum = 8;
239 		ri->ri_gpos = 8;
240 		ri->ri_bnum = 8;
241 		ri->ri_bpos = 0;
242 		flags &= ~RI_BSWAP;
243 	}
244 
245 	fbwscons_init(&sc->sc_sunfb, flags, console);
246 	fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor);
247 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
248 
249 	gfxp_init(sc);
250 	ri->ri_ops.copyrows = gfxp_copyrows;
251 	ri->ri_ops.copycols = gfxp_copycols;
252 	ri->ri_ops.eraserows = gfxp_eraserows;
253 	ri->ri_ops.erasecols = gfxp_erasecols;
254 
255 	if (console)
256 		fbwscons_console_init(&sc->sc_sunfb, -1);
257 	fbwscons_attach(&sc->sc_sunfb, &gfxp_accessops, console);
258 }
259 
260 int
261 gfxp_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
262 {
263 	struct gfxp_softc *sc = v;
264 	struct wsdisplay_fbinfo *wdf;
265 	struct pcisel *sel;
266 
267 	switch (cmd) {
268 	case WSDISPLAYIO_GTYPE:
269 		*(u_int *)data = WSDISPLAY_TYPE_GFXP;
270 		break;
271 	case WSDISPLAYIO_SMODE:
272 		sc->sc_mode = *(u_int *)data;
273 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
274 			fbwscons_setcolormap(&sc->sc_sunfb, gfxp_setcolor);
275 
276 			/* Clean up the mess left behind by X. */
277 			gfxp_reinit(sc);
278 		}
279 		break;
280 	case WSDISPLAYIO_GINFO:
281 		wdf = (void *)data;
282 		wdf->height = sc->sc_sunfb.sf_height;
283 		wdf->width  = sc->sc_sunfb.sf_width;
284 		wdf->depth  = sc->sc_sunfb.sf_depth;
285 		if (sc->sc_sunfb.sf_depth == 32)
286 			wdf->cmsize = 0;
287 		else
288 			wdf->cmsize = 256;
289 		break;
290 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
291 		if (sc->sc_sunfb.sf_depth == 32)
292 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
293 		else
294 			return (-1);
295 		break;
296 	case WSDISPLAYIO_LINEBYTES:
297 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
298 		break;
299 
300 	case WSDISPLAYIO_GETCMAP:
301 		return gfxp_getcmap(sc, (struct wsdisplay_cmap *)data);
302 	case WSDISPLAYIO_PUTCMAP:
303 		return gfxp_putcmap(sc, (struct wsdisplay_cmap *)data);
304 
305 	case WSDISPLAYIO_GPCIID:
306 		sel = (struct pcisel *)data;
307 		sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
308 		sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
309 		sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
310 		break;
311 
312 	case WSDISPLAYIO_SVIDEO:
313 	case WSDISPLAYIO_GVIDEO:
314 		break;
315 
316 	case WSDISPLAYIO_GCURPOS:
317 	case WSDISPLAYIO_SCURPOS:
318 	case WSDISPLAYIO_GCURMAX:
319 	case WSDISPLAYIO_GCURSOR:
320 	case WSDISPLAYIO_SCURSOR:
321 	default:
322 		return -1; /* not supported yet */
323         }
324 
325 	return (0);
326 }
327 
328 paddr_t
329 gfxp_mmap(void *v, off_t off, int prot)
330 {
331 	struct gfxp_softc *sc = v;
332 
333 	if (off & PGOFSET)
334 		return (-1);
335 
336 	switch (sc->sc_mode) {
337 	case WSDISPLAYIO_MODE_MAPPED:
338 #ifdef APERTURE
339 		if (allowaperture == 0)
340 			return (-1);
341 #endif
342 
343 		if (sc->sc_mmiosize == 0)
344 			return (-1);
345 
346 		if (off >= sc->sc_membase_be &&
347 		    off < (sc->sc_membase_be + sc->sc_memsize_be))
348 			return (bus_space_mmap(sc->sc_memt,
349 			    sc->sc_membase_be, off - sc->sc_membase_be,
350 			    prot, BUS_SPACE_MAP_LINEAR));
351 
352 		if (off >= sc->sc_mmiobase &&
353 		    off < (sc->sc_mmiobase + sc->sc_mmiosize))
354 			return (bus_space_mmap(sc->sc_mmiot,
355 			    sc->sc_mmiobase, off - sc->sc_mmiobase,
356 			    prot, BUS_SPACE_MAP_LINEAR));
357 		break;
358 
359 	case WSDISPLAYIO_MODE_DUMBFB:
360 		if (off >= 0 && off < sc->sc_memsize_le)
361 			return (bus_space_mmap(sc->sc_memt, sc->sc_membase_le,
362 			    off, prot, BUS_SPACE_MAP_LINEAR));
363 		break;
364 	}
365 
366 	return (-1);
367 }
368 
369 int
370 gfxp_is_console(int node)
371 {
372 	extern int fbnode;
373 
374 	return (fbnode == node);
375 }
376 
377 int
378 gfxp_getcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm)
379 {
380 	u_int index = cm->index;
381 	u_int count = cm->count;
382 	int error;
383 
384 	if (index >= 256 || count > 256 - index)
385 		return (EINVAL);
386 
387 	error = copyout(&sc->sc_cmap_red[index], cm->red, count);
388 	if (error)
389 		return (error);
390 	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
391 	if (error)
392 		return (error);
393 	error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
394 	if (error)
395 		return (error);
396 	return (0);
397 }
398 
399 int
400 gfxp_putcmap(struct gfxp_softc *sc, struct wsdisplay_cmap *cm)
401 {
402 	u_int index = cm->index;
403 	u_int count = cm->count;
404 	u_int i;
405 	int error;
406 	u_char *r, *g, *b;
407 
408 	if (index >= 256 || count > 256 - index)
409 		return (EINVAL);
410 
411 	if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
412 		return (error);
413 	if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
414 		return (error);
415 	if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
416 		return (error);
417 
418 	r = &sc->sc_cmap_red[index];
419 	g = &sc->sc_cmap_green[index];
420 	b = &sc->sc_cmap_blue[index];
421 
422 	gfxp_wait_fifo(sc, 1);
423 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
424 	    PM2_PALETTE_WRITE_ADDR, index);
425 	for (i = 0; i < count; i++) {
426 		gfxp_wait_fifo(sc, 3);
427 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
428 		    PM2_PALETTE_DATA, *r);
429 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
430 		    PM2_PALETTE_DATA, *g);
431 		bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
432 		    PM2_PALETTE_DATA, *b);
433 		r++, g++, b++;
434 	}
435 	return (0);
436 }
437 
438 void
439 gfxp_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
440 {
441 	struct gfxp_softc *sc = v;
442 
443 	sc->sc_cmap_red[index] = r;
444 	sc->sc_cmap_green[index] = g;
445 	sc->sc_cmap_blue[index] = b;
446 
447 	gfxp_wait_fifo(sc, 4);
448 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
449 	    PM2_PALETTE_WRITE_ADDR, index);
450 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, r);
451 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, g);
452 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_PALETTE_DATA, b);
453 }
454 
455 /*
456  * Accelerated routines.
457  */
458 
459 int
460 gfxp_copycols(void *cookie, int row, int src, int dst, int num)
461 {
462 	struct rasops_info *ri = cookie;
463 	struct gfxp_softc *sc = ri->ri_hw;
464 
465 	num *= ri->ri_font->fontwidth;
466 	src *= ri->ri_font->fontwidth;
467 	dst *= ri->ri_font->fontwidth;
468 	row *= ri->ri_font->fontheight;
469 
470 	gfxp_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
471 	    ri->ri_xorigin + dst, ri->ri_yorigin + row,
472 	    num, ri->ri_font->fontheight);
473 
474 	return 0;
475 }
476 
477 int
478 gfxp_erasecols(void *cookie, int row, int col, int num, long attr)
479 {
480 	struct rasops_info *ri = cookie;
481 	struct gfxp_softc *sc = ri->ri_hw;
482 	int bg, fg;
483 
484 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
485 
486 	row *= ri->ri_font->fontheight;
487 	col *= ri->ri_font->fontwidth;
488 	num *= ri->ri_font->fontwidth;
489 
490 	gfxp_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
491 	    num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
492 
493 	return 0;
494 }
495 
496 int
497 gfxp_copyrows(void *cookie, int src, int dst, int num)
498 {
499 	struct rasops_info *ri = cookie;
500 	struct gfxp_softc *sc = ri->ri_hw;
501 
502 	num *= ri->ri_font->fontheight;
503 	src *= ri->ri_font->fontheight;
504 	dst *= ri->ri_font->fontheight;
505 
506 	gfxp_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
507 	    ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
508 
509 	return 0;
510 }
511 
512 int
513 gfxp_eraserows(void *cookie, int row, int num, long attr)
514 {
515 	struct rasops_info *ri = cookie;
516 	struct gfxp_softc *sc = ri->ri_hw;
517 	int bg, fg;
518 	int x, y, w;
519 
520 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
521 
522 	if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
523 		num = ri->ri_height;
524 		x = y = 0;
525 		w = ri->ri_width;
526 	} else {
527 		num *= ri->ri_font->fontheight;
528 		x = ri->ri_xorigin;
529 		y = ri->ri_yorigin + row * ri->ri_font->fontheight;
530 		w = ri->ri_emuwidth;
531 	}
532 	gfxp_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
533 
534 	return 0;
535 }
536 
537 void
538 gfxp_init(struct gfxp_softc *sc)
539 {
540 	/* XXX Save. */
541 	sc->sc_read_mode = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
542 	    PM2_FB_READ_MODE);
543 	sc->sc_read_pixel = bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
544 	    PM2_FB_READ_PIXEL);
545 }
546 
547 void
548 gfxp_reinit(struct gfxp_softc *sc)
549 {
550 	struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
551 	int i;
552 
553 	/* XXX Restore. */
554 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
555 	    PM2_FB_READ_MODE, sc->sc_read_mode);
556 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
557 	    PM2_FB_READ_PIXEL, sc->sc_read_pixel);
558 
559 	/* Disable cursor. */
560 	gfxp_indexed_write(sc, PM2V_CURSOR_MODE, 0x10);
561 
562 	/* Clear cursor image. */
563 	for (i = 0; i < 1024; i++)
564 		gfxp_indexed_write(sc, PM2V_CURSOR_PATTERN + i, 0x00);
565 
566 	/* Clear screen. */
567 	gfxp_fillrect(sc, 0, 0, ri->ri_width, ri->ri_height,
568 	    ri->ri_devcmap[WSCOL_WHITE]);
569 }
570 
571 void
572 gfxp_indexed_write(struct gfxp_softc *sc, bus_size_t offset, uint32_t value)
573 {
574 	gfxp_wait_fifo(sc, 3);
575 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
576 	    PM2V_INDEX_HIGH, offset >> 8);
577 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
578 	    PM2V_INDEX_LOW, offset & 0xff);
579 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2V_INDEX_DATA, value);
580 }
581 
582 int
583 gfxp_wait_fifo(struct gfxp_softc *sc, int n)
584 {
585 	int i;
586 
587 	for (i = 1000000; i != 0; i--) {
588 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
589 		     PM2_IN_FIFO_SPACE) >= n)
590 			break;
591 		DELAY(1);
592 	}
593 
594 	return i;
595 }
596 
597 int
598 gfxp_wait(struct gfxp_softc *sc)
599 {
600 	int i;
601 
602 	for (i = 1000000; i != 0; i--) {
603 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
604 		    PM2_DMA_COUNT) == 0)
605 			break;
606 		DELAY(1);
607 	}
608 
609 	/*
610 	 * Insert a sync into the FIFO...
611 	 */
612 	gfxp_wait_fifo(sc, 2);
613 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh,
614 	    PM2_FILTER_MODE, PM2_FM_PASS_SYNC_TAG);
615 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_SYNC, 0);
616 
617 	/*
618 	 * ...and wait for it to appear on the other end, indicating
619 	 * completion of the operations before it.
620 	 */
621 	for (i = 1000000; i != 0; i--) {
622 		if (bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
623 		    PM2_OUT_FIFO_SPACE) > 0 &&
624 		    bus_space_read_4(sc->sc_mmiot, sc->sc_mmioh,
625 		    PM2_OUT_FIFO) == PM2_SYNC_TAG)
626 			break;
627 		DELAY(1);
628 	}
629 
630 	return i;
631 }
632 
633 void
634 gfxp_copyrect(struct gfxp_softc *sc, int sx, int sy, int dx, int dy,
635     int w, int h)
636 {
637 	int dir = 0;
638 
639 	if (sx > dx)
640 		dir |= PM2_INCREASE_X;
641 	if (sy > dy)
642 		dir |= PM2_INCREASE_Y;
643 
644 	gfxp_wait_fifo(sc, 5);
645 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG,
646 	    PM2_CONFIG_FB_WRITE_EN | PM2_CONFIG_FB_READ_SRC_EN);
647 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_SRC_DELTA,
648 	    PM2_COORDS((sx - dx) & 0xffff, (sy - dy) & 0xffff));
649 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG,
650 	    PM2_COORDS(dx, dy));
651 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE,
652 	    PM2_COORDS(w, h));
653 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER,
654 	    PM2_RENDER_RECT | dir);
655 
656 	gfxp_wait(sc);
657 }
658 
659 void
660 gfxp_fillrect(struct gfxp_softc *sc, int x, int y, int w, int h, int color)
661 {
662 	gfxp_wait_fifo(sc, 5);
663 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_CONFIG,
664 	    PM2_CONFIG_FB_WRITE_EN);
665 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_ORIG,
666 	    PM2_COORDS(x, y));
667 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RECT_SIZE,
668 	    PM2_COORDS(w, h));
669 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_FB_BLOCK_COLOR,
670 	    color);
671 	bus_space_write_4(sc->sc_mmiot, sc->sc_mmioh, PM2_RENDER,
672 	    PM2_RENDER_RECT | PM2_RENDER_FASTFILL);
673 
674 	gfxp_wait(sc);
675 }
676