xref: /netbsd/sys/dev/tc/cfb.c (revision bf9ec67e)
1 /* $NetBSD: cfb.c,v 1.32 2002/03/17 19:41:02 atatat 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.32 2002/03/17 19:41:02 atatat 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 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
333 	    WSDISPLAY_FONTORDER_L2R);
334 	if (cookie <= 0)
335 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
336 		    WSDISPLAY_FONTORDER_L2R);
337 	if (cookie <= 0) {
338 		printf("cfb: font table is empty\n");
339 		return;
340 	}
341 
342 	if (wsfont_lock(cookie, &ri->ri_font)) {
343 		printf("cfb: couldn't lock font\n");
344 		return;
345 	}
346 	ri->ri_wsfcookie = cookie;
347 
348 	rasops_init(ri, 34, 80);
349 
350 	/* XXX shouldn't be global */
351 	cfb_stdscreen.nrows = ri->ri_rows;
352 	cfb_stdscreen.ncols = ri->ri_cols;
353 	cfb_stdscreen.textops = &ri->ri_ops;
354 	cfb_stdscreen.capabilities = ri->ri_caps;
355 }
356 
357 static int
358 cfbioctl(v, cmd, data, flag, p)
359 	void *v;
360 	u_long cmd;
361 	caddr_t data;
362 	int flag;
363 	struct proc *p;
364 {
365 	struct cfb_softc *sc = v;
366 	struct rasops_info *ri = sc->sc_ri;
367 	int turnoff;
368 
369 	switch (cmd) {
370 	case WSDISPLAYIO_GTYPE:
371 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
372 		return (0);
373 
374 	case WSDISPLAYIO_GINFO:
375 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
376 		wsd_fbip->height = ri->ri_height;
377 		wsd_fbip->width = ri->ri_width;
378 		wsd_fbip->depth = ri->ri_depth;
379 		wsd_fbip->cmsize = CMAP_SIZE;
380 #undef fbt
381 		return (0);
382 
383 	case WSDISPLAYIO_GETCMAP:
384 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
385 
386 	case WSDISPLAYIO_PUTCMAP:
387 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
388 
389 	case WSDISPLAYIO_SVIDEO:
390 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
391 		if ((sc->sc_blanked == 0) ^ turnoff) {
392 			sc->sc_blanked = turnoff;
393 			/* XXX later XXX */
394 		}
395 		return (0);
396 
397 	case WSDISPLAYIO_GVIDEO:
398 		*(u_int *)data = sc->sc_blanked ?
399 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
400 		return (0);
401 
402 	case WSDISPLAYIO_GCURPOS:
403 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
404 		return (0);
405 
406 	case WSDISPLAYIO_SCURPOS:
407 		set_curpos(sc, (struct wsdisplay_curpos *)data);
408 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
409 		return (0);
410 
411 	case WSDISPLAYIO_GCURMAX:
412 		((struct wsdisplay_curpos *)data)->x =
413 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
414 		return (0);
415 
416 	case WSDISPLAYIO_GCURSOR:
417 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
418 
419 	case WSDISPLAYIO_SCURSOR:
420 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
421 	}
422 	return EPASSTHROUGH;
423 }
424 
425 paddr_t
426 cfbmmap(v, offset, prot)
427 	void *v;
428 	off_t offset;
429 	int prot;
430 {
431 	struct cfb_softc *sc = v;
432 
433 	if (offset >= CX_FB_SIZE || offset < 0)
434 		return (-1);
435 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
436 }
437 
438 static int
439 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
440 	void *v;
441 	const struct wsscreen_descr *type;
442 	void **cookiep;
443 	int *curxp, *curyp;
444 	long *attrp;
445 {
446 	struct cfb_softc *sc = v;
447 	struct rasops_info *ri = sc->sc_ri;
448 	long defattr;
449 
450 	if (sc->nscreens > 0)
451 		return (ENOMEM);
452 
453 	*cookiep = ri;	 /* one and only for now */
454 	*curxp = 0;
455 	*curyp = 0;
456 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
457 	*attrp = defattr;
458 	sc->nscreens++;
459 	return (0);
460 }
461 
462 static void
463 cfb_free_screen(v, cookie)
464 	void *v;
465 	void *cookie;
466 {
467 	struct cfb_softc *sc = v;
468 
469 	if (sc->sc_ri == &cfb_console_ri)
470 		panic("cfb_free_screen: console");
471 
472 	sc->nscreens--;
473 }
474 
475 static int
476 cfb_show_screen(v, cookie, waitok, cb, cbarg)
477 	void *v;
478 	void *cookie;
479 	int waitok;
480 	void (*cb) __P((void *, int, int));
481 	void *cbarg;
482 {
483 
484 	return (0);
485 }
486 
487 /* EXPORT */ int
488 cfb_cnattach(addr)
489 	tc_addr_t addr;
490 {
491 	struct rasops_info *ri;
492 	long defattr;
493 
494 	ri = &cfb_console_ri;
495 	ri->ri_hw = (void *)addr;
496 	cfb_common_init(ri);
497 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
498 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
499 	cfb_consaddr = addr;
500 	return(0);
501 }
502 
503 static int
504 cfbintr(arg)
505 	void *arg;
506 {
507 	struct cfb_softc *sc = arg;
508 	caddr_t base, vdac;
509 	int v;
510 
511 	base = (caddr_t)sc->sc_ri->ri_hw;
512 	*(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
513 	if (sc->sc_changed == 0)
514 		return (1);
515 
516 	vdac = base + CX_BT459_OFFSET;
517 	v = sc->sc_changed;
518 	if (v & WSDISPLAY_CURSOR_DOCUR) {
519 		SELECT(vdac, BT459_IREG_CCR);
520 		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
521 	}
522 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
523 		int x, y;
524 
525 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
526 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
527 
528 		x += sc->sc_cursor.cc_magic.x;
529 		y += sc->sc_cursor.cc_magic.y;
530 
531 		SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
532 		REG(vdac, bt_reg) = x;		tc_wmb();
533 		REG(vdac, bt_reg) = x >> 8;	tc_wmb();
534 		REG(vdac, bt_reg) = y;		tc_wmb();
535 		REG(vdac, bt_reg) = y >> 8;	tc_wmb();
536 	}
537 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
538 		u_int8_t *cp = sc->sc_cursor.cc_color;
539 
540 		SELECT(vdac, BT459_IREG_CCOLOR_2);
541 		REG(vdac, bt_reg) = cp[1];	tc_wmb();
542 		REG(vdac, bt_reg) = cp[3];	tc_wmb();
543 		REG(vdac, bt_reg) = cp[5];	tc_wmb();
544 
545 		REG(vdac, bt_reg) = cp[0];	tc_wmb();
546 		REG(vdac, bt_reg) = cp[2];	tc_wmb();
547 		REG(vdac, bt_reg) = cp[4];	tc_wmb();
548 	}
549 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
550 		u_int8_t *ip, *mp, img, msk;
551 		u_int8_t u;
552 		int bcnt;
553 
554 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
555 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
556 
557 		bcnt = 0;
558 		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
559 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
560 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
561 			/* pad right half 32 pixel when smaller than 33 */
562 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
563 				REG(vdac, bt_reg) = 0; tc_wmb();
564 				REG(vdac, bt_reg) = 0; tc_wmb();
565 			}
566 			else {
567 				img = *ip++;
568 				msk = *mp++;
569 				img &= msk;	/* cookie off image */
570 				u = (msk & 0x0f) << 4 | (img & 0x0f);
571 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
572 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
573 				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
574 			}
575 			bcnt += 2;
576 		}
577 		/* pad unoccupied scan lines */
578 		while (bcnt < CURSOR_MAX_SIZE * 16) {
579 			REG(vdac, bt_reg) = 0; tc_wmb();
580 			REG(vdac, bt_reg) = 0; tc_wmb();
581 			bcnt += 2;
582 		}
583 	}
584 	if (v & WSDISPLAY_CMAP_DOLUT) {
585 		struct hwcmap256 *cm = &sc->sc_cmap;
586 		int index;
587 
588 		SELECT(vdac, 0);
589 		for (index = 0; index < CMAP_SIZE; index++) {
590 			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
591 			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
592 			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
593 		}
594 	}
595 	sc->sc_changed = 0;
596 	return (1);
597 }
598 
599 static void
600 cfbhwinit(cfbbase)
601 	caddr_t cfbbase;
602 {
603 	caddr_t vdac = cfbbase + CX_BT459_OFFSET;
604 	const u_int8_t *p;
605 	int i;
606 
607 	SELECT(vdac, BT459_IREG_COMMAND_0);
608 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
609 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
610 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
611 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
612 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
613 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
614 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
615 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
616 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
617 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
618 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
619 
620 	SELECT(vdac, BT459_IREG_CCR);
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 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
634 
635 	/* build sane colormap */
636 	SELECT(vdac, 0);
637 	p = rasops_cmap;
638 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
639 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
640 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
641 		REG(vdac, bt_cmap) = p[2];	tc_wmb();
642 	}
643 
644 	/* clear out cursor image */
645 	SELECT(vdac, BT459_IREG_CRAM_BASE);
646 	for (i = 0; i < 1024; i++)
647 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
648 
649 	/*
650 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
651 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
652 	 * image color.  CCOLOR_1 will be never used.
653 	 */
654 	SELECT(vdac, BT459_IREG_CCOLOR_1);
655 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
656 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
657 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
658 
659 	REG(vdac, bt_reg) = 0;	tc_wmb();
660 	REG(vdac, bt_reg) = 0;	tc_wmb();
661 	REG(vdac, bt_reg) = 0;	tc_wmb();
662 
663 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
664 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
665 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
666 }
667 
668 static int
669 get_cmap(sc, p)
670 	struct cfb_softc *sc;
671 	struct wsdisplay_cmap *p;
672 {
673 	u_int index = p->index, count = p->count;
674 
675 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
676 		return (EINVAL);
677 
678 	if (!uvm_useracc(p->red, count, B_WRITE) ||
679 	    !uvm_useracc(p->green, count, B_WRITE) ||
680 	    !uvm_useracc(p->blue, count, B_WRITE))
681 		return (EFAULT);
682 
683 	copyout(&sc->sc_cmap.r[index], p->red, count);
684 	copyout(&sc->sc_cmap.g[index], p->green, count);
685 	copyout(&sc->sc_cmap.b[index], p->blue, count);
686 
687 	return (0);
688 }
689 
690 static int
691 set_cmap(sc, p)
692 	struct cfb_softc *sc;
693 	struct wsdisplay_cmap *p;
694 {
695 	u_int index = p->index, count = p->count;
696 
697 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
698 		return (EINVAL);
699 
700 	if (!uvm_useracc(p->red, count, B_READ) ||
701 	    !uvm_useracc(p->green, count, B_READ) ||
702 	    !uvm_useracc(p->blue, count, B_READ))
703 		return (EFAULT);
704 
705 	copyin(p->red, &sc->sc_cmap.r[index], count);
706 	copyin(p->green, &sc->sc_cmap.g[index], count);
707 	copyin(p->blue, &sc->sc_cmap.b[index], count);
708 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
709 	return (0);
710 }
711 
712 static int
713 set_cursor(sc, p)
714 	struct cfb_softc *sc;
715 	struct wsdisplay_cursor *p;
716 {
717 #define	cc (&sc->sc_cursor)
718 	u_int v, index, count, icount;
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 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
727 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
728 		    !uvm_useracc(p->cmap.blue, count, B_READ))
729 			return (EFAULT);
730 	}
731 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
732 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
733 			return (EINVAL);
734 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
735 		if (!uvm_useracc(p->image, icount, B_READ) ||
736 		    !uvm_useracc(p->mask, icount, B_READ))
737 			return (EFAULT);
738 	}
739 
740 	if (v & WSDISPLAY_CURSOR_DOCUR)
741 		sc->sc_curenb = p->enable;
742 	if (v & WSDISPLAY_CURSOR_DOPOS)
743 		set_curpos(sc, &p->pos);
744 	if (v & WSDISPLAY_CURSOR_DOHOT)
745 		cc->cc_hot = p->hot;
746 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
747 		copyin(p->cmap.red, &cc->cc_color[index], count);
748 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
749 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
750 	}
751 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
752 		cc->cc_size = p->size;
753 		memset(cc->cc_image, 0, sizeof cc->cc_image);
754 		copyin(p->image, cc->cc_image, icount);
755 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
756 	}
757 	sc->sc_changed |= v;
758 
759 	return (0);
760 #undef cc
761 }
762 
763 static int
764 get_cursor(sc, p)
765 	struct cfb_softc *sc;
766 	struct wsdisplay_cursor *p;
767 {
768 	return (EPASSTHROUGH); /* XXX */
769 }
770 
771 static void
772 set_curpos(sc, curpos)
773 	struct cfb_softc *sc;
774 	struct wsdisplay_curpos *curpos;
775 {
776 	struct rasops_info *ri = sc->sc_ri;
777 	int x = curpos->x, y = curpos->y;
778 
779 	if (y < 0)
780 		y = 0;
781 	else if (y > ri->ri_height)
782 		y = ri->ri_height;
783 	if (x < 0)
784 		x = 0;
785 	else if (x > ri->ri_width)
786 		x = ri->ri_width;
787 	sc->sc_cursor.cc_pos.x = x;
788 	sc->sc_cursor.cc_pos.y = y;
789 }
790