xref: /netbsd-src/sys/dev/tc/xcfb.c (revision ecb9191049815c59afb1757b3285c0609cb4d65b)
1 /* $NetBSD: xcfb.c,v 1.60 2021/12/06 16:00:07 abs 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.60 2021/12/06 16:00:07 abs Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42 
43 #include <sys/bus.h>
44 #include <sys/intr.h>
45 
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48 
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
51 
52 #include <dev/tc/tcvar.h>
53 #include <dev/tc/ioasicreg.h>
54 #include <dev/ic/ims332reg.h>
55 #include <pmax/pmax/maxine.h>
56 
57 struct hwcmap256 {
58 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
59 	uint8_t r[CMAP_SIZE];
60 	uint8_t g[CMAP_SIZE];
61 	uint8_t b[CMAP_SIZE];
62 };
63 
64 struct hwcursor64 {
65 	struct wsdisplay_curpos cc_pos;
66 	struct wsdisplay_curpos cc_hot;
67 	struct wsdisplay_curpos cc_size;
68 	struct wsdisplay_curpos cc_magic;	/* not used by PMAG-DV */
69 #define	CURSOR_MAX_SIZE	64
70 	uint8_t cc_color[6];
71 	uint64_t cc_image[CURSOR_MAX_SIZE];
72 	uint64_t cc_mask[CURSOR_MAX_SIZE];
73 };
74 
75 #define	XCFB_FB_BASE	(XINE_PHYS_CFB_START + 0x2000000)
76 #define	XCFB_FB_SIZE	0x100000
77 
78 #define	IMS332_HIGH	(IOASIC_SLOT_5_START)
79 #define	IMS332_RLOW	(IOASIC_SLOT_7_START)
80 #define	IMS332_WLOW	(IOASIC_SLOT_7_START + 0x20000)
81 
82 struct xcfb_softc {
83 	vaddr_t sc_vaddr;
84 	size_t sc_size;
85 	struct rasops_info *sc_ri;
86 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
87 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
88 	int sc_blanked;
89 	/* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
90 	int nscreens;
91 	/* cursor coordinate is located at upper-left corner */
92 	int sc_csr;			/* software copy of IMS332 CSR A */
93 };
94 
95 static int  xcfbmatch(device_t, cfdata_t, void *);
96 static void xcfbattach(device_t, device_t, void *);
97 
98 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
99     xcfbmatch, xcfbattach, NULL, NULL);
100 
101 static tc_addr_t xcfb_consaddr;
102 static struct rasops_info xcfb_console_ri;
103 static void xcfb_common_init(struct rasops_info *);
104 static void xcfbhwinit(void *);
105 int xcfb_cnattach(void);
106 
107 struct wsscreen_descr xcfb_stdscreen = {
108 	"std", 0, 0,
109 	0, /* textops */
110 	0, 0,
111 	WSSCREEN_REVERSE
112 };
113 
114 static const struct wsscreen_descr *_xcfb_scrlist[] = {
115 	&xcfb_stdscreen,
116 };
117 
118 static const struct wsscreen_list xcfb_screenlist = {
119 	sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
120 };
121 
122 static int	xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
123 static paddr_t	xcfbmmap(void *, void *, off_t, int);
124 
125 static int	xcfb_alloc_screen(void *, const struct wsscreen_descr *,
126 				       void **, int *, int *, long *);
127 static void	xcfb_free_screen(void *, void *);
128 static int	xcfb_show_screen(void *, void *, int,
129 				      void (*) (void *, int, int), void *);
130 
131 static const struct wsdisplay_accessops xcfb_accessops = {
132 	xcfbioctl,
133 	xcfbmmap,
134 	xcfb_alloc_screen,
135 	xcfb_free_screen,
136 	xcfb_show_screen,
137 	0 /* load_font */
138 };
139 
140 static int  xcfbintr(void *);
141 static void xcfb_screenblank(struct xcfb_softc *);
142 static void xcfb_cmap_init(struct xcfb_softc *);
143 static int  set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
144 static int  get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
145 static int  set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
146 static int  get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
147 static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
148 static void ims332_loadcmap(struct hwcmap256 *);
149 static void ims332_set_curpos(struct xcfb_softc *);
150 static void ims332_load_curcmap(struct xcfb_softc *);
151 static void ims332_load_curshape(struct xcfb_softc *);
152 static void ims332_write_reg(int, uint32_t);
153 #if 0
154 static uint32_t ims332_read_reg(int);
155 #endif
156 
157 extern long ioasic_base;	/* XXX */
158 
159 /*
160  * Compose 2 bit/pixel cursor image.
161  *   M M M M I I I I		M I M I M I M I
162  *	[ before ]		   [ after ]
163  *   3 2 1 0 3 2 1 0		3 3 2 2 1 1 0 0
164  *   7 6 5 4 7 6 5 4		7 7 6 6 5 5 4 4
165  */
166 static const uint8_t shuffle[256] = {
167 	0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
168 	0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
169 	0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
170 	0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
171 	0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
172 	0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
173 	0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
174 	0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
175 	0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
176 	0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
177 	0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
178 	0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
179 	0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
180 	0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
181 	0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
182 	0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
183 	0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
184 	0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
185 	0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
186 	0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
187 	0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
188 	0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
189 	0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
190 	0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
191 	0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
192 	0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
193 	0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
194 	0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
195 	0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
196 	0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
197 	0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
198 	0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
199 };
200 
201 static int
xcfbmatch(device_t parent,cfdata_t match,void * aux)202 xcfbmatch(device_t parent, cfdata_t match, void *aux)
203 {
204 	struct tc_attach_args *ta = aux;
205 
206 	if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
207 		return (0);
208 
209 	return (1);
210 }
211 
212 static void
xcfbattach(device_t parent,device_t self,void * aux)213 xcfbattach(device_t parent, device_t self, void *aux)
214 {
215 	struct xcfb_softc *sc = device_private(self);
216 	struct tc_attach_args *ta = aux;
217 	struct rasops_info *ri;
218 	struct wsemuldisplaydev_attach_args waa;
219 	int console;
220 
221 	console = (ta->ta_addr == xcfb_consaddr);
222 	if (console) {
223 		sc->sc_ri = ri = &xcfb_console_ri;
224 		ri->ri_flg &= ~RI_NO_AUTO;
225 		sc->nscreens = 1;
226 	}
227 	else {
228 		ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_WAITOK | M_ZERO);
229 		ri->ri_hw = (void *)ioasic_base;
230 		xcfb_common_init(ri);
231 		sc->sc_ri = ri;
232 	}
233 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
234 
235 	xcfb_cmap_init(sc);
236 
237 	sc->sc_vaddr = ta->ta_addr;
238 	sc->sc_blanked = 0;
239 	sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
240 
241         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
242 
243 	waa.console = console;
244 	waa.scrdata = &xcfb_screenlist;
245 	waa.accessops = &xcfb_accessops;
246 	waa.accesscookie = sc;
247 
248 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
249 }
250 
251 static void
xcfb_cmap_init(struct xcfb_softc * sc)252 xcfb_cmap_init(struct xcfb_softc *sc)
253 {
254 	struct hwcmap256 *cm;
255 	const uint8_t *p;
256 	int index;
257 
258 	cm = &sc->sc_cmap;
259 	p = rasops_cmap;
260 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
261 		cm->r[index] = p[0];
262 		cm->g[index] = p[1];
263 		cm->b[index] = p[2];
264 	}
265 }
266 
267 static void
xcfb_common_init(struct rasops_info * ri)268 xcfb_common_init(struct rasops_info *ri)
269 {
270 	int cookie;
271 
272 	/* initialize colormap and cursor hardware */
273 	xcfbhwinit((void *)ri->ri_hw);
274 
275 	ri->ri_flg = RI_CENTER;
276 	if (ri == &xcfb_console_ri)
277 		ri->ri_flg |= RI_NO_AUTO;
278 	ri->ri_depth = 8;
279 	ri->ri_width = 1024;
280 	ri->ri_height = 768;
281 	ri->ri_stride = 1024;
282 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
283 
284 	/* clear the screen */
285 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
286 
287 	wsfont_init();
288 	/* prefer 12 pixel wide font */
289 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
290 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
291 	if (cookie <= 0)
292 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
293 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
294 	if (cookie <= 0) {
295 		printf("xcfb: font table is empty\n");
296 		return;
297 	}
298 
299 	if (wsfont_lock(cookie, &ri->ri_font)) {
300 		printf("xcfb: couldn't lock font\n");
301 		return;
302 	}
303 	ri->ri_wsfcookie = cookie;
304 
305 	rasops_init(ri, 34, 80);
306 
307 	/* XXX shouldn't be global */
308 	xcfb_stdscreen.nrows = ri->ri_rows;
309 	xcfb_stdscreen.ncols = ri->ri_cols;
310 	xcfb_stdscreen.textops = &ri->ri_ops;
311 	xcfb_stdscreen.capabilities = ri->ri_caps;
312 }
313 
314 int
xcfb_cnattach(void)315 xcfb_cnattach(void)
316 {
317 	struct rasops_info *ri;
318 	long defattr;
319 
320 	ri = &xcfb_console_ri;
321 	ri->ri_hw = (void *)ioasic_base;
322 	xcfb_common_init(ri);
323 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
324 	wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
325 	xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
326 	return (0);
327 }
328 
329 static void
xcfbhwinit(void * base)330 xcfbhwinit(void *base)
331 {
332 	volatile uint32_t *csr;
333 	uint32_t i;
334 	const uint8_t *p;
335 
336 	csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
337 	i = *csr;
338 	i &= ~XINE_CSR_VDAC_ENABLE;
339 	*csr = i;
340 	DELAY(50);
341 	i |= XINE_CSR_VDAC_ENABLE;
342 	*csr = i;
343 	DELAY(50);
344 	ims332_write_reg(IMS332_REG_BOOT, 0x2c);
345 	ims332_write_reg(IMS332_REG_CSR_A,
346 		IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
347 	ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
348 	ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
349 	ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
350 	ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
351 	ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
352 	ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
353 	ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
354 	ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
355 	ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
356 	ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
357 	ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
358 	ims332_write_reg(IMS332_REG_LINE_START, 0x10);
359 	ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
360 	ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
361 	ims332_write_reg(IMS332_REG_CSR_A,
362 		IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
363 
364 	/* build sane colormap */
365 	p = rasops_cmap;
366 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
367 		uint32_t bgr;
368 
369 		bgr = p[2] << 16 | p[1] << 8 | p[0];
370 		ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
371 	}
372 
373 	/* clear out cursor image */
374 	for (i = 0; i < 512; i++)
375 		ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
376 
377 	/*
378 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
379 	 * cursor image.  LUT_1 for mask color, while LUT_2 for
380 	 * image color.  LUT_0 will be never used.
381 	 */
382 	ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
383 	ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
384 	ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
385 }
386 
387 static int
xcfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)388 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
389 {
390 	struct xcfb_softc *sc = v;
391 	struct rasops_info *ri = sc->sc_ri;
392 	int turnoff, error;
393 
394 	switch (cmd) {
395 	case WSDISPLAYIO_GTYPE:
396 		*(u_int *)data = WSDISPLAY_TYPE_XCFB;
397 		return (0);
398 
399 	case WSDISPLAYIO_GET_FBINFO: {
400 		struct wsdisplayio_fbinfo *fbi = data;
401 		return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
402 	}
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
xcfbmmap(void * v,void * vs,off_t offset,int prot)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
xcfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)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
xcfb_free_screen(void * v,void * cookie)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
xcfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)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
xcfbintr(void * v)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
xcfb_screenblank(struct xcfb_softc * sc)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
get_cmap(struct xcfb_softc * sc,struct wsdisplay_cmap * p)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
set_cmap(struct xcfb_softc * sc,struct wsdisplay_cmap * p)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
set_cursor(struct xcfb_softc * sc,struct wsdisplay_cursor * p)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 || count > 2 - index)
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
get_cursor(struct xcfb_softc * sc,struct wsdisplay_cursor * p)653 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
654 {
655 	return (EPASSTHROUGH); /* XXX */
656 }
657 
658 static void
set_curpos(struct xcfb_softc * sc,struct wsdisplay_curpos * curpos)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
ims332_loadcmap(struct hwcmap256 * cm)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
ims332_set_curpos(struct xcfb_softc * sc)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
ims332_load_curcmap(struct xcfb_softc * sc)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
ims332_load_curshape(struct xcfb_softc * sc)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
ims332_write_reg(int regno,uint32_t val)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