cfb.c revision 1.42
1/* $NetBSD: cfb.c,v 1.42 2003/11/13 03:09:29 chs 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.42 2003/11/13 03:09:29 chs 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
100struct 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
107struct 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[CURSOR_MAX_SIZE];
115	u_int64_t cc_mask[CURSOR_MAX_SIZE];
116};
117
118struct cfb_softc {
119	struct device sc_dev;
120	vaddr_t sc_vaddr;
121	size_t sc_size;
122	struct rasops_info *sc_ri;
123	struct hwcmap256 sc_cmap;	/* software copy of colormap */
124	struct hwcursor64 sc_cursor;	/* software copy of cursor */
125	int sc_blanked;
126	int sc_curenb;			/* cursor sprite enabled */
127	int sc_changed;			/* need update of hardware */
128#define	WSDISPLAY_CMAP_DOLUT	0x20
129	int nscreens;
130};
131
132#define	CX_MAGIC_X	220
133#define	CX_MAGIC_Y 	35
134
135#define	CX_FB_OFFSET	0x000000
136#define	CX_FB_SIZE	0x100000
137#define	CX_BT459_OFFSET	0x200000
138#define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
139
140static int  cfbmatch __P((struct device *, struct cfdata *, void *));
141static void cfbattach __P((struct device *, struct device *, void *));
142
143CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
144    cfbmatch, cfbattach, NULL, NULL);
145
146static void cfb_common_init __P((struct rasops_info *));
147static struct rasops_info cfb_console_ri;
148static tc_addr_t cfb_consaddr;
149
150static struct wsscreen_descr cfb_stdscreen = {
151	"std", 0, 0,
152	0, /* textops */
153	0, 0,
154	WSSCREEN_REVERSE
155};
156
157static const struct wsscreen_descr *_cfb_scrlist[] = {
158	&cfb_stdscreen,
159};
160
161static const struct wsscreen_list cfb_screenlist = {
162	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
163};
164
165static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
166static paddr_t	cfbmmap __P((void *, off_t, int));
167
168static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
169				      void **, int *, int *, long *));
170static void	cfb_free_screen __P((void *, void *));
171static int	cfb_show_screen __P((void *, void *, int,
172				     void (*) (void *, int, int), void *));
173
174static 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
183int  cfb_cnattach __P((tc_addr_t));
184static int  cfbintr __P((void *));
185static void cfbhwinit __P((caddr_t));
186
187static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
188static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
189static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
190static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
191static 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 */
200static 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
235static int
236cfbmatch(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
249static void
250cfbattach(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
308static void
309cfb_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
357static int
358cfbioctl(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
425paddr_t
426cfbmmap(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
438static int
439cfb_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.allocattr)(ri, 0, 0, 0, &defattr);
457	*attrp = defattr;
458	sc->nscreens++;
459	return (0);
460}
461
462static void
463cfb_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
475static int
476cfb_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
488cfb_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.allocattr)(ri, 0, 0, 0, &defattr);
498	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
499	cfb_consaddr = addr;
500	return(0);
501}
502
503static int
504cfbintr(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_mask;
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
599static void
600cfbhwinit(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
668static int
669get_cmap(sc, p)
670	struct cfb_softc *sc;
671	struct wsdisplay_cmap *p;
672{
673	u_int index = p->index, count = p->count;
674	int error;
675
676	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
677		return (EINVAL);
678
679	error = copyout(&sc->sc_cmap.r[index], p->red, count);
680	if (error)
681		return error;
682	error = copyout(&sc->sc_cmap.g[index], p->green, count);
683	if (error)
684		return error;
685	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
686	return error;
687}
688
689static int
690set_cmap(sc, p)
691	struct cfb_softc *sc;
692	struct wsdisplay_cmap *p;
693{
694	struct hwcmap256 cmap;
695	u_int index = p->index, count = p->count;
696	int error;
697
698	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
699		return (EINVAL);
700
701	error = copyin(p->red, &cmap.r[index], count);
702	if (error)
703		return error;
704	error = copyin(p->green, &cmap.g[index], count);
705	if (error)
706		return error;
707	error = copyin(p->blue, &cmap.b[index], count);
708	if (error)
709		return error;
710	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
711	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
712	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
713	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
714	return (0);
715}
716
717static int
718set_cursor(sc, p)
719	struct cfb_softc *sc;
720	struct wsdisplay_cursor *p;
721{
722#define	cc (&sc->sc_cursor)
723	u_int v, index = 0, count = 0, icount = 0;
724	uint8_t r[2], g[2], b[2], image[512], mask[512];
725	int error;
726
727	v = p->which;
728	if (v & WSDISPLAY_CURSOR_DOCMAP) {
729		index = p->cmap.index;
730		count = p->cmap.count;
731		if (index >= 2 || (index + count) > 2)
732			return (EINVAL);
733		error = copyin(p->cmap.red, &r[index], count);
734		if (error)
735			return error;
736		error = copyin(p->cmap.green, &g[index], count);
737		if (error)
738			return error;
739		error = copyin(p->cmap.blue, &b[index], count);
740		if (error)
741			return error;
742	}
743	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
744		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
745			return (EINVAL);
746		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
747		error = copyin(p->image, image, icount);
748		if (error)
749			return error;
750		error = copyin(p->mask, mask, icount);
751		if (error)
752			return error;
753	}
754
755	if (v & WSDISPLAY_CURSOR_DOCUR)
756		sc->sc_curenb = p->enable;
757	if (v & WSDISPLAY_CURSOR_DOPOS)
758		set_curpos(sc, &p->pos);
759	if (v & WSDISPLAY_CURSOR_DOHOT)
760		cc->cc_hot = p->hot;
761	if (v & WSDISPLAY_CURSOR_DOCMAP) {
762		memcpy(&cc->cc_color[index], &r[index], count);
763		memcpy(&cc->cc_color[index + 2], &g[index], count);
764		memcpy(&cc->cc_color[index + 4], &b[index], count);
765	}
766	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
767		cc->cc_size = p->size;
768		memset(cc->cc_image, 0, sizeof cc->cc_image);
769		memcpy(cc->cc_image, image, icount);
770		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
771		memcpy(cc->cc_mask, mask, icount);
772	}
773	sc->sc_changed |= v;
774
775	return (0);
776#undef cc
777}
778
779static int
780get_cursor(sc, p)
781	struct cfb_softc *sc;
782	struct wsdisplay_cursor *p;
783{
784	return (EPASSTHROUGH); /* XXX */
785}
786
787static void
788set_curpos(sc, curpos)
789	struct cfb_softc *sc;
790	struct wsdisplay_curpos *curpos;
791{
792	struct rasops_info *ri = sc->sc_ri;
793	int x = curpos->x, y = curpos->y;
794
795	if (y < 0)
796		y = 0;
797	else if (y > ri->ri_height)
798		y = ri->ri_height;
799	if (x < 0)
800		x = 0;
801	else if (x > ri->ri_width)
802		x = ri->ri_width;
803	sc->sc_cursor.cc_pos.x = x;
804	sc->sc_cursor.cc_pos.y = y;
805}
806