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