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