xref: /netbsd-src/sys/dev/tc/xcfb.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /* $NetBSD: xcfb.c,v 1.55 2012/01/11 21:12:37 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: xcfb.c,v 1.55 2012/01/11 21:12:37 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/tc/ioasicreg.h>
54 #include <dev/ic/ims332reg.h>
55 #include <pmax/pmax/maxine.h>
56 
57 struct hwcmap256 {
58 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
59 	uint8_t r[CMAP_SIZE];
60 	uint8_t g[CMAP_SIZE];
61 	uint8_t b[CMAP_SIZE];
62 };
63 
64 struct hwcursor64 {
65 	struct wsdisplay_curpos cc_pos;
66 	struct wsdisplay_curpos cc_hot;
67 	struct wsdisplay_curpos cc_size;
68 	struct wsdisplay_curpos cc_magic;	/* not used by PMAG-DV */
69 #define	CURSOR_MAX_SIZE	64
70 	uint8_t cc_color[6];
71 	uint64_t cc_image[CURSOR_MAX_SIZE];
72 	uint64_t cc_mask[CURSOR_MAX_SIZE];
73 };
74 
75 #define	XCFB_FB_BASE	(XINE_PHYS_CFB_START + 0x2000000)
76 #define	XCFB_FB_SIZE	0x100000
77 
78 #define	IMS332_HIGH	(IOASIC_SLOT_5_START)
79 #define	IMS332_RLOW	(IOASIC_SLOT_7_START)
80 #define	IMS332_WLOW	(IOASIC_SLOT_7_START + 0x20000)
81 
82 struct xcfb_softc {
83 	vaddr_t sc_vaddr;
84 	size_t sc_size;
85 	struct rasops_info *sc_ri;
86 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
87 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
88 	int sc_blanked;
89 	/* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
90 	int nscreens;
91 	/* cursor coordinate is located at upper-left corner */
92 	int sc_csr;			/* software copy of IMS332 CSR A */
93 };
94 
95 static int  xcfbmatch(device_t, cfdata_t, void *);
96 static void xcfbattach(device_t, device_t, void *);
97 
98 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
99     xcfbmatch, xcfbattach, NULL, NULL);
100 
101 static tc_addr_t xcfb_consaddr;
102 static struct rasops_info xcfb_console_ri;
103 static void xcfb_common_init(struct rasops_info *);
104 static void xcfbhwinit(void *);
105 int xcfb_cnattach(void);
106 
107 struct wsscreen_descr xcfb_stdscreen = {
108 	"std", 0, 0,
109 	0, /* textops */
110 	0, 0,
111 	WSSCREEN_REVERSE
112 };
113 
114 static const struct wsscreen_descr *_xcfb_scrlist[] = {
115 	&xcfb_stdscreen,
116 };
117 
118 static const struct wsscreen_list xcfb_screenlist = {
119 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
120 };
121 
122 static int	xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
123 static paddr_t	xcfbmmap(void *, void *, off_t, int);
124 
125 static int	xcfb_alloc_screen(void *, const struct wsscreen_descr *,
126 				       void **, int *, int *, long *);
127 static void	xcfb_free_screen(void *, void *);
128 static int	xcfb_show_screen(void *, void *, int,
129 				      void (*) (void *, int, int), void *);
130 
131 static const struct wsdisplay_accessops xcfb_accessops = {
132 	xcfbioctl,
133 	xcfbmmap,
134 	xcfb_alloc_screen,
135 	xcfb_free_screen,
136 	xcfb_show_screen,
137 	0 /* load_font */
138 };
139 
140 static int  xcfbintr(void *);
141 static void xcfb_screenblank(struct xcfb_softc *);
142 static void xcfb_cmap_init(struct xcfb_softc *);
143 static int  set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
144 static int  get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
145 static int  set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
146 static int  get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
147 static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
148 static void ims332_loadcmap(struct hwcmap256 *);
149 static void ims332_set_curpos(struct xcfb_softc *);
150 static void ims332_load_curcmap(struct xcfb_softc *);
151 static void ims332_load_curshape(struct xcfb_softc *);
152 static void ims332_write_reg(int, uint32_t);
153 #if 0
154 static uint32_t ims332_read_reg(int);
155 #endif
156 
157 extern long ioasic_base;	/* XXX */
158 
159 /*
160  * Compose 2 bit/pixel cursor image.
161  *   M M M M I I I I		M I M I M I M I
162  *	[ before ]		   [ after ]
163  *   3 2 1 0 3 2 1 0		3 3 2 2 1 1 0 0
164  *   7 6 5 4 7 6 5 4		7 7 6 6 5 5 4 4
165  */
166 static const uint8_t shuffle[256] = {
167 	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
168 	0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
169 	0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
170 	0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
171 	0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
172 	0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
173 	0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
174 	0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
175 	0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
176 	0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
177 	0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
178 	0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
179 	0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
180 	0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
181 	0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
182 	0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
183 	0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
184 	0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
185 	0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
186 	0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
187 	0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
188 	0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
189 	0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
190 	0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
191 	0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
192 	0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
193 	0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
194 	0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
195 	0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
196 	0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
197 	0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
198 	0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
199 };
200 
201 static int
202 xcfbmatch(device_t parent, cfdata_t match, void *aux)
203 {
204 	struct tc_attach_args *ta = aux;
205 
206 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
207 		return (0);
208 
209 	return (1);
210 }
211 
212 static void
213 xcfbattach(device_t parent, device_t self, void *aux)
214 {
215 	struct xcfb_softc *sc = device_private(self);
216 	struct tc_attach_args *ta = aux;
217 	struct rasops_info *ri;
218 	struct wsemuldisplaydev_attach_args waa;
219 	int console;
220 
221 	console = (ta->ta_addr == xcfb_consaddr);
222 	if (console) {
223 		sc->sc_ri = ri = &xcfb_console_ri;
224 		ri->ri_flg &= ~RI_NO_AUTO;
225 		sc->nscreens = 1;
226 	}
227 	else {
228 		ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT);
229 		if (ri == NULL) {
230 			printf(": can't alloc memory\n");
231 			return;
232 		}
233 		memset(ri, 0, sizeof(struct rasops_info));
234 
235 		ri->ri_hw = (void *)ioasic_base;
236 		xcfb_common_init(ri);
237 		sc->sc_ri = ri;
238 	}
239 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
240 
241 	xcfb_cmap_init(sc);
242 
243 	sc->sc_vaddr = ta->ta_addr;
244 	sc->sc_blanked = 0;
245 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
246 
247         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
248 
249 	waa.console = console;
250 	waa.scrdata = &xcfb_screenlist;
251 	waa.accessops = &xcfb_accessops;
252 	waa.accesscookie = sc;
253 
254 	config_found(self, &waa, wsemuldisplaydevprint);
255 }
256 
257 static void
258 xcfb_cmap_init(struct xcfb_softc *sc)
259 {
260 	struct hwcmap256 *cm;
261 	const uint8_t *p;
262 	int index;
263 
264 	cm = &sc->sc_cmap;
265 	p = rasops_cmap;
266 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
267 		cm->r[index] = p[0];
268 		cm->g[index] = p[1];
269 		cm->b[index] = p[2];
270 	}
271 }
272 
273 static void
274 xcfb_common_init(struct rasops_info *ri)
275 {
276 	int cookie;
277 
278 	/* initialize colormap and cursor hardware */
279 	xcfbhwinit((void *)ri->ri_hw);
280 
281 	ri->ri_flg = RI_CENTER;
282 	if (ri == &xcfb_console_ri)
283 		ri->ri_flg |= RI_NO_AUTO;
284 	ri->ri_depth = 8;
285 	ri->ri_width = 1024;
286 	ri->ri_height = 768;
287 	ri->ri_stride = 1024;
288 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
289 
290 	/* clear the screen */
291 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
292 
293 	wsfont_init();
294 	/* prefer 12 pixel wide font */
295 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
296 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
297 	if (cookie <= 0)
298 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
299 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
300 	if (cookie <= 0) {
301 		printf("xcfb: font table is empty\n");
302 		return;
303 	}
304 
305 	if (wsfont_lock(cookie, &ri->ri_font)) {
306 		printf("xcfb: couldn't lock font\n");
307 		return;
308 	}
309 	ri->ri_wsfcookie = cookie;
310 
311 	rasops_init(ri, 34, 80);
312 
313 	/* XXX shouldn't be global */
314 	xcfb_stdscreen.nrows = ri->ri_rows;
315 	xcfb_stdscreen.ncols = ri->ri_cols;
316 	xcfb_stdscreen.textops = &ri->ri_ops;
317 	xcfb_stdscreen.capabilities = ri->ri_caps;
318 }
319 
320 int
321 xcfb_cnattach(void)
322 {
323 	struct rasops_info *ri;
324 	long defattr;
325 
326 	ri = &xcfb_console_ri;
327 	ri->ri_hw = (void *)ioasic_base;
328 	xcfb_common_init(ri);
329 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
330 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
331 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
332 	return (0);
333 }
334 
335 static void
336 xcfbhwinit(void *base)
337 {
338 	volatile uint32_t *csr;
339 	uint32_t i;
340 	const uint8_t *p;
341 
342 	csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
343 	i = *csr;
344 	i &= ~XINE_CSR_VDAC_ENABLE;
345 	*csr = i;
346 	DELAY(50);
347 	i |= XINE_CSR_VDAC_ENABLE;
348 	*csr = i;
349 	DELAY(50);
350 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
351 	ims332_write_reg(IMS332_REG_CSR_A,
352 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
353 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
354 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
355 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
356 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
357 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
358 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
359 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
360 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
361 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
362 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
363 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
364 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
365 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
366 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
367 	ims332_write_reg(IMS332_REG_CSR_A,
368 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
369 
370 	/* build sane colormap */
371 	p = rasops_cmap;
372 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
373 		uint32_t bgr;
374 
375 		bgr = p[2] << 16 | p[1] << 8 | p[0];
376 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
377 	}
378 
379 	/* clear out cursor image */
380 	for (i = 0; i < 512; i++)
381 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
382 
383 	/*
384 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
385 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
386 	 * image color.  LUT_0 will be never used.
387 	 */
388 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
389 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
390 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
391 }
392 
393 static int
394 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
395 {
396 	struct xcfb_softc *sc = v;
397 	struct rasops_info *ri = sc->sc_ri;
398 	int turnoff, error;
399 
400 	switch (cmd) {
401 	case WSDISPLAYIO_GTYPE:
402 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
403 		return (0);
404 
405 	case WSDISPLAYIO_GINFO:
406 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
407 		wsd_fbip->height = ri->ri_height;
408 		wsd_fbip->width = ri->ri_width;
409 		wsd_fbip->depth = ri->ri_depth;
410 		wsd_fbip->cmsize = CMAP_SIZE;
411 #undef fbt
412 		return (0);
413 
414 	case WSDISPLAYIO_GETCMAP:
415 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
416 
417 	case WSDISPLAYIO_PUTCMAP:
418 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
419 		if (error == 0)
420 			ims332_loadcmap(&sc->sc_cmap);
421 		return (error);
422 
423 	case WSDISPLAYIO_SVIDEO:
424 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
425 		if (sc->sc_blanked != turnoff) {
426 			sc->sc_blanked = turnoff;
427 			xcfb_screenblank(sc);
428 		}
429 		return (0);
430 
431 	case WSDISPLAYIO_GVIDEO:
432 		*(u_int *)data = sc->sc_blanked ?
433 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
434 		return (0);
435 
436 	case WSDISPLAYIO_GCURPOS:
437 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
438 		return (0);
439 
440 	case WSDISPLAYIO_SCURPOS:
441 		set_curpos(sc, (struct wsdisplay_curpos *)data);
442 		ims332_set_curpos(sc);
443 		return (0);
444 
445 	case WSDISPLAYIO_GCURMAX:
446 		((struct wsdisplay_curpos *)data)->x =
447 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
448 		return (0);
449 
450 	case WSDISPLAYIO_GCURSOR:
451 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
452 
453 	case WSDISPLAYIO_SCURSOR:
454 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
455 
456 	case WSDISPLAYIO_SMODE:
457 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
458 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
459 			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
460 			xcfb_cmap_init(sc);
461 			ims332_loadcmap(&sc->sc_cmap);
462 			sc->sc_blanked = 0;
463 			xcfb_screenblank(sc);
464 		}
465 		return (0);
466 	}
467 	return (EPASSTHROUGH);
468 }
469 
470 static paddr_t
471 xcfbmmap(void *v, void *vs, off_t offset, int prot)
472 {
473 
474 	if (offset >= XCFB_FB_SIZE || offset < 0)
475 		return (-1);
476 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
477 }
478 
479 static int
480 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
481     int *curxp, int *curyp, long *attrp)
482 {
483 	struct xcfb_softc *sc = v;
484 	struct rasops_info *ri = sc->sc_ri;
485 	long defattr;
486 
487 	if (sc->nscreens > 0)
488 		return (ENOMEM);
489 
490 	*cookiep = ri; 		/* one and only for now */
491 	*curxp = 0;
492 	*curyp = 0;
493 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
494 	*attrp = defattr;
495 	sc->nscreens++;
496 	return (0);
497 }
498 
499 static void
500 xcfb_free_screen(void *v, void *cookie)
501 {
502 	struct xcfb_softc *sc = v;
503 
504 	if (sc->sc_ri == &xcfb_console_ri)
505 		panic("xcfb_free_screen: console");
506 
507 	sc->nscreens--;
508 }
509 
510 static int
511 xcfb_show_screen(void *v, void *cookie, int waitok,
512     void (*cb)(void *, int, int), void *cbarg)
513 {
514 
515 	return (0);
516 }
517 
518 static int
519 xcfbintr(void *v)
520 {
521 	struct xcfb_softc *sc = v;
522 	uint32_t *intr, i;
523 
524 	intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR);
525 	i = *intr;
526 	i &= ~XINE_INTR_VINT;
527 	*intr = i;
528 	return (1);
529 }
530 
531 static void
532 xcfb_screenblank(struct xcfb_softc *sc)
533 {
534 	if (sc->sc_blanked)
535 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
536 	else
537 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
538 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
539 }
540 
541 static int
542 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
543 {
544 	u_int index = p->index, count = p->count;
545 	int error;
546 
547 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
548 		return (EINVAL);
549 
550 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
551 	if (error)
552 		return error;
553 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
554 	if (error)
555 		return error;
556 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
557 	return error;
558 }
559 
560 static int
561 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
562 {
563 	struct hwcmap256 cmap;
564 	u_int index = p->index, count = p->count;
565 	int error;
566 
567 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
568 		return (EINVAL);
569 
570 	error = copyin(p->red, &cmap.r[index], count);
571 	if (error)
572 		return error;
573 	error = copyin(p->green, &cmap.g[index], count);
574 	if (error)
575 		return error;
576 	error = copyin(p->blue, &cmap.b[index], count);
577 	if (error)
578 		return error;
579 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
580 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
581 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
582 	return (0);
583 }
584 
585 static int
586 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
587 {
588 #define	cc (&sc->sc_cursor)
589 	u_int v, index = 0, count = 0, icount = 0;
590 	uint8_t r[2], g[2], b[2], image[512], mask[512];
591 	int error;
592 
593 	v = p->which;
594 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
595 		index = p->cmap.index;
596 		count = p->cmap.count;
597 
598 		if (index >= 2 || index + count > 2)
599 			return (EINVAL);
600 		error = copyin(p->cmap.red, &r[index], count);
601 		if (error)
602 			return error;
603 		error = copyin(p->cmap.green, &g[index], count);
604 		if (error)
605 			return error;
606 		error = copyin(p->cmap.blue, &b[index], count);
607 		if (error)
608 			return error;
609 	}
610 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
611 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
612 			return (EINVAL);
613 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
614 		error = copyin(p->image, image, icount);
615 		if (error)
616 			return error;
617 		error = copyin(p->mask, mask, icount);
618 		if (error)
619 			return error;
620 	}
621 
622 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
623 		memcpy(&cc->cc_color[index], &r[index], count);
624 		memcpy(&cc->cc_color[index + 2], &g[index], count);
625 		memcpy(&cc->cc_color[index + 4], &b[index], count);
626 		ims332_load_curcmap(sc);
627 	}
628 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
629 		cc->cc_size = p->size;
630 		memset(cc->cc_image, 0, sizeof cc->cc_image);
631 		memcpy(cc->cc_image, image, icount);
632 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
633 		memcpy(cc->cc_mask, mask, icount);
634 		ims332_load_curshape(sc);
635 	}
636 	if (v & WSDISPLAY_CURSOR_DOCUR) {
637 		cc->cc_hot = p->hot;
638 		if (p->enable)
639 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
640 		else
641 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
642 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
643 	}
644 	if (v & WSDISPLAY_CURSOR_DOPOS) {
645 		set_curpos(sc, &p->pos);
646 		ims332_set_curpos(sc);
647 	}
648 
649 	return (0);
650 #undef cc
651 }
652 
653 static int
654 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
655 {
656 	return (EPASSTHROUGH); /* XXX */
657 }
658 
659 static void
660 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
661 {
662 	struct rasops_info *ri = sc->sc_ri;
663 	int x = curpos->x, y = curpos->y;
664 
665 	if (y < 0)
666 		y = 0;
667 	else if (y > ri->ri_height)
668 		y = ri->ri_height;
669 	if (x < 0)
670 		x = 0;
671 	else if (x > ri->ri_width)
672 		x = ri->ri_width;
673 	sc->sc_cursor.cc_pos.x = x;
674 	sc->sc_cursor.cc_pos.y = y;
675 }
676 
677 static void
678 ims332_loadcmap(struct hwcmap256 *cm)
679 {
680 	int i;
681 	uint32_t rgb;
682 
683 	for (i = 0; i < CMAP_SIZE; i++) {
684 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
685 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
686 	}
687 }
688 
689 static void
690 ims332_set_curpos(struct xcfb_softc *sc)
691 {
692 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
693 	uint32_t pos;
694 	int s;
695 
696 	s = spltty();
697 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
698 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
699 	splx(s);
700 }
701 
702 static void
703 ims332_load_curcmap(struct xcfb_softc *sc)
704 {
705 	uint8_t *cp = sc->sc_cursor.cc_color;
706 	uint32_t rgb;
707 
708 	/* cursor background */
709 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
710 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
711 
712 	/* cursor foreground */
713 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
714 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
715 }
716 
717 static void
718 ims332_load_curshape(struct xcfb_softc *sc)
719 {
720 	u_int i, img, msk, bits;
721 	uint8_t u, *ip, *mp;
722 
723 	ip = (uint8_t *)sc->sc_cursor.cc_image;
724 	mp = (uint8_t *)sc->sc_cursor.cc_mask;
725 
726 	i = 0;
727 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
728 	while (i < sc->sc_cursor.cc_size.y * 8) {
729 		/* pad right half 32 pixel when smaller than 33 */
730 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
731 			bits = 0;
732 		else {
733 			img = *ip++;
734 			msk = *mp++;
735 			img &= msk;	/* cookie off image */
736 			u = (msk & 0x0f) << 4 | (img & 0x0f);
737 			bits = shuffle[u];
738 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
739 			bits = (shuffle[u] << 8) | bits;
740 		}
741 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
742 		i += 1;
743 	}
744 	/* pad unoccupied scan lines */
745 	while (i < CURSOR_MAX_SIZE * 8) {
746 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
747 		i += 1;
748 	}
749 }
750 
751 static void
752 ims332_write_reg(int regno, uint32_t val)
753 {
754 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
755 	void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
756 
757 	*(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
758 	*(volatile uint16_t *)low16 = val;
759 }
760 
761 #if 0
762 static uint32_t
763 ims332_read_reg(int regno)
764 {
765 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
766 	void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
767 	u_int v0, v1;
768 
769 	v1 = *(volatile uint16_t *)high8;
770 	v0 = *(volatile uint16_t *)low16;
771 	return (v1 & 0xff00) << 8 | v0;
772 }
773 #endif
774