xref: /netbsd-src/sys/dev/tc/cfb.c (revision 220b5c059a84c51ea44107ea8951a57ffaecdc8c)
1 /* $NetBSD: cfb.c,v 1.30 2001/11/13 06:26:09 lukem Exp $ */
2 
3 /*
4  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tohru Nishimura
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.30 2001/11/13 06:26:09 lukem Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52 
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt459reg.h>
55 
56 #include <uvm/uvm_extern.h>
57 
58 #if defined(pmax)
59 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
60 #endif
61 
62 #if defined(alpha)
63 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
64 #endif
65 
66 /*
67  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
68  * obscure register layout such as 2nd and 3rd Bt459 registers are
69  * adjacent each other in a word, i.e.,
70  *	struct bt459triplet {
71  * 		struct {
72  *			u_int8_t u0;
73  *			u_int8_t u1;
74  *			u_int8_t u2;
75  *			unsigned :8;
76  *		} bt_lo;
77  *		...
78  * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
79  *	struct bt459reg {
80  *		   u_int32_t	   bt_lo;
81  *		   u_int32_t	   bt_hi;
82  *		   u_int32_t	   bt_reg;
83  *		   u_int32_t	   bt_cmap;
84  *	};
85  */
86 
87 /* Bt459 hardware registers */
88 #define	bt_lo	0
89 #define	bt_hi	1
90 #define	bt_reg	2
91 #define	bt_cmap 3
92 
93 #define	REG(base, index)	*((u_int32_t *)(base) + (index))
94 #define	SELECT(vdac, regno) do {			\
95 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
96 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
97 	tc_wmb();					\
98    } while (0)
99 
100 struct hwcmap256 {
101 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
102 	u_int8_t r[CMAP_SIZE];
103 	u_int8_t g[CMAP_SIZE];
104 	u_int8_t b[CMAP_SIZE];
105 };
106 
107 struct hwcursor64 {
108 	struct wsdisplay_curpos cc_pos;
109 	struct wsdisplay_curpos cc_hot;
110 	struct wsdisplay_curpos cc_size;
111 	struct wsdisplay_curpos cc_magic;
112 #define	CURSOR_MAX_SIZE	64
113 	u_int8_t cc_color[6];
114 	u_int64_t cc_image[64 + 64];
115 };
116 
117 struct cfb_softc {
118 	struct device sc_dev;
119 	vaddr_t sc_vaddr;
120 	size_t sc_size;
121 	struct rasops_info *sc_ri;
122 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
123 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
124 	int sc_blanked;
125 	int sc_curenb;			/* cursor sprite enabled */
126 	int sc_changed;			/* need update of hardware */
127 #define	WSDISPLAY_CMAP_DOLUT	0x20
128 	int nscreens;
129 };
130 
131 #define	CX_MAGIC_X	220
132 #define	CX_MAGIC_Y 	35
133 
134 #define	CX_FB_OFFSET	0x000000
135 #define	CX_FB_SIZE	0x100000
136 #define	CX_BT459_OFFSET	0x200000
137 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
138 
139 static int  cfbmatch __P((struct device *, struct cfdata *, void *));
140 static void cfbattach __P((struct device *, struct device *, void *));
141 
142 const struct cfattach cfb_ca = {
143 	sizeof(struct cfb_softc), cfbmatch, cfbattach,
144 };
145 
146 static void cfb_common_init __P((struct rasops_info *));
147 static struct rasops_info cfb_console_ri;
148 static tc_addr_t cfb_consaddr;
149 
150 static struct wsscreen_descr cfb_stdscreen = {
151 	"std", 0, 0,
152 	0, /* textops */
153 	0, 0,
154 	WSSCREEN_REVERSE
155 };
156 
157 static const struct wsscreen_descr *_cfb_scrlist[] = {
158 	&cfb_stdscreen,
159 };
160 
161 static const struct wsscreen_list cfb_screenlist = {
162 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
163 };
164 
165 static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
166 static paddr_t	cfbmmap __P((void *, off_t, int));
167 
168 static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
169 				      void **, int *, int *, long *));
170 static void	cfb_free_screen __P((void *, void *));
171 static int	cfb_show_screen __P((void *, void *, int,
172 				     void (*) (void *, int, int), void *));
173 
174 static const struct wsdisplay_accessops cfb_accessops = {
175 	cfbioctl,
176 	cfbmmap,
177 	cfb_alloc_screen,
178 	cfb_free_screen,
179 	cfb_show_screen,
180 	0 /* load_font */
181 };
182 
183 int  cfb_cnattach __P((tc_addr_t));
184 static int  cfbintr __P((void *));
185 static void cfbhwinit __P((caddr_t));
186 
187 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
188 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
189 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
190 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
191 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
192 
193 /*
194  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
195  *   M M M M I I I I		M I M I M I M I
196  *	[ before ]		   [ after ]
197  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
198  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
199  */
200 static const u_int8_t shuffle[256] = {
201 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
202 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
203 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
204 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
205 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
206 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
207 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
208 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
209 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
210 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
211 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
212 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
213 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
214 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
215 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
216 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
217 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
218 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
219 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
220 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
221 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
222 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
223 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
224 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
225 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
226 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
227 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
228 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
229 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
230 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
231 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
232 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
233 };
234 
235 static int
236 cfbmatch(parent, match, aux)
237 	struct device *parent;
238 	struct cfdata *match;
239 	void *aux;
240 {
241 	struct tc_attach_args *ta = aux;
242 
243 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
244 		return (0);
245 
246 	return (1);
247 }
248 
249 static void
250 cfbattach(parent, self, aux)
251 	struct device *parent, *self;
252 	void *aux;
253 {
254 	struct cfb_softc *sc = (struct cfb_softc *)self;
255 	struct tc_attach_args *ta = aux;
256 	struct rasops_info *ri;
257 	struct wsemuldisplaydev_attach_args waa;
258 	struct hwcmap256 *cm;
259 	const u_int8_t *p;
260 	int console, index;
261 
262 	console = (ta->ta_addr == cfb_consaddr);
263 	if (console) {
264 		sc->sc_ri = ri = &cfb_console_ri;
265 		sc->nscreens = 1;
266 	}
267 	else {
268 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
269 			M_DEVBUF, M_NOWAIT);
270 		if (ri == NULL) {
271 			printf(": can't alloc memory\n");
272 			return;
273 		}
274 		memset(ri, 0, sizeof(struct rasops_info));
275 
276 		ri->ri_hw = (void *)ta->ta_addr;
277 		cfb_common_init(ri);
278 		sc->sc_ri = ri;
279 	}
280 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
281 
282 	cm = &sc->sc_cmap;
283 	p = rasops_cmap;
284 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
285 		cm->r[index] = p[0];
286 		cm->g[index] = p[1];
287 		cm->b[index] = p[2];
288 	}
289 
290 	sc->sc_vaddr = ta->ta_addr;
291 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
292 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
293 	sc->sc_blanked = sc->sc_curenb = 0;
294 
295 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
296 
297 	/* clear any pending interrupts */
298 	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
299 
300 	waa.console = console;
301 	waa.scrdata = &cfb_screenlist;
302 	waa.accessops = &cfb_accessops;
303 	waa.accesscookie = sc;
304 
305 	config_found(self, &waa, wsemuldisplaydevprint);
306 }
307 
308 static void
309 cfb_common_init(ri)
310 	struct rasops_info *ri;
311 {
312 	caddr_t base;
313 	int cookie;
314 
315 	base = (caddr_t)ri->ri_hw;
316 
317 	/* initialize colormap and cursor hardware */
318 	cfbhwinit(base);
319 
320 	ri->ri_flg = RI_CENTER;
321 	ri->ri_depth = 8;
322 	ri->ri_width = 1024;
323 	ri->ri_height = 864;
324 	ri->ri_stride = 1024;
325 	ri->ri_bits = base + CX_FB_OFFSET;
326 
327 	/* clear the screen */
328 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
329 
330 	wsfont_init();
331 	/* prefer 12 pixel wide font */
332 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
333 		cookie = wsfont_find(NULL, 0, 0, 0);
334 	if (cookie <= 0) {
335 		printf("cfb: font table is empty\n");
336 		return;
337 	}
338 
339 	if (wsfont_lock(cookie, &ri->ri_font,
340 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
341 		printf("cfb: couldn't lock font\n");
342 		return;
343 	}
344 	ri->ri_wsfcookie = cookie;
345 
346 	rasops_init(ri, 34, 80);
347 
348 	/* XXX shouldn't be global */
349 	cfb_stdscreen.nrows = ri->ri_rows;
350 	cfb_stdscreen.ncols = ri->ri_cols;
351 	cfb_stdscreen.textops = &ri->ri_ops;
352 	cfb_stdscreen.capabilities = ri->ri_caps;
353 }
354 
355 static int
356 cfbioctl(v, cmd, data, flag, p)
357 	void *v;
358 	u_long cmd;
359 	caddr_t data;
360 	int flag;
361 	struct proc *p;
362 {
363 	struct cfb_softc *sc = v;
364 	struct rasops_info *ri = sc->sc_ri;
365 	int turnoff;
366 
367 	switch (cmd) {
368 	case WSDISPLAYIO_GTYPE:
369 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
370 		return (0);
371 
372 	case WSDISPLAYIO_GINFO:
373 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
374 		wsd_fbip->height = ri->ri_height;
375 		wsd_fbip->width = ri->ri_width;
376 		wsd_fbip->depth = ri->ri_depth;
377 		wsd_fbip->cmsize = CMAP_SIZE;
378 #undef fbt
379 		return (0);
380 
381 	case WSDISPLAYIO_GETCMAP:
382 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
383 
384 	case WSDISPLAYIO_PUTCMAP:
385 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
386 
387 	case WSDISPLAYIO_SVIDEO:
388 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
389 		if ((sc->sc_blanked == 0) ^ turnoff) {
390 			sc->sc_blanked = turnoff;
391 			/* XXX later XXX */
392 		}
393 		return (0);
394 
395 	case WSDISPLAYIO_GVIDEO:
396 		*(u_int *)data = sc->sc_blanked ?
397 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
398 		return (0);
399 
400 	case WSDISPLAYIO_GCURPOS:
401 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
402 		return (0);
403 
404 	case WSDISPLAYIO_SCURPOS:
405 		set_curpos(sc, (struct wsdisplay_curpos *)data);
406 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
407 		return (0);
408 
409 	case WSDISPLAYIO_GCURMAX:
410 		((struct wsdisplay_curpos *)data)->x =
411 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
412 		return (0);
413 
414 	case WSDISPLAYIO_GCURSOR:
415 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
416 
417 	case WSDISPLAYIO_SCURSOR:
418 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
419 	}
420 	return ENOTTY;
421 }
422 
423 paddr_t
424 cfbmmap(v, offset, prot)
425 	void *v;
426 	off_t offset;
427 	int prot;
428 {
429 	struct cfb_softc *sc = v;
430 
431 	if (offset >= CX_FB_SIZE || offset < 0)
432 		return (-1);
433 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
434 }
435 
436 static int
437 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
438 	void *v;
439 	const struct wsscreen_descr *type;
440 	void **cookiep;
441 	int *curxp, *curyp;
442 	long *attrp;
443 {
444 	struct cfb_softc *sc = v;
445 	struct rasops_info *ri = sc->sc_ri;
446 	long defattr;
447 
448 	if (sc->nscreens > 0)
449 		return (ENOMEM);
450 
451 	*cookiep = ri;	 /* one and only for now */
452 	*curxp = 0;
453 	*curyp = 0;
454 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
455 	*attrp = defattr;
456 	sc->nscreens++;
457 	return (0);
458 }
459 
460 static void
461 cfb_free_screen(v, cookie)
462 	void *v;
463 	void *cookie;
464 {
465 	struct cfb_softc *sc = v;
466 
467 	if (sc->sc_ri == &cfb_console_ri)
468 		panic("cfb_free_screen: console");
469 
470 	sc->nscreens--;
471 }
472 
473 static int
474 cfb_show_screen(v, cookie, waitok, cb, cbarg)
475 	void *v;
476 	void *cookie;
477 	int waitok;
478 	void (*cb) __P((void *, int, int));
479 	void *cbarg;
480 {
481 
482 	return (0);
483 }
484 
485 /* EXPORT */ int
486 cfb_cnattach(addr)
487 	tc_addr_t addr;
488 {
489 	struct rasops_info *ri;
490 	long defattr;
491 
492 	ri = &cfb_console_ri;
493 	ri->ri_hw = (void *)addr;
494 	cfb_common_init(ri);
495 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
496 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
497 	cfb_consaddr = addr;
498 	return(0);
499 }
500 
501 static int
502 cfbintr(arg)
503 	void *arg;
504 {
505 	struct cfb_softc *sc = arg;
506 	caddr_t base, vdac;
507 	int v;
508 
509 	base = (caddr_t)sc->sc_ri->ri_hw;
510 	*(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
511 	if (sc->sc_changed == 0)
512 		return (1);
513 
514 	vdac = base + CX_BT459_OFFSET;
515 	v = sc->sc_changed;
516 	if (v & WSDISPLAY_CURSOR_DOCUR) {
517 		SELECT(vdac, BT459_IREG_CCR);
518 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
519 	}
520 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
521 		int x, y;
522 
523 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
524 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
525 
526 		x += sc->sc_cursor.cc_magic.x;
527 		y += sc->sc_cursor.cc_magic.y;
528 
529 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
530 		REG(vdac, bt_reg) = x;		tc_wmb();
531 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
532 		REG(vdac, bt_reg) = y;		tc_wmb();
533 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
534 	}
535 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
536 		u_int8_t *cp = sc->sc_cursor.cc_color;
537 
538 		SELECT(vdac, BT459_IREG_CCOLOR_2);
539 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
540 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
541 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
542 
543 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
544 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
545 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
546 	}
547 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
548 		u_int8_t *ip, *mp, img, msk;
549 		u_int8_t u;
550 		int bcnt;
551 
552 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
553 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
554 
555 		bcnt = 0;
556 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
557 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
558 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
559 			/* pad right half 32 pixel when smaller than 33 */
560 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
561 				REG(vdac, bt_reg) = 0; tc_wmb();
562 				REG(vdac, bt_reg) = 0; tc_wmb();
563 			}
564 			else {
565 				img = *ip++;
566 				msk = *mp++;
567 				img &= msk;	/* cookie off image */
568 				u = (msk & 0x0f) << 4 | (img & 0x0f);
569 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
570 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
571 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
572 			}
573 			bcnt += 2;
574 		}
575 		/* pad unoccupied scan lines */
576 		while (bcnt < CURSOR_MAX_SIZE * 16) {
577 			REG(vdac, bt_reg) = 0; tc_wmb();
578 			REG(vdac, bt_reg) = 0; tc_wmb();
579 			bcnt += 2;
580 		}
581 	}
582 	if (v & WSDISPLAY_CMAP_DOLUT) {
583 		struct hwcmap256 *cm = &sc->sc_cmap;
584 		int index;
585 
586 		SELECT(vdac, 0);
587 		for (index = 0; index < CMAP_SIZE; index++) {
588 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
589 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
590 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
591 		}
592 	}
593 	sc->sc_changed = 0;
594 	return (1);
595 }
596 
597 static void
598 cfbhwinit(cfbbase)
599 	caddr_t cfbbase;
600 {
601 	caddr_t vdac = cfbbase + CX_BT459_OFFSET;
602 	const u_int8_t *p;
603 	int i;
604 
605 	SELECT(vdac, BT459_IREG_COMMAND_0);
606 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
607 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
608 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
609 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
610 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
611 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
612 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
613 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
614 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
615 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
616 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
617 
618 	SELECT(vdac, BT459_IREG_CCR);
619 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
620 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
621 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
622 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
623 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
624 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
625 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
626 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
627 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
628 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
629 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
630 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
631 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
632 
633 	/* build sane colormap */
634 	SELECT(vdac, 0);
635 	p = rasops_cmap;
636 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
637 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
638 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
639 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
640 	}
641 
642 	/* clear out cursor image */
643 	SELECT(vdac, BT459_IREG_CRAM_BASE);
644 	for (i = 0; i < 1024; i++)
645 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
646 
647 	/*
648 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
649 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
650 	 * image color.  CCOLOR_1 will be never used.
651 	 */
652 	SELECT(vdac, BT459_IREG_CCOLOR_1);
653 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
654 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
655 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
656 
657 	REG(vdac, bt_reg) = 0;	tc_wmb();
658 	REG(vdac, bt_reg) = 0;	tc_wmb();
659 	REG(vdac, bt_reg) = 0;	tc_wmb();
660 
661 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
662 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
663 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
664 }
665 
666 static int
667 get_cmap(sc, p)
668 	struct cfb_softc *sc;
669 	struct wsdisplay_cmap *p;
670 {
671 	u_int index = p->index, count = p->count;
672 
673 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
674 		return (EINVAL);
675 
676 	if (!uvm_useracc(p->red, count, B_WRITE) ||
677 	    !uvm_useracc(p->green, count, B_WRITE) ||
678 	    !uvm_useracc(p->blue, count, B_WRITE))
679 		return (EFAULT);
680 
681 	copyout(&sc->sc_cmap.r[index], p->red, count);
682 	copyout(&sc->sc_cmap.g[index], p->green, count);
683 	copyout(&sc->sc_cmap.b[index], p->blue, count);
684 
685 	return (0);
686 }
687 
688 static int
689 set_cmap(sc, p)
690 	struct cfb_softc *sc;
691 	struct wsdisplay_cmap *p;
692 {
693 	u_int index = p->index, count = p->count;
694 
695 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
696 		return (EINVAL);
697 
698 	if (!uvm_useracc(p->red, count, B_READ) ||
699 	    !uvm_useracc(p->green, count, B_READ) ||
700 	    !uvm_useracc(p->blue, count, B_READ))
701 		return (EFAULT);
702 
703 	copyin(p->red, &sc->sc_cmap.r[index], count);
704 	copyin(p->green, &sc->sc_cmap.g[index], count);
705 	copyin(p->blue, &sc->sc_cmap.b[index], count);
706 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
707 	return (0);
708 }
709 
710 static int
711 set_cursor(sc, p)
712 	struct cfb_softc *sc;
713 	struct wsdisplay_cursor *p;
714 {
715 #define	cc (&sc->sc_cursor)
716 	u_int v, index, count, icount;
717 
718 	v = p->which;
719 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
720 		index = p->cmap.index;
721 		count = p->cmap.count;
722 		if (index >= 2 || (index + count) > 2)
723 			return (EINVAL);
724 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
725 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
726 		    !uvm_useracc(p->cmap.blue, count, B_READ))
727 			return (EFAULT);
728 	}
729 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
730 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
731 			return (EINVAL);
732 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
733 		if (!uvm_useracc(p->image, icount, B_READ) ||
734 		    !uvm_useracc(p->mask, icount, B_READ))
735 			return (EFAULT);
736 	}
737 
738 	if (v & WSDISPLAY_CURSOR_DOCUR)
739 		sc->sc_curenb = p->enable;
740 	if (v & WSDISPLAY_CURSOR_DOPOS)
741 		set_curpos(sc, &p->pos);
742 	if (v & WSDISPLAY_CURSOR_DOHOT)
743 		cc->cc_hot = p->hot;
744 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
745 		copyin(p->cmap.red, &cc->cc_color[index], count);
746 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
747 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
748 	}
749 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
750 		cc->cc_size = p->size;
751 		memset(cc->cc_image, 0, sizeof cc->cc_image);
752 		copyin(p->image, cc->cc_image, icount);
753 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
754 	}
755 	sc->sc_changed |= v;
756 
757 	return (0);
758 #undef cc
759 }
760 
761 static int
762 get_cursor(sc, p)
763 	struct cfb_softc *sc;
764 	struct wsdisplay_cursor *p;
765 {
766 	return (ENOTTY); /* XXX */
767 }
768 
769 static void
770 set_curpos(sc, curpos)
771 	struct cfb_softc *sc;
772 	struct wsdisplay_curpos *curpos;
773 {
774 	struct rasops_info *ri = sc->sc_ri;
775 	int x = curpos->x, y = curpos->y;
776 
777 	if (y < 0)
778 		y = 0;
779 	else if (y > ri->ri_height)
780 		y = ri->ri_height;
781 	if (x < 0)
782 		x = 0;
783 	else if (x > ri->ri_width)
784 		x = ri->ri_width;
785 	sc->sc_cursor.cc_pos.x = x;
786 	sc->sc_cursor.cc_pos.y = y;
787 }
788