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