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