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