cfb.c revision 1.63
1/* $NetBSD: cfb.c,v 1.63 2019/11/10 21:16:37 chs Exp $ */
2
3/*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.63 2019/11/10 21:16:37 chs Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/device.h>
39#include <sys/malloc.h>
40#include <sys/buf.h>
41#include <sys/ioctl.h>
42
43#include <sys/bus.h>
44#include <sys/intr.h>
45
46#include <dev/wscons/wsconsio.h>
47#include <dev/wscons/wsdisplayvar.h>
48
49#include <dev/rasops/rasops.h>
50#include <dev/wsfont/wsfont.h>
51
52#include <dev/tc/tcvar.h>
53#include <dev/ic/bt459reg.h>
54
55#if defined(pmax)
56#define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
57#endif
58
59#if defined(alpha)
60#define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
61#endif
62
63/*
64 * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
65 * obscure register layout such as 2nd and 3rd Bt459 registers are
66 * adjacent each other in a word, i.e.,
67 *	struct bt459triplet {
68 * 		struct {
69 *			uint8_t u0;
70 *			uint8_t u1;
71 *			uint8_t u2;
72 *			unsigned :8;
73 *		} bt_lo;
74 *		...
75 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
76 *	struct bt459reg {
77 *		   uint32_t	   bt_lo;
78 *		   uint32_t	   bt_hi;
79 *		   uint32_t	   bt_reg;
80 *		   uint32_t	   bt_cmap;
81 *	};
82 */
83
84/* Bt459 hardware registers, memory-mapped in 32bit stride */
85#define	bt_lo	0x0
86#define	bt_hi	0x4
87#define	bt_reg	0x8
88#define	bt_cmap 0xc
89
90#define	REGWRITE32(p,i,v) do {					\
91	*(volatile uint32_t *)((p) + (i)) = (v); tc_wmb();	\
92    } while (0)
93#define	VDACSELECT(p,r) do {					\
94	REGWRITE32(p, bt_lo, 0xff & (r));			\
95	REGWRITE32(p, bt_hi, 0x0f & ((r)>>8));			\
96   } while (0)
97
98struct hwcmap256 {
99#define	CMAP_SIZE	256	/* 256 R/G/B entries */
100	uint8_t r[CMAP_SIZE];
101	uint8_t g[CMAP_SIZE];
102	uint8_t b[CMAP_SIZE];
103};
104
105struct hwcursor64 {
106	struct wsdisplay_curpos cc_pos;
107	struct wsdisplay_curpos cc_hot;
108	struct wsdisplay_curpos cc_size;
109	struct wsdisplay_curpos cc_magic;
110#define	CURSOR_MAX_SIZE	64
111	uint8_t cc_color[6];
112	uint64_t cc_image[CURSOR_MAX_SIZE];
113	uint64_t cc_mask[CURSOR_MAX_SIZE];
114};
115
116struct cfb_softc {
117	vaddr_t sc_vaddr;
118	size_t sc_size;
119	struct rasops_info *sc_ri;
120	struct hwcmap256 sc_cmap;	/* software copy of colormap */
121	struct hwcursor64 sc_cursor;	/* software copy of cursor */
122	int sc_blanked;
123	int sc_curenb;			/* cursor sprite enabled */
124	int sc_changed;			/* need update of hardware */
125#define	WSDISPLAY_CMAP_DOLUT	0x20
126	int nscreens;
127};
128
129#define	CX_MAGIC_X	220
130#define	CX_MAGIC_Y 	35
131
132#define	CX_FB_OFFSET	0x000000
133#define	CX_FB_SIZE	0x100000
134#define	CX_BT459_OFFSET	0x200000
135#define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
136
137static int  cfbmatch(device_t, cfdata_t, void *);
138static void cfbattach(device_t, device_t, void *);
139
140CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc),
141    cfbmatch, cfbattach, NULL, NULL);
142
143static void cfb_common_init(struct rasops_info *);
144static struct rasops_info cfb_console_ri;
145static tc_addr_t cfb_consaddr;
146
147static struct wsscreen_descr cfb_stdscreen = {
148	"std", 0, 0,
149	0, /* textops */
150	0, 0,
151	WSSCREEN_REVERSE
152};
153
154static const struct wsscreen_descr *_cfb_scrlist[] = {
155	&cfb_stdscreen,
156};
157
158static const struct wsscreen_list cfb_screenlist = {
159	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
160};
161
162static int	cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
163static paddr_t	cfbmmap(void *, void *, off_t, int);
164
165static int	cfb_alloc_screen(void *, const struct wsscreen_descr *,
166				      void **, int *, int *, long *);
167static void	cfb_free_screen(void *, void *);
168static int	cfb_show_screen(void *, void *, int,
169				     void (*) (void *, int, int), void *);
170
171static const struct wsdisplay_accessops cfb_accessops = {
172	cfbioctl,
173	cfbmmap,
174	cfb_alloc_screen,
175	cfb_free_screen,
176	cfb_show_screen,
177	0 /* load_font */
178};
179
180int  cfb_cnattach(tc_addr_t);
181static int  cfbintr(void *);
182static void cfbhwinit(void *);
183static void cfb_cmap_init(struct cfb_softc *);
184
185static int  get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
186static int  set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
187static int  set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
188static int  get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
189static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *);
190
191/*
192 * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
193 *   M M M M I I I I		M I M I M I M I
194 *	[ before ]		   [ after ]
195 *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
196 *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
197 */
198static const uint8_t shuffle[256] = {
199	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
200	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
201	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
202	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
203	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
204	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
205	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
206	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
207	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
208	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
209	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
210	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
211	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
212	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
213	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
214	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
215	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
216	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
217	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
218	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
219	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
220	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
221	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
222	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
223	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
224	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
225	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
226	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
227	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
228	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
229	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
230	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
231};
232
233static int
234cfbmatch(device_t parent, cfdata_t match, void *aux)
235{
236	struct tc_attach_args *ta = aux;
237
238	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
239		return (0);
240
241	return (1);
242}
243
244static void
245cfbattach(device_t parent, device_t self, void *aux)
246{
247	struct cfb_softc *sc = device_private(self);
248	struct tc_attach_args *ta = aux;
249	struct rasops_info *ri;
250	struct wsemuldisplaydev_attach_args waa;
251	int console;
252
253	console = (ta->ta_addr == cfb_consaddr);
254	if (console) {
255		sc->sc_ri = ri = &cfb_console_ri;
256		ri->ri_flg &= ~RI_NO_AUTO;
257		sc->nscreens = 1;
258	}
259	else {
260		ri = malloc(sizeof(struct rasops_info),
261			M_DEVBUF, M_WAITOK | M_ZERO);
262		ri->ri_hw = (void *)ta->ta_addr;
263		cfb_common_init(ri);
264		sc->sc_ri = ri;
265	}
266	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
267
268	cfb_cmap_init(sc);
269
270	sc->sc_vaddr = ta->ta_addr;
271	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
272	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
273	sc->sc_blanked = sc->sc_curenb = 0;
274
275	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
276
277	/* clear any pending interrupts */
278	*(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
279
280	waa.console = console;
281	waa.scrdata = &cfb_screenlist;
282	waa.accessops = &cfb_accessops;
283	waa.accesscookie = sc;
284
285	config_found(self, &waa, wsemuldisplaydevprint);
286}
287
288static void
289cfb_cmap_init(struct cfb_softc *sc)
290{
291	struct hwcmap256 *cm;
292	const uint8_t *p;
293	int index;
294
295	cm = &sc->sc_cmap;
296	p = rasops_cmap;
297	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
298		cm->r[index] = p[0];
299		cm->g[index] = p[1];
300		cm->b[index] = p[2];
301	}
302}
303
304static void
305cfb_common_init(struct rasops_info *ri)
306{
307	char *base;
308	int cookie;
309
310	base = (void *)ri->ri_hw;
311
312	/* initialize colormap and cursor hardware */
313	cfbhwinit(base);
314
315	ri->ri_flg = RI_CENTER;
316	if (ri == &cfb_console_ri)
317		ri->ri_flg |= RI_NO_AUTO;
318	ri->ri_depth = 8;
319	ri->ri_width = 1024;
320	ri->ri_height = 864;
321	ri->ri_stride = 1024;
322	ri->ri_bits = base + CX_FB_OFFSET;
323
324	/* clear the screen */
325	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
326
327	wsfont_init();
328	/* prefer 12 pixel wide font */
329	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
330	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
331	if (cookie <= 0)
332		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
333		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
334	if (cookie <= 0) {
335		printf("cfb: font table is empty\n");
336		return;
337	}
338
339	if (wsfont_lock(cookie, &ri->ri_font)) {
340		printf("cfb: couldn't lock font\n");
341		return;
342	}
343	ri->ri_wsfcookie = cookie;
344
345	rasops_init(ri, 34, 80);
346
347	/* XXX shouldn't be global */
348	cfb_stdscreen.nrows = ri->ri_rows;
349	cfb_stdscreen.ncols = ri->ri_cols;
350	cfb_stdscreen.textops = &ri->ri_ops;
351	cfb_stdscreen.capabilities = ri->ri_caps;
352}
353
354static int
355cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
356{
357	struct cfb_softc *sc = v;
358	struct rasops_info *ri = sc->sc_ri;
359	int turnoff, s;
360
361	switch (cmd) {
362	case WSDISPLAYIO_GTYPE:
363		*(u_int *)data = WSDISPLAY_TYPE_CFB;
364		return (0);
365
366	case WSDISPLAYIO_GINFO:
367#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
368		wsd_fbip->height = ri->ri_height;
369		wsd_fbip->width = ri->ri_width;
370		wsd_fbip->depth = ri->ri_depth;
371		wsd_fbip->cmsize = CMAP_SIZE;
372#undef fbt
373		return (0);
374
375	case WSDISPLAYIO_GETCMAP:
376		return get_cmap(sc, (struct wsdisplay_cmap *)data);
377
378	case WSDISPLAYIO_PUTCMAP:
379		return set_cmap(sc, (struct wsdisplay_cmap *)data);
380
381	case WSDISPLAYIO_SVIDEO:
382		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
383		if (sc->sc_blanked != turnoff) {
384			sc->sc_blanked = turnoff;
385			/* XXX later XXX */
386		}
387		return (0);
388
389	case WSDISPLAYIO_GVIDEO:
390		*(u_int *)data = sc->sc_blanked ?
391		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
392		return (0);
393
394	case WSDISPLAYIO_GCURPOS:
395		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
396		return (0);
397
398	case WSDISPLAYIO_SCURPOS:
399		s = spltty();
400		set_curpos(sc, (struct wsdisplay_curpos *)data);
401		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
402		splx(s);
403		return (0);
404
405	case WSDISPLAYIO_GCURMAX:
406		((struct wsdisplay_curpos *)data)->x =
407		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
408		return (0);
409
410	case WSDISPLAYIO_GCURSOR:
411		return get_cursor(sc, (struct wsdisplay_cursor *)data);
412
413	case WSDISPLAYIO_SCURSOR:
414		return set_cursor(sc, (struct wsdisplay_cursor *)data);
415
416	case WSDISPLAYIO_SMODE:
417		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
418			s = spltty();
419			cfb_cmap_init(sc);
420			sc->sc_curenb = 0;
421			sc->sc_blanked = 0;
422			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
423			    WSDISPLAY_CMAP_DOLUT);
424			splx(s);
425		}
426		return (0);
427	}
428	return EPASSTHROUGH;
429}
430
431paddr_t
432cfbmmap(void *v, void *vs, off_t offset, int prot)
433{
434	struct cfb_softc *sc = v;
435
436	if (offset >= CX_FB_SIZE || offset < 0)
437		return (-1);
438	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
439}
440
441static int
442cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
443    int *curxp, int *curyp, 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.allocattr)(ri, 0, 0, 0, &defattr);
456	*attrp = defattr;
457	sc->nscreens++;
458	return (0);
459}
460
461static void
462cfb_free_screen(void *v, void *cookie)
463{
464	struct cfb_softc *sc = v;
465
466	if (sc->sc_ri == &cfb_console_ri)
467		panic("cfb_free_screen: console");
468
469	sc->nscreens--;
470}
471
472static int
473cfb_show_screen(void *v, void *cookie, int waitok,
474    void (*cb)(void *, int, int), void *cbarg)
475{
476
477	return (0);
478}
479
480/* EXPORT */ int
481cfb_cnattach(tc_addr_t addr)
482{
483	struct rasops_info *ri;
484	long defattr;
485
486	ri = &cfb_console_ri;
487	ri->ri_hw = (void *)addr;
488	cfb_common_init(ri);
489	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
490	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
491	cfb_consaddr = addr;
492	return(0);
493}
494
495static int
496cfbintr(void *arg)
497{
498	struct cfb_softc *sc = arg;
499	char *base, *vdac;
500	int v;
501
502	base = (void *)sc->sc_ri->ri_hw;
503	*(uint8_t *)(base + CX_OFFSET_IREQ) = 0;
504	if (sc->sc_changed == 0)
505		return (1);
506
507	vdac = base + CX_BT459_OFFSET;
508	v = sc->sc_changed;
509	if (v & WSDISPLAY_CURSOR_DOCUR) {
510		VDACSELECT(vdac, BT459_IREG_CCR);
511		REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
512	}
513	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
514		int x, y;
515
516		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
517		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
518
519		x += sc->sc_cursor.cc_magic.x;
520		y += sc->sc_cursor.cc_magic.y;
521
522		VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
523		REGWRITE32(vdac, bt_reg, x);
524		REGWRITE32(vdac, bt_reg, x >> 8);
525		REGWRITE32(vdac, bt_reg, y);
526		REGWRITE32(vdac, bt_reg, y >> 8);
527	}
528	if (v & WSDISPLAY_CURSOR_DOCMAP) {
529		uint8_t *cp = sc->sc_cursor.cc_color;
530
531		VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
532		REGWRITE32(vdac, bt_reg, cp[1]);
533		REGWRITE32(vdac, bt_reg, cp[3]);
534		REGWRITE32(vdac, bt_reg, cp[5]);
535
536		REGWRITE32(vdac, bt_reg, cp[0]);
537		REGWRITE32(vdac, bt_reg, cp[2]);
538		REGWRITE32(vdac, bt_reg, cp[4]);
539	}
540	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
541		uint8_t *ip, *mp, img, msk;
542		uint8_t u;
543		int bcnt;
544
545		ip = (uint8_t *)sc->sc_cursor.cc_image;
546		mp = (uint8_t *)sc->sc_cursor.cc_mask;
547
548		bcnt = 0;
549		VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
550		/* 64 pixel scan line is consisted with 16 byte cursor ram */
551		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
552			/* pad right half 32 pixel when smaller than 33 */
553			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
554				REGWRITE32(vdac, bt_reg, 0);
555				REGWRITE32(vdac, bt_reg, 0);
556			}
557			else {
558				img = *ip++;
559				msk = *mp++;
560				img &= msk;	/* cookie off image */
561				u = (msk & 0x0f) << 4 | (img & 0x0f);
562				REGWRITE32(vdac, bt_reg, shuffle[u]);
563				u = (msk & 0xf0) | (img & 0xf0) >> 4;
564				REGWRITE32(vdac, bt_reg, shuffle[u]);
565			}
566			bcnt += 2;
567		}
568		/* pad unoccupied scan lines */
569		while (bcnt < CURSOR_MAX_SIZE * 16) {
570			REGWRITE32(vdac, bt_reg, 0);
571			REGWRITE32(vdac, bt_reg, 0);
572			bcnt += 2;
573		}
574	}
575	if (v & WSDISPLAY_CMAP_DOLUT) {
576		struct hwcmap256 *cm = &sc->sc_cmap;
577		int index;
578
579		VDACSELECT(vdac, 0);
580		for (index = 0; index < CMAP_SIZE; index++) {
581			REGWRITE32(vdac, bt_cmap, cm->r[index]);
582			REGWRITE32(vdac, bt_cmap, cm->g[index]);
583			REGWRITE32(vdac, bt_cmap, cm->b[index]);
584		}
585	}
586	sc->sc_changed = 0;
587	return (1);
588}
589
590static void
591cfbhwinit(void *cfbbase)
592{
593	char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
594	const uint8_t *p;
595	int i;
596
597	VDACSELECT(vdac, BT459_IREG_COMMAND_0);
598	REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
599	REGWRITE32(vdac, bt_reg, 0x0);  /* CMD1 */
600	REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
601	REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
602	REGWRITE32(vdac, bt_reg, 0);    /* 205 */
603	REGWRITE32(vdac, bt_reg, 0x0);  /* PBM */
604	REGWRITE32(vdac, bt_reg, 0);    /* 207 */
605	REGWRITE32(vdac, bt_reg, 0x0);  /* ORM */
606	REGWRITE32(vdac, bt_reg, 0x0);  /* OBM */
607	REGWRITE32(vdac, bt_reg, 0x0);  /* ILV */
608	REGWRITE32(vdac, bt_reg, 0x0);  /* TEST */
609
610	VDACSELECT(vdac, BT459_IREG_CCR);
611	REGWRITE32(vdac, bt_reg, 0x0);
612	REGWRITE32(vdac, bt_reg, 0x0);
613	REGWRITE32(vdac, bt_reg, 0x0);
614	REGWRITE32(vdac, bt_reg, 0x0);
615	REGWRITE32(vdac, bt_reg, 0x0);
616	REGWRITE32(vdac, bt_reg, 0x0);
617	REGWRITE32(vdac, bt_reg, 0x0);
618	REGWRITE32(vdac, bt_reg, 0x0);
619	REGWRITE32(vdac, bt_reg, 0x0);
620	REGWRITE32(vdac, bt_reg, 0x0);
621	REGWRITE32(vdac, bt_reg, 0x0);
622	REGWRITE32(vdac, bt_reg, 0x0);
623	REGWRITE32(vdac, bt_reg, 0x0);
624
625	/* build sane colormap */
626	VDACSELECT(vdac, 0);
627	p = rasops_cmap;
628	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
629		REGWRITE32(vdac, bt_cmap, p[0]);
630		REGWRITE32(vdac, bt_cmap, p[1]);
631		REGWRITE32(vdac, bt_cmap, p[2]);
632	}
633
634	/* clear out cursor image */
635	VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
636	for (i = 0; i < 1024; i++)
637		REGWRITE32(vdac, bt_reg, 0xff);
638
639	/*
640	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
641	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
642	 * image color.  CCOLOR_1 will be never used.
643	 */
644	VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
645	REGWRITE32(vdac, bt_reg, 0xff);
646	REGWRITE32(vdac, bt_reg, 0xff);
647	REGWRITE32(vdac, bt_reg, 0xff);
648
649	REGWRITE32(vdac, bt_reg, 0);
650	REGWRITE32(vdac, bt_reg, 0);
651	REGWRITE32(vdac, bt_reg, 0);
652
653	REGWRITE32(vdac, bt_reg, 0xff);
654	REGWRITE32(vdac, bt_reg, 0xff);
655	REGWRITE32(vdac, bt_reg, 0xff);
656}
657
658static int
659get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
660{
661	u_int index = p->index, count = p->count;
662	int error;
663
664	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
665		return (EINVAL);
666
667	error = copyout(&sc->sc_cmap.r[index], p->red, count);
668	if (error)
669		return error;
670	error = copyout(&sc->sc_cmap.g[index], p->green, count);
671	if (error)
672		return error;
673	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
674	return error;
675}
676
677static int
678set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
679{
680	struct hwcmap256 cmap;
681	u_int index = p->index, count = p->count;
682	int error, s;
683
684	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
685		return (EINVAL);
686
687	error = copyin(p->red, &cmap.r[index], count);
688	if (error)
689		return error;
690	error = copyin(p->green, &cmap.g[index], count);
691	if (error)
692		return error;
693	error = copyin(p->blue, &cmap.b[index], count);
694	if (error)
695		return error;
696	s = spltty();
697	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
698	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
699	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
700	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
701	splx(s);
702	return (0);
703}
704
705static int
706set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
707{
708#define	cc (&sc->sc_cursor)
709	u_int v, index = 0, count = 0, icount = 0;
710	uint8_t r[2], g[2], b[2], image[512], mask[512];
711	int error, s;
712
713	v = p->which;
714	if (v & WSDISPLAY_CURSOR_DOCMAP) {
715		index = p->cmap.index;
716		count = p->cmap.count;
717		if (index >= 2 || count > 2 - index)
718			return (EINVAL);
719		error = copyin(p->cmap.red, &r[index], count);
720		if (error)
721			return error;
722		error = copyin(p->cmap.green, &g[index], count);
723		if (error)
724			return error;
725		error = copyin(p->cmap.blue, &b[index], count);
726		if (error)
727			return error;
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		error = copyin(p->image, image, icount);
734		if (error)
735			return error;
736		error = copyin(p->mask, mask, icount);
737		if (error)
738			return error;
739	}
740
741	s = spltty();
742	if (v & WSDISPLAY_CURSOR_DOCUR)
743		sc->sc_curenb = p->enable;
744	if (v & WSDISPLAY_CURSOR_DOPOS)
745		set_curpos(sc, &p->pos);
746	if (v & WSDISPLAY_CURSOR_DOHOT)
747		cc->cc_hot = p->hot;
748	if (v & WSDISPLAY_CURSOR_DOCMAP) {
749		memcpy(&cc->cc_color[index], &r[index], count);
750		memcpy(&cc->cc_color[index + 2], &g[index], count);
751		memcpy(&cc->cc_color[index + 4], &b[index], count);
752	}
753	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
754		cc->cc_size = p->size;
755		memset(cc->cc_image, 0, sizeof cc->cc_image);
756		memcpy(cc->cc_image, image, icount);
757		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
758		memcpy(cc->cc_mask, mask, icount);
759	}
760	sc->sc_changed |= v;
761	splx(s);
762
763	return (0);
764#undef cc
765}
766
767static int
768get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
769{
770	return (EPASSTHROUGH); /* XXX */
771}
772
773static void
774set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
775{
776	struct rasops_info *ri = sc->sc_ri;
777	int x = curpos->x, y = curpos->y;
778
779	if (y < 0)
780		y = 0;
781	else if (y > ri->ri_height)
782		y = ri->ri_height;
783	if (x < 0)
784		x = 0;
785	else if (x > ri->ri_width)
786		x = ri->ri_width;
787	sc->sc_cursor.cc_pos.x = x;
788	sc->sc_cursor.cc_pos.y = y;
789}
790