xcfb.c revision 1.37
1/* $NetBSD: xcfb.c,v 1.37 2005/01/02 20:41:20 mhitch 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.37 2005/01/02 20:41:20 mhitch 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(struct device *, struct cfdata *, void *);
100static void xcfbattach(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(struct rasops_info *);
108static void xcfbhwinit(caddr_t);
109int xcfb_cnattach(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(void *, u_long, caddr_t, int, struct proc *);
127static paddr_t	xcfbmmap(void *, off_t, int);
128
129static int	xcfb_alloc_screen(void *, const struct wsscreen_descr *,
130				       void **, int *, int *, long *);
131static void	xcfb_free_screen(void *, void *);
132static int	xcfb_show_screen(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(void *);
145static void xcfb_screenblank(struct xcfb_softc *);
146static void xcfb_cmap_init(struct xcfb_softc *);
147static int  set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
148static int  get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
149static int  set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
150static int  get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
151static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
152static void ims332_loadcmap(struct hwcmap256 *);
153static void ims332_set_curpos(struct xcfb_softc *);
154static void ims332_load_curcmap(struct xcfb_softc *);
155static void ims332_load_curshape(struct xcfb_softc *);
156static void ims332_write_reg(int, u_int32_t);
157#if 0
158static u_int32_t ims332_read_reg(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	volatile u_int32_t *csr;
349	u_int32_t i;
350	const u_int8_t *p;
351
352	csr = (volatile u_int32_t *)(base + IOASIC_CSR);
353	i = *csr;
354	i &= ~XINE_CSR_VDAC_ENABLE;
355	*csr = i;
356	DELAY(50);
357	i |= XINE_CSR_VDAC_ENABLE;
358	*csr = i;
359	DELAY(50);
360	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
361	ims332_write_reg(IMS332_REG_CSR_A,
362		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
363	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
364	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
365	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
366	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
367	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
368	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
369	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
370	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
371	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
372	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
373	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
374	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
375	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
376	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
377	ims332_write_reg(IMS332_REG_CSR_A,
378		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
379
380	/* build sane colormap */
381	p = rasops_cmap;
382	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
383		u_int32_t bgr;
384
385		bgr = p[2] << 16 | p[1] << 8 | p[0];
386		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
387	}
388
389	/* clear out cursor image */
390	for (i = 0; i < 512; i++)
391		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
392
393	/*
394	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
395	 * cursor image.  LUT_1 for mask color, while LUT_2 for
396	 * image color.  LUT_0 will be never used.
397	 */
398	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
399	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
400	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
401}
402
403static int
404xcfbioctl(v, cmd, data, flag, p)
405	void *v;
406	u_long cmd;
407	caddr_t data;
408	int flag;
409	struct proc *p;
410{
411	struct xcfb_softc *sc = v;
412	struct rasops_info *ri = sc->sc_ri;
413	int turnoff, error;
414
415	switch (cmd) {
416	case WSDISPLAYIO_GTYPE:
417		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
418		return (0);
419
420	case WSDISPLAYIO_GINFO:
421#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
422		wsd_fbip->height = ri->ri_height;
423		wsd_fbip->width = ri->ri_width;
424		wsd_fbip->depth = ri->ri_depth;
425		wsd_fbip->cmsize = CMAP_SIZE;
426#undef fbt
427		return (0);
428
429	case WSDISPLAYIO_GETCMAP:
430		return get_cmap(sc, (struct wsdisplay_cmap *)data);
431
432	case WSDISPLAYIO_PUTCMAP:
433		error = set_cmap(sc, (struct wsdisplay_cmap *)data);
434		if (error == 0)
435			ims332_loadcmap(&sc->sc_cmap);
436		return (error);
437
438	case WSDISPLAYIO_SVIDEO:
439		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
440		if (sc->sc_blanked != turnoff) {
441			sc->sc_blanked = turnoff;
442			xcfb_screenblank(sc);
443		}
444		return (0);
445
446	case WSDISPLAYIO_GVIDEO:
447		*(u_int *)data = sc->sc_blanked ?
448		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
449		return (0);
450
451	case WSDISPLAYIO_GCURPOS:
452		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
453		return (0);
454
455	case WSDISPLAYIO_SCURPOS:
456		set_curpos(sc, (struct wsdisplay_curpos *)data);
457		ims332_set_curpos(sc);
458		return (0);
459
460	case WSDISPLAYIO_GCURMAX:
461		((struct wsdisplay_curpos *)data)->x =
462		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
463		return (0);
464
465	case WSDISPLAYIO_GCURSOR:
466		return get_cursor(sc, (struct wsdisplay_cursor *)data);
467
468	case WSDISPLAYIO_SCURSOR:
469		return set_cursor(sc, (struct wsdisplay_cursor *)data);
470
471	case WSDISPLAYIO_SMODE:
472		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
473			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
474			ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
475			xcfb_cmap_init(sc);
476			ims332_loadcmap(&sc->sc_cmap);
477			sc->sc_blanked = 0;
478			xcfb_screenblank(sc);
479		}
480		return (0);
481	}
482	return (EPASSTHROUGH);
483}
484
485static paddr_t
486xcfbmmap(v, offset, prot)
487	void *v;
488	off_t offset;
489	int prot;
490{
491
492	if (offset >= XCFB_FB_SIZE || offset < 0)
493		return (-1);
494	return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
495}
496
497static int
498xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
499	void *v;
500	const struct wsscreen_descr *type;
501	void **cookiep;
502	int *curxp, *curyp;
503	long *attrp;
504{
505	struct xcfb_softc *sc = v;
506	struct rasops_info *ri = sc->sc_ri;
507	long defattr;
508
509	if (sc->nscreens > 0)
510		return (ENOMEM);
511
512	*cookiep = ri; 		/* one and only for now */
513	*curxp = 0;
514	*curyp = 0;
515	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
516	*attrp = defattr;
517	sc->nscreens++;
518	return (0);
519}
520
521static void
522xcfb_free_screen(v, cookie)
523	void *v;
524	void *cookie;
525{
526	struct xcfb_softc *sc = v;
527
528	if (sc->sc_ri == &xcfb_console_ri)
529		panic("xcfb_free_screen: console");
530
531	sc->nscreens--;
532}
533
534static int
535xcfb_show_screen(v, cookie, waitok, cb, cbarg)
536	void *v;
537	void *cookie;
538	int waitok;
539	void (*cb)(void *, int, int);
540	void *cbarg;
541{
542
543	return (0);
544}
545
546static int
547xcfbintr(v)
548	void *v;
549{
550	struct xcfb_softc *sc = v;
551	u_int32_t *intr, i;
552
553	intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
554	i = *intr;
555	i &= ~XINE_INTR_VINT;
556	*intr = i;
557	return (1);
558}
559
560static void
561xcfb_screenblank(sc)
562	struct xcfb_softc *sc;
563{
564	if (sc->sc_blanked)
565		sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
566	else
567		sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
568	ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
569}
570
571static int
572get_cmap(sc, p)
573	struct xcfb_softc *sc;
574	struct wsdisplay_cmap *p;
575{
576	u_int index = p->index, count = p->count;
577	int error;
578
579	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
580		return (EINVAL);
581
582	error = copyout(&sc->sc_cmap.r[index], p->red, count);
583	if (error)
584		return error;
585	error = copyout(&sc->sc_cmap.g[index], p->green, count);
586	if (error)
587		return error;
588	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
589	return error;
590}
591
592static int
593set_cmap(sc, p)
594	struct xcfb_softc *sc;
595	struct wsdisplay_cmap *p;
596{
597	struct hwcmap256 cmap;
598	u_int index = p->index, count = p->count;
599	int error;
600
601	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
602		return (EINVAL);
603
604	error = copyin(p->red, &cmap.r[index], count);
605	if (error)
606		return error;
607	error = copyin(p->green, &cmap.g[index], count);
608	if (error)
609		return error;
610	error = copyin(p->blue, &cmap.b[index], count);
611	if (error)
612		return error;
613	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
614	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
615	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
616	return (0);
617}
618
619static int
620set_cursor(sc, p)
621	struct xcfb_softc *sc;
622	struct wsdisplay_cursor *p;
623{
624#define	cc (&sc->sc_cursor)
625	u_int v, index = 0, count = 0, icount = 0;
626	uint8_t r[2], g[2], b[2], image[512], mask[512];
627	int error;
628
629	v = p->which;
630	if (v & WSDISPLAY_CURSOR_DOCMAP) {
631		index = p->cmap.index;
632		count = p->cmap.count;
633
634		if (index >= 2 || index + count > 2)
635			return (EINVAL);
636		error = copyin(p->cmap.red, &r[index], count);
637		if (error)
638			return error;
639		error = copyin(p->cmap.green, &g[index], count);
640		if (error)
641			return error;
642		error = copyin(p->cmap.blue, &b[index], count);
643		if (error)
644			return error;
645	}
646	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
647		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
648			return (EINVAL);
649		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
650		error = copyin(p->image, image, icount);
651		if (error)
652			return error;
653		error = copyin(p->mask, mask, icount);
654		if (error)
655			return error;
656	}
657
658	if (v & WSDISPLAY_CURSOR_DOCMAP) {
659		memcpy(&cc->cc_color[index], &r[index], count);
660		memcpy(&cc->cc_color[index + 2], &g[index], count);
661		memcpy(&cc->cc_color[index + 4], &b[index], count);
662		ims332_load_curcmap(sc);
663	}
664	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
665		cc->cc_size = p->size;
666		memset(cc->cc_image, 0, sizeof cc->cc_image);
667		memcpy(cc->cc_image, image, icount);
668		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
669		memcpy(cc->cc_mask, mask, icount);
670		ims332_load_curshape(sc);
671	}
672	if (v & WSDISPLAY_CURSOR_DOCUR) {
673		cc->cc_hot = p->hot;
674		if (p->enable)
675			sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
676		else
677			sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
678		ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
679	}
680	if (v & WSDISPLAY_CURSOR_DOPOS) {
681		set_curpos(sc, &p->pos);
682		ims332_set_curpos(sc);
683	}
684
685	return (0);
686#undef cc
687}
688
689static int
690get_cursor(sc, p)
691	struct xcfb_softc *sc;
692	struct wsdisplay_cursor *p;
693{
694	return (EPASSTHROUGH); /* XXX */
695}
696
697static void
698set_curpos(sc, curpos)
699	struct xcfb_softc *sc;
700	struct wsdisplay_curpos *curpos;
701{
702	struct rasops_info *ri = sc->sc_ri;
703	int x = curpos->x, y = curpos->y;
704
705	if (y < 0)
706		y = 0;
707	else if (y > ri->ri_height)
708		y = ri->ri_height;
709	if (x < 0)
710		x = 0;
711	else if (x > ri->ri_width)
712		x = ri->ri_width;
713	sc->sc_cursor.cc_pos.x = x;
714	sc->sc_cursor.cc_pos.y = y;
715}
716
717static void
718ims332_loadcmap(cm)
719	struct hwcmap256 *cm;
720{
721	int i;
722	u_int32_t rgb;
723
724	for (i = 0; i < CMAP_SIZE; i++) {
725		rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
726		ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
727	}
728}
729
730static void
731ims332_set_curpos(sc)
732	struct xcfb_softc *sc;
733{
734	struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
735	u_int32_t pos;
736	int s;
737
738	s = spltty();
739	pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
740	ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
741	splx(s);
742}
743
744static void
745ims332_load_curcmap(sc)
746	struct xcfb_softc *sc;
747{
748	u_int8_t *cp = sc->sc_cursor.cc_color;
749	u_int32_t rgb;
750
751	/* cursor background */
752	rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
753	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
754
755	/* cursor foreground */
756	rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
757	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
758}
759
760static void
761ims332_load_curshape(sc)
762	struct xcfb_softc *sc;
763{
764	u_int i, img, msk, bits;
765	u_int8_t u, *ip, *mp;
766
767	ip = (u_int8_t *)sc->sc_cursor.cc_image;
768	mp = (u_int8_t *)sc->sc_cursor.cc_mask;
769
770	i = 0;
771	/* 64 pixel scan line is consisted with 8 halfword cursor ram */
772	while (i < sc->sc_cursor.cc_size.y * 8) {
773		/* pad right half 32 pixel when smaller than 33 */
774		if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
775			bits = 0;
776		else {
777			img = *ip++;
778			msk = *mp++;
779			img &= msk;	/* cookie off image */
780			u = (msk & 0x0f) << 4 | (img & 0x0f);
781			bits = shuffle[u];
782			u = (msk & 0xf0) | (img & 0xf0) >> 4;
783			bits = (shuffle[u] << 8) | bits;
784		}
785		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
786		i += 1;
787	}
788	/* pad unoccupied scan lines */
789	while (i < CURSOR_MAX_SIZE * 8) {
790		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
791		i += 1;
792	}
793}
794
795static void
796ims332_write_reg(regno, val)
797	int regno;
798	u_int32_t val;
799{
800	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
801	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
802
803	*(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
804	*(volatile u_int16_t *)low16 = val;
805}
806
807#if 0
808static u_int32_t
809ims332_read_reg(regno)
810	int regno;
811{
812	caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
813	caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
814	u_int v0, v1;
815
816	v1 = *(volatile u_int16_t *)high8;
817	v0 = *(volatile u_int16_t *)low16;
818	return (v1 & 0xff00) << 8 | v0;
819}
820#endif
821