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