xref: /netbsd/sys/dev/tc/cfb.c (revision c4a72b64)
1 /* $NetBSD: cfb.c,v 1.38 2002/10/02 16:53:02 thorpej 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.38 2002/10/02 16:53:02 thorpej 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 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
143     cfbmatch, cfbattach, NULL, NULL);
144 
145 static void cfb_common_init __P((struct rasops_info *));
146 static struct rasops_info cfb_console_ri;
147 static tc_addr_t cfb_consaddr;
148 
149 static struct wsscreen_descr cfb_stdscreen = {
150 	"std", 0, 0,
151 	0, /* textops */
152 	0, 0,
153 	WSSCREEN_REVERSE
154 };
155 
156 static const struct wsscreen_descr *_cfb_scrlist[] = {
157 	&cfb_stdscreen,
158 };
159 
160 static const struct wsscreen_list cfb_screenlist = {
161 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
162 };
163 
164 static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
165 static paddr_t	cfbmmap __P((void *, off_t, int));
166 
167 static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
168 				      void **, int *, int *, long *));
169 static void	cfb_free_screen __P((void *, void *));
170 static int	cfb_show_screen __P((void *, void *, int,
171 				     void (*) (void *, int, int), void *));
172 
173 static const struct wsdisplay_accessops cfb_accessops = {
174 	cfbioctl,
175 	cfbmmap,
176 	cfb_alloc_screen,
177 	cfb_free_screen,
178 	cfb_show_screen,
179 	0 /* load_font */
180 };
181 
182 int  cfb_cnattach __P((tc_addr_t));
183 static int  cfbintr __P((void *));
184 static void cfbhwinit __P((caddr_t));
185 
186 static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
187 static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
188 static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
189 static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
190 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
191 
192 /*
193  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
194  *   M M M M I I I I		M I M I M I M I
195  *	[ before ]		   [ after ]
196  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
197  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
198  */
199 static const u_int8_t shuffle[256] = {
200 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
201 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
202 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
203 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
204 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
205 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
206 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
207 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
208 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
209 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
210 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
211 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
212 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
213 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
214 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
215 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
216 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
217 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
218 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
219 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
220 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
221 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
222 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
223 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
224 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
225 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
226 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
227 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
228 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
229 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
230 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
231 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
232 };
233 
234 static int
235 cfbmatch(parent, match, aux)
236 	struct device *parent;
237 	struct cfdata *match;
238 	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(parent, self, aux)
250 	struct device *parent, *self;
251 	void *aux;
252 {
253 	struct cfb_softc *sc = (struct cfb_softc *)self;
254 	struct tc_attach_args *ta = aux;
255 	struct rasops_info *ri;
256 	struct wsemuldisplaydev_attach_args waa;
257 	struct hwcmap256 *cm;
258 	const u_int8_t *p;
259 	int console, index;
260 
261 	console = (ta->ta_addr == cfb_consaddr);
262 	if (console) {
263 		sc->sc_ri = ri = &cfb_console_ri;
264 		sc->nscreens = 1;
265 	}
266 	else {
267 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
268 			M_DEVBUF, M_NOWAIT);
269 		if (ri == NULL) {
270 			printf(": can't alloc memory\n");
271 			return;
272 		}
273 		memset(ri, 0, sizeof(struct rasops_info));
274 
275 		ri->ri_hw = (void *)ta->ta_addr;
276 		cfb_common_init(ri);
277 		sc->sc_ri = ri;
278 	}
279 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
280 
281 	cm = &sc->sc_cmap;
282 	p = rasops_cmap;
283 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
284 		cm->r[index] = p[0];
285 		cm->g[index] = p[1];
286 		cm->b[index] = p[2];
287 	}
288 
289 	sc->sc_vaddr = ta->ta_addr;
290 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
291 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
292 	sc->sc_blanked = sc->sc_curenb = 0;
293 
294 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
295 
296 	/* clear any pending interrupts */
297 	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
298 
299 	waa.console = console;
300 	waa.scrdata = &cfb_screenlist;
301 	waa.accessops = &cfb_accessops;
302 	waa.accesscookie = sc;
303 
304 	config_found(self, &waa, wsemuldisplaydevprint);
305 }
306 
307 static void
308 cfb_common_init(ri)
309 	struct rasops_info *ri;
310 {
311 	caddr_t base;
312 	int cookie;
313 
314 	base = (caddr_t)ri->ri_hw;
315 
316 	/* initialize colormap and cursor hardware */
317 	cfbhwinit(base);
318 
319 	ri->ri_flg = RI_CENTER;
320 	ri->ri_depth = 8;
321 	ri->ri_width = 1024;
322 	ri->ri_height = 864;
323 	ri->ri_stride = 1024;
324 	ri->ri_bits = base + CX_FB_OFFSET;
325 
326 	/* clear the screen */
327 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
328 
329 	wsfont_init();
330 	/* prefer 12 pixel wide font */
331 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
332 	    WSDISPLAY_FONTORDER_L2R);
333 	if (cookie <= 0)
334 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
335 		    WSDISPLAY_FONTORDER_L2R);
336 	if (cookie <= 0) {
337 		printf("cfb: font table is empty\n");
338 		return;
339 	}
340 
341 	if (wsfont_lock(cookie, &ri->ri_font)) {
342 		printf("cfb: couldn't lock font\n");
343 		return;
344 	}
345 	ri->ri_wsfcookie = cookie;
346 
347 	rasops_init(ri, 34, 80);
348 
349 	/* XXX shouldn't be global */
350 	cfb_stdscreen.nrows = ri->ri_rows;
351 	cfb_stdscreen.ncols = ri->ri_cols;
352 	cfb_stdscreen.textops = &ri->ri_ops;
353 	cfb_stdscreen.capabilities = ri->ri_caps;
354 }
355 
356 static int
357 cfbioctl(v, cmd, data, flag, p)
358 	void *v;
359 	u_long cmd;
360 	caddr_t data;
361 	int flag;
362 	struct proc *p;
363 {
364 	struct cfb_softc *sc = v;
365 	struct rasops_info *ri = sc->sc_ri;
366 	int turnoff;
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 == 0) ^ 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 		set_curpos(sc, (struct wsdisplay_curpos *)data);
407 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
408 		return (0);
409 
410 	case WSDISPLAYIO_GCURMAX:
411 		((struct wsdisplay_curpos *)data)->x =
412 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
413 		return (0);
414 
415 	case WSDISPLAYIO_GCURSOR:
416 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
417 
418 	case WSDISPLAYIO_SCURSOR:
419 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
420 	}
421 	return EPASSTHROUGH;
422 }
423 
424 paddr_t
425 cfbmmap(v, offset, prot)
426 	void *v;
427 	off_t offset;
428 	int prot;
429 {
430 	struct cfb_softc *sc = v;
431 
432 	if (offset >= CX_FB_SIZE || offset < 0)
433 		return (-1);
434 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
435 }
436 
437 static int
438 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
439 	void *v;
440 	const struct wsscreen_descr *type;
441 	void **cookiep;
442 	int *curxp, *curyp;
443 	long *attrp;
444 {
445 	struct cfb_softc *sc = v;
446 	struct rasops_info *ri = sc->sc_ri;
447 	long defattr;
448 
449 	if (sc->nscreens > 0)
450 		return (ENOMEM);
451 
452 	*cookiep = ri;	 /* one and only for now */
453 	*curxp = 0;
454 	*curyp = 0;
455 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
456 	*attrp = defattr;
457 	sc->nscreens++;
458 	return (0);
459 }
460 
461 static void
462 cfb_free_screen(v, cookie)
463 	void *v;
464 	void *cookie;
465 {
466 	struct cfb_softc *sc = v;
467 
468 	if (sc->sc_ri == &cfb_console_ri)
469 		panic("cfb_free_screen: console");
470 
471 	sc->nscreens--;
472 }
473 
474 static int
475 cfb_show_screen(v, cookie, waitok, cb, cbarg)
476 	void *v;
477 	void *cookie;
478 	int waitok;
479 	void (*cb) __P((void *, int, int));
480 	void *cbarg;
481 {
482 
483 	return (0);
484 }
485 
486 /* EXPORT */ int
487 cfb_cnattach(addr)
488 	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(arg)
504 	void *arg;
505 {
506 	struct cfb_softc *sc = arg;
507 	caddr_t base, vdac;
508 	int v;
509 
510 	base = (caddr_t)sc->sc_ri->ri_hw;
511 	*(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
512 	if (sc->sc_changed == 0)
513 		return (1);
514 
515 	vdac = base + CX_BT459_OFFSET;
516 	v = sc->sc_changed;
517 	if (v & WSDISPLAY_CURSOR_DOCUR) {
518 		SELECT(vdac, BT459_IREG_CCR);
519 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
520 	}
521 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
522 		int x, y;
523 
524 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
525 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
526 
527 		x += sc->sc_cursor.cc_magic.x;
528 		y += sc->sc_cursor.cc_magic.y;
529 
530 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
531 		REG(vdac, bt_reg) = x;		tc_wmb();
532 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
533 		REG(vdac, bt_reg) = y;		tc_wmb();
534 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
535 	}
536 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
537 		u_int8_t *cp = sc->sc_cursor.cc_color;
538 
539 		SELECT(vdac, BT459_IREG_CCOLOR_2);
540 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
541 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
542 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
543 
544 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
545 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
546 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
547 	}
548 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
549 		u_int8_t *ip, *mp, img, msk;
550 		u_int8_t u;
551 		int bcnt;
552 
553 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
554 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
555 
556 		bcnt = 0;
557 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
558 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
559 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
560 			/* pad right half 32 pixel when smaller than 33 */
561 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
562 				REG(vdac, bt_reg) = 0; tc_wmb();
563 				REG(vdac, bt_reg) = 0; tc_wmb();
564 			}
565 			else {
566 				img = *ip++;
567 				msk = *mp++;
568 				img &= msk;	/* cookie off image */
569 				u = (msk & 0x0f) << 4 | (img & 0x0f);
570 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
571 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
572 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
573 			}
574 			bcnt += 2;
575 		}
576 		/* pad unoccupied scan lines */
577 		while (bcnt < CURSOR_MAX_SIZE * 16) {
578 			REG(vdac, bt_reg) = 0; tc_wmb();
579 			REG(vdac, bt_reg) = 0; tc_wmb();
580 			bcnt += 2;
581 		}
582 	}
583 	if (v & WSDISPLAY_CMAP_DOLUT) {
584 		struct hwcmap256 *cm = &sc->sc_cmap;
585 		int index;
586 
587 		SELECT(vdac, 0);
588 		for (index = 0; index < CMAP_SIZE; index++) {
589 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
590 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
591 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
592 		}
593 	}
594 	sc->sc_changed = 0;
595 	return (1);
596 }
597 
598 static void
599 cfbhwinit(cfbbase)
600 	caddr_t cfbbase;
601 {
602 	caddr_t vdac = cfbbase + CX_BT459_OFFSET;
603 	const u_int8_t *p;
604 	int i;
605 
606 	SELECT(vdac, BT459_IREG_COMMAND_0);
607 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
608 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
609 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
610 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
611 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
612 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
613 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
614 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
615 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
616 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
617 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
618 
619 	SELECT(vdac, BT459_IREG_CCR);
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 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
633 
634 	/* build sane colormap */
635 	SELECT(vdac, 0);
636 	p = rasops_cmap;
637 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
638 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
639 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
640 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
641 	}
642 
643 	/* clear out cursor image */
644 	SELECT(vdac, BT459_IREG_CRAM_BASE);
645 	for (i = 0; i < 1024; i++)
646 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
647 
648 	/*
649 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
650 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
651 	 * image color.  CCOLOR_1 will be never used.
652 	 */
653 	SELECT(vdac, BT459_IREG_CCOLOR_1);
654 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
655 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
656 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
657 
658 	REG(vdac, bt_reg) = 0;	tc_wmb();
659 	REG(vdac, bt_reg) = 0;	tc_wmb();
660 	REG(vdac, bt_reg) = 0;	tc_wmb();
661 
662 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
663 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
664 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
665 }
666 
667 static int
668 get_cmap(sc, p)
669 	struct cfb_softc *sc;
670 	struct wsdisplay_cmap *p;
671 {
672 	u_int index = p->index, count = p->count;
673 
674 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
675 		return (EINVAL);
676 
677 	if (!uvm_useracc(p->red, count, B_WRITE) ||
678 	    !uvm_useracc(p->green, count, B_WRITE) ||
679 	    !uvm_useracc(p->blue, count, B_WRITE))
680 		return (EFAULT);
681 
682 	copyout(&sc->sc_cmap.r[index], p->red, count);
683 	copyout(&sc->sc_cmap.g[index], p->green, count);
684 	copyout(&sc->sc_cmap.b[index], p->blue, count);
685 
686 	return (0);
687 }
688 
689 static int
690 set_cmap(sc, p)
691 	struct cfb_softc *sc;
692 	struct wsdisplay_cmap *p;
693 {
694 	u_int index = p->index, count = p->count;
695 
696 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
697 		return (EINVAL);
698 
699 	if (!uvm_useracc(p->red, count, B_READ) ||
700 	    !uvm_useracc(p->green, count, B_READ) ||
701 	    !uvm_useracc(p->blue, count, B_READ))
702 		return (EFAULT);
703 
704 	copyin(p->red, &sc->sc_cmap.r[index], count);
705 	copyin(p->green, &sc->sc_cmap.g[index], count);
706 	copyin(p->blue, &sc->sc_cmap.b[index], count);
707 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
708 	return (0);
709 }
710 
711 static int
712 set_cursor(sc, p)
713 	struct cfb_softc *sc;
714 	struct wsdisplay_cursor *p;
715 {
716 #define	cc (&sc->sc_cursor)
717 	u_int v, index, count, icount;
718 
719 	v = p->which;
720 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
721 		index = p->cmap.index;
722 		count = p->cmap.count;
723 		if (index >= 2 || (index + count) > 2)
724 			return (EINVAL);
725 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
726 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
727 		    !uvm_useracc(p->cmap.blue, count, B_READ))
728 			return (EFAULT);
729 	}
730 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
731 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
732 			return (EINVAL);
733 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
734 		if (!uvm_useracc(p->image, icount, B_READ) ||
735 		    !uvm_useracc(p->mask, icount, B_READ))
736 			return (EFAULT);
737 	}
738 
739 	if (v & WSDISPLAY_CURSOR_DOCUR)
740 		sc->sc_curenb = p->enable;
741 	if (v & WSDISPLAY_CURSOR_DOPOS)
742 		set_curpos(sc, &p->pos);
743 	if (v & WSDISPLAY_CURSOR_DOHOT)
744 		cc->cc_hot = p->hot;
745 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
746 		copyin(p->cmap.red, &cc->cc_color[index], count);
747 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
748 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
749 	}
750 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
751 		cc->cc_size = p->size;
752 		memset(cc->cc_image, 0, sizeof cc->cc_image);
753 		copyin(p->image, cc->cc_image, icount);
754 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
755 	}
756 	sc->sc_changed |= v;
757 
758 	return (0);
759 #undef cc
760 }
761 
762 static int
763 get_cursor(sc, p)
764 	struct cfb_softc *sc;
765 	struct wsdisplay_cursor *p;
766 {
767 	return (EPASSTHROUGH); /* XXX */
768 }
769 
770 static void
771 set_curpos(sc, curpos)
772 	struct cfb_softc *sc;
773 	struct wsdisplay_curpos *curpos;
774 {
775 	struct rasops_info *ri = sc->sc_ri;
776 	int x = curpos->x, y = curpos->y;
777 
778 	if (y < 0)
779 		y = 0;
780 	else if (y > ri->ri_height)
781 		y = ri->ri_height;
782 	if (x < 0)
783 		x = 0;
784 	else if (x > ri->ri_width)
785 		x = ri->ri_width;
786 	sc->sc_cursor.cc_pos.x = x;
787 	sc->sc_cursor.cc_pos.y = y;
788 }
789