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