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