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