xref: /netbsd-src/sys/dev/tc/sfbplus.c (revision e4d7c2e329d54c97e0c0bd3016bbe74f550c3d5e)
1 /* $NetBSD: sfbplus.c,v 1.3 1999/12/15 15:09:37 ad 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.3 1999/12/15 15:09:37 ad Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45 
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48 
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 
54 #include <dev/tc/tcvar.h>
55 #include <dev/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 	struct raster	dc_raster;	/* raster description */
95 	struct rcons	dc_rcons;	/* raster blitter control info */
96 	int	    dc_blanked;		/* currently has video disabled */
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 int  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 	struct raster *rap;
277 	struct rcons *rcp;
278 	caddr_t sfbasic;
279 	int i, hsetup, vsetup, vbase;
280 
281 	dc->dc_vaddr = dense_addr;
282 	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
283 
284 	sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
285 	hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
286 	vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
287 	i = *(u_int32_t *)(sfbasic + SFB_ASIC_DEEP);
288 	*(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
289 
290 	dc->dc_wid = (hsetup & 0x1ff) << 2;
291 	dc->dc_ht = (vsetup & 0x7ff);
292 	dc->dc_depth = (i & 1) ? 32 : 8;
293 	dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
294 	dc->dc_videobase = dc->dc_vaddr + 0x800000 + vbase * 4096; /* XXX */
295 	dc->dc_blanked = 0;
296 
297 	/* initialize colormap and cursor resource */
298 	sfbpinit(dc);
299 
300 	/* clear the screen */
301 	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
302 		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
303 
304 	/* initialize the raster */
305 	rap = &dc->dc_raster;
306 	rap->width = dc->dc_wid;
307 	rap->height = dc->dc_ht;
308 	rap->depth = dc->dc_depth;
309 	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
310 	rap->pixels = (u_int32_t *)dc->dc_videobase;
311 	rap->data = sfbasic;
312 
313 	/* initialize the raster console blitter */
314 	rcp = &dc->dc_rcons;
315 	rcp->rc_sp = rap;
316 	rcp->rc_crow = rcp->rc_ccol = -1;
317 	rcp->rc_crowp = &rcp->rc_crow;
318 	rcp->rc_ccolp = &rcp->rc_ccol;
319 	rcons_init(rcp, 34, 80);
320 
321 	sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
322 	sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
323 	sfb_stdscreen.textops
324 	    = (dc->dc_depth == 8) ? &sfbp_emulops : &sfbp_emulops32;
325 }
326 
327 static void
328 sfbpattach(parent, self, aux)
329 	struct device *parent, *self;
330 	void *aux;
331 {
332 	struct sfb_softc *sc = (struct sfb_softc *)self;
333 	struct tc_attach_args *ta = aux;
334 	struct wsemuldisplaydev_attach_args waa;
335 	struct hwcmap256 *cm;
336 	caddr_t sfbasic;
337 	int console;
338 
339 	console = (ta->ta_addr == sfbp_consaddr);
340 	if (console) {
341 		sc->sc_dc = &sfbp_console_dc;
342 		sc->nscreens = 1;
343 	}
344 	else {
345 		sc->sc_dc = (struct fb_devconfig *)
346 		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
347 		sfbp_getdevconfig(ta->ta_addr, sc->sc_dc);
348 	}
349 	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
350 	    sc->sc_dc->dc_depth);
351 
352 	cm = &sc->sc_cmap;
353 	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
354 	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
355 
356 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
357 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
358 
359 	if (sc->sc_dc->dc_depth == 8) {
360 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
361 		sc->sc_hw1 = sc->sc_hw0;
362 		sc->sc_hwops.visible = bt459visible;
363 		sc->sc_hwops.locate = bt459locate;
364 		sc->sc_hwops.shape = bt459shape;
365 		sc->sc_hwops.color = bt459color;
366 		sc->sc_hwops.setlut = bt459setlut;
367 		sc->sc_hwops.getlut = noplut;
368 	}
369 	else {
370 		sc->sc_hw0 = (caddr_t)ta->ta_addr + SFB_ASIC_OFFSET;
371 		sc->sc_hw1 = (caddr_t)ta->ta_addr + SFB_RAMDAC_OFFSET;
372 		sc->sc_hwops.visible = sfbpvisible;
373 		sc->sc_hwops.locate = sfbplocate;
374 		sc->sc_hwops.shape = sfbpshape;
375 		sc->sc_hwops.color = bt463color;
376 		sc->sc_hwops.setlut = noplut;
377 		sc->sc_hwops.getlut = noplut;
378 	}
379 
380         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
381 
382 	sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
383 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;	tc_wmb();
384 	*(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;	tc_wmb();
385 
386 	waa.console = console;
387 	waa.scrdata = &sfb_screenlist;
388 	waa.accessops = &sfb_accessops;
389 	waa.accesscookie = sc;
390 
391 	config_found(self, &waa, wsemuldisplaydevprint);
392 }
393 
394 static int
395 sfbioctl(v, cmd, data, flag, p)
396 	void *v;
397 	u_long cmd;
398 	caddr_t data;
399 	int flag;
400 	struct proc *p;
401 {
402 	struct sfb_softc *sc = v;
403 	struct fb_devconfig *dc = sc->sc_dc;
404 	int turnoff;
405 
406 	switch (cmd) {
407 	case WSDISPLAYIO_GTYPE:
408 		*(u_int *)data = WSDISPLAY_TYPE_SFB; /* XXX SFBP XXX */
409 		return (0);
410 
411 	case WSDISPLAYIO_GINFO:
412 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
413 		wsd_fbip->height = sc->sc_dc->dc_ht;
414 		wsd_fbip->width = sc->sc_dc->dc_wid;
415 		wsd_fbip->depth = sc->sc_dc->dc_depth;
416 		wsd_fbip->cmsize = CMAP_SIZE;
417 #undef fbt
418 		return (0);
419 
420 	case WSDISPLAYIO_GETCMAP:
421 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
422 
423 	case WSDISPLAYIO_PUTCMAP:
424 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
425 
426 	case WSDISPLAYIO_SVIDEO:
427 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
428 		if ((dc->dc_blanked == 0) ^ turnoff) {
429 			dc->dc_blanked = turnoff;
430 #if 0 /* XXX later XXX */
431 	Low order 3bit control visibilities of screen and builtin cursor.
432 #endif	/* XXX XXX XXX */
433 		}
434 		return (0);
435 
436 	case WSDISPLAYIO_GVIDEO:
437 		*(u_int *)data = dc->dc_blanked ?
438 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
439 		return (0);
440 
441 	case WSDISPLAYIO_GCURPOS:
442 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
443 		return (0);
444 
445 	case WSDISPLAYIO_SCURPOS: {
446 		struct wsdisplay_curpos *pos = (void *)data;
447 		int x, y;
448 
449 		x = pos->x;
450 		y = pos->y;
451 		if (y < 0)
452 			y = 0;
453 		else if (y > dc->dc_ht)
454 			y = dc->dc_ht;
455 		if (x < 0)
456 			x = 0;
457 		else if (x > dc->dc_wid)
458 			x = dc->dc_wid;
459 		sc->sc_cursor.cc_pos.x = x;
460 		sc->sc_cursor.cc_pos.y = y;
461 		x -= sc->sc_cursor.cc_hot.x;
462 		y -= sc->sc_cursor.cc_hot.y;
463 		x += sc->sc_cursor.cc_magic.x;
464 		y += sc->sc_cursor.cc_magic.y;
465 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
466 		return (0);
467 		}
468 
469 	case WSDISPLAYIO_GCURMAX:
470 		((struct wsdisplay_curpos *)data)->x =
471 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
472 		return (0);
473 
474 	case WSDISPLAYIO_GCURSOR:
475 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
476 
477 	case WSDISPLAYIO_SCURSOR:
478 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
479 	}
480 	return ENOTTY;
481 }
482 
483 int
484 sfbmmap(v, offset, prot)
485 	void *v;
486 	off_t offset;
487 	int prot;
488 {
489 	struct sfb_softc *sc = v;
490 
491 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
492 		return (-1);
493 	return machine_btop(sc->sc_dc->dc_paddr + offset);
494 }
495 
496 static int
497 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
498 	void *v;
499 	const struct wsscreen_descr *type;
500 	void **cookiep;
501 	int *curxp, *curyp;
502 	long *attrp;
503 {
504 	struct sfb_softc *sc = v;
505 	long defattr;
506 
507 	if (sc->nscreens > 0)
508 		return (ENOMEM);
509 
510 	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
511 	*curxp = 0;
512 	*curyp = 0;
513 	sfb_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
514 	*attrp = defattr;
515 	sc->nscreens++;
516 	return (0);
517 }
518 
519 void
520 sfb_free_screen(v, cookie)
521 	void *v;
522 	void *cookie;
523 {
524 	struct sfb_softc *sc = v;
525 
526 	if (sc->sc_dc == &sfbp_console_dc)
527 		panic("sfb_free_screen: console");
528 
529 	sc->nscreens--;
530 }
531 
532 static int
533 sfb_show_screen(v, cookie, waitok, cb, cbarg)
534 	void *v;
535 	void *cookie;
536 	int waitok;
537 	void (*cb) __P((void *, int, int));
538 	void *cbarg;
539 {
540 
541 	return (0);
542 }
543 
544 int
545 sfbp_cnattach(addr)
546         tc_addr_t addr;
547 {
548         struct fb_devconfig *dcp = &sfbp_console_dc;
549         long defattr;
550 
551         sfbp_getdevconfig(addr, dcp);
552 
553         sfb_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
554 
555         wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
556                            0, 0, defattr);
557         sfbp_consaddr = addr;
558         return(0);
559 }
560 
561 static int
562 sfbpintr(arg)
563 	void *arg;
564 {
565 	struct sfb_softc *sc = arg;
566 	caddr_t sfbasic = (caddr_t)sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET;
567 	int v;
568 	u_int32_t sisr;
569 
570 #define	cc (&sc->sc_cursor)
571 	sisr = *((u_int32_t *)sfbasic + TGA_REG_SISR);
572 
573 	*(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
574 
575 	if (sc->sc_changed == 0)
576 		goto finish;
577 
578 	v = sc->sc_changed;
579 	sc->sc_changed = 0;
580 
581 	if (v & DATA_ENB_CHANGED)
582 		(*sc->sc_hwops.visible)(sc->sc_hw0, sc->sc_curenb);
583 	if (v & DATA_CURCMAP_CHANGED)
584 		(*sc->sc_hwops.color)(sc->sc_hw1, cc->cc_color);
585 	if (v & DATA_CURSHAPE_CHANGED)
586 		(*sc->sc_hwops.shape)(sc->sc_hw0, &cc->cc_size, cc->cc_image);
587 	if (v & DATA_CMAP_CHANGED)
588 		(*sc->sc_hwops.setlut)(sc->sc_hw1, &sc->sc_cmap);
589 
590 finish:
591 	*((u_int32_t *)sfbasic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
592 	return (1);
593 #undef cc
594 }
595 
596 static void
597 sfbpinit(dc)
598 	struct fb_devconfig *dc;
599 {
600 	caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
601 	caddr_t vdac = (caddr_t)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
602 	int i;
603 
604 	*(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
605 	*(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
606 	*(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0; /* MODE_SIMPLE */
607 	*(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3;  /* ROP_COPY */
608 
609     if (dc->dc_depth == 8) {
610 	*(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
611 
612 	SELECT(vdac, BT459_IREG_COMMAND_0);
613 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
614 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
615 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
616 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
617 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
618 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
619 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
620 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
621 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
622 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
623 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
624 
625 	SELECT(vdac, BT459_IREG_CCR);
626 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
627 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
628 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
629 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
630 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
631 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
632 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
633 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
634 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
635 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
636 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
637 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
638 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
639 
640 	/* build sane colormap */
641 	SELECT(vdac, 0);
642 	REG(vdac, bt_cmap) = 0;	tc_wmb();
643 	REG(vdac, bt_cmap) = 0;	tc_wmb();
644 	REG(vdac, bt_cmap) = 0;	tc_wmb();
645 	for (i = 1; i < CMAP_SIZE; i++) {
646 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
647 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
648 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
649 	}
650 
651 	/* clear out cursor image */
652 	SELECT(vdac, BT459_IREG_CRAM_BASE);
653 	for (i = 0; i < 1024; i++)
654 		REG(vdac, bt_reg) = 0xff;	tc_wmb();
655 
656 	/*
657 	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
658 	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
659 	 * image color.  CCOLOR_1 will be never used.
660 	 */
661 	SELECT(vdac, BT459_IREG_CCOLOR_1);
662 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
663 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
664 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
665 
666 	REG(vdac, bt_reg) = 0;		tc_wmb();
667 	REG(vdac, bt_reg) = 0;		tc_wmb();
668 	REG(vdac, bt_reg) = 0;		tc_wmb();
669 
670 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
671 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
672 	REG(vdac, bt_reg) = 0xff;	tc_wmb();
673     } else {
674 	SELECT(vdac, BT463_IREG_COMMAND_0);
675 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
676 	REG(vdac, bt_reg) = 0x46;	tc_wmb();	/* CMD 1 */
677 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
678 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
679 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
680 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
681 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
682 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
683 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
684 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
685 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
686 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
687 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
688 
689 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
690   {
691 	static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
692 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
693 	};
694 
695 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
696 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
697 		REG(vdac, bt_reg) = windowtype[i];	  /*   0:7  */
698 		REG(vdac, bt_reg) = windowtype[i] >> 8;  /*   8:15 */
699 		REG(vdac, bt_reg) = windowtype[i] >> 16; /*  16:23 */
700 	}
701   }
702 #endif
703 
704 	SELECT(vdac, BT463_IREG_CPALETTE_RAM);
705 	REG(vdac, bt_cmap) = 0;		tc_wmb();
706 	REG(vdac, bt_cmap) = 0;		tc_wmb();
707 	REG(vdac, bt_cmap) = 0;		tc_wmb();
708 	for (i = 1; i < 256; i++) {
709 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
710 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
711 		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
712 	}
713 
714 	/* !? Eeeh !? */
715 	SELECT(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
716 	for (i = 0; i < 256; i++) {
717 		REG(vdac, bt_cmap) = i;	tc_wmb();
718 		REG(vdac, bt_cmap) = i;	tc_wmb();
719 		REG(vdac, bt_cmap) = i;	tc_wmb();
720 	}
721     }
722 }
723 
724 static int
725 get_cmap(sc, p)
726 	struct sfb_softc *sc;
727 	struct wsdisplay_cmap *p;
728 {
729 	u_int index = p->index, count = p->count;
730 
731 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
732 		return (EINVAL);
733 
734 	if (!uvm_useracc(p->red, count, B_WRITE) ||
735 	    !uvm_useracc(p->green, count, B_WRITE) ||
736 	    !uvm_useracc(p->blue, count, B_WRITE))
737 		return (EFAULT);
738 
739 	copyout(&sc->sc_cmap.r[index], p->red, count);
740 	copyout(&sc->sc_cmap.g[index], p->green, count);
741 	copyout(&sc->sc_cmap.b[index], p->blue, count);
742 
743 	return (0);
744 }
745 
746 static int
747 set_cmap(sc, p)
748 	struct sfb_softc *sc;
749 	struct wsdisplay_cmap *p;
750 {
751 	u_int index = p->index, count = p->count;
752 
753 	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
754 		return (EINVAL);
755 
756 	if (!uvm_useracc(p->red, count, B_READ) ||
757 	    !uvm_useracc(p->green, count, B_READ) ||
758 	    !uvm_useracc(p->blue, count, B_READ))
759 		return (EFAULT);
760 
761 	copyin(p->red, &sc->sc_cmap.r[index], count);
762 	copyin(p->green, &sc->sc_cmap.g[index], count);
763 	copyin(p->blue, &sc->sc_cmap.b[index], count);
764 
765 	sc->sc_changed |= DATA_CMAP_CHANGED;
766 
767 	return (0);
768 }
769 
770 
771 static int
772 set_cursor(sc, p)
773 	struct sfb_softc *sc;
774 	struct wsdisplay_cursor *p;
775 {
776 #define	cc (&sc->sc_cursor)
777 	int v, index, count, icount, x, y;
778 
779 	v = p->which;
780 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
781 		index = p->cmap.index;
782 		count = p->cmap.count;
783 		if (index >= 2 || (index + count) > 2)
784 			return (EINVAL);
785 		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
786 		    !uvm_useracc(p->cmap.green, count, B_READ) ||
787 		    !uvm_useracc(p->cmap.blue, count, B_READ))
788 			return (EFAULT);
789 	}
790 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
791 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
792 			return (EINVAL);
793 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
794 		if (!uvm_useracc(p->image, icount, B_READ) ||
795 		    !uvm_useracc(p->mask, icount, B_READ))
796 			return (EFAULT);
797 	}
798 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
799 		if (v & WSDISPLAY_CURSOR_DOCUR)
800 			cc->cc_hot = p->hot;
801 		if (v & WSDISPLAY_CURSOR_DOPOS) {
802 			struct fb_devconfig *dc = sc->sc_dc;
803 
804 			x = p->pos.x;
805 			y = p->pos.y;
806 			if (y < 0)
807 				y = 0;
808 			else if (y > dc->dc_ht)
809 				y = dc->dc_ht;
810 			if (x < 0)
811 				x = 0;
812 			else if (x > dc->dc_wid)
813 				x = dc->dc_wid;
814 			sc->sc_cursor.cc_pos.x = x;
815 			sc->sc_cursor.cc_pos.y = y;
816 		}
817 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
818 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
819 		x += sc->sc_cursor.cc_magic.x;
820 		y += sc->sc_cursor.cc_magic.y;
821 		(*sc->sc_hwops.locate)(sc->sc_hw0, x, y);
822 	}
823 
824 	sc->sc_changed = 0;
825 	if (v & WSDISPLAY_CURSOR_DOCUR) {
826 		sc->sc_curenb = p->enable;
827 		sc->sc_changed |= DATA_ENB_CHANGED;
828 	}
829 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
830 		copyin(p->cmap.red, &cc->cc_color[index], count);
831 		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
832 		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
833 		sc->sc_changed |= DATA_CURCMAP_CHANGED;
834 	}
835 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
836 		cc->cc_size = p->size;
837 		memset(cc->cc_image, 0, sizeof cc->cc_image);
838 		copyin(p->image, cc->cc_image, icount);
839 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
840 		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
841 	}
842 
843 	return (0);
844 #undef cc
845 }
846 
847 static int
848 get_cursor(sc, p)
849 	struct sfb_softc *sc;
850 	struct wsdisplay_cursor *p;
851 {
852 	return (ENOTTY); /* XXX */
853 }
854 
855 int
856 sfb_alloc_attr(id, fg, bg, flags, attrp)
857 	void *id;
858 	int fg, bg, flags;
859 	long *attrp;
860 {
861 	if (flags & (WSATTR_HILIT | WSATTR_BLINK |
862 		     WSATTR_UNDERLINE | WSATTR_WSCOLORS))
863 		return (EINVAL);
864 	if (flags & WSATTR_REVERSE)
865 		*attrp = 1;
866 	else
867 		*attrp = 0;
868 	return (0);
869 }
870 
871 static void
872 bt459visible(hw, on)
873 	void *hw;
874 	int on;
875 {
876 	SELECT(hw, BT459_IREG_CCR);
877 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
878 	tc_wmb();
879 }
880 
881 static void
882 sfbpvisible(hw, on)
883 	void *hw;
884 	int on;
885 {
886 }
887 
888 static void
889 bt459locate(hw, x, y)
890 	void *hw;
891 	int x, y;
892 {
893 	int s;
894 
895 	s = spltty();
896 	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
897 	REG(hw, bt_reg) = x;		tc_wmb();
898 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
899 	REG(hw, bt_reg) = y;		tc_wmb();
900 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
901 	splx(s);
902 }
903 
904 static void
905 sfbplocate(hw, x, y)
906 	void *hw;
907 	int x, y;
908 {
909 	*((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
910 	tc_wmb();
911 }
912 
913 static void
914 bt459color(hw, cp)
915 	void *hw;
916 	u_int8_t *cp;
917 {
918 	SELECT(hw, BT459_IREG_CCOLOR_2);
919 	REG(hw, bt_reg) = cp[1]; tc_wmb();
920 	REG(hw, bt_reg) = cp[3]; tc_wmb();
921 	REG(hw, bt_reg) = cp[5]; tc_wmb();
922 
923 	REG(hw, bt_reg) = cp[0]; tc_wmb();
924 	REG(hw, bt_reg) = cp[2]; tc_wmb();
925 	REG(hw, bt_reg) = cp[4]; tc_wmb();
926 }
927 
928 static void
929 bt463color(hw, cp)
930 	void *hw;
931 	u_int8_t *cp;
932 {
933 }
934 
935 static void
936 bt459shape(hw, size, image)
937 	void *hw;
938 	struct wsdisplay_curpos *size;
939 	u_int64_t *image;
940 {
941 	u_int8_t *ip, *mp, img, msk;
942 	u_int8_t u;
943 	int bcnt;
944 
945 	ip = (u_int8_t *)image;
946 	mp = (u_int8_t *)(image + CURSOR_MAX_SIZE);
947 
948 	bcnt = 0;
949 	SELECT(hw, BT459_IREG_CRAM_BASE+0);
950 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
951 	while (bcnt < size->y * 16) {
952 		/* pad right half 32 pixel when smaller than 33 */
953 		if ((bcnt & 0x8) && size->x < 33) {
954 			REG(hw, bt_reg) = 0; tc_wmb();
955 			REG(hw, bt_reg) = 0; tc_wmb();
956 		}
957 		else {
958 			img = *ip++;
959 			msk = *mp++;
960 			img &= msk;	/* cookie off image */
961 			u = (msk & 0x0f) << 4 | (img & 0x0f);
962 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
963 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
964 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
965 		}
966 		bcnt += 2;
967 	}
968 	/* pad unoccupied scan lines */
969 	while (bcnt < CURSOR_MAX_SIZE * 16) {
970 		REG(hw, bt_reg) = 0; tc_wmb();
971 		REG(hw, bt_reg) = 0; tc_wmb();
972 		bcnt += 2;
973 	}
974 }
975 
976 static void
977 sfbpshape(hw, size, image)
978 	void *hw;
979 	struct wsdisplay_curpos *size;
980 	u_int64_t *image;
981 {
982 }
983 
984 static void
985 bt459setlut(hw, cm)
986 	void *hw;
987 	struct hwcmap256 *cm;
988 {
989 	int index;
990 
991 	SELECT(hw, 0);
992 	for (index = 0; index < CMAP_SIZE; index++) {
993 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
994 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
995 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
996 	}
997 }
998 
999 static void
1000 noplut(hw, cm)
1001 	void *hw;
1002 	struct hwcmap256 *cm;
1003 {
1004 }
1005