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