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