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