xref: /netbsd-src/sys/dev/tc/cfb.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: cfb.c,v 1.53 2007/10/19 12:01:19 ad 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.53 2007/10/19 12:01:19 ad 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 <sys/bus.h>
45 #include <sys/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, memory-mapped in 32bit stride */
88 #define	bt_lo	0x0
89 #define	bt_hi	0x4
90 #define	bt_reg	0x8
91 #define	bt_cmap 0xc
92 
93 #define	REGWRITE32(p,i,v) do {					\
94 	*(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb();	\
95     } while (0)
96 #define	VDACSELECT(p,r) do {					\
97 	REGWRITE32(p, bt_lo, 0xff & (r));			\
98 	REGWRITE32(p, bt_hi, 0x0f & ((r)>>8));			\
99    } while (0)
100 
101 struct hwcmap256 {
102 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
103 	u_int8_t r[CMAP_SIZE];
104 	u_int8_t g[CMAP_SIZE];
105 	u_int8_t b[CMAP_SIZE];
106 };
107 
108 struct hwcursor64 {
109 	struct wsdisplay_curpos cc_pos;
110 	struct wsdisplay_curpos cc_hot;
111 	struct wsdisplay_curpos cc_size;
112 	struct wsdisplay_curpos cc_magic;
113 #define	CURSOR_MAX_SIZE	64
114 	u_int8_t cc_color[6];
115 	u_int64_t cc_image[CURSOR_MAX_SIZE];
116 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
117 };
118 
119 struct cfb_softc {
120 	struct device sc_dev;
121 	vaddr_t sc_vaddr;
122 	size_t sc_size;
123 	struct rasops_info *sc_ri;
124 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
125 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
126 	int sc_blanked;
127 	int sc_curenb;			/* cursor sprite enabled */
128 	int sc_changed;			/* need update of hardware */
129 #define	WSDISPLAY_CMAP_DOLUT	0x20
130 	int nscreens;
131 };
132 
133 #define	CX_MAGIC_X	220
134 #define	CX_MAGIC_Y 	35
135 
136 #define	CX_FB_OFFSET	0x000000
137 #define	CX_FB_SIZE	0x100000
138 #define	CX_BT459_OFFSET	0x200000
139 #define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
140 
141 static int  cfbmatch(struct device *, struct cfdata *, void *);
142 static void cfbattach(struct device *, struct device *, void *);
143 
144 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
145     cfbmatch, cfbattach, NULL, NULL);
146 
147 static void cfb_common_init(struct rasops_info *);
148 static struct rasops_info cfb_console_ri;
149 static tc_addr_t cfb_consaddr;
150 
151 static struct wsscreen_descr cfb_stdscreen = {
152 	"std", 0, 0,
153 	0, /* textops */
154 	0, 0,
155 	WSSCREEN_REVERSE
156 };
157 
158 static const struct wsscreen_descr *_cfb_scrlist[] = {
159 	&cfb_stdscreen,
160 };
161 
162 static const struct wsscreen_list cfb_screenlist = {
163 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
164 };
165 
166 static int	cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
167 static paddr_t	cfbmmap(void *, void *, off_t, int);
168 
169 static int	cfb_alloc_screen(void *, const struct wsscreen_descr *,
170 				      void **, int *, int *, long *);
171 static void	cfb_free_screen(void *, void *);
172 static int	cfb_show_screen(void *, void *, int,
173 				     void (*) (void *, int, int), void *);
174 
175 static const struct wsdisplay_accessops cfb_accessops = {
176 	cfbioctl,
177 	cfbmmap,
178 	cfb_alloc_screen,
179 	cfb_free_screen,
180 	cfb_show_screen,
181 	0 /* load_font */
182 };
183 
184 int  cfb_cnattach(tc_addr_t);
185 static int  cfbintr(void *);
186 static void cfbhwinit(void *);
187 static void cfb_cmap_init(struct cfb_softc *);
188 
189 static int  get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
190 static int  set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
191 static int  set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
192 static int  get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
193 static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *);
194 
195 /*
196  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
197  *   M M M M I I I I		M I M I M I M I
198  *	[ before ]		   [ after ]
199  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
200  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
201  */
202 static const u_int8_t shuffle[256] = {
203 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
204 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
205 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
206 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
207 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
208 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
209 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
210 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
211 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
212 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
213 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
214 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
215 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
216 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
217 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
218 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
219 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
220 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
221 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
222 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
223 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
224 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
225 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
226 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
227 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
228 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
229 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
230 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
231 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
232 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
233 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
234 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
235 };
236 
237 static int
238 cfbmatch(struct device *parent, struct cfdata *match, void *aux)
239 {
240 	struct tc_attach_args *ta = aux;
241 
242 	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
243 		return (0);
244 
245 	return (1);
246 }
247 
248 static void
249 cfbattach(struct device *parent, struct device *self, void *aux)
250 {
251 	struct cfb_softc *sc = device_private(self);
252 	struct tc_attach_args *ta = aux;
253 	struct rasops_info *ri;
254 	struct wsemuldisplaydev_attach_args waa;
255 	int console;
256 
257 	console = (ta->ta_addr == cfb_consaddr);
258 	if (console) {
259 		sc->sc_ri = ri = &cfb_console_ri;
260 		sc->nscreens = 1;
261 	}
262 	else {
263 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
264 			M_DEVBUF, M_NOWAIT);
265 		if (ri == NULL) {
266 			printf(": can't alloc memory\n");
267 			return;
268 		}
269 		memset(ri, 0, sizeof(struct rasops_info));
270 
271 		ri->ri_hw = (void *)ta->ta_addr;
272 		cfb_common_init(ri);
273 		sc->sc_ri = ri;
274 	}
275 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
276 
277 	cfb_cmap_init(sc);
278 
279 	sc->sc_vaddr = ta->ta_addr;
280 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
281 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
282 	sc->sc_blanked = sc->sc_curenb = 0;
283 
284 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
285 
286 	/* clear any pending interrupts */
287 	*(volatile u_int8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
288 
289 	waa.console = console;
290 	waa.scrdata = &cfb_screenlist;
291 	waa.accessops = &cfb_accessops;
292 	waa.accesscookie = sc;
293 
294 	config_found(self, &waa, wsemuldisplaydevprint);
295 }
296 
297 static void
298 cfb_cmap_init(struct cfb_softc *sc)
299 {
300 	struct hwcmap256 *cm;
301 	const u_int8_t *p;
302 	int index;
303 
304 	cm = &sc->sc_cmap;
305 	p = rasops_cmap;
306 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
307 		cm->r[index] = p[0];
308 		cm->g[index] = p[1];
309 		cm->b[index] = p[2];
310 	}
311 }
312 
313 static void
314 cfb_common_init(struct rasops_info *ri)
315 {
316 	char *base;
317 	int cookie;
318 
319 	base = (void *)ri->ri_hw;
320 
321 	/* initialize colormap and cursor hardware */
322 	cfbhwinit(base);
323 
324 	ri->ri_flg = RI_CENTER;
325 	ri->ri_depth = 8;
326 	ri->ri_width = 1024;
327 	ri->ri_height = 864;
328 	ri->ri_stride = 1024;
329 	ri->ri_bits = base + CX_FB_OFFSET;
330 
331 	/* clear the screen */
332 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
333 
334 	wsfont_init();
335 	/* prefer 12 pixel wide font */
336 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
337 	    WSDISPLAY_FONTORDER_L2R);
338 	if (cookie <= 0)
339 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
340 		    WSDISPLAY_FONTORDER_L2R);
341 	if (cookie <= 0) {
342 		printf("cfb: font table is empty\n");
343 		return;
344 	}
345 
346 	if (wsfont_lock(cookie, &ri->ri_font)) {
347 		printf("cfb: couldn't lock font\n");
348 		return;
349 	}
350 	ri->ri_wsfcookie = cookie;
351 
352 	rasops_init(ri, 34, 80);
353 
354 	/* XXX shouldn't be global */
355 	cfb_stdscreen.nrows = ri->ri_rows;
356 	cfb_stdscreen.ncols = ri->ri_cols;
357 	cfb_stdscreen.textops = &ri->ri_ops;
358 	cfb_stdscreen.capabilities = ri->ri_caps;
359 }
360 
361 static int
362 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
363 {
364 	struct cfb_softc *sc = v;
365 	struct rasops_info *ri = sc->sc_ri;
366 	int turnoff, s;
367 
368 	switch (cmd) {
369 	case WSDISPLAYIO_GTYPE:
370 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
371 		return (0);
372 
373 	case WSDISPLAYIO_GINFO:
374 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
375 		wsd_fbip->height = ri->ri_height;
376 		wsd_fbip->width = ri->ri_width;
377 		wsd_fbip->depth = ri->ri_depth;
378 		wsd_fbip->cmsize = CMAP_SIZE;
379 #undef fbt
380 		return (0);
381 
382 	case WSDISPLAYIO_GETCMAP:
383 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
384 
385 	case WSDISPLAYIO_PUTCMAP:
386 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
387 
388 	case WSDISPLAYIO_SVIDEO:
389 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
390 		if (sc->sc_blanked != turnoff) {
391 			sc->sc_blanked = turnoff;
392 			/* XXX later XXX */
393 		}
394 		return (0);
395 
396 	case WSDISPLAYIO_GVIDEO:
397 		*(u_int *)data = sc->sc_blanked ?
398 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
399 		return (0);
400 
401 	case WSDISPLAYIO_GCURPOS:
402 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
403 		return (0);
404 
405 	case WSDISPLAYIO_SCURPOS:
406 		s = spltty();
407 		set_curpos(sc, (struct wsdisplay_curpos *)data);
408 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
409 		splx(s);
410 		return (0);
411 
412 	case WSDISPLAYIO_GCURMAX:
413 		((struct wsdisplay_curpos *)data)->x =
414 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
415 		return (0);
416 
417 	case WSDISPLAYIO_GCURSOR:
418 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
419 
420 	case WSDISPLAYIO_SCURSOR:
421 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
422 
423 	case WSDISPLAYIO_SMODE:
424 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
425 			s = spltty();
426 			cfb_cmap_init(sc);
427 			sc->sc_curenb = 0;
428 			sc->sc_blanked = 0;
429 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
430 			    WSDISPLAY_CMAP_DOLUT);
431 			splx(s);
432 		}
433 		return (0);
434 	}
435 	return EPASSTHROUGH;
436 }
437 
438 paddr_t
439 cfbmmap(void *v, void *vs, off_t offset, int prot)
440 {
441 	struct cfb_softc *sc = v;
442 
443 	if (offset >= CX_FB_SIZE || offset < 0)
444 		return (-1);
445 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
446 }
447 
448 static int
449 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
450     int *curxp, int *curyp, long *attrp)
451 {
452 	struct cfb_softc *sc = v;
453 	struct rasops_info *ri = sc->sc_ri;
454 	long defattr;
455 
456 	if (sc->nscreens > 0)
457 		return (ENOMEM);
458 
459 	*cookiep = ri;	 /* one and only for now */
460 	*curxp = 0;
461 	*curyp = 0;
462 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
463 	*attrp = defattr;
464 	sc->nscreens++;
465 	return (0);
466 }
467 
468 static void
469 cfb_free_screen(void *v, void *cookie)
470 {
471 	struct cfb_softc *sc = v;
472 
473 	if (sc->sc_ri == &cfb_console_ri)
474 		panic("cfb_free_screen: console");
475 
476 	sc->nscreens--;
477 }
478 
479 static int
480 cfb_show_screen(void *v, void *cookie, int waitok,
481     void (*cb)(void *, int, int), void *cbarg)
482 {
483 
484 	return (0);
485 }
486 
487 /* EXPORT */ int
488 cfb_cnattach(tc_addr_t addr)
489 {
490 	struct rasops_info *ri;
491 	long defattr;
492 
493 	ri = &cfb_console_ri;
494 	ri->ri_hw = (void *)addr;
495 	cfb_common_init(ri);
496 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
497 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
498 	cfb_consaddr = addr;
499 	return(0);
500 }
501 
502 static int
503 cfbintr(void *arg)
504 {
505 	struct cfb_softc *sc = arg;
506 	char *base, *vdac;
507 	int v;
508 
509 	base = (void *)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 		VDACSELECT(vdac, BT459_IREG_CCR);
518 		REGWRITE32(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 		VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
530 		REGWRITE32(vdac, bt_reg, x);
531 		REGWRITE32(vdac, bt_reg, x >> 8);
532 		REGWRITE32(vdac, bt_reg, y);
533 		REGWRITE32(vdac, bt_reg, y >> 8);
534 	}
535 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
536 		u_int8_t *cp = sc->sc_cursor.cc_color;
537 
538 		VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
539 		REGWRITE32(vdac, bt_reg, cp[1]);
540 		REGWRITE32(vdac, bt_reg, cp[3]);
541 		REGWRITE32(vdac, bt_reg, cp[5]);
542 
543 		REGWRITE32(vdac, bt_reg, cp[0]);
544 		REGWRITE32(vdac, bt_reg, cp[2]);
545 		REGWRITE32(vdac, bt_reg, cp[4]);
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_mask;
554 
555 		bcnt = 0;
556 		VDACSELECT(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 				REGWRITE32(vdac, bt_reg, 0);
562 				REGWRITE32(vdac, bt_reg, 0);
563 			}
564 			else {
565 				img = *ip++;
566 				msk = *mp++;
567 				img &= msk;	/* cookie off image */
568 				u = (msk & 0x0f) << 4 | (img & 0x0f);
569 				REGWRITE32(vdac, bt_reg, shuffle[u]);
570 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
571 				REGWRITE32(vdac, bt_reg, shuffle[u]);
572 			}
573 			bcnt += 2;
574 		}
575 		/* pad unoccupied scan lines */
576 		while (bcnt < CURSOR_MAX_SIZE * 16) {
577 			REGWRITE32(vdac, bt_reg, 0);
578 			REGWRITE32(vdac, bt_reg, 0);
579 			bcnt += 2;
580 		}
581 	}
582 	if (v & WSDISPLAY_CMAP_DOLUT) {
583 		struct hwcmap256 *cm = &sc->sc_cmap;
584 		int index;
585 
586 		VDACSELECT(vdac, 0);
587 		for (index = 0; index < CMAP_SIZE; index++) {
588 			REGWRITE32(vdac, bt_cmap, cm->r[index]);
589 			REGWRITE32(vdac, bt_cmap, cm->g[index]);
590 			REGWRITE32(vdac, bt_cmap, cm->b[index]);
591 		}
592 	}
593 	sc->sc_changed = 0;
594 	return (1);
595 }
596 
597 static void
598 cfbhwinit(void *cfbbase)
599 {
600 	char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
601 	const u_int8_t *p;
602 	int i;
603 
604 	VDACSELECT(vdac, BT459_IREG_COMMAND_0);
605 	REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
606 	REGWRITE32(vdac, bt_reg, 0x0);  /* CMD1 */
607 	REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
608 	REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
609 	REGWRITE32(vdac, bt_reg, 0);    /* 205 */
610 	REGWRITE32(vdac, bt_reg, 0x0);  /* PBM */
611 	REGWRITE32(vdac, bt_reg, 0);    /* 207 */
612 	REGWRITE32(vdac, bt_reg, 0x0);  /* ORM */
613 	REGWRITE32(vdac, bt_reg, 0x0);  /* OBM */
614 	REGWRITE32(vdac, bt_reg, 0x0);  /* ILV */
615 	REGWRITE32(vdac, bt_reg, 0x0);  /* TEST */
616 
617 	VDACSELECT(vdac, BT459_IREG_CCR);
618 	REGWRITE32(vdac, bt_reg, 0x0);
619 	REGWRITE32(vdac, bt_reg, 0x0);
620 	REGWRITE32(vdac, bt_reg, 0x0);
621 	REGWRITE32(vdac, bt_reg, 0x0);
622 	REGWRITE32(vdac, bt_reg, 0x0);
623 	REGWRITE32(vdac, bt_reg, 0x0);
624 	REGWRITE32(vdac, bt_reg, 0x0);
625 	REGWRITE32(vdac, bt_reg, 0x0);
626 	REGWRITE32(vdac, bt_reg, 0x0);
627 	REGWRITE32(vdac, bt_reg, 0x0);
628 	REGWRITE32(vdac, bt_reg, 0x0);
629 	REGWRITE32(vdac, bt_reg, 0x0);
630 	REGWRITE32(vdac, bt_reg, 0x0);
631 
632 	/* build sane colormap */
633 	VDACSELECT(vdac, 0);
634 	p = rasops_cmap;
635 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
636 		REGWRITE32(vdac, bt_cmap, p[0]);
637 		REGWRITE32(vdac, bt_cmap, p[1]);
638 		REGWRITE32(vdac, bt_cmap, p[2]);
639 	}
640 
641 	/* clear out cursor image */
642 	VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
643 	for (i = 0; i < 1024; i++)
644 		REGWRITE32(vdac, bt_reg, 0xff);
645 
646 	/*
647 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
648 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
649 	 * image color.  CCOLOR_1 will be never used.
650 	 */
651 	VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
652 	REGWRITE32(vdac, bt_reg, 0xff);
653 	REGWRITE32(vdac, bt_reg, 0xff);
654 	REGWRITE32(vdac, bt_reg, 0xff);
655 
656 	REGWRITE32(vdac, bt_reg, 0);
657 	REGWRITE32(vdac, bt_reg, 0);
658 	REGWRITE32(vdac, bt_reg, 0);
659 
660 	REGWRITE32(vdac, bt_reg, 0xff);
661 	REGWRITE32(vdac, bt_reg, 0xff);
662 	REGWRITE32(vdac, bt_reg, 0xff);
663 }
664 
665 static int
666 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
667 {
668 	u_int index = p->index, count = p->count;
669 	int error;
670 
671 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
672 		return (EINVAL);
673 
674 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
675 	if (error)
676 		return error;
677 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
678 	if (error)
679 		return error;
680 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
681 	return error;
682 }
683 
684 static int
685 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
686 {
687 	struct hwcmap256 cmap;
688 	u_int index = p->index, count = p->count;
689 	int error, s;
690 
691 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
692 		return (EINVAL);
693 
694 	error = copyin(p->red, &cmap.r[index], count);
695 	if (error)
696 		return error;
697 	error = copyin(p->green, &cmap.g[index], count);
698 	if (error)
699 		return error;
700 	error = copyin(p->blue, &cmap.b[index], count);
701 	if (error)
702 		return error;
703 	s = spltty();
704 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
705 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
706 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
707 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
708 	splx(s);
709 	return (0);
710 }
711 
712 static int
713 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
714 {
715 #define	cc (&sc->sc_cursor)
716 	u_int v, index = 0, count = 0, icount = 0;
717 	uint8_t r[2], g[2], b[2], image[512], mask[512];
718 	int error, s;
719 
720 	v = p->which;
721 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
722 		index = p->cmap.index;
723 		count = p->cmap.count;
724 		if (index >= 2 || (index + count) > 2)
725 			return (EINVAL);
726 		error = copyin(p->cmap.red, &r[index], count);
727 		if (error)
728 			return error;
729 		error = copyin(p->cmap.green, &g[index], count);
730 		if (error)
731 			return error;
732 		error = copyin(p->cmap.blue, &b[index], count);
733 		if (error)
734 			return error;
735 	}
736 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
737 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
738 			return (EINVAL);
739 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
740 		error = copyin(p->image, image, icount);
741 		if (error)
742 			return error;
743 		error = copyin(p->mask, mask, icount);
744 		if (error)
745 			return error;
746 	}
747 
748 	s = spltty();
749 	if (v & WSDISPLAY_CURSOR_DOCUR)
750 		sc->sc_curenb = p->enable;
751 	if (v & WSDISPLAY_CURSOR_DOPOS)
752 		set_curpos(sc, &p->pos);
753 	if (v & WSDISPLAY_CURSOR_DOHOT)
754 		cc->cc_hot = p->hot;
755 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
756 		memcpy(&cc->cc_color[index], &r[index], count);
757 		memcpy(&cc->cc_color[index + 2], &g[index], count);
758 		memcpy(&cc->cc_color[index + 4], &b[index], count);
759 	}
760 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
761 		cc->cc_size = p->size;
762 		memset(cc->cc_image, 0, sizeof cc->cc_image);
763 		memcpy(cc->cc_image, image, icount);
764 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
765 		memcpy(cc->cc_mask, mask, icount);
766 	}
767 	sc->sc_changed |= v;
768 	splx(s);
769 
770 	return (0);
771 #undef cc
772 }
773 
774 static int
775 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
776 {
777 	return (EPASSTHROUGH); /* XXX */
778 }
779 
780 static void
781 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
782 {
783 	struct rasops_info *ri = sc->sc_ri;
784 	int x = curpos->x, y = curpos->y;
785 
786 	if (y < 0)
787 		y = 0;
788 	else if (y > ri->ri_height)
789 		y = ri->ri_height;
790 	if (x < 0)
791 		x = 0;
792 	else if (x > ri->ri_width)
793 		x = ri->ri_width;
794 	sc->sc_cursor.cc_pos.x = x;
795 	sc->sc_cursor.cc_pos.y = y;
796 }
797