gsfb.c revision 1.17 1 /* $NetBSD: gsfb.c,v 1.17 2007/03/04 06:00:30 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: gsfb.c,v 1.17 2007/03/04 06:00:30 christos Exp $");
41
42 #include "debug_playstation2.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46
47 #include <machine/autoconf.h>
48
49 #include <dev/cons.h>
50
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/wscons/wscons_callbacks.h>
54
55 #include <dev/wsfont/wsfont.h>
56
57 #include <playstation2/ee/eevar.h>
58 #include <playstation2/ee/gsvar.h>
59 #include <playstation2/ee/gsreg.h>
60 #include <playstation2/ee/dmacvar.h>
61 #include <playstation2/ee/dmacreg.h>
62
63 #ifdef DEBUG
64 #define STATIC
65 #else
66 #define STATIC static
67 #endif
68
69 STATIC struct gsfb {
70 int initialized;
71 int attached;
72 int is_console;
73 const struct wsscreen_descr *screen;
74 struct wsdisplay_font *font;
75 } gsfb;
76
77 STATIC void gsfb_dma_kick(paddr_t, size_t);
78 STATIC void gsfb_font_expand_psmct32(const struct wsdisplay_font *, u_int,
79 long, u_int32_t *);
80 STATIC inline void gsfb_set_cursor_pos(u_int32_t *, int, int, int, int);
81
82 #define ATTR_FG_GET(a) (((a )>> 24) & 0xf)
83 #define ATTR_BG_GET(a) (((a )>> 16) & 0xf)
84 #define ATTR_FG_SET(x) (((x) << 24) & 0x0f000000)
85 #define ATTR_BG_SET(x) (((x) << 16) & 0x000f0000)
86
87 STATIC const u_int32_t gsfb_ansi_psmct32[] = {
88 0x80000000, /* black */
89 0x800000aa, /* red */
90 0x8000aa00, /* green */
91 0x8000aaaa, /* brown */
92 0x80aa0000, /* blue */
93 0x80aa00aa, /* magenta */
94 0x80aaaa00, /* cyan */
95 0x80aaaaaa, /* white */
96 0x80000000, /* black */
97 0x800000ff, /* red */
98 0x8000ff00, /* green */
99 0x8000ffff, /* brown */
100 0x80ff0000, /* blue */
101 0x80ff00ff, /* magenta */
102 0x80ffff00, /* cyan */
103 0x80ffffff, /* black */
104 };
105
106 #define TRXPOS_DXY(f, x, y) \
107 ({ \
108 f[9] = ((x) & 0x000007ff) | (((y) << 16) & 0x07ff0000); \
109 })
110
111 #define TRXPOS_SY_DY(f, sy, dy) \
112 ({ \
113 f[8] = (((sy) << 16) & 0x07ff0000); \
114 f[9] = (((dy) << 16) & 0x07ff0000); \
115 })
116
117 #define TRXPOS_DXY_SXY(f, dx, dy, sx, sy) \
118 ({ \
119 f[8] = ((((sy) << 16) & 0x07ff0000) | ((sx) & 0x000007ff)); \
120 f[9] = ((((dy) << 16) & 0x07ff0000) | ((dx) & 0x000007ff)); \
121 })
122
123 STATIC u_int32_t gsfb_scroll_cmd_640x16[] __attribute__((__aligned__(16))) = {
124 0x00008004, 0x10000000, 0x0000000e, 0x00000000,
125 0x000a0000, 0x000a0000, 0x00000050, 0x00000000,
126 0x07ff0000, 0x07ff0000, 0x00000051, 0x00000000,
127 0x00000280, 0x00000010, 0x00000052, 0x00000000,
128 0x00000002, 0x00000000, 0x00000053, 0x00000000,
129 };
130
131 STATIC u_int32_t gsfb_cursor_cmd[] __attribute__((__aligned__(16))) = {
132 0x00008007, 0x10000000, 0x0000000e, 0x00000000,
133 0x00000001, 0x00000000, 0x0000001a, 0x00000000,
134 0x000000a4, 0x00000080, 0x00000042, 0x00000000,
135 0x00000046, 0x00000000, 0x00000000, 0x00000000,
136 0x80ffffff, 0x00000000, 0x00000001, 0x00000000,
137 0x00000000, 0x00000000, 0x0000000d, 0x00000000,
138 0x80ffffff, 0x00000000, 0x00000001, 0x00000000,
139 0x00000000, 0x00000000, 0x00000005, 0x00000000,
140 };
141
142 STATIC u_int32_t gsfb_copy_cmd_8x16[] __attribute__((__aligned__(16))) = {
143 0x00008004, 0x10000000, 0x0000000e, 0x00000000,
144 0x000a0000, 0x000a0000, 0x00000050, 0x00000000,
145 0x07ff07ff, 0x07ff07ff, 0x00000051, 0x00000000,
146 0x00000008, 0x00000010, 0x00000052, 0x00000000,
147 0x00000002, 0x00000000, 0x00000053, 0x00000000,
148 };
149
150 STATIC u_int32_t gsfb_init_cmd_640x480[] __attribute__((__aligned__(16))) = {
151 0x00008008, 0x10000000, 0x0000000e, 0x00000000,
152 0x000a0000, 0x00000000, 0x0000004c, 0x00000000,
153 0x00000096, 0x00000000, 0x0000004e, 0x00000000,
154 0x02800000, 0x01e00000, 0x00000040, 0x00000000,
155 0x00000006, 0x00000000, 0x00000000, 0x00000000,
156 0x80000000, 0x00000000, 0x00000001, 0x00000000,
157 0x00000000, 0x00000000, 0x0000000d, 0x00000000,
158 0x80000000, 0x00000000, 0x00000001, 0x00000000,
159 0x1e002800, 0x00000000, 0x00000005, 0x00000000,
160 };
161
162 STATIC u_int32_t gsfb_load_cmd_8x16_psmct32[(6 + 32) * 4]
163 __attribute__((__aligned__(16))) = {
164 /* GIF tag + GS command */
165 0x00000004, 0x10000000, 0x0000000e, 0x00000000,
166 0x00000000, 0x000a0000, 0x00000050, 0x00000000,
167 0x00000000, 0x00000000, 0x00000051, 0x00000000,
168 0x00000008, 0x00000016, 0x00000052, 0x00000000,
169 0x00000000, 0x00000000, 0x00000053, 0x00000000,
170 0x00008020, 0x08000000, 0x00000000, 0x00000000,
171 /* Load area */
172 #define FONT_SCRATCH_BASE (6 * 4)
173 };
174
175 #ifdef GSFB_DEBUG_MONITOR
176 #include <machine/stdarg.h>
177 STATIC const struct _gsfb_debug_window {
178 int start, nrow, attr;
179 } _gsfb_debug_window[3] = {
180 { 24, 2 , ATTR_BG_SET(WSCOL_BROWN) | ATTR_FG_SET(WSCOL_BLUE) },
181 { 26, 2 , ATTR_BG_SET(WSCOL_CYAN) | ATTR_FG_SET(WSCOL_BLUE) },
182 { 28, 2 , ATTR_BG_SET(WSCOL_WHITE) | ATTR_FG_SET(WSCOL_BLUE) },
183 };
184 STATIC char _gsfb_debug_buf[80 * 2];
185 #endif /* GSFB_DEBUG_MONITOR */
186
187 STATIC int gsfb_match(struct device *, struct cfdata *, void *);
188 STATIC void gsfb_attach(struct device *, struct device *, void *);
189
190 CFATTACH_DECL(gsfb, sizeof(struct device),
191 gsfb_match, gsfb_attach, NULL, NULL);
192
193 STATIC void gsfb_hwinit(void);
194 STATIC int gsfb_swinit(void);
195
196 /* console */
197 void gsfbcnprobe(struct consdev *);
198 void gsfbcninit(struct consdev *);
199
200 /* emul ops */
201 STATIC void _gsfb_cursor(void *, int, int, int);
202 STATIC int _gsfb_mapchar(void *, int, unsigned int *);
203 STATIC void _gsfb_putchar(void *, int, int, u_int, long);
204 STATIC void _gsfb_copycols(void *, int, int, int, int);
205 STATIC void _gsfb_erasecols(void *, int, int, int, long);
206 STATIC void _gsfb_copyrows(void *, int, int, int);
207 STATIC void _gsfb_eraserows(void *, int, int, long);
208 STATIC int _gsfb_allocattr(void *, int, int, int, long *);
209
210 /* access ops */
211 STATIC int _gsfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
212 STATIC paddr_t _gsfb_mmap(void *, void *, off_t, int);
213 STATIC int _gsfb_alloc_screen(void *, const struct wsscreen_descr *, void **,
214 int *, int *, long *);
215 STATIC void _gsfb_free_screen(void *, void *);
216 STATIC int _gsfb_show_screen(void *, void *, int, void (*)(void *, int, int),
217 void *);
218 STATIC void _gsfb_pollc(void *, int);
219
220 /*
221 * wsdisplay attach args
222 * std: screen size 640 x 480, font size 8 x 16
223 */
224 #define GSFB_STD_SCREEN_WIDTH 640
225 #define GSFB_STD_SCREEN_HEIGHT 480
226 #define GSFB_STD_FONT_WIDTH 8
227 #define GSFB_STD_FONT_HEIGHT 16
228 const struct wsdisplay_emulops _gsfb_emulops = {
229 .cursor = _gsfb_cursor,
230 .mapchar = _gsfb_mapchar,
231 .putchar = _gsfb_putchar,
232 .copycols = _gsfb_copycols,
233 .erasecols = _gsfb_erasecols,
234 .copyrows = _gsfb_copyrows,
235 .eraserows = _gsfb_eraserows,
236 .allocattr = _gsfb_allocattr
237 };
238
239 const struct wsscreen_descr _gsfb_std_screen = {
240 .name = "std",
241 .ncols = 80,
242 #ifdef GSFB_DEBUG_MONITOR
243 .nrows = 24,
244 #else
245 .nrows = 30,
246 #endif
247 .textops = &_gsfb_emulops,
248 .fontwidth = 8,
249 .fontheight = 16,
250 .capabilities = WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
251 WSSCREEN_WSCOLORS
252 };
253
254 const struct wsscreen_descr *_gsfb_screen_table[] = {
255 &_gsfb_std_screen,
256 };
257
258 struct wsscreen_list _gsfb_screen_list = {
259 .nscreens = sizeof(_gsfb_screen_table) /
260 sizeof(_gsfb_screen_table[0]),
261 .screens = _gsfb_screen_table
262 };
263
264 struct wsdisplay_accessops _gsfb_accessops = {
265 .ioctl = _gsfb_ioctl,
266 .mmap = _gsfb_mmap,
267 .alloc_screen = _gsfb_alloc_screen,
268 .free_screen = _gsfb_free_screen,
269 .show_screen = _gsfb_show_screen,
270 .load_font = 0,
271 .pollc = _gsfb_pollc
272 };
273
274 int
275 gsfb_match(struct device *parent, struct cfdata *cf, void *aux)
276 {
277 extern struct cfdriver gsfb_cd;
278 struct mainbus_attach_args *ma = aux;
279
280 if (strcmp(ma->ma_name, gsfb_cd.cd_name) != 0)
281 return (0);
282
283 return (!gsfb.attached);
284 }
285
286 void
287 gsfb_attach(struct device *parent, struct device *self, void *aux)
288 {
289 struct wsemuldisplaydev_attach_args wa;
290
291 gsfb.attached = 1;
292 if (!gsfb.is_console && gsfb_swinit() != 0)
293 return;
294
295 printf("\n");
296
297 wa.console = gsfb.is_console;
298 wa.scrdata = &_gsfb_screen_list;
299 wa.accessops = &_gsfb_accessops;
300 wa.accesscookie = &gsfb;
301
302 config_found(self, &wa, wsdisplaydevprint);
303 }
304
305 /*
306 * console
307 */
308 void
309 gsfbcnprobe(struct consdev *cndev)
310 {
311
312 cndev->cn_pri = CN_INTERNAL;
313 }
314
315 void
316 gsfbcninit(struct consdev *cndev)
317 {
318 paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_init_cmd_640x480);
319 u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
320 long defattr = ATTR_BG_SET(WS_DEFAULT_BG) | ATTR_FG_SET(WS_DEFAULT_FG);
321
322 gsfb.is_console = 1;
323
324 gsfb_hwinit();
325 gsfb_swinit();
326
327 /* Set the screen to the default background color at boot */
328 buf[28] = gsfb_ansi_psmct32[ATTR_BG_GET(defattr)];
329 gsfb_dma_kick(paddr, sizeof gsfb_init_cmd_640x480);
330 #ifdef GSFB_DEBUG_MONITOR
331 {
332 const struct _gsfb_debug_window *win;
333 int i;
334
335 for (i = 0; i < 3; i++) {
336 win = &_gsfb_debug_window[i];
337 _gsfb_eraserows(0, win->start, win->nrow, win->attr);
338 }
339 }
340 #endif /* GSFB_DEBUG_MONITOR */
341
342 wsdisplay_cnattach(&_gsfb_std_screen, &gsfb, 0, 0, defattr);
343 }
344
345 void
346 gsfb_hwinit()
347 {
348 /*
349 gs_init(VESA_1A) hang up on SCPH-50000.
350 use bootloader's setting.
351 EN1 | CRTMOD | MMOD | AMOD | ALP(all 1.0)
352 */
353 _reg_write_8(GS_S_PMODE_REG, 0xffa5);
354
355 dmac_init();
356
357 /* reset GIF channel DMA */
358 _reg_write_4(D2_QWC_REG, 0);
359 _reg_write_4(D2_MADR_REG, 0);
360 _reg_write_4(D2_TADR_REG, 0);
361 _reg_write_4(D2_CHCR_REG, 0);
362 }
363
364 int
365 gsfb_swinit()
366 {
367 int font;
368
369 wsfont_init();
370 font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
371 WSDISPLAY_FONTORDER_L2R);
372 if (font < 0)
373 return (1);
374
375 if (wsfont_lock(font, &gsfb.font))
376 return (1);
377
378 gsfb.screen = &_gsfb_std_screen;
379 gsfb.initialized = 1;
380
381 return (0);
382 }
383
384 /*
385 * wsdisplay
386 */
387 void
388 _gsfb_cursor(void *cookie, int on, int row, int col)
389 {
390 paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_cursor_cmd);
391 u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
392 struct wsdisplay_font *font = gsfb.font;
393
394 gsfb_set_cursor_pos(buf, col, row, font->fontwidth, font->fontheight);
395
396 gsfb_dma_kick(paddr, sizeof gsfb_cursor_cmd);
397 }
398
399 inline void
400 gsfb_set_cursor_pos(u_int32_t *p, int x, int y, int w, int h)
401 {
402
403 x *= w;
404 y *= h;
405 p[20] = ((x << 4) & 0xffff) | ((y << 20) & 0xffff0000);
406 p[28] = (((x + w) << 4) & 0xffff) | (((y + h) << 20) & 0xffff0000);
407 }
408
409 int
410 _gsfb_mapchar(void *cookie, int c, unsigned int *cp)
411 {
412 struct wsdisplay_font *font = gsfb.font;
413
414 if (font->encoding != WSDISPLAY_FONTENC_ISO)
415 if ((c = wsfont_map_unichar(font, c)) < 0)
416 goto nomap;
417
418 if (c < font->firstchar || c >= font->firstchar + font->numchars)
419 goto nomap;
420
421 *cp = c;
422 return (5);
423
424 nomap:
425 *cp = ' ';
426 return (0);
427 }
428
429 void
430 _gsfb_putchar(void *cookie, int row, int col, u_int uc, long attr)
431 {
432 paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_load_cmd_8x16_psmct32);
433 u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
434 struct wsdisplay_font *font = gsfb.font;
435
436 /* copy font data to DMA region */
437 gsfb_font_expand_psmct32(font, uc, attr, &buf[FONT_SCRATCH_BASE]);
438
439 /* set destination position */
440 TRXPOS_DXY(buf, col * font->fontwidth, row * font->fontheight);
441
442 /* kick to GIF */
443 gsfb_dma_kick(paddr, sizeof gsfb_load_cmd_8x16_psmct32);
444 }
445
446 void
447 _gsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
448 {
449 paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_copy_cmd_8x16);
450 u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
451 int y = gsfb.font->fontheight * row;
452 int w = gsfb.font->fontwidth;
453 int i;
454
455 if (dstcol > srccol) {
456 for (i = ncols - 1; i >= 0; i--) {
457 TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
458 gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
459 }
460 } else {
461 for (i = 0; i < ncols; i++) {
462 TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
463 gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
464 }
465 }
466 }
467
468 void
469 _gsfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
470 {
471 int i;
472
473 for (i = 0; i < ncols; i++)
474 _gsfb_putchar(cookie, row, startcol + i, ' ', attr);
475 }
476
477 void
478 _gsfb_copyrows(void *cookie, int src, int dst, int num)
479 {
480 paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_scroll_cmd_640x16);
481 u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
482 int i;
483 int h = gsfb.font->fontheight;
484
485 if (dst > src) {
486 for (i = num - 1; i >= 0; i--) {
487 TRXPOS_SY_DY(cmd, (src + i) * h, (dst + i) * h);
488 gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
489 }
490 } else {
491 for (i = 0; i < num; i++) {
492 TRXPOS_SY_DY(cmd, (src + i) * h, (dst + i) * h);
493 gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
494 }
495 }
496 }
497
498 void
499 _gsfb_eraserows(void *cookie, int row, int nrow, long attr)
500 {
501 int i, j;
502
503 for (j = 0; j < nrow; j++)
504 for (i = 0; i < gsfb.screen->ncols; i++)
505 _gsfb_putchar(cookie, row + j, i, ' ', attr);
506 }
507
508 int
509 _gsfb_allocattr(void *cookie, int fg, int bg, int flags, long *attr)
510 {
511
512 if ((flags & WSATTR_BLINK) != 0)
513 return (EINVAL);
514
515 if ((flags & WSATTR_WSCOLORS) == 0) {
516 fg = WS_DEFAULT_FG;
517 bg = WS_DEFAULT_BG;
518 }
519
520 if ((flags & WSATTR_HILIT) != 0)
521 fg += 8;
522
523 flags = (flags & WSATTR_UNDERLINE) ? 1 : 0;
524
525
526 *attr = ATTR_BG_SET(bg) | ATTR_FG_SET(fg) | flags;
527
528 return (0);
529 }
530
531 int
532 _gsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
533 struct lwp *l)
534 {
535
536 return (EPASSTHROUGH); /* Inappropriate ioctl for device */
537 }
538
539 paddr_t
540 _gsfb_mmap(void *v, void *vs, off_t offset, int prot)
541 {
542
543 return (-1); /* can't mmap */
544 }
545
546 int
547 _gsfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
548 int *curxp, int *curyp, long *attrp)
549 {
550
551 *attrp = ATTR_BG_SET(WS_DEFAULT_BG) | ATTR_FG_SET(WS_DEFAULT_FG);
552
553 return (0);
554 }
555
556 void
557 _gsfb_free_screen(void *v, void *cookie)
558 {
559 }
560
561 int
562 _gsfb_show_screen(void *v, void *cookie, int waitok,
563 void (*cb)(void *, int, int), void *cbarg)
564 {
565
566 return (0);
567 }
568
569 void
570 _gsfb_pollc(void *v, int on)
571 {
572
573 }
574
575 /*
576 * font expansion
577 * PSMCT32 only
578 */
579 void
580 gsfb_font_expand_psmct32(const struct wsdisplay_font *font, u_int c, long attr,
581 u_int32_t *buf)
582 {
583 u_int32_t fg, bg;
584 u_int8_t *bitmap;
585 int i, j;
586
587 KDASSERT(((u_int32_t)buf & 15) == 0);
588
589 fg = gsfb_ansi_psmct32[ATTR_FG_GET(attr)];
590 bg = gsfb_ansi_psmct32[ATTR_BG_GET(attr)];
591
592 bitmap = (u_int8_t *)font->data + (c - font->firstchar) *
593 font->fontheight * font->stride;
594 for (i = 0; i < font->fontheight; i++, bitmap++) {
595 u_int32_t b = *bitmap;
596 for (j = 0; j < font->fontwidth; j++, b <<= 1)
597 *buf++ = (b & 0x80) ? fg : bg;
598 }
599 }
600
601 void
602 gsfb_dma_kick(paddr_t addr, size_t size)
603 {
604 /* Wait for previous DMA request complete */
605 while (_reg_read_4(D2_QWC_REG))
606 ;
607
608 /* Wait until GS FIFO empty */
609 while ((_reg_read_8(GS_S_CSR_REG) & (3 << 14)) != (1 << 14))
610 ;
611
612 /* wait for DMA complete */
613 dmac_bus_poll(D_CH2_GIF);
614
615 /* transfer addr */
616 _reg_write_4(D2_MADR_REG, addr);
617 /* transfer data size (unit qword) */
618 _reg_write_4(D2_QWC_REG, bytetoqwc(size));
619
620 /* kick DMA (normal-mode) */
621 dmac_chcr_write(D_CH2_GIF, D_CHCR_STR);
622 }
623
624 #ifdef GSFB_DEBUG_MONITOR
625 void
626 __gsfb_print(int window, const char *fmt, ...)
627 {
628 const struct _gsfb_debug_window *win;
629 int i, s, x, y, n, a;
630 u_int c;
631 va_list ap;
632
633 if (!gsfb.initialized)
634 return;
635
636 s = _intr_suspend();
637 win = &_gsfb_debug_window[window];
638 x = 0;
639 y = win->start;
640 n = win->nrow * 80;
641 a = win->attr;
642
643 va_start(ap, fmt);
644 vsnprintf(_gsfb_debug_buf, n, fmt, ap);
645 va_end(ap);
646
647 _gsfb_eraserows(0, y, win->nrow, a);
648
649 for (i = 0; i < n &&
650 (c = (u_int)_gsfb_debug_buf[i] & 0x7f) != 0; i++) {
651 if (c == '\n')
652 x = 0, y++;
653 else
654 _gsfb_putchar(0, y, x++, c, a);
655 }
656
657 _intr_resume(s);
658 }
659
660 void
661 __gsfb_print_hex(int a0, int a1, int a2, int a3)
662 {
663 __gsfb_print(2, "a0=%08x a1=%08x a2=%08x a3=%08x",
664 a0, a1, a2, a3);
665 }
666 #endif /* GSFB_DEBUG_MONITOR */
667