cfb.c revision 1.29
1/* $NetBSD: cfb.c,v 1.29 2001/08/22 02:24:29 nisimura 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>			/* RCS ID & Copyright macro defns */
34
35__KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.29 2001/08/22 02:24:29 nisimura Exp $");
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/device.h>
41#include <sys/malloc.h>
42#include <sys/buf.h>
43#include <sys/ioctl.h>
44
45#include <machine/bus.h>
46#include <machine/intr.h>
47
48#include <dev/wscons/wsconsio.h>
49#include <dev/wscons/wsdisplayvar.h>
50
51#include <dev/rasops/rasops.h>
52#include <dev/wsfont/wsfont.h>
53
54#include <dev/tc/tcvar.h>
55#include <dev/ic/bt459reg.h>
56
57#include <uvm/uvm_extern.h>
58
59#if defined(pmax)
60#define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
61#endif
62
63#if defined(alpha)
64#define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
65#endif
66
67/*
68 * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
69 * obscure register layout such as 2nd and 3rd Bt459 registers are
70 * adjacent each other in a word, i.e.,
71 *	struct bt459triplet {
72 * 		struct {
73 *			u_int8_t u0;
74 *			u_int8_t u1;
75 *			u_int8_t u2;
76 *			unsigned :8;
77 *		} bt_lo;
78 *		...
79 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
80 *	struct bt459reg {
81 *		   u_int32_t	   bt_lo;
82 *		   u_int32_t	   bt_hi;
83 *		   u_int32_t	   bt_reg;
84 *		   u_int32_t	   bt_cmap;
85 *	};
86 */
87
88/* Bt459 hardware registers */
89#define	bt_lo	0
90#define	bt_hi	1
91#define	bt_reg	2
92#define	bt_cmap 3
93
94#define	REG(base, index)	*((u_int32_t *)(base) + (index))
95#define	SELECT(vdac, regno) do {			\
96	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
97	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
98	tc_wmb();					\
99   } while (0)
100
101struct 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
108struct 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[64 + 64];
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
143const struct cfattach cfb_ca = {
144	sizeof(struct cfb_softc), cfbmatch, cfbattach,
145};
146
147static void cfb_common_init __P((struct rasops_info *));
148static struct rasops_info cfb_console_ri;
149static tc_addr_t cfb_consaddr;
150
151static struct wsscreen_descr cfb_stdscreen = {
152	"std", 0, 0,
153	0, /* textops */
154	0, 0,
155	WSSCREEN_REVERSE
156};
157
158static const struct wsscreen_descr *_cfb_scrlist[] = {
159	&cfb_stdscreen,
160};
161
162static const struct wsscreen_list cfb_screenlist = {
163	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
164};
165
166static int	cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
167static paddr_t	cfbmmap __P((void *, off_t, int));
168
169static int	cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
170				      void **, int *, int *, long *));
171static void	cfb_free_screen __P((void *, void *));
172static int	cfb_show_screen __P((void *, void *, int,
173				     void (*) (void *, int, int), void *));
174
175static 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
184int  cfb_cnattach __P((tc_addr_t));
185static int  cfbintr __P((void *));
186static void cfbhwinit __P((caddr_t));
187
188static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
189static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
190static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
191static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
192static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
193
194/*
195 * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
196 *   M M M M I I I I		M I M I M I M I
197 *	[ before ]		   [ after ]
198 *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
199 *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
200 */
201static const u_int8_t shuffle[256] = {
202	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
203	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
204	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
205	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
206	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
207	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
208	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
209	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
210	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
211	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
212	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
213	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
214	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
215	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
216	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
217	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
218	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
219	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
220	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
221	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
222	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
223	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
224	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
225	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
226	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
227	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
228	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
229	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
230	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
231	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
232	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
233	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
234};
235
236static int
237cfbmatch(parent, match, aux)
238	struct device *parent;
239	struct cfdata *match;
240	void *aux;
241{
242	struct tc_attach_args *ta = aux;
243
244	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
245		return (0);
246
247	return (1);
248}
249
250static void
251cfbattach(parent, self, aux)
252	struct device *parent, *self;
253	void *aux;
254{
255	struct cfb_softc *sc = (struct cfb_softc *)self;
256	struct tc_attach_args *ta = aux;
257	struct rasops_info *ri;
258	struct wsemuldisplaydev_attach_args waa;
259	struct hwcmap256 *cm;
260	const u_int8_t *p;
261	int console, index;
262
263	console = (ta->ta_addr == cfb_consaddr);
264	if (console) {
265		sc->sc_ri = ri = &cfb_console_ri;
266		sc->nscreens = 1;
267	}
268	else {
269		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
270			M_DEVBUF, M_NOWAIT);
271		if (ri == NULL) {
272			printf(": can't alloc memory\n");
273			return;
274		}
275		memset(ri, 0, sizeof(struct rasops_info));
276
277		ri->ri_hw = (void *)ta->ta_addr;
278		cfb_common_init(ri);
279		sc->sc_ri = ri;
280	}
281	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
282
283	cm = &sc->sc_cmap;
284	p = rasops_cmap;
285	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
286		cm->r[index] = p[0];
287		cm->g[index] = p[1];
288		cm->b[index] = p[2];
289	}
290
291	sc->sc_vaddr = ta->ta_addr;
292	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
293	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
294	sc->sc_blanked = sc->sc_curenb = 0;
295
296	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
297
298	/* clear any pending interrupts */
299	*(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
300
301	waa.console = console;
302	waa.scrdata = &cfb_screenlist;
303	waa.accessops = &cfb_accessops;
304	waa.accesscookie = sc;
305
306	config_found(self, &waa, wsemuldisplaydevprint);
307}
308
309static void
310cfb_common_init(ri)
311	struct rasops_info *ri;
312{
313	caddr_t base;
314	int cookie;
315
316	base = (caddr_t)ri->ri_hw;
317
318	/* initialize colormap and cursor hardware */
319	cfbhwinit(base);
320
321	ri->ri_flg = RI_CENTER;
322	ri->ri_depth = 8;
323	ri->ri_width = 1024;
324	ri->ri_height = 864;
325	ri->ri_stride = 1024;
326	ri->ri_bits = base + CX_FB_OFFSET;
327
328	/* clear the screen */
329	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
330
331	wsfont_init();
332	/* prefer 12 pixel wide font */
333	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
334		cookie = wsfont_find(NULL, 0, 0, 0);
335	if (cookie <= 0) {
336		printf("cfb: font table is empty\n");
337		return;
338	}
339
340	if (wsfont_lock(cookie, &ri->ri_font,
341	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
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
356static int
357cfbioctl(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 ENOTTY;
422}
423
424paddr_t
425cfbmmap(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
437static int
438cfb_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.alloc_attr)(ri, 0, 0, 0, &defattr);
456	*attrp = defattr;
457	sc->nscreens++;
458	return (0);
459}
460
461static void
462cfb_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
474static int
475cfb_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
487cfb_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.alloc_attr)(ri, 0, 0, 0, &defattr);
497	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
498	cfb_consaddr = addr;
499	return(0);
500}
501
502static int
503cfbintr(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
598static void
599cfbhwinit(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
667static int
668get_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 || (index + count) > CMAP_SIZE)
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
689static int
690set_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 || (index + count) > CMAP_SIZE)
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
711static int
712set_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
762static int
763get_cursor(sc, p)
764	struct cfb_softc *sc;
765	struct wsdisplay_cursor *p;
766{
767	return (ENOTTY); /* XXX */
768}
769
770static void
771set_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