xref: /openbsd-src/sys/dev/sbus/cgsix.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: cgsix.c,v 1.44 2003/07/03 21:02:13 jason Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Effort sponsored in part by the Defense Advanced Research Projects
29  * Agency (DARPA) and Air Force Research Laboratory, Air Force
30  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31  *
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/errno.h>
38 #include <sys/device.h>
39 #include <sys/ioctl.h>
40 #include <sys/malloc.h>
41 
42 #include <machine/bus.h>
43 #include <machine/intr.h>
44 #include <machine/autoconf.h>
45 #include <machine/openfirm.h>
46 
47 #include <dev/sbus/sbusvar.h>
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50 #include <dev/wscons/wscons_raster.h>
51 #include <dev/rasops/rasops.h>
52 #include <machine/fbvar.h>
53 #include <dev/sbus/cgsixreg.h>
54 #include <dev/ic/bt458reg.h>
55 
56 struct wsscreen_descr cgsix_stdscreen = {
57 	"std",
58 };
59 
60 const struct wsscreen_descr *cgsix_scrlist[] = {
61 	&cgsix_stdscreen,
62 	/* XXX other formats? */
63 };
64 
65 struct wsscreen_list cgsix_screenlist = {
66 	sizeof(cgsix_scrlist) / sizeof(struct wsscreen_descr *), cgsix_scrlist
67 };
68 
69 int cgsix_ioctl(void *, u_long, caddr_t, int, struct proc *);
70 int cgsix_alloc_screen(void *, const struct wsscreen_descr *, void **,
71     int *, int *, long *);
72 void cgsix_free_screen(void *, void *);
73 int cgsix_show_screen(void *, void *, int, void (*cb)(void *, int, int),
74     void *);
75 paddr_t cgsix_mmap(void *, off_t, int);
76 int cgsix_is_console(int);
77 int cg6_bt_getcmap(union bt_cmap *, struct wsdisplay_cmap *);
78 int cg6_bt_putcmap(union bt_cmap *, struct wsdisplay_cmap *);
79 void cgsix_loadcmap_immediate(struct cgsix_softc *, u_int, u_int);
80 void cgsix_loadcmap_deferred(struct cgsix_softc *, u_int, u_int);
81 void cgsix_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
82 void cgsix_reset(struct cgsix_softc *, u_int32_t);
83 void cgsix_hardreset(struct cgsix_softc *);
84 void cgsix_burner(void *, u_int, u_int);
85 int cgsix_intr(void *);
86 void cgsix_ras_init(struct cgsix_softc *);
87 void cgsix_ras_copyrows(void *, int, int, int);
88 void cgsix_ras_copycols(void *, int, int, int, int);
89 void cgsix_ras_erasecols(void *, int, int, int, long int);
90 void cgsix_ras_eraserows(void *, int, int, long int);
91 void cgsix_ras_do_cursor(struct rasops_info *);
92 void cgsix_ras_updatecursor(struct rasops_info *);
93 int cgsix_setcursor(struct cgsix_softc *, struct wsdisplay_cursor *);
94 int cgsix_updatecursor(struct cgsix_softc *, u_int);
95 
96 struct wsdisplay_accessops cgsix_accessops = {
97 	cgsix_ioctl,
98 	cgsix_mmap,
99 	cgsix_alloc_screen,
100 	cgsix_free_screen,
101 	cgsix_show_screen,
102 	NULL,	/* load_font */
103 	NULL,	/* scrollback */
104 	NULL,	/* getchar */
105 	cgsix_burner,
106 };
107 
108 int	cgsixmatch(struct device *, void *, void *);
109 void	cgsixattach(struct device *, struct device *, void *);
110 
111 struct cfattach cgsix_ca = {
112 	sizeof (struct cgsix_softc), cgsixmatch, cgsixattach
113 };
114 
115 struct cfdriver cgsix_cd = {
116 	NULL, "cgsix", DV_DULL
117 };
118 
119 int
120 cgsixmatch(struct device *parent, void *vcf, void *aux)
121 {
122 	struct cfdata *cf = vcf;
123 	struct sbus_attach_args *sa = aux;
124 
125 	return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
126 }
127 
128 void
129 cgsixattach(struct device *parent, struct device *self, void *aux)
130 {
131 	struct cgsix_softc *sc = (struct cgsix_softc *)self;
132 	struct sbus_attach_args *sa = aux;
133 	struct wsemuldisplaydev_attach_args waa;
134 	int console, i;
135 	u_int32_t fhc, rev;
136 
137 	sc->sc_bustag = sa->sa_bustag;
138 	sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, sa->sa_offset);
139 
140 	if (sa->sa_nreg != 1) {
141 		printf(": expected %d registers, got %d\n", 1, sa->sa_nreg);
142 		goto fail;
143 	}
144 
145 	fb_setsize(&sc->sc_sunfb, 8, 1152, 900, sa->sa_node, 0);
146 
147 	/*
148 	 * Map just BT, FHC, FBC, THC, and video RAM.
149 	 */
150 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
151 	    sa->sa_reg[0].sbr_offset + CGSIX_BT_OFFSET,
152 	    CGSIX_BT_SIZE, 0, 0, &sc->sc_bt_regs) != 0) {
153 		printf(": cannot map bt registers\n");
154 		goto fail_bt;
155 	}
156 
157 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
158 	    sa->sa_reg[0].sbr_offset + CGSIX_FHC_OFFSET,
159 	    CGSIX_FHC_SIZE, 0, 0, &sc->sc_fhc_regs) != 0) {
160 		printf(": cannot map fhc registers\n");
161 		goto fail_fhc;
162 	}
163 
164 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
165 	    sa->sa_reg[0].sbr_offset + CGSIX_THC_OFFSET,
166 	    CGSIX_THC_SIZE, 0, 0, &sc->sc_thc_regs) != 0) {
167 		printf(": cannot map thc registers\n");
168 		goto fail_thc;
169 	}
170 
171 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
172 	    sa->sa_reg[0].sbr_offset + CGSIX_VID_OFFSET,
173 	    sc->sc_sunfb.sf_fbsize, BUS_SPACE_MAP_LINEAR,
174 	    0, &sc->sc_vid_regs) != 0) {
175 		printf(": cannot map vid registers\n");
176 		goto fail_vid;
177 	}
178 
179 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
180 	    sa->sa_reg[0].sbr_offset + CGSIX_TEC_OFFSET,
181 	    CGSIX_TEC_SIZE, 0, 0, &sc->sc_tec_regs) != 0) {
182 		printf(": cannot map tec registers\n");
183 		goto fail_tec;
184 	}
185 
186 	if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
187 	    sa->sa_reg[0].sbr_offset + CGSIX_FBC_OFFSET,
188 	    CGSIX_FBC_SIZE, 0, 0, &sc->sc_fbc_regs) != 0) {
189 		printf(": cannot map fbc registers\n");
190 		goto fail_fbc;
191 	}
192 
193 	if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri,
194 	    IPL_TTY, 0, cgsix_intr, sc, self->dv_xname)) == NULL) {
195 		printf(": couldn't establish interrupt, pri %d\n", sa->sa_pri);
196 		goto fail_intr;
197 	}
198 
199 	/* if prom didn't initialize us, do it the hard way */
200 	if (OF_getproplen(sa->sa_node, "width") != sizeof(u_int32_t))
201 		cgsix_hardreset(sc);
202 
203 	console = cgsix_is_console(sa->sa_node);
204 
205 	fhc = FHC_READ(sc);
206 	rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT;
207 	cgsix_reset(sc, rev);
208 
209 	/* grab the current palette */
210 	BT_WRITE(sc, BT_ADDR, 0);
211 	for (i = 0; i < 256; i++) {
212 		sc->sc_cmap.cm_map[i][0] = BT_READ(sc, BT_CMAP) >> 24;
213 		sc->sc_cmap.cm_map[i][1] = BT_READ(sc, BT_CMAP) >> 24;
214 		sc->sc_cmap.cm_map[i][2] = BT_READ(sc, BT_CMAP) >> 24;
215 	}
216 
217 	cgsix_burner(sc, 1, 0);
218 
219 	sbus_establish(&sc->sc_sd, self);
220 
221 	sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bustag,
222 	    sc->sc_vid_regs);
223 	sc->sc_sunfb.sf_ro.ri_hw = sc;
224 	fbwscons_init(&sc->sc_sunfb, console ? 0 : RI_CLEAR);
225 
226 	/*
227 	 * Old rev. cg6 cards do not like the current acceleration code.
228 	 *
229 	 * Some hints from Sun point out at timing and cache problems, which
230 	 * will be investigated later.
231 	 */
232 	if (rev < 5)
233 		sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags |= CG6_CFFLAG_NOACCEL;
234 
235 	if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CG6_CFFLAG_NOACCEL)
236 	    == 0) {
237 		sc->sc_sunfb.sf_ro.ri_ops.copyrows = cgsix_ras_copyrows;
238 		sc->sc_sunfb.sf_ro.ri_ops.copycols = cgsix_ras_copycols;
239 		sc->sc_sunfb.sf_ro.ri_ops.eraserows = cgsix_ras_eraserows;
240 		sc->sc_sunfb.sf_ro.ri_ops.erasecols = cgsix_ras_erasecols;
241 		sc->sc_sunfb.sf_ro.ri_do_cursor = cgsix_ras_do_cursor;
242 		cgsix_ras_init(sc);
243 	}
244 
245 	cgsix_stdscreen.capabilities = sc->sc_sunfb.sf_ro.ri_caps;
246 	cgsix_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows;
247 	cgsix_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols;
248 	cgsix_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops;
249 
250 	printf("\n");
251 
252 	fbwscons_setcolormap(&sc->sc_sunfb, cgsix_setcolor);
253 
254 	if (console) {
255 		sc->sc_sunfb.sf_ro.ri_updatecursor = cgsix_ras_updatecursor;
256 		fbwscons_console_init(&sc->sc_sunfb, &cgsix_stdscreen, -1,
257 		    cgsix_burner);
258 	}
259 
260 	waa.console = console;
261 	waa.scrdata = &cgsix_screenlist;
262 	waa.accessops = &cgsix_accessops;
263 	waa.accesscookie = sc;
264 	config_found(self, &waa, wsemuldisplaydevprint);
265 
266 	return;
267 
268 fail_intr:
269 	bus_space_unmap(sa->sa_bustag, sc->sc_fbc_regs, CGSIX_FBC_SIZE);
270 fail_fbc:
271 	bus_space_unmap(sa->sa_bustag, sc->sc_tec_regs, CGSIX_TEC_SIZE);
272 fail_tec:
273 	bus_space_unmap(sa->sa_bustag, sc->sc_vid_regs, CGSIX_VID_SIZE);
274 fail_vid:
275 	bus_space_unmap(sa->sa_bustag, sc->sc_thc_regs, CGSIX_THC_SIZE);
276 fail_thc:
277 	bus_space_unmap(sa->sa_bustag, sc->sc_fhc_regs, CGSIX_FHC_SIZE);
278 fail_fhc:
279 	bus_space_unmap(sa->sa_bustag, sc->sc_bt_regs, CGSIX_BT_SIZE);
280 fail_bt:
281 fail:
282 ;
283 }
284 
285 int
286 cgsix_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
287 {
288 	struct cgsix_softc *sc = v;
289 	struct wsdisplay_cmap *cm;
290 	struct wsdisplay_fbinfo *wdf;
291 	struct wsdisplay_cursor *curs;
292 	struct wsdisplay_curpos *pos;
293 	u_char r[2], g[2], b[2];
294 	int error, s;
295 	u_int mode;
296 
297 	switch (cmd) {
298 	case WSDISPLAYIO_GTYPE:
299 		*(u_int *)data = WSDISPLAY_TYPE_SUNCG6;
300 		break;
301 	case WSDISPLAYIO_SMODE:
302 		mode = *(u_int *)data;
303 		if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags &
304 		    CG6_CFFLAG_NOACCEL) == 0) {
305 			if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL &&
306 			    mode == WSDISPLAYIO_MODE_EMUL)
307 				cgsix_ras_init(sc);
308 		}
309 		sc->sc_mode = mode;
310 		break;
311 	case WSDISPLAYIO_GINFO:
312 		wdf = (void *)data;
313 		wdf->height = sc->sc_sunfb.sf_height;
314 		wdf->width  = sc->sc_sunfb.sf_width;
315 		wdf->depth  = sc->sc_sunfb.sf_depth;
316 		wdf->cmsize = 256;
317 		break;
318 	case WSDISPLAYIO_LINEBYTES:
319 		*(u_int *)data = sc->sc_sunfb.sf_linebytes;
320 		break;
321 	case WSDISPLAYIO_GETCMAP:
322 		cm = (struct wsdisplay_cmap *)data;
323 		error = cg6_bt_getcmap(&sc->sc_cmap, cm);
324 		if (error)
325 			return (error);
326 		break;
327 	case WSDISPLAYIO_PUTCMAP:
328 		cm = (struct wsdisplay_cmap *)data;
329 		error = cg6_bt_putcmap(&sc->sc_cmap, cm);
330 		if (error)
331 			return (error);
332 		cgsix_loadcmap_deferred(sc, cm->index, cm->count);
333 		break;
334 	case WSDISPLAYIO_SCURSOR:
335 		curs = (struct wsdisplay_cursor *)data;
336 		return (cgsix_setcursor(sc, curs));
337 	case WSDISPLAYIO_GCURSOR:
338 		curs = (struct wsdisplay_cursor *)data;
339 		if (curs->which & WSDISPLAY_CURSOR_DOCUR)
340 			curs->enable = sc->sc_curs_enabled;
341 		if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
342 			curs->pos.x = sc->sc_curs_pos.x;
343 			curs->pos.y = sc->sc_curs_pos.y;
344 		}
345 		if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
346 			curs->hot.x = sc->sc_curs_hot.x;
347 			curs->hot.y = sc->sc_curs_hot.y;
348 		}
349 		if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
350 			curs->cmap.index = 0;
351 			curs->cmap.count = 2;
352 			r[0] = sc->sc_curs_fg >> 16;
353 			g[0] = sc->sc_curs_fg >> 8;
354 			b[0] = sc->sc_curs_fg >> 0;
355 			r[1] = sc->sc_curs_bg >> 16;
356 			g[1] = sc->sc_curs_bg >> 8;
357 			b[1] = sc->sc_curs_bg >> 0;
358 			error = copyout(r, curs->cmap.red, sizeof(r));
359 			if (error)
360 				return (error);
361 			error = copyout(g, curs->cmap.green, sizeof(g));
362 			if (error)
363 				return (error);
364 			error = copyout(b, curs->cmap.blue, sizeof(b));
365 			if (error)
366 				return (error);
367 		}
368 		if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
369 			size_t l;
370 
371 			curs->size.x = sc->sc_curs_size.x;
372 			curs->size.y = sc->sc_curs_size.y;
373 			l = (sc->sc_curs_size.x * sc->sc_curs_size.y) / NBBY;
374 			error = copyout(sc->sc_curs_image, curs->image, l);
375 			if (error)
376 				return (error);
377 			error = copyout(sc->sc_curs_mask, curs->mask, l);
378 			if (error)
379 				return (error);
380 		}
381 		break;
382 	case WSDISPLAYIO_GCURPOS:
383 		pos = (struct wsdisplay_curpos *)data;
384 		pos->x = sc->sc_curs_pos.x;
385 		pos->y = sc->sc_curs_pos.y;
386 		break;
387 	case WSDISPLAYIO_SCURPOS:
388 		pos = (struct wsdisplay_curpos *)data;
389 		s = spltty();
390 		sc->sc_curs_pos.x = pos->x;
391 		sc->sc_curs_pos.y = pos->y;
392 		cgsix_updatecursor(sc, WSDISPLAY_CURSOR_DOPOS);
393 		splx(s);
394 		break;
395 	case WSDISPLAYIO_GCURMAX:
396 		pos = (struct wsdisplay_curpos *)data;
397 		pos->x = pos->y = 32;
398 		break;
399 	case WSDISPLAYIO_SVIDEO:
400 	case WSDISPLAYIO_GVIDEO:
401 	default:
402 		return -1; /* not supported */
403         }
404 
405 	return (0);
406 }
407 
408 int
409 cgsix_setcursor(struct cgsix_softc *sc, struct wsdisplay_cursor *curs)
410 {
411 	u_int8_t r[2], g[2], b[2], image[128], mask[128];
412 	int s, error;
413 	size_t imcount;
414 
415 	/*
416 	 * Do stuff that can generate errors first, then we'll blast it
417 	 * all at once.
418 	 */
419 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
420 		if (curs->cmap.count < 2)
421 			return (EINVAL);
422 		error = copyin(curs->cmap.red, r, sizeof(r));
423 		if (error)
424 			return (error);
425 		error = copyin(curs->cmap.green, g, sizeof(g));
426 		if (error)
427 			return (error);
428 		error = copyin(curs->cmap.blue, b, sizeof(b));
429 		if (error)
430 			return (error);
431 	}
432 
433 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
434 		if (curs->size.x > CG6_MAX_CURSOR ||
435 		    curs->size.y > CG6_MAX_CURSOR)
436 			return (EINVAL);
437 		imcount = (curs->size.x * curs->size.y) / NBBY;
438 		error = copyin(curs->image, image, imcount);
439 		if (error)
440 			return (error);
441 		error = copyin(curs->mask, mask, imcount);
442 		if (error)
443 			return (error);
444 	}
445 
446 	/*
447 	 * Ok, everything is in kernel space and sane, update state.
448 	 */
449 	s = spltty();
450 
451 	if (curs->which & WSDISPLAY_CURSOR_DOCUR)
452 		sc->sc_curs_enabled = curs->enable;
453 	if (curs->which & WSDISPLAY_CURSOR_DOPOS) {
454 		sc->sc_curs_pos.x = curs->pos.x;
455 		sc->sc_curs_pos.y = curs->pos.y;
456 	}
457 	if (curs->which & WSDISPLAY_CURSOR_DOHOT) {
458 		sc->sc_curs_hot.x = curs->hot.x;
459 		sc->sc_curs_hot.y = curs->hot.y;
460 	}
461 	if (curs->which & WSDISPLAY_CURSOR_DOCMAP) {
462 		sc->sc_curs_fg = ((r[0] << 16) | (g[0] << 8) | (b[0] << 0));
463 		sc->sc_curs_bg = ((r[1] << 16) | (g[1] << 8) | (b[1] << 0));
464 	}
465 	if (curs->which & WSDISPLAY_CURSOR_DOSHAPE) {
466 		sc->sc_curs_size.x = curs->size.x;
467 		sc->sc_curs_size.y = curs->size.y;
468 		bcopy(image, sc->sc_curs_image, imcount);
469 		bcopy(mask, sc->sc_curs_mask, imcount);
470 	}
471 
472 	cgsix_updatecursor(sc, curs->which);
473 	splx(s);
474 
475 	return (0);
476 }
477 
478 int
479 cgsix_updatecursor(struct cgsix_softc *sc, u_int which)
480 {
481 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
482 		BT_WRITE(sc, BT_ADDR, BT_OV1 << 24);
483 		BT_WRITE(sc, BT_OMAP,
484 		    ((sc->sc_curs_fg & 0x00ff0000) >> 16) << 24);
485 		BT_WRITE(sc, BT_OMAP,
486 		    ((sc->sc_curs_fg & 0x0000ff00) >> 8) << 24);
487 		BT_WRITE(sc, BT_OMAP,
488 		    ((sc->sc_curs_fg & 0x000000ff) >> 0) << 24);
489 
490 		BT_WRITE(sc, BT_ADDR, BT_OV3 << 24);
491 		BT_WRITE(sc, BT_OMAP,
492 		    ((sc->sc_curs_bg & 0x00ff0000) >> 16) << 24);
493 		BT_WRITE(sc, BT_OMAP,
494 		    ((sc->sc_curs_bg & 0x0000ff00) >> 8) << 24);
495 		BT_WRITE(sc, BT_OMAP,
496 		    ((sc->sc_curs_bg & 0x000000ff) >> 0) << 24);
497 	}
498 
499 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
500 		u_int32_t x, y;
501 
502 		x = sc->sc_curs_pos.x + CG6_MAX_CURSOR - sc->sc_curs_hot.x;
503 		y = sc->sc_curs_pos.y + CG6_MAX_CURSOR - sc->sc_curs_hot.y;
504 		THC_WRITE(sc, CG6_THC_CURSXY,
505 		    ((x & 0xffff) << 16) | (y & 0xffff));
506 	}
507 
508 	if (which & WSDISPLAY_CURSOR_DOCUR) {
509 		u_int32_t c;
510 
511 		/* Enable or disable the cursor overlay planes */
512 		if (sc->sc_curs_enabled) {
513 			BT_WRITE(sc, BT_ADDR, BT_CR << 24);
514 			c = BT_READ(sc, BT_CTRL);
515 			c |= (BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24;
516 			BT_WRITE(sc, BT_CTRL, c);
517 		} else {
518 			BT_WRITE(sc, BT_ADDR, BT_CR << 24);
519 			c = BT_READ(sc, BT_CTRL);
520 			c &= ~((BTCR_DISPENA_OV0 | BTCR_DISPENA_OV1) << 24);
521 			BT_WRITE(sc, BT_CTRL, c);
522 			THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF);
523 		}
524 	}
525 
526 	return (0);
527 }
528 
529 int
530 cgsix_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
531     int *curxp, int *curyp, long *attrp)
532 {
533 	struct cgsix_softc *sc = v;
534 
535 	if (sc->sc_nscreens > 0)
536 		return (ENOMEM);
537 
538 	*cookiep = &sc->sc_sunfb.sf_ro;
539 	*curyp = 0;
540 	*curxp = 0;
541 	sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
542 	    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
543 	sc->sc_nscreens++;
544 	return (0);
545 }
546 
547 void
548 cgsix_free_screen(void *v, void *cookie)
549 {
550 	struct cgsix_softc *sc = v;
551 
552 	sc->sc_nscreens--;
553 }
554 
555 int
556 cgsix_show_screen(void *v, void *cookie, int waitok,
557     void (*cb)(void *, int, int), void *cbarg)
558 {
559 	return (0);
560 }
561 
562 struct mmo {
563 	off_t mo_uaddr;
564 	bus_size_t mo_size;
565 	bus_size_t mo_physoff;
566 };
567 
568 paddr_t
569 cgsix_mmap(void *v, off_t off, int prot)
570 {
571 	struct cgsix_softc *sc = v;
572 	struct mmo *mo;
573 	bus_addr_t u;
574 	bus_size_t sz;
575 
576 	static struct mmo mmo[] = {
577 		{ CG6_USER_RAM, 0, CGSIX_VID_OFFSET },
578 
579 		/* do not actually know how big most of these are! */
580 		{ CG6_USER_FBC, 1, CGSIX_FBC_OFFSET },
581 		{ CG6_USER_TEC, 1, CGSIX_TEC_OFFSET },
582 		{ CG6_USER_BTREGS, 8192 /* XXX */, CGSIX_BT_OFFSET },
583 		{ CG6_USER_FHC, 1, CGSIX_FHC_OFFSET },
584 		{ CG6_USER_THC, CGSIX_THC_SIZE, CGSIX_THC_OFFSET },
585 		{ CG6_USER_ROM, 65536, CGSIX_ROM_OFFSET },
586 		{ CG6_USER_DHC, 1, CGSIX_DHC_OFFSET },
587 	};
588 #define	NMMO (sizeof mmo / sizeof *mmo)
589 
590 	if (off & PGOFSET || off < 0)
591 		return (-1);
592 
593 	switch (sc->sc_mode) {
594 	case WSDISPLAYIO_MODE_MAPPED:
595 		for (mo = mmo; mo < &mmo[NMMO]; mo++) {
596 			if (off < mo->mo_uaddr)
597 				continue;
598 			u = off - mo->mo_uaddr;
599 			sz = mo->mo_size ? mo->mo_size : sc->sc_sunfb.sf_fbsize;
600 			if (u < sz) {
601 				return (bus_space_mmap(sc->sc_bustag,
602 				    sc->sc_paddr, u + mo->mo_physoff,
603 				    prot, BUS_SPACE_MAP_LINEAR));
604 			}
605 		}
606 		break;
607 
608 	case WSDISPLAYIO_MODE_DUMBFB:
609 		/* Allow mapping as a dumb framebuffer from offset 0 */
610 		if (off >= 0 && off < sc->sc_sunfb.sf_fbsize)
611 			return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
612 			    off + CGSIX_VID_OFFSET, prot,
613 			    BUS_SPACE_MAP_LINEAR));
614 		break;
615 	}
616 
617 	return (-1);
618 }
619 
620 int
621 cgsix_is_console(int node)
622 {
623 	extern int fbnode;
624 
625 	return (fbnode == node);
626 }
627 
628 int
629 cg6_bt_getcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm)
630 {
631 	u_int index = rcm->index, count = rcm->count, i;
632 	int error;
633 
634 	if (index >= 256 || count > 256 - index)
635 		return (EINVAL);
636 	for (i = 0; i < count; i++) {
637 		if ((error = copyout(&bcm->cm_map[index + i][0],
638 		    &rcm->red[i], 1)) != 0)
639 			return (error);
640 		if ((error = copyout(&bcm->cm_map[index + i][1],
641 		    &rcm->green[i], 1)) != 0)
642 			return (error);
643 		if ((error = copyout(&bcm->cm_map[index + i][2],
644 		    &rcm->blue[i], 1)) != 0)
645 			return (error);
646 	}
647 	return (0);
648 }
649 
650 int
651 cg6_bt_putcmap(union bt_cmap *bcm, struct wsdisplay_cmap *rcm)
652 {
653 	u_int index = rcm->index, count = rcm->count, i;
654 	int error;
655 
656 	if (index >= 256 || count > 256 - index)
657 		return (EINVAL);
658 	for (i = 0; i < count; i++) {
659 		if ((error = copyin(&rcm->red[i],
660 		    &bcm->cm_map[index + i][0], 1)) != 0)
661 			return (error);
662 		if ((error = copyin(&rcm->green[i],
663 		    &bcm->cm_map[index + i][1], 1)) != 0)
664 			return (error);
665 		if ((error = copyin(&rcm->blue[i],
666 		    &bcm->cm_map[index + i][2], 1)) != 0)
667 			return (error);
668 	}
669 	return (0);
670 }
671 
672 void
673 cgsix_loadcmap_deferred(struct cgsix_softc *sc, u_int start, u_int ncolors)
674 {
675 	u_int32_t thcm;
676 
677 	thcm = THC_READ(sc, CG6_THC_MISC);
678 	thcm &= ~THC_MISC_RESET;
679 	thcm |= THC_MISC_INTEN;
680 	THC_WRITE(sc, CG6_THC_MISC, thcm);
681 }
682 
683 void
684 cgsix_loadcmap_immediate(struct cgsix_softc *sc, u_int start, u_int ncolors)
685 {
686 	u_int cstart;
687 	u_int32_t v;
688 	int count;
689 
690 	cstart = BT_D4M3(start);
691 	count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3;
692 	BT_WRITE(sc, BT_ADDR, BT_D4M4(start) << 24);
693 	while (--count >= 0) {
694 		v = sc->sc_cmap.cm_chip[cstart];
695 		BT_WRITE(sc, BT_CMAP, v << 0);
696 		BT_WRITE(sc, BT_CMAP, v << 8);
697 		BT_WRITE(sc, BT_CMAP, v << 16);
698 		BT_WRITE(sc, BT_CMAP, v << 24);
699 		cstart++;
700 	}
701 }
702 
703 void
704 cgsix_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
705 {
706 	struct cgsix_softc *sc = v;
707 	union bt_cmap *bcm = &sc->sc_cmap;
708 
709 	bcm->cm_map[index][0] = r;
710 	bcm->cm_map[index][1] = g;
711 	bcm->cm_map[index][2] = b;
712 	cgsix_loadcmap_immediate(sc, index, 1);
713 }
714 
715 void
716 cgsix_reset(struct cgsix_softc *sc, u_int32_t fhcrev)
717 {
718 	u_int32_t fhc;
719 
720 	/* hide the cursor, just in case */
721 	THC_WRITE(sc, CG6_THC_CURSXY, THC_CURSOFF);
722 
723 	TEC_WRITE(sc, CG6_TEC_MV, 0);
724 	TEC_WRITE(sc, CG6_TEC_CLIP, 0);
725 	TEC_WRITE(sc, CG6_TEC_VDC, 0);
726 
727 	/* take core of hardware bugs in old revisions */
728 	if (fhcrev < 5) {
729 		/*
730 		 * Keep current resolution; set cpu to 68020, set test
731 		 * window (size 1Kx1K), and for rev 1, disable dest cache.
732 		 */
733 		fhc = FHC_READ(sc);
734 		fhc &= FHC_RES_MASK;
735 		fhc |= FHC_CPU_68020 | FHC_TEST |
736 		    (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT);
737 		if (fhcrev < 2)
738 			fhc |= FHC_DST_DISABLE;
739 		FHC_WRITE(sc, fhc);
740 	}
741 
742 	/* enable cursor overlays in brooktree DAC */
743 	BT_WRITE(sc, BT_ADDR, BT_CR << 24);
744 	BT_WRITE(sc, BT_CTRL, BT_READ(sc, BT_CTRL) |
745 	    ((BTCR_DISPENA_OV1 | BTCR_DISPENA_OV0) << 24));
746 }
747 
748 void
749 cgsix_hardreset(struct cgsix_softc *sc)
750 {
751 	u_int32_t fhc, rev;
752 
753 	/* enable all of the bit planes */
754 	BT_WRITE(sc, BT_ADDR, BT_RMR << 24);
755 	BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
756 	BT_WRITE(sc, BT_CTRL, 0xff << 24);
757 	BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
758 
759 	/* no bit planes should blink */
760 	BT_WRITE(sc, BT_ADDR, BT_BMR << 24);
761 	BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
762 	BT_WRITE(sc, BT_CTRL, 0x00 << 24);
763 	BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
764 
765 	/*
766 	 * enable the RAMDAC, disable blink, disable overlay 0 and 1,
767 	 * use 4:1 multiplexor.
768 	 */
769 	BT_WRITE(sc, BT_ADDR, BT_CR << 24);
770 	BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
771 	BT_WRITE(sc, BT_CTRL,
772 	    (BTCR_MPLX_4 | BTCR_RAMENA | BTCR_BLINK_6464) << 24);
773 	BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
774 
775 	/* disable the D/A read pins */
776 	BT_WRITE(sc, BT_ADDR, BT_CTR << 24);
777 	BT_BARRIER(sc, BT_ADDR, BUS_SPACE_BARRIER_WRITE);
778 	BT_WRITE(sc, BT_CTRL, 0x00 << 24);
779 	BT_BARRIER(sc, BT_CTRL, BUS_SPACE_BARRIER_WRITE);
780 
781 	/* configure thc */
782 	THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR |
783 	    THC_MISC_CYCLS);
784 	THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS);
785 
786 	THC_WRITE(sc, CG6_THC_HSYNC1, 0x10009);
787 	THC_WRITE(sc, CG6_THC_HSYNC2, 0x570000);
788 	THC_WRITE(sc, CG6_THC_HSYNC3, 0x15005d);
789 	THC_WRITE(sc, CG6_THC_VSYNC1, 0x10005);
790 	THC_WRITE(sc, CG6_THC_VSYNC2, 0x2403a8);
791 	THC_WRITE(sc, CG6_THC_REFRESH, 0x16b);
792 
793 	THC_WRITE(sc, CG6_THC_MISC, THC_MISC_RESET | THC_MISC_INTR |
794 	    THC_MISC_CYCLS);
795 	THC_WRITE(sc, CG6_THC_MISC, THC_MISC_INTR | THC_MISC_CYCLS);
796 
797 	/* configure fhc (1152x900) */
798 	fhc = FHC_READ(sc);
799 	rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT;
800 
801 	fhc = FHC_RES_1152 | FHC_CPU_68020 | FHC_TEST;
802 	if (rev < 1)
803 		fhc |= FHC_FROP_DISABLE;
804 	if (rev < 2)
805 		fhc |= FHC_DST_DISABLE;
806 	FHC_WRITE(sc, fhc);
807 }
808 
809 void
810 cgsix_burner(void *vsc, u_int on, u_int flags)
811 {
812 	struct cgsix_softc *sc = vsc;
813 	int s;
814 	u_int32_t thcm;
815 
816 	s = splhigh();
817 	thcm = THC_READ(sc, CG6_THC_MISC);
818 	if (on)
819 		thcm |= THC_MISC_VIDEN | THC_MISC_SYNCEN;
820 	else {
821 		thcm &= ~THC_MISC_VIDEN;
822 		if (flags & WSDISPLAY_BURN_VBLANK)
823 			thcm &= ~THC_MISC_SYNCEN;
824 	}
825 	THC_WRITE(sc, CG6_THC_MISC, thcm);
826 	splx(s);
827 }
828 
829 int
830 cgsix_intr(void *vsc)
831 {
832 	struct cgsix_softc *sc = vsc;
833 	u_int32_t thcm;
834 
835 	thcm = THC_READ(sc, CG6_THC_MISC);
836 	if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) !=
837 	    (THC_MISC_INTEN | THC_MISC_INTR)) {
838 		/* Not expecting an interrupt, it's not for us. */
839 		return (0);
840 	}
841 
842 	/* Acknowledge the interrupt and disable it. */
843 	thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN);
844 	thcm |= THC_MISC_INTR;
845 	THC_WRITE(sc, CG6_THC_MISC, thcm);
846 	cgsix_loadcmap_immediate(sc, 0, 256);
847 	return (1);
848 }
849 
850 void
851 cgsix_ras_init(struct cgsix_softc *sc)
852 {
853 	u_int32_t m;
854 
855 	CG6_DRAIN(sc);
856 	m = FBC_READ(sc, CG6_FBC_MODE);
857 	m &= ~FBC_MODE_MASK;
858 	m |= FBC_MODE_VAL;
859 	FBC_WRITE(sc, CG6_FBC_MODE, m);
860 }
861 
862 void
863 cgsix_ras_copyrows(void *cookie, int src, int dst, int n)
864 {
865 	struct rasops_info *ri = cookie;
866 	struct cgsix_softc *sc = ri->ri_hw;
867 
868 	if (dst == src)
869 		return;
870 	if (src < 0) {
871 		n += src;
872 		src = 0;
873 	}
874 	if (src + n > ri->ri_rows)
875 		n = ri->ri_rows - src;
876 	if (dst < 0) {
877 		n += dst;
878 		dst = 0;
879 	}
880 	if (dst + n > ri->ri_rows)
881 		n = ri->ri_rows - dst;
882 	if (n <= 0)
883 		return;
884 	n *= ri->ri_font->fontheight;
885 	src *= ri->ri_font->fontheight;
886 	dst *= ri->ri_font->fontheight;
887 
888 	FBC_WRITE(sc, CG6_FBC_CLIP, 0);
889 	FBC_WRITE(sc, CG6_FBC_S, 0);
890 	FBC_WRITE(sc, CG6_FBC_OFFX, 0);
891 	FBC_WRITE(sc, CG6_FBC_OFFY, 0);
892 	FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
893 	FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
894 	FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
895 	FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
896 	FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY);
897 	FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin);
898 	FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + src);
899 	FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + ri->ri_emuwidth - 1);
900 	FBC_WRITE(sc, CG6_FBC_Y1, ri->ri_yorigin + src + n - 1);
901 	FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin);
902 	FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + dst);
903 	FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + ri->ri_emuwidth - 1);
904 	FBC_WRITE(sc, CG6_FBC_Y3, ri->ri_yorigin + dst + n - 1);
905 	CG6_BLIT_WAIT(sc);
906 	CG6_DRAIN(sc);
907 }
908 
909 void
910 cgsix_ras_copycols(void *cookie, int row, int src, int dst, int n)
911 {
912 	struct rasops_info *ri = cookie;
913 	struct cgsix_softc *sc = ri->ri_hw;
914 
915 	if (dst == src)
916 		return;
917 	if ((row < 0) || (row >= ri->ri_rows))
918 		return;
919 	if (src < 0) {
920 		n += src;
921 		src = 0;
922 	}
923 	if (src + n > ri->ri_cols)
924 		n = ri->ri_cols - src;
925 	if (dst < 0) {
926 		n += dst;
927 		dst = 0;
928 	}
929 	if (dst + n > ri->ri_cols)
930 		n = ri->ri_cols - dst;
931 	if (n <= 0)
932 		return;
933 	n *= ri->ri_font->fontwidth;
934 	src *= ri->ri_font->fontwidth;
935 	dst *= ri->ri_font->fontwidth;
936 	row *= ri->ri_font->fontheight;
937 
938 	FBC_WRITE(sc, CG6_FBC_CLIP, 0);
939 	FBC_WRITE(sc, CG6_FBC_S, 0);
940 	FBC_WRITE(sc, CG6_FBC_OFFX, 0);
941 	FBC_WRITE(sc, CG6_FBC_OFFY, 0);
942 	FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
943 	FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
944 	FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
945 	FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
946 	FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_COPY);
947 	FBC_WRITE(sc, CG6_FBC_X0, ri->ri_xorigin + src);
948 	FBC_WRITE(sc, CG6_FBC_Y0, ri->ri_yorigin + row);
949 	FBC_WRITE(sc, CG6_FBC_X1, ri->ri_xorigin + src + n - 1);
950 	FBC_WRITE(sc, CG6_FBC_Y1,
951 	    ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
952 	FBC_WRITE(sc, CG6_FBC_X2, ri->ri_xorigin + dst);
953 	FBC_WRITE(sc, CG6_FBC_Y2, ri->ri_yorigin + row);
954 	FBC_WRITE(sc, CG6_FBC_X3, ri->ri_xorigin + dst + n - 1);
955 	FBC_WRITE(sc, CG6_FBC_Y3,
956 	    ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
957 	CG6_BLIT_WAIT(sc);
958 	CG6_DRAIN(sc);
959 }
960 
961 void
962 cgsix_ras_erasecols(void *cookie, int row, int col, int n, long int attr)
963 {
964 	struct rasops_info *ri = cookie;
965 	struct cgsix_softc *sc = ri->ri_hw;
966 
967 	if ((row < 0) || (row >= ri->ri_rows))
968 		return;
969 	if (col < 0) {
970 		n += col;
971 		col = 0;
972 	}
973 	if (col + n > ri->ri_cols)
974 		n = ri->ri_cols - col;
975 	if (n <= 0)
976 		return;
977 	n *= ri->ri_font->fontwidth;
978 	col *= ri->ri_font->fontwidth;
979 	row *= ri->ri_font->fontheight;
980 
981 	FBC_WRITE(sc, CG6_FBC_CLIP, 0);
982 	FBC_WRITE(sc, CG6_FBC_S, 0);
983 	FBC_WRITE(sc, CG6_FBC_OFFX, 0);
984 	FBC_WRITE(sc, CG6_FBC_OFFY, 0);
985 	FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
986 	FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
987 	FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
988 	FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
989 	FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL);
990 	FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[(attr >> 16) & 0xf]);
991 	FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
992 	FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col);
993 	FBC_WRITE(sc, CG6_FBC_ARECTY,
994 	    ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
995 	FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col + n - 1);
996 	CG6_DRAW_WAIT(sc);
997 	CG6_DRAIN(sc);
998 }
999 
1000 void
1001 cgsix_ras_eraserows(void *cookie, int row, int n, long int attr)
1002 {
1003 	struct rasops_info *ri = cookie;
1004 	struct cgsix_softc *sc = ri->ri_hw;
1005 
1006 	if (row < 0) {
1007 		n += row;
1008 		row = 0;
1009 	}
1010 	if (row + n > ri->ri_rows)
1011 		n = ri->ri_rows - row;
1012 	if (n <= 0)
1013 		return;
1014 
1015 	FBC_WRITE(sc, CG6_FBC_CLIP, 0);
1016 	FBC_WRITE(sc, CG6_FBC_S, 0);
1017 	FBC_WRITE(sc, CG6_FBC_OFFX, 0);
1018 	FBC_WRITE(sc, CG6_FBC_OFFY, 0);
1019 	FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
1020 	FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
1021 	FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
1022 	FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
1023 	FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FILL);
1024 	FBC_WRITE(sc, CG6_FBC_FG, ri->ri_devcmap[(attr >> 16) & 0xf]);
1025 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
1026 		FBC_WRITE(sc, CG6_FBC_ARECTY, 0);
1027 		FBC_WRITE(sc, CG6_FBC_ARECTX, 0);
1028 		FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_height - 1);
1029 		FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_width - 1);
1030 	} else {
1031 		row *= ri->ri_font->fontheight;
1032 		FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
1033 		FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin);
1034 		FBC_WRITE(sc, CG6_FBC_ARECTY,
1035 		    ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1);
1036 		FBC_WRITE(sc, CG6_FBC_ARECTX,
1037 		    ri->ri_xorigin + ri->ri_emuwidth - 1);
1038 	}
1039 	CG6_DRAW_WAIT(sc);
1040 	CG6_DRAIN(sc);
1041 }
1042 
1043 void
1044 cgsix_ras_do_cursor(struct rasops_info *ri)
1045 {
1046 	struct cgsix_softc *sc = ri->ri_hw;
1047 	int row, col;
1048 
1049 	row = ri->ri_crow * ri->ri_font->fontheight;
1050 	col = ri->ri_ccol * ri->ri_font->fontwidth;
1051 	FBC_WRITE(sc, CG6_FBC_CLIP, 0);
1052 	FBC_WRITE(sc, CG6_FBC_S, 0);
1053 	FBC_WRITE(sc, CG6_FBC_OFFX, 0);
1054 	FBC_WRITE(sc, CG6_FBC_OFFY, 0);
1055 	FBC_WRITE(sc, CG6_FBC_CLIPMINX, 0);
1056 	FBC_WRITE(sc, CG6_FBC_CLIPMINY, 0);
1057 	FBC_WRITE(sc, CG6_FBC_CLIPMAXX, ri->ri_width - 1);
1058 	FBC_WRITE(sc, CG6_FBC_CLIPMAXY, ri->ri_height - 1);
1059 	FBC_WRITE(sc, CG6_FBC_ALU, FBC_ALU_FLIP);
1060 	FBC_WRITE(sc, CG6_FBC_ARECTY, ri->ri_yorigin + row);
1061 	FBC_WRITE(sc, CG6_FBC_ARECTX, ri->ri_xorigin + col);
1062 	FBC_WRITE(sc, CG6_FBC_ARECTY,
1063 	    ri->ri_yorigin + row + ri->ri_font->fontheight - 1);
1064 	FBC_WRITE(sc, CG6_FBC_ARECTX,
1065 	    ri->ri_xorigin + col + ri->ri_font->fontwidth - 1);
1066 	CG6_DRAW_WAIT(sc);
1067 	CG6_DRAIN(sc);
1068 }
1069 
1070 void
1071 cgsix_ras_updatecursor(struct rasops_info *ri)
1072 {
1073 	struct cgsix_softc *sc = ri->ri_hw;
1074 
1075 	if (sc->sc_sunfb.sf_crowp != NULL)
1076 		*sc->sc_sunfb.sf_crowp = ri->ri_crow;
1077 	if (sc->sc_sunfb.sf_ccolp != NULL)
1078 		*sc->sc_sunfb.sf_ccolp = ri->ri_ccol;
1079 }
1080