xref: /netbsd-src/sys/arch/vax/vsa/lcg.c (revision 2b6fd3cd1580e736a5e08cec71e8d991ea819a12)
1*2b6fd3cdSjakllsch /*	$NetBSD: lcg.c,v 1.11 2022/12/10 19:50:43 jakllsch Exp $ */
27e580c6eSjklos /*
37e580c6eSjklos  * LCG accelerated framebuffer driver
47e580c6eSjklos  * Copyright (c) 2003, 2004 Blaz Antonic
57e580c6eSjklos  * All rights reserved.
67e580c6eSjklos  *
77e580c6eSjklos  * Redistribution and use in source and binary forms, with or without
87e580c6eSjklos  * modification, are permitted provided that the following conditions
97e580c6eSjklos  * are met:
107e580c6eSjklos  * 1. Redistributions of source code must retain the above copyright
117e580c6eSjklos  *    notice, this list of conditions and the following disclaimer.
127e580c6eSjklos  * 2. Redistributions in binary form must reproduce the above copyright
137e580c6eSjklos  *    notice, this list of conditions and the following disclaimer in the
147e580c6eSjklos  *    documentation and/or other materials provided with the distribution.
157e580c6eSjklos  * 3. All advertising materials mentioning features or use of this software
167e580c6eSjklos  *    must display the abovementioned copyrights
177e580c6eSjklos  * 4. The name of the author may not be used to endorse or promote products
187e580c6eSjklos  *    derived from this software without specific prior written permission
197e580c6eSjklos  *
207e580c6eSjklos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
217e580c6eSjklos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
227e580c6eSjklos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
237e580c6eSjklos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
247e580c6eSjklos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
257e580c6eSjklos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
267e580c6eSjklos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
277e580c6eSjklos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
287e580c6eSjklos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
297e580c6eSjklos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
307e580c6eSjklos  */
317e580c6eSjklos /*
327e580c6eSjklos  * Resurrection and dumb framebuffer mode by Björn Johannesson
337e580c6eSjklos  * rherdware@yahoo.com in December 2014
347e580c6eSjklos  */
357e580c6eSjklos 
367e580c6eSjklos #include <sys/cdefs.h>
37*2b6fd3cdSjakllsch __KERNEL_RCSID(0, "$NetBSD: lcg.c,v 1.11 2022/12/10 19:50:43 jakllsch Exp $");
387e580c6eSjklos 
397e580c6eSjklos #define LCG_NO_ACCEL
407e580c6eSjklos 
417e580c6eSjklos #include <sys/param.h>
427e580c6eSjklos #include <sys/device.h>
437e580c6eSjklos #include <sys/systm.h>
447e580c6eSjklos #include <sys/callout.h>
457e580c6eSjklos #include <sys/time.h>
4674ee8752Sthorpej #include <sys/kmem.h>
477e580c6eSjklos #include <sys/conf.h>
487e580c6eSjklos #include <sys/kernel.h>
497e580c6eSjklos #include <sys/systm.h>
507e580c6eSjklos 
517e580c6eSjklos #include <machine/vsbus.h>
527e580c6eSjklos #include <machine/sid.h>
537e580c6eSjklos #include <machine/cpu.h>
547e580c6eSjklos #include <machine/lcgreg.h>
557e580c6eSjklos 
567e580c6eSjklos #include <dev/cons.h>
577e580c6eSjklos 
587e580c6eSjklos #include <dev/dec/dzreg.h>
597e580c6eSjklos #include <dev/dec/dzvar.h>
607e580c6eSjklos #include <dev/dec/dzkbdvar.h>
617e580c6eSjklos 
627e580c6eSjklos #include <dev/wscons/wsdisplayvar.h>
637e580c6eSjklos #include <dev/wscons/wsconsio.h>
647e580c6eSjklos #include <dev/wscons/wscons_callbacks.h>
657e580c6eSjklos #include <dev/wsfont/wsfont.h>
667e580c6eSjklos 
677e580c6eSjklos #include "machine/scb.h"
687e580c6eSjklos 
697e580c6eSjklos #include "dzkbd.h"
707e580c6eSjklos 
717e580c6eSjklos /* Screen hardware defs */
727e580c6eSjklos 
737e580c6eSjklos #define	LCG_FB_ADDR		0x21801000	/* Frame buffer */
747e580c6eSjklos 
757e580c6eSjklos /* FIFO defines */
767e580c6eSjklos #define LCG_FIFO_SIZE		0x10000	/* 64 KB */
777e580c6eSjklos #define LCG_FIFO_WIN_ADDR	0x20180000
787e580c6eSjklos #define LCG_FIFO_WIN_SIZE	VAX_NBPG
797e580c6eSjklos #define LCG_FIFO_ALIGN		0x10000
807e580c6eSjklos 
817e580c6eSjklos /* font rendering defines */
827e580c6eSjklos #define LCG_FONT_ADDR		(LCG_FB_ADDR + lcg_fb_size)
8332cded6cSdholland #define LCG_FONT_STORAGE_SIZE	0x40000	/* 16 KB, enough to accommodate 16x32 font bitmaps */
847e580c6eSjklos 
857e580c6eSjklos /* register space defines */
867e580c6eSjklos #define LCG_REG_ADDR	0x20100000	/* LCG registers */
877e580c6eSjklos #define LCG_REG_SIZE	0x4000		/* 16384 bytes */
887e580c6eSjklos #define LCG_REG(reg) regaddr[(reg / 4)]
897e580c6eSjklos 
907e580c6eSjklos /* LUT defines */
917e580c6eSjklos #define LCG_LUT_ADDR	0x21800800	/* LUT right before onscreen FB */
927e580c6eSjklos #define LCG_LUT_OFFSET	0x00000800
937e580c6eSjklos #define LCG_LUT_SIZE	0x800		/* 2048 bytes */
947e580c6eSjklos 
957e580c6eSjklos #define	LCG_BG_COLOR	WSCOL_BLACK
967e580c6eSjklos #define	LCG_FG_COLOR	WSCOL_WHITE
977e580c6eSjklos 
987e580c6eSjklos #define	LCG_CONFIG	0x200f0010	/* LCG model information */
997e580c6eSjklos 
1007e580c6eSjklos /* implement sanity checks at certain points to ensure safer operation */
1017e580c6eSjklos #define LCG_SAFE
1027e580c6eSjklos //#define LCG_DEBUG
1037e580c6eSjklos 
1047e580c6eSjklos static	int lcg_match(struct device *, struct cfdata *, void *);
1057e580c6eSjklos static	void lcg_attach(struct device *, struct device *, void *);
1067e580c6eSjklos 
1077e580c6eSjklos struct	lcg_softc {
1087e580c6eSjklos 	bus_dmamap_t sc_dm;
1097e580c6eSjklos };
1107e580c6eSjklos 
1117e580c6eSjklos CFATTACH_DECL_NEW(lcg, sizeof(struct lcg_softc),
1127e580c6eSjklos     lcg_match, lcg_attach, NULL, NULL);
1137e580c6eSjklos 
1147e580c6eSjklos static void	lcg_cursor(void *, int, int, int);
1157e580c6eSjklos static int	lcg_mapchar(void *, int, unsigned int *);
1167e580c6eSjklos static void	lcg_putchar(void *, int, int, u_int, long);
1177e580c6eSjklos static void	lcg_copycols(void *, int, int, int,int);
1187e580c6eSjklos static void	lcg_erasecols(void *, int, int, int, long);
1197e580c6eSjklos static void	lcg_copyrows(void *, int, int, int);
1207e580c6eSjklos static void	lcg_eraserows(void *, int, int, long);
1217e580c6eSjklos static int	lcg_allocattr(void *, int, int, int, long *);
1227e580c6eSjklos static int	lcg_get_cmap(struct wsdisplay_cmap *);
1237e580c6eSjklos static int	lcg_set_cmap(struct wsdisplay_cmap *);
1247e580c6eSjklos static void	lcg_init_common(struct device *, struct vsbus_attach_args *);
1257e580c6eSjklos 
1267e580c6eSjklos const struct wsdisplay_emulops lcg_emulops = {
1277e580c6eSjklos 	lcg_cursor,
1287e580c6eSjklos 	lcg_mapchar,
1297e580c6eSjklos 	lcg_putchar,
1307e580c6eSjklos 	lcg_copycols,
1317e580c6eSjklos 	lcg_erasecols,
1327e580c6eSjklos 	lcg_copyrows,
1337e580c6eSjklos 	lcg_eraserows,
1347e580c6eSjklos 	lcg_allocattr
1357e580c6eSjklos };
1367e580c6eSjklos 
1377e580c6eSjklos static char lcg_stdscreen_name[10] = "160x68";
1387e580c6eSjklos struct wsscreen_descr lcg_stdscreen = {
1397e580c6eSjklos 	lcg_stdscreen_name, 160, 68,		/* dynamically set */
1407e580c6eSjklos 	&lcg_emulops,
1417e580c6eSjklos 	8, 15,					/* dynamically set */
1427e580c6eSjklos 	WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS,
1437e580c6eSjklos };
1447e580c6eSjklos 
1457e580c6eSjklos const struct wsscreen_descr *_lcg_scrlist[] = {
1467e580c6eSjklos 	&lcg_stdscreen,
1477e580c6eSjklos };
1487e580c6eSjklos 
1497e580c6eSjklos const struct wsscreen_list lcg_screenlist = {
1507e580c6eSjklos 	sizeof(_lcg_scrlist) / sizeof(struct wsscreen_descr *),
1517e580c6eSjklos 	_lcg_scrlist,
1527e580c6eSjklos };
1537e580c6eSjklos 
1547e580c6eSjklos static	char *lcgaddr;
1557e580c6eSjklos static	char *lutaddr;
1567e580c6eSjklos static	volatile long *regaddr;
1577e580c6eSjklos static	volatile long *fifoaddr;
1587e580c6eSjklos #ifndef LCG_NO_ACCEL
1597e580c6eSjklos static	char *fontaddr;
1607e580c6eSjklos #endif
1617e580c6eSjklos 
1627e580c6eSjklos static int	lcg_xsize;
1637e580c6eSjklos static int	lcg_ysize;
1647e580c6eSjklos static int	lcg_depth;
1657e580c6eSjklos static int	lcg_cols;
1667e580c6eSjklos static int	lcg_rows;
1677e580c6eSjklos static int	lcg_onerow;
1687e580c6eSjklos static int	lcg_fb_size;
1697e580c6eSjklos static int	lcg_glyph_size; /* bitmap size in bits */
1707e580c6eSjklos 
1717e580c6eSjklos static	char *cursor;
1727e580c6eSjklos 
1737e580c6eSjklos static	int cur_on;
1747e580c6eSjklos 
1757e580c6eSjklos static	int cur_fg, cur_bg;
1767e580c6eSjklos 
1777e580c6eSjklos 
1787e580c6eSjklos /* Our current hardware colormap */
1797e580c6eSjklos static struct hwcmap256 {
1807e580c6eSjklos #define	CMAP_SIZE	256	/* 256 R/G/B entries */
1817e580c6eSjklos 	u_int8_t r[CMAP_SIZE];
1827e580c6eSjklos 	u_int8_t g[CMAP_SIZE];
1837e580c6eSjklos 	u_int8_t b[CMAP_SIZE];
1847e580c6eSjklos } lcg_cmap;
1857e580c6eSjklos 
1867e580c6eSjklos /* The default colormap */
1877e580c6eSjklos static struct {
1887e580c6eSjklos 	u_int8_t r[8];
1897e580c6eSjklos 	u_int8_t g[8];
1907e580c6eSjklos 	u_int8_t b[8];
1917e580c6eSjklos } lcg_default_cmap = {
1927e580c6eSjklos 	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
1937e580c6eSjklos 	{ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff },
1947e580c6eSjklos 	{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }
1957e580c6eSjklos };
1967e580c6eSjklos 
1977e580c6eSjklos struct wsdisplay_font lcg_font;
1987e580c6eSjklos static u_char *qf;
1997e580c6eSjklos static u_short *qf2;
2007e580c6eSjklos 
2017e580c6eSjklos #define QCHAR(c) (c < lcg_font.firstchar ? 0 : \
2027e580c6eSjklos 	(c >= (lcg_font.firstchar + lcg_font.numchars) ? 0 : c - lcg_font.firstchar))
2037e580c6eSjklos #define QFONT(c,line)	((lcg_font.stride == 2 ? \
2047e580c6eSjklos 	qf2[QCHAR(c) * lcg_font.fontheight + line] : \
2057e580c6eSjklos 	qf[QCHAR(c) * lcg_font.fontheight + line]))
2067e580c6eSjklos #define	LCG_ADDR(row, col, line, dot) \
2077e580c6eSjklos 	lcgaddr[((col) * lcg_font.fontwidth) + ((row) * lcg_font.fontheight * lcg_xsize) + \
2087e580c6eSjklos 	    (line) * lcg_xsize + dot]
2097e580c6eSjklos 
2107e580c6eSjklos 
2117e580c6eSjklos static int	lcg_ioctl(void *, void *, u_long, void *, int, struct lwp *);
2127e580c6eSjklos static paddr_t	lcg_mmap(void *, void *, off_t, int);
2137e580c6eSjklos static int	lcg_alloc_screen(void *, const struct wsscreen_descr *,
2147e580c6eSjklos 				      void **, int *, int *, long *);
2157e580c6eSjklos static void	lcg_free_screen(void *, void *);
2167e580c6eSjklos static int	lcg_show_screen(void *, void *, int,
2177e580c6eSjklos 				     void (*) (void *, int, int), void *);
2187e580c6eSjklos static void	lcg_crsr_blink(void *);
2197e580c6eSjklos 
2207e580c6eSjklos /* LCG HW accel functions */
2217e580c6eSjklos #ifndef LCG_NO_ACCEL
2227e580c6eSjklos static void	fifo_put(long data);
2237e580c6eSjklos static int	fifo_fill(int iterations);
2247e580c6eSjklos static u_char	fifo_counter = 0;
2257e580c6eSjklos 
2267e580c6eSjklos static void	blkcpy(long source, long dest, int xdim, int ydim);
2277e580c6eSjklos static void	blkset(long dest, int xdim, int ydim, char color);
2287e580c6eSjklos static void	renderchar(long source, long dest, int xdim, int ydim, char fg, char bg);
2297e580c6eSjklos #endif /* LCG_NO_ACCEL */
2307e580c6eSjklos 
2317e580c6eSjklos const struct wsdisplay_accessops lcg_accessops = {
2327e580c6eSjklos 	lcg_ioctl,
2337e580c6eSjklos 	lcg_mmap,
2347e580c6eSjklos 	lcg_alloc_screen,
2357e580c6eSjklos 	lcg_free_screen,
2367e580c6eSjklos 	lcg_show_screen,
2377e580c6eSjklos 	0 /* load_font */
2387e580c6eSjklos };
2397e580c6eSjklos 
2407e580c6eSjklos /* TODO allocate ss_image dynamically for consoles beyond first one */
2417e580c6eSjklos struct	lcg_screen {
2427e580c6eSjklos 	int	ss_curx;
2437e580c6eSjklos 	int	ss_cury;
2447e580c6eSjklos 	int	ss_cur_fg;
2457e580c6eSjklos 	int	ss_cur_bg;
2467e580c6eSjklos 	struct {
2477e580c6eSjklos 		u_char	data;			/* Image character */
2487e580c6eSjklos 		u_char	attr;			/* Attribute: 80/70/08/07 */
2497e580c6eSjklos 	} ss_image[160 * 128];			/* allow for maximum possible cell matrix */
2507e580c6eSjklos };
2517e580c6eSjklos #define	LCG_ATTR_UNDERLINE	0x80
2527e580c6eSjklos #define	LCG_BG_MASK		0x70
2537e580c6eSjklos #define	LCG_ATTR_REVERSE	0x08
2547e580c6eSjklos #define	LCG_FG_MASK		0x07
2557e580c6eSjklos 
2567e580c6eSjklos static	struct lcg_screen lcg_conscreen;
2577e580c6eSjklos static	struct lcg_screen *curscr;
2587e580c6eSjklos static	struct lcg_screen *savescr;
2597e580c6eSjklos 
2607e580c6eSjklos static	callout_t lcg_cursor_ch;
2617e580c6eSjklos 
2627e580c6eSjklos #ifndef LCG_NO_ACCEL
fifo_put(long data)2637e580c6eSjklos void fifo_put(long data)
2647e580c6eSjklos {
2657e580c6eSjklos 	fifo_counter &= 0x3;
2667e580c6eSjklos 	fifoaddr[fifo_counter] = data;
2677e580c6eSjklos 	fifo_counter++;
2687e580c6eSjklos }
2697e580c6eSjklos 
fifo_fill(int iterations)2707e580c6eSjklos int fifo_fill(int iterations)
2717e580c6eSjklos {
2727e580c6eSjklos 	long status;
273a50c0670Smaya 	int counter = 0;
2747e580c6eSjklos 
2757e580c6eSjklos 	while (fifo_counter % 4)
2767e580c6eSjklos 		fifo_put(0);
2777e580c6eSjklos 
2787e580c6eSjklos #ifdef LCG_SAFE
2797e580c6eSjklos 	status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS);
2807e580c6eSjklos 	while ((counter < iterations) && ((status & 0x80000000) == 0x80000000)) {
2817e580c6eSjklos 		delay(1000);
2827e580c6eSjklos 		status = LCG_REG(LCG_REG_GRAPHICS_SUB_STATUS);
2837e580c6eSjklos 		counter++;
2847e580c6eSjklos 	}
2857e580c6eSjklos #endif
2867e580c6eSjklos 
2877e580c6eSjklos 	if (counter == 0)
2887e580c6eSjklos 		return 0;
2897e580c6eSjklos 	else
2907e580c6eSjklos 		return 1;
2917e580c6eSjklos }
2927e580c6eSjklos 
blkcpy(long source,long dest,int xdim,int ydim)2937e580c6eSjklos void blkcpy(long source, long dest, int xdim, int ydim)
2947e580c6eSjklos {
2957e580c6eSjklos 	int err;
2967e580c6eSjklos 
2977e580c6eSjklos #ifdef LCG_SAFE
2987e580c6eSjklos 	if ((source < LCG_FB_ADDR) || (source > LCG_FB_ADDR + lcg_fb_size)) {
2997e580c6eSjklos 		printf("lcg: blkcpy: invalid source 0x%lx\n", source);
3007e580c6eSjklos 		return;
3017e580c6eSjklos 	}
3027e580c6eSjklos 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
3037e580c6eSjklos 		printf("lcg: blkcpy: invalid destination 0x%lx\n", dest);
3047e580c6eSjklos 		return;
3057e580c6eSjklos 	}
3067e580c6eSjklos #endif
3077e580c6eSjklos 
3087e580c6eSjklos #ifdef LCG_SAFE
3097e580c6eSjklos 	fifo_put(0x0c010000 | (cur_fg & 0xff));
3107e580c6eSjklos #endif
3117e580c6eSjklos 	fifo_put(0x01020006);
3127e580c6eSjklos 
3137e580c6eSjklos 	fifo_put(0x06800000);
3147e580c6eSjklos 	fifo_put(source);
3157e580c6eSjklos 	fifo_put(lcg_xsize);
3167e580c6eSjklos 
3177e580c6eSjklos 	fifo_put(0x05800000);
3187e580c6eSjklos 	fifo_put(dest);
3197e580c6eSjklos 	fifo_put(lcg_xsize);
3207e580c6eSjklos 
3217e580c6eSjklos 	fifo_put(0x03400000);
3227e580c6eSjklos 	fifo_put(0xff);
3237e580c6eSjklos 
3247e580c6eSjklos 	fifo_put(0x02000003);
3257e580c6eSjklos 
3267e580c6eSjklos #ifdef LCG_SAFE
3277e580c6eSjklos 	fifo_put(0x04c00000);
3287e580c6eSjklos 	fifo_put(0);
3297e580c6eSjklos 	fifo_put(lcg_xsize);
3307e580c6eSjklos 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
3317e580c6eSjklos #endif
3327e580c6eSjklos 
3337e580c6eSjklos 	fifo_put(0x09c00000);
3347e580c6eSjklos 	fifo_put(((ydim & 0xffff) << 16) | xdim);
3357e580c6eSjklos 	fifo_put(0);
3367e580c6eSjklos 	fifo_put(0);
3377e580c6eSjklos 
3387e580c6eSjklos 	err = fifo_fill(200);
3397e580c6eSjklos 	if (err)
3407e580c6eSjklos 		printf("lcg: AG still busy after 200 msec\n");
3417e580c6eSjklos }
3427e580c6eSjklos 
blkset(long dest,int xdim,int ydim,char color)3437e580c6eSjklos void blkset(long dest, int xdim, int ydim, char color)
3447e580c6eSjklos {
3457e580c6eSjklos 	int err;
3467e580c6eSjklos 
3477e580c6eSjklos #ifdef LCG_SAFE
3487e580c6eSjklos 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
3497e580c6eSjklos 		printf("lcg: blkset: invalid destination 0x%lx\n", dest);
3507e580c6eSjklos 		return;
3517e580c6eSjklos 	}
3527e580c6eSjklos #endif
3537e580c6eSjklos 
3547e580c6eSjklos 	fifo_put(0x0c010000 | (color & 0xff));
3557e580c6eSjklos 
3567e580c6eSjklos 	fifo_put(0x01000000);
3577e580c6eSjklos 
3587e580c6eSjklos 	fifo_put(0x05800000);
3597e580c6eSjklos 	fifo_put(dest);
3607e580c6eSjklos 	fifo_put(lcg_xsize);
3617e580c6eSjklos 
3627e580c6eSjklos 	fifo_put(0x03400000);
3637e580c6eSjklos 	fifo_put(0xff);
3647e580c6eSjklos 
3657e580c6eSjklos 	fifo_put(0x02000003);
3667e580c6eSjklos 
3677e580c6eSjklos #ifdef LCG_SAFE
3687e580c6eSjklos 	fifo_put(0x04c00000);
3697e580c6eSjklos 	fifo_put(0);
3707e580c6eSjklos 	fifo_put(lcg_xsize);
3717e580c6eSjklos 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
3727e580c6eSjklos #endif
3737e580c6eSjklos 
3747e580c6eSjklos 	fifo_put(0x09c00000);
3757e580c6eSjklos 	fifo_put(((ydim & 0xffff) << 16) | xdim);
3767e580c6eSjklos 	fifo_put(0);
3777e580c6eSjklos 	fifo_put(0);
3787e580c6eSjklos 
3797e580c6eSjklos 	err = fifo_fill(200);
3807e580c6eSjklos 	if (err)
3817e580c6eSjklos 		printf("lcg: AG still busy after 200 msec\n");
3827e580c6eSjklos }
3837e580c6eSjklos 
renderchar(long source,long dest,int xdim,int ydim,char fg,char bg)3847e580c6eSjklos void renderchar(long source, long dest, int xdim, int ydim, char fg, char bg)
3857e580c6eSjklos {
3867e580c6eSjklos 	int err;
3877e580c6eSjklos #ifdef LCG_SAFE
3887e580c6eSjklos 	if ((dest < LCG_FB_ADDR) || (dest > LCG_FB_ADDR + lcg_fb_size)) {
3897e580c6eSjklos 		printf("lcg: blkset: invalid destination 0x%lx\n", dest);
3907e580c6eSjklos 		return;
3917e580c6eSjklos 	}
3927e580c6eSjklos #endif
3937e580c6eSjklos 
3947e580c6eSjklos 	fifo_put(0x0c050000 | (bg & 0xff));
3957e580c6eSjklos 	fifo_put(0x0c010000 | (fg & 0xff));
3967e580c6eSjklos 
3977e580c6eSjklos 	fifo_put(0x01030008);
3987e580c6eSjklos 
3997e580c6eSjklos 	fifo_put(0x06800000);
4007e580c6eSjklos 	fifo_put(source);
4017e580c6eSjklos 	//fifo_put(lcg_xsize);
4027e580c6eSjklos 	fifo_put(lcg_font.stride);
4037e580c6eSjklos 
4047e580c6eSjklos 	fifo_put(0x05800000);
4057e580c6eSjklos 	fifo_put(dest);
4067e580c6eSjklos 	fifo_put(lcg_xsize);
4077e580c6eSjklos 
4087e580c6eSjklos 	fifo_put(0x03400000);
4097e580c6eSjklos 	fifo_put(0xff);
4107e580c6eSjklos 
4117e580c6eSjklos 	fifo_put(0x02000003);
4127e580c6eSjklos 
4137e580c6eSjklos #ifdef LCG_SAFE
4147e580c6eSjklos 	fifo_put(0x04c00000);
4157e580c6eSjklos 	fifo_put(0);
4167e580c6eSjklos 	fifo_put(lcg_xsize);
4177e580c6eSjklos 	fifo_put(lcg_fb_size - (dest - LCG_FB_ADDR));
4187e580c6eSjklos #endif
4197e580c6eSjklos 
4207e580c6eSjklos 	fifo_put(0x09c00000);
4217e580c6eSjklos 	fifo_put(((ydim & 0xffff) << 16) | (xdim & 0xffff));
4227e580c6eSjklos 	fifo_put(0);
4237e580c6eSjklos 	fifo_put(0);
4247e580c6eSjklos 
4257e580c6eSjklos 	err = fifo_fill(200);
4267e580c6eSjklos 	if (err)
4277e580c6eSjklos 		printf("lcg: AG still busy after 200 msec\n");
4287e580c6eSjklos }
4297e580c6eSjklos #endif /* LCG_NO_ACCEL */
4307e580c6eSjklos 
4317e580c6eSjklos int
lcg_match(struct device * parent,struct cfdata * match,void * aux)4327e580c6eSjklos lcg_match(struct device *parent, struct cfdata *match, void *aux)
4337e580c6eSjklos {
4347e580c6eSjklos 	struct vsbus_softc *sc = device_private(parent);
4357e580c6eSjklos 	struct vsbus_attach_args *va = aux;
436*2b6fd3cdSjakllsch 	volatile char * const ch = (char *)va->va_addr;
4377e580c6eSjklos 
4387e580c6eSjklos 	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
4397e580c6eSjklos 		return 0;
4407e580c6eSjklos 
4417e580c6eSjklos 	*ch = 1;
4427e580c6eSjklos 	if ((*ch & 1) == 0)
4437e580c6eSjklos 		return 0;
4447e580c6eSjklos 	*ch = 0;
4457e580c6eSjklos 	if ((*ch & 1) != 0)
4467e580c6eSjklos 		return 0;
4477e580c6eSjklos 
4487e580c6eSjklos 	/* XXX use vertical interrupt? */
4497e580c6eSjklos 	sc->sc_mask = 0x04; /* XXX - should be generated */
4507e580c6eSjklos 	scb_fake(0x120, 0x15);
4517e580c6eSjklos 	return 20;
4527e580c6eSjklos }
4537e580c6eSjklos 
4547e580c6eSjklos void
lcg_attach(struct device * parent,struct device * self,void * aux)4557e580c6eSjklos lcg_attach(struct device *parent, struct device *self, void *aux)
4567e580c6eSjklos {
4577e580c6eSjklos 	struct vsbus_attach_args *va = aux;
4587e580c6eSjklos 	struct wsemuldisplaydev_attach_args aa;
4597e580c6eSjklos 
4607e580c6eSjklos 	printf("\n");
4617e580c6eSjklos 	aa.console = lcgaddr != NULL;
4627e580c6eSjklos 
4637e580c6eSjklos 	lcg_init_common(self, va);
4647e580c6eSjklos 
4657e580c6eSjklos 	curscr = &lcg_conscreen;
4667e580c6eSjklos 
4677e580c6eSjklos 	aa.scrdata = &lcg_screenlist;
4687e580c6eSjklos 	aa.accessops = &lcg_accessops;
4697e580c6eSjklos 
4707e580c6eSjklos 	/* enable software cursor */
4717e580c6eSjklos 	callout_init(&lcg_cursor_ch, 0);
4727e580c6eSjklos 	callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL);
4737e580c6eSjklos 
474c7fb772bSthorpej 	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
4757e580c6eSjklos }
4767e580c6eSjklos 
4777e580c6eSjklos static void
lcg_crsr_blink(void * arg)4787e580c6eSjklos lcg_crsr_blink(void *arg)
4797e580c6eSjklos {
4807e580c6eSjklos 	int dot;
4817e580c6eSjklos 
4827e580c6eSjklos 	if (cur_on && curscr != NULL)
4837e580c6eSjklos 		for (dot = 0; dot < lcg_font.fontwidth; dot++)
4847e580c6eSjklos 			cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg;
4857e580c6eSjklos 
4867e580c6eSjklos 	callout_reset(&lcg_cursor_ch, hz / 2, lcg_crsr_blink, NULL);
4877e580c6eSjklos }
4887e580c6eSjklos 
4897e580c6eSjklos void
lcg_cursor(void * id,int on,int row,int col)4907e580c6eSjklos lcg_cursor(void *id, int on, int row, int col)
4917e580c6eSjklos {
4927e580c6eSjklos 	struct lcg_screen *ss = id;
4937e580c6eSjklos 	int dot, attr;
4947e580c6eSjklos 
4957e580c6eSjklos 	attr = ss->ss_image[row * lcg_cols + col].attr;
4967e580c6eSjklos 	if (ss == curscr) {
4977e580c6eSjklos 		if (cursor != NULL) {
4987e580c6eSjklos 			int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols +
4997e580c6eSjklos 			    ss->ss_curx].data, lcg_font.fontheight - 1);
5007e580c6eSjklos 			attr = ss->ss_image[ss->ss_cury * lcg_cols +
5017e580c6eSjklos 			    ss->ss_curx].attr;
5027e580c6eSjklos 
5037e580c6eSjklos 			if (attr & LCG_ATTR_REVERSE) {
5047e580c6eSjklos 				cur_bg = attr & LCG_FG_MASK;
5057e580c6eSjklos 				cur_fg = (attr & LCG_BG_MASK) >> 4;
5067e580c6eSjklos 			} else {
5077e580c6eSjklos 				cur_fg = attr & LCG_FG_MASK;
5087e580c6eSjklos 				cur_bg = (attr & LCG_BG_MASK) >> 4;
5097e580c6eSjklos 			}
5107e580c6eSjklos 			for (dot = 0; dot < lcg_font.fontwidth; dot++)
5117e580c6eSjklos 				cursor[dot] =  (ch & (1 << dot)) ?
5127e580c6eSjklos 				    cur_fg : cur_bg;
5137e580c6eSjklos 		}
5147e580c6eSjklos 
5157e580c6eSjklos 		cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
5167e580c6eSjklos 		cur_on = on;
5177e580c6eSjklos 		if (attr & LCG_ATTR_REVERSE) {
5187e580c6eSjklos 			cur_bg = attr & LCG_FG_MASK;
5197e580c6eSjklos 			cur_fg = (attr & LCG_BG_MASK) >> 4;
5207e580c6eSjklos 		} else {
5217e580c6eSjklos 			cur_fg = attr & LCG_FG_MASK;
5227e580c6eSjklos 			cur_bg = (attr & LCG_BG_MASK) >> 4;
5237e580c6eSjklos 		}
5247e580c6eSjklos 	}
5257e580c6eSjklos 	ss->ss_curx = col;
5267e580c6eSjklos 	ss->ss_cury = row;
5277e580c6eSjklos 	if (attr & LCG_ATTR_REVERSE) {
5287e580c6eSjklos 		ss->ss_cur_bg = attr & LCG_FG_MASK;
5297e580c6eSjklos 		ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4;
5307e580c6eSjklos 	} else {
5317e580c6eSjklos 		ss->ss_cur_fg = attr & LCG_FG_MASK;
5327e580c6eSjklos 		ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4;
5337e580c6eSjklos 	}
5347e580c6eSjklos }
5357e580c6eSjklos 
5367e580c6eSjklos int
lcg_mapchar(void * id,int uni,unsigned int * index)5377e580c6eSjklos lcg_mapchar(void *id, int uni, unsigned int *index)
5387e580c6eSjklos {
5397e580c6eSjklos 	if (uni < 256) {
5407e580c6eSjklos 		*index = uni;
5417e580c6eSjklos 		return (5);
5427e580c6eSjklos 	}
5437e580c6eSjklos 	*index = ' ';
5447e580c6eSjklos 	return (0);
5457e580c6eSjklos }
5467e580c6eSjklos 
5477e580c6eSjklos static void
lcg_putchar(void * id,int row,int col,u_int c,long attr)5487e580c6eSjklos lcg_putchar(void *id, int row, int col, u_int c, long attr)
5497e580c6eSjklos {
5507e580c6eSjklos 	struct lcg_screen *ss = id;
5517e580c6eSjklos 	int i;
5527e580c6eSjklos 	char dot_fg, dot_bg;
5537e580c6eSjklos 
5547e580c6eSjklos 	c &= 0xff;
5557e580c6eSjklos 
5567e580c6eSjklos 	ss->ss_image[row * lcg_cols + col].data = c;
5577e580c6eSjklos 	ss->ss_image[row * lcg_cols + col].attr = attr;
5587e580c6eSjklos 	if (ss != curscr)
5597e580c6eSjklos 		return;
5607e580c6eSjklos 
5617e580c6eSjklos 	dot_fg = attr & LCG_FG_MASK;
5627e580c6eSjklos 	dot_bg = (attr & LCG_BG_MASK) >> 4;
5637e580c6eSjklos 	if (attr & LCG_ATTR_REVERSE) {
5647e580c6eSjklos 		dot_fg = (attr & LCG_BG_MASK) >> 4;
5657e580c6eSjklos 		dot_bg = attr & LCG_FG_MASK;
5667e580c6eSjklos 	}
5677e580c6eSjklos 
5687e580c6eSjklos #ifndef LCG_NO_ACCEL
5697e580c6eSjklos 	renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size),
5707e580c6eSjklos 		   LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth),
5717e580c6eSjklos 		   lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg);
5727e580c6eSjklos #else
5737e580c6eSjklos 	for (i = 0; i < lcg_font.fontheight; i++) {
5747e580c6eSjklos 		unsigned char ch = QFONT(c,i);
5757e580c6eSjklos 		for (int j = 0; j < lcg_font.fontwidth; j++) {
5767e580c6eSjklos 			LCG_ADDR(row, col, i, j) = ((ch >> j) & 1) ? dot_fg : dot_bg;
5777e580c6eSjklos 		}
5787e580c6eSjklos 	}
5797e580c6eSjklos #endif /* LCG_NO_ACCEL */
5807e580c6eSjklos 	if (attr & LCG_ATTR_UNDERLINE) {
5817e580c6eSjklos 		char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
5827e580c6eSjklos 		for (i = 0; i < lcg_font.fontwidth; i++)
5837e580c6eSjklos 			p[i] = ~p[i];
5847e580c6eSjklos 	}
5857e580c6eSjklos }
5867e580c6eSjklos 
5877e580c6eSjklos 
5887e580c6eSjklos 
5897e580c6eSjklos /*
5907e580c6eSjklos  * copies columns inside a row.
5917e580c6eSjklos  */
5927e580c6eSjklos static void
lcg_copycols(void * id,int row,int srccol,int dstcol,int ncols)5937e580c6eSjklos lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols)
5947e580c6eSjklos {
5957e580c6eSjklos 	struct lcg_screen *ss = id;
5967e580c6eSjklos #ifdef LCG_NO_ACCEL
5977e580c6eSjklos 	int i = 0;
5987e580c6eSjklos #endif
5997e580c6eSjklos 
6007e580c6eSjklos 	bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row *
6017e580c6eSjklos 	    lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0]));
6027e580c6eSjklos 	if (ss != curscr)
6037e580c6eSjklos 		return;
6047e580c6eSjklos #ifdef LCG_NO_ACCEL
6057e580c6eSjklos 	for (i = 0; i < lcg_font.fontheight; i++)
6067e580c6eSjklos 		memcpy(&LCG_ADDR(row, dstcol, i, 0),
6077e580c6eSjklos 		&LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth);
6087e580c6eSjklos 
6097e580c6eSjklos #else
6107e580c6eSjklos 	blkcpy(LCG_FB_ADDR + (row * lcg_onerow) + (srccol * lcg_font.fontwidth),
6117e580c6eSjklos 	       LCG_FB_ADDR + (row * lcg_onerow) + (dstcol * lcg_font.fontwidth),
6127e580c6eSjklos 	       (ncols * lcg_font.fontwidth), lcg_font.fontheight);
6137e580c6eSjklos #endif
6147e580c6eSjklos }
6157e580c6eSjklos 
6167e580c6eSjklos /*
6177e580c6eSjklos  * Erases a bunch of chars inside one row.
6187e580c6eSjklos  */
6197e580c6eSjklos static void
lcg_erasecols(void * id,int row,int startcol,int ncols,long fillattr)6207e580c6eSjklos lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
6217e580c6eSjklos {
6227e580c6eSjklos 	struct lcg_screen *ss = id;
6237e580c6eSjklos 	int i;
6247e580c6eSjklos 
6257e580c6eSjklos 	bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0]));
6267e580c6eSjklos 	for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i)
6277e580c6eSjklos 		ss->ss_image[i].attr = fillattr;
6287e580c6eSjklos 	if (ss != curscr)
6297e580c6eSjklos 		return;
6307e580c6eSjklos #ifdef LCG_NO_ACCEL
6317e580c6eSjklos 	for (i = 0; i < lcg_font.fontheight; i++)
6327e580c6eSjklos                 memset(&LCG_ADDR(row, startcol, i, 0), 0, ncols * lcg_font.fontwidth);
6337e580c6eSjklos #else
6347e580c6eSjklos 	blkset(LCG_FB_ADDR + (row * lcg_onerow) + (startcol * lcg_font.fontwidth),
6357e580c6eSjklos 		(ncols * lcg_font.fontwidth), lcg_font.fontheight, (fillattr & LCG_BG_MASK) >> 4);
6367e580c6eSjklos #endif
6377e580c6eSjklos }
6387e580c6eSjklos 
6397e580c6eSjklos static void
lcg_copyrows(void * id,int srcrow,int dstrow,int nrows)6407e580c6eSjklos lcg_copyrows(void *id, int srcrow, int dstrow, int nrows)
6417e580c6eSjklos {
6427e580c6eSjklos 	struct lcg_screen *ss = id;
6437e580c6eSjklos 
6447e580c6eSjklos 	bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols],
6457e580c6eSjklos 	    nrows * lcg_cols * sizeof(ss->ss_image[0]));
6467e580c6eSjklos 	if (ss != curscr)
6477e580c6eSjklos 		return;
6487e580c6eSjklos #ifdef LCG_NO_ACCEL
6497e580c6eSjklos 	memcpy(&lcgaddr[dstrow * lcg_onerow],
6507e580c6eSjklos             &lcgaddr[srcrow * lcg_onerow], nrows * lcg_onerow);
6517e580c6eSjklos #else
6527e580c6eSjklos 	blkcpy(LCG_FB_ADDR + (srcrow * lcg_onerow), LCG_FB_ADDR + (dstrow * lcg_onerow),
6537e580c6eSjklos 		(lcg_cols * lcg_font.fontwidth), (nrows * lcg_font.fontheight));
6547e580c6eSjklos #endif
6557e580c6eSjklos }
6567e580c6eSjklos 
6577e580c6eSjklos static void
lcg_eraserows(void * id,int startrow,int nrows,long fillattr)6587e580c6eSjklos lcg_eraserows(void *id, int startrow, int nrows, long fillattr)
6597e580c6eSjklos {
6607e580c6eSjklos 	struct lcg_screen *ss = id;
6617e580c6eSjklos 	int i;
6627e580c6eSjklos 
6637e580c6eSjklos 	bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols *
6647e580c6eSjklos 	    sizeof(ss->ss_image[0]));
6657e580c6eSjklos 	for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i)
6667e580c6eSjklos 		ss->ss_image[i].attr = fillattr;
6677e580c6eSjklos 	if (ss != curscr)
6687e580c6eSjklos 		return;
6697e580c6eSjklos #ifdef LCG_NO_ACCEL
6707e580c6eSjklos 	memset(&lcgaddr[startrow * lcg_onerow], 0, nrows * lcg_onerow);
6717e580c6eSjklos #else
6727e580c6eSjklos 	blkset(LCG_FB_ADDR + (startrow * lcg_onerow), (lcg_cols * lcg_font.fontwidth),
6737e580c6eSjklos 		(nrows * lcg_font.fontheight), (fillattr & LCG_BG_MASK) >> 4);
6747e580c6eSjklos #endif
6757e580c6eSjklos }
6767e580c6eSjklos 
6777e580c6eSjklos static int
lcg_allocattr(void * id,int fg,int bg,int flags,long * attrp)6787e580c6eSjklos lcg_allocattr(void *id, int fg, int bg, int flags, long *attrp)
6797e580c6eSjklos {
6807e580c6eSjklos 	long myattr;
6817e580c6eSjklos 
6827e580c6eSjklos 	if (flags & WSATTR_WSCOLORS)
6837e580c6eSjklos 		myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK);
6847e580c6eSjklos 	else
6857e580c6eSjklos 		myattr = WSCOL_WHITE << 4;	/* XXXX */
6867e580c6eSjklos 	if (flags & WSATTR_REVERSE)
6877e580c6eSjklos 		myattr |= LCG_ATTR_REVERSE;
6887e580c6eSjklos 	if (flags & WSATTR_UNDERLINE)
6897e580c6eSjklos 		myattr |= LCG_ATTR_UNDERLINE;
6907e580c6eSjklos 	*attrp = myattr;
6917e580c6eSjklos 	return 0;
6927e580c6eSjklos }
6937e580c6eSjklos 
6947e580c6eSjklos static int
lcg_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)6957e580c6eSjklos lcg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
6967e580c6eSjklos {
6977e580c6eSjklos 	struct wsdisplay_fbinfo *fb = (void *)data;
6987e580c6eSjklos 	int i;
6997e580c6eSjklos 
7007e580c6eSjklos 	switch (cmd) {
7017e580c6eSjklos 	case WSDISPLAYIO_GTYPE:
7027e580c6eSjklos 		*(u_int *)data = WSDISPLAY_TYPE_LCG;
7037e580c6eSjklos 		break;
7047e580c6eSjklos 
7057e580c6eSjklos 	case WSDISPLAYIO_GINFO:
7067e580c6eSjklos 		fb->height = lcg_ysize;
7077e580c6eSjklos 		fb->width = lcg_xsize;
7087e580c6eSjklos 		fb->depth = lcg_depth;
7097e580c6eSjklos 		fb->cmsize = 1 << lcg_depth;
7107e580c6eSjklos 		break;
7117e580c6eSjklos 
7125ebf3ef3Sjklos 	case WSDISPLAYIO_LINEBYTES:
7135ebf3ef3Sjklos 		*(u_int *)data = lcg_xsize;
7145ebf3ef3Sjklos 		break;
7155ebf3ef3Sjklos 
7167e580c6eSjklos 	case WSDISPLAYIO_GETCMAP:
7177e580c6eSjklos 		return lcg_get_cmap((struct wsdisplay_cmap *)data);
7187e580c6eSjklos 
7197e580c6eSjklos 	case WSDISPLAYIO_PUTCMAP:
7207e580c6eSjklos 		return lcg_set_cmap((struct wsdisplay_cmap *)data);
7217e580c6eSjklos 
7227e580c6eSjklos 	case WSDISPLAYIO_GMODE:
7237e580c6eSjklos 		return EPASSTHROUGH;
7247e580c6eSjklos 
7257e580c6eSjklos 	case WSDISPLAYIO_SMODE:
7267e580c6eSjklos 		/* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */
7277e580c6eSjklos 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) {
7287e580c6eSjklos 			/* FIXME: if this is meant to reset palette LUT reload has to be triggered too */
7297e580c6eSjklos 			bzero(lutaddr, LCG_LUT_SIZE);
7307e580c6eSjklos 			for (i = 0; i < 8; ++i) {
7317e580c6eSjklos 				lcg_cmap.r[i] = lcg_default_cmap.r[i];
7327e580c6eSjklos 				lcg_cmap.g[i] = lcg_default_cmap.g[i];
7337e580c6eSjklos 				lcg_cmap.b[i] = lcg_default_cmap.b[i];
7347e580c6eSjklos 				lutaddr[i * 8 + 1] = i;
7357e580c6eSjklos 				lutaddr[i * 8 + 2] = 1;
7367e580c6eSjklos 				lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
7377e580c6eSjklos 				lutaddr[i * 8 + 4] = 1;
7387e580c6eSjklos 				lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
7397e580c6eSjklos 				lutaddr[i * 8 + 6] = 1;
7407e580c6eSjklos 				lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
7417e580c6eSjklos 			}
7427e580c6eSjklos 			if (savescr != NULL)
7437e580c6eSjklos 				lcg_show_screen(NULL, savescr, 0, NULL, NULL);
7447e580c6eSjklos 			savescr = NULL;
7457e580c6eSjklos 		} else {		/* WSDISPLAYIO_MODE_MAPPED */
7467e580c6eSjklos 			savescr = curscr;
7477e580c6eSjklos 			curscr = NULL;
7487e580c6eSjklos 			/* clear screen? */
7497e580c6eSjklos 		}
7507e580c6eSjklos 
7517e580c6eSjklos 		return EPASSTHROUGH;
7527e580c6eSjklos #if 0
7537e580c6eSjklos 	case WSDISPLAYIO_SVIDEO:
7547e580c6eSjklos 		if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) {
7557e580c6eSjklos 			curcmd = curc;
7567e580c6eSjklos 		} else {
7577e580c6eSjklos 			curc = curcmd;
7587e580c6eSjklos 			curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA);
7597e580c6eSjklos 			curcmd |= CUR_CMD_FOPB;
7607e580c6eSjklos 		}
7617e580c6eSjklos 		WRITECUR(CUR_CMD, curcmd);
7627e580c6eSjklos 		break;
7637e580c6eSjklos 
7647e580c6eSjklos 	case WSDISPLAYIO_GVIDEO:
7657e580c6eSjklos 		*(u_int *)data = (curcmd & CUR_CMD_FOPB ?
7667e580c6eSjklos 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
7677e580c6eSjklos 		break;
7687e580c6eSjklos 
7697e580c6eSjklos #endif
7707e580c6eSjklos 	default:
7717e580c6eSjklos 		return EPASSTHROUGH;
7727e580c6eSjklos 	}
7737e580c6eSjklos 	return 0;
7747e580c6eSjklos }
7757e580c6eSjklos 
7767e580c6eSjklos static paddr_t
lcg_mmap(void * v,void * vs,off_t offset,int prot)7777e580c6eSjklos lcg_mmap(void *v, void *vs, off_t offset, int prot)
7787e580c6eSjklos {
7797e580c6eSjklos 	if (offset >= lcg_fb_size || offset < 0)
7807e580c6eSjklos 		return -1;
7817e580c6eSjklos 	return (LCG_FB_ADDR + offset) >> PGSHIFT;
7827e580c6eSjklos }
7837e580c6eSjklos 
7847e580c6eSjklos int
lcg_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * defattrp)7857e580c6eSjklos lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
7867e580c6eSjklos     int *curxp, int *curyp, long *defattrp)
7877e580c6eSjklos {
7887e580c6eSjklos 	int i;
7897e580c6eSjklos 	struct lcg_screen *ss;
7907e580c6eSjklos 
79174ee8752Sthorpej 	*cookiep = kmem_alloc(sizeof(struct lcg_screen), KM_SLEEP);
7927e580c6eSjklos 	bzero(*cookiep, sizeof(struct lcg_screen));
7937e580c6eSjklos 	*curxp = *curyp = 0;
7947e580c6eSjklos 	*defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
7957e580c6eSjklos 	ss = *cookiep;
7967e580c6eSjklos 	for (i = 0; i < lcg_cols * lcg_rows; ++i)
7977e580c6eSjklos 		ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
7987e580c6eSjklos 	return 0;
7997e580c6eSjklos }
8007e580c6eSjklos 
8017e580c6eSjklos void
lcg_free_screen(void * v,void * cookie)8027e580c6eSjklos lcg_free_screen(void *v, void *cookie)
8037e580c6eSjklos {
8047e580c6eSjklos }
8057e580c6eSjklos 
8067e580c6eSjklos int
lcg_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)8077e580c6eSjklos lcg_show_screen(void *v, void *cookie, int waitok,
8087e580c6eSjklos     void (*cb)(void *, int, int), void *cbarg)
8097e580c6eSjklos {
8107e580c6eSjklos 	struct lcg_screen *ss = cookie;
8117e580c6eSjklos 	int row, col, dot_fg, dot_bg, j, attr;
8127e580c6eSjklos #ifdef LCG_NO_ACCEL
8137e580c6eSjklos 	int iter, jter;
8147e580c6eSjklos 	unsigned char ch;
8157e580c6eSjklos #endif
8167e580c6eSjklos 
8177e580c6eSjklos 	if (ss == curscr)
8187e580c6eSjklos 		return (0);
8197e580c6eSjklos #ifdef LCG_NO_ACCEL
8207e580c6eSjklos 	memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize);
8217e580c6eSjklos #endif
8227e580c6eSjklos 
8237e580c6eSjklos 	for (row = 0; row < lcg_rows; row++)
8247e580c6eSjklos 		for (col = 0; col < lcg_cols; col++) {
8257e580c6eSjklos 			attr = ss->ss_image[row * lcg_cols + col].attr;
8267e580c6eSjklos 			if (attr & LCG_ATTR_REVERSE) {
8277e580c6eSjklos 				dot_fg = (attr & LCG_BG_MASK) >> 4;
8287e580c6eSjklos 				dot_bg = attr & LCG_FG_MASK;
8297e580c6eSjklos 			} else {
8307e580c6eSjklos 				dot_fg = attr & LCG_FG_MASK;
8317e580c6eSjklos 				dot_bg = (attr & LCG_BG_MASK) >> 4;
8327e580c6eSjklos 			}
8337e580c6eSjklos 			u_char c = ss->ss_image[row * lcg_cols + col].data;
8347e580c6eSjklos 
8357e580c6eSjklos 			if (c < 32)
8367e580c6eSjklos 				c = 32;
8377e580c6eSjklos #ifndef LCG_NO_ACCEL
8387e580c6eSjklos 			renderchar(LCG_FONT_ADDR + (c * lcg_glyph_size),
8397e580c6eSjklos 				   LCG_FB_ADDR + (row * lcg_onerow) + (col * lcg_font.fontwidth),
8407e580c6eSjklos 				   lcg_font.fontwidth, lcg_font.fontheight, dot_fg, dot_bg);
8417e580c6eSjklos #else
8427e580c6eSjklos 			for (iter = 0; iter < lcg_font.fontheight; iter++) {
8437e580c6eSjklos 				ch = QFONT(c,iter);
8447e580c6eSjklos 				for (jter = 0; jter < lcg_font.fontwidth; jter++) {
8457e580c6eSjklos 					LCG_ADDR(row, col, iter, jter) = ((ch >> jter) & 1) ? dot_fg : dot_bg;
8467e580c6eSjklos 				}
8477e580c6eSjklos 			}
8487e580c6eSjklos #endif
8497e580c6eSjklos 			if (attr & LCG_ATTR_UNDERLINE)
8507e580c6eSjklos 				for (j = 0; j < lcg_font.fontwidth; j++)
8517e580c6eSjklos 					LCG_ADDR(row, col,
8527e580c6eSjklos 					    lcg_font.fontheight - 1, j) = dot_fg;
8537e580c6eSjklos 		}
8547e580c6eSjklos 
8557e580c6eSjklos 	cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) +
8567e580c6eSjklos 		((lcg_font.fontheight - 1) * lcg_xsize) +
8577e580c6eSjklos 			(ss->ss_curx * lcg_font.fontwidth)];
8587e580c6eSjklos 	cur_fg = ss->ss_cur_fg;
8597e580c6eSjklos 	cur_bg = ss->ss_cur_bg;
8607e580c6eSjklos 
8617e580c6eSjklos 	curscr = ss;
8627e580c6eSjklos 	return (0);
8637e580c6eSjklos }
8647e580c6eSjklos 
8657e580c6eSjklos static int
lcg_get_cmap(struct wsdisplay_cmap * p)8667e580c6eSjklos lcg_get_cmap(struct wsdisplay_cmap *p)
8677e580c6eSjklos {
8687e580c6eSjklos 	u_int index = p->index, count = p->count;
8697e580c6eSjklos 	int error;
8707e580c6eSjklos 
8717e580c6eSjklos 	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
8727e580c6eSjklos 		return (EINVAL);
8737e580c6eSjklos 
8747e580c6eSjklos 	error = copyout(&lcg_cmap.r[index], p->red, count);
8757e580c6eSjklos 	if (error)
8767e580c6eSjklos 		return error;
8777e580c6eSjklos 	error = copyout(&lcg_cmap.g[index], p->green, count);
8787e580c6eSjklos 	if (error)
8797e580c6eSjklos 		return error;
8807e580c6eSjklos 	error = copyout(&lcg_cmap.b[index], p->blue, count);
8817e580c6eSjklos 	return error;
8827e580c6eSjklos }
8837e580c6eSjklos 
8847e580c6eSjklos static int
lcg_set_cmap(struct wsdisplay_cmap * p)8857e580c6eSjklos lcg_set_cmap(struct wsdisplay_cmap *p)
8867e580c6eSjklos {
8877e580c6eSjklos 	u_int index = p->index, count = p->count;
8887e580c6eSjklos 	int error, s;
8897e580c6eSjklos 
8907e580c6eSjklos 	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
8917e580c6eSjklos 		return (EINVAL);
8927e580c6eSjklos 
8937e580c6eSjklos 	error = copyin(p->red, &lcg_cmap.r[index], count);
8947e580c6eSjklos 	if (error)
8957e580c6eSjklos 		return error;
8967e580c6eSjklos 	error = copyin(p->green, &lcg_cmap.g[index], count);
8977e580c6eSjklos 	if (error)
8987e580c6eSjklos 		return error;
8997e580c6eSjklos 	error = copyin(p->blue, &lcg_cmap.b[index], count);
9007e580c6eSjklos 	if (error)
9017e580c6eSjklos 		return error;
9027e580c6eSjklos 
9037e580c6eSjklos 	s = spltty();
9047e580c6eSjklos 	/* FIXME: if this is meant to set palette LUT reload has to be triggered too */
9057e580c6eSjklos 	while (count-- > 0) {
9067e580c6eSjklos 		lutaddr[index * 8 + 0] = 0;
9077e580c6eSjklos 		lutaddr[index * 8 + 1] = index;
9087e580c6eSjklos 		lutaddr[index * 8 + 2] = 1;
9097e580c6eSjklos 		lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7);
9107e580c6eSjklos 		lutaddr[index * 8 + 4] = 1;
9117e580c6eSjklos 		lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7);
9127e580c6eSjklos 		lutaddr[index * 8 + 6] = 1;
9137e580c6eSjklos 		lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7);
9147e580c6eSjklos 		++index;
9157e580c6eSjklos 	}
9167e580c6eSjklos 	splx(s);
9177e580c6eSjklos 	return (0);
9187e580c6eSjklos }
9197e580c6eSjklos 
9207e580c6eSjklos cons_decl(lcg);
9217e580c6eSjklos 
9227e580c6eSjklos void
lcgcninit(struct consdev * cndev)9237e580c6eSjklos lcgcninit(struct consdev *cndev)
9247e580c6eSjklos {
9257e580c6eSjklos 	int i;
9267e580c6eSjklos 	/* Clear screen */
9277e580c6eSjklos 	memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize);
9287e580c6eSjklos 
9297e580c6eSjklos 	curscr = &lcg_conscreen;
9307e580c6eSjklos 	for (i = 0; i < lcg_cols * lcg_rows; ++i)
9317e580c6eSjklos 		lcg_conscreen.ss_image[i].attr =
9327e580c6eSjklos 		    (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
9337e580c6eSjklos 	wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0,
9347e580c6eSjklos 	    (LCG_BG_COLOR << 4) | LCG_FG_COLOR);
9357e580c6eSjklos 	cn_tab->cn_pri = CN_INTERNAL;
9367e580c6eSjklos 
9377e580c6eSjklos 
9387e580c6eSjklos #if NDZKBD > 0
9397e580c6eSjklos 	dzkbd_cnattach(0); /* Connect keyboard and screen together */
9407e580c6eSjklos #endif
9417e580c6eSjklos }
9427e580c6eSjklos 
9437e580c6eSjklos /*
9447e580c6eSjklos  * Called very early to setup the glass tty as console.
9457e580c6eSjklos  * Because it's called before the VM system is inited, virtual memory
9467e580c6eSjklos  * for the framebuffer can be stolen directly without disturbing anything.
9477e580c6eSjklos  */
9487e580c6eSjklos void
lcgcnprobe(struct consdev * cndev)9497e580c6eSjklos lcgcnprobe(struct consdev *cndev)
9507e580c6eSjklos {
9517e580c6eSjklos 	extern const struct cdevsw wsdisplay_cdevsw;
9527e580c6eSjklos 
9537e580c6eSjklos 	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
9547e580c6eSjklos 		return; /* Only for VS 4000/60 and VLC */
9557e580c6eSjklos 
9567e580c6eSjklos 	if (vax_confdata & 0x100)
9577e580c6eSjklos 		return; /* Diagnostic console */
9587e580c6eSjklos 
9597e580c6eSjklos 	lcg_init_common(NULL, NULL);
9607e580c6eSjklos 
9617e580c6eSjklos 	/* Set up default LUT */
9627e580c6eSjklos 
9637e580c6eSjklos 	cndev->cn_pri = CN_INTERNAL;
9647e580c6eSjklos 	cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
9657e580c6eSjklos }
9667e580c6eSjklos 
9677e580c6eSjklos void
lcg_init_common(struct device * self,struct vsbus_attach_args * va)9687e580c6eSjklos lcg_init_common(struct device *self, struct vsbus_attach_args *va)
9697e580c6eSjklos {
9707e580c6eSjklos 	u_int magic, *lcg_config;
9717e580c6eSjklos 	int i;
9727e580c6eSjklos 	extern vaddr_t virtual_avail;
9737e580c6eSjklos 	long video_conf;
9747e580c6eSjklos 	int cookie;
9757e580c6eSjklos 	struct wsdisplay_font *wf;
9767e580c6eSjklos 
9777e580c6eSjklos 	struct lcg_softc *sc = (void *)self;
9787e580c6eSjklos 	bus_dma_segment_t seg;
9797e580c6eSjklos 	int rseg, err;
9807e580c6eSjklos 	void *fifo_mem_vaddr;
9817e580c6eSjklos #ifndef LCG_NO_ACCEL
9827e580c6eSjklos 	u_char line;
9837e580c6eSjklos 	u_int ch, temp;
9847e580c6eSjklos #endif
9857e580c6eSjklos 
9867e580c6eSjklos 	if (regaddr != NULL)
9877e580c6eSjklos 		return;
9887e580c6eSjklos 
9897e580c6eSjklos 	/* map LCG registers first */
9907e580c6eSjklos 	if (self != NULL) {
9917e580c6eSjklos 		regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
9927e580c6eSjklos 		if (regaddr == 0) {
9933aa5a3aeSriastradh 			device_printf(self,
9943aa5a3aeSriastradh 			    "Couldn't allocate register memory.\n");
9957e580c6eSjklos 			return;
9967e580c6eSjklos 		}
9977e580c6eSjklos 	} else {
9987e580c6eSjklos 		regaddr = (long*)virtual_avail;
9997e580c6eSjklos 		virtual_avail += LCG_REG_SIZE;
10007e580c6eSjklos 		ioaccess((vaddr_t)regaddr, LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
10017e580c6eSjklos 	}
10027e580c6eSjklos 
10037e580c6eSjklos 	/*
10047e580c6eSjklos 	 * v = *0x200f0010 & VLC ? 0x07 : 0xf0;
10057e580c6eSjklos 	 * switch(v) {
10067e580c6eSjklos 	 * 0x05: 1280x1024
10077e580c6eSjklos 	 * 0x06: conf & 0x80 ? 1024x768 : 640x480
10087e580c6eSjklos 	 * 0x07: conf & 0x80 ? 1024x768 ? 1024x864
10097e580c6eSjklos 	 * 0x20: 1024x864
10107e580c6eSjklos 	 * 0x40: 1024x768
10117e580c6eSjklos 	 * 0x60: 1024x864
10127e580c6eSjklos 	 * 0x80: 1280x1024 4BPN
10137e580c6eSjklos 	 * 0x90: 1280x1024 8BPN
10147e580c6eSjklos 	 * 0xb0: 1280x1024 8BPN 2HD
10157e580c6eSjklos 	 */
10167e580c6eSjklos 	if (self != NULL) {
10177e580c6eSjklos 		lcg_config = (u_int *)vax_map_physmem(LCG_CONFIG, 1);
10187e580c6eSjklos 	} else {
10197e580c6eSjklos 		lcg_config = (u_int *)virtual_avail;
10207e580c6eSjklos 		ioaccess((vaddr_t)lcg_config, LCG_CONFIG, 1);
10217e580c6eSjklos 	}
10227e580c6eSjklos 	magic = *lcg_config & (vax_boardtype == VAX_BTYP_46 ? 0xf0 : 0x07);
10237e580c6eSjklos 	if (self != NULL) {
10247e580c6eSjklos 		vax_unmap_physmem((vaddr_t)lcg_config, 1);
10257e580c6eSjklos 	} else {
10267e580c6eSjklos 		iounaccess((vaddr_t)lcg_config, 1);
10277e580c6eSjklos 	}
10287e580c6eSjklos 	lcg_depth = 8;
10297e580c6eSjklos 	switch(magic) {
10307e580c6eSjklos 	case 0x80:		/* KA46 HR 1280x1024 4BPLN */
10317e580c6eSjklos 		lcg_depth = 4;
10327e580c6eSjklos 	case 0x05:		/* KA48 HR 1280x1024 8BPLN */
10337e580c6eSjklos 	case 0x90:		/* KA46 HR 1280x1024 8BPLN */
10347e580c6eSjklos 	case 0xb0:		/* KA46 HR 1280x1024 8BPLN 2HD */
10357e580c6eSjklos 		lcg_xsize = 1280;
10367e580c6eSjklos 		lcg_ysize = 1024;
10377e580c6eSjklos 		break;
10387e580c6eSjklos 	case 0x06:		/* KA48 1024x768 or 640x480 */
10397e580c6eSjklos 		if (vax_confdata & 0x80) {
10407e580c6eSjklos 			lcg_xsize = 1024;
10417e580c6eSjklos 			lcg_ysize = 768;
10427e580c6eSjklos 		} else {
10437e580c6eSjklos 			lcg_xsize = 640;
10447e580c6eSjklos 			lcg_ysize = 480;
10457e580c6eSjklos 		}
10467e580c6eSjklos 		break;
10477e580c6eSjklos 	case 0x07:		/* KA48 1024x768 or 1024x864 */
10487e580c6eSjklos 		lcg_xsize = 1024;
10497e580c6eSjklos 		lcg_ysize = (vax_confdata & 0x80) ? 768 : 864;
10507e580c6eSjklos 		break;
10517e580c6eSjklos 	case 0x20:		/* KA46 1024x864 */
10527e580c6eSjklos 	case 0x60:		/* KA46 1024x864 */
10537e580c6eSjklos 		lcg_xsize = 1024;
10547e580c6eSjklos 		lcg_ysize = 864;
10557e580c6eSjklos 		break;
10567e580c6eSjklos 	case 0x40:		/* KA46 1024x768 */
10577e580c6eSjklos 		lcg_xsize = 1024;
10587e580c6eSjklos 		lcg_ysize = 768;
10597e580c6eSjklos 		break;
10607e580c6eSjklos 	default:
10617e580c6eSjklos 		panic("LCG model not supported");
10627e580c6eSjklos 	}
10637e580c6eSjklos 	if (self != NULL)
10643aa5a3aeSriastradh 		aprint_normal_dev(self,
10653aa5a3aeSriastradh 		    "framebuffer size %dx%d, depth %d (magic 0x%x)\n",
10663aa5a3aeSriastradh 		    lcg_xsize, lcg_ysize, lcg_depth, magic);
10677e580c6eSjklos 
10687e580c6eSjklos 	wsfont_init();
10697e580c6eSjklos 	cookie = wsfont_find(NULL, 12, 22, 0, WSDISPLAY_FONTORDER_R2L,
10707e580c6eSjklos 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
10717e580c6eSjklos 	if (cookie == -1)
10727e580c6eSjklos 		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 0,
10737e580c6eSjklos 				WSFONT_FIND_BITMAP);
10747e580c6eSjklos 	if (cookie == -1)
10757e580c6eSjklos 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
10767e580c6eSjklos 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
10777e580c6eSjklos 	if (cookie == -1 || wsfont_lock(cookie, &wf))
10787e580c6eSjklos 		panic("lcg_common_init: can't load console font");
10797e580c6eSjklos 	lcg_font = *wf;
10807e580c6eSjklos 	lcg_cols = lcg_xsize / lcg_font.fontwidth;
10817e580c6eSjklos 	lcg_rows = lcg_ysize / lcg_font.fontheight;
10827e580c6eSjklos 	if (self != NULL) {
10833aa5a3aeSriastradh 		aprint_normal_dev(self, "using font %s (%dx%d), ",
10843aa5a3aeSriastradh 		    lcg_font.name,
10857e580c6eSjklos 		    lcg_font.fontwidth, lcg_font.fontheight);
10867e580c6eSjklos 		aprint_normal("console size: %dx%d\n", lcg_cols, lcg_rows);
10877e580c6eSjklos 	}
10887e580c6eSjklos 	lcg_onerow = lcg_xsize * lcg_font.fontheight;
10897e580c6eSjklos 	lcg_fb_size = lcg_xsize * lcg_ysize;
10907e580c6eSjklos 	lcg_stdscreen.ncols = lcg_cols;
10917e580c6eSjklos 	lcg_stdscreen.nrows = lcg_rows;
10927e580c6eSjklos 	lcg_stdscreen.fontwidth = lcg_font.fontwidth;
10937e580c6eSjklos 	lcg_stdscreen.fontheight = lcg_font.fontheight;
10947e580c6eSjklos 	lcg_glyph_size = lcg_font.stride * lcg_font.fontheight;
10957e580c6eSjklos 	snprintf(lcg_stdscreen_name, sizeof(lcg_stdscreen_name), "%dx%d", lcg_cols, lcg_rows);
10967e580c6eSjklos 	qf = lcg_font.data;
10977e580c6eSjklos 	qf2 = (u_short *)lcg_font.data;
10987e580c6eSjklos 
10997e580c6eSjklos 	if (self != NULL) {
11007e580c6eSjklos 		lcgaddr = (void *)vax_map_physmem(va->va_paddr,
11017e580c6eSjklos 					((lcg_fb_size + LCG_FONT_STORAGE_SIZE)/VAX_NBPG));
11027e580c6eSjklos 		if (lcgaddr == 0) {
11033aa5a3aeSriastradh 			device_printf(self,
11043aa5a3aeSriastradh 			    "unable to allocate framebuffer memory.\n");
11057e580c6eSjklos 			return;
11067e580c6eSjklos 		}
11077e580c6eSjklos #ifndef LCG_NO_ACCEL
11087e580c6eSjklos 		fontaddr = lcgaddr + lcg_fb_size;
11097e580c6eSjklos 
11107e580c6eSjklos 		/* copy font bitmaps */
11117e580c6eSjklos 		for (ch = 0; ch < 256; ch++)
11127e580c6eSjklos 			for (line = 0; line < lcg_font.fontheight; line++) {
11137e580c6eSjklos 				temp = QFONT(ch, line);
11147e580c6eSjklos 				if (lcg_font.stride == 1)
11157e580c6eSjklos 					fontaddr[(ch * lcg_font.fontheight) + line] = temp;
11167e580c6eSjklos 				else {
11177e580c6eSjklos 					/* stride == 2 */
11187e580c6eSjklos 					fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line] = temp & 0xff;
11197e580c6eSjklos 					fontaddr[(ch * lcg_font.stride * lcg_font.fontheight) + line + 1] = (temp >> 16) & 0xff;
11207e580c6eSjklos 				}
11217e580c6eSjklos 			}
11227e580c6eSjklos #endif
11237e580c6eSjklos 
11247e580c6eSjklos 		lutaddr = (void *)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
11257e580c6eSjklos 		if (lutaddr == 0) {
11263aa5a3aeSriastradh 			device_printf(self,
11273aa5a3aeSriastradh 			    "unable to allocate LUT memory.\n");
11287e580c6eSjklos 			return;
11297e580c6eSjklos 		}
11307e580c6eSjklos 		fifoaddr = (long*)vax_map_physmem(LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG));
11317e580c6eSjklos 		if (regaddr == 0) {
11323aa5a3aeSriastradh 			device_printf(self, "unable to map FIFO window\n");
11337e580c6eSjklos 			return;
11347e580c6eSjklos 		}
11357e580c6eSjklos 
11367e580c6eSjklos 		/* allocate contiguous physical memory block for FIFO */
11377e580c6eSjklos 		err = bus_dmamem_alloc(va->va_dmat, LCG_FIFO_SIZE,
11387e580c6eSjklos 			LCG_FIFO_ALIGN, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
11397e580c6eSjklos 		if (err) {
11403aa5a3aeSriastradh 			device_printf(self,
11413aa5a3aeSriastradh 			    "unable to allocate FIFO memory block, err = %d\n",
11423aa5a3aeSriastradh 			    err);
11437e580c6eSjklos 			return;
11447e580c6eSjklos 		}
11457e580c6eSjklos 
11467e580c6eSjklos 		err = bus_dmamem_map(va->va_dmat, &seg, rseg, LCG_FIFO_SIZE,
11477e580c6eSjklos 			&fifo_mem_vaddr, BUS_DMA_NOWAIT);
11487e580c6eSjklos 		if (err) {
11493aa5a3aeSriastradh 			device_printf(self,
11503aa5a3aeSriastradh 			    "unable to map FIFO memory block, err = %d\n",
11513aa5a3aeSriastradh 			    err);
11527e580c6eSjklos 			bus_dmamem_free(va->va_dmat, &seg, rseg);
11537e580c6eSjklos 			return;
11547e580c6eSjklos 		}
11557e580c6eSjklos 
11567e580c6eSjklos 		err = bus_dmamap_create(va->va_dmat, LCG_FIFO_SIZE, rseg,
11577e580c6eSjklos 			LCG_FIFO_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dm);
11587e580c6eSjklos 		if (err) {
11593aa5a3aeSriastradh 			device_printf(self,
11603aa5a3aeSriastradh 			    "unable to create DMA map, err = %d\n",
11613aa5a3aeSriastradh 			    err);
11627e580c6eSjklos 			bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE);
11637e580c6eSjklos 			bus_dmamem_free(va->va_dmat, &seg, rseg);
11647e580c6eSjklos 			return;
11657e580c6eSjklos 		}
11667e580c6eSjklos 
11677e580c6eSjklos 		err = bus_dmamap_load(va->va_dmat, sc->sc_dm, fifo_mem_vaddr,
11687e580c6eSjklos 			LCG_FIFO_SIZE, NULL, BUS_DMA_NOWAIT);
11697e580c6eSjklos 		if (err) {
11703aa5a3aeSriastradh 			device_printf(self,
11713aa5a3aeSriastradh 			    "unable to load DMA map, err = %d\n",
11723aa5a3aeSriastradh 			    err);
11737e580c6eSjklos 			bus_dmamap_destroy(va->va_dmat, sc->sc_dm);
11747e580c6eSjklos 			bus_dmamem_unmap(va->va_dmat, fifo_mem_vaddr, LCG_FIFO_SIZE);
11757e580c6eSjklos 			bus_dmamem_free(va->va_dmat, &seg, rseg);
11767e580c6eSjklos 			return;
11777e580c6eSjklos 		}
11787e580c6eSjklos 
11797e580c6eSjklos 		/* initialize LCG hardware */
11807e580c6eSjklos 		LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0xd8000000; /* gfx reset, FIFO and AG enable */
11817e580c6eSjklos //		LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = (((LCG_FB_ADDR + lcg_fb_size) & 0xffff0000) | (LCG_FB_ADDR >> 16));
11827e580c6eSjklos 		LCG_REG(LCG_REG_WRITE_PROTECT_LOW_HIGH) = 0xffff0000;
11837e580c6eSjklos 		LCG_REG(LCG_REG_FIFO_BASE) = sc->sc_dm->dm_segs[0].ds_addr;
11847e580c6eSjklos 		LCG_REG(LCG_REG_FIFO_BASE2) = sc->sc_dm->dm_segs[0].ds_addr;
11857e580c6eSjklos 		LCG_REG(LCG_REG_FIFO_MASKS) = 0xffff;
11867e580c6eSjklos 		LCG_REG(LCG_REG_FIFO_SAVE_HEAD_OFFSET) = sc->sc_dm->dm_segs[0].ds_addr;
11877e580c6eSjklos //		LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0;
11887e580c6eSjklos //		LCG_REG(LCG_REG_GRAPHICS_CONTROL) = 0x50000000; /* FIFO and AG enable */
11897e580c6eSjklos 		LCG_REG(LCG_REG_GRAPHICS_INT_STATUS) = 0xffffffff;
11907e580c6eSjklos 		LCG_REG(LCG_REG_GRAPHICS_INT_SET_ENABLE) = 0;
11917e580c6eSjklos 		LCG_REG(LCG_REG_GRAPHICS_INT_CLR_ENABLE) = 0xffffffff;
11927e580c6eSjklos 		LCG_REG(LCG_REG_LCG_GO) = 3; /* FIFO and AG go */
11937e580c6eSjklos //		LCG_REG(LCG_REG_BREAKPT_ADDRESS) = 0x2fffffff;
11947e580c6eSjklos 
11957e580c6eSjklos 	} else {
11967e580c6eSjklos 		lcgaddr = (void *)virtual_avail;
11977e580c6eSjklos 		virtual_avail += lcg_fb_size + LCG_FONT_STORAGE_SIZE;
11987e580c6eSjklos 		ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG));
11997e580c6eSjklos 
12007e580c6eSjklos 		lutaddr = (void *)virtual_avail;
12017e580c6eSjklos 		virtual_avail += LCG_LUT_SIZE;
12027e580c6eSjklos 		ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
12037e580c6eSjklos 
12047e580c6eSjklos 		fifoaddr = (long*)virtual_avail;
12057e580c6eSjklos 		virtual_avail += LCG_FIFO_WIN_SIZE;
12067e580c6eSjklos 		ioaccess((vaddr_t)fifoaddr, LCG_FIFO_WIN_ADDR, (LCG_FIFO_WIN_SIZE/VAX_NBPG));
12077e580c6eSjklos 	}
12087e580c6eSjklos 
12097e580c6eSjklos 	bzero(lutaddr, LCG_LUT_SIZE);
12107e580c6eSjklos 	for (i = 0; i < 8; ++i) {
12117e580c6eSjklos 		lcg_cmap.r[i] = lcg_default_cmap.r[i];
12127e580c6eSjklos 		lcg_cmap.g[i] = lcg_default_cmap.g[i];
12137e580c6eSjklos 		lcg_cmap.b[i] = lcg_default_cmap.b[i];
12147e580c6eSjklos 		lutaddr[i * 8 + 1] = i;
12157e580c6eSjklos 		lutaddr[i * 8 + 2] = 1;
12167e580c6eSjklos 		lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
12177e580c6eSjklos 		lutaddr[i * 8 + 4] = 1;
12187e580c6eSjklos 		lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
12197e580c6eSjklos 		lutaddr[i * 8 + 6] = 1;
12207e580c6eSjklos 		lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
12217e580c6eSjklos 	}
12227e580c6eSjklos 
12237e580c6eSjklos 	/*
12247e580c6eSjklos 	 * 0xf100165b 4000/60
12257e580c6eSjklos 	 * 1111 0001 0000 0000 0001 0110 0101 1011
12267e580c6eSjklos 	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
12277e580c6eSjklos 	 * 3322 2222 2222 1111 1111 11
12287e580c6eSjklos 	 * 1098 7654 3210 9876 5432 1098 7654 3210
12297e580c6eSjklos 	 *
12307e580c6eSjklos  	 * 0xf1001d7b 4000/VLC
12317e580c6eSjklos 	 * 1111 0001 0000 0000 0001 1101 0111 1011
12327e580c6eSjklos 	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
12337e580c6eSjklos 	 * 3322 2222 2222 1111 1111 11
12347e580c6eSjklos 	 * 1098 7654 3210 9876 5432 1098 7654 3210
12357e580c6eSjklos 	 *
12367e580c6eSjklos 	 * 31-30     11 Vertical state
12377e580c6eSjklos 	 * 29-38     11 Horizontal state
12387e580c6eSjklos 	 * 27-26     00
12397e580c6eSjklos 	 * 25         0 console LUT select
12407e580c6eSjklos 	 * 24         1 control LUT select
12417e580c6eSjklos 	 * 23         0
12427e580c6eSjklos 	 * 22         0 cursor active
12437e580c6eSjklos 	 * 21-16 000000
12447e580c6eSjklos 	 * 15         0 video subsystem reset
12457e580c6eSjklos 	 * 14         0
12467e580c6eSjklos 	 * 13         0 LUT load size 2KB
12477e580c6eSjklos 	 * 12         1 enable H sync
12487e580c6eSjklos 	 * 11         0 Full LUT load		 1
12497e580c6eSjklos 	 * 10         1 video clock select
12507e580c6eSjklos 	 *  9- 8     10 memory refresh rate	01
12517e580c6eSjklos 	 *  7- 6     01 video refresh rate
12527e580c6eSjklos 	 *  5         0 load select		 1
12537e580c6eSjklos 	 *  4         1 read cursor output
12547e580c6eSjklos 	 *  3         1 LUT load enable
12557e580c6eSjklos 	 *  2         0 cursor enable
12567e580c6eSjklos 	 *  1         1 video enable
12577e580c6eSjklos 	 *  0         1 refresh clock enable
12587e580c6eSjklos 	 */
1259a299e660Sandvar 	/* prepare video_config reg for LUT reload */
12607e580c6eSjklos 	video_conf
12617e580c6eSjklos 		 = (3 << 30) /* vertical state */
12627e580c6eSjklos 		 | (3 << 28) /* horizontal state */
12637e580c6eSjklos 		 | (0 << 26) /* unused */
12647e580c6eSjklos 		 | (0 << 25) /* console LUT select */
12657e580c6eSjklos 		 | (0 << 24) /* control LUT select */
12667e580c6eSjklos 		 | (0 << 23) /* unused */
12677e580c6eSjklos 		 | (0 << 22) /* cursor active */
12687e580c6eSjklos 		 | (0 << 16) /* current cursor scanline showing */
12697e580c6eSjklos 		 | (0 << 15) /* video subsystem reset */
12707e580c6eSjklos 		 | (0 << 14) /* unused */
12717e580c6eSjklos 		 | (1 << 13) /* LUT load size 2 KB */
12727e580c6eSjklos 		 | (1 << 12) /* enable horizontal sync */
12737e580c6eSjklos 		 | (1 << 10) /* video clock select */
12747e580c6eSjklos 		 | (1 << 6) /* video refresh select */
1275a299e660Sandvar 		 | (1 << 4) /* read cursor output */
12767e580c6eSjklos 		 | (1 << 3) /* LUT load enable */
12777e580c6eSjklos 		 | (0 << 2) /* cursor enable */
12787e580c6eSjklos 		 | (1 << 1) /* video enable */
12797e580c6eSjklos 		 | (1 << 0); /* refresh clock enable */
12807e580c6eSjklos 	/* FIXME needs updating for all supported models */
12817e580c6eSjklos 	if (lcg_xsize == 1280) {		/* 4000/60 HR 4PLN */
12827e580c6eSjklos 		video_conf |= (0 << 11); /* split LUT load */
12837e580c6eSjklos 		video_conf |= (2 << 8); /* memory refresh select */
12847e580c6eSjklos 		video_conf |= (0 << 5); /* split shift register load */
12857e580c6eSjklos 	} else {				/* 4000/VLC LR 8PLN */
12867e580c6eSjklos 		video_conf |= (1 << 11); /* Full LUT load */
12877e580c6eSjklos 		video_conf |= (1 << 8); /* memory refresh select */
12887e580c6eSjklos 		video_conf |= (1 << 5); /* split shift register load */
12897e580c6eSjklos 	}
12907e580c6eSjklos 
12917e580c6eSjklos 	LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf;
12927e580c6eSjklos 	/* vital !!! */
12937e580c6eSjklos 	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1;
12947e580c6eSjklos 	LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET;
12957e580c6eSjklos 
12967e580c6eSjklos 	delay(1000);
12977e580c6eSjklos 	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0;
12987e580c6eSjklos 
12997e580c6eSjklos #ifdef LCG_DEBUG
13007e580c6eSjklos 	if (self != NULL)
13013aa5a3aeSriastradh 		device_printf(self, "video config register set 0x%08lx\n",
13023aa5a3aeSriastradh 		    video_conf);
13037e580c6eSjklos #endif
13047e580c6eSjklos }
1305