xref: /netbsd-src/sys/dev/tc/xcfb.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /* $NetBSD: xcfb.c,v 1.51 2009/08/22 17:38:06 tsutsui 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.51 2009/08/22 17:38:06 tsutsui 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 #include <uvm/uvm_extern.h>
58 
59 struct hwcmap256 {
60 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
61 	uint8_t r[CMAP_SIZE];
62 	uint8_t g[CMAP_SIZE];
63 	uint8_t b[CMAP_SIZE];
64 };
65 
66 struct hwcursor64 {
67 	struct wsdisplay_curpos cc_pos;
68 	struct wsdisplay_curpos cc_hot;
69 	struct wsdisplay_curpos cc_size;
70 	struct wsdisplay_curpos cc_magic;	/* not used by PMAG-DV */
71 #define	CURSOR_MAX_SIZE	64
72 	uint8_t cc_color[6];
73 	uint64_t cc_image[CURSOR_MAX_SIZE];
74 	uint64_t cc_mask[CURSOR_MAX_SIZE];
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 	vaddr_t sc_vaddr;
86 	size_t sc_size;
87 	struct rasops_info *sc_ri;
88 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
89 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
90 	int sc_blanked;
91 	/* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
92 	int nscreens;
93 	/* cursor coordinate is located at upper-left corner */
94 	int sc_csr;			/* software copy of IMS332 CSR A */
95 };
96 
97 static int  xcfbmatch(device_t, cfdata_t, void *);
98 static void xcfbattach(device_t, device_t, void *);
99 
100 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
101     xcfbmatch, xcfbattach, NULL, NULL);
102 
103 static tc_addr_t xcfb_consaddr;
104 static struct rasops_info xcfb_console_ri;
105 static void xcfb_common_init(struct rasops_info *);
106 static void xcfbhwinit(void *);
107 int xcfb_cnattach(void);
108 
109 struct wsscreen_descr xcfb_stdscreen = {
110 	"std", 0, 0,
111 	0, /* textops */
112 	0, 0,
113 	WSSCREEN_REVERSE
114 };
115 
116 static const struct wsscreen_descr *_xcfb_scrlist[] = {
117 	&xcfb_stdscreen,
118 };
119 
120 static const struct wsscreen_list xcfb_screenlist = {
121 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
122 };
123 
124 static int	xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
125 static paddr_t	xcfbmmap(void *, void *, off_t, int);
126 
127 static int	xcfb_alloc_screen(void *, const struct wsscreen_descr *,
128 				       void **, int *, int *, long *);
129 static void	xcfb_free_screen(void *, void *);
130 static int	xcfb_show_screen(void *, void *, int,
131 				      void (*) (void *, int, int), void *);
132 
133 static const struct wsdisplay_accessops xcfb_accessops = {
134 	xcfbioctl,
135 	xcfbmmap,
136 	xcfb_alloc_screen,
137 	xcfb_free_screen,
138 	xcfb_show_screen,
139 	0 /* load_font */
140 };
141 
142 static int  xcfbintr(void *);
143 static void xcfb_screenblank(struct xcfb_softc *);
144 static void xcfb_cmap_init(struct xcfb_softc *);
145 static int  set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
146 static int  get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
147 static int  set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
148 static int  get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
149 static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
150 static void ims332_loadcmap(struct hwcmap256 *);
151 static void ims332_set_curpos(struct xcfb_softc *);
152 static void ims332_load_curcmap(struct xcfb_softc *);
153 static void ims332_load_curshape(struct xcfb_softc *);
154 static void ims332_write_reg(int, uint32_t);
155 #if 0
156 static uint32_t ims332_read_reg(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 uint8_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(device_t parent, cfdata_t match, void *aux)
205 {
206 	struct tc_attach_args *ta = aux;
207 
208 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
209 		return (0);
210 
211 	return (1);
212 }
213 
214 static void
215 xcfbattach(device_t parent, device_t self, void *aux)
216 {
217 	struct xcfb_softc *sc = device_private(self);
218 	struct tc_attach_args *ta = aux;
219 	struct rasops_info *ri;
220 	struct wsemuldisplaydev_attach_args waa;
221 	int console;
222 
223 	console = (ta->ta_addr == xcfb_consaddr);
224 	if (console) {
225 		sc->sc_ri = ri = &xcfb_console_ri;
226 		sc->nscreens = 1;
227 	}
228 	else {
229 		ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT);
230 		if (ri == NULL) {
231 			printf(": can't alloc memory\n");
232 			return;
233 		}
234 		memset(ri, 0, sizeof(struct rasops_info));
235 
236 		ri->ri_hw = (void *)ioasic_base;
237 		xcfb_common_init(ri);
238 		sc->sc_ri = ri;
239 	}
240 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
241 
242 	xcfb_cmap_init(sc);
243 
244 	sc->sc_vaddr = ta->ta_addr;
245 	sc->sc_blanked = 0;
246 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
247 
248         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
249 
250 	waa.console = console;
251 	waa.scrdata = &xcfb_screenlist;
252 	waa.accessops = &xcfb_accessops;
253 	waa.accesscookie = sc;
254 
255 	config_found(self, &waa, wsemuldisplaydevprint);
256 }
257 
258 static void
259 xcfb_cmap_init(struct xcfb_softc *sc)
260 {
261 	struct hwcmap256 *cm;
262 	const uint8_t *p;
263 	int index;
264 
265 	cm = &sc->sc_cmap;
266 	p = rasops_cmap;
267 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
268 		cm->r[index] = p[0];
269 		cm->g[index] = p[1];
270 		cm->b[index] = p[2];
271 	}
272 }
273 
274 static void
275 xcfb_common_init(struct rasops_info *ri)
276 {
277 	int cookie;
278 
279 	/* initialize colormap and cursor hardware */
280 	xcfbhwinit((void *)ri->ri_hw);
281 
282 	ri->ri_flg = RI_CENTER;
283 	ri->ri_depth = 8;
284 	ri->ri_width = 1024;
285 	ri->ri_height = 768;
286 	ri->ri_stride = 1024;
287 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
288 
289 	/* clear the screen */
290 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
291 
292 	wsfont_init();
293 	/* prefer 12 pixel wide font */
294 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
295 	    WSDISPLAY_FONTORDER_L2R);
296 	if (cookie <= 0)
297 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
298 		    WSDISPLAY_FONTORDER_L2R);
299 	if (cookie <= 0) {
300 		printf("xcfb: font table is empty\n");
301 		return;
302 	}
303 
304 	if (wsfont_lock(cookie, &ri->ri_font)) {
305 		printf("xcfb: couldn't lock font\n");
306 		return;
307 	}
308 	ri->ri_wsfcookie = cookie;
309 
310 	rasops_init(ri, 34, 80);
311 
312 	/* XXX shouldn't be global */
313 	xcfb_stdscreen.nrows = ri->ri_rows;
314 	xcfb_stdscreen.ncols = ri->ri_cols;
315 	xcfb_stdscreen.textops = &ri->ri_ops;
316 	xcfb_stdscreen.capabilities = ri->ri_caps;
317 }
318 
319 int
320 xcfb_cnattach(void)
321 {
322 	struct rasops_info *ri;
323 	long defattr;
324 
325 	ri = &xcfb_console_ri;
326 	ri->ri_hw = (void *)ioasic_base;
327 	xcfb_common_init(ri);
328 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
329 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
330 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
331 	return (0);
332 }
333 
334 static void
335 xcfbhwinit(void *base)
336 {
337 	volatile uint32_t *csr;
338 	uint32_t i;
339 	const uint8_t *p;
340 
341 	csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
342 	i = *csr;
343 	i &= ~XINE_CSR_VDAC_ENABLE;
344 	*csr = i;
345 	DELAY(50);
346 	i |= XINE_CSR_VDAC_ENABLE;
347 	*csr = i;
348 	DELAY(50);
349 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
350 	ims332_write_reg(IMS332_REG_CSR_A,
351 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
352 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
353 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
354 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
355 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
356 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
357 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
358 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
359 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
360 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
361 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
362 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
363 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
364 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
365 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
366 	ims332_write_reg(IMS332_REG_CSR_A,
367 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
368 
369 	/* build sane colormap */
370 	p = rasops_cmap;
371 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
372 		uint32_t bgr;
373 
374 		bgr = p[2] << 16 | p[1] << 8 | p[0];
375 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
376 	}
377 
378 	/* clear out cursor image */
379 	for (i = 0; i < 512; i++)
380 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
381 
382 	/*
383 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
384 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
385 	 * image color.  LUT_0 will be never used.
386 	 */
387 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
388 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
389 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
390 }
391 
392 static int
393 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
394 {
395 	struct xcfb_softc *sc = v;
396 	struct rasops_info *ri = sc->sc_ri;
397 	int turnoff, error;
398 
399 	switch (cmd) {
400 	case WSDISPLAYIO_GTYPE:
401 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
402 		return (0);
403 
404 	case WSDISPLAYIO_GINFO:
405 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
406 		wsd_fbip->height = ri->ri_height;
407 		wsd_fbip->width = ri->ri_width;
408 		wsd_fbip->depth = ri->ri_depth;
409 		wsd_fbip->cmsize = CMAP_SIZE;
410 #undef fbt
411 		return (0);
412 
413 	case WSDISPLAYIO_GETCMAP:
414 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
415 
416 	case WSDISPLAYIO_PUTCMAP:
417 		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
418 		if (error == 0)
419 			ims332_loadcmap(&sc->sc_cmap);
420 		return (error);
421 
422 	case WSDISPLAYIO_SVIDEO:
423 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
424 		if (sc->sc_blanked != turnoff) {
425 			sc->sc_blanked = turnoff;
426 			xcfb_screenblank(sc);
427 		}
428 		return (0);
429 
430 	case WSDISPLAYIO_GVIDEO:
431 		*(u_int *)data = sc->sc_blanked ?
432 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
433 		return (0);
434 
435 	case WSDISPLAYIO_GCURPOS:
436 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
437 		return (0);
438 
439 	case WSDISPLAYIO_SCURPOS:
440 		set_curpos(sc, (struct wsdisplay_curpos *)data);
441 		ims332_set_curpos(sc);
442 		return (0);
443 
444 	case WSDISPLAYIO_GCURMAX:
445 		((struct wsdisplay_curpos *)data)->x =
446 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
447 		return (0);
448 
449 	case WSDISPLAYIO_GCURSOR:
450 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
451 
452 	case WSDISPLAYIO_SCURSOR:
453 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
454 
455 	case WSDISPLAYIO_SMODE:
456 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
457 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
458 			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
459 			xcfb_cmap_init(sc);
460 			ims332_loadcmap(&sc->sc_cmap);
461 			sc->sc_blanked = 0;
462 			xcfb_screenblank(sc);
463 		}
464 		return (0);
465 	}
466 	return (EPASSTHROUGH);
467 }
468 
469 static paddr_t
470 xcfbmmap(void *v, void *vs, off_t offset, int prot)
471 {
472 
473 	if (offset >= XCFB_FB_SIZE || offset < 0)
474 		return (-1);
475 	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
476 }
477 
478 static int
479 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
480     int *curxp, int *curyp, 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(void *v, void *cookie)
500 {
501 	struct xcfb_softc *sc = v;
502 
503 	if (sc->sc_ri == &xcfb_console_ri)
504 		panic("xcfb_free_screen: console");
505 
506 	sc->nscreens--;
507 }
508 
509 static int
510 xcfb_show_screen(void *v, void *cookie, int waitok,
511     void (*cb)(void *, int, int), void *cbarg)
512 {
513 
514 	return (0);
515 }
516 
517 static int
518 xcfbintr(void *v)
519 {
520 	struct xcfb_softc *sc = v;
521 	uint32_t *intr, i;
522 
523 	intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR);
524 	i = *intr;
525 	i &= ~XINE_INTR_VINT;
526 	*intr = i;
527 	return (1);
528 }
529 
530 static void
531 xcfb_screenblank(struct xcfb_softc *sc)
532 {
533 	if (sc->sc_blanked)
534 		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
535 	else
536 		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
537 	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
538 }
539 
540 static int
541 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
542 {
543 	u_int index = p->index, count = p->count;
544 	int error;
545 
546 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
547 		return (EINVAL);
548 
549 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
550 	if (error)
551 		return error;
552 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
553 	if (error)
554 		return error;
555 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
556 	return error;
557 }
558 
559 static int
560 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
561 {
562 	struct hwcmap256 cmap;
563 	u_int index = p->index, count = p->count;
564 	int error;
565 
566 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
567 		return (EINVAL);
568 
569 	error = copyin(p->red, &cmap.r[index], count);
570 	if (error)
571 		return error;
572 	error = copyin(p->green, &cmap.g[index], count);
573 	if (error)
574 		return error;
575 	error = copyin(p->blue, &cmap.b[index], count);
576 	if (error)
577 		return error;
578 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
579 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
580 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
581 	return (0);
582 }
583 
584 static int
585 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
586 {
587 #define	cc (&sc->sc_cursor)
588 	u_int v, index = 0, count = 0, icount = 0;
589 	uint8_t r[2], g[2], b[2], image[512], mask[512];
590 	int error;
591 
592 	v = p->which;
593 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
594 		index = p->cmap.index;
595 		count = p->cmap.count;
596 
597 		if (index >= 2 || index + count > 2)
598 			return (EINVAL);
599 		error = copyin(p->cmap.red, &r[index], count);
600 		if (error)
601 			return error;
602 		error = copyin(p->cmap.green, &g[index], count);
603 		if (error)
604 			return error;
605 		error = copyin(p->cmap.blue, &b[index], count);
606 		if (error)
607 			return error;
608 	}
609 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
610 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
611 			return (EINVAL);
612 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
613 		error = copyin(p->image, image, icount);
614 		if (error)
615 			return error;
616 		error = copyin(p->mask, mask, icount);
617 		if (error)
618 			return error;
619 	}
620 
621 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
622 		memcpy(&cc->cc_color[index], &r[index], count);
623 		memcpy(&cc->cc_color[index + 2], &g[index], count);
624 		memcpy(&cc->cc_color[index + 4], &b[index], count);
625 		ims332_load_curcmap(sc);
626 	}
627 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
628 		cc->cc_size = p->size;
629 		memset(cc->cc_image, 0, sizeof cc->cc_image);
630 		memcpy(cc->cc_image, image, icount);
631 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
632 		memcpy(cc->cc_mask, mask, icount);
633 		ims332_load_curshape(sc);
634 	}
635 	if (v & WSDISPLAY_CURSOR_DOCUR) {
636 		cc->cc_hot = p->hot;
637 		if (p->enable)
638 			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
639 		else
640 			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
641 		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
642 	}
643 	if (v & WSDISPLAY_CURSOR_DOPOS) {
644 		set_curpos(sc, &p->pos);
645 		ims332_set_curpos(sc);
646 	}
647 
648 	return (0);
649 #undef cc
650 }
651 
652 static int
653 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
654 {
655 	return (EPASSTHROUGH); /* XXX */
656 }
657 
658 static void
659 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
660 {
661 	struct rasops_info *ri = sc->sc_ri;
662 	int x = curpos->x, y = curpos->y;
663 
664 	if (y < 0)
665 		y = 0;
666 	else if (y > ri->ri_height)
667 		y = ri->ri_height;
668 	if (x < 0)
669 		x = 0;
670 	else if (x > ri->ri_width)
671 		x = ri->ri_width;
672 	sc->sc_cursor.cc_pos.x = x;
673 	sc->sc_cursor.cc_pos.y = y;
674 }
675 
676 static void
677 ims332_loadcmap(struct hwcmap256 *cm)
678 {
679 	int i;
680 	uint32_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(struct xcfb_softc *sc)
690 {
691 	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
692 	uint32_t pos;
693 	int s;
694 
695 	s = spltty();
696 	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
697 	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
698 	splx(s);
699 }
700 
701 static void
702 ims332_load_curcmap(struct xcfb_softc *sc)
703 {
704 	uint8_t *cp = sc->sc_cursor.cc_color;
705 	uint32_t rgb;
706 
707 	/* cursor background */
708 	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
709 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
710 
711 	/* cursor foreground */
712 	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
713 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
714 }
715 
716 static void
717 ims332_load_curshape(struct xcfb_softc *sc)
718 {
719 	u_int i, img, msk, bits;
720 	uint8_t u, *ip, *mp;
721 
722 	ip = (uint8_t *)sc->sc_cursor.cc_image;
723 	mp = (uint8_t *)sc->sc_cursor.cc_mask;
724 
725 	i = 0;
726 	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
727 	while (i < sc->sc_cursor.cc_size.y * 8) {
728 		/* pad right half 32 pixel when smaller than 33 */
729 		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
730 			bits = 0;
731 		else {
732 			img = *ip++;
733 			msk = *mp++;
734 			img &= msk;	/* cookie off image */
735 			u = (msk & 0x0f) << 4 | (img & 0x0f);
736 			bits = shuffle[u];
737 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
738 			bits = (shuffle[u] << 8) | bits;
739 		}
740 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
741 		i += 1;
742 	}
743 	/* pad unoccupied scan lines */
744 	while (i < CURSOR_MAX_SIZE * 8) {
745 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
746 		i += 1;
747 	}
748 }
749 
750 static void
751 ims332_write_reg(int regno, uint32_t val)
752 {
753 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
754 	void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
755 
756 	*(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
757 	*(volatile uint16_t *)low16 = val;
758 }
759 
760 #if 0
761 static uint32_t
762 ims332_read_reg(int regno)
763 {
764 	void *high8 = (void *)(ioasic_base + IMS332_HIGH);
765 	void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
766 	u_int v0, v1;
767 
768 	v1 = *(volatile uint16_t *)high8;
769 	v0 = *(volatile uint16_t *)low16;
770 	return (v1 & 0xff00) << 8 | v0;
771 }
772 #endif
773