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