Home | History | Annotate | Line # | Download | only in vsa
      1 /*	$NetBSD: lcg.c,v 1.13 2025/02/28 13:13:41 hans Exp $ */
      2 /*
      3  * LCG accelerated framebuffer driver
      4  * Copyright (c) 2003, 2004 Blaz Antonic
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the abovementioned copyrights
     17  * 4. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 /*
     32  * Resurrection and dumb framebuffer mode by Bjrn Johannesson
     33  * rherdware (at) yahoo.com in December 2014
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: lcg.c,v 1.13 2025/02/28 13:13:41 hans Exp $");
     38 
     39 #define LCG_NO_ACCEL
     40 
     41 #include <sys/param.h>
     42 #include <sys/device.h>
     43 #include <sys/systm.h>
     44 #include <sys/callout.h>
     45 #include <sys/time.h>
     46 #include <sys/kmem.h>
     47 #include <sys/conf.h>
     48 #include <sys/kernel.h>
     49 #include <sys/systm.h>
     50 
     51 #include <machine/vsbus.h>
     52 #include <machine/sid.h>
     53 #include <machine/cpu.h>
     54 #include <machine/lcgreg.h>
     55 
     56 #include <dev/cons.h>
     57 
     58 #include <dev/dec/dzreg.h>
     59 #include <dev/dec/dzvar.h>
     60 #include <dev/dec/dzkbdvar.h>
     61 
     62 #include <dev/wscons/wsdisplayvar.h>
     63 #include <dev/wscons/wsconsio.h>
     64 #include <dev/wscons/wscons_callbacks.h>
     65 #include <dev/wsfont/wsfont.h>
     66 
     67 #include "machine/scb.h"
     68 
     69 #include "dzkbd.h"
     70 
     71 /* Screen hardware defs */
     72 
     73 #define	LCG_FB_ADDR		0x21801000	/* Frame buffer */
     74 
     75 /* FIFO defines */
     76 #define LCG_FIFO_SIZE		0x10000	/* 64 KB */
     77 #define LCG_FIFO_WIN_ADDR	0x20180000
     78 #define LCG_FIFO_WIN_SIZE	VAX_NBPG
     79 #define LCG_FIFO_ALIGN		0x10000
     80 
     81 /* font rendering defines */
     82 #define LCG_FONT_ADDR		(LCG_FB_ADDR + lcg_fb_size)
     83 #define LCG_FONT_STORAGE_SIZE	0x40000	/* 16 KB, enough to accommodate 16x32 font bitmaps */
     84 
     85 /* register space defines */
     86 #define LCG_REG_ADDR	0x20100000	/* LCG registers */
     87 #define LCG_REG_SIZE	0x4000		/* 16384 bytes */
     88 #define LCG_REG(reg) regaddr[(reg / 4)]
     89 
     90 /* LUT defines */
     91 #define LCG_LUT_ADDR	0x21800800	/* LUT right before onscreen FB */
     92 #define LCG_LUT_OFFSET	0x00000800
     93 #define LCG_LUT_SIZE	0x800		/* 2048 bytes */
     94 
     95 #define	LCG_BG_COLOR	WSCOL_BLACK
     96 #define	LCG_FG_COLOR	WSCOL_WHITE
     97 
     98 #define	LCG_CONFIG	0x200f0010	/* LCG model information */
     99 
    100 /* implement sanity checks at certain points to ensure safer operation */
    101 #define LCG_SAFE
    102 //#define LCG_DEBUG
    103 
    104 static	int lcg_match(struct device *, struct cfdata *, void *);
    105 static	void lcg_attach(struct device *, struct device *, void *);
    106 
    107 struct	lcg_softc {
    108 	bus_dmamap_t sc_dm;
    109 };
    110 
    111 CFATTACH_DECL_NEW(lcg, sizeof(struct lcg_softc),
    112     lcg_match, lcg_attach, NULL, NULL);
    113 
    114 static void	lcg_cursor(void *, int, int, int);
    115 static int	lcg_mapchar(void *, int, unsigned int *);
    116 static void	lcg_putchar(void *, int, int, u_int, long);
    117 static void	lcg_copycols(void *, int, int, int,int);
    118 static void	lcg_erasecols(void *, int, int, int, long);
    119 static void	lcg_copyrows(void *, int, int, int);
    120 static void	lcg_eraserows(void *, int, int, long);
    121 static int	lcg_allocattr(void *, int, int, int, long *);
    122 static int	lcg_get_cmap(struct wsdisplay_cmap *);
    123 static int	lcg_set_cmap(struct wsdisplay_cmap *);
    124 static void	lcg_init_common(struct device *, struct vsbus_attach_args *);
    125 
    126 const struct wsdisplay_emulops lcg_emulops = {
    127 	lcg_cursor,
    128 	lcg_mapchar,
    129 	lcg_putchar,
    130 	lcg_copycols,
    131 	lcg_erasecols,
    132 	lcg_copyrows,
    133 	lcg_eraserows,
    134 	lcg_allocattr
    135 };
    136 
    137 static char lcg_stdscreen_name[10] = "160x68";
    138 struct wsscreen_descr lcg_stdscreen = {
    139 	lcg_stdscreen_name, 160, 68,		/* dynamically set */
    140 	&lcg_emulops,
    141 	8, 15,					/* dynamically set */
    142 	WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS,
    143 };
    144 
    145 const struct wsscreen_descr *_lcg_scrlist[] = {
    146 	&lcg_stdscreen,
    147 };
    148 
    149 const struct wsscreen_list lcg_screenlist = {
    150 	sizeof(_lcg_scrlist) / sizeof(struct wsscreen_descr *),
    151 	_lcg_scrlist,
    152 };
    153 
    154 static	char *lcgaddr;
    155 static	char *lutaddr;
    156 static	volatile long *regaddr;
    157 static	volatile long *fifoaddr;
    158 #ifndef LCG_NO_ACCEL
    159 static	char *fontaddr;
    160 #endif
    161 
    162 static int	lcg_xsize;
    163 static int	lcg_ysize;
    164 static int	lcg_depth;
    165 static int	lcg_cols;
    166 static int	lcg_rows;
    167 static int	lcg_onerow;
    168 static int	lcg_fb_size;
    169 static int	lcg_glyph_size; /* bitmap size in bits */
    170 
    171 static	char *cursor;
    172 
    173 static	int cur_on;
    174 
    175 static	int cur_fg, cur_bg;
    176 
    177 
    178 /* Our current hardware colormap */
    179 static struct hwcmap256 {
    180 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
    181 	u_int8_t r[CMAP_SIZE];
    182 	u_int8_t g[CMAP_SIZE];
    183 	u_int8_t b[CMAP_SIZE];
    184 } lcg_cmap;
    185 
    186 /* The default colormap */
    187 static struct {
    188 	u_int8_t r[8];
    189 	u_int8_t g[8];
    190 	u_int8_t b[8];
    191 } lcg_default_cmap = {
    192 	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
    193 	{ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff },
    194 	{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }
    195 };
    196 
    197 struct wsdisplay_font lcg_font;
    198 static u_char *qf;
    199 static u_short *qf2;
    200 
    201 #define QCHAR(c) (c < lcg_font.firstchar ? 0 : \
    202 	(c >= (lcg_font.firstchar + lcg_font.numchars) ? 0 : c - lcg_font.firstchar))
    203 #define QFONT(c,line)	((lcg_font.stride == 2 ? \
    204 	qf2[QCHAR(c) * lcg_font.fontheight + line] : \
    205 	qf[QCHAR(c) * lcg_font.fontheight + line]))
    206 #define	LCG_ADDR(row, col, line, dot) \
    207 	lcgaddr[((col) * lcg_font.fontwidth) + ((row) * lcg_font.fontheight * lcg_xsize) + \
    208 	    (line) * lcg_xsize + dot]
    209 
    210 
    211 static int	lcg_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    212 static paddr_t	lcg_mmap(void *, void *, off_t, int);
    213 static int	lcg_alloc_screen(void *, const struct wsscreen_descr *,
    214 				      void **, int *, int *, long *);
    215 static void	lcg_free_screen(void *, void *);
    216 static int	lcg_show_screen(void *, void *, int,
    217 				     void (*) (void *, int, int), void *);
    218 static void	lcg_crsr_blink(void *);
    219 
    220 /* LCG HW accel functions */
    221 #ifndef LCG_NO_ACCEL
    222 static void	fifo_put(long data);
    223 static int	fifo_fill(int iterations);
    224 static u_char	fifo_counter = 0;
    225 
    226 static void	blkcpy(long source, long dest, int xdim, int ydim);
    227 static void	blkset(long dest, int xdim, int ydim, char color);
    228 static void	renderchar(long source, long dest, int xdim, int ydim, char fg, char bg);
    229 #endif /* LCG_NO_ACCEL */
    230 
    231 const struct wsdisplay_accessops lcg_accessops = {
    232 	lcg_ioctl,
    233 	lcg_mmap,
    234 	lcg_alloc_screen,
    235 	lcg_free_screen,
    236 	lcg_show_screen,
    237 	0 /* load_font */
    238 };
    239 
    240 /* TODO allocate ss_image dynamically for consoles beyond first one */
    241 struct	lcg_screen {
    242 	int	ss_curx;
    243 	int	ss_cury;
    244 	int	ss_cur_fg;
    245 	int	ss_cur_bg;
    246 	struct {
    247 		u_char	data;			/* Image character */
    248 		u_char	attr;			/* Attribute: 80/70/08/07 */
    249 	} ss_image[160 * 128];			/* allow for maximum possible cell matrix */
    250 };
    251 #define	LCG_ATTR_UNDERLINE	0x80
    252 #define	LCG_BG_MASK		0x70
    253 #define	LCG_ATTR_REVERSE	0x08
    254 #define	LCG_FG_MASK		0x07
    255 
    256 static	struct lcg_screen lcg_conscreen;
    257 static	struct lcg_screen *curscr;
    258 static	struct lcg_screen *savescr;
    259 
    260 static	callout_t lcg_cursor_ch;
    261 
    262 #ifndef LCG_NO_ACCEL
    263 void fifo_put(long data)
    264 {
    265 	fifo_counter &= 0x3;
    266 	fifoaddr[fifo_counter] = data;
    267 	fifo_counter++;
    268 }
    269 
    270 int fifo_fill(int iterations)
    271 {
    272 	long status;
    273 	int counter = 0;
    274 
    275 	while (fifo_counter % 4)
    276 		fifo_put(0);
    277 
    278 #ifdef LCG_SAFE
    279 	status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS);
    280 	while ((counter < iterations) && ((status & 0x80000000) == 0x80000000)) {
    281 		delay(1000);
    282 		status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS);
    283 		counter++;
    284 	}
    285 #endif
    286 
    287 	if (counter == 0)
    288 		return 0;
    289 	else
    290 		return 1;
    291 }
    292 
    293 void blkcpy(long source, long dest, int xdim, int ydim)
    294 {
    295 	int err;
    296 
    297 #ifdef LCG_SAFE
    298 	if ((source < LCG_FB_ADDR) || (source > LCG_FB_ADDR + lcg_fb_size)) {
    299 		printf("lcg: blkcpy: invalid source 0x%lx\n", source);
    300 		return;
    301 	}
    302 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
    303 		printf("lcg: blkcpy: invalid destination 0x%lx\n", dest);
    304 		return;
    305 	}
    306 #endif
    307 
    308 #ifdef LCG_SAFE
    309 	fifo_put(0x0c010000 | (cur_fg & 0xff));
    310 #endif
    311 	fifo_put(0x01020006);
    312 
    313 	fifo_put(0x06800000);
    314 	fifo_put(source);
    315 	fifo_put(lcg_xsize);
    316 
    317 	fifo_put(0x05800000);
    318 	fifo_put(dest);
    319 	fifo_put(lcg_xsize);
    320 
    321 	fifo_put(0x03400000);
    322 	fifo_put(0xff);
    323 
    324 	fifo_put(0x02000003);
    325 
    326 #ifdef LCG_SAFE
    327 	fifo_put(0x04c00000);
    328 	fifo_put(0);
    329 	fifo_put(lcg_xsize);
    330 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
    331 #endif
    332 
    333 	fifo_put(0x09c00000);
    334 	fifo_put(((ydim & 0xffff) << 16) | xdim);
    335 	fifo_put(0);
    336 	fifo_put(0);
    337 
    338 	err = fifo_fill(200);
    339 	if (err)
    340 		printf("lcg: AG still busy after 200 msec\n");
    341 }
    342 
    343 void blkset(long dest, int xdim, int ydim, char color)
    344 {
    345 	int err;
    346 
    347 #ifdef LCG_SAFE
    348 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
    349 		printf("lcg: blkset: invalid destination 0x%lx\n", dest);
    350 		return;
    351 	}
    352 #endif
    353 
    354 	fifo_put(0x0c010000 | (color & 0xff));
    355 
    356 	fifo_put(0x01000000);
    357 
    358 	fifo_put(0x05800000);
    359 	fifo_put(dest);
    360 	fifo_put(lcg_xsize);
    361 
    362 	fifo_put(0x03400000);
    363 	fifo_put(0xff);
    364 
    365 	fifo_put(0x02000003);
    366 
    367 #ifdef LCG_SAFE
    368 	fifo_put(0x04c00000);
    369 	fifo_put(0);
    370 	fifo_put(lcg_xsize);
    371 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
    372 #endif
    373 
    374 	fifo_put(0x09c00000);
    375 	fifo_put(((ydim & 0xffff) << 16) | xdim);
    376 	fifo_put(0);
    377 	fifo_put(0);
    378 
    379 	err = fifo_fill(200);
    380 	if (err)
    381 		printf("lcg: AG still busy after 200 msec\n");
    382 }
    383 
    384 void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg)
    385 {
    386 	int err;
    387 #ifdef LCG_SAFE
    388 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
    389 		printf("lcg: blkset: invalid destination 0x%lx\n", dest);
    390 		return;
    391 	}
    392 #endif
    393 
    394 	fifo_put(0x0c050000 | (bg & 0xff));
    395 	fifo_put(0x0c010000 | (fg & 0xff));
    396 
    397 	fifo_put(0x01030008);
    398 
    399 	fifo_put(0x06800000);
    400 	fifo_put(source);
    401 	//fifo_put(lcg_xsize);
    402 	fifo_put(lcg_font.stride);
    403 
    404 	fifo_put(0x05800000);
    405 	fifo_put(dest);
    406 	fifo_put(lcg_xsize);
    407 
    408 	fifo_put(0x03400000);
    409 	fifo_put(0xff);
    410 
    411 	fifo_put(0x02000003);
    412 
    413 #ifdef LCG_SAFE
    414 	fifo_put(0x04c00000);
    415 	fifo_put(0);
    416 	fifo_put(lcg_xsize);
    417 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
    418 #endif
    419 
    420 	fifo_put(0x09c00000);
    421 	fifo_put(((ydim & 0xffff) << 16) | (xdim & 0xffff));
    422 	fifo_put(0);
    423 	fifo_put(0);
    424 
    425 	err = fifo_fill(200);
    426 	if (err)
    427 		printf("lcg: AG still busy after 200 msec\n");
    428 }
    429 #endif /* LCG_NO_ACCEL */
    430 
    431 int
    432 lcg_match(struct device *parent, struct cfdata *match, void *aux)
    433 {
    434 	struct vsbus_softc *sc = device_private(parent);
    435 	struct vsbus_attach_args *va = aux;
    436 	volatile char * const ch = (char *)va->va_addr;
    437 
    438 	/*
    439 	 * Check the VAX board type. LCG can exist on two board types:
    440 	 * - KA46 (VAXstation 4000/60 or MicroVAX 3100/80)
    441 	 * - KA48 (VAXstation 4000 VLC or MicroVAX 3100/m{30,40}
    442 	 */
    443 	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
    444 		return 0;
    445 
    446 	/*
    447 	 * LCG supposedly only exists on VAXstations, not the MicroVAXen using
    448 	 * the same board type.
    449 	 *
    450 	 * These are "magic values", taken from vax/locore.c
    451 	 */
    452 	if ((vax_siedata & 0x3) != 2)
    453 		return 0;
    454 
    455 	*ch = 1;
    456 	if ((*ch & 1) == 0)
    457 		return 0;
    458 	*ch = 0;
    459 	if ((*ch & 1) != 0)
    460 		return 0;
    461 
    462 	/* XXX use vertical interrupt? */
    463 	sc->sc_mask = 0x04; /* XXX - should be generated */
    464 	scb_fake(0x120, 0x15);
    465 	return 20;
    466 }
    467 
    468 void
    469 lcg_attach(struct device *parent, struct device *self, void *aux)
    470 {
    471 	struct vsbus_attach_args *va = aux;
    472 	struct wsemuldisplaydev_attach_args aa;
    473 
    474 	printf("\n");
    475 	aa.console = lcgaddr != NULL;
    476 
    477 	lcg_init_common(self, va);
    478 
    479 	curscr = &lcg_conscreen;
    480 
    481 	aa.scrdata = &lcg_screenlist;
    482 	aa.accessops = &lcg_accessops;
    483 
    484 	/* enable software cursor */
    485 	callout_init(&lcg_cursor_ch, 0);
    486 	callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL);
    487 
    488 	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
    489 }
    490 
    491 static void
    492 lcg_crsr_blink(void *arg)
    493 {
    494 	int dot;
    495 
    496 	if (cur_on && curscr != NULL)
    497 		for (dot = 0; dot < lcg_font.fontwidth; dot++)
    498 			cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg;
    499 
    500 	callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL);
    501 }
    502 
    503 void
    504 lcg_cursor(void *id, int on, int row, int col)
    505 {
    506 	struct lcg_screen *ss = id;
    507 	int dot, attr;
    508 
    509 	attr = ss->ss_image[row * lcg_cols + col].attr;
    510 	if (ss == curscr) {
    511 		if (cursor != NULL) {
    512 			int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols +
    513 			    ss->ss_curx].data, lcg_font.fontheight - 1);
    514 			attr = ss->ss_image[ss->ss_cury * lcg_cols +
    515 			    ss->ss_curx].attr;
    516 
    517 			if (attr & LCG_ATTR_REVERSE) {
    518 				cur_bg = attr & LCG_FG_MASK;
    519 				cur_fg = (attr & LCG_BG_MASK) >> 4;
    520 			} else {
    521 				cur_fg = attr & LCG_FG_MASK;
    522 				cur_bg = (attr & LCG_BG_MASK) >> 4;
    523 			}
    524 			for (dot = 0; dot < lcg_font.fontwidth; dot++)
    525 				cursor[dot] =  (ch & (1 << dot)) ?
    526 				    cur_fg : cur_bg;
    527 		}
    528 
    529 		cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
    530 		cur_on = on;
    531 		if (attr & LCG_ATTR_REVERSE) {
    532 			cur_bg = attr & LCG_FG_MASK;
    533 			cur_fg = (attr & LCG_BG_MASK) >> 4;
    534 		} else {
    535 			cur_fg = attr & LCG_FG_MASK;
    536 			cur_bg = (attr & LCG_BG_MASK) >> 4;
    537 		}
    538 	}
    539 	ss->ss_curx = col;
    540 	ss->ss_cury = row;
    541 	if (attr & LCG_ATTR_REVERSE) {
    542 		ss->ss_cur_bg = attr & LCG_FG_MASK;
    543 		ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4;
    544 	} else {
    545 		ss->ss_cur_fg = attr & LCG_FG_MASK;
    546 		ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4;
    547 	}
    548 }
    549 
    550 int
    551 lcg_mapchar(void *id, int uni, unsigned int *index)
    552 {
    553 	if (uni < 256) {
    554 		*index = uni;
    555 		return (5);
    556 	}
    557 	*index = ' ';
    558 	return (0);
    559 }
    560 
    561 static void
    562 lcg_putchar(void *id, int row, int col, u_int c, long attr)
    563 {
    564 	struct lcg_screen *ss = id;
    565 	int i;
    566 	char dot_fg, dot_bg;
    567 
    568 	c &= 0xff;
    569 
    570 	ss->ss_image[row * lcg_cols + col].data = c;
    571 	ss->ss_image[row * lcg_cols + col].attr = attr;
    572 	if (ss != curscr)
    573 		return;
    574 
    575 	dot_fg = attr & LCG_FG_MASK;
    576 	dot_bg = (attr & LCG_BG_MASK) >> 4;
    577 	if (attr & LCG_ATTR_REVERSE) {
    578 		dot_fg = (attr & LCG_BG_MASK) >> 4;
    579 		dot_bg = attr & LCG_FG_MASK;
    580 	}
    581 
    582 #ifndef LCG_NO_ACCEL
    583 	renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size),
    584 		   LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth),
    585 		   lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg);
    586 #else
    587 	for (i = 0; i < lcg_font.fontheight; i++) {
    588 		unsigned char ch = QFONT(c,i);
    589 		for (int j = 0; j < lcg_font.fontwidth; j++) {
    590 			LCG_ADDR(row, col, i, j) = ((ch >> j) & 1) ? dot_fg : dot_bg;
    591 		}
    592 	}
    593 #endif /* LCG_NO_ACCEL */
    594 	if (attr & LCG_ATTR_UNDERLINE) {
    595 		char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
    596 		for (i = 0; i < lcg_font.fontwidth; i++)
    597 			p[i] = ~p[i];
    598 	}
    599 }
    600 
    601 
    602 
    603 /*
    604  * copies columns inside a row.
    605  */
    606 static void
    607 lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols)
    608 {
    609 	struct lcg_screen *ss = id;
    610 #ifdef LCG_NO_ACCEL
    611 	int i = 0;
    612 #endif
    613 
    614 	bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row *
    615 	    lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0]));
    616 	if (ss != curscr)
    617 		return;
    618 #ifdef LCG_NO_ACCEL
    619 	for (i = 0; i < lcg_font.fontheight; i++)
    620 		memcpy(&LCG_ADDR(row, dstcol, i, 0),
    621 		&LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth);
    622 
    623 #else
    624 	blkcpy(LCG_FB_ADDR + (row * lcg_onerow) + (srccol * lcg_font.fontwidth),
    625 	       LCG_FB_ADDR + (row * lcg_onerow) + (dstcol * lcg_font.fontwidth),
    626 	       (ncols * lcg_font.fontwidth), lcg_font.fontheight);
    627 #endif
    628 }
    629 
    630 /*
    631  * Erases a bunch of chars inside one row.
    632  */
    633 static void
    634 lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
    635 {
    636 	struct lcg_screen *ss = id;
    637 	int i;
    638 
    639 	bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0]));
    640 	for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i)
    641 		ss->ss_image[i].attr = fillattr;
    642 	if (ss != curscr)
    643 		return;
    644 #ifdef LCG_NO_ACCEL
    645 	for (i = 0; i < lcg_font.fontheight; i++)
    646                 memset(&LCG_ADDR(row, startcol, i, 0), 0, ncols * lcg_font.fontwidth);
    647 #else
    648 	blkset(LCG_FB_ADDR + (row * lcg_onerow) + (startcol * lcg_font.fontwidth),
    649 		(ncols * lcg_font.fontwidth), lcg_font.fontheight, (fillattr & LCG_BG_MASK) >> 4);
    650 #endif
    651 }
    652 
    653 static void
    654 lcg_copyrows(void *id, int srcrow, int dstrow, int nrows)
    655 {
    656 	struct lcg_screen *ss = id;
    657 
    658 	bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols],
    659 	    nrows * lcg_cols * sizeof(ss->ss_image[0]));
    660 	if (ss != curscr)
    661 		return;
    662 #ifdef LCG_NO_ACCEL
    663 	memcpy(&lcgaddr[dstrow * lcg_onerow],
    664             &lcgaddr[srcrow * lcg_onerow], nrows * lcg_onerow);
    665 #else
    666 	blkcpy(LCG_FB_ADDR + (srcrow * lcg_onerow), LCG_FB_ADDR + (dstrow * lcg_onerow),
    667 		(lcg_cols * lcg_font.fontwidth), (nrows * lcg_font.fontheight));
    668 #endif
    669 }
    670 
    671 static void
    672 lcg_eraserows(void *id, int startrow, int nrows, long fillattr)
    673 {
    674 	struct lcg_screen *ss = id;
    675 	int i;
    676 
    677 	bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols *
    678 	    sizeof(ss->ss_image[0]));
    679 	for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i)
    680 		ss->ss_image[i].attr = fillattr;
    681 	if (ss != curscr)
    682 		return;
    683 #ifdef LCG_NO_ACCEL
    684 	memset(&lcgaddr[startrow * lcg_onerow], 0, nrows * lcg_onerow);
    685 #else
    686 	blkset(LCG_FB_ADDR + (startrow * lcg_onerow), (lcg_cols * lcg_font.fontwidth),
    687 		(nrows * lcg_font.fontheight), (fillattr & LCG_BG_MASK) >> 4);
    688 #endif
    689 }
    690 
    691 static int
    692 lcg_allocattr(void *id, int fg, int bg, int flags, long *attrp)
    693 {
    694 	long myattr;
    695 
    696 	if (flags & WSATTR_WSCOLORS)
    697 		myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK);
    698 	else
    699 		myattr = WSCOL_WHITE << 4;	/* XXXX */
    700 	if (flags & WSATTR_REVERSE)
    701 		myattr |= LCG_ATTR_REVERSE;
    702 	if (flags & WSATTR_UNDERLINE)
    703 		myattr |= LCG_ATTR_UNDERLINE;
    704 	*attrp = myattr;
    705 	return 0;
    706 }
    707 
    708 static int
    709 lcg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    710 {
    711 	struct wsdisplay_fbinfo *fb = (void *)data;
    712 	int i;
    713 
    714 	switch (cmd) {
    715 	case WSDISPLAYIO_GTYPE:
    716 		*(u_int *)data = WSDISPLAY_TYPE_LCG;
    717 		break;
    718 
    719 	case WSDISPLAYIO_GINFO:
    720 		fb->height = lcg_ysize;
    721 		fb->width = lcg_xsize;
    722 		fb->depth = lcg_depth;
    723 		fb->cmsize = 1 << lcg_depth;
    724 		break;
    725 
    726 	case WSDISPLAYIO_LINEBYTES:
    727 		*(u_int *)data = lcg_xsize;
    728 		break;
    729 
    730 	case WSDISPLAYIO_GETCMAP:
    731 		return lcg_get_cmap((struct wsdisplay_cmap *)data);
    732 
    733 	case WSDISPLAYIO_PUTCMAP:
    734 		return lcg_set_cmap((struct wsdisplay_cmap *)data);
    735 
    736 	case WSDISPLAYIO_GMODE:
    737 		return EPASSTHROUGH;
    738 
    739 	case WSDISPLAYIO_SMODE:
    740 		/* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */
    741 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) {
    742 			/* FIXME: if this is meant to reset palette LUT reload has to be triggered too */
    743 			bzero(lutaddr, LCG_LUT_SIZE);
    744 			for (i = 0; i < 8; ++i) {
    745 				lcg_cmap.r[i] = lcg_default_cmap.r[i];
    746 				lcg_cmap.g[i] = lcg_default_cmap.g[i];
    747 				lcg_cmap.b[i] = lcg_default_cmap.b[i];
    748 				lutaddr[i * 8 + 1] = i;
    749 				lutaddr[i * 8 + 2] = 1;
    750 				lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
    751 				lutaddr[i * 8 + 4] = 1;
    752 				lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
    753 				lutaddr[i * 8 + 6] = 1;
    754 				lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
    755 			}
    756 			if (savescr != NULL)
    757 				lcg_show_screen(NULL, savescr, 0, NULL, NULL);
    758 			savescr = NULL;
    759 		} else {		/* WSDISPLAYIO_MODE_MAPPED */
    760 			savescr = curscr;
    761 			curscr = NULL;
    762 			/* clear screen? */
    763 		}
    764 
    765 		return EPASSTHROUGH;
    766 #if 0
    767 	case WSDISPLAYIO_SVIDEO:
    768 		if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) {
    769 			curcmd = curc;
    770 		} else {
    771 			curc = curcmd;
    772 			curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA);
    773 			curcmd |= CUR_CMD_FOPB;
    774 		}
    775 		WRITECUR(CUR_CMD, curcmd);
    776 		break;
    777 
    778 	case WSDISPLAYIO_GVIDEO:
    779 		*(u_int *)data = (curcmd & CUR_CMD_FOPB ?
    780 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
    781 		break;
    782 
    783 #endif
    784 	default:
    785 		return EPASSTHROUGH;
    786 	}
    787 	return 0;
    788 }
    789 
    790 static paddr_t
    791 lcg_mmap(void *v, void *vs, off_t offset, int prot)
    792 {
    793 	if (offset >= lcg_fb_size || offset < 0)
    794 		return -1;
    795 	return (LCG_FB_ADDR + offset) >> PGSHIFT;
    796 }
    797 
    798 int
    799 lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    800     int *curxp, int *curyp, long *defattrp)
    801 {
    802 	int i;
    803 	struct lcg_screen *ss;
    804 
    805 	*cookiep = kmem_alloc(sizeof(struct lcg_screen), KM_SLEEP);
    806 	bzero(*cookiep, sizeof(struct lcg_screen));
    807 	*curxp = *curyp = 0;
    808 	*defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
    809 	ss = *cookiep;
    810 	for (i = 0; i < lcg_cols * lcg_rows; ++i)
    811 		ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
    812 	return 0;
    813 }
    814 
    815 void
    816 lcg_free_screen(void *v, void *cookie)
    817 {
    818 }
    819 
    820 int
    821 lcg_show_screen(void *v, void *cookie, int waitok,
    822     void (*cb)(void *, int, int), void *cbarg)
    823 {
    824 	struct lcg_screen *ss = cookie;
    825 	int row, col, dot_fg, dot_bg, j, attr;
    826 #ifdef LCG_NO_ACCEL
    827 	int iter, jter;
    828 	unsigned char ch;
    829 #endif
    830 
    831 	if (ss == curscr)
    832 		return (0);
    833 #ifdef LCG_NO_ACCEL
    834 	memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize);
    835 #endif
    836 
    837 	for (row = 0; row < lcg_rows; row++)
    838 		for (col = 0; col < lcg_cols; col++) {
    839 			attr = ss->ss_image[row * lcg_cols + col].attr;
    840 			if (attr & LCG_ATTR_REVERSE) {
    841 				dot_fg = (attr & LCG_BG_MASK) >> 4;
    842 				dot_bg = attr & LCG_FG_MASK;
    843 			} else {
    844 				dot_fg = attr & LCG_FG_MASK;
    845 				dot_bg = (attr & LCG_BG_MASK) >> 4;
    846 			}
    847 			u_char c = ss->ss_image[row * lcg_cols + col].data;
    848 
    849 			if (c < 32)
    850 				c = 32;
    851 #ifndef LCG_NO_ACCEL
    852 			renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size),
    853 				   LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth),
    854 				   lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg);
    855 #else
    856 			for (iter = 0; iter < lcg_font.fontheight; iter++) {
    857 				ch = QFONT(c,iter);
    858 				for (jter = 0; jter < lcg_font.fontwidth; jter++) {
    859 					LCG_ADDR(row, col, iter, jter) = ((ch >> jter) & 1) ? dot_fg : dot_bg;
    860 				}
    861 			}
    862 #endif
    863 			if (attr & LCG_ATTR_UNDERLINE)
    864 				for (j = 0; j < lcg_font.fontwidth; j++)
    865 					LCG_ADDR(row, col,
    866 					    lcg_font.fontheight - 1, j) = dot_fg;
    867 		}
    868 
    869 	cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) +
    870 		((lcg_font.fontheight - 1) * lcg_xsize) +
    871 			(ss->ss_curx * lcg_font.fontwidth)];
    872 	cur_fg = ss->ss_cur_fg;
    873 	cur_bg = ss->ss_cur_bg;
    874 
    875 	curscr = ss;
    876 	return (0);
    877 }
    878 
    879 static int
    880 lcg_get_cmap(struct wsdisplay_cmap *p)
    881 {
    882 	u_int index = p->index, count = p->count;
    883 	int error;
    884 
    885 	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
    886 		return (EINVAL);
    887 
    888 	error = copyout(&lcg_cmap.r[index], p->red, count);
    889 	if (error)
    890 		return error;
    891 	error = copyout(&lcg_cmap.g[index], p->green, count);
    892 	if (error)
    893 		return error;
    894 	error = copyout(&lcg_cmap.b[index], p->blue, count);
    895 	return error;
    896 }
    897 
    898 static int
    899 lcg_set_cmap(struct wsdisplay_cmap *p)
    900 {
    901 	u_int index = p->index, count = p->count;
    902 	int error, s;
    903 
    904 	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
    905 		return (EINVAL);
    906 
    907 	error = copyin(p->red, &lcg_cmap.r[index], count);
    908 	if (error)
    909 		return error;
    910 	error = copyin(p->green, &lcg_cmap.g[index], count);
    911 	if (error)
    912 		return error;
    913 	error = copyin(p->blue, &lcg_cmap.b[index], count);
    914 	if (error)
    915 		return error;
    916 
    917 	s = spltty();
    918 	/* FIXME: if this is meant to set palette LUT reload has to be triggered too */
    919 	while (count-- > 0) {
    920 		lutaddr[index * 8 + 0] = 0;
    921 		lutaddr[index * 8 + 1] = index;
    922 		lutaddr[index * 8 + 2] = 1;
    923 		lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7);
    924 		lutaddr[index * 8 + 4] = 1;
    925 		lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7);
    926 		lutaddr[index * 8 + 6] = 1;
    927 		lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7);
    928 		++index;
    929 	}
    930 	splx(s);
    931 	return (0);
    932 }
    933 
    934 cons_decl(lcg);
    935 
    936 void
    937 lcgcninit(struct consdev *cndev)
    938 {
    939 	int i;
    940 	/* Clear screen */
    941 	memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize);
    942 
    943 	curscr = &lcg_conscreen;
    944 	for (i = 0; i < lcg_cols * lcg_rows; ++i)
    945 		lcg_conscreen.ss_image[i].attr =
    946 		    (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
    947 	wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0,
    948 	    (LCG_BG_COLOR << 4) | LCG_FG_COLOR);
    949 	cn_tab->cn_pri = CN_INTERNAL;
    950 
    951 
    952 #if NDZKBD > 0
    953 	dzkbd_cnattach(0); /* Connect keyboard and screen together */
    954 #endif
    955 }
    956 
    957 /*
    958  * Called very early to setup the glass tty as console.
    959  * Because it's called before the VM system is inited, virtual memory
    960  * for the framebuffer can be stolen directly without disturbing anything.
    961  */
    962 void
    963 lcgcnprobe(struct consdev *cndev)
    964 {
    965 	extern const struct cdevsw wsdisplay_cdevsw;
    966 
    967 	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
    968 		return; /* Only for VS 4000/60 and VLC */
    969 
    970 	if ((vax_siedata & 0x3) != 2)
    971 		return; /* VAXstation only */
    972 
    973 	if (vax_confdata & 0x100)
    974 		return; /* Diagnostic console */
    975 
    976 	lcg_init_common(NULL, NULL);
    977 
    978 	/* Set up default LUT */
    979 
    980 	cndev->cn_pri = CN_INTERNAL;
    981 	cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
    982 }
    983 
    984 void
    985 lcg_init_common(struct device *self, struct vsbus_attach_args *va)
    986 {
    987 	u_int magic, *lcg_config;
    988 	int i;
    989 	extern vaddr_t virtual_avail;
    990 	long video_conf;
    991 	int cookie;
    992 	struct wsdisplay_font *wf;
    993 
    994 	struct lcg_softc *sc = device_private(self);
    995 	bus_dma_segment_t seg;
    996 	int rseg, err;
    997 	void *fifo_mem_vaddr;
    998 #ifndef LCG_NO_ACCEL
    999 	u_char line;
   1000 	u_int ch, temp;
   1001 #endif
   1002 
   1003 	if (regaddr != NULL)
   1004 		return;
   1005 
   1006 	/* map LCG registers first */
   1007 	if (self != NULL) {
   1008 		regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
   1009 		if (regaddr == 0) {
   1010 			device_printf(self,
   1011 			    "Couldn't allocate register memory.\n");
   1012 			return;
   1013 		}
   1014 	} else {
   1015 		regaddr = (long*)virtual_avail;
   1016 		virtual_avail += LCG_REG_SIZE;
   1017 		ioaccess((vaddr_t)regaddr, LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
   1018 	}
   1019 
   1020 	/*
   1021 	 * v = *0x200f0010 & VLC ? 0x07 : 0xf0;
   1022 	 * switch(v) {
   1023 	 * 0x05: 1280x1024
   1024 	 * 0x06: conf & 0x80 ? 1024x768 : 640x480
   1025 	 * 0x07: conf & 0x80 ? 1024x768 ? 1024x864
   1026 	 * 0x20: 1024x864
   1027 	 * 0x40: 1024x768
   1028 	 * 0x60: 1024x864
   1029 	 * 0x80: 1280x1024 4BPN
   1030 	 * 0x90: 1280x1024 8BPN
   1031 	 * 0xb0: 1280x1024 8BPN 2HD
   1032 	 */
   1033 	if (self != NULL) {
   1034 		lcg_config = (u_int *)vax_map_physmem(LCG_CONFIG, 1);
   1035 	} else {
   1036 		lcg_config = (u_int *)virtual_avail;
   1037 		ioaccess((vaddr_t)lcg_config, LCG_CONFIG, 1);
   1038 	}
   1039 	magic = *lcg_config & (vax_boardtype == VAX_BTYP_46 ? 0xf0 : 0x07);
   1040 	if (self != NULL) {
   1041 		vax_unmap_physmem((vaddr_t)lcg_config, 1);
   1042 	} else {
   1043 		iounaccess((vaddr_t)lcg_config, 1);
   1044 	}
   1045 	lcg_depth = 8;
   1046 	switch(magic) {
   1047 	case 0x80:		/* KA46 HR 1280x1024 4BPLN */
   1048 		lcg_depth = 4;
   1049 	case 0x05:		/* KA48 HR 1280x1024 8BPLN */
   1050 	case 0x90:		/* KA46 HR 1280x1024 8BPLN */
   1051 	case 0xb0:		/* KA46 HR 1280x1024 8BPLN 2HD */
   1052 		lcg_xsize = 1280;
   1053 		lcg_ysize = 1024;
   1054 		break;
   1055 	case 0x06:		/* KA48 1024x768 or 640x480 */
   1056 		if (vax_confdata & 0x80) {
   1057 			lcg_xsize = 1024;
   1058 			lcg_ysize = 768;
   1059 		} else {
   1060 			lcg_xsize = 640;
   1061 			lcg_ysize = 480;
   1062 		}
   1063 		break;
   1064 	case 0x07:		/* KA48 1024x768 or 1024x864 */
   1065 		lcg_xsize = 1024;
   1066 		lcg_ysize = (vax_confdata & 0x80) ? 768 : 864;
   1067 		break;
   1068 	case 0x20:		/* KA46 1024x864 */
   1069 	case 0x60:		/* KA46 1024x864 */
   1070 		lcg_xsize = 1024;
   1071 		lcg_ysize = 864;
   1072 		break;
   1073 	case 0x40:		/* KA46 1024x768 */
   1074 		lcg_xsize = 1024;
   1075 		lcg_ysize = 768;
   1076 		break;
   1077 	default:
   1078 		panic("LCG model not supported");
   1079 	}
   1080 	if (self != NULL)
   1081 		aprint_normal_dev(self,
   1082 		    "framebuffer size %dx%d, depth %d (magic 0x%x)\n",
   1083 		    lcg_xsize, lcg_ysize, lcg_depth, magic);
   1084 
   1085 	wsfont_init();
   1086 	cookie = wsfont_find(NULL, 12, 22, 0, WSDISPLAY_FONTORDER_R2L,
   1087 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
   1088 	if (cookie == -1)
   1089 		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0,
   1090 				WSFONT_FIND_BITMAP);
   1091 	if (cookie == -1)
   1092 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
   1093 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
   1094 	if (cookie == -1 || wsfont_lock(cookie, &wf))
   1095 		panic("lcg_common_init: can't load console font");
   1096 	lcg_font = *wf;
   1097 	lcg_cols = lcg_xsize / lcg_font.fontwidth;
   1098 	lcg_rows = lcg_ysize / lcg_font.fontheight;
   1099 	if (self != NULL) {
   1100 		aprint_normal_dev(self, "using font %s (%dx%d), ",
   1101 		    lcg_font.name,
   1102 		    lcg_font.fontwidth, lcg_font.fontheight);
   1103 		aprint_normal("console size: %dx%d\n", lcg_cols, lcg_rows);
   1104 	}
   1105 	lcg_onerow = lcg_xsize * lcg_font.fontheight;
   1106 	lcg_fb_size = lcg_xsize * lcg_ysize;
   1107 	lcg_stdscreen.ncols = lcg_cols;
   1108 	lcg_stdscreen.nrows = lcg_rows;
   1109 	lcg_stdscreen.fontwidth = lcg_font.fontwidth;
   1110 	lcg_stdscreen.fontheight = lcg_font.fontheight;
   1111 	lcg_glyph_size = lcg_font.stride * lcg_font.fontheight;
   1112 	snprintf(lcg_stdscreen_name, sizeof(lcg_stdscreen_name), "%dx%d", lcg_cols, lcg_rows);
   1113 	qf = lcg_font.data;
   1114 	qf2 = (u_short *)lcg_font.data;
   1115 
   1116 	if (self != NULL) {
   1117 		lcgaddr = (void *)vax_map_physmem(va->va_paddr,
   1118 					((lcg_fb_size + LCG_FONT_STORAGE_SIZE)/VAX_NBPG));
   1119 		if (lcgaddr == 0) {
   1120 			device_printf(self,
   1121 			    "unable to allocate framebuffer memory.\n");
   1122 			return;
   1123 		}
   1124 #ifndef LCG_NO_ACCEL
   1125 		fontaddr = lcgaddr + lcg_fb_size;
   1126 
   1127 		/* copy font bitmaps */
   1128 		for (ch = 0; ch < 256; ch++)
   1129 			for (line = 0; line < lcg_font.fontheight; line++) {
   1130 				temp = QFONT(ch, line);
   1131 				if (lcg_font.stride == 1)
   1132 					fontaddr[(ch * lcg_font.fontheight) + line] = temp;
   1133 				else {
   1134 					/* stride == 2 */
   1135 					fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line] = temp & 0xff;
   1136 					fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line + 1] = (temp >> 16) & 0xff;
   1137 				}
   1138 			}
   1139 #endif
   1140 
   1141 		lutaddr = (void *)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
   1142 		if (lutaddr == 0) {
   1143 			device_printf(self,
   1144 			    "unable to allocate LUT memory.\n");
   1145 			return;
   1146 		}
   1147 		fifoaddr = (long*)vax_map_physmem(LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG));
   1148 		if (regaddr == 0) {
   1149 			device_printf(self, "unable to map FIFO window\n");
   1150 			return;
   1151 		}
   1152 
   1153 		/* allocate contiguous physical memory block for FIFO */
   1154 		err = bus_dmamem_alloc(va->va_dmat, LCG_FIFO_SIZE,
   1155 			LCG_FIFO_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
   1156 		if (err) {
   1157 			device_printf(self,
   1158 			    "unable to allocate FIFO memory block, err = %d\n",
   1159 			    err);
   1160 			return;
   1161 		}
   1162 
   1163 		err = bus_dmamem_map(va->va_dmat, &seg, rseg, LCG_FIFO_SIZE,
   1164 			&fifo_mem_vaddr, BUS_DMA_NOWAIT);
   1165 		if (err) {
   1166 			device_printf(self,
   1167 			    "unable to map FIFO memory block, err = %d\n",
   1168 			    err);
   1169 			bus_dmamem_free(va->va_dmat, &seg, rseg);
   1170 			return;
   1171 		}
   1172 
   1173 		err = bus_dmamap_create(va->va_dmat, LCG_FIFO_SIZE, rseg,
   1174 			LCG_FIFO_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dm);
   1175 		if (err) {
   1176 			device_printf(self,
   1177 			    "unable to create DMA map, err = %d\n",
   1178 			    err);
   1179 			bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE);
   1180 			bus_dmamem_free(va->va_dmat, &seg, rseg);
   1181 			return;
   1182 		}
   1183 
   1184 		err = bus_dmamap_load(va->va_dmat, sc->sc_dm, fifo_mem_vaddr,
   1185 			LCG_FIFO_SIZE, NULL, BUS_DMA_NOWAIT);
   1186 		if (err) {
   1187 			device_printf(self,
   1188 			    "unable to load DMA map, err = %d\n",
   1189 			    err);
   1190 			bus_dmamap_destroy(va->va_dmat, sc->sc_dm);
   1191 			bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE);
   1192 			bus_dmamem_free(va->va_dmat, &seg, rseg);
   1193 			return;
   1194 		}
   1195 
   1196 		/* initialize LCG hardware */
   1197 		LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0xd8000000; /* gfx reset, FIFO and AG enable */
   1198 //		LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = (((LCG_FB_ADDR + lcg_fb_size) & 0xffff0000) | (LCG_FB_ADDR >> 16));
   1199 		LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = 0xffff0000;
   1200 		LCG_REG(LCG_REG_FIFO_BASE) = sc->sc_dm->dm_segs[0].ds_addr;
   1201 		LCG_REG(LCG_REG_FIFO_BASE2) = sc->sc_dm->dm_segs[0].ds_addr;
   1202 		LCG_REG(LCG_REG_FIFO_MASKS) = 0xffff;
   1203 		LCG_REG(LCG_REG_FIFO_SAVE_HEAD_OFFSET) = sc->sc_dm->dm_segs[0].ds_addr;
   1204 //		LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0;
   1205 //		LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0x50000000; /* FIFO and AG enable */
   1206 		LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0xffffffff;
   1207 		LCG_REG(LCG_REG_GRAPHICS_INT_SET_ENABLE) = 0;
   1208 		LCG_REG(LCG_REG_GRAPHICS_INT_CLR_ENABLE) = 0xffffffff;
   1209 		LCG_REG(LCG_REG_LCG_GO) = 3; /* FIFO and AG go */
   1210 //		LCG_REG(LCG_REG_BREAKPT_ADDRESS) = 0x2fffffff;
   1211 
   1212 	} else {
   1213 		lcgaddr = (void *)virtual_avail;
   1214 		virtual_avail += lcg_fb_size + LCG_FONT_STORAGE_SIZE;
   1215 		ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG));
   1216 
   1217 		lutaddr = (void *)virtual_avail;
   1218 		virtual_avail += LCG_LUT_SIZE;
   1219 		ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
   1220 
   1221 		fifoaddr = (long*)virtual_avail;
   1222 		virtual_avail += LCG_FIFO_WIN_SIZE;
   1223 		ioaccess((vaddr_t)fifoaddr, LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG));
   1224 	}
   1225 
   1226 	bzero(lutaddr, LCG_LUT_SIZE);
   1227 	for (i = 0; i < 8; ++i) {
   1228 		lcg_cmap.r[i] = lcg_default_cmap.r[i];
   1229 		lcg_cmap.g[i] = lcg_default_cmap.g[i];
   1230 		lcg_cmap.b[i] = lcg_default_cmap.b[i];
   1231 		lutaddr[i * 8 + 1] = i;
   1232 		lutaddr[i * 8 + 2] = 1;
   1233 		lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
   1234 		lutaddr[i * 8 + 4] = 1;
   1235 		lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
   1236 		lutaddr[i * 8 + 6] = 1;
   1237 		lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
   1238 	}
   1239 
   1240 	/*
   1241 	 * 0xf100165b 4000/60
   1242 	 * 1111 0001 0000 0000 0001 0110 0101 1011
   1243 	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
   1244 	 * 3322 2222 2222 1111 1111 11
   1245 	 * 1098 7654 3210 9876 5432 1098 7654 3210
   1246 	 *
   1247  	 * 0xf1001d7b 4000/VLC
   1248 	 * 1111 0001 0000 0000 0001 1101 0111 1011
   1249 	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
   1250 	 * 3322 2222 2222 1111 1111 11
   1251 	 * 1098 7654 3210 9876 5432 1098 7654 3210
   1252 	 *
   1253 	 * 31-30     11 Vertical state
   1254 	 * 29-38     11 Horizontal state
   1255 	 * 27-26     00
   1256 	 * 25         0 console LUT select
   1257 	 * 24         1 control LUT select
   1258 	 * 23         0
   1259 	 * 22         0 cursor active
   1260 	 * 21-16 000000
   1261 	 * 15         0 video subsystem reset
   1262 	 * 14         0
   1263 	 * 13         0 LUT load size 2KB
   1264 	 * 12         1 enable H sync
   1265 	 * 11         0 Full LUT load		 1
   1266 	 * 10         1 video clock select
   1267 	 *  9- 8     10 memory refresh rate	01
   1268 	 *  7- 6     01 video refresh rate
   1269 	 *  5         0 load select		 1
   1270 	 *  4         1 read cursor output
   1271 	 *  3         1 LUT load enable
   1272 	 *  2         0 cursor enable
   1273 	 *  1         1 video enable
   1274 	 *  0         1 refresh clock enable
   1275 	 */
   1276 	/* prepare video_config reg for LUT reload */
   1277 	video_conf
   1278 		 = (3 << 30) /* vertical state */
   1279 		 | (3 << 28) /* horizontal state */
   1280 		 | (0 << 26) /* unused */
   1281 		 | (0 << 25) /* console LUT select */
   1282 		 | (0 << 24) /* control LUT select */
   1283 		 | (0 << 23) /* unused */
   1284 		 | (0 << 22) /* cursor active */
   1285 		 | (0 << 16) /* current cursor scanline showing */
   1286 		 | (0 << 15) /* video subsystem reset */
   1287 		 | (0 << 14) /* unused */
   1288 		 | (1 << 13) /* LUT load size 2 KB */
   1289 		 | (1 << 12) /* enable horizontal sync */
   1290 		 | (1 << 10) /* video clock select */
   1291 		 | (1 << 6) /* video refresh select */
   1292 		 | (1 << 4) /* read cursor output */
   1293 		 | (1 << 3) /* LUT load enable */
   1294 		 | (0 << 2) /* cursor enable */
   1295 		 | (1 << 1) /* video enable */
   1296 		 | (1 << 0); /* refresh clock enable */
   1297 	/* FIXME needs updating for all supported models */
   1298 	if (lcg_xsize == 1280) {		/* 4000/60 HR 4PLN */
   1299 		video_conf |= (0 << 11); /* split LUT load */
   1300 		video_conf |= (2 << 8); /* memory refresh select */
   1301 		video_conf |= (0 << 5); /* split shift register load */
   1302 	} else {				/* 4000/VLC LR 8PLN */
   1303 		video_conf |= (1 << 11); /* Full LUT load */
   1304 		video_conf |= (1 << 8); /* memory refresh select */
   1305 		video_conf |= (1 << 5); /* split shift register load */
   1306 	}
   1307 
   1308 	LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf;
   1309 	/* vital !!! */
   1310 	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1;
   1311 	LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET;
   1312 
   1313 	delay(1000);
   1314 	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0;
   1315 
   1316 #ifdef LCG_DEBUG
   1317 	if (self != NULL)
   1318 		device_printf(self, "video config register set 0x%08lx\n",
   1319 		    video_conf);
   1320 #endif
   1321 }
   1322