xref: /netbsd-src/sys/dev/sun/cgsix.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: cgsix.c,v 1.65 2014/07/25 08:10:39 dholland Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1993
34  *	The Regents of the University of California.  All rights reserved.
35  *
36  * This software was developed by the Computer Systems Engineering group
37  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
38  * contributed to Berkeley.
39  *
40  * All advertising materials mentioning features or use of this software
41  * must display the following acknowledgement:
42  *	This product includes software developed by the University of
43  *	California, Lawrence Berkeley Laboratory.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 3. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  *
69  *	@(#)cgsix.c	8.4 (Berkeley) 1/21/94
70  */
71 
72 /*
73  * color display (cgsix) driver.
74  *
75  * Does not handle interrupts, even though they can occur.
76  *
77  * XXX should defer colormap updates to vertical retrace interrupts
78  */
79 
80 #include <sys/cdefs.h>
81 __KERNEL_RCSID(0, "$NetBSD: cgsix.c,v 1.65 2014/07/25 08:10:39 dholland Exp $");
82 
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/buf.h>
86 #include <sys/device.h>
87 #include <sys/ioctl.h>
88 #include <sys/malloc.h>
89 #include <sys/mman.h>
90 #include <sys/tty.h>
91 #include <sys/conf.h>
92 
93 #ifdef DEBUG
94 #include <sys/proc.h>
95 #include <sys/syslog.h>
96 #endif
97 
98 #include <sys/bus.h>
99 
100 #include <dev/sun/fbio.h>
101 #include <dev/sun/fbvar.h>
102 
103 #include <dev/sun/btreg.h>
104 #include <dev/sun/btvar.h>
105 #include <dev/sun/pfourreg.h>
106 
107 #include <dev/wscons/wsconsio.h>
108 #include <dev/wsfont/wsfont.h>
109 #include <dev/rasops/rasops.h>
110 
111 #include "opt_wsemul.h"
112 #include "rasops_glue.h"
113 
114 #include <dev/sun/cgsixreg.h>
115 #include <dev/sun/cgsixvar.h>
116 
117 #include "ioconf.h"
118 
119 static void	cg6_unblank(device_t);
120 static void	cg6_blank(struct cgsix_softc *, int);
121 
122 dev_type_open(cgsixopen);
123 dev_type_close(cgsixclose);
124 dev_type_ioctl(cgsixioctl);
125 dev_type_mmap(cgsixmmap);
126 
127 const struct cdevsw cgsix_cdevsw = {
128 	.d_open = cgsixopen,
129 	.d_close = cgsixclose,
130 	.d_read = noread,
131 	.d_write = nowrite,
132 	.d_ioctl = cgsixioctl,
133 	.d_stop = nostop,
134 	.d_tty = notty,
135 	.d_poll = nopoll,
136 	.d_mmap = cgsixmmap,
137 	.d_kqfilter = nokqfilter,
138 	.d_discard = nodiscard,
139 	.d_flag = D_OTHER
140 };
141 
142 /* frame buffer generic driver */
143 static struct fbdriver cg6_fbdriver = {
144 	cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, nopoll, cgsixmmap,
145 	nokqfilter
146 };
147 
148 static void cg6_reset (struct cgsix_softc *);
149 static void cg6_loadcmap (struct cgsix_softc *, int, int);
150 static void cg6_loadomap (struct cgsix_softc *);
151 static void cg6_setcursor (struct cgsix_softc *);/* set position */
152 static void cg6_loadcursor (struct cgsix_softc *);/* set shape */
153 
154 #if NWSDISPLAY > 0
155 #ifdef RASTERCONSOLE
156 #error RASTERCONSOLE and wsdisplay are mutually exclusive
157 #endif
158 
159 static void cg6_setup_palette(struct cgsix_softc *);
160 
161 struct wsscreen_descr cgsix_defaultscreen = {
162 	"std",
163 	0, 0,	/* will be filled in -- XXX shouldn't, it's global */
164 	NULL,		/* textops */
165 	8, 16,	/* font width/height */
166 	WSSCREEN_WSCOLORS,	/* capabilities */
167 	NULL	/* modecookie */
168 };
169 
170 static int 	cgsix_ioctl(void *, void *, u_long, void *, int, struct lwp *);
171 static paddr_t	cgsix_mmap(void *, void *, off_t, int);
172 static void	cgsix_init_screen(void *, struct vcons_screen *, int, long *);
173 
174 static void	cgsix_clearscreen(struct cgsix_softc *);
175 
176 void 	cgsix_setup_mono(struct cgsix_softc *, int, int, int, int, uint32_t,
177 		uint32_t);
178 void 	cgsix_feed_line(struct cgsix_softc *, int, uint8_t *);
179 void 	cgsix_rectfill(struct cgsix_softc *, int, int, int, int, uint32_t);
180 void	cgsix_bitblt(void *, int, int, int, int, int, int, int);
181 
182 int	cgsix_putcmap(struct cgsix_softc *, struct wsdisplay_cmap *);
183 int	cgsix_getcmap(struct cgsix_softc *, struct wsdisplay_cmap *);
184 void	cgsix_putchar(void *, int, int, u_int, long);
185 void	cgsix_putchar_aa(void *, int, int, u_int, long);
186 void	cgsix_cursor(void *, int, int, int);
187 
188 struct wsdisplay_accessops cgsix_accessops = {
189 	cgsix_ioctl,
190 	cgsix_mmap,
191 	NULL,	/* alloc_screen */
192 	NULL,	/* free_screen */
193 	NULL,	/* show_screen */
194 	NULL, 	/* load_font */
195 	NULL,	/* pollc */
196 	NULL	/* scroll */
197 };
198 
199 const struct wsscreen_descr *_cgsix_scrlist[] = {
200 	&cgsix_defaultscreen
201 };
202 
203 struct wsscreen_list cgsix_screenlist = {
204 	sizeof(_cgsix_scrlist) / sizeof(struct wsscreen_descr *),
205 	_cgsix_scrlist
206 };
207 
208 
209 extern const u_char rasops_cmap[768];
210 
211 #endif /* NWSDISPLAY > 0 */
212 
213 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
214 void	cg6_invert(struct cgsix_softc *, int, int, int, int);
215 
216 /* need this for both cases because ri_hw points to it */
217 static struct vcons_screen cg6_console_screen;
218 #endif
219 
220 #ifdef RASTERCONSOLE
221 int cgsix_use_rasterconsole = 1;
222 #endif
223 
224 /*
225  * cg6 accelerated console routines.
226  *
227  * Note that buried in this code in several places is the assumption
228  * that pixels are exactly one byte wide.  Since this is cg6-specific
229  * code, this seems safe.  This assumption resides in things like the
230  * use of ri_emuwidth without messing around with ri_pelbytes, or the
231  * assumption that ri_font->fontwidth is the right thing to multiply
232  * character-cell counts by to get byte counts.
233  */
234 
235 /*
236  * Magic values for blitter
237  */
238 
239 /* Values for the mode register */
240 #define CG6_MODE	(						\
241 	  0x00200000 /* GX_BLIT_SRC */					\
242 	| 0x00020000 /* GX_MODE_COLOR8 */				\
243 	| 0x00008000 /* GX_DRAW_RENDER */				\
244 	| 0x00002000 /* GX_BWRITE0_ENABLE */				\
245 	| 0x00001000 /* GX_BWRITE1_DISABLE */				\
246 	| 0x00000200 /* GX_BREAD_0 */					\
247 	| 0x00000080 /* GX_BDISP_0 */					\
248 )
249 #define CG6_MODE_MASK	(						\
250 	  0x00300000 /* GX_BLIT_ALL */					\
251 	| 0x00060000 /* GX_MODE_ALL */					\
252 	| 0x00018000 /* GX_DRAW_ALL */					\
253 	| 0x00006000 /* GX_BWRITE0_ALL */				\
254 	| 0x00001800 /* GX_BWRITE1_ALL */				\
255 	| 0x00000600 /* GX_BREAD_ALL */					\
256 	| 0x00000180 /* GX_BDISP_ALL */					\
257 )
258 
259 /* Value for the alu register for screen-to-screen copies */
260 #define CG6_ALU_COPY	(						\
261 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
262 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
263 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
264 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
265 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
266 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
267 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
268 	| 0x0000cccc /* ALU = src */					\
269 )
270 
271 /* Value for the alu register for region fills */
272 #define CG6_ALU_FILL	(						\
273 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
274 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
275 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
276 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
277 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
278 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
279 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
280 	| 0x0000ff00 /* ALU = fg color */				\
281 )
282 
283 /* Value for the alu register for toggling an area */
284 #define CG6_ALU_FLIP	(						\
285 	  0x80000000 /* GX_PLANE_ONES (ignore planemask register) */	\
286 	| 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */	\
287 	| 0x00800000 /* GX_ATTR_SUPP (function unknown) */		\
288 	| 0x00000000 /* GX_RAST_BOOL (function unknown) */		\
289 	| 0x00000000 /* GX_PLOT_PLOT (function unknown) */		\
290 	| 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */		\
291 	| 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */	\
292 	| 0x00005555 /* ALU = ~dst */					\
293 )
294 
295 /*
296  * Run a blitter command
297  */
298 #define CG6_BLIT(f) { (void)f->fbc_blit; }
299 
300 /*
301  * Run a drawing command
302  */
303 #define CG6_DRAW(f) { (void)f->fbc_draw; }
304 
305 /*
306  * Wait for the whole engine to go idle.  This may not matter in our case;
307  * I'm not sure whether blits are actually queued or not.  It more likely
308  * is intended for lines and such that do get queued.
309  * 0x10000000 bit: GX_INPROGRESS
310  */
311 #define CG6_DRAIN(fbc) do {						\
312 	while ((fbc)->fbc_s & GX_INPROGRESS)				\
313 		/*EMPTY*/;						\
314 } while (0)
315 
316 /*
317  * something is missing here
318  * Waiting for GX_FULL to clear should be enough to send another command
319  * but some CG6 ( LX onboard for example ) lock up if we do that while
320  * it works fine on others ( a 4MB TGX+ I've got here )
321  * So, until I figure out what's going on we wait for the blitter to go
322  * fully idle.
323  */
324 #define CG6_WAIT_READY(fbc) do {					\
325        	while (((fbc)->fbc_s & GX_INPROGRESS/*GX_FULL*/) != 0)		\
326 		/*EMPTY*/;						\
327 } while (0)
328 
329 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
330 static void cg6_ras_init(struct cgsix_softc *);
331 static void cg6_ras_copyrows(void *, int, int, int);
332 static void cg6_ras_copycols(void *, int, int, int, int);
333 static void cg6_ras_erasecols(void *, int, int, int, long int);
334 static void cg6_ras_eraserows(void *, int, int, long int);
335 #if defined(RASTERCONSOLE) && defined(CG6_BLIT_CURSOR)
336 static void cg6_ras_do_cursor(struct rasops_info *);
337 #endif
338 
339 static void
340 cg6_ras_init(struct cgsix_softc *sc)
341 {
342 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
343 
344 	CG6_DRAIN(fbc);
345 	fbc->fbc_mode &= ~CG6_MODE_MASK;
346 	fbc->fbc_mode |= CG6_MODE;
347 
348 	/* set some common drawing engine parameters */
349 	fbc->fbc_clip = 0;
350 	fbc->fbc_s = 0;
351 	fbc->fbc_offx = 0;
352 	fbc->fbc_offy = 0;
353 	fbc->fbc_clipminx = 0;
354 	fbc->fbc_clipminy = 0;
355 	fbc->fbc_clipmaxx = 0x3fff;
356 	fbc->fbc_clipmaxy = 0x3fff;
357 }
358 
359 static void
360 cg6_ras_copyrows(void *cookie, int src, int dst, int n)
361 {
362 	struct rasops_info *ri = cookie;
363 	struct vcons_screen *scr = ri->ri_hw;
364 	struct cgsix_softc *sc = scr->scr_cookie;
365 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
366 
367 	if (dst == src)
368 		return;
369 	if (src < 0) {
370 		n += src;
371 		src = 0;
372 	}
373 	if (src+n > ri->ri_rows)
374 		n = ri->ri_rows - src;
375 	if (dst < 0) {
376 		n += dst;
377 		dst = 0;
378 	}
379 	if (dst+n > ri->ri_rows)
380 		n = ri->ri_rows - dst;
381 	if (n <= 0)
382 		return;
383 	n *= ri->ri_font->fontheight;
384 	src *= ri->ri_font->fontheight;
385 	dst *= ri->ri_font->fontheight;
386 
387 	CG6_WAIT_READY(fbc);
388 
389 	fbc->fbc_alu = CG6_ALU_COPY;
390 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
391 
392 	fbc->fbc_x0 = ri->ri_xorigin;
393 	fbc->fbc_y0 = ri->ri_yorigin + src;
394 	fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1;
395 	fbc->fbc_y1 = ri->ri_yorigin + src + n - 1;
396 	fbc->fbc_x2 = ri->ri_xorigin;
397 	fbc->fbc_y2 = ri->ri_yorigin + dst;
398 	fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1;
399 	fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1;
400 	CG6_BLIT(fbc);
401 }
402 
403 static void
404 cg6_ras_copycols(void *cookie, int row, int src, int dst, int n)
405 {
406 	struct rasops_info *ri = cookie;
407 	struct vcons_screen *scr = ri->ri_hw;
408 	struct cgsix_softc *sc = scr->scr_cookie;
409 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
410 
411 	if (dst == src)
412 		return;
413 	if ((row < 0) || (row >= ri->ri_rows))
414 		return;
415 	if (src < 0) {
416 		n += src;
417 		src = 0;
418 	}
419 	if (src+n > ri->ri_cols)
420 		n = ri->ri_cols - src;
421 	if (dst < 0) {
422 		n += dst;
423 		dst = 0;
424 	}
425 	if (dst+n > ri->ri_cols)
426 		n = ri->ri_cols - dst;
427 	if (n <= 0)
428 		return;
429 	n *= ri->ri_font->fontwidth;
430 	src *= ri->ri_font->fontwidth;
431 	dst *= ri->ri_font->fontwidth;
432 	row *= ri->ri_font->fontheight;
433 
434 	CG6_WAIT_READY(fbc);
435 
436 	fbc->fbc_alu = CG6_ALU_COPY;
437 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
438 
439 	fbc->fbc_x0 = ri->ri_xorigin + src;
440 	fbc->fbc_y0 = ri->ri_yorigin + row;
441 	fbc->fbc_x1 = ri->ri_xorigin + src + n - 1;
442 	fbc->fbc_y1 = ri->ri_yorigin + row +
443 	    ri->ri_font->fontheight - 1;
444 	fbc->fbc_x2 = ri->ri_xorigin + dst;
445 	fbc->fbc_y2 = ri->ri_yorigin + row;
446 	fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1;
447 	fbc->fbc_y3 = ri->ri_yorigin + row +
448 	    ri->ri_font->fontheight - 1;
449 	CG6_BLIT(fbc);
450 }
451 
452 static void
453 cg6_ras_erasecols(void *cookie, int row, int col, int n, long int attr)
454 {
455 	struct rasops_info *ri = cookie;
456 	struct vcons_screen *scr = ri->ri_hw;
457 	struct cgsix_softc *sc = scr->scr_cookie;
458 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
459 
460 	if ((row < 0) || (row >= ri->ri_rows))
461 		return;
462 	if (col < 0) {
463 		n += col;
464 		col = 0;
465 	}
466 	if (col+n > ri->ri_cols)
467 		n = ri->ri_cols - col;
468 	if (n <= 0)
469 		return;
470 	n *= ri->ri_font->fontwidth;
471 	col *= ri->ri_font->fontwidth;
472 	row *= ri->ri_font->fontheight;
473 
474 	CG6_WAIT_READY(fbc);
475 	fbc->fbc_alu = CG6_ALU_FILL;
476 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
477 
478 	fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff];
479 	fbc->fbc_arecty = ri->ri_yorigin + row;
480 	fbc->fbc_arectx = ri->ri_xorigin + col;
481 	fbc->fbc_arecty = ri->ri_yorigin + row +
482 	    ri->ri_font->fontheight - 1;
483 	fbc->fbc_arectx = ri->ri_xorigin + col + n - 1;
484 	CG6_DRAW(fbc);
485 }
486 
487 static void
488 cg6_ras_eraserows(void *cookie, int row, int n, long int attr)
489 {
490 	struct rasops_info *ri = cookie;
491 	struct vcons_screen *scr = ri->ri_hw;
492 	struct cgsix_softc *sc = scr->scr_cookie;
493 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
494 
495 	if (row < 0) {
496 		n += row;
497 		row = 0;
498 	}
499 	if (row+n > ri->ri_rows)
500 		n = ri->ri_rows - row;
501 	if (n <= 0)
502 		return;
503 
504 	CG6_WAIT_READY(fbc);
505 	fbc->fbc_alu = CG6_ALU_FILL;
506 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
507 
508 	fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xff];
509 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
510 		fbc->fbc_arecty = 0;
511 		fbc->fbc_arectx = 0;
512 		fbc->fbc_arecty = ri->ri_height - 1;
513 		fbc->fbc_arectx = ri->ri_width - 1;
514 	} else {
515 		row *= ri->ri_font->fontheight;
516 		fbc->fbc_arecty = ri->ri_yorigin + row;
517 		fbc->fbc_arectx = ri->ri_xorigin;
518 		fbc->fbc_arecty = ri->ri_yorigin + row +
519 		    (n * ri->ri_font->fontheight) - 1;
520 		fbc->fbc_arectx = ri->ri_xorigin + ri->ri_emuwidth - 1;
521 	}
522 	CG6_DRAW(fbc);
523 }
524 
525 #if defined(RASTERCONSOLE) && defined(CG6_BLIT_CURSOR)
526 /*
527  * Really want something more like fg^bg here, but that would be more
528  * or less impossible to migrate to colors.  So we hope there's
529  * something not too inappropriate in the colormap...besides, it's what
530  * the non-accelerated code did. :-)
531  */
532 static void
533 cg6_ras_do_cursor(struct rasops_info *ri)
534 {
535 	struct vcons_screen *scr = ri->ri_hw;
536 	struct cgsix_softc *sc = scr->cookie;
537 	int row, col;
538 
539 	row = ri->ri_crow * ri->ri_font->fontheight;
540 	col = ri->ri_ccol * ri->ri_font->fontwidth;
541 	cg6_invert(sc, ri->ri_xorigin + col,ri->ri_yorigin +
542 	    row, ri->ri_font->fontwidth, ri->ri_font->fontheight);
543 }
544 #endif	/* RASTERCONSOLE */
545 
546 #endif	/* (NWSDISPLAY > 0) || defined(RASTERCONSOLE) */
547 
548 void
549 cg6attach(struct cgsix_softc *sc, const char *name, int isconsole)
550 {
551 	struct fbdevice *fb = &sc->sc_fb;
552 #if NWSDISPLAY > 0
553 	struct wsemuldisplaydev_attach_args aa;
554 	struct rasops_info *ri = &cg6_console_screen.scr_ri;
555 	unsigned long defattr;
556 #endif
557 
558 	fb->fb_driver = &cg6_fbdriver;
559 
560 	/* Don't have to map the pfour register on the cgsix. */
561 	fb->fb_pfour = NULL;
562 
563 	fb->fb_type.fb_cmsize = 256;
564 	fb->fb_type.fb_size = sc->sc_ramsize;
565 
566 	printf(": %s, %d x %d", name,
567 	       fb->fb_type.fb_width, fb->fb_type.fb_height);
568 	if(sc->sc_fhc) {
569 		sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) &
570 			(FHC_REV_MASK >> FHC_REV_SHIFT);
571 	} else
572 		sc->sc_fhcrev=-1;
573 	printf(", rev %d", sc->sc_fhcrev);
574 
575 	/* reset cursor & frame buffer controls */
576 	cg6_reset(sc);
577 
578 	/* enable video */
579 	sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
580 
581 	if (isconsole) {
582 		printf(" (console)");
583 
584 /* this is the old console attachment stuff - sparc still needs it */
585 #ifdef RASTERCONSOLE
586 		if (cgsix_use_rasterconsole) {
587 			fbrcons_init(&sc->sc_fb);
588 			/*
589 			 * we don't use the screen struct but keep it here to
590 			 * avoid ugliness in the cg6_ras_* functions
591 			 */
592 			cg6_console_screen.scr_cookie = sc;
593 			sc->sc_fb.fb_rinfo.ri_hw = &cg6_console_screen;
594 			sc->sc_fb.fb_rinfo.ri_ops.copyrows = cg6_ras_copyrows;
595 			sc->sc_fb.fb_rinfo.ri_ops.copycols = cg6_ras_copycols;
596 			sc->sc_fb.fb_rinfo.ri_ops.erasecols = cg6_ras_erasecols;
597 			sc->sc_fb.fb_rinfo.ri_ops.eraserows = cg6_ras_eraserows;
598 #ifdef CG6_BLIT_CURSOR
599 			sc->sc_fb.fb_rinfo.ri_do_cursor = cg6_ras_do_cursor;
600 #endif
601 			cg6_ras_init(sc);
602 		}
603 #endif
604 	}
605 	printf("\n");
606 
607 	fb_attach(&sc->sc_fb, isconsole);
608 	sc->sc_width = fb->fb_type.fb_width;
609 	sc->sc_stride = fb->fb_type.fb_width;
610 	sc->sc_height = fb->fb_type.fb_height;
611 
612 	printf("%s: framebuffer size: %d MB\n", device_xname(sc->sc_dev),
613 	    sc->sc_ramsize >> 20);
614 
615 #if NWSDISPLAY
616 	/* setup rasops and so on for wsdisplay */
617 	memcpy(sc->sc_default_cmap, rasops_cmap, 768);
618 	wsfont_init();
619 	cg6_ras_init(sc);
620 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
621 	sc->sc_bg = WS_DEFAULT_BG;
622 	sc->sc_fb_is_open = FALSE;
623 
624 	vcons_init(&sc->vd, sc, &cgsix_defaultscreen, &cgsix_accessops);
625 	sc->vd.init_screen = cgsix_init_screen;
626 
627 	sc->sc_gc.gc_bitblt = cgsix_bitblt;
628 	sc->sc_gc.gc_blitcookie = sc;
629 	sc->sc_gc.gc_rop = CG6_ALU_COPY;
630 
631 	if(isconsole) {
632 		/* we mess with cg6_console_screen only once */
633 		vcons_init_screen(&sc->vd, &cg6_console_screen, 1,
634 		    &defattr);
635 		sc->sc_bg = (defattr >> 16) & 0xf; /* yes, this is an index into devcmap */
636 
637 		/*
638 		 * XXX
639 		 * Is this actually necessary? We're going to use the blitter later on anyway.
640 		 */
641 		/* We need unaccelerated initial screen clear on old revisions */
642 		if (sc->sc_fhcrev < 2) {
643 			memset(sc->sc_fb.fb_pixels, ri->ri_devcmap[sc->sc_bg],
644 			    sc->sc_stride * sc->sc_height);
645 		} else
646 			cgsix_clearscreen(sc);
647 
648 		cg6_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
649 
650 		cgsix_defaultscreen.textops = &ri->ri_ops;
651 		cgsix_defaultscreen.capabilities = ri->ri_caps;
652 		cgsix_defaultscreen.nrows = ri->ri_rows;
653 		cgsix_defaultscreen.ncols = ri->ri_cols;
654 		SCREEN_VISIBLE(&cg6_console_screen);
655 		sc->vd.active = &cg6_console_screen;
656 		wsdisplay_cnattach(&cgsix_defaultscreen, ri, 0, 0, defattr);
657 		if (ri->ri_flg & RI_ENABLE_ALPHA) {
658 			glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
659 				(sc->sc_ramsize / sc->sc_stride) -
660 				  sc->sc_height - 5,
661 				sc->sc_width,
662 				ri->ri_font->fontwidth,
663 				ri->ri_font->fontheight,
664 				defattr);
665 		}
666 		vcons_replay_msgbuf(&cg6_console_screen);
667 	} else {
668 		/*
669 		 * since we're not the console we can postpone the rest
670 		 * until someone actually allocates a screen for us
671 		 */
672 		if (cg6_console_screen.scr_ri.ri_rows == 0) {
673 			/* do some minimal setup to avoid weirdnesses later */
674 			vcons_init_screen(&sc->vd, &cg6_console_screen, 1,
675 			    &defattr);
676 		} else
677 			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
678 		sc->sc_bg = (defattr >> 16) & 0xf;
679 		if (ri->ri_flg & RI_ENABLE_ALPHA) {
680 			glyphcache_init(&sc->sc_gc, sc->sc_height + 5,
681 				(sc->sc_ramsize / sc->sc_stride) -
682 				  sc->sc_height - 5,
683 				sc->sc_width,
684 				ri->ri_font->fontwidth,
685 				ri->ri_font->fontheight,
686 				defattr);
687 		}
688 	}
689 	cg6_setup_palette(sc);
690 
691 	aa.scrdata = &cgsix_screenlist;
692 	aa.console = isconsole;
693 	aa.accessops = &cgsix_accessops;
694 	aa.accesscookie = &sc->vd;
695 	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
696 #else
697 	bt_initcmap(&sc->sc_cmap, 256);
698 	cg6_loadcmap(sc, 0, 256);
699 
700 #endif
701 }
702 
703 
704 int
705 cgsixopen(dev_t dev, int flags, int mode, struct lwp *l)
706 {
707 	device_t dv = device_lookup(&cgsix_cd, minor(dev));
708 	struct cgsix_softc *sc = device_private(dv);
709 
710 	if (dv == NULL)
711 		return ENXIO;
712 	sc->sc_fb_is_open = TRUE;
713 
714 	return 0;
715 }
716 
717 int
718 cgsixclose(dev_t dev, int flags, int mode, struct lwp *l)
719 {
720 	device_t dv = device_lookup(&cgsix_cd, minor(dev));
721 	struct cgsix_softc *sc = device_private(dv);
722 
723 	cg6_reset(sc);
724 	sc->sc_fb_is_open = FALSE;
725 
726 #if NWSDISPLAY > 0
727 	if (IS_IN_EMUL_MODE(sc)) {
728 		struct vcons_screen *ms = sc->vd.active;
729 
730 		cg6_ras_init(sc);
731 		cg6_setup_palette(sc);
732 		glyphcache_wipe(&sc->sc_gc);
733 
734 		/* we don't know if the screen exists */
735 		if (ms != NULL)
736 			vcons_redraw_screen(ms);
737 	}
738 #else
739 	/* (re-)initialize the default color map */
740 	bt_initcmap(&sc->sc_cmap, 256);
741 
742 	cg6_loadcmap(sc, 0, 256);
743 #endif
744 	return 0;
745 }
746 
747 int
748 cgsixioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
749 {
750 	struct cgsix_softc *sc = device_lookup_private(&cgsix_cd, minor(dev));
751 	union cursor_cmap tcm;
752 	uint32_t image[32], mask[32];
753 	u_int count;
754 	int v, error;
755 
756 #ifdef CGSIX_DEBUG
757 	printf("cgsixioctl(%lx)\n",cmd);
758 #endif
759 
760 	switch (cmd) {
761 
762 	case FBIOGTYPE:
763 		*(struct fbtype *)data = sc->sc_fb.fb_type;
764 		break;
765 
766 	case FBIOGATTR:
767 #define fba ((struct fbgattr *)data)
768 		fba->real_type = sc->sc_fb.fb_type.fb_type;
769 		fba->owner = 0;		/* XXX ??? */
770 		fba->fbtype = sc->sc_fb.fb_type;
771 		fba->sattr.flags = 0;
772 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
773 		fba->sattr.dev_specific[0] = -1;
774 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
775 		fba->emu_types[1] = -1;
776 #undef fba
777 		break;
778 
779 	case FBIOGETCMAP:
780 #define	p ((struct fbcmap *)data)
781 		return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
782 
783 	case FBIOPUTCMAP:
784 		/* copy to software map */
785 		error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
786 		if (error)
787 			return error;
788 		/* now blast them into the chip */
789 		/* XXX should use retrace interrupt */
790 		cg6_loadcmap(sc, p->index, p->count);
791 #undef p
792 		break;
793 
794 	case FBIOGVIDEO:
795 		*(int *)data = sc->sc_blanked;
796 		break;
797 
798 	case FBIOSVIDEO:
799 		cg6_blank(sc, !(*(int *)data));
800 		break;
801 
802 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
803 #define p ((struct fbcursor *)data)
804 #define cc (&sc->sc_cursor)
805 
806 	case FBIOGCURSOR:
807 		/* do not quite want everything here... */
808 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
809 		p->enable = cc->cc_enable;
810 		p->pos = cc->cc_pos;
811 		p->hot = cc->cc_hot;
812 		p->size = cc->cc_size;
813 
814 		/* begin ugh ... can we lose some of this crap?? */
815 		if (p->image != NULL) {
816 			count = cc->cc_size.y * 32 / NBBY;
817 			error = copyout(cc->cc_bits[1], p->image, count);
818 			if (error)
819 				return error;
820 			error = copyout(cc->cc_bits[0], p->mask, count);
821 			if (error)
822 				return error;
823 		}
824 		if (p->cmap.red != NULL) {
825 			error = bt_getcmap(&p->cmap,
826 			    (union bt_cmap *)&cc->cc_color, 2, 1);
827 			if (error)
828 				return error;
829 		} else {
830 			p->cmap.index = 0;
831 			p->cmap.count = 2;
832 		}
833 		/* end ugh */
834 		break;
835 
836 	case FBIOSCURSOR:
837 		/*
838 		 * For setcmap and setshape, verify parameters, so that
839 		 * we do not get halfway through an update and then crap
840 		 * out with the software state screwed up.
841 		 */
842 		v = p->set;
843 		if (v & FB_CUR_SETCMAP) {
844 			/*
845 			 * This use of a temporary copy of the cursor
846 			 * colormap is not terribly efficient, but these
847 			 * copies are small (8 bytes)...
848 			 */
849 			tcm = cc->cc_color;
850 			error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2,
851 			    1);
852 			if (error)
853 				return error;
854 		}
855 		if (v & FB_CUR_SETSHAPE) {
856 			if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32)
857 				return EINVAL;
858 			count = p->size.y * 32 / NBBY;
859 			error = copyin(p->image, image, count);
860 			if (error)
861 				return error;
862 			error = copyin(p->mask, mask, count);
863 			if (error)
864 				return error;
865 		}
866 
867 		/* parameters are OK; do it */
868 		if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) {
869 			if (v & FB_CUR_SETCUR)
870 				cc->cc_enable = p->enable;
871 			if (v & FB_CUR_SETPOS)
872 				cc->cc_pos = p->pos;
873 			if (v & FB_CUR_SETHOT)
874 				cc->cc_hot = p->hot;
875 			cg6_setcursor(sc);
876 		}
877 		if (v & FB_CUR_SETCMAP) {
878 			cc->cc_color = tcm;
879 			cg6_loadomap(sc); /* XXX defer to vertical retrace */
880 		}
881 		if (v & FB_CUR_SETSHAPE) {
882 			cc->cc_size = p->size;
883 			count = p->size.y * 32 / NBBY;
884 			memset(cc->cc_bits, 0, sizeof cc->cc_bits);
885 			memcpy(cc->cc_bits[1], image, count);
886 			memcpy(cc->cc_bits[0], mask, count);
887 			cg6_loadcursor(sc);
888 		}
889 		break;
890 
891 #undef p
892 #undef cc
893 
894 	case FBIOGCURPOS:
895 		*(struct fbcurpos *)data = sc->sc_cursor.cc_pos;
896 		break;
897 
898 	case FBIOSCURPOS:
899 		sc->sc_cursor.cc_pos = *(struct fbcurpos *)data;
900 		cg6_setcursor(sc);
901 		break;
902 
903 	case FBIOGCURMAX:
904 		/* max cursor size is 32x32 */
905 		((struct fbcurpos *)data)->x = 32;
906 		((struct fbcurpos *)data)->y = 32;
907 		break;
908 
909 	default:
910 #ifdef DEBUG
911 		log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd,
912 		    l->l_proc->p_comm, l->l_proc->p_pid);
913 #endif
914 		return ENOTTY;
915 	}
916 	return 0;
917 }
918 
919 /*
920  * Clean up hardware state (e.g., after bootup or after X crashes).
921  */
922 static void
923 cg6_reset(struct cgsix_softc *sc)
924 {
925 	volatile struct cg6_tec_xxx *tec;
926 	int fhc;
927 	volatile struct bt_regs *bt;
928 
929 	/* hide the cursor, just in case */
930 	sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF;
931 
932 	/* turn off frobs in transform engine (makes X11 work) */
933 	tec = sc->sc_tec;
934 	tec->tec_mv = 0;
935 	tec->tec_clip = 0;
936 	tec->tec_vdc = 0;
937 
938 	/* take care of hardware bugs in old revisions */
939 	if (sc->sc_fhcrev < 5) {
940 		/*
941 		 * Keep current resolution; set CPU to 68020, set test
942 		 * window (size 1Kx1K), and for rev 1, disable dest cache.
943 		 */
944 		fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 |
945 		    FHC_TEST |
946 		    (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
947 		if (sc->sc_fhcrev < 2)
948 			fhc |= FHC_DST_DISABLE;
949 		*sc->sc_fhc = fhc;
950 	}
951 
952 	/* Enable cursor in Brooktree DAC. */
953 	bt = sc->sc_bt;
954 	bt->bt_addr = 0x06 << 24;
955 	bt->bt_ctrl |= 0x03 << 24;
956 }
957 
958 static void
959 cg6_setcursor(struct cgsix_softc *sc)
960 {
961 
962 	/* we need to subtract the hot-spot value here */
963 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f)
964 	sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ?
965 	    ((COORD(x) << 16) | (COORD(y) & 0xffff)) :
966 	    (THC_CURSOFF << 16) | THC_CURSOFF;
967 #undef COORD
968 }
969 
970 static void
971 cg6_loadcursor(struct cgsix_softc *sc)
972 {
973 	volatile struct cg6_thc *thc;
974 	u_int edgemask, m;
975 	int i;
976 
977 	/*
978 	 * Keep the top size.x bits.  Here we *throw out* the top
979 	 * size.x bits from an all-one-bits word, introducing zeros in
980 	 * the top size.x bits, then invert all the bits to get what
981 	 * we really wanted as our mask.  But this fails if size.x is
982 	 * 32---a sparc uses only the low 5 bits of the shift count---
983 	 * so we have to special case that.
984 	 */
985 	edgemask = ~0;
986 	if (sc->sc_cursor.cc_size.x < 32)
987 		edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x);
988 	thc = sc->sc_thc;
989 	for (i = 0; i < 32; i++) {
990 		m = sc->sc_cursor.cc_bits[0][i] & edgemask;
991 		thc->thc_cursmask[i] = m;
992 		thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i];
993 	}
994 }
995 
996 /*
997  * Load a subset of the current (new) colormap into the color DAC.
998  */
999 static void
1000 cg6_loadcmap(struct cgsix_softc *sc, int start, int ncolors)
1001 {
1002 	volatile struct bt_regs *bt;
1003 	u_int *ip, i;
1004 	int count;
1005 
1006 	ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)];	/* start/4 * 3 */
1007 	count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
1008 	bt = sc->sc_bt;
1009 	bt->bt_addr = BT_D4M4(start) << 24;
1010 	while (--count >= 0) {
1011 		i = *ip++;
1012 		/* hardware that makes one want to pound boards with hammers */
1013 		bt->bt_cmap = i;
1014 		bt->bt_cmap = i << 8;
1015 		bt->bt_cmap = i << 16;
1016 		bt->bt_cmap = i << 24;
1017 	}
1018 }
1019 
1020 /*
1021  * Load the cursor (overlay `foreground' and `background') colors.
1022  */
1023 static void
1024 cg6_loadomap(struct cgsix_softc *sc)
1025 {
1026 	volatile struct bt_regs *bt;
1027 	u_int i;
1028 
1029 	bt = sc->sc_bt;
1030 	bt->bt_addr = 0x01 << 24;	/* set background color */
1031 	i = sc->sc_cursor.cc_color.cm_chip[0];
1032 	bt->bt_omap = i;		/* R */
1033 	bt->bt_omap = i << 8;		/* G */
1034 	bt->bt_omap = i << 16;		/* B */
1035 
1036 	bt->bt_addr = 0x03 << 24;	/* set foreground color */
1037 	bt->bt_omap = i << 24;		/* R */
1038 	i = sc->sc_cursor.cc_color.cm_chip[1];
1039 	bt->bt_omap = i;		/* G */
1040 	bt->bt_omap = i << 8;		/* B */
1041 }
1042 
1043 /* blank or unblank the screen */
1044 static void
1045 cg6_blank(struct cgsix_softc *sc, int flag)
1046 {
1047 
1048 	if (sc->sc_blanked != flag) {
1049 		sc->sc_blanked = flag;
1050 		if (flag) {
1051 			sc->sc_thc->thc_misc &= ~THC_MISC_VIDEN;
1052 		} else {
1053 			sc->sc_thc->thc_misc |= THC_MISC_VIDEN;
1054 		}
1055 	}
1056 }
1057 
1058 /*
1059  * this is called on panic or ddb entry - force the console to the front, reset
1060  * the colour map and enable drawing so we actually see the message even when X
1061  * is running
1062  */
1063 static void
1064 cg6_unblank(device_t dev)
1065 {
1066 	struct cgsix_softc *sc = device_private(dev);
1067 
1068 	cg6_blank(sc, 0);
1069 }
1070 
1071 /* XXX the following should be moved to a "user interface" header */
1072 /*
1073  * Base addresses at which users can mmap() the various pieces of a cg6.
1074  * Note that although the Brooktree color registers do not occupy 8K,
1075  * the X server dies if we do not allow it to map 8K there (it just maps
1076  * from 0x70000000 forwards, as a contiguous chunk).
1077  */
1078 #define	CG6_USER_FBC	0x70000000
1079 #define	CG6_USER_TEC	0x70001000
1080 #define	CG6_USER_BTREGS	0x70002000
1081 #define	CG6_USER_FHC	0x70004000
1082 #define	CG6_USER_THC	0x70005000
1083 #define	CG6_USER_ROM	0x70006000
1084 #define	CG6_USER_RAM	0x70016000
1085 #define	CG6_USER_DHC	0x80000000
1086 
1087 struct mmo {
1088 	u_long	mo_uaddr;	/* user (virtual) address */
1089 	u_long	mo_size;	/* size, or 0 for video ram size */
1090 	u_long	mo_physoff;	/* offset from sc_physadr */
1091 };
1092 
1093 /*
1094  * Return the address that would map the given device at the given
1095  * offset, allowing for the given protection, or return -1 for error.
1096  *
1097  * XXX	needs testing against `demanding' applications (e.g., aviator)
1098  */
1099 paddr_t
1100 cgsixmmap(dev_t dev, off_t off, int prot)
1101 {
1102 	struct cgsix_softc *sc = device_lookup_private(&cgsix_cd, minor(dev));
1103 	struct mmo *mo;
1104 	u_int u, sz;
1105 	static struct mmo mmo[] = {
1106 		{ CG6_USER_RAM, 0, CGSIX_RAM_OFFSET },
1107 
1108 		/* do not actually know how big most of these are! */
1109 		{ CG6_USER_FBC, 1, CGSIX_FBC_OFFSET },
1110 		{ CG6_USER_TEC, 1, CGSIX_TEC_OFFSET },
1111 		{ CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET },
1112 		{ CG6_USER_FHC, 1, CGSIX_FHC_OFFSET },
1113 		{ CG6_USER_THC, sizeof(struct cg6_thc), CGSIX_THC_OFFSET },
1114 		{ CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET },
1115 		{ CG6_USER_DHC, 1, CGSIX_DHC_OFFSET },
1116 	};
1117 #define NMMO (sizeof mmo / sizeof *mmo)
1118 
1119 	if (off & PGOFSET)
1120 		panic("cgsixmmap");
1121 
1122 	/*
1123 	 * Entries with size 0 map video RAM (i.e., the size in fb data).
1124 	 *
1125 	 * Since we work in pages, the fact that the map offset table's
1126 	 * sizes are sometimes bizarre (e.g., 1) is effectively ignored:
1127 	 * one byte is as good as one page.
1128 	 */
1129 	for (mo = mmo; mo < &mmo[NMMO]; mo++) {
1130 		if ((u_long)off < mo->mo_uaddr)
1131 			continue;
1132 		u = off - mo->mo_uaddr;
1133 		sz = mo->mo_size ? mo->mo_size :
1134 		    sc->sc_ramsize;
1135 		if (u < sz) {
1136 			return (bus_space_mmap(sc->sc_bustag,
1137 				sc->sc_paddr, u+mo->mo_physoff,
1138 				prot, BUS_SPACE_MAP_LINEAR));
1139 		}
1140 	}
1141 
1142 #ifdef DEBUG
1143 	{
1144 	  struct proc *p = curlwp->l_proc;	/* XXX */
1145 	  log(LOG_NOTICE, "cgsixmmap(0x%llx) (%s[%d])\n",
1146 		(long long)off, p->p_comm, p->p_pid);
1147 	}
1148 #endif
1149 	return -1;	/* not a user-map offset */
1150 }
1151 
1152 #if NWSDISPLAY > 0
1153 
1154 static void
1155 cg6_setup_palette(struct cgsix_softc *sc)
1156 {
1157 	int i, j;
1158 
1159 	rasops_get_cmap(&cg6_console_screen.scr_ri, sc->sc_default_cmap,
1160 	    sizeof(sc->sc_default_cmap));
1161 	j = 0;
1162 	for (i = 0; i < 256; i++) {
1163 		sc->sc_cmap.cm_map[i][0] = sc->sc_default_cmap[j];
1164 		j++;
1165 		sc->sc_cmap.cm_map[i][1] = sc->sc_default_cmap[j];
1166 		j++;
1167 		sc->sc_cmap.cm_map[i][2] = sc->sc_default_cmap[j];
1168 		j++;
1169 	}
1170 	cg6_loadcmap(sc, 0, 256);
1171 }
1172 
1173 int
1174 cgsix_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
1175 	struct lwp *l)
1176 {
1177 	/* we'll probably need to add more stuff here */
1178 	struct vcons_data *vd = v;
1179 	struct cgsix_softc *sc = vd->cookie;
1180 	struct wsdisplay_fbinfo *wdf;
1181 	struct rasops_info *ri = &sc->sc_fb.fb_rinfo;
1182 	struct vcons_screen *ms = sc->vd.active;
1183 
1184 #ifdef CGSIX_DEBUG
1185 	printf("cgsix_ioctl(%lx)\n",cmd);
1186 #endif
1187 	switch (cmd) {
1188 		case WSDISPLAYIO_GTYPE:
1189 			*(u_int *)data = WSDISPLAY_TYPE_SUNTCX;
1190 			return 0;
1191 		case WSDISPLAYIO_GINFO:
1192 			wdf = (void *)data;
1193 			wdf->height = ri->ri_height;
1194 			wdf->width = ri->ri_width;
1195 			wdf->depth = ri->ri_depth;
1196 			wdf->cmsize = 256;
1197 			return 0;
1198 
1199 		case WSDISPLAYIO_GETCMAP:
1200 			return cgsix_getcmap(sc,
1201 			    (struct wsdisplay_cmap *)data);
1202 		case WSDISPLAYIO_PUTCMAP:
1203 			return cgsix_putcmap(sc,
1204 			    (struct wsdisplay_cmap *)data);
1205 
1206 		case WSDISPLAYIO_LINEBYTES:
1207 			*(u_int *)data = sc->sc_stride;
1208 			return 0;
1209 
1210 		case WSDISPLAYIO_SMODE:
1211 			{
1212 				int new_mode = *(int*)data;
1213 
1214 				if (new_mode != sc->sc_mode) {
1215 					sc->sc_mode = new_mode;
1216 					if (IS_IN_EMUL_MODE(sc)) {
1217 						cg6_reset(sc);
1218 						cg6_ras_init(sc);
1219 						cg6_setup_palette(sc);
1220 						glyphcache_wipe(&sc->sc_gc);
1221 						vcons_redraw_screen(ms);
1222 					}
1223 				}
1224 			}
1225 	}
1226 	return EPASSTHROUGH;
1227 }
1228 
1229 paddr_t
1230 cgsix_mmap(void *v, void *vs, off_t offset, int prot)
1231 {
1232 	struct vcons_data *vd = v;
1233 	struct cgsix_softc *sc = vd->cookie;
1234 
1235 	if (offset < sc->sc_ramsize) {
1236 		return bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
1237 		    CGSIX_RAM_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR);
1238 	}
1239 	return -1;
1240 }
1241 
1242 int
1243 cgsix_putcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm)
1244 {
1245 	u_int index = cm->index;
1246 	u_int count = cm->count;
1247 	int error, i;
1248 
1249 	if (index >= 256 || count > 256 || index + count > 256)
1250 		return EINVAL;
1251 
1252 	for (i = 0; i < count; i++)
1253 	{
1254 		error = copyin(&cm->red[i],
1255 		    &sc->sc_cmap.cm_map[index + i][0], 1);
1256 		if (error)
1257 			return error;
1258 		error = copyin(&cm->green[i],
1259 		    &sc->sc_cmap.cm_map[index + i][1],
1260 		    1);
1261 		if (error)
1262 			return error;
1263 		error = copyin(&cm->blue[i],
1264 		    &sc->sc_cmap.cm_map[index + i][2], 1);
1265 		if (error)
1266 			return error;
1267 	}
1268 	cg6_loadcmap(sc, index, count);
1269 
1270 	return 0;
1271 }
1272 
1273 int
1274 cgsix_getcmap(struct cgsix_softc *sc, struct wsdisplay_cmap *cm)
1275 {
1276 	u_int index = cm->index;
1277 	u_int count = cm->count;
1278 	int error,i;
1279 
1280 	if (index >= 256 || count > 256 || index + count > 256)
1281 		return EINVAL;
1282 
1283 	for (i = 0; i < count; i++)
1284 	{
1285 		error = copyout(&sc->sc_cmap.cm_map[index + i][0],
1286 		    &cm->red[i], 1);
1287 		if (error)
1288 			return error;
1289 		error = copyout(&sc->sc_cmap.cm_map[index + i][1],
1290 		    &cm->green[i], 1);
1291 		if (error)
1292 			return error;
1293 		error = copyout(&sc->sc_cmap.cm_map[index + i][2],
1294 		    &cm->blue[i], 1);
1295 		if (error)
1296 			return error;
1297 	}
1298 
1299 	return 0;
1300 }
1301 
1302 void
1303 cgsix_init_screen(void *cookie, struct vcons_screen *scr,
1304     int existing, long *defattr)
1305 {
1306 	struct cgsix_softc *sc = cookie;
1307 	struct rasops_info *ri = &scr->scr_ri;
1308 	int av;
1309 
1310 	ri->ri_depth = 8;
1311 	ri->ri_width = sc->sc_width;
1312 	ri->ri_height = sc->sc_height;
1313 	ri->ri_stride = sc->sc_stride;
1314 	av = sc->sc_ramsize - (sc->sc_height * sc->sc_stride);
1315 	ri->ri_flg = RI_CENTER  | RI_8BIT_IS_RGB;
1316 	if (av > (128 * 1024)) {
1317 		ri->ri_flg |= RI_ENABLE_ALPHA;
1318 	}
1319 	ri->ri_bits = sc->sc_fb.fb_pixels;
1320 
1321 	rasops_init(ri, 0, 0);
1322 	ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_REVERSE;
1323 	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
1324 		    sc->sc_width / ri->ri_font->fontwidth);
1325 
1326 	/* enable acceleration */
1327 	ri->ri_hw = scr;
1328 	ri->ri_ops.copyrows = cg6_ras_copyrows;
1329 	ri->ri_ops.copycols = cg6_ras_copycols;
1330 	ri->ri_ops.eraserows = cg6_ras_eraserows;
1331 	ri->ri_ops.erasecols = cg6_ras_erasecols;
1332 	ri->ri_ops.cursor = cgsix_cursor;
1333 	if (FONT_IS_ALPHA(ri->ri_font)) {
1334 		ri->ri_ops.putchar = cgsix_putchar_aa;
1335 	} else
1336 		ri->ri_ops.putchar = cgsix_putchar;
1337 }
1338 
1339 void
1340 cgsix_rectfill(struct cgsix_softc *sc, int xs, int ys, int wi, int he,
1341     uint32_t col)
1342 {
1343 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1344 
1345 	CG6_WAIT_READY(fbc);
1346 
1347 	fbc->fbc_alu = CG6_ALU_FILL;
1348 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
1349 
1350 	fbc->fbc_fg = col;
1351 	fbc->fbc_arecty = ys;
1352 	fbc->fbc_arectx = xs;
1353 	fbc->fbc_arecty = ys + he - 1;
1354 	fbc->fbc_arectx = xs + wi - 1;
1355 	CG6_DRAW(fbc);
1356 }
1357 
1358 void
1359 cgsix_bitblt(void *cookie, int xs, int ys, int xd, int yd,
1360     int wi, int he, int rop)
1361 {
1362 	struct cgsix_softc *sc = cookie;
1363 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1364 	CG6_WAIT_READY(fbc);
1365 
1366 	fbc->fbc_alu = rop;
1367 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
1368 
1369 	fbc->fbc_x0 = xs;
1370 	fbc->fbc_y0 = ys;
1371 	fbc->fbc_x1 = xs + wi - 1;
1372 	fbc->fbc_y1 = ys + he - 1;
1373 	fbc->fbc_x2 = xd;
1374 	fbc->fbc_y2 = yd;
1375 	fbc->fbc_x3 = xd + wi - 1;
1376 	fbc->fbc_y3 = yd + he - 1;
1377 	CG6_BLIT(fbc);
1378 }
1379 
1380 void
1381 cgsix_setup_mono(struct cgsix_softc *sc, int x, int y, int wi, int he,
1382     uint32_t fg, uint32_t bg)
1383 {
1384 	volatile struct cg6_fbc *fbc=sc->sc_fbc;
1385 
1386 	CG6_WAIT_READY(fbc);
1387 
1388 	fbc->fbc_x0 = x;
1389 	fbc->fbc_x1 = x + wi - 1;
1390 	fbc->fbc_y0 = y;
1391 	fbc->fbc_incx = 0;
1392 	fbc->fbc_incy = 1;
1393 	fbc->fbc_fg = fg;
1394 	fbc->fbc_bg = bg;
1395 	fbc->fbc_mode = GX_BLIT_NOSRC | GX_MODE_COLOR1;
1396 	fbc->fbc_alu = GX_PATTERN_ONES | ROP_OSTP(GX_ROP_CLEAR, GX_ROP_SET);
1397 	sc->sc_mono_width = wi;
1398 	/* now feed the data into the chip */
1399 }
1400 
1401 void
1402 cgsix_feed_line(struct cgsix_softc *sc, int count, uint8_t *data)
1403 {
1404 	int i;
1405 	uint32_t latch, res = 0, shift;
1406 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1407 
1408 	if (sc->sc_mono_width > 32) {
1409 		/* ARGH! */
1410 	} else
1411 	{
1412 		shift = 24;
1413 		for (i = 0; i < count; i++) {
1414 			latch = data[i];
1415 			res |= latch << shift;
1416 			shift -= 8;
1417 		}
1418 		fbc->fbc_font = res;
1419 	}
1420 }
1421 
1422 void
1423 cgsix_putchar(void *cookie, int row, int col, u_int c, long attr)
1424 {
1425 	struct rasops_info *ri = cookie;
1426 	struct wsdisplay_font *font = PICK_FONT(ri, c);
1427 	struct vcons_screen *scr = ri->ri_hw;
1428 	struct cgsix_softc *sc = scr->scr_cookie;
1429 	int inv;
1430 
1431 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
1432 	    (col < ri->ri_cols)) {
1433 
1434 		if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1435 
1436 			int fg, bg, uc, i;
1437 			uint8_t *data;
1438 			int x, y, wi, he;
1439 			volatile struct cg6_fbc *fbc = sc->sc_fbc;
1440 
1441 			wi = font->fontwidth;
1442 			he = font->fontheight;
1443 
1444 			if (!CHAR_IN_FONT(c, font))
1445 				return;
1446 			inv = ((attr >> 8) & WSATTR_REVERSE);
1447 			if (inv) {
1448 				fg = (u_char)ri->ri_devcmap[(attr >> 16) &
1449 				    0xff];
1450 				bg = (u_char)ri->ri_devcmap[(attr >> 24) &
1451 				    0xff];
1452 			} else {
1453 				bg = (u_char)ri->ri_devcmap[(attr >> 16) &
1454 				    0xff];
1455 				fg = (u_char)ri->ri_devcmap[(attr >> 24) &
1456 				    0xff];
1457 			}
1458 
1459 			x = ri->ri_xorigin + col * wi;
1460 			y = ri->ri_yorigin + row * he;
1461 
1462 			if (c == 0x20) {
1463 				cgsix_rectfill(sc, x, y, wi, he, bg);
1464 			} else {
1465 				uc = c - font->firstchar;
1466 				data = (uint8_t *)font->data + uc *
1467 				    ri->ri_fontscale;
1468 
1469 				cgsix_setup_mono(sc, x, y, wi, 1, fg, bg);
1470 				for (i = 0; i < he; i++) {
1471 					cgsix_feed_line(sc, font->stride,
1472 					    data);
1473 					data += font->stride;
1474 				}
1475 				/* put the chip back to normal */
1476 				fbc->fbc_incy = 0;
1477 			}
1478 		}
1479 	}
1480 }
1481 
1482 void
1483 cgsix_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
1484 {
1485 	struct rasops_info *ri = cookie;
1486 	struct wsdisplay_font *font = PICK_FONT(ri, c);
1487 	struct vcons_screen *scr = ri->ri_hw;
1488 	struct cgsix_softc *sc = scr->scr_cookie;
1489 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1490 
1491 	uint32_t bg, latch = 0, bg8, fg8, pixel;
1492 	int i, j, shift, x, y, wi, he, r, g, b, aval;
1493 	int r1, g1, b1, r0, g0, b0, fgo, bgo;
1494 	uint8_t *data8;
1495 	int rv;
1496 
1497 	if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL)
1498 		return;
1499 
1500 	if (!CHAR_IN_FONT(c, font))
1501 		return;
1502 
1503 	wi = font->fontwidth;
1504 	he = font->fontheight;
1505 
1506 	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
1507 	x = ri->ri_xorigin + col * wi;
1508 	y = ri->ri_yorigin + row * he;
1509 	if (c == 0x20) {
1510 		cgsix_rectfill(sc, x, y, wi, he, bg);
1511 		return;
1512 	}
1513 
1514 	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
1515 	if (rv == GC_OK)
1516 		return;
1517 
1518 	data8 = WSFONT_GLYPH(c, font);
1519 
1520 	CG6_WAIT_READY(sc->sc_fbc);
1521 	fbc->fbc_incx = 4;
1522 	fbc->fbc_incy = 0;
1523 	fbc->fbc_mode = GX_BLIT_NOSRC | GX_MODE_COLOR8;
1524 	fbc->fbc_alu = CG6_ALU_COPY;
1525 	fbc->fbc_clipmaxx = x + wi - 1;
1526 
1527 	/*
1528 	 * we need the RGB colours here, so get offsets into rasops_cmap
1529 	 */
1530 	fgo = ((attr >> 24) & 0xf) * 3;
1531 	bgo = ((attr >> 16) & 0xf) * 3;
1532 
1533 	r0 = rasops_cmap[bgo];
1534 	r1 = rasops_cmap[fgo];
1535 	g0 = rasops_cmap[bgo + 1];
1536 	g1 = rasops_cmap[fgo + 1];
1537 	b0 = rasops_cmap[bgo + 2];
1538 	b1 = rasops_cmap[fgo + 2];
1539 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6))
1540 	bg8 = R3G3B2(r0, g0, b0);
1541 	fg8 = R3G3B2(r1, g1, b1);
1542 
1543 	for (i = 0; i < he; i++) {
1544 
1545 		CG6_WAIT_READY(fbc);
1546 		fbc->fbc_x0 = x;
1547 		fbc->fbc_x1 = x + 3;
1548 		fbc->fbc_y0 = y + i;
1549 
1550 		shift = 24;
1551 		for (j = 0; j < wi; j++) {
1552 			aval = *data8;
1553 			if (aval == 0) {
1554 				pixel = bg8;
1555 			} else if (aval == 255) {
1556 				pixel = fg8;
1557 			} else {
1558 				r = aval * r1 + (255 - aval) * r0;
1559 				g = aval * g1 + (255 - aval) * g0;
1560 				b = aval * b1 + (255 - aval) * b0;
1561 				pixel = ((r & 0xe000) >> 8) |
1562 					((g & 0xe000) >> 11) |
1563 					((b & 0xc000) >> 14);
1564 			}
1565 			data8++;
1566 
1567 			latch |= pixel << shift;
1568 			if (shift == 0) {
1569 				fbc->fbc_font = latch;
1570 				latch = 0;
1571 				shift = 24;
1572 			} else
1573 				shift -= 8;
1574 		}
1575 		if (shift != 24)
1576 			fbc->fbc_font = latch;
1577 	}
1578 	fbc->fbc_clipmaxx = 0x3fff;
1579 
1580 	if (rv == GC_ADD) {
1581 		glyphcache_add(&sc->sc_gc, c, x, y);
1582 	}
1583 }
1584 
1585 void
1586 cgsix_cursor(void *cookie, int on, int row, int col)
1587 {
1588 	struct rasops_info *ri = cookie;
1589 	struct vcons_screen *scr = ri->ri_hw;
1590 	struct cgsix_softc *sc = scr->scr_cookie;
1591 	int x, y, wi, he;
1592 
1593 	wi = ri->ri_font->fontwidth;
1594 	he = ri->ri_font->fontheight;
1595 
1596 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1597 		x = ri->ri_ccol * wi + ri->ri_xorigin;
1598 		y = ri->ri_crow * he + ri->ri_yorigin;
1599 		if (ri->ri_flg & RI_CURSOR) {
1600 			cg6_invert(sc, x, y, wi, he);
1601 			ri->ri_flg &= ~RI_CURSOR;
1602 		}
1603 		ri->ri_crow = row;
1604 		ri->ri_ccol = col;
1605 		if (on)
1606 		{
1607 			x = ri->ri_ccol * wi + ri->ri_xorigin;
1608 			y = ri->ri_crow * he + ri->ri_yorigin;
1609 			cg6_invert(sc, x, y, wi, he);
1610 			ri->ri_flg |= RI_CURSOR;
1611 		}
1612 	} else
1613 	{
1614 		ri->ri_crow = row;
1615 		ri->ri_ccol = col;
1616 		ri->ri_flg &= ~RI_CURSOR;
1617 	}
1618 }
1619 
1620 void
1621 cgsix_clearscreen(struct cgsix_softc *sc)
1622 {
1623 	struct rasops_info *ri = &cg6_console_screen.scr_ri;
1624 
1625 	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
1626 		volatile struct cg6_fbc *fbc = sc->sc_fbc;
1627 
1628 		CG6_WAIT_READY(fbc);
1629 
1630 		fbc->fbc_alu = CG6_ALU_FILL;
1631 		fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
1632 
1633 		fbc->fbc_fg = ri->ri_devcmap[sc->sc_bg];
1634 		fbc->fbc_arectx = 0;
1635 		fbc->fbc_arecty = 0;
1636 		fbc->fbc_arectx = ri->ri_width - 1;
1637 		fbc->fbc_arecty = ri->ri_height - 1;
1638 		CG6_DRAW(fbc);
1639 	}
1640 }
1641 
1642 #endif /* NWSDISPLAY > 0 */
1643 
1644 #if (NWSDISPLAY > 0) || defined(RASTERCONSOLE)
1645 void
1646 cg6_invert(struct cgsix_softc *sc, int x, int y, int wi, int he)
1647 {
1648 	volatile struct cg6_fbc *fbc = sc->sc_fbc;
1649 
1650 	CG6_WAIT_READY(fbc);
1651 
1652 	fbc->fbc_alu = CG6_ALU_FLIP;
1653 	fbc->fbc_mode = GX_BLIT_SRC | GX_MODE_COLOR8;
1654 	fbc->fbc_arecty = y;
1655 	fbc->fbc_arectx = x;
1656 	fbc->fbc_arecty = y + he - 1;
1657 	fbc->fbc_arectx = x + wi - 1;
1658 	CG6_DRAW(fbc);
1659 }
1660 
1661 #endif
1662 
1663