1 /* $NetBSD: cfb.c,v 1.61 2012/01/11 21:12:36 macallan 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.61 2012/01/11 21:12:36 macallan 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 
98 struct 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 
105 struct 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 
116 struct 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 
137 static int  cfbmatch(device_t, cfdata_t, void *);
138 static void cfbattach(device_t, device_t, void *);
139 
140 CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc),
141     cfbmatch, cfbattach, NULL, NULL);
142 
143 static void cfb_common_init(struct rasops_info *);
144 static struct rasops_info cfb_console_ri;
145 static tc_addr_t cfb_consaddr;
146 
147 static struct wsscreen_descr cfb_stdscreen = {
148 	"std", 0, 0,
149 	0, /* textops */
150 	0, 0,
151 	WSSCREEN_REVERSE
152 };
153 
154 static const struct wsscreen_descr *_cfb_scrlist[] = {
155 	&cfb_stdscreen,
156 };
157 
158 static const struct wsscreen_list cfb_screenlist = {
159 	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
160 };
161 
162 static int	cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
163 static paddr_t	cfbmmap(void *, void *, off_t, int);
164 
165 static int	cfb_alloc_screen(void *, const struct wsscreen_descr *,
166 				      void **, int *, int *, long *);
167 static void	cfb_free_screen(void *, void *);
168 static int	cfb_show_screen(void *, void *, int,
169 				     void (*) (void *, int, int), void *);
170 
171 static 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 
180 int  cfb_cnattach(tc_addr_t);
181 static int  cfbintr(void *);
182 static void cfbhwinit(void *);
183 static void cfb_cmap_init(struct cfb_softc *);
184 
185 static int  get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
186 static int  set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
187 static int  set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
188 static int  get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
189 static 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  */
198 static 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 
233 static int
cfbmatch(device_t parent,cfdata_t match,void * aux)234 cfbmatch(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 
244 static void
cfbattach(device_t parent,device_t self,void * aux)245 cfbattach(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_NOWAIT|M_ZERO);
262 		if (ri == NULL) {
263 			printf(": can't alloc memory\n");
264 			return;
265 		}
266 
267 		ri->ri_hw = (void *)ta->ta_addr;
268 		cfb_common_init(ri);
269 		sc->sc_ri = ri;
270 	}
271 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
272 
273 	cfb_cmap_init(sc);
274 
275 	sc->sc_vaddr = ta->ta_addr;
276 	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
277 	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
278 	sc->sc_blanked = sc->sc_curenb = 0;
279 
280 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
281 
282 	/* clear any pending interrupts */
283 	*(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
284 
285 	waa.console = console;
286 	waa.scrdata = &cfb_screenlist;
287 	waa.accessops = &cfb_accessops;
288 	waa.accesscookie = sc;
289 
290 	config_found(self, &waa, wsemuldisplaydevprint);
291 }
292 
293 static void
cfb_cmap_init(struct cfb_softc * sc)294 cfb_cmap_init(struct cfb_softc *sc)
295 {
296 	struct hwcmap256 *cm;
297 	const uint8_t *p;
298 	int index;
299 
300 	cm = &sc->sc_cmap;
301 	p = rasops_cmap;
302 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
303 		cm->r[index] = p[0];
304 		cm->g[index] = p[1];
305 		cm->b[index] = p[2];
306 	}
307 }
308 
309 static void
cfb_common_init(struct rasops_info * ri)310 cfb_common_init(struct rasops_info *ri)
311 {
312 	char *base;
313 	int cookie;
314 
315 	base = (void *)ri->ri_hw;
316 
317 	/* initialize colormap and cursor hardware */
318 	cfbhwinit(base);
319 
320 	ri->ri_flg = RI_CENTER;
321 	if (ri == &cfb_console_ri)
322 		ri->ri_flg |= RI_NO_AUTO;
323 	ri->ri_depth = 8;
324 	ri->ri_width = 1024;
325 	ri->ri_height = 864;
326 	ri->ri_stride = 1024;
327 	ri->ri_bits = base + CX_FB_OFFSET;
328 
329 	/* clear the screen */
330 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
331 
332 	wsfont_init();
333 	/* prefer 12 pixel wide font */
334 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
335 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
336 	if (cookie <= 0)
337 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
338 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
339 	if (cookie <= 0) {
340 		printf("cfb: font table is empty\n");
341 		return;
342 	}
343 
344 	if (wsfont_lock(cookie, &ri->ri_font)) {
345 		printf("cfb: couldn't lock font\n");
346 		return;
347 	}
348 	ri->ri_wsfcookie = cookie;
349 
350 	rasops_init(ri, 34, 80);
351 
352 	/* XXX shouldn't be global */
353 	cfb_stdscreen.nrows = ri->ri_rows;
354 	cfb_stdscreen.ncols = ri->ri_cols;
355 	cfb_stdscreen.textops = &ri->ri_ops;
356 	cfb_stdscreen.capabilities = ri->ri_caps;
357 }
358 
359 static int
cfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)360 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
361 {
362 	struct cfb_softc *sc = v;
363 	struct rasops_info *ri = sc->sc_ri;
364 	int turnoff, s;
365 
366 	switch (cmd) {
367 	case WSDISPLAYIO_GTYPE:
368 		*(u_int *)data = WSDISPLAY_TYPE_CFB;
369 		return (0);
370 
371 	case WSDISPLAYIO_GINFO:
372 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
373 		wsd_fbip->height = ri->ri_height;
374 		wsd_fbip->width = ri->ri_width;
375 		wsd_fbip->depth = ri->ri_depth;
376 		wsd_fbip->cmsize = CMAP_SIZE;
377 #undef fbt
378 		return (0);
379 
380 	case WSDISPLAYIO_GETCMAP:
381 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
382 
383 	case WSDISPLAYIO_PUTCMAP:
384 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
385 
386 	case WSDISPLAYIO_SVIDEO:
387 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
388 		if (sc->sc_blanked != turnoff) {
389 			sc->sc_blanked = turnoff;
390 			/* XXX later XXX */
391 		}
392 		return (0);
393 
394 	case WSDISPLAYIO_GVIDEO:
395 		*(u_int *)data = sc->sc_blanked ?
396 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
397 		return (0);
398 
399 	case WSDISPLAYIO_GCURPOS:
400 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
401 		return (0);
402 
403 	case WSDISPLAYIO_SCURPOS:
404 		s = spltty();
405 		set_curpos(sc, (struct wsdisplay_curpos *)data);
406 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
407 		splx(s);
408 		return (0);
409 
410 	case WSDISPLAYIO_GCURMAX:
411 		((struct wsdisplay_curpos *)data)->x =
412 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
413 		return (0);
414 
415 	case WSDISPLAYIO_GCURSOR:
416 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
417 
418 	case WSDISPLAYIO_SCURSOR:
419 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
420 
421 	case WSDISPLAYIO_SMODE:
422 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
423 			s = spltty();
424 			cfb_cmap_init(sc);
425 			sc->sc_curenb = 0;
426 			sc->sc_blanked = 0;
427 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
428 			    WSDISPLAY_CMAP_DOLUT);
429 			splx(s);
430 		}
431 		return (0);
432 	}
433 	return EPASSTHROUGH;
434 }
435 
436 paddr_t
cfbmmap(void * v,void * vs,off_t offset,int prot)437 cfbmmap(void *v, void *vs, off_t offset, int prot)
438 {
439 	struct cfb_softc *sc = v;
440 
441 	if (offset >= CX_FB_SIZE || offset < 0)
442 		return (-1);
443 	return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
444 }
445 
446 static int
cfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)447 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
448     int *curxp, int *curyp, long *attrp)
449 {
450 	struct cfb_softc *sc = v;
451 	struct rasops_info *ri = sc->sc_ri;
452 	long defattr;
453 
454 	if (sc->nscreens > 0)
455 		return (ENOMEM);
456 
457 	*cookiep = ri;	 /* one and only for now */
458 	*curxp = 0;
459 	*curyp = 0;
460 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
461 	*attrp = defattr;
462 	sc->nscreens++;
463 	return (0);
464 }
465 
466 static void
cfb_free_screen(void * v,void * cookie)467 cfb_free_screen(void *v, void *cookie)
468 {
469 	struct cfb_softc *sc = v;
470 
471 	if (sc->sc_ri == &cfb_console_ri)
472 		panic("cfb_free_screen: console");
473 
474 	sc->nscreens--;
475 }
476 
477 static int
cfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)478 cfb_show_screen(void *v, void *cookie, int waitok,
479     void (*cb)(void *, int, int), void *cbarg)
480 {
481 
482 	return (0);
483 }
484 
485 /* EXPORT */ int
cfb_cnattach(tc_addr_t addr)486 cfb_cnattach(tc_addr_t addr)
487 {
488 	struct rasops_info *ri;
489 	long defattr;
490 
491 	ri = &cfb_console_ri;
492 	ri->ri_hw = (void *)addr;
493 	cfb_common_init(ri);
494 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
495 	wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
496 	cfb_consaddr = addr;
497 	return(0);
498 }
499 
500 static int
cfbintr(void * arg)501 cfbintr(void *arg)
502 {
503 	struct cfb_softc *sc = arg;
504 	char *base, *vdac;
505 	int v;
506 
507 	base = (void *)sc->sc_ri->ri_hw;
508 	*(uint8_t *)(base + CX_OFFSET_IREQ) = 0;
509 	if (sc->sc_changed == 0)
510 		return (1);
511 
512 	vdac = base + CX_BT459_OFFSET;
513 	v = sc->sc_changed;
514 	if (v & WSDISPLAY_CURSOR_DOCUR) {
515 		VDACSELECT(vdac, BT459_IREG_CCR);
516 		REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
517 	}
518 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
519 		int x, y;
520 
521 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
522 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
523 
524 		x += sc->sc_cursor.cc_magic.x;
525 		y += sc->sc_cursor.cc_magic.y;
526 
527 		VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
528 		REGWRITE32(vdac, bt_reg, x);
529 		REGWRITE32(vdac, bt_reg, x >> 8);
530 		REGWRITE32(vdac, bt_reg, y);
531 		REGWRITE32(vdac, bt_reg, y >> 8);
532 	}
533 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
534 		uint8_t *cp = sc->sc_cursor.cc_color;
535 
536 		VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
537 		REGWRITE32(vdac, bt_reg, cp[1]);
538 		REGWRITE32(vdac, bt_reg, cp[3]);
539 		REGWRITE32(vdac, bt_reg, cp[5]);
540 
541 		REGWRITE32(vdac, bt_reg, cp[0]);
542 		REGWRITE32(vdac, bt_reg, cp[2]);
543 		REGWRITE32(vdac, bt_reg, cp[4]);
544 	}
545 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
546 		uint8_t *ip, *mp, img, msk;
547 		uint8_t u;
548 		int bcnt;
549 
550 		ip = (uint8_t *)sc->sc_cursor.cc_image;
551 		mp = (uint8_t *)sc->sc_cursor.cc_mask;
552 
553 		bcnt = 0;
554 		VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
555 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
556 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
557 			/* pad right half 32 pixel when smaller than 33 */
558 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
559 				REGWRITE32(vdac, bt_reg, 0);
560 				REGWRITE32(vdac, bt_reg, 0);
561 			}
562 			else {
563 				img = *ip++;
564 				msk = *mp++;
565 				img &= msk;	/* cookie off image */
566 				u = (msk & 0x0f) << 4 | (img & 0x0f);
567 				REGWRITE32(vdac, bt_reg, shuffle[u]);
568 				u = (msk & 0xf0) | (img & 0xf0) >> 4;
569 				REGWRITE32(vdac, bt_reg, shuffle[u]);
570 			}
571 			bcnt += 2;
572 		}
573 		/* pad unoccupied scan lines */
574 		while (bcnt < CURSOR_MAX_SIZE * 16) {
575 			REGWRITE32(vdac, bt_reg, 0);
576 			REGWRITE32(vdac, bt_reg, 0);
577 			bcnt += 2;
578 		}
579 	}
580 	if (v & WSDISPLAY_CMAP_DOLUT) {
581 		struct hwcmap256 *cm = &sc->sc_cmap;
582 		int index;
583 
584 		VDACSELECT(vdac, 0);
585 		for (index = 0; index < CMAP_SIZE; index++) {
586 			REGWRITE32(vdac, bt_cmap, cm->r[index]);
587 			REGWRITE32(vdac, bt_cmap, cm->g[index]);
588 			REGWRITE32(vdac, bt_cmap, cm->b[index]);
589 		}
590 	}
591 	sc->sc_changed = 0;
592 	return (1);
593 }
594 
595 static void
cfbhwinit(void * cfbbase)596 cfbhwinit(void *cfbbase)
597 {
598 	char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
599 	const uint8_t *p;
600 	int i;
601 
602 	VDACSELECT(vdac, BT459_IREG_COMMAND_0);
603 	REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
604 	REGWRITE32(vdac, bt_reg, 0x0);  /* CMD1 */
605 	REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
606 	REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
607 	REGWRITE32(vdac, bt_reg, 0);    /* 205 */
608 	REGWRITE32(vdac, bt_reg, 0x0);  /* PBM */
609 	REGWRITE32(vdac, bt_reg, 0);    /* 207 */
610 	REGWRITE32(vdac, bt_reg, 0x0);  /* ORM */
611 	REGWRITE32(vdac, bt_reg, 0x0);  /* OBM */
612 	REGWRITE32(vdac, bt_reg, 0x0);  /* ILV */
613 	REGWRITE32(vdac, bt_reg, 0x0);  /* TEST */
614 
615 	VDACSELECT(vdac, BT459_IREG_CCR);
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 	REGWRITE32(vdac, bt_reg, 0x0);
625 	REGWRITE32(vdac, bt_reg, 0x0);
626 	REGWRITE32(vdac, bt_reg, 0x0);
627 	REGWRITE32(vdac, bt_reg, 0x0);
628 	REGWRITE32(vdac, bt_reg, 0x0);
629 
630 	/* build sane colormap */
631 	VDACSELECT(vdac, 0);
632 	p = rasops_cmap;
633 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
634 		REGWRITE32(vdac, bt_cmap, p[0]);
635 		REGWRITE32(vdac, bt_cmap, p[1]);
636 		REGWRITE32(vdac, bt_cmap, p[2]);
637 	}
638 
639 	/* clear out cursor image */
640 	VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
641 	for (i = 0; i < 1024; i++)
642 		REGWRITE32(vdac, bt_reg, 0xff);
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 	VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
650 	REGWRITE32(vdac, bt_reg, 0xff);
651 	REGWRITE32(vdac, bt_reg, 0xff);
652 	REGWRITE32(vdac, bt_reg, 0xff);
653 
654 	REGWRITE32(vdac, bt_reg, 0);
655 	REGWRITE32(vdac, bt_reg, 0);
656 	REGWRITE32(vdac, bt_reg, 0);
657 
658 	REGWRITE32(vdac, bt_reg, 0xff);
659 	REGWRITE32(vdac, bt_reg, 0xff);
660 	REGWRITE32(vdac, bt_reg, 0xff);
661 }
662 
663 static int
get_cmap(struct cfb_softc * sc,struct wsdisplay_cmap * p)664 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
665 {
666 	u_int index = p->index, count = p->count;
667 	int error;
668 
669 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
670 		return (EINVAL);
671 
672 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
673 	if (error)
674 		return error;
675 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
676 	if (error)
677 		return error;
678 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
679 	return error;
680 }
681 
682 static int
set_cmap(struct cfb_softc * sc,struct wsdisplay_cmap * p)683 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
684 {
685 	struct hwcmap256 cmap;
686 	u_int index = p->index, count = p->count;
687 	int error, s;
688 
689 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
690 		return (EINVAL);
691 
692 	error = copyin(p->red, &cmap.r[index], count);
693 	if (error)
694 		return error;
695 	error = copyin(p->green, &cmap.g[index], count);
696 	if (error)
697 		return error;
698 	error = copyin(p->blue, &cmap.b[index], count);
699 	if (error)
700 		return error;
701 	s = spltty();
702 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
703 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
704 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
705 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
706 	splx(s);
707 	return (0);
708 }
709 
710 static int
set_cursor(struct cfb_softc * sc,struct wsdisplay_cursor * p)711 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
712 {
713 #define	cc (&sc->sc_cursor)
714 	u_int v, index = 0, count = 0, icount = 0;
715 	uint8_t r[2], g[2], b[2], image[512], mask[512];
716 	int error, s;
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 		error = copyin(p->cmap.red, &r[index], count);
725 		if (error)
726 			return error;
727 		error = copyin(p->cmap.green, &g[index], count);
728 		if (error)
729 			return error;
730 		error = copyin(p->cmap.blue, &b[index], count);
731 		if (error)
732 			return error;
733 	}
734 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
735 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
736 			return (EINVAL);
737 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
738 		error = copyin(p->image, image, icount);
739 		if (error)
740 			return error;
741 		error = copyin(p->mask, mask, icount);
742 		if (error)
743 			return error;
744 	}
745 
746 	s = spltty();
747 	if (v & WSDISPLAY_CURSOR_DOCUR)
748 		sc->sc_curenb = p->enable;
749 	if (v & WSDISPLAY_CURSOR_DOPOS)
750 		set_curpos(sc, &p->pos);
751 	if (v & WSDISPLAY_CURSOR_DOHOT)
752 		cc->cc_hot = p->hot;
753 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
754 		memcpy(&cc->cc_color[index], &r[index], count);
755 		memcpy(&cc->cc_color[index + 2], &g[index], count);
756 		memcpy(&cc->cc_color[index + 4], &b[index], count);
757 	}
758 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
759 		cc->cc_size = p->size;
760 		memset(cc->cc_image, 0, sizeof cc->cc_image);
761 		memcpy(cc->cc_image, image, icount);
762 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
763 		memcpy(cc->cc_mask, mask, icount);
764 	}
765 	sc->sc_changed |= v;
766 	splx(s);
767 
768 	return (0);
769 #undef cc
770 }
771 
772 static int
get_cursor(struct cfb_softc * sc,struct wsdisplay_cursor * p)773 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
774 {
775 	return (EPASSTHROUGH); /* XXX */
776 }
777 
778 static void
set_curpos(struct cfb_softc * sc,struct wsdisplay_curpos * curpos)779 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
780 {
781 	struct rasops_info *ri = sc->sc_ri;
782 	int x = curpos->x, y = curpos->y;
783 
784 	if (y < 0)
785 		y = 0;
786 	else if (y > ri->ri_height)
787 		y = ri->ri_height;
788 	if (x < 0)
789 		x = 0;
790 	else if (x > ri->ri_width)
791 		x = ri->ri_width;
792 	sc->sc_cursor.cc_pos.x = x;
793 	sc->sc_cursor.cc_pos.y = y;
794 }
795