xref: /netbsd-src/sys/dev/tc/xcfb.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /* $NetBSD: xcfb.c,v 1.57 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: xcfb.c,v 1.57 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/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_WAITOK | M_ZERO);
229 		ri->ri_hw = (void *)ioasic_base;
230 		xcfb_common_init(ri);
231 		sc->sc_ri = ri;
232 	}
233 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
234 
235 	xcfb_cmap_init(sc);
236 
237 	sc->sc_vaddr = ta->ta_addr;
238 	sc->sc_blanked = 0;
239 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
240 
241         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
242 
243 	waa.console = console;
244 	waa.scrdata = &xcfb_screenlist;
245 	waa.accessops = &xcfb_accessops;
246 	waa.accesscookie = sc;
247 
248 	config_found(self, &waa, wsemuldisplaydevprint);
249 }
250 
251 static void
252 xcfb_cmap_init(struct xcfb_softc *sc)
253 {
254 	struct hwcmap256 *cm;
255 	const uint8_t *p;
256 	int index;
257 
258 	cm = &sc->sc_cmap;
259 	p = rasops_cmap;
260 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
261 		cm->r[index] = p[0];
262 		cm->g[index] = p[1];
263 		cm->b[index] = p[2];
264 	}
265 }
266 
267 static void
268 xcfb_common_init(struct rasops_info *ri)
269 {
270 	int cookie;
271 
272 	/* initialize colormap and cursor hardware */
273 	xcfbhwinit((void *)ri->ri_hw);
274 
275 	ri->ri_flg = RI_CENTER;
276 	if (ri == &xcfb_console_ri)
277 		ri->ri_flg |= RI_NO_AUTO;
278 	ri->ri_depth = 8;
279 	ri->ri_width = 1024;
280 	ri->ri_height = 768;
281 	ri->ri_stride = 1024;
282 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
283 
284 	/* clear the screen */
285 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
286 
287 	wsfont_init();
288 	/* prefer 12 pixel wide font */
289 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
290 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
291 	if (cookie <= 0)
292 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
293 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
294 	if (cookie <= 0) {
295 		printf("xcfb: font table is empty\n");
296 		return;
297 	}
298 
299 	if (wsfont_lock(cookie, &ri->ri_font)) {
300 		printf("xcfb: couldn't lock font\n");
301 		return;
302 	}
303 	ri->ri_wsfcookie = cookie;
304 
305 	rasops_init(ri, 34, 80);
306 
307 	/* XXX shouldn't be global */
308 	xcfb_stdscreen.nrows = ri->ri_rows;
309 	xcfb_stdscreen.ncols = ri->ri_cols;
310 	xcfb_stdscreen.textops = &ri->ri_ops;
311 	xcfb_stdscreen.capabilities = ri->ri_caps;
312 }
313 
314 int
315 xcfb_cnattach(void)
316 {
317 	struct rasops_info *ri;
318 	long defattr;
319 
320 	ri = &xcfb_console_ri;
321 	ri->ri_hw = (void *)ioasic_base;
322 	xcfb_common_init(ri);
323 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
324 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
325 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
326 	return (0);
327 }
328 
329 static void
330 xcfbhwinit(void *base)
331 {
332 	volatile uint32_t *csr;
333 	uint32_t i;
334 	const uint8_t *p;
335 
336 	csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
337 	i = *csr;
338 	i &= ~XINE_CSR_VDAC_ENABLE;
339 	*csr = i;
340 	DELAY(50);
341 	i |= XINE_CSR_VDAC_ENABLE;
342 	*csr = i;
343 	DELAY(50);
344 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
345 	ims332_write_reg(IMS332_REG_CSR_A,
346 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
347 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
348 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
349 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
350 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
351 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
352 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
353 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
354 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
355 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
356 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
357 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
358 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
359 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
360 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
361 	ims332_write_reg(IMS332_REG_CSR_A,
362 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
363 
364 	/* build sane colormap */
365 	p = rasops_cmap;
366 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
367 		uint32_t bgr;
368 
369 		bgr = p[2] << 16 | p[1] << 8 | p[0];
370 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
371 	}
372 
373 	/* clear out cursor image */
374 	for (i = 0; i < 512; i++)
375 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
376 
377 	/*
378 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
379 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
380 	 * image color.  LUT_0 will be never used.
381 	 */
382 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
383 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
384 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
385 }
386 
387 static int
388 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
389 {
390 	struct xcfb_softc *sc = v;
391 	struct rasops_info *ri = sc->sc_ri;
392 	int turnoff, error;
393 
394 	switch (cmd) {
395 	case WSDISPLAYIO_GTYPE:
396 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
397 		return (0);
398 
399 	case WSDISPLAYIO_GINFO:
400 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
401 		wsd_fbip->height = ri->ri_height;
402 		wsd_fbip->width = ri->ri_width;
403 		wsd_fbip->depth = ri->ri_depth;
404 		wsd_fbip->cmsize = CMAP_SIZE;
405 #undef fbt
406 		return (0);
407 
408 	case WSDISPLAYIO_GETCMAP:
409 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
410 
411 	case WSDISPLAYIO_PUTCMAP:
412 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
413 		if (error == 0)
414 			ims332_loadcmap(&sc->sc_cmap);
415 		return (error);
416 
417 	case WSDISPLAYIO_SVIDEO:
418 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
419 		if (sc->sc_blanked != turnoff) {
420 			sc->sc_blanked = turnoff;
421 			xcfb_screenblank(sc);
422 		}
423 		return (0);
424 
425 	case WSDISPLAYIO_GVIDEO:
426 		*(u_int *)data = sc->sc_blanked ?
427 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
428 		return (0);
429 
430 	case WSDISPLAYIO_GCURPOS:
431 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
432 		return (0);
433 
434 	case WSDISPLAYIO_SCURPOS:
435 		set_curpos(sc, (struct wsdisplay_curpos *)data);
436 		ims332_set_curpos(sc);
437 		return (0);
438 
439 	case WSDISPLAYIO_GCURMAX:
440 		((struct wsdisplay_curpos *)data)->x =
441 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
442 		return (0);
443 
444 	case WSDISPLAYIO_GCURSOR:
445 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
446 
447 	case WSDISPLAYIO_SCURSOR:
448 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
449 
450 	case WSDISPLAYIO_SMODE:
451 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
452 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
453 			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
454 			xcfb_cmap_init(sc);
455 			ims332_loadcmap(&sc->sc_cmap);
456 			sc->sc_blanked = 0;
457 			xcfb_screenblank(sc);
458 		}
459 		return (0);
460 	}
461 	return (EPASSTHROUGH);
462 }
463 
464 static paddr_t
465 xcfbmmap(void *v, void *vs, off_t offset, int prot)
466 {
467 
468 	if (offset >= XCFB_FB_SIZE || offset < 0)
469 		return (-1);
470 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
471 }
472 
473 static int
474 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
475     int *curxp, int *curyp, long *attrp)
476 {
477 	struct xcfb_softc *sc = v;
478 	struct rasops_info *ri = sc->sc_ri;
479 	long defattr;
480 
481 	if (sc->nscreens > 0)
482 		return (ENOMEM);
483 
484 	*cookiep = ri; 		/* one and only for now */
485 	*curxp = 0;
486 	*curyp = 0;
487 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
488 	*attrp = defattr;
489 	sc->nscreens++;
490 	return (0);
491 }
492 
493 static void
494 xcfb_free_screen(void *v, void *cookie)
495 {
496 	struct xcfb_softc *sc = v;
497 
498 	if (sc->sc_ri == &xcfb_console_ri)
499 		panic("xcfb_free_screen: console");
500 
501 	sc->nscreens--;
502 }
503 
504 static int
505 xcfb_show_screen(void *v, void *cookie, int waitok,
506     void (*cb)(void *, int, int), void *cbarg)
507 {
508 
509 	return (0);
510 }
511 
512 static int
513 xcfbintr(void *v)
514 {
515 	struct xcfb_softc *sc = v;
516 	uint32_t *intr, i;
517 
518 	intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR);
519 	i = *intr;
520 	i &= ~XINE_INTR_VINT;
521 	*intr = i;
522 	return (1);
523 }
524 
525 static void
526 xcfb_screenblank(struct xcfb_softc *sc)
527 {
528 	if (sc->sc_blanked)
529 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
530 	else
531 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
532 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
533 }
534 
535 static int
536 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
537 {
538 	u_int index = p->index, count = p->count;
539 	int error;
540 
541 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
542 		return (EINVAL);
543 
544 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
545 	if (error)
546 		return error;
547 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
548 	if (error)
549 		return error;
550 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
551 	return error;
552 }
553 
554 static int
555 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
556 {
557 	struct hwcmap256 cmap;
558 	u_int index = p->index, count = p->count;
559 	int error;
560 
561 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
562 		return (EINVAL);
563 
564 	error = copyin(p->red, &cmap.r[index], count);
565 	if (error)
566 		return error;
567 	error = copyin(p->green, &cmap.g[index], count);
568 	if (error)
569 		return error;
570 	error = copyin(p->blue, &cmap.b[index], count);
571 	if (error)
572 		return error;
573 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
574 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
575 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
576 	return (0);
577 }
578 
579 static int
580 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
581 {
582 #define	cc (&sc->sc_cursor)
583 	u_int v, index = 0, count = 0, icount = 0;
584 	uint8_t r[2], g[2], b[2], image[512], mask[512];
585 	int error;
586 
587 	v = p->which;
588 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
589 		index = p->cmap.index;
590 		count = p->cmap.count;
591 
592 		if (index >= 2 || count > 2 - index)
593 			return (EINVAL);
594 		error = copyin(p->cmap.red, &r[index], count);
595 		if (error)
596 			return error;
597 		error = copyin(p->cmap.green, &g[index], count);
598 		if (error)
599 			return error;
600 		error = copyin(p->cmap.blue, &b[index], count);
601 		if (error)
602 			return error;
603 	}
604 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
605 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
606 			return (EINVAL);
607 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
608 		error = copyin(p->image, image, icount);
609 		if (error)
610 			return error;
611 		error = copyin(p->mask, mask, icount);
612 		if (error)
613 			return error;
614 	}
615 
616 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
617 		memcpy(&cc->cc_color[index], &r[index], count);
618 		memcpy(&cc->cc_color[index + 2], &g[index], count);
619 		memcpy(&cc->cc_color[index + 4], &b[index], count);
620 		ims332_load_curcmap(sc);
621 	}
622 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
623 		cc->cc_size = p->size;
624 		memset(cc->cc_image, 0, sizeof cc->cc_image);
625 		memcpy(cc->cc_image, image, icount);
626 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
627 		memcpy(cc->cc_mask, mask, icount);
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(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
649 {
650 	return (EPASSTHROUGH); /* XXX */
651 }
652 
653 static void
654 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
655 {
656 	struct rasops_info *ri = sc->sc_ri;
657 	int x = curpos->x, y = curpos->y;
658 
659 	if (y < 0)
660 		y = 0;
661 	else if (y > ri->ri_height)
662 		y = ri->ri_height;
663 	if (x < 0)
664 		x = 0;
665 	else if (x > ri->ri_width)
666 		x = ri->ri_width;
667 	sc->sc_cursor.cc_pos.x = x;
668 	sc->sc_cursor.cc_pos.y = y;
669 }
670 
671 static void
672 ims332_loadcmap(struct hwcmap256 *cm)
673 {
674 	int i;
675 	uint32_t rgb;
676 
677 	for (i = 0; i < CMAP_SIZE; i++) {
678 		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
679 		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
680 	}
681 }
682 
683 static void
684 ims332_set_curpos(struct xcfb_softc *sc)
685 {
686 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
687 	uint32_t pos;
688 	int s;
689 
690 	s = spltty();
691 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
692 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
693 	splx(s);
694 }
695 
696 static void
697 ims332_load_curcmap(struct xcfb_softc *sc)
698 {
699 	uint8_t *cp = sc->sc_cursor.cc_color;
700 	uint32_t rgb;
701 
702 	/* cursor background */
703 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
704 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
705 
706 	/* cursor foreground */
707 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
708 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
709 }
710 
711 static void
712 ims332_load_curshape(struct xcfb_softc *sc)
713 {
714 	u_int i, img, msk, bits;
715 	uint8_t u, *ip, *mp;
716 
717 	ip = (uint8_t *)sc->sc_cursor.cc_image;
718 	mp = (uint8_t *)sc->sc_cursor.cc_mask;
719 
720 	i = 0;
721 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
722 	while (i < sc->sc_cursor.cc_size.y * 8) {
723 		/* pad right half 32 pixel when smaller than 33 */
724 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
725 			bits = 0;
726 		else {
727 			img = *ip++;
728 			msk = *mp++;
729 			img &= msk;	/* cookie off image */
730 			u = (msk & 0x0f) << 4 | (img & 0x0f);
731 			bits = shuffle[u];
732 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
733 			bits = (shuffle[u] << 8) | bits;
734 		}
735 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
736 		i += 1;
737 	}
738 	/* pad unoccupied scan lines */
739 	while (i < CURSOR_MAX_SIZE * 8) {
740 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
741 		i += 1;
742 	}
743 }
744 
745 static void
746 ims332_write_reg(int regno, uint32_t val)
747 {
748 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
749 	void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
750 
751 	*(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
752 	*(volatile uint16_t *)low16 = val;
753 }
754 
755 #if 0
756 static uint32_t
757 ims332_read_reg(int regno)
758 {
759 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
760 	void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
761 	u_int v0, v1;
762 
763 	v1 = *(volatile uint16_t *)high8;
764 	v0 = *(volatile uint16_t *)low16;
765 	return (v1 & 0xff00) << 8 | v0;
766 }
767 #endif
768