xref: /netbsd-src/sys/dev/tc/stic.c (revision 1a8114347d4c0badc20f65e7e355aebec01f8270)
1 /*	$NetBSD: stic.c,v 1.59 2022/07/20 15:45:28 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
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 /*
33  * Driver for the DEC PixelStamp interface chip (STIC).
34  *
35  * XXX The bt459 interface shouldn't be replicated here.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: stic.c,v 1.59 2022/07/20 15:45:28 thorpej Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/buf.h>
47 #include <sys/ioctl.h>
48 #include <sys/callout.h>
49 #include <sys/conf.h>
50 #include <sys/kauth.h>
51 #include <sys/lwp.h>
52 #include <sys/event.h>
53 
54 #if defined(pmax)
55 #include <mips/cpuregs.h>
56 #elif defined(alpha)
57 #include <alpha/alpha_cpu.h>
58 #endif
59 
60 #include <machine/vmparam.h>
61 #include <sys/bus.h>
62 #include <sys/intr.h>
63 
64 #include <dev/wscons/wsconsio.h>
65 #include <dev/wscons/wsdisplayvar.h>
66 
67 #include <dev/wsfont/wsfont.h>
68 
69 #include <dev/ic/bt459reg.h>
70 
71 #include <dev/tc/tcvar.h>
72 #include <dev/tc/sticreg.h>
73 #include <dev/tc/sticio.h>
74 #include <dev/tc/sticvar.h>
75 
76 #define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff))
77 #define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff))
78 #define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff))
79 
80 #define PACK(p, o) ((p)[(o)] | ((p)[(o)+1] << 16))
81 
82 #if defined(pmax)
83 #define	machine_btop(x)		mips_btop(x)
84 #elif defined(alpha)
85 #define machine_btop(x)		alpha_btop(x)
86 #endif
87 
88 /*
89  * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
90  * obscure register layout such as 2nd and 3rd Bt459 registers are
91  * adjacent each other in a word, i.e.,
92  *	struct bt459triplet {
93  * 		struct {
94  *			uint8_t u0;
95  *			uint8_t u1;
96  *			uint8_t u2;
97  *			unsigned :8;
98  *		} bt_lo;
99  *		struct {
100  *
101  * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
102  *	struct bt459reg {
103  *		   uint32_t	   bt_lo;
104  *		   uint32_t	   bt_hi;
105  *		   uint32_t	   bt_reg;
106  *		   uint32_t	   bt_cmap;
107  *	};
108  *
109  */
110 
111 /* Bt459 hardware registers */
112 #define bt_lo	0
113 #define bt_hi	1
114 #define bt_reg	2
115 #define bt_cmap 3
116 
117 #define REG(base, index)	*((volatile uint32_t *)(base) + (index))
118 #define SELECT(vdac, regno) do {		\
119 	REG(vdac, bt_lo) = DUPBYTE0(regno);	\
120 	REG(vdac, bt_hi) = DUPBYTE1(regno);	\
121 	tc_wmb();				\
122    } while (0)
123 
124 static int	sticioctl(void *, void *, u_long, void *, int, struct lwp *);
125 static int	stic_alloc_screen(void *, const struct wsscreen_descr *,
126 				  void **, int *, int *, long *);
127 static void	stic_free_screen(void *, void *);
128 static int	stic_show_screen(void *, void *, int,
129 				 void (*)(void *, int, int), void *);
130 
131 static void	stic_do_switch(void *);
132 static void	stic_setup_backing(struct stic_info *, struct stic_screen *);
133 static void	stic_setup_vdac(struct stic_info *);
134 static void	stic_clear_screen(struct stic_info *);
135 
136 static int	stic_get_cmap(struct stic_info *, struct wsdisplay_cmap *);
137 static int	stic_set_cmap(struct stic_info *, struct wsdisplay_cmap *);
138 static int	stic_set_cursor(struct stic_info *, struct wsdisplay_cursor *);
139 static int	stic_get_cursor(struct stic_info *, struct wsdisplay_cursor *);
140 static void	stic_set_curpos(struct stic_info *, struct wsdisplay_curpos *);
141 static void	stic_set_hwcurpos(struct stic_info *);
142 
143 static void	stic_cursor(void *, int, int, int);
144 static void	stic_copycols(void *, int, int, int, int);
145 static void	stic_copyrows(void *, int, int, int);
146 static void	stic_erasecols(void *, int, int, int, long);
147 static void	stic_eraserows(void *, int, int, long);
148 static int	stic_mapchar(void *, int, u_int *);
149 static void	stic_putchar(void *, int, int, u_int, long);
150 static int	stic_allocattr(void *, int, int, int, long *);
151 
152 static dev_type_open(sticopen);
153 static dev_type_close(sticclose);
154 static dev_type_mmap(sticmmap);
155 
156 const struct cdevsw stic_cdevsw = {
157 	.d_open = sticopen,
158 	.d_close = sticclose,
159 	.d_read = noread,
160 	.d_write = nowrite,
161 	.d_ioctl = noioctl,
162 	.d_stop = nostop,
163 	.d_tty = notty,
164 	.d_poll = nopoll,
165 	.d_mmap = sticmmap,
166 	.d_kqfilter = nokqfilter,
167 	.d_discard = nodiscard,
168 	.d_flag = 0
169 };
170 
171 /* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity. */
172 static const uint8_t stic_cmap[16*3] = {
173 	0x00, 0x00, 0x00, /* black */
174 	0x7f, 0x00, 0x00, /* red */
175 	0x00, 0x7f, 0x00, /* green */
176 	0x7f, 0x7f, 0x00, /* brown */
177 	0x00, 0x00, 0x7f, /* blue */
178 	0x7f, 0x00, 0x7f, /* magenta */
179 	0x00, 0x7f, 0x7f, /* cyan */
180 	0xc7, 0xc7, 0xc7, /* white */
181 
182 	0x7f, 0x7f, 0x7f, /* black */
183 	0xff, 0x00, 0x00, /* red */
184 	0x00, 0xff, 0x00, /* green */
185 	0xff, 0xff, 0x00, /* brown */
186 	0x00, 0x00, 0xff, /* blue */
187 	0xff, 0x00, 0xff, /* magenta */
188 	0x00, 0xff, 0xff, /* cyan */
189 	0xff, 0xff, 0xff, /* white */
190 };
191 
192 /*
193  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
194  *   M M M M I I I I		M I M I M I M I
195  *	[ before ]		   [ after ]
196  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
197  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
198  */
199 static const uint8_t shuffle[256] = {
200 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
201 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
202 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
203 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
204 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
205 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
206 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
207 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
208 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
209 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
210 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
211 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
212 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
213 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
214 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
215 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
216 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
217 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
218 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
219 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
220 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
221 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
222 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
223 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
224 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
225 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
226 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
227 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
228 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
229 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
230 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
231 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
232 };
233 
234 static const struct wsdisplay_accessops stic_accessops = {
235 	sticioctl,
236 	NULL,			/* mmap */
237 	stic_alloc_screen,
238 	stic_free_screen,
239 	stic_show_screen,
240 	NULL,			/* load_font */
241 };
242 
243 static const struct wsdisplay_emulops stic_emulops = {
244 	stic_cursor,
245 	stic_mapchar,
246 	stic_putchar,
247 	stic_copycols,
248 	stic_erasecols,
249 	stic_copyrows,
250 	stic_eraserows,
251 	stic_allocattr
252 };
253 
254 static struct wsscreen_descr stic_stdscreen = {
255 	"std",
256 	0, 0,
257 	&stic_emulops,
258 	0, 0,
259 	WSSCREEN_WSCOLORS | WSSCREEN_HILIT
260 };
261 
262 static const struct wsscreen_descr *_stic_scrlist[] = {
263 	&stic_stdscreen,
264 };
265 
266 static const struct wsscreen_list stic_screenlist = {
267 	sizeof(_stic_scrlist) / sizeof(struct wsscreen_descr *), _stic_scrlist
268 };
269 
270 struct	stic_info stic_consinfo;
271 static struct	stic_screen stic_consscr;
272 static struct	stic_info *stic_info[STIC_MAXDV];
273 static int	stic_unit;
274 
275 void
stic_init(struct stic_info * si)276 stic_init(struct stic_info *si)
277 {
278 	volatile uint32_t *vdac;
279 	int i, cookie;
280 
281 	/* Reset the STIC & stamp(s). */
282 	stic_reset(si);
283 	vdac = si->si_vdac;
284 
285 	/* Hit it... */
286 	SELECT(vdac, BT459_IREG_COMMAND_0);
287 	REG(vdac, bt_reg) = 0x00c0c0c0; tc_wmb();
288 
289 	/* Now reset the VDAC. */
290 	*si->si_vdac_reset = 0;
291 	tc_syncbus();
292 	DELAY(1000);
293 
294 	/* Finish the initialization. */
295 	SELECT(vdac, BT459_IREG_COMMAND_1);
296 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
297 	REG(vdac, bt_reg) = 0x00c2c2c2; tc_wmb();
298 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
299 
300 	for (i = 0; i < 7; i++) {
301 		REG(vdac, bt_reg) = 0x00000000;
302 		tc_wmb();
303 	}
304 
305 	/* Set cursor colormap. */
306 	SELECT(vdac, BT459_IREG_CCOLOR_1);
307 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
308 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
309 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
310 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
311 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
312 	REG(vdac, bt_reg) = 0x00000000; tc_wmb();
313 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
314 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
315 	REG(vdac, bt_reg) = 0x00ffffff; tc_wmb();
316 
317 	/* Get a font and set up screen metrics. */
318 	wsfont_init();
319 
320 	cookie = wsfont_find(NULL, 12, 0, 2, WSDISPLAY_FONTORDER_R2L,
321 	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
322 	if (cookie <= 0)
323 		cookie = wsfont_find(NULL, 0, 0, 2, WSDISPLAY_FONTORDER_R2L,
324 		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
325 	if (cookie <= 0)
326 		panic("stic_init: font table is empty");
327 
328 	if (wsfont_lock(cookie, &si->si_font))
329 		panic("stic_init: couldn't lock font");
330 
331 	si->si_fontw = si->si_font->fontwidth;
332 	si->si_fonth = si->si_font->fontheight;
333 	si->si_consw = (1280 / si->si_fontw) & ~1;
334 	si->si_consh = 1024 / si->si_fonth;
335 	stic_stdscreen.ncols = si->si_consw;
336 	stic_stdscreen.nrows = si->si_consh;
337 
338 #ifdef DIAGNOSTIC
339 	if ((u_int)si->si_fonth > 32 || (u_int)si->si_fontw > 16)
340 		panic("stic_init: unusable font");
341 #endif
342 
343 	stic_setup_vdac(si);
344 	stic_clear_screen(si);
345 	si->si_dispmode = WSDISPLAYIO_MODE_EMUL;
346 }
347 
348 void
stic_reset(struct stic_info * si)349 stic_reset(struct stic_info *si)
350 {
351 	int modtype, xconfig, yconfig, config;
352 	volatile struct stic_regs *sr;
353 
354 	sr = si->si_stic;
355 
356 	/*
357 	 * Initialize the interface chip registers.
358 	 */
359 	sr->sr_sticsr = 0x00000030;	/* Get the STIC's attention. */
360 	tc_syncbus();
361 	DELAY(2000);			/* wait 2ms for STIC to respond. */
362 	sr->sr_sticsr = 0x00000000;	/* Hit the STIC's csr again... */
363 	tc_wmb();
364 	sr->sr_buscsr = 0xffffffff;	/* and bash its bus-access csr. */
365 	tc_syncbus();			/* Blam! */
366 	DELAY(20000);			/* wait until the stic recovers... */
367 
368 	modtype = sr->sr_modcl;
369 	xconfig = (modtype & 0x800) >> 11;
370 	yconfig = (modtype & 0x600) >> 9;
371 	config = (yconfig << 1) | xconfig;
372 	si->si_stampw = (xconfig ? 5 : 4);
373 	si->si_stamph = (1 << yconfig);
374 	si->si_stamphm = si->si_stamph - 1;
375 #ifdef notyet
376 	si->si_option = (char)((modtype >> 12) & 3);
377 #endif
378 
379 	/* First PixelStamp */
380 	si->si_stamp[0x000b0] = config;
381 	si->si_stamp[0x000b4] = 0x0;
382 
383 	/* Second PixelStamp */
384 	if (yconfig > 0) {
385 		si->si_stamp[0x100b0] = config | 8;
386 		si->si_stamp[0x100b4] = 0;
387 	}
388 
389 	/*
390 	 * Initialize STIC video registers.  Enable error and vertical
391 	 * retrace interrupts.  Set the packet done flag so the Xserver will
392 	 * not time-out on the first packet submitted.
393 	 */
394 	sr->sr_vblank = (1024 << 16) | 1063;
395 	sr->sr_vsync = (1027 << 16) | 1030;
396 	sr->sr_hblank = (255 << 16) | 340;
397 	sr->sr_hsync2 = 245;
398 	sr->sr_hsync = (261 << 16) | 293;
399 	sr->sr_ipdvint =
400 	    STIC_INT_WE | STIC_INT_P | STIC_INT_E_EN | STIC_INT_V_EN;
401 	sr->sr_sticsr = 8;
402 	tc_syncbus();
403 }
404 
405 void
stic_attach(device_t self,struct stic_info * si,int console)406 stic_attach(device_t self, struct stic_info *si, int console)
407 {
408 	struct wsemuldisplaydev_attach_args waa;
409 
410 	if (stic_unit < STIC_MAXDV) {
411 		stic_info[stic_unit] = si;
412 		si->si_unit = stic_unit++;
413 	} else
414 		si->si_unit = -1;
415 
416 	callout_init(&si->si_switch_callout, 0);
417 
418 	/*
419 	 * Allocate backing for the console.  We could trawl back through
420 	 * msgbuf and fill the backing, but it's not worth the hassle.
421 	 * We could also grab backing using pmap_steal_memory() early on,
422 	 * but that's a little ugly.
423 	 */
424 	if (console)
425 		stic_setup_backing(si, &stic_consscr);
426 
427 	waa.console = console;
428 	waa.scrdata = &stic_screenlist;
429 	waa.accessops = &stic_accessops;
430 	waa.accesscookie = si;
431 
432 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
433 }
434 
435 void
stic_cnattach(struct stic_info * si)436 stic_cnattach(struct stic_info *si)
437 {
438 	struct stic_screen *ss;
439 	long defattr;
440 
441 	ss = &stic_consscr;
442 	si->si_curscreen = ss;
443 	ss->ss_flags = SS_ALLOCED | SS_ACTIVE | SS_CURENB;
444 	ss->ss_si = si;
445 
446 	si->si_flags |= SI_CURENB_CHANGED;
447 	stic_flush(si);
448 
449 	stic_allocattr(ss, 0, 0, 0, &defattr);
450 	stic_eraserows(ss, 0, si->si_consh, 0);
451 	wsdisplay_cnattach(&stic_stdscreen, ss, 0, 0, defattr);
452 }
453 
454 static void
stic_setup_vdac(struct stic_info * si)455 stic_setup_vdac(struct stic_info *si)
456 {
457 	uint8_t *ip, *mp;
458 	int r, c, o, b, i, s;
459 
460 	s = spltty();
461 
462 	ip = (uint8_t *)si->si_cursor.cc_image;
463 	mp = (uint8_t *)si->si_cursor.cc_mask;
464 	memset(ip, 0, sizeof(si->si_cursor.cc_image));
465 	memset(mp, 0, sizeof(si->si_cursor.cc_mask));
466 
467 	for (r = 0; r < si->si_fonth; r++) {
468 		for (c = r & 1; c < si->si_fontw; c += 2) {
469 			o = c >> 3;
470 			b = 1 << (c & 7);
471 			ip[o] |= b;
472 			mp[o] |= b;
473 		}
474 
475 		ip += 8;
476 		mp += 8;
477 	}
478 
479 	si->si_cursor.cc_size.x = 64;
480 	si->si_cursor.cc_size.y = si->si_fonth;
481 	si->si_cursor.cc_hot.x = 0;
482 	si->si_cursor.cc_hot.y = 0;
483 
484 	si->si_cursor.cc_color[0] = 0xff;
485 	si->si_cursor.cc_color[2] = 0xff;
486 	si->si_cursor.cc_color[4] = 0xff;
487 	si->si_cursor.cc_color[1] = 0x00;
488 	si->si_cursor.cc_color[3] = 0x00;
489 	si->si_cursor.cc_color[5] = 0x00;
490 
491 	memset(&si->si_cmap, 0, sizeof(si->si_cmap));
492 	for (i = 0; i < 16; i++) {
493 		si->si_cmap.r[i] = stic_cmap[i*3 + 0];
494 		si->si_cmap.g[i] = stic_cmap[i*3 + 1];
495 		si->si_cmap.b[i] = stic_cmap[i*3 + 2];
496 	}
497 
498 	si->si_flags |= SI_CMAP_CHANGED | SI_CURSHAPE_CHANGED |
499 	    SI_CURCMAP_CHANGED;
500 
501 	splx(s);
502 }
503 
504 static void
stic_clear_screen(struct stic_info * si)505 stic_clear_screen(struct stic_info *si)
506 {
507 	uint32_t *pb;
508 	int i;
509 
510 	/*
511 	 * Do this twice, since the first packet after a reset may be
512 	 * silently ignored.
513 	 */
514 	for (i = 0; i < 2; i++) {
515 		pb = (*si->si_pbuf_get)(si);
516 
517 		pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
518 		pb[1] = 0x01ffffff;
519 		pb[2] = 0;
520 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
521 		pb[4] = (1024 << 2) - 1;
522 		pb[5] = 0;
523 		pb[6] = 0;
524 		pb[7] = (1280 << 19) | ((1024 << 3) + pb[4]);
525 
526 		(*si->si_pbuf_post)(si, pb);
527 	}
528 }
529 
530 static int
sticioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)531 sticioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
532 {
533 	struct stic_info *si;
534 	int s;
535 
536 	si = v;
537 
538 	switch (cmd) {
539 	case WSDISPLAYIO_GTYPE:
540 		*(u_int *)data = si->si_disptype;
541 		return (0);
542 
543 	case WSDISPLAYIO_GINFO:
544 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
545 		wsd_fbip->height = 1024;
546 		wsd_fbip->width = 1280;
547 		wsd_fbip->depth = si->si_depth == 8 ? 8 : 32;
548 		wsd_fbip->cmsize = CMAP_SIZE;
549 #undef fbt
550 		return (0);
551 
552 	case WSDISPLAYIO_GETCMAP:
553 		return (stic_get_cmap(si, (struct wsdisplay_cmap *)data));
554 
555 	case WSDISPLAYIO_PUTCMAP:
556 		return (stic_set_cmap(si, (struct wsdisplay_cmap *)data));
557 
558 	case WSDISPLAYIO_SVIDEO:
559 #if 0 /* XXX later */
560 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
561 		if ((si->si_blanked == 0) ^ turnoff)
562 			si->si_blanked = turnoff;
563 #endif
564 		return (0);
565 
566 	case WSDISPLAYIO_GVIDEO:
567 #if 0 /* XXX later */
568 		*(u_int *)data = si->si_blanked ?
569 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
570 #endif
571 		return (0);
572 
573 	case WSDISPLAYIO_GCURPOS:
574 		*(struct wsdisplay_curpos *)data = si->si_cursor.cc_pos;
575 		return (0);
576 
577 	case WSDISPLAYIO_SCURPOS:
578 		stic_set_curpos(si, (struct wsdisplay_curpos *)data);
579 		return (0);
580 
581 	case WSDISPLAYIO_GCURMAX:
582 		((struct wsdisplay_curpos *)data)->x =
583 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
584 		return (0);
585 
586 	case WSDISPLAYIO_GCURSOR:
587 		return (stic_get_cursor(si, (struct wsdisplay_cursor *)data));
588 
589 	case WSDISPLAYIO_SCURSOR:
590 		return (stic_set_cursor(si, (struct wsdisplay_cursor *)data));
591 
592 	case WSDISPLAYIO_SMODE:
593 		si->si_dispmode = *(int *)data;
594 		if (si->si_dispmode == WSDISPLAYIO_MODE_EMUL) {
595 			(*si->si_ioctl)(si, STICIO_STOPQ, NULL, flag, l);
596 			stic_setup_vdac(si);
597 			s = spltty();
598 			stic_flush(si);
599 			splx(s);
600 			stic_clear_screen(si);
601 			stic_do_switch(si->si_curscreen);
602 		}
603 		return (0);
604 
605 	case STICIO_RESET:
606 		stic_reset(si);
607 		return (0);
608 	}
609 
610 	if (si->si_ioctl != NULL)
611 		return ((*si->si_ioctl)(si, cmd, data, flag, l));
612 
613 	return (EPASSTHROUGH);
614 }
615 
616 static void
stic_setup_backing(struct stic_info * si,struct stic_screen * ss)617 stic_setup_backing(struct stic_info *si, struct stic_screen *ss)
618 {
619 	int size;
620 
621 	size = si->si_consw * si->si_consh * sizeof(*ss->ss_backing);
622 	ss->ss_backing = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
623 }
624 
625 static int
stic_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)626 stic_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
627 		  int *curxp, int *curyp, long *attrp)
628 {
629 	struct stic_info *si;
630 	struct stic_screen *ss;
631 
632 	si = (struct stic_info *)v;
633 
634 	if ((stic_consscr.ss_flags & SS_ALLOCED) == 0)
635 		ss = &stic_consscr;
636 	else {
637 		ss = malloc(sizeof(*ss), M_DEVBUF, M_WAITOK|M_ZERO);
638 	}
639 	stic_setup_backing(si, ss);
640 
641 	ss->ss_si = si;
642 	ss->ss_flags = SS_ALLOCED | SS_CURENB;
643 
644 	*cookiep = ss;
645 	*curxp = 0;
646 	*curyp = 0;
647 
648 	stic_allocattr(ss, 0, 0, 0, attrp);
649 	return (0);
650 }
651 
652 static void
stic_free_screen(void * v,void * cookie)653 stic_free_screen(void *v, void *cookie)
654 {
655 	struct stic_screen *ss;
656 
657 	ss = cookie;
658 
659 #ifdef DIAGNOSTIC
660 	if (ss == &stic_consscr)
661 		panic("stic_free_screen: console");
662 	if (ss == ((struct stic_info *)v)->si_curscreen)
663 		panic("stic_free_screen: freeing current screen");
664 #endif
665 
666 	free(ss->ss_backing, M_DEVBUF);
667 	free(ss, M_DEVBUF);
668 }
669 
670 static int
stic_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)671 stic_show_screen(void *v, void *cookie, int waitok,
672 		 void (*cb)(void *, int, int), void *cbarg)
673 {
674 	struct stic_info *si;
675 
676 	si = (struct stic_info *)v;
677 	if (si->si_switchcbarg != NULL)
678 		return (EAGAIN);
679 	si->si_switchcb = cb;
680 	si->si_switchcbarg = cbarg;
681 
682 	if (cb != NULL) {
683 		callout_reset(&si->si_switch_callout, 0, stic_do_switch,
684 		    cookie);
685 		return (EAGAIN);
686 	}
687 
688 	stic_do_switch(cookie);
689 	return (0);
690 }
691 
692 static void
stic_do_switch(void * cookie)693 stic_do_switch(void *cookie)
694 {
695 	struct stic_screen *ss;
696 	struct stic_info *si;
697 	u_int r, c, nr, nc;
698 	uint16_t *p, *sp;
699 
700 	ss = cookie;
701 	si = ss->ss_si;
702 
703 #ifdef DIAGNOSTIC
704 	if (ss->ss_backing == NULL)
705 		panic("stic_do_switch: screen not backed");
706 #endif
707 
708 	/* Swap in the new screen, and temporarily disable its backing. */
709 	if (si->si_curscreen != NULL)
710 		si->si_curscreen->ss_flags ^= SS_ACTIVE;
711 	si->si_curscreen = ss;
712 	ss->ss_flags |= SS_ACTIVE;
713 	sp = ss->ss_backing;
714 	ss->ss_backing = NULL;
715 
716 	/*
717 	 * We assume that most of the screen is blank and blast it with
718 	 * eraserows(), because eraserows() is cheap.
719 	 */
720 	nr = si->si_consh;
721 	stic_eraserows(ss, 0, nr, 0);
722 
723 	nc = si->si_consw;
724 	p = sp;
725 	for (r = 0; r < nr; r++)
726 		for (c = 0; c < nc; c += 2, p += 2) {
727 			if ((p[0] & 0xfff0) != 0)
728 				stic_putchar(ss, r, c, p[0] >> 8,
729 				    p[0] & 0x00ff);
730 			if ((p[1] & 0xfff0) != 0)
731 				stic_putchar(ss, r, c + 1, p[1] >> 8,
732 				    p[1] & 0x00ff);
733 		}
734 
735 	/*
736 	 * Re-enable the screen's backing, and move the cursor to the
737 	 * correct spot.
738 	 */
739 	ss->ss_backing = sp;
740 	si->si_cursor.cc_pos.x = ss->ss_curx;
741 	si->si_cursor.cc_pos.y = ss->ss_cury;
742 	stic_set_hwcurpos(si);
743 	si->si_flags |= SI_CURENB_CHANGED;
744 
745 	/*
746 	 * XXX Since we don't yet receive vblank interrupts from the
747 	 * PXG, we must flush immediately.
748 	 */
749 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
750 		stic_flush(si);
751 
752 	/* Tell wscons that we're done. */
753 	if (si->si_switchcbarg != NULL) {
754 		cookie = si->si_switchcbarg;
755 		si->si_switchcbarg = NULL;
756 		(*si->si_switchcb)(cookie, 0, 0);
757 	}
758 }
759 
760 static int
stic_allocattr(void * cookie,int fg,int bg,int flags,long * attr)761 stic_allocattr(void *cookie, int fg, int bg, int flags, long *attr)
762 {
763 	long tmp;
764 
765 	if ((flags & (WSATTR_BLINK | WSATTR_UNDERLINE)) != 0)
766 		return (EINVAL);
767 
768 	if ((flags & WSATTR_WSCOLORS) == 0) {
769 		fg = 7;
770 		bg = 0;
771 	}
772 
773 	if ((flags & WSATTR_HILIT) != 0)
774 		fg += 8;
775 
776 	tmp = fg | (bg << 4);
777 	*attr = tmp | (tmp << 16);
778 	return (0);
779 }
780 
781 static void
stic_erasecols(void * cookie,int row,int col,int num,long attr)782 stic_erasecols(void *cookie, int row, int col, int num, long attr)
783 {
784 	struct stic_info *si;
785 	struct stic_screen *ss;
786 	uint32_t *pb;
787 	u_int i, linewidth;
788 	uint16_t *p;
789 
790 	ss = cookie;
791 	si = ss->ss_si;
792 
793 	if (ss->ss_backing != NULL) {
794 		p = ss->ss_backing + row * si->si_consw + col;
795 		for (i = num; i != 0; i--)
796 			*p++ = (uint16_t)attr;
797 	}
798 	if ((ss->ss_flags & SS_ACTIVE) == 0)
799 		return;
800 
801 	col = (col * si->si_fontw) << 19;
802 	num = (num * si->si_fontw) << 19;
803 	row = row * si->si_fonth;
804 	attr = (attr & 0xf0) >> 4;
805 	linewidth = (si->si_fonth << 2) - 1;
806 	row = (row << 3) + linewidth;
807 
808 	pb = (*si->si_pbuf_get)(si);
809 
810 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
811 	pb[1] = 0x01ffffff;
812 	pb[2] = 0;
813 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
814 	pb[4] = linewidth;
815 	pb[5] = DUPBYTE0(attr);
816 	pb[6] = col | row;
817 	pb[7] = (col + num) | row;
818 
819 	(*si->si_pbuf_post)(si, pb);
820 }
821 
822 static void
stic_eraserows(void * cookie,int row,int num,long attr)823 stic_eraserows(void *cookie, int row, int num, long attr)
824 {
825 	struct stic_info *si;
826 	struct stic_screen *ss;
827 	u_int linewidth, i;
828 	uint32_t *pb;
829 
830 	ss = cookie;
831 	si = ss->ss_si;
832 
833 	if (ss->ss_backing != NULL) {
834 		pb = (uint32_t *)(ss->ss_backing + row * si->si_consw);
835 		for (i = si->si_consw * num; i > 0; i -= 2)
836 			*pb++ = (uint32_t)attr;
837 	}
838 	if ((ss->ss_flags & SS_ACTIVE) == 0)
839 		return;
840 
841 	row *= si->si_fonth;
842 	num *= si->si_fonth;
843 	attr = (attr & 0xf0) >> 4;
844 	linewidth = (num << 2) - 1;
845 	row = (row << 3) + linewidth;
846 
847 	pb = (*si->si_pbuf_get)(si);
848 
849 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_CONST | STAMP_LW_PERPACKET;
850 	pb[1] = 0x01ffffff;
851 	pb[2] = 0;
852 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY;
853 	pb[4] = linewidth;
854 	pb[5] = DUPBYTE0(attr);
855 	pb[6] = row;
856 	pb[7] = (1280 << 19) | row;
857 
858 	(*si->si_pbuf_post)(si, pb);
859 }
860 
861 static void
stic_copyrows(void * cookie,int src,int dst,int height)862 stic_copyrows(void *cookie, int src, int dst, int height)
863 {
864 	struct stic_info *si;
865 	struct stic_screen *ss;
866 	uint32_t *pb, *pbs;
867 	u_int num, inc, adj;
868 
869 	ss = cookie;
870 	si = ss->ss_si;
871 
872 	if (ss->ss_backing != NULL)
873 		bcopy(ss->ss_backing + src * si->si_consw,
874 		    ss->ss_backing + dst * si->si_consw,
875 		    si->si_consw * sizeof(*ss->ss_backing) * height);
876 	if ((ss->ss_flags & SS_ACTIVE) == 0)
877 		return;
878 
879 	/*
880 	 * We need to do this in reverse if the destination row is below
881 	 * the source.
882 	 */
883 	if (dst > src) {
884 		src += height;
885 		dst += height;
886 		inc = -8;
887 		adj = -1;
888 	} else {
889 		inc = 8;
890 		adj = 0;
891 	}
892 
893 	src = (src * si->si_fonth + adj) << 3;
894 	dst = (dst * si->si_fonth + adj) << 3;
895 	height *= si->si_fonth;
896 
897 	while (height > 0) {
898 		num = (height < 255 ? height : 255);
899 		height -= num;
900 
901 		pbs = (*si->si_pbuf_get)(si);
902 		pb = pbs;
903 
904 		pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
905 		pb[1] = (num << 24) | 0xffffff;
906 		pb[2] = 0x0;
907 		pb[3] = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN |
908 		    STAMP_COPYSPAN_ALIGNED;
909 		pb[4] = 1; /* linewidth */
910 
911 		for (; num != 0; num--, src += inc, dst += inc, pb += 3) {
912 			pb[5] = 1280 << 3;
913 			pb[6] = src;
914 			pb[7] = dst;
915 		}
916 
917 	    	(*si->si_pbuf_post)(si, pbs);
918 	}
919 }
920 
921 static void
stic_copycols(void * cookie,int row,int src,int dst,int num)922 stic_copycols(void *cookie, int row, int src, int dst, int num)
923 {
924 	struct stic_info *si;
925 	struct stic_screen *ss;
926 	u_int height, updword;
927 	uint32_t *pb, *pbs;
928 
929 	ss = cookie;
930 	si = ss->ss_si;
931 
932 	if (ss->ss_backing != NULL)
933 		bcopy(ss->ss_backing + row * si->si_consw + src,
934 		    ss->ss_backing + row * si->si_consw + dst,
935 		    num * sizeof(*ss->ss_backing));
936 	if ((ss->ss_flags & SS_ACTIVE) == 0)
937 		return;
938 
939 	/*
940 	 * The stamp reads and writes left -> right only, so we need to
941 	 * buffer the span if the source and destination regions overlap
942 	 * and the source is left of the destination.
943 	 */
944 	updword = STAMP_UPDATE_ENABLE | STAMP_METHOD_COPY | STAMP_SPAN;
945 
946 	if (src < dst && src + num > dst)
947 		updword |= STAMP_HALF_BUFF;
948 
949 	row = (row * si->si_fonth) << 3;
950 	num = (num * si->si_fontw) << 3;
951 	src = row | ((src * si->si_fontw) << 19);
952 	dst = row | ((dst * si->si_fontw) << 19);
953 	height = si->si_fonth;
954 
955 	pbs = (*si->si_pbuf_get)(si);
956 	pb = pbs;
957 
958 	pb[0] = STAMP_CMD_COPYSPANS | STAMP_LW_PERPACKET;
959 	pb[1] = (height << 24) | 0xffffff;
960 	pb[2] = 0x0;
961 	pb[3] = updword;
962 	pb[4] = 1; /* linewidth */
963 
964 	for ( ; height != 0; height--, src += 8, dst += 8, pb += 3) {
965 		pb[5] = num;
966 		pb[6] = src;
967 		pb[7] = dst;
968 	}
969 
970 	(*si->si_pbuf_post)(si, pbs);
971 }
972 
973 static void
stic_putchar(void * cookie,int r,int c,u_int uc,long attr)974 stic_putchar(void *cookie, int r, int c, u_int uc, long attr)
975 {
976 	struct wsdisplay_font *font;
977 	struct stic_screen *ss;
978 	struct stic_info *si;
979 	u_int i, bgcolor, fgcolor;
980 	u_int *pb, v1, v2, xya;
981 	u_short *fr;
982 
983 	ss = cookie;
984 	si = ss->ss_si;
985 
986 	/* It's cheaper to use erasecols() to blit blanks. */
987 	if (uc == 0) {
988 		stic_erasecols(cookie, r, c, 1, attr);
989 		return;
990 	}
991 
992 	if (ss->ss_backing != NULL)
993 		ss->ss_backing[r * si->si_consw + c] =
994 		    (u_short)((attr & 0xff) | (uc << 8));
995 	if ((ss->ss_flags & SS_ACTIVE) == 0)
996 		return;
997 
998 	font = si->si_font;
999 	pb = (*si->si_pbuf_get)(si);
1000 
1001 	/*
1002 	 * Create a mask from the glyph.  Squeeze the foreground color
1003 	 * through the mask, and then squeeze the background color through
1004 	 * the inverted mask.  We may well read outside the glyph when
1005 	 * creating the mask, but it's bounded by the hardware so it
1006 	 * shouldn't matter a great deal...
1007 	 */
1008 	pb[0] = STAMP_CMD_LINES | STAMP_RGB_FLAT | STAMP_XY_PERPRIMATIVE |
1009 	    STAMP_LW_PERPRIMATIVE;
1010 	pb[1] = font->fontheight > 16 ? 0x04ffffff : 0x02ffffff;
1011 	pb[2] = 0x0;
1012 	pb[3] = STAMP_UPDATE_ENABLE | STAMP_WE_XYMASK | STAMP_METHOD_COPY;
1013 
1014 	r *= font->fontheight;
1015 	c *= font->fontwidth;
1016 	uc = (uc - font->firstchar) * font->stride * font->fontheight;
1017 	fr = (u_short *)((char *)font->data + uc);
1018 	bgcolor = DUPBYTE0((attr & 0xf0) >> 4);
1019 	fgcolor = DUPBYTE0(attr & 0x0f);
1020 
1021 	i = ((font->fontheight > 16 ? 16 : font->fontheight) << 2) - 1;
1022 	v1 = (c << 19) | ((r << 3) + i);
1023 	v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1024 	xya = XYMASKADDR(si->si_stampw, si->si_stamphm, c, r, 0, 0);
1025 
1026 	pb[4] = PACK(fr, 0);
1027 	pb[5] = PACK(fr, 2);
1028 	pb[6] = PACK(fr, 4);
1029 	pb[7] = PACK(fr, 6);
1030 	pb[8] = PACK(fr, 8);
1031 	pb[9] = PACK(fr, 10);
1032 	pb[10] = PACK(fr, 12);
1033 	pb[11] = PACK(fr, 14);
1034 	pb[12] = xya;
1035 	pb[13] = v1;
1036 	pb[14] = v2;
1037 	pb[15] = i;
1038 	pb[16] = fgcolor;
1039 
1040 	pb[17] = ~pb[4];
1041 	pb[18] = ~pb[5];
1042 	pb[19] = ~pb[6];
1043 	pb[20] = ~pb[7];
1044 	pb[21] = ~pb[8];
1045 	pb[22] = ~pb[9];
1046 	pb[23] = ~pb[10];
1047 	pb[24] = ~pb[11];
1048 	pb[25] = xya;
1049 	pb[26] = v1;
1050 	pb[27] = v2;
1051 	pb[28] = i;
1052 	pb[29] = bgcolor;
1053 
1054 	/* Two more squeezes for the lower part of the character. */
1055 	if (font->fontheight > 16) {
1056 		i = ((font->fontheight - 16) << 2) - 1;
1057 		r += 16;
1058 		v1 = (c << 19) | ((r << 3) + i);
1059 		v2 = ((c + font->fontwidth) << 19) | (v1 & 0xffff);
1060 
1061 		pb[30] = PACK(fr, 16);
1062 		pb[31] = PACK(fr, 18);
1063 		pb[32] = PACK(fr, 20);
1064 		pb[33] = PACK(fr, 22);
1065 		pb[34] = PACK(fr, 24);
1066 		pb[35] = PACK(fr, 26);
1067 		pb[36] = PACK(fr, 28);
1068 		pb[37] = PACK(fr, 30);
1069 		pb[38] = xya;
1070 		pb[39] = v1;
1071 		pb[40] = v2;
1072 		pb[41] = i;
1073 		pb[42] = fgcolor;
1074 
1075 		pb[43] = ~pb[30];
1076 		pb[44] = ~pb[31];
1077 		pb[45] = ~pb[32];
1078 		pb[46] = ~pb[33];
1079 		pb[47] = ~pb[34];
1080 		pb[48] = ~pb[35];
1081 		pb[49] = ~pb[36];
1082 		pb[50] = ~pb[37];
1083 		pb[51] = xya;
1084 		pb[52] = v1;
1085 		pb[53] = v2;
1086 		pb[54] = i;
1087 		pb[55] = bgcolor;
1088 	}
1089 
1090 	(*si->si_pbuf_post)(si, pb);
1091 }
1092 
1093 static int
stic_mapchar(void * cookie,int c,u_int * cp)1094 stic_mapchar(void *cookie, int c, u_int *cp)
1095 {
1096 	struct stic_info *si;
1097 
1098 	si = ((struct stic_screen *)cookie)->ss_si;
1099 
1100 	if (c < si->si_font->firstchar || c == ' ') {
1101 		*cp = 0;
1102 		return (0);
1103 	}
1104 
1105 	if (c - si->si_font->firstchar >= si->si_font->numchars) {
1106 		*cp = 0;
1107 		return (0);
1108 	}
1109 
1110 	*cp = c;
1111 	return (5);
1112 }
1113 
1114 static void
stic_cursor(void * cookie,int on,int row,int col)1115 stic_cursor(void *cookie, int on, int row, int col)
1116 {
1117 	struct stic_screen *ss;
1118 	struct stic_info *si;
1119 	int s;
1120 
1121 	ss = cookie;
1122 	si = ss->ss_si;
1123 
1124 	ss->ss_curx = col * si->si_fontw;
1125 	ss->ss_cury = row * si->si_fonth;
1126 
1127 	s = spltty();
1128 
1129 	if (on)
1130 		ss->ss_flags |= SS_CURENB;
1131 	else
1132 		ss->ss_flags &= ~SS_CURENB;
1133 
1134 	if ((ss->ss_flags & SS_ACTIVE) != 0) {
1135 		si->si_cursor.cc_pos.x = ss->ss_curx;
1136 		si->si_cursor.cc_pos.y = ss->ss_cury;
1137 		si->si_flags |= SI_CURENB_CHANGED;
1138 		stic_set_hwcurpos(si);
1139 
1140 		/*
1141 		 * XXX Since we don't yet receive vblank interrupts from the
1142 		 * PXG, we must flush immediately.
1143 		 */
1144 		if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1145 			stic_flush(si);
1146 	}
1147 
1148 	splx(s);
1149 }
1150 
1151 void
stic_flush(struct stic_info * si)1152 stic_flush(struct stic_info *si)
1153 {
1154 	volatile uint32_t *vdac;
1155 	int v;
1156 
1157 	if ((si->si_flags & SI_ALL_CHANGED) == 0)
1158 		return;
1159 
1160 	vdac = si->si_vdac;
1161 	v = si->si_flags;
1162 	si->si_flags &= ~SI_ALL_CHANGED;
1163 
1164 	if ((v & SI_CURENB_CHANGED) != 0) {
1165 		SELECT(vdac, BT459_IREG_CCR);
1166 		if ((si->si_curscreen->ss_flags & SS_CURENB) != 0)
1167 			REG(vdac, bt_reg) = 0x00c0c0c0;
1168 		else
1169 			REG(vdac, bt_reg) = 0x00000000;
1170 		tc_wmb();
1171 	}
1172 
1173 	if ((v & SI_CURCMAP_CHANGED) != 0) {
1174 		uint8_t *cp;
1175 
1176 		cp = si->si_cursor.cc_color;
1177 
1178 		SELECT(vdac, BT459_IREG_CCOLOR_2);
1179 		REG(vdac, bt_reg) = DUPBYTE0(cp[1]);	tc_wmb();
1180 		REG(vdac, bt_reg) = DUPBYTE0(cp[3]);	tc_wmb();
1181 		REG(vdac, bt_reg) = DUPBYTE0(cp[5]);	tc_wmb();
1182 		REG(vdac, bt_reg) = DUPBYTE0(cp[0]);	tc_wmb();
1183 		REG(vdac, bt_reg) = DUPBYTE0(cp[2]);	tc_wmb();
1184 		REG(vdac, bt_reg) = DUPBYTE0(cp[4]);	tc_wmb();
1185 	}
1186 
1187 	if ((v & SI_CURSHAPE_CHANGED) != 0) {
1188 		uint8_t *ip, *mp, img, msk;
1189 		uint8_t u;
1190 		int bcnt;
1191 
1192 		ip = (uint8_t *)si->si_cursor.cc_image;
1193 		mp = (uint8_t *)si->si_cursor.cc_mask;
1194 
1195 		bcnt = 0;
1196 		SELECT(vdac, BT459_IREG_CRAM_BASE);
1197 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
1198 		while (bcnt < CURSOR_MAX_SIZE * 16) {
1199 			img = *ip++;
1200 			msk = *mp++;
1201 			img &= msk;	/* cookie off image */
1202 			u = (msk & 0x0f) << 4 | (img & 0x0f);
1203 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1204 			tc_wmb();
1205 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
1206 			REG(vdac, bt_reg) = DUPBYTE0(shuffle[u]);
1207 			tc_wmb();
1208 			bcnt += 2;
1209 		}
1210 	}
1211 
1212 	if ((v & SI_CMAP_CHANGED) != 0) {
1213 		struct stic_hwcmap256 *cm;
1214 		int index;
1215 
1216 		cm = &si->si_cmap;
1217 
1218 		SELECT(vdac, 0);
1219 		SELECT(vdac, 0);
1220 		for (index = 0; index < CMAP_SIZE; index++) {
1221 			REG(vdac, bt_cmap) = DUPBYTE0(cm->r[index]);
1222 			tc_wmb();
1223 			REG(vdac, bt_cmap) = DUPBYTE0(cm->g[index]);
1224 			tc_wmb();
1225 			REG(vdac, bt_cmap) = DUPBYTE0(cm->b[index]);
1226 			tc_wmb();
1227 		}
1228 	}
1229 }
1230 
1231 static int
stic_get_cmap(struct stic_info * si,struct wsdisplay_cmap * p)1232 stic_get_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1233 {
1234 	u_int index = p->index, count = p->count;
1235 	int error;
1236 
1237 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
1238 		return (EINVAL);
1239 
1240 	error = copyout(&si->si_cmap.r[index], p->red, count);
1241 	if (error)
1242 		return error;
1243 	error = copyout(&si->si_cmap.g[index], p->green, count);
1244 	if (error)
1245 		return error;
1246 	error = copyout(&si->si_cmap.b[index], p->blue, count);
1247 	return error;
1248 }
1249 
1250 static int
stic_set_cmap(struct stic_info * si,struct wsdisplay_cmap * p)1251 stic_set_cmap(struct stic_info *si, struct wsdisplay_cmap *p)
1252 {
1253 	struct stic_hwcmap256 cmap;
1254 	u_int index, count;
1255 	int s, error;
1256 
1257 	index = p->index;
1258 	count = p->count;
1259 
1260 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
1261 		return (EINVAL);
1262 
1263 	error = copyin(p->red, &cmap.r[index], count);
1264 	if (error)
1265 		return error;
1266 	error = copyin(p->green, &cmap.g[index], count);
1267 	if (error)
1268 		return error;
1269 	error = copyin(p->blue, &cmap.b[index], count);
1270 	if (error)
1271 		return error;
1272 
1273 	s = spltty();
1274 	memcpy(&si->si_cmap.r[index], &cmap.r[index], count);
1275 	memcpy(&si->si_cmap.g[index], &cmap.g[index], count);
1276 	memcpy(&si->si_cmap.b[index], &cmap.b[index], count);
1277 	si->si_flags |= SI_CMAP_CHANGED;
1278 	splx(s);
1279 
1280 	/*
1281 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1282 	 * must flush immediately.
1283 	 */
1284 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1285 		stic_flush(si);
1286 
1287 	return (0);
1288 }
1289 
1290 static int
stic_set_cursor(struct stic_info * si,struct wsdisplay_cursor * p)1291 stic_set_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1292 {
1293 #define	cc (&si->si_cursor)
1294 	u_int v, index = 0, count = 0, icount = 0;
1295 	struct stic_screen *ss;
1296 	uint8_t r[2], g[2], b[2], image[512], mask[512];
1297 	int s, error;
1298 
1299 	v = p->which;
1300 	ss = si->si_curscreen;
1301 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1302 		index = p->cmap.index;
1303 		count = p->cmap.count;
1304 		if (index >= 2 || count > 2 - index)
1305 			return (EINVAL);
1306 		error = copyin(p->cmap.red, &r[index], count);
1307 		if (error)
1308 			return error;
1309 		error = copyin(p->cmap.green, &g[index], count);
1310 		if (error)
1311 			return error;
1312 		error = copyin(p->cmap.blue, &b[index], count);
1313 		if (error)
1314 			return error;
1315 	}
1316 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1317 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
1318 			return (EINVAL);
1319 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
1320 		error = copyin(p->image, image, icount);
1321 		if (error)
1322 			return error;
1323 		error = copyin(p->mask, mask, icount);
1324 		if (error)
1325 			return error;
1326 	}
1327 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) != 0) {
1328 		if (v & WSDISPLAY_CURSOR_DOCUR)
1329 			cc->cc_hot = p->hot;
1330 		if (v & WSDISPLAY_CURSOR_DOPOS)
1331 			stic_set_curpos(si, &p->pos);
1332 	}
1333 
1334 	s = spltty();
1335 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
1336 		if (p->enable)
1337 			ss->ss_flags |= SS_CURENB;
1338 		else
1339 			ss->ss_flags &= ~SS_CURENB;
1340 		si->si_flags |= SI_CURENB_CHANGED;
1341 	}
1342 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
1343 		memcpy(&cc->cc_color[index], &r[index], count);
1344 		memcpy(&cc->cc_color[index + 2], &g[index], count);
1345 		memcpy(&cc->cc_color[index + 4], &b[index], count);
1346 		si->si_flags |= SI_CURCMAP_CHANGED;
1347 	}
1348 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
1349 		memset(cc->cc_image, 0, sizeof cc->cc_image);
1350 		memcpy(cc->cc_image, image, icount);
1351 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
1352 		memcpy(cc->cc_mask, mask, icount);
1353 		si->si_flags |= SI_CURSHAPE_CHANGED;
1354 	}
1355 	splx(s);
1356 
1357 	/*
1358 	 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1359 	 * must flush immediately.
1360 	 */
1361 	if (si->si_disptype == WSDISPLAY_TYPE_PXG)
1362 		stic_flush(si);
1363 
1364 	return (0);
1365 #undef cc
1366 }
1367 
1368 static int
stic_get_cursor(struct stic_info * si,struct wsdisplay_cursor * p)1369 stic_get_cursor(struct stic_info *si, struct wsdisplay_cursor *p)
1370 {
1371 
1372 	/* XXX */
1373 	return (EPASSTHROUGH);
1374 }
1375 
1376 static void
stic_set_curpos(struct stic_info * si,struct wsdisplay_curpos * curpos)1377 stic_set_curpos(struct stic_info *si, struct wsdisplay_curpos *curpos)
1378 {
1379 	int x, y;
1380 
1381 	x = curpos->x;
1382 	y = curpos->y;
1383 
1384 	if (y < 0)
1385 		y = 0;
1386 	else if (y > 1023)
1387 		y = 1023;
1388 	if (x < 0)
1389 		x = 0;
1390 	else if (x > 1279)
1391 		x = 1279;
1392 
1393 	si->si_cursor.cc_pos.x = x;
1394 	si->si_cursor.cc_pos.y = y;
1395 	stic_set_hwcurpos(si);
1396 }
1397 
1398 static void
stic_set_hwcurpos(struct stic_info * si)1399 stic_set_hwcurpos(struct stic_info *si)
1400 {
1401 	volatile uint32_t *vdac;
1402 	int x, y, s;
1403 
1404 	vdac = si->si_vdac;
1405 
1406 	x = si->si_cursor.cc_pos.x - si->si_cursor.cc_hot.x;
1407 	y = si->si_cursor.cc_pos.y - si->si_cursor.cc_hot.y;
1408 	x += STIC_MAGIC_X;
1409 	y += STIC_MAGIC_Y;
1410 
1411 	s = spltty();
1412 	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
1413 	REG(vdac, bt_reg) = DUPBYTE0(x); tc_wmb();
1414 	REG(vdac, bt_reg) = DUPBYTE1(x); tc_wmb();
1415 	REG(vdac, bt_reg) = DUPBYTE0(y); tc_wmb();
1416 	REG(vdac, bt_reg) = DUPBYTE1(y); tc_wmb();
1417 	splx(s);
1418 }
1419 
1420 /*
1421  * STIC control interface.  We have a separate device for mapping the board,
1422  * because access to the DMA engine means that it's possible to circumvent
1423  * the securelevel mechanism.
1424  */
1425 static int
sticopen(dev_t dev,int flag,int mode,struct lwp * l)1426 sticopen(dev_t dev, int flag, int mode, struct lwp *l)
1427 {
1428 	struct stic_info *si;
1429 	int s, error;
1430 
1431 	error = kauth_authorize_device_passthru(l->l_cred, dev,
1432 	    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, NULL);
1433 	if (error)
1434 		return (error);
1435 	if (minor(dev) >= STIC_MAXDV)
1436 		return (ENXIO);
1437 	if ((si = stic_info[minor(dev)]) == NULL)
1438 		return (ENXIO);
1439 
1440 	s = spltty();
1441 	if ((si->si_flags & SI_DVOPEN) != 0) {
1442 		splx(s);
1443 		return (EBUSY);
1444 	}
1445 	si->si_flags |= SI_DVOPEN;
1446 	splx(s);
1447 
1448 	return (0);
1449 }
1450 
1451 static int
sticclose(dev_t dev,int flag,int mode,struct lwp * l)1452 sticclose(dev_t dev, int flag, int mode, struct lwp *l)
1453 {
1454 	struct stic_info *si;
1455 	int s;
1456 
1457 	si = stic_info[minor(dev)];
1458 	s = spltty();
1459 	si->si_flags &= ~SI_DVOPEN;
1460 	splx(s);
1461 
1462 	return (0);
1463 }
1464 
1465 static paddr_t
sticmmap(dev_t dev,off_t offset,int prot)1466 sticmmap(dev_t dev, off_t offset, int prot)
1467 {
1468 	struct stic_info *si;
1469 	struct stic_xmap *sxm;
1470 	paddr_t pa;
1471 
1472 	si = stic_info[minor(dev)];
1473 	sxm = NULL;
1474 
1475 	if (si->si_dispmode != WSDISPLAYIO_MODE_MAPPED)
1476 		return (-1L);
1477 
1478 	if (offset < 0)
1479 		return ((paddr_t)-1L);
1480 
1481 	if (offset < sizeof(sxm->sxm_stic)) {
1482 		pa = STIC_KSEG_TO_PHYS(si->si_stic);
1483 		return (machine_btop(pa + offset));
1484 	}
1485 	offset -= sizeof(sxm->sxm_stic);
1486 
1487 	if (offset < sizeof(sxm->sxm_poll)) {
1488 		pa = STIC_KSEG_TO_PHYS(si->si_slotbase);
1489 		return (machine_btop(pa + offset));
1490 	}
1491 	offset -= sizeof(sxm->sxm_poll);
1492 
1493 	if (offset < si->si_buf_size)
1494 		return (machine_btop(si->si_buf_phys + offset));
1495 
1496 	return ((paddr_t)-1L);
1497 }
1498