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