xref: /netbsd-src/sys/dev/tc/sfbplus.c (revision 7cc2f76925f078d01ddc9e640a98f4ccfc9f8c3b)
1 /* $NetBSD: sfbplus.c,v 1.6 2000/09/09 06:15:17 nisimura Exp $ */
2 
3 /*
4  * Copyright (c) 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: sfbplus.c,v 1.6 2000/09/09 06:15:17 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 
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50 
51 #include <dev/rasops/rasops.h>
52 #include <dev/wsfont/wsfont.h>
53 
54 #include <dev/tc/tcvar.h>
55 #include <dev/ic/bt459reg.h>
56 #include <dev/ic/bt463reg.h>
57 #include <dev/tc/sfbreg.h>
58 #include <dev/pci/tgareg.h>
59 
60 #include <uvm/uvm_extern.h>
61 
62 #if defined(pmax)
63 #define	machine_btop(x) mips_btop(x)
64 #define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
65 #endif
66 
67 #if defined(__alpha__) || defined(alpha)
68 #define machine_btop(x) alpha_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
70 #endif
71 
72 /* Bt459/Bt463 hardware registers */
73 #define bt_lo	0
74 #define bt_hi	1
75 #define bt_reg	2
76 #define bt_cmap 3
77 
78 #define REG(base, index)	*((u_int32_t *)(base) + (index))
79 #define SELECT(vdac, regno) do {			\
80 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
81 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
82 	tc_wmb();					\
83    } while (0)
84 
85 struct fb_devconfig {
86 	vaddr_t dc_vaddr;		/* memory space virtual base address */
87 	paddr_t dc_paddr;		/* memory space physical base address */
88 	vsize_t dc_size;		/* size of slot memory */
89 	int	dc_wid;			/* width of frame buffer */
90 	int	dc_ht;			/* height of frame buffer */
91 	int	dc_depth;		/* depth, bits per pixel */
92 	int	dc_rowbytes;		/* bytes in a FB scan line */
93 	vaddr_t	dc_videobase;		/* base of flat frame buffer */
94 	int	dc_blanked;		/* currently has video disabled */
95 
96 	struct rasops_info rinfo;
97 };
98 
99 struct hwcmap256 {
100 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
101 	u_int8_t r[CMAP_SIZE];
102 	u_int8_t g[CMAP_SIZE];
103 	u_int8_t b[CMAP_SIZE];
104 };
105 
106 struct hwcursor64 {
107 	struct wsdisplay_curpos cc_pos;
108 	struct wsdisplay_curpos cc_hot;
109 	struct wsdisplay_curpos cc_size;
110 	struct wsdisplay_curpos cc_magic;
111 #define	CURSOR_MAX_SIZE	64
112 	u_int8_t cc_color[6];
113 	u_int64_t cc_image[64 + 64];
114 };
115 
116 struct hwops {
117 	void (*setlut) __P((void *, struct hwcmap256 *));
118 	void (*getlut) __P((void *, struct hwcmap256 *));
119 	void (*visible) __P((void *, int));
120 	void (*locate) __P((void *, int, int));
121 	void (*shape) __P((void *, struct wsdisplay_curpos *, u_int64_t *));
122 	void (*color) __P((void *, u_int8_t *));
123 };
124 
125 struct sfb_softc {
126 	struct device sc_dev;
127 	struct fb_devconfig *sc_dc;	/* device configuration */
128 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
129 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
130 	int sc_curenb;			/* cursor sprite enabled */
131 	int sc_changed;			/* need update of colormap */
132 #define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
133 #define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
134 #define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
135 #define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
136 #define	DATA_ALL_CHANGED	0x0f
137 	int nscreens;
138 	struct hwops sc_hwops;
139 	void *sc_hw0, *sc_hw1;
140 };
141 
142 #define	HX_MAGIC_X 368
143 #define	HX_MAGIC_Y 38
144 
145 static int  sfbpmatch __P((struct device *, struct cfdata *, void *));
146 static void sfbpattach __P((struct device *, struct device *, void *));
147 
148 struct cfattach sfbp_ca = {
149 	sizeof(struct sfb_softc), sfbpmatch, sfbpattach,
150 };
151 
152 static void sfbp_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
153 static struct fb_devconfig sfbp_console_dc;
154 static tc_addr_t sfbp_consaddr;
155 
156 extern const struct wsdisplay_emulops sfbp_emulops, sfbp_emulops32;
157 
158 static struct wsscreen_descr sfb_stdscreen = {
159 	"std", 0, 0,
160 	NULL, /* textops */
161 	0, 0,
162 	WSSCREEN_REVERSE
163 };
164 
165 static const struct wsscreen_descr *_sfb_scrlist[] = {
166 	&sfb_stdscreen,
167 };
168 
169 static const struct wsscreen_list sfb_screenlist = {
170 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
171 };
172 
173 static int	sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
174 static paddr_t	sfbmmap __P((void *, off_t, int));
175 
176 static int	sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
177 				      void **, int *, int *, long *));
178 static void	sfb_free_screen __P((void *, void *));
179 static int	sfb_show_screen __P((void *, void *, int,
180 				     void (*) (void *, int, int), void *));
181 /* EXPORT */ int  sfb_alloc_attr __P((void *, int, int, int, long *));
182 
183 static const struct wsdisplay_accessops sfb_accessops = {
184 	sfbioctl,
185 	sfbmmap,
186 	sfb_alloc_screen,
187 	sfb_free_screen,
188 	sfb_show_screen,
189 	0 /* load_font */
190 };
191 
192 static void bt459visible __P((void *, int));
193 static void bt459locate __P((void *, int, int));
194 static void bt459shape __P((void *, struct wsdisplay_curpos *, u_int64_t *));
195 static void bt459color __P((void *, u_int8_t *));
196 static void bt459setlut __P((void *, struct hwcmap256 *));
197 
198 static void sfbpvisible __P((void *, int));
199 static void sfbplocate __P((void *, int, int));
200 static void sfbpshape __P((void *, struct wsdisplay_curpos *, u_int64_t *));
201 static void bt463color __P((void *, u_int8_t *));
202 static void noplut __P((void *, struct hwcmap256 *));
203 
204 
205 /* EXPORT */ int sfbp_cnattach __P((tc_addr_t));
206 static int  sfbpintr __P((void *));
207 static void sfbpinit __P((struct fb_devconfig *));
208 
209 static int  get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
210 static int  set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
211 static int  set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
212 static int  get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
213 
214 
215 /*
216  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
217  *   M M M M I I I I		M I M I M I M I
218  *	[ before ]		   [ after ]
219  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
220  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
221  */
222 static const u_int8_t shuffle[256] = {
223 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
224 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
225 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
226 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
227 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
228 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
229 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
230 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
231 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
232 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
233 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
234 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
235 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
236 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
237 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
238 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
239 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
240 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
241 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
242 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
243 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
244 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
245 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
246 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
247 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
248 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
249 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
250 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
251 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
252 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
253 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
254 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
255 };
256 
257 static int
258 sfbpmatch(parent, match, aux)
259 	struct device *parent;
260 	struct cfdata *match;
261 	void *aux;
262 {
263 	struct tc_attach_args *ta = aux;
264 
265 	if (strncmp("PMAGD", ta->ta_modname, 5) != 0)
266 		return (0);
267 
268 	return (1);
269 }
270 
271 static void
272 sfbp_getdevconfig(dense_addr, dc)
273 	tc_addr_t dense_addr;
274 	struct fb_devconfig *dc;
275 {
276 	caddr_t sfbasic;
277 	int i, hsetup, vsetup, vbase, cookie;
278 
279 	dc->dc_vaddr = dense_addr;
280 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
281 
282 	sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
283 	hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
284 	vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
285 	i = *(u_int32_t *)(sfbasic + SFB_ASIC_DEEP);
286 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
287 
288 	dc->dc_wid = (hsetup & 0x1ff) << 2;
289 	dc->dc_ht = (vsetup & 0x7ff);
290 	dc->dc_depth = (i & 1) ? 32 : 8;
291 	dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
292 	dc->dc_videobase = dc->dc_vaddr + 0x800000 + vbase * 4096; /* XXX */
293 	dc->dc_blanked = 0;
294 
295 	/* initialize colormap and cursor resource */
296 	sfbpinit(dc);
297 
298 	/* clear the screen */
299 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
300 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
301 
302 	dc->rinfo.ri_flg = RI_CENTER;
303 	dc->rinfo.ri_depth = dc->dc_depth;
304 	dc->rinfo.ri_bits = (void *)dc->dc_videobase;
305 	dc->rinfo.ri_width = dc->dc_wid;
306 	dc->rinfo.ri_height = dc->dc_ht;
307 	dc->rinfo.ri_stride = dc->dc_rowbytes;
308 	dc->rinfo.ri_hw = sfbasic;
309 
310 	wsfont_init();
311 	/* prefer 8 pixel wide font */
312 	if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
313 		cookie = wsfont_find(NULL, 0, 0, 0);
314 	if (cookie <= 0) {
315 		printf("sfb: font table is empty\n");
316 		return;
317 	}
318 
319 	/* the accelerated sfb_putchar() needs LSbit left */
320 	if (wsfont_lock(cookie, &dc->rinfo.ri_font,
321 	    WSDISPLAY_FONTORDER_R2L, WSDISPLAY_FONTORDER_L2R) <= 0) {
322 		printf("sfb: couldn't lock font\n");
323 		return;
324 	}
325 	dc->rinfo.ri_wsfcookie = cookie;
326 
327 	rasops_init(&dc->rinfo, 34, 80);
328 
329 	/* XXX shouldn't be global */
330 	sfb_stdscreen.nrows = dc->rinfo.ri_rows;
331 	sfb_stdscreen.ncols = dc->rinfo.ri_cols;
332 	sfb_stdscreen.textops
333 	    = (dc->dc_depth == 8) ? &sfbp_emulops : &sfbp_emulops32;
334 	sfb_stdscreen.capabilities = dc->rinfo.ri_caps;
335 	/* our accelerated putchar can't underline */
336 	sfb_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE;
337 }
338 
339 static void
340 sfbpattach(parent, self, aux)
341 	struct device *parent, *self;
342 	void *aux;
343 {
344 	struct sfb_softc *sc = (struct sfb_softc *)self;
345 	struct tc_attach_args *ta = aux;
346 	struct wsemuldisplaydev_attach_args waa;
347 	struct hwcmap256 *cm;
348 	caddr_t sfbasic;
349 	int console;
350 
351 	console = (ta->ta_addr == sfbp_consaddr);
352 	if (console) {
353 		sc->sc_dc = &sfbp_console_dc;
354 		sc->nscreens = 1;
355 	}
356 	else {
357 		sc->sc_dc = (struct fb_devconfig *)
358 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
359 		sfbp_getdevconfig(ta->ta_addr, sc->sc_dc);
360 	}
361 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
362 	    sc->sc_dc->dc_depth);
363 
364 	cm = &sc->sc_cmap;
365 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
366 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
367 
368 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
369 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
370 
371 	if (sc->sc_dc->dc_depth == 8) {
372 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
373 		sc->sc_hw1 = sc->sc_hw0;
374 		sc->sc_hwops.visible = bt459visible;
375 		sc->sc_hwops.locate = bt459locate;
376 		sc->sc_hwops.shape = bt459shape;
377 		sc->sc_hwops.color = bt459color;
378 		sc->sc_hwops.setlut = bt459setlut;
379 		sc->sc_hwops.getlut = noplut;
380 	}
381 	else {
382 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_ASIC_OFFSET;
383 		sc->sc_hw1 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
384 		sc->sc_hwops.visible = sfbpvisible;
385 		sc->sc_hwops.locate = sfbplocate;
386 		sc->sc_hwops.shape = sfbpshape;
387 		sc->sc_hwops.color = bt463color;
388 		sc->sc_hwops.setlut = noplut;
389 		sc->sc_hwops.getlut = noplut;
390 	}
391 
392         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
393 
394 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
395 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;	tc_wmb();
396 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;	tc_wmb();
397 
398 	waa.console = console;
399 	waa.scrdata = &sfb_screenlist;
400 	waa.accessops = &sfb_accessops;
401 	waa.accesscookie = sc;
402 
403 	config_found(self, &waa, wsemuldisplaydevprint);
404 }
405 
406 static int
407 sfbioctl(v, cmd, data, flag, p)
408 	void *v;
409 	u_long cmd;
410 	caddr_t data;
411 	int flag;
412 	struct proc *p;
413 {
414 	struct sfb_softc *sc = v;
415 	struct fb_devconfig *dc = sc->sc_dc;
416 	int turnoff;
417 
418 	switch (cmd) {
419 	case WSDISPLAYIO_GTYPE:
420 		*(u_int *)data = WSDISPLAY_TYPE_SFB; /* XXX SFBP XXX */
421 		return (0);
422 
423 	case WSDISPLAYIO_GINFO:
424 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
425 		wsd_fbip->height = sc->sc_dc->dc_ht;
426 		wsd_fbip->width = sc->sc_dc->dc_wid;
427 		wsd_fbip->depth = sc->sc_dc->dc_depth;
428 		wsd_fbip->cmsize = CMAP_SIZE;
429 #undef fbt
430 		return (0);
431 
432 	case WSDISPLAYIO_GETCMAP:
433 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
434 
435 	case WSDISPLAYIO_PUTCMAP:
436 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
437 
438 	case WSDISPLAYIO_SVIDEO:
439 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
440 		if ((dc->dc_blanked == 0) ^ turnoff) {
441 			dc->dc_blanked = turnoff;
442 #if 0 /* XXX later XXX */
443 	Low order 3bit control visibilities of screen and builtin cursor.
444 #endif	/* XXX XXX XXX */
445 		}
446 		return (0);
447 
448 	case WSDISPLAYIO_GVIDEO:
449 		*(u_int *)data = dc->dc_blanked ?
450 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
451 		return (0);
452 
453 	case WSDISPLAYIO_GCURPOS:
454 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
455 		return (0);
456 
457 	case WSDISPLAYIO_SCURPOS: {
458 		struct wsdisplay_curpos *pos = (void *)data;
459 		int x, y;
460 
461 		x = pos->x;
462 		y = pos->y;
463 		if (y < 0)
464 			y = 0;
465 		else if (y > dc->dc_ht)
466 			y = dc->dc_ht;
467 		if (x < 0)
468 			x = 0;
469 		else if (x > dc->dc_wid)
470 			x = dc->dc_wid;
471 		sc->sc_cursor.cc_pos.x = x;
472 		sc->sc_cursor.cc_pos.y = y;
473 		x -= sc->sc_cursor.cc_hot.x;
474 		y -= sc->sc_cursor.cc_hot.y;
475 		x += sc->sc_cursor.cc_magic.x;
476 		y += sc->sc_cursor.cc_magic.y;
477 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
478 		return (0);
479 		}
480 
481 	case WSDISPLAYIO_GCURMAX:
482 		((struct wsdisplay_curpos *)data)->x =
483 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
484 		return (0);
485 
486 	case WSDISPLAYIO_GCURSOR:
487 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
488 
489 	case WSDISPLAYIO_SCURSOR:
490 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
491 	}
492 	return ENOTTY;
493 }
494 
495 paddr_t
496 sfbmmap(v, offset, prot)
497 	void *v;
498 	off_t offset;
499 	int prot;
500 {
501 	struct sfb_softc *sc = v;
502 
503 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
504 		return (-1);
505 	return machine_btop(sc->sc_dc->dc_paddr + offset);
506 }
507 
508 static int
509 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
510 	void *v;
511 	const struct wsscreen_descr *type;
512 	void **cookiep;
513 	int *curxp, *curyp;
514 	long *attrp;
515 {
516 	struct sfb_softc *sc = v;
517 	long defattr;
518 
519 	if (sc->nscreens > 0)
520 		return (ENOMEM);
521 
522 	*cookiep = &sc->sc_dc->rinfo; /* one and only for now */
523 	*curxp = 0;
524 	*curyp = 0;
525 	(*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
526 	*attrp = defattr;
527 	sc->nscreens++;
528 	return (0);
529 }
530 
531 void
532 sfb_free_screen(v, cookie)
533 	void *v;
534 	void *cookie;
535 {
536 	struct sfb_softc *sc = v;
537 
538 	if (sc->sc_dc == &sfbp_console_dc)
539 		panic("sfb_free_screen: console");
540 
541 	sc->nscreens--;
542 }
543 
544 static int
545 sfb_show_screen(v, cookie, waitok, cb, cbarg)
546 	void *v;
547 	void *cookie;
548 	int waitok;
549 	void (*cb) __P((void *, int, int));
550 	void *cbarg;
551 {
552 
553 	return (0);
554 }
555 
556 int
557 sfbp_cnattach(addr)
558 	tc_addr_t addr;
559 {
560 	struct fb_devconfig *dcp = &sfbp_console_dc;
561 	long defattr;
562 
563 	sfbp_getdevconfig(addr, dcp);
564 
565 	(*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
566 
567 	wsdisplay_cnattach(&sfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
568 	sfbp_consaddr = addr;
569 	return(0);
570 }
571 
572 static int
573 sfbpintr(arg)
574 	void *arg;
575 {
576 	struct sfb_softc *sc = arg;
577 	caddr_t sfbasic = (caddr_t)sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET;
578 	int v;
579 	u_int32_t sisr;
580 
581 #define	cc (&sc->sc_cursor)
582 	sisr = *((u_int32_t *)sfbasic + TGA_REG_SISR);
583 
584 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
585 
586 	if (sc->sc_changed == 0)
587 		goto finish;
588 
589 	v = sc->sc_changed;
590 	sc->sc_changed = 0;
591 
592 	if (v & DATA_ENB_CHANGED)
593 		(*sc->sc_hwops.visible)(sc->sc_hw0, sc->sc_curenb);
594 	if (v & DATA_CURCMAP_CHANGED)
595 		(*sc->sc_hwops.color)(sc->sc_hw1, cc->cc_color);
596 	if (v & DATA_CURSHAPE_CHANGED)
597 		(*sc->sc_hwops.shape)(sc->sc_hw0, &cc->cc_size, cc->cc_image);
598 	if (v & DATA_CMAP_CHANGED)
599 		(*sc->sc_hwops.setlut)(sc->sc_hw1, &sc->sc_cmap);
600 
601 finish:
602 	*((u_int32_t *)sfbasic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
603 	return (1);
604 #undef cc
605 }
606 
607 static void
608 sfbpinit(dc)
609 	struct fb_devconfig *dc;
610 {
611 	caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
612 	caddr_t vdac = (caddr_t)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
613 	int i;
614 
615 	*(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
616 	*(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
617 	*(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0; /* MODE_SIMPLE */
618 	*(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3;  /* ROP_COPY */
619 
620     if (dc->dc_depth == 8) {
621 	*(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
622 
623 	SELECT(vdac, BT459_IREG_COMMAND_0);
624 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
625 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
626 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
627 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
628 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
629 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
630 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
631 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
632 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
633 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
634 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
635 
636 	SELECT(vdac, BT459_IREG_CCR);
637 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
638 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
639 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
640 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
641 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
642 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
643 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
644 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
645 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
646 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
647 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
648 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
649 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
650 
651 	/* build sane colormap */
652 	SELECT(vdac, 0);
653 	REG(vdac, bt_cmap) = 0;	tc_wmb();
654 	REG(vdac, bt_cmap) = 0;	tc_wmb();
655 	REG(vdac, bt_cmap) = 0;	tc_wmb();
656 	for (i = 1; i < CMAP_SIZE; i++) {
657 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
658 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
659 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
660 	}
661 
662 	/* clear out cursor image */
663 	SELECT(vdac, BT459_IREG_CRAM_BASE);
664 	for (i = 0; i < 1024; i++)
665 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
666 
667 	/*
668 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
669 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
670 	 * image color.  CCOLOR_1 will be never used.
671 	 */
672 	SELECT(vdac, BT459_IREG_CCOLOR_1);
673 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
674 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
675 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
676 
677 	REG(vdac, bt_reg) = 0;		tc_wmb();
678 	REG(vdac, bt_reg) = 0;		tc_wmb();
679 	REG(vdac, bt_reg) = 0;		tc_wmb();
680 
681 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
682 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
683 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
684     } else {
685 	SELECT(vdac, BT463_IREG_COMMAND_0);
686 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
687 	REG(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
688 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
689 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
690 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
691 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
692 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
693 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
694 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
695 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
696 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
697 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
698 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
699 
700 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
701   {
702 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
703 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
704 	};
705 
706 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
707 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
708 		REG(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
709 		REG(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
710 		REG(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
711 	}
712   }
713 #endif
714 
715 	SELECT(vdac, BT463_IREG_CPALETTE_RAM);
716 	REG(vdac, bt_cmap) = 0;		tc_wmb();
717 	REG(vdac, bt_cmap) = 0;		tc_wmb();
718 	REG(vdac, bt_cmap) = 0;		tc_wmb();
719 	for (i = 1; i < 256; i++) {
720 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
721 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
722 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
723 	}
724 
725 	/* !? Eeeh !? */
726 	SELECT(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
727 	for (i = 0; i < 256; i++) {
728 		REG(vdac, bt_cmap) = i;	tc_wmb();
729 		REG(vdac, bt_cmap) = i;	tc_wmb();
730 		REG(vdac, bt_cmap) = i;	tc_wmb();
731 	}
732     }
733 }
734 
735 static int
736 get_cmap(sc, p)
737 	struct sfb_softc *sc;
738 	struct wsdisplay_cmap *p;
739 {
740 	u_int index = p->index, count = p->count;
741 
742 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
743 		return (EINVAL);
744 
745 	if (!uvm_useracc(p->red, count, B_WRITE) ||
746 	    !uvm_useracc(p->green, count, B_WRITE) ||
747 	    !uvm_useracc(p->blue, count, B_WRITE))
748 		return (EFAULT);
749 
750 	copyout(&sc->sc_cmap.r[index], p->red, count);
751 	copyout(&sc->sc_cmap.g[index], p->green, count);
752 	copyout(&sc->sc_cmap.b[index], p->blue, count);
753 
754 	return (0);
755 }
756 
757 static int
758 set_cmap(sc, p)
759 	struct sfb_softc *sc;
760 	struct wsdisplay_cmap *p;
761 {
762 	u_int index = p->index, count = p->count;
763 
764 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
765 		return (EINVAL);
766 
767 	if (!uvm_useracc(p->red, count, B_READ) ||
768 	    !uvm_useracc(p->green, count, B_READ) ||
769 	    !uvm_useracc(p->blue, count, B_READ))
770 		return (EFAULT);
771 
772 	copyin(p->red, &sc->sc_cmap.r[index], count);
773 	copyin(p->green, &sc->sc_cmap.g[index], count);
774 	copyin(p->blue, &sc->sc_cmap.b[index], count);
775 
776 	sc->sc_changed |= DATA_CMAP_CHANGED;
777 
778 	return (0);
779 }
780 
781 
782 static int
783 set_cursor(sc, p)
784 	struct sfb_softc *sc;
785 	struct wsdisplay_cursor *p;
786 {
787 #define	cc (&sc->sc_cursor)
788 	int v, index, count, icount, x, y;
789 
790 	v = p->which;
791 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
792 		index = p->cmap.index;
793 		count = p->cmap.count;
794 		if (index >= 2 || (index + count) > 2)
795 			return (EINVAL);
796 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
797 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
798 		    !uvm_useracc(p->cmap.blue, count, B_READ))
799 			return (EFAULT);
800 	}
801 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
802 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
803 			return (EINVAL);
804 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
805 		if (!uvm_useracc(p->image, icount, B_READ) ||
806 		    !uvm_useracc(p->mask, icount, B_READ))
807 			return (EFAULT);
808 	}
809 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
810 		if (v & WSDISPLAY_CURSOR_DOCUR)
811 			cc->cc_hot = p->hot;
812 		if (v & WSDISPLAY_CURSOR_DOPOS) {
813 			struct fb_devconfig *dc = sc->sc_dc;
814 
815 			x = p->pos.x;
816 			y = p->pos.y;
817 			if (y < 0)
818 				y = 0;
819 			else if (y > dc->dc_ht)
820 				y = dc->dc_ht;
821 			if (x < 0)
822 				x = 0;
823 			else if (x > dc->dc_wid)
824 				x = dc->dc_wid;
825 			sc->sc_cursor.cc_pos.x = x;
826 			sc->sc_cursor.cc_pos.y = y;
827 		}
828 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
829 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
830 		x += sc->sc_cursor.cc_magic.x;
831 		y += sc->sc_cursor.cc_magic.y;
832 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
833 	}
834 
835 	sc->sc_changed = 0;
836 	if (v & WSDISPLAY_CURSOR_DOCUR) {
837 		sc->sc_curenb = p->enable;
838 		sc->sc_changed |= DATA_ENB_CHANGED;
839 	}
840 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
841 		copyin(p->cmap.red, &cc->cc_color[index], count);
842 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
843 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
844 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
845 	}
846 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
847 		cc->cc_size = p->size;
848 		memset(cc->cc_image, 0, sizeof cc->cc_image);
849 		copyin(p->image, cc->cc_image, icount);
850 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
851 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
852 	}
853 
854 	return (0);
855 #undef cc
856 }
857 
858 static int
859 get_cursor(sc, p)
860 	struct sfb_softc *sc;
861 	struct wsdisplay_cursor *p;
862 {
863 	return (ENOTTY); /* XXX */
864 }
865 
866 int
867 sfb_alloc_attr(id, fg, bg, flags, attrp)
868 	void *id;
869 	int fg, bg, flags;
870 	long *attrp;
871 {
872 	if (flags & (WSATTR_HILIT | WSATTR_BLINK |
873 		     WSATTR_UNDERLINE | WSATTR_WSCOLORS))
874 		return (EINVAL);
875 	if (flags & WSATTR_REVERSE)
876 		*attrp = 1;
877 	else
878 		*attrp = 0;
879 	return (0);
880 }
881 
882 static void
883 bt459visible(hw, on)
884 	void *hw;
885 	int on;
886 {
887 	SELECT(hw, BT459_IREG_CCR);
888 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
889 	tc_wmb();
890 }
891 
892 static void
893 sfbpvisible(hw, on)
894 	void *hw;
895 	int on;
896 {
897 }
898 
899 static void
900 bt459locate(hw, x, y)
901 	void *hw;
902 	int x, y;
903 {
904 	int s;
905 
906 	s = spltty();
907 	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
908 	REG(hw, bt_reg) = x;		tc_wmb();
909 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
910 	REG(hw, bt_reg) = y;		tc_wmb();
911 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
912 	splx(s);
913 }
914 
915 static void
916 sfbplocate(hw, x, y)
917 	void *hw;
918 	int x, y;
919 {
920 	*((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
921 	tc_wmb();
922 }
923 
924 static void
925 bt459color(hw, cp)
926 	void *hw;
927 	u_int8_t *cp;
928 {
929 	SELECT(hw, BT459_IREG_CCOLOR_2);
930 	REG(hw, bt_reg) = cp[1]; tc_wmb();
931 	REG(hw, bt_reg) = cp[3]; tc_wmb();
932 	REG(hw, bt_reg) = cp[5]; tc_wmb();
933 
934 	REG(hw, bt_reg) = cp[0]; tc_wmb();
935 	REG(hw, bt_reg) = cp[2]; tc_wmb();
936 	REG(hw, bt_reg) = cp[4]; tc_wmb();
937 }
938 
939 static void
940 bt463color(hw, cp)
941 	void *hw;
942 	u_int8_t *cp;
943 {
944 }
945 
946 static void
947 bt459shape(hw, size, image)
948 	void *hw;
949 	struct wsdisplay_curpos *size;
950 	u_int64_t *image;
951 {
952 	u_int8_t *ip, *mp, img, msk;
953 	u_int8_t u;
954 	int bcnt;
955 
956 	ip = (u_int8_t *)image;
957 	mp = (u_int8_t *)(image + CURSOR_MAX_SIZE);
958 
959 	bcnt = 0;
960 	SELECT(hw, BT459_IREG_CRAM_BASE+0);
961 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
962 	while (bcnt < size->y * 16) {
963 		/* pad right half 32 pixel when smaller than 33 */
964 		if ((bcnt & 0x8) && size->x < 33) {
965 			REG(hw, bt_reg) = 0; tc_wmb();
966 			REG(hw, bt_reg) = 0; tc_wmb();
967 		}
968 		else {
969 			img = *ip++;
970 			msk = *mp++;
971 			img &= msk;	/* cookie off image */
972 			u = (msk & 0x0f) << 4 | (img & 0x0f);
973 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
974 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
975 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
976 		}
977 		bcnt += 2;
978 	}
979 	/* pad unoccupied scan lines */
980 	while (bcnt < CURSOR_MAX_SIZE * 16) {
981 		REG(hw, bt_reg) = 0; tc_wmb();
982 		REG(hw, bt_reg) = 0; tc_wmb();
983 		bcnt += 2;
984 	}
985 }
986 
987 static void
988 sfbpshape(hw, size, image)
989 	void *hw;
990 	struct wsdisplay_curpos *size;
991 	u_int64_t *image;
992 {
993 }
994 
995 static void
996 bt459setlut(hw, cm)
997 	void *hw;
998 	struct hwcmap256 *cm;
999 {
1000 	int index;
1001 
1002 	SELECT(hw, 0);
1003 	for (index = 0; index < CMAP_SIZE; index++) {
1004 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
1005 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
1006 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
1007 	}
1008 }
1009 
1010 static void
1011 noplut(hw, cm)
1012 	void *hw;
1013 	struct hwcmap256 *cm;
1014 {
1015 }
1016