xref: /netbsd-src/sys/arch/sparc/dev/cgfourteen.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /*	$NetBSD: cgfourteen.c,v 1.21 2001/09/24 23:49:31 eeh Exp $ */
2 
3 /*
4  * Copyright (c) 1996
5  *	The President and Fellows of Harvard College. All rights reserved.
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by Harvard University.
16  *	This product includes software developed by the University of
17  *	California, Lawrence Berkeley Laboratory.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  * 1. Redistributions of source code must retain the above copyright
23  *    notice, this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in the
26  *    documentation and/or other materials provided with the distribution.
27  * 3. All advertising materials mentioning features or use of this software
28  *    must display the following acknowledgement:
29  *	This product includes software developed by the University of
30  *	California, Berkeley and its contributors.
31  *	This product includes software developed by Harvard University and
32  *	its contributors.
33  * 4. Neither the name of the University nor the names of its contributors
34  *    may be used to endorse or promote products derived from this software
35  *    without specific prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  *   Based on:
50  *	NetBSD: cgthree.c,v 1.28 1996/05/31 09:59:22 pk Exp
51  *	NetBSD: cgsix.c,v 1.25 1996/04/01 17:30:00 christos Exp
52  */
53 
54 /*
55  * Driver for Campus-II on-board mbus-based video (cgfourteen).
56  * Provides minimum emulation of a Sun cgthree 8-bit framebuffer to
57  * allow X to run.
58  *
59  * Does not handle interrupts, even though they can occur.
60  *
61  * XXX should defer colormap updates to vertical retrace interrupts
62  */
63 
64 /*
65  * The following is for debugging only; it opens up a security hole
66  * enabled by allowing any user to map the control registers for the
67  * cg14 into their space.
68  */
69 #undef CG14_MAP_REGS
70 
71 /*
72  * The following enables 24-bit operation: when opened, the framebuffer
73  * will switch to 24-bit mode (actually 32-bit mode), and provide a
74  * simple cg8 emulation.
75  *
76  * XXX Note that the code enabled by this define is currently untested/broken.
77  */
78 #undef CG14_CG8
79 
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/buf.h>
83 #include <sys/device.h>
84 #include <sys/ioctl.h>
85 #include <sys/malloc.h>
86 #include <sys/mman.h>
87 #include <sys/tty.h>
88 #include <sys/conf.h>
89 
90 #include <uvm/uvm_extern.h>
91 
92 #include <machine/bus.h>
93 #include <machine/autoconf.h>
94 #include <machine/conf.h>
95 
96 #include <dev/sbus/sbusvar.h>
97 
98 #include <dev/sun/fbio.h>
99 #include <dev/sun/fbvar.h>
100 
101 #include <sparc/dev/cgfourteenreg.h>
102 #include <sparc/dev/cgfourteenvar.h>
103 
104 /* autoconfiguration driver */
105 static void	cgfourteenattach(struct device *, struct device *, void *);
106 static int	cgfourteenmatch(struct device *, struct cfdata *, void *);
107 static void	cgfourteenunblank(struct device *);
108 
109 /* cdevsw prototypes */
110 cdev_decl(cgfourteen);
111 
112 struct cfattach cgfourteen_ca = {
113 	sizeof(struct cgfourteen_softc), cgfourteenmatch, cgfourteenattach
114 };
115 
116 extern struct cfdriver cgfourteen_cd;
117 
118 /* frame buffer generic driver */
119 static struct fbdriver cgfourteenfbdriver = {
120 	cgfourteenunblank, cgfourteenopen, cgfourteenclose, cgfourteenioctl,
121 	cgfourteenpoll, cgfourteenmmap
122 };
123 
124 static void cg14_set_video __P((struct cgfourteen_softc *, int));
125 static int  cg14_get_video __P((struct cgfourteen_softc *));
126 static int  cg14_get_cmap __P((struct fbcmap *, union cg14cmap *, int));
127 static int  cg14_put_cmap __P((struct fbcmap *, union cg14cmap *, int));
128 static void cg14_load_hwcmap __P((struct cgfourteen_softc *, int, int));
129 static void cg14_init __P((struct cgfourteen_softc *));
130 static void cg14_reset __P((struct cgfourteen_softc *));
131 static void cg14_loadomap __P((struct cgfourteen_softc *));/* cursor overlay */
132 static void cg14_setcursor __P((struct cgfourteen_softc *));/* set position */
133 static void cg14_loadcursor __P((struct cgfourteen_softc *));/* set shape */
134 
135 /*
136  * Match a cgfourteen.
137  */
138 int
139 cgfourteenmatch(parent, cf, aux)
140 	struct device *parent;
141 	struct cfdata *cf;
142 	void *aux;
143 {
144 	union obio_attach_args *uoba = aux;
145 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
146 
147 	/*
148 	 * The cgfourteen is a local-bus video adaptor, accessed directly
149 	 * via the processor, and not through device space or an external
150 	 * bus. Thus we look _only_ at the obio bus.
151 	 * Additionally, these things exist only on the Sun4m.
152 	 */
153 
154 	if (uoba->uoba_isobio4 != 0 || !CPU_ISSUN4M)
155 		return (0);
156 
157 	/* Check driver name */
158 	return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
159 }
160 
161 /*
162  * Attach a display.  We need to notice if it is the console, too.
163  */
164 void
165 cgfourteenattach(parent, self, aux)
166 	struct device *parent, *self;
167 	void *aux;
168 {
169 	union obio_attach_args *uoba = aux;
170 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
171 	struct cgfourteen_softc *sc = (struct cgfourteen_softc *)self;
172 	struct fbdevice *fb = &sc->sc_fb;
173 	bus_space_handle_t bh;
174 	int node, ramsize;
175 	u_int32_t *lut;
176 	int i, isconsole;
177 
178 	node = sa->sa_node;
179 
180 	/* Remember cookies for cgfourteenmmap() */
181 	sc->sc_bustag = sa->sa_bustag;
182 
183 	fb->fb_driver = &cgfourteenfbdriver;
184 	fb->fb_device = &sc->sc_dev;
185 	/* Mask out invalid flags from the user. */
186 	fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK;
187 
188 	/*
189 	 * We're emulating a cg3/8, so represent ourselves as one
190 	 */
191 #ifdef CG14_CG8
192 	fb->fb_type.fb_type = FBTYPE_MEMCOLOR;
193 	fb->fb_type.fb_depth = 32;
194 #else
195 	fb->fb_type.fb_type = FBTYPE_SUN3COLOR;
196 	fb->fb_type.fb_depth = 8;
197 #endif
198 	fb_setsize_obp(fb, sc->sc_fb.fb_type.fb_depth, 1152, 900, node);
199 
200 	ramsize = roundup(fb->fb_type.fb_height * fb->fb_linebytes, NBPG);
201 	fb->fb_type.fb_cmsize = CG14_CLUT_SIZE;
202 	fb->fb_type.fb_size = ramsize;
203 
204 	if (sa->sa_nreg < 2) {
205 		printf("%s: only %d register sets\n",
206 			self->dv_xname, sa->sa_nreg);
207 		return;
208 	}
209 	bcopy(sa->sa_reg, sc->sc_physadr,
210 	      sa->sa_nreg * sizeof(struct sbus_reg));
211 
212 	/*
213 	 * Now map in the 8 useful pages of registers
214 	 */
215 	if (sa->sa_size < 0x10000) {
216 #ifdef DIAGNOSTIC
217 		printf("warning: can't find all cgfourteen registers...\n");
218 #endif
219 		sa->sa_size = 0x10000;
220 	}
221 	if (sbus_bus_map(sa->sa_bustag, sa->sa_slot,
222 			 sa->sa_offset,
223 			 sa->sa_size,
224 			 BUS_SPACE_MAP_LINEAR,
225 			 0, &bh) != 0) {
226 		printf("%s: cannot map control registers\n", self->dv_xname);
227 		return;
228 	}
229 
230 	sc->sc_ctl   = (struct cg14ctl  *) (bh);
231 	sc->sc_hwc   = (struct cg14curs *) (bh + CG14_OFFSET_CURS);
232 	sc->sc_dac   = (struct cg14dac  *) (bh + CG14_OFFSET_DAC);
233 	sc->sc_xlut  = (struct cg14xlut *) (bh + CG14_OFFSET_XLUT);
234 	sc->sc_clut1 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT1);
235 	sc->sc_clut2 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT2);
236 	sc->sc_clut3 = (struct cg14clut *) (bh + CG14_OFFSET_CLUT3);
237 	sc->sc_clutincr =        (u_int *) (bh + CG14_OFFSET_CLUTINCR);
238 
239 	/*
240 	 * Let the user know that we're here
241 	 */
242 #ifdef CG14_CG8
243 	printf(": cgeight emulated at %dx%dx24bpp",
244 		fb->fb_type.fb_width, fb->fb_type.fb_height);
245 #else
246 	printf(": cgthree emulated at %dx%dx8bpp",
247 		fb->fb_type.fb_width, fb->fb_type.fb_height);
248 #endif
249 	/*
250 	 * Enable the video, but don't change the pixel depth.
251 	 */
252 	cg14_set_video(sc, 1);
253 
254 	/*
255 	 * Grab the initial colormap
256 	 */
257 	lut = (u_int32_t *) sc->sc_clut1->clut_lut;
258 	for (i = 0; i < CG14_CLUT_SIZE; i++)
259 		sc->sc_cmap.cm_chip[i] = lut[i];
260 
261 	/* See if we're the console */
262 	isconsole = fb_is_console(node);
263 
264 	if (isconsole) {
265 		printf(" (console)\n");
266 #ifdef notdef
267 		/*
268 		 * We don't use the raster console since the cg14 is
269 		 * fast enough already.
270 		 */
271 #ifdef RASTERCONSOLE
272 		fbrcons_init(fb);
273 #endif
274 #endif /* notdef */
275 	} else
276 		printf("\n");
277 
278 	/* Attach to /dev/fb */
279 	fb_attach(&sc->sc_fb, isconsole);
280 }
281 
282 /*
283  * Keep track of the number of opens made. In the 24-bit driver, we need to
284  * switch to 24-bit mode on the first open, and switch back to 8-bit on
285  * the last close. This kind of nonsense is needed to give screenblank
286  * a fighting chance of working.
287  */
288 static int cg14_opens = 0;
289 
290 int
291 cgfourteenopen(dev, flags, mode, p)
292 	dev_t dev;
293 	int flags, mode;
294 	struct proc *p;
295 {
296 	struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)];
297 	int unit = minor(dev);
298 	int s, oldopens;
299 
300 	if (unit >= cgfourteen_cd.cd_ndevs ||
301 	    cgfourteen_cd.cd_devs[unit] == NULL)
302 		return (ENXIO);
303 
304 	s = splhigh();
305 	oldopens = cg14_opens++;
306 	splx(s);
307 
308 	/* Setup the cg14 as we want it, and save the original PROM state */
309 	if (oldopens == 0)	/* first open only, to make screenblank work */
310 		cg14_init(sc);
311 
312 	return (0);
313 }
314 
315 int
316 cgfourteenclose(dev, flags, mode, p)
317 	dev_t dev;
318 	int flags, mode;
319 	struct proc *p;
320 {
321 	struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)];
322 	int s, opens;
323 
324 	s = splhigh();
325 	opens = --cg14_opens;
326 	if (cg14_opens < 0)
327 		opens = cg14_opens = 0;
328 	splx(s);
329 
330 	/*
331 	 * Restore video state to make the PROM happy, on last close.
332 	 */
333 	if (opens == 0)
334 		cg14_reset(sc);
335 
336 	return (0);
337 }
338 
339 int
340 cgfourteenioctl(dev, cmd, data, flags, p)
341 	dev_t dev;
342 	u_long cmd;
343 	caddr_t data;
344 	int flags;
345 	struct proc *p;
346 {
347 	struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)];
348 	struct fbgattr *fba;
349 	union cg14cursor_cmap tcm;
350 	int v, error;
351 	u_int count;
352 
353 	switch (cmd) {
354 
355 	case FBIOGTYPE:
356 		*(struct fbtype *)data = sc->sc_fb.fb_type;
357 		break;
358 
359 	case FBIOGATTR:
360 		fba = (struct fbgattr *)data;
361 		fba->real_type = FBTYPE_MDICOLOR;
362 		fba->owner = 0;		/* XXX ??? */
363 		fba->fbtype = sc->sc_fb.fb_type;
364 		fba->sattr.flags = 0;
365 		fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
366 		fba->sattr.dev_specific[0] = -1;
367 		fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
368 		fba->emu_types[1] = -1;
369 		break;
370 
371 	case FBIOGETCMAP:
372 		return (cg14_get_cmap((struct fbcmap *)data, &sc->sc_cmap,
373 				     CG14_CLUT_SIZE));
374 
375 	case FBIOPUTCMAP:
376 		/* copy to software map */
377 #define p ((struct fbcmap *)data)
378 #ifdef CG14_CG8
379 		p->index &= 0xffffff;
380 #endif
381 		error = cg14_put_cmap(p, &sc->sc_cmap, CG14_CLUT_SIZE);
382 		if (error)
383 			return (error);
384 		/* now blast them into the chip */
385 		/* XXX should use retrace interrupt */
386 		cg14_load_hwcmap(sc, p->index, p->count);
387 #undef p
388 		break;
389 
390 	case FBIOGVIDEO:
391 		*(int *)data = cg14_get_video(sc);
392 		break;
393 
394 	case FBIOSVIDEO:
395 		cg14_set_video(sc, *(int *)data);
396 		break;
397 
398 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
399 #define p ((struct fbcursor *)data)
400 #define cc (&sc->sc_cursor)
401 	case FBIOGCURSOR:
402 		/* do not quite want everything here... */
403 		p->set = FB_CUR_SETALL;	/* close enough, anyway */
404 		p->enable = cc->cc_enable;
405 		p->pos = cc->cc_pos;
406 		p->hot = cc->cc_hot;
407 		p->size = cc->cc_size;
408 
409 		/* begin ugh ... can we lose some of this crap?? */
410 		if (p->image != NULL) {
411 			count = cc->cc_size.y * 32 / NBBY;
412 			error = copyout((caddr_t)cc->cc_cplane,
413 			    (caddr_t)p->image, count);
414 			if (error)
415 				return (error);
416 			error = copyout((caddr_t)cc->cc_eplane,
417 			    (caddr_t)p->mask, count);
418 			if (error)
419 				return (error);
420 		}
421 		if (p->cmap.red != NULL) {
422 			error = cg14_get_cmap(&p->cmap,
423 			    (union cg14cmap *)&cc->cc_color, 2);
424 			if (error)
425 				return (error);
426 		} else {
427 			p->cmap.index = 0;
428 			p->cmap.count = 2;
429 		}
430 		/* end ugh */
431 		break;
432 
433 	case FBIOSCURSOR:
434 		/*
435 		 * For setcmap and setshape, verify parameters, so that
436 		 * we do not get halfway through an update and then crap
437 		 * out with the software state screwed up.
438 		 */
439 		v = p->set;
440 		if (v & FB_CUR_SETCMAP) {
441 			/*
442 			 * This use of a temporary copy of the cursor
443 			 * colormap is not terribly efficient, but these
444 			 * copies are small (8 bytes)...
445 			 */
446 			tcm = cc->cc_color;
447 			error = cg14_put_cmap(&p->cmap, (union cg14cmap *)&tcm,
448 					      2);
449 			if (error)
450 				return (error);
451 		}
452 		if (v & FB_CUR_SETSHAPE) {
453 			if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32)
454 				return (EINVAL);
455 			count = p->size.y * 32 / NBBY;
456 			if (!uvm_useracc(p->image, count, B_READ) ||
457 			    !uvm_useracc(p->mask, count, B_READ))
458 				return (EFAULT);
459 		}
460 
461 		/* parameters are OK; do it */
462 		if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) {
463 			if (v & FB_CUR_SETCUR)
464 				cc->cc_enable = p->enable;
465 			if (v & FB_CUR_SETPOS)
466 				cc->cc_pos = p->pos;
467 			if (v & FB_CUR_SETHOT)
468 				cc->cc_hot = p->hot;
469 			cg14_setcursor(sc);
470 		}
471 		if (v & FB_CUR_SETCMAP) {
472 			cc->cc_color = tcm;
473 			cg14_loadomap(sc); /* XXX defer to vertical retrace */
474 		}
475 		if (v & FB_CUR_SETSHAPE) {
476 			cc->cc_size = p->size;
477 			count = p->size.y * 32 / NBBY;
478 			bzero((caddr_t)cc->cc_eplane, sizeof cc->cc_eplane);
479 			bzero((caddr_t)cc->cc_cplane, sizeof cc->cc_cplane);
480 			bcopy(p->mask, (caddr_t)cc->cc_eplane, count);
481 			bcopy(p->image, (caddr_t)cc->cc_cplane, count);
482 			cg14_loadcursor(sc);
483 		}
484 		break;
485 
486 #undef cc
487 #undef p
488 	case FBIOGCURPOS:
489 		*(struct fbcurpos *)data = sc->sc_cursor.cc_pos;
490 		break;
491 
492 	case FBIOSCURPOS:
493 		sc->sc_cursor.cc_pos = *(struct fbcurpos *)data;
494 		cg14_setcursor(sc);
495 		break;
496 
497 	case FBIOGCURMAX:
498 		/* max cursor size is 32x32 */
499 		((struct fbcurpos *)data)->x = 32;
500 		((struct fbcurpos *)data)->y = 32;
501 		break;
502 
503 	default:
504 		return (ENOTTY);
505 	}
506 	return (0);
507 }
508 
509 /*
510  * Undo the effect of an FBIOSVIDEO that turns the video off.
511  */
512 static void
513 cgfourteenunblank(dev)
514 	struct device *dev;
515 {
516 
517 	cg14_set_video((struct cgfourteen_softc *)dev, 1);
518 }
519 
520 /*
521  * Return the address that would map the given device at the given
522  * offset, allowing for the given protection, or return -1 for error.
523  *
524  * The cg14 frame buffer can be mapped in either 8-bit or 32-bit mode
525  * starting at the address stored in the PROM. In 8-bit mode, the X
526  * channel is not present, and can be ignored. In 32-bit mode, mapping
527  * at 0K delivers a 32-bpp buffer where the upper 8 bits select the X
528  * channel information. We hardwire the Xlut to all zeroes to insure
529  * that, regardless of this value, direct 24-bit color access will be
530  * used.
531  *
532  * Alternatively, mapping the frame buffer at an offset of 16M seems to
533  * tell the chip to ignore the X channel. XXX where does it get the X value
534  * to use?
535  */
536 paddr_t
537 cgfourteenmmap(dev, off, prot)
538 	dev_t dev;
539 	off_t off;
540 	int prot;
541 {
542 	struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)];
543 
544 #define CG3START	(128*1024 + 128*1024)
545 #define CG8START	(256*1024)
546 #define NOOVERLAY	(0x04000000)
547 
548 	if (off & PGOFSET)
549 		panic("cgfourteenmmap");
550 
551 	if (off < 0)
552 		return (-1);
553 
554 #if defined(DEBUG) && defined(CG14_MAP_REGS) /* XXX: security hole */
555 	/*
556 	 * Map the control registers into user space. Should only be
557 	 * used for debugging!
558 	 */
559 	if ((u_int)off >= 0x10000000 && (u_int)off < 0x10000000 + 16*4096) {
560 		off -= 0x10000000;
561 		if (bus_space_mmap(sc->sc_bustag,
562 			BUS_ADDR(sc->sc_physadr[CG14_CTL_IDX].sbr_slot,
563 				sc->sc_physadr[CG14_CTL_IDX].sbr_offset),
564 			off, prot, BUS_SPACE_MAP_LINEAR));
565 	}
566 #endif
567 
568 	if ((u_int)off >= NOOVERLAY)
569 		off -= NOOVERLAY;
570 #ifdef CG14_CG8
571 	else if ((u_int)off >= CG8START) {
572 		off -= CG8START;
573 	}
574 #else
575 	else if ((u_int)off >= CG3START)
576 		off -= CG3START;
577 #endif
578 	else
579 		off = 0;
580 
581 	if (off >= sc->sc_fb.fb_type.fb_size *
582 		sc->sc_fb.fb_type.fb_depth/8) {
583 #ifdef DEBUG
584 		printf("\nmmap request out of bounds: request 0x%x, "
585 		    "bound 0x%x\n", (unsigned) off,
586 		    (unsigned)sc->sc_fb.fb_type.fb_size);
587 #endif
588 		return (-1);
589 	}
590 
591 	return (bus_space_mmap(sc->sc_bustag,
592 		BUS_ADDR(sc->sc_physadr[CG14_PXL_IDX].sbr_slot,
593 			sc->sc_physadr[CG14_PXL_IDX].sbr_offset),
594 		off, prot, BUS_SPACE_MAP_LINEAR));
595 }
596 
597 int
598 cgfourteenpoll(dev, events, p)
599 	dev_t dev;
600 	int events;
601 	struct proc *p;
602 {
603 
604 	return (seltrue(dev, events, p));
605 }
606 
607 /*
608  * Miscellaneous helper functions
609  */
610 
611 /* Initialize the framebuffer, storing away useful state for later reset */
612 static void
613 cg14_init(sc)
614 	struct cgfourteen_softc *sc;
615 {
616 	u_int32_t *clut;
617 	u_int8_t  *xlut;
618 	int i;
619 
620 	/*
621 	 * We stash away the following to restore on close:
622 	 *
623 	 * 	color look-up table 1 	(sc->sc_saveclut)
624 	 *	x look-up table		(sc->sc_savexlut)
625 	 *	control register	(sc->sc_savectl)
626 	 *	cursor control register (sc->sc_savehwc)
627 	 */
628 	sc->sc_savectl = sc->sc_ctl->ctl_mctl;
629 	sc->sc_savehwc = sc->sc_hwc->curs_ctl;
630 
631 	clut = (u_int32_t *) sc->sc_clut1->clut_lut;
632 	xlut = (u_int8_t *) sc->sc_xlut->xlut_lut;
633 	for (i = 0; i < CG14_CLUT_SIZE; i++) {
634 		sc->sc_saveclut.cm_chip[i] = clut[i];
635 		sc->sc_savexlut[i] = xlut[i];
636 	}
637 
638 #ifdef CG14_CG8
639 	/*
640 	 * Enable the video, and put in 24 bit mode.
641 	 */
642 	sc->sc_ctl->ctl_mctl = CG14_MCTL_ENABLEVID | CG14_MCTL_PIXMODE_32 |
643 		CG14_MCTL_POWERCTL;
644 
645 	/*
646 	 * Zero the xlut to enable direct-color mode
647 	 */
648 	bzero(sc->sc_xlut, CG14_CLUT_SIZE);
649 #else
650 	/*
651 	 * Enable the video and put it in 8 bit mode
652 	 */
653 	sc->sc_ctl->ctl_mctl = CG14_MCTL_ENABLEVID | CG14_MCTL_PIXMODE_8 |
654 		CG14_MCTL_POWERCTL;
655 #endif
656 }
657 
658 static void
659 cg14_reset(sc)	/* Restore the state saved on cg14_init */
660 	struct cgfourteen_softc *sc;
661 {
662 	u_int32_t *clut;
663 	u_int8_t  *xlut;
664 	int i;
665 
666 	/*
667 	 * We restore the following, saved in cg14_init:
668 	 *
669 	 * 	color look-up table 1 	(sc->sc_saveclut)
670 	 *	x look-up table		(sc->sc_savexlut)
671 	 *	control register	(sc->sc_savectl)
672 	 *	cursor control register (sc->sc_savehwc)
673 	 *
674 	 * Note that we don't touch the video enable bits in the
675 	 * control register; otherwise, screenblank wouldn't work.
676 	 */
677 	sc->sc_ctl->ctl_mctl = (sc->sc_ctl->ctl_mctl & (CG14_MCTL_ENABLEVID |
678 							CG14_MCTL_POWERCTL)) |
679 				(sc->sc_savectl & ~(CG14_MCTL_ENABLEVID |
680 						    CG14_MCTL_POWERCTL));
681 	sc->sc_hwc->curs_ctl = sc->sc_savehwc;
682 
683 	clut = (u_int32_t *) sc->sc_clut1->clut_lut;
684 	xlut = (u_int8_t *) sc->sc_xlut->xlut_lut;
685 	for (i = 0; i < CG14_CLUT_SIZE; i++) {
686 		clut[i] = sc->sc_saveclut.cm_chip[i];
687 		xlut[i] = sc->sc_savexlut[i];
688 	}
689 }
690 
691 /* Enable/disable video display; power down monitor if DPMS-capable */
692 static void
693 cg14_set_video(sc, enable)
694 	struct cgfourteen_softc *sc;
695 	int enable;
696 {
697 	/*
698 	 * We can only use DPMS to power down the display if the chip revision
699 	 * is greater than 0.
700 	 */
701 	if (enable) {
702 		if ((sc->sc_ctl->ctl_rsr & CG14_RSR_REVMASK) > 0)
703 			sc->sc_ctl->ctl_mctl |= (CG14_MCTL_ENABLEVID |
704 						 CG14_MCTL_POWERCTL);
705 		else
706 			sc->sc_ctl->ctl_mctl |= CG14_MCTL_ENABLEVID;
707 	} else {
708 		if ((sc->sc_ctl->ctl_rsr & CG14_RSR_REVMASK) > 0)
709 			sc->sc_ctl->ctl_mctl &= ~(CG14_MCTL_ENABLEVID |
710 						  CG14_MCTL_POWERCTL);
711 		else
712 			sc->sc_ctl->ctl_mctl &= ~CG14_MCTL_ENABLEVID;
713 	}
714 }
715 
716 /* Get status of video display */
717 static int
718 cg14_get_video(sc)
719 	struct cgfourteen_softc *sc;
720 {
721 	return ((sc->sc_ctl->ctl_mctl & CG14_MCTL_ENABLEVID) != 0);
722 }
723 
724 /* Read the software shadow colormap */
725 static int
726 cg14_get_cmap(p, cm, cmsize)
727 	struct fbcmap *p;
728 	union cg14cmap *cm;
729 	int cmsize;
730 {
731         u_int i, start, count;
732         u_char *cp;
733 
734         start = p->index;
735         count = p->count;
736         if (start >= cmsize || start + count > cmsize)
737 #ifdef DEBUG
738 	{
739 		printf("putcmaperror: start %d cmsize %d count %d\n",
740 		    start,cmsize,count);
741 #endif
742                 return (EINVAL);
743 #ifdef DEBUG
744 	}
745 #endif
746 
747         if (!uvm_useracc(p->red, count, B_WRITE) ||
748             !uvm_useracc(p->green, count, B_WRITE) ||
749             !uvm_useracc(p->blue, count, B_WRITE))
750                 return (EFAULT);
751         for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 4, i++) {
752                 p->red[i] = cp[3];
753                 p->green[i] = cp[2];
754                 p->blue[i] = cp[1];
755         }
756         return (0);
757 }
758 
759 /* Write the software shadow colormap */
760 static int
761 cg14_put_cmap(p, cm, cmsize)
762         struct fbcmap *p;
763         union cg14cmap *cm;
764         int cmsize;
765 {
766         u_int i, start, count;
767         u_char *cp;
768 
769         start = p->index;
770         count = p->count;
771         if (start >= cmsize || start + count > cmsize)
772 #ifdef DEBUG
773 	{
774 		printf("putcmaperror: start %d cmsize %d count %d\n",
775 		    start,cmsize,count);
776 #endif
777                 return (EINVAL);
778 #ifdef DEBUG
779 	}
780 #endif
781 
782         if (!uvm_useracc(p->red, count, B_READ) ||
783             !uvm_useracc(p->green, count, B_READ) ||
784             !uvm_useracc(p->blue, count, B_READ))
785                 return (EFAULT);
786         for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 4, i++) {
787                 cp[3] = p->red[i];
788                 cp[2] = p->green[i];
789                 cp[1] = p->blue[i];
790 		cp[0] = 0;	/* no alpha channel */
791         }
792         return (0);
793 }
794 
795 static void
796 cg14_load_hwcmap(sc, start, ncolors)
797 	struct cgfourteen_softc *sc;
798 	int start, ncolors;
799 {
800 	/* XXX switch to auto-increment, and on retrace intr */
801 
802 	/* Setup pointers to source and dest */
803 	u_int32_t *colp = &sc->sc_cmap.cm_chip[start];
804 	volatile u_int32_t *lutp = &sc->sc_clut1->clut_lut[start];
805 
806 	/* Copy by words */
807 	while (--ncolors >= 0)
808 		*lutp++ = *colp++;
809 }
810 
811 /*
812  * Load the cursor (overlay `foreground' and `background') colors.
813  */
814 static void
815 cg14_setcursor(sc)
816 	struct cgfourteen_softc *sc;
817 {
818 	/* we need to subtract the hot-spot value here */
819 #define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f)
820 
821 	sc->sc_hwc->curs_ctl = (sc->sc_cursor.cc_enable ? CG14_CURS_ENABLE : 0);
822 	sc->sc_hwc->curs_x = COORD(x);
823 	sc->sc_hwc->curs_y = COORD(y);
824 
825 #undef COORD
826 }
827 
828 static void
829 cg14_loadcursor(sc)
830 	struct cgfourteen_softc *sc;
831 {
832 	volatile struct cg14curs *hwc;
833 	u_int edgemask, m;
834 	int i;
835 
836 	/*
837 	 * Keep the top size.x bits.  Here we *throw out* the top
838 	 * size.x bits from an all-one-bits word, introducing zeros in
839 	 * the top size.x bits, then invert all the bits to get what
840 	 * we really wanted as our mask.  But this fails if size.x is
841 	 * 32---a sparc uses only the low 5 bits of the shift count---
842 	 * so we have to special case that.
843 	 */
844 	edgemask = ~0;
845 	if (sc->sc_cursor.cc_size.x < 32)
846 		edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x);
847 	hwc = sc->sc_hwc;
848 	for (i = 0; i < 32; i++) {
849 		m = sc->sc_cursor.cc_eplane[i] & edgemask;
850 		hwc->curs_plane0[i] = m;
851 		hwc->curs_plane1[i] = m & sc->sc_cursor.cc_cplane[i];
852 	}
853 }
854 
855 static void
856 cg14_loadomap(sc)
857 	struct cgfourteen_softc *sc;
858 {
859 	/* set background color */
860 	sc->sc_hwc->curs_color1 = sc->sc_cursor.cc_color.cm_chip[0];
861 	/* set foreground color */
862 	sc->sc_hwc->curs_color2 = sc->sc_cursor.cc_color.cm_chip[1];
863 }
864