Home | History | Annotate | Line # | Download | only in ee
gsfb.c revision 1.3
      1 /*	$NetBSD: gsfb.c,v 1.3 2002/03/17 19:40:48 atatat 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 struct cfattach gsfb_ca = {
    188 	sizeof(struct device), gsfb_match, gsfb_attach
    189 };
    190 
    191 STATIC void gsfb_hwinit(void);
    192 STATIC int gsfb_swinit(void);
    193 
    194 /* console */
    195 void gsfbcnprobe(struct consdev *);
    196 void gsfbcninit(struct consdev *);
    197 
    198 /* emul ops */
    199 STATIC void _gsfb_cursor(void *, int, int, int);
    200 STATIC int _gsfb_mapchar(void *, int, unsigned int *);
    201 STATIC void _gsfb_putchar(void *, int, int, u_int, long);
    202 STATIC void _gsfb_copycols(void *, int, int, int, int);
    203 STATIC void _gsfb_erasecols(void *, int, int, int, long);
    204 STATIC void _gsfb_copyrows(void *, int, int, int);
    205 STATIC void _gsfb_eraserows(void *, int, int, long);
    206 STATIC int _gsfb_alloc_attr(void *, int, int, int, long *);
    207 
    208 /* access ops */
    209 STATIC int _gsfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
    210 STATIC paddr_t _gsfb_mmap(void *, off_t, int);
    211 STATIC int _gsfb_alloc_screen(void *, const struct wsscreen_descr *, void **,
    212     int *, int *, long *);
    213 STATIC void _gsfb_free_screen(void *, void *);
    214 STATIC int _gsfb_show_screen(void *, void *, int, void (*)(void *, int, int),
    215     void *);
    216 STATIC void _gsfb_pollc(void *, int);
    217 
    218 /*
    219  * wsdisplay attach args
    220  *   std: screen size 640 x 480, font size 8 x 16
    221  */
    222 #define GSFB_STD_SCREEN_WIDTH		640
    223 #define GSFB_STD_SCREEN_HEIGHT		480
    224 #define GSFB_STD_FONT_WIDTH		8
    225 #define GSFB_STD_FONT_HEIGHT		16
    226 const struct wsdisplay_emulops _gsfb_emulops = {
    227 	.cursor		= _gsfb_cursor,
    228 	.mapchar	= _gsfb_mapchar,
    229 	.putchar	= _gsfb_putchar,
    230 	.copycols	= _gsfb_copycols,
    231 	.erasecols	= _gsfb_erasecols,
    232 	.copyrows	= _gsfb_copyrows,
    233 	.eraserows	= _gsfb_eraserows,
    234 	.alloc_attr	= _gsfb_alloc_attr
    235 };
    236 
    237 const struct wsscreen_descr _gsfb_std_screen = {
    238 	.name		= "std",
    239 	.ncols		= 80,
    240 #ifdef GSFB_DEBUG_MONITOR
    241 	.nrows		= 24,
    242 #else
    243 	.nrows		= 30,
    244 #endif
    245 	.textops	= &_gsfb_emulops,
    246 	.fontwidth	= 8,
    247 	.fontheight	= 16,
    248 	.capabilities	= WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
    249 	WSSCREEN_WSCOLORS
    250 };
    251 
    252 const struct wsscreen_descr *_gsfb_screen_table[] = {
    253 	&_gsfb_std_screen,
    254 };
    255 
    256 struct wsscreen_list _gsfb_screen_list = {
    257 	.nscreens	= sizeof(_gsfb_screen_table) /
    258 	sizeof(_gsfb_screen_table[0]),
    259 	.screens	= _gsfb_screen_table
    260 };
    261 
    262 struct wsdisplay_accessops _gsfb_accessops = {
    263 	.ioctl		= _gsfb_ioctl,
    264 	.mmap		= _gsfb_mmap,
    265 	.alloc_screen	= _gsfb_alloc_screen,
    266 	.free_screen	= _gsfb_free_screen,
    267 	.show_screen	= _gsfb_show_screen,
    268 	.load_font	= 0,
    269 	.pollc		= _gsfb_pollc
    270 };
    271 
    272 int
    273 gsfb_match(struct device *parent, struct cfdata *cf, void *aux)
    274 {
    275 	extern struct cfdriver gsfb_cd;
    276 	struct mainbus_attach_args *ma = aux;
    277 
    278 	if (strcmp(ma->ma_name, gsfb_cd.cd_name) != 0)
    279 		return (0);
    280 
    281 	return (!gsfb.attached);
    282 }
    283 
    284 void
    285 gsfb_attach(struct device *parent, struct device *self, void *aux)
    286 {
    287 	struct wsemuldisplaydev_attach_args wa;
    288 
    289 	gsfb.attached = 1;
    290 	if (!gsfb.is_console && gsfb_swinit() != 0)
    291 		return;
    292 
    293 	printf("\n");
    294 
    295 	wa.console	= gsfb.is_console;
    296 	wa.scrdata	= &_gsfb_screen_list;
    297 	wa.accessops	= &_gsfb_accessops;
    298 	wa.accesscookie	= &gsfb;
    299 
    300 	config_found(self, &wa, wsdisplaydevprint);
    301 }
    302 
    303 /*
    304  * console
    305  */
    306 void
    307 gsfbcnprobe(struct consdev *cndev)
    308 {
    309 
    310 	cndev->cn_pri = CN_INTERNAL;
    311 }
    312 
    313 void
    314 gsfbcninit(struct consdev *cndev)
    315 {
    316 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_init_cmd_640x480);
    317 	long defattr =  ATTR_BG_SET(WSCOL_BLACK) | ATTR_FG_SET(WSCOL_WHITE);
    318 
    319 	gsfb.is_console = 1;
    320 
    321 	gsfb_hwinit();
    322 	gsfb_swinit();
    323 
    324 	gsfb_dma_kick(paddr, sizeof gsfb_init_cmd_640x480);
    325 #ifdef GSFB_DEBUG_MONITOR
    326 	{
    327 		const struct _gsfb_debug_window *win;
    328 		int i;
    329 
    330 		for (i = 0; i < 3; i++) {
    331 			win = &_gsfb_debug_window[i];
    332 			_gsfb_eraserows(0, win->start, win->nrow, win->attr);
    333 		}
    334 	}
    335 #endif /* GSFB_DEBUG_MONITOR */
    336 
    337 	wsdisplay_cnattach(&_gsfb_std_screen, &gsfb, 0, 0, defattr);
    338 }
    339 
    340 void
    341 gsfb_hwinit()
    342 {
    343 	gs_init(VESA_1A);
    344 	dmac_init();
    345 
    346 	/* reset GIF channel DMA */
    347 	_reg_write_4(D2_QWC_REG, 0);
    348 	_reg_write_4(D2_MADR_REG, 0);
    349 	_reg_write_4(D2_TADR_REG, 0);
    350 	_reg_write_4(D2_CHCR_REG, 0);
    351 }
    352 
    353 int
    354 gsfb_swinit()
    355 {
    356 	int font;
    357 
    358 	wsfont_init();
    359 	font = wsfont_find(NULL, 8, 16, 0,  WSDISPLAY_FONTORDER_L2R,
    360 	    WSDISPLAY_FONTORDER_L2R);
    361 	if (font < 0)
    362 		return (1);
    363 
    364 	if (wsfont_lock(font, &gsfb.font))
    365 		return (1);
    366 
    367 	gsfb.screen = &_gsfb_std_screen;
    368 	gsfb.initialized = 1;
    369 
    370 	return (0);
    371 }
    372 
    373 /*
    374  * wsdisplay
    375  */
    376 void
    377 _gsfb_cursor(void *cookie, int on, int row, int col)
    378 {
    379 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_cursor_cmd);
    380 	u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    381 	struct wsdisplay_font *font = gsfb.font;
    382 
    383 	gsfb_set_cursor_pos(buf, col, row, font->fontwidth, font->fontheight);
    384 
    385 	gsfb_dma_kick(paddr, sizeof gsfb_cursor_cmd);
    386 }
    387 
    388 __inline__ void
    389 gsfb_set_cursor_pos(u_int32_t *p, int x, int y, int w, int h)
    390 {
    391 
    392 	x *= w;
    393 	y *= h;
    394 	p[20] = ((x << 4) & 0xffff) | ((y << 20) & 0xffff0000);
    395 	p[28] = (((x + w - 1) << 4) & 0xffff) |
    396 	    (((y + h - 1) << 20) & 0xffff0000);
    397 }
    398 
    399 int
    400 _gsfb_mapchar(void *cookie, int c, unsigned int *cp)
    401 {
    402 	struct wsdisplay_font *font = gsfb.font;
    403 
    404 	if (font->encoding != WSDISPLAY_FONTENC_ISO)
    405 		if ((c = wsfont_map_unichar(font, c)) < 0)
    406 			goto nomap;
    407 
    408 	if (c < font->firstchar || c >= font->firstchar + font->numchars)
    409 			goto nomap;
    410 
    411 	*cp = c;
    412 	return (5);
    413 
    414  nomap:
    415 	*cp = ' ';
    416 	return (0);
    417 }
    418 
    419 void
    420 _gsfb_putchar(void *cookie, int row, int col, u_int uc, long attr)
    421 {
    422 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_load_cmd_8x16_psmct32);
    423 	u_int32_t *buf = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    424 	struct wsdisplay_font *font = gsfb.font;
    425 
    426 	/* copy font data to DMA region */
    427 	gsfb_font_expand_psmct32(font, uc, attr, &buf[FONT_SCRATCH_BASE]);
    428 
    429 	/* set destination position */
    430 	TRXPOS_DXY(buf, col * font->fontwidth, row * font->fontheight);
    431 
    432 	/* kick to GIF */
    433 	gsfb_dma_kick(paddr, sizeof gsfb_load_cmd_8x16_psmct32);
    434 }
    435 
    436 void
    437 _gsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
    438 {
    439 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_copy_cmd_8x16);
    440 	u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    441 	int y = gsfb.font->fontheight * row;
    442 	int w = gsfb.font->fontwidth;
    443 	int i;
    444 
    445 	if (dstcol > srccol) {
    446 		for (i = ncols - 1; i >= 0; i--) {
    447 			TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
    448 			gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
    449 		}
    450 	} else {
    451 		for (i = 0; i < ncols; i++) {
    452 			TRXPOS_DXY_SXY(cmd, (dstcol + i) * w, y, (srccol + i) * w, y);
    453 			gsfb_dma_kick(paddr, sizeof gsfb_copy_cmd_8x16);
    454 		}
    455 	}
    456 }
    457 
    458 void
    459 _gsfb_erasecols(void *cookie, int row, int startcol, int ncols, long attr)
    460 {
    461 	int i;
    462 
    463 	for (i = 0; i < ncols; i++)
    464 		_gsfb_putchar(cookie, row, startcol + i, ' ', attr);
    465 }
    466 
    467 void
    468 _gsfb_copyrows(void *cookie, int src, int dst, int num)
    469 {
    470 	paddr_t paddr = MIPS_KSEG0_TO_PHYS(gsfb_scroll_cmd_640x16);
    471 	u_int32_t *cmd = (void *)MIPS_PHYS_TO_KSEG1(paddr);
    472 	int i;
    473 	int h = gsfb.font->fontheight;
    474 
    475 	if (dst > src) {
    476 		for (i = num - 1; i >= 0; i--) {
    477 			TRXPOS_SY_DY(cmd, (src + i) * h, (dst  + i) * h);
    478 			gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
    479 		}
    480 	} else {
    481 		for (i = 0; i < num; i++) {
    482 			TRXPOS_SY_DY(cmd, (src + i) * h, (dst  + i) * h);
    483 			gsfb_dma_kick(paddr, sizeof gsfb_scroll_cmd_640x16);
    484 		}
    485 	}
    486 }
    487 
    488 void
    489 _gsfb_eraserows(void *cookie, int row, int nrow, long attr)
    490 {
    491 	int i, j;
    492 
    493 	for (j = 0; j < nrow; j++)
    494 		for (i = 0; i < gsfb.screen->ncols; i++)
    495 			_gsfb_putchar(cookie, row + j, i, ' ', attr);
    496 }
    497 
    498 int
    499 _gsfb_alloc_attr(void *cookie, int fg, int bg, int flags, long *attr)
    500 {
    501 
    502 	if ((flags & WSATTR_BLINK) != 0)
    503 		return (EINVAL);
    504 
    505 	if ((flags & WSATTR_WSCOLORS) == 0) {
    506 		fg = WSCOL_WHITE;
    507 		bg = WSCOL_BLACK;
    508 	}
    509 
    510 	if ((flags & WSATTR_HILIT) != 0)
    511 		fg += 8;
    512 
    513 	flags = (flags & WSATTR_UNDERLINE) ? 1 : 0;
    514 
    515 
    516 	*attr = ATTR_BG_SET(bg) | ATTR_FG_SET(fg) | flags;
    517 
    518 	return (0);
    519 }
    520 
    521 int
    522 _gsfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
    523 {
    524 
    525 	return (EPASSTHROUGH); /* Inappropriate ioctl for device */
    526 }
    527 
    528 paddr_t
    529 _gsfb_mmap(void *v, off_t offset, int prot)
    530 {
    531 
    532 	return (NULL); /* can't mmap */
    533 }
    534 
    535 int
    536 _gsfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    537     int *curxp, int *curyp, long *attrp)
    538 {
    539 
    540 	*attrp = ATTR_BG_SET(WSCOL_BLACK) | ATTR_FG_SET(WSCOL_WHITE);
    541 
    542 	return (0);
    543 }
    544 
    545 void
    546 _gsfb_free_screen(void *v, void *cookie)
    547 {
    548 }
    549 
    550 int
    551 _gsfb_show_screen(void *v, void *cookie, int waitok,
    552     void (*cb)(void *, int, int), void *cbarg)
    553 {
    554 
    555 	return (0);
    556 }
    557 
    558 void
    559 _gsfb_pollc(void *v, int on)
    560 {
    561 
    562 }
    563 
    564 /*
    565  * font expansion
    566  *   PSMCT32 only
    567  */
    568 void
    569 gsfb_font_expand_psmct32(const struct wsdisplay_font *font, u_int c, long attr,
    570     u_int32_t *buf)
    571 {
    572 	u_int32_t fg, bg;
    573 	u_int8_t *bitmap;
    574 	int i, j;
    575 
    576 	KDASSERT(((u_int32_t)buf & 15) == 0);
    577 
    578 	fg = gsfb_ansi_psmct32[ATTR_FG_GET(attr)];
    579 	bg = gsfb_ansi_psmct32[ATTR_BG_GET(attr)];
    580 
    581 	bitmap = (u_int8_t *)font->data + (c - font->firstchar) *
    582 	    font->fontheight * font->stride;
    583 	for (i = 0; i < font->fontheight; i++, bitmap++) {
    584 		u_int32_t b = *bitmap;
    585 		for (j = 0; j < font->fontwidth; j++, b <<= 1)
    586 			*buf++ = (b & 0x80) ? fg : bg;
    587 	}
    588 }
    589 
    590 void
    591 gsfb_dma_kick(paddr_t addr, size_t size)
    592 {
    593 	/* Wait for previous DMA request complete */
    594 	while (_reg_read_4(D2_QWC_REG))
    595 		;
    596 
    597 	/* Wait until GS FIFO empty */
    598 	while ((_reg_read_8(GS_S_CSR_REG) & (3 << 14)) != (1 << 14))
    599 		;
    600 
    601 	/* wait for DMA complete */
    602 	dmac_bus_poll(D_CH2_GIF);
    603 
    604 	/* transfer addr */
    605 	_reg_write_4(D2_MADR_REG, addr);
    606 	/* transfer data size (unit qword) */
    607 	_reg_write_4(D2_QWC_REG, bytetoqwc(size));
    608 
    609 	/* kick DMA (normal-mode) */
    610 	dmac_chcr_write(D_CH2_GIF, D_CHCR_STR);
    611 }
    612 
    613 #ifdef GSFB_DEBUG_MONITOR
    614 void
    615 __gsfb_print(int window, const char *fmt, ...)
    616 {
    617 	const struct _gsfb_debug_window *win;
    618 	int i, s, x, y, n, a;
    619 	u_int c;
    620 	va_list ap;
    621 
    622 	if (!gsfb.initialized)
    623 		return;
    624 
    625 	s = _intr_suspend();
    626 	win = &_gsfb_debug_window[window];
    627 	x = 0;
    628 	y = win->start;
    629 	n = win->nrow * 80;
    630 	a = win->attr;
    631 
    632 	va_start(ap, fmt);
    633 	vsnprintf(_gsfb_debug_buf, n, fmt, ap);
    634 	va_end(ap);
    635 
    636 	_gsfb_eraserows(0, y, win->nrow, a);
    637 
    638 	for (i = 0; i < n &&
    639 	    (c = (u_int)_gsfb_debug_buf[i] & 0x7f) != 0; i++) {
    640 		if (c == '\n')
    641 			x = 0, y++;
    642 		else
    643 			_gsfb_putchar(0, y, x++, c, a);
    644 	}
    645 
    646 	_intr_resume(s);
    647 }
    648 
    649 void
    650 __gsfb_print_hex(int a0, int a1, int a2, int a3)
    651 {
    652 	__gsfb_print(2, "a0=%08x a1=%08x a2=%08x a3=%08x",
    653 	    a0, a1, a2, a3);
    654 }
    655 #endif /* GSFB_DEBUG_MONITOR */
    656