xref: /netbsd-src/sys/dev/tc/sfbplus.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /* $NetBSD: sfbplus.c,v 1.29 2007/10/19 12:01:20 ad Exp $ */
2 
3 /*
4  * Copyright (c) 1999, 2000, 2001 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>
34 __KERNEL_RCSID(0, "$NetBSD: sfbplus.c,v 1.29 2007/10/19 12:01:20 ad Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <sys/bus.h>
45 #include <sys/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.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(MIPS_KSEG1_TO_PHYS(x))
63 #endif
64 
65 #if defined(alpha)
66 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
67 #endif
68 
69 /* Bt459/Bt463 hardware registers */
70 #define bt_lo	0
71 #define bt_hi	1
72 #define bt_reg	2
73 #define bt_cmap 3
74 
75 #define REG(base, index)	*((u_int32_t *)(base) + (index))
76 #define SELECT(vdac, regno) do {			\
77 	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
78 	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
79 	tc_wmb();					\
80    } while (0)
81 
82 struct hwcmap256 {
83 #define	CMAP_SIZE	256	/* 256 R/G/B entries */
84 	u_int8_t r[CMAP_SIZE];
85 	u_int8_t g[CMAP_SIZE];
86 	u_int8_t b[CMAP_SIZE];
87 };
88 
89 struct hwcursor64 {
90 	struct wsdisplay_curpos cc_pos;
91 	struct wsdisplay_curpos cc_hot;
92 	struct wsdisplay_curpos cc_size;
93 	struct wsdisplay_curpos cc_magic;
94 #define	CURSOR_MAX_SIZE	64
95 	u_int8_t cc_color[6];
96 	u_int64_t cc_image[CURSOR_MAX_SIZE];
97 	u_int64_t cc_mask[CURSOR_MAX_SIZE];
98 };
99 
100 struct hwops {
101 	void (*setlut)(void *, struct hwcmap256 *);
102 	void (*getlut)(void *, struct hwcmap256 *);
103 	void (*visible)(void *, int);
104 	void (*locate)(void *, struct hwcursor64 *);
105 	void (*shape)(void *, struct wsdisplay_curpos *, u_int64_t *);
106 	void (*color)(void *, u_int8_t *);
107 };
108 
109 struct sfbp_softc {
110 	struct device sc_dev;
111 	vaddr_t sc_vaddr;
112 	size_t sc_size;
113 	struct rasops_info *sc_ri;
114 	struct hwcmap256 sc_cmap;	/* software copy of colormap */
115 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
116 	int sc_blanked;
117 	int sc_curenb;			/* cursor sprite enabled */
118 	int sc_changed;			/* need update of hardware */
119 #define	WSDISPLAY_CMAP_DOLUT	0x20
120 	int nscreens;
121 	struct hwops sc_hwops;
122 };
123 
124 #define	HX_MAGIC_X	368
125 #define	HX_MAGIC_Y	38
126 
127 static int  sfbpmatch(struct device *, struct cfdata *, void *);
128 static void sfbpattach(struct device *, struct device *, void *);
129 
130 CFATTACH_DECL(sfbp, sizeof(struct sfbp_softc),
131     sfbpmatch, sfbpattach, NULL, NULL);
132 
133 static void sfbp_common_init(struct rasops_info *);
134 static struct rasops_info sfbp_console_ri;
135 static tc_addr_t sfbp_consaddr;
136 
137 static struct wsscreen_descr sfbp_stdscreen = {
138 	"std", 0, 0,
139 	NULL, /* textops */
140 	0, 0,
141 	WSSCREEN_REVERSE
142 };
143 
144 static const struct wsscreen_descr *_sfb_scrlist[] = {
145 	&sfbp_stdscreen,
146 };
147 
148 static const struct wsscreen_list sfb_screenlist = {
149 	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
150 };
151 
152 static int	sfbioctl(void *, void *, u_long, void *, int, struct proc *);
153 static paddr_t	sfbmmap(void *, void *, off_t, int);
154 
155 static int	sfb_alloc_screen(void *, const struct wsscreen_descr *,
156 				      void **, int *, int *, long *);
157 static void	sfb_free_screen(void *, void *);
158 static int	sfb_show_screen(void *, void *, int,
159 				     void (*) (void *, int, int), void *);
160 static void sfbp_putchar(void *, int, int, u_int, long);
161 static void sfbp_erasecols(void *, int, int, int, long);
162 static void sfbp_eraserows(void *, int, int, long);
163 static void sfbp_copyrows(void *, int, int, int);
164 
165 static const struct wsdisplay_accessops sfb_accessops = {
166 	sfbioctl,
167 	sfbmmap,
168 	sfb_alloc_screen,
169 	sfb_free_screen,
170 	sfb_show_screen,
171 	0 /* load_font */
172 };
173 
174 static void bt459init(void *);
175 static void bt459visible(void *, int);
176 static void bt459locate(void *, struct hwcursor64 *);
177 static void bt459shape(void *, struct wsdisplay_curpos *, u_int64_t *);
178 static void bt459color(void *, u_int8_t *);
179 static void bt459setlut(void *, struct hwcmap256 *);
180 
181 static void sfbpvisible(void *, int);
182 static void sfbplocate(void *, struct hwcursor64 *);
183 static void sfbpshape(void *, struct wsdisplay_curpos *, u_int64_t *);
184 static void bt463init(void *);
185 static void bt463color(void *, u_int8_t *);
186 static void noplut(void *, struct hwcmap256 *);
187 
188 /* EXPORT */ int sfbp_cnattach(tc_addr_t);
189 static int  sfbpintr(void *);
190 static void sfbp_cmap_init(struct sfbp_softc *);
191 static void sfbp_screenblank(struct sfbp_softc *, int);
192 
193 static int  get_cmap(struct sfbp_softc *, struct wsdisplay_cmap *);
194 static int  set_cmap(struct sfbp_softc *, struct wsdisplay_cmap *);
195 static int  set_cursor(struct sfbp_softc *, struct wsdisplay_cursor *);
196 static int  get_cursor(struct sfbp_softc *, struct wsdisplay_cursor *);
197 static void set_curpos(struct sfbp_softc *, struct wsdisplay_curpos *);
198 
199 /*
200  * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
201  *   M M M M I I I I		M I M I M I M I
202  *	[ before ]		   [ after ]
203  *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
204  *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
205  */
206 static const u_int8_t shuffle[256] = {
207 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
208 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
209 	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
210 	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
211 	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
212 	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
213 	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
214 	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
215 	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
216 	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
217 	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
218 	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
219 	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
220 	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
221 	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
222 	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
223 	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
224 	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
225 	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
226 	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
227 	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
228 	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
229 	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
230 	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
231 	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
232 	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
233 	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
234 	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
235 	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
236 	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
237 	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
238 	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
239 };
240 
241 static int
242 sfbpmatch(struct device *parent, struct cfdata *match, void *aux)
243 {
244 	struct tc_attach_args *ta = aux;
245 
246 	if (strncmp("PMAGD   ", ta->ta_modname, TC_ROM_LLEN) != 0)
247 		return (0);
248 
249 	return (1);
250 }
251 
252 static void
253 sfbpattach(struct device *parent, struct device *self, void *aux)
254 {
255 	struct sfbp_softc *sc = device_private(self);
256 	struct tc_attach_args *ta = aux;
257 	struct rasops_info *ri;
258 	struct wsemuldisplaydev_attach_args waa;
259 	void *asic;
260 	int console;
261 
262 	console = (ta->ta_addr == sfbp_consaddr);
263 	if (console) {
264 		sc->sc_ri = ri = &sfbp_console_ri;
265 		sc->nscreens = 1;
266 	}
267 	else {
268 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
269 			M_DEVBUF, M_NOWAIT);
270 		if (ri == NULL) {
271 			printf(": can't alloc memory\n");
272 			return;
273 		}
274 		memset(ri, 0, sizeof(struct rasops_info));
275 
276 		ri->ri_hw = (void *)ta->ta_addr;
277 		sfbp_common_init(ri);
278 		sc->sc_ri = ri;
279 	}
280 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height,
281 	    (ri->ri_depth != 32) ? 8 : 24);
282 
283 	sc->sc_vaddr = ta->ta_addr;
284 	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
285 	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
286 	sc->sc_blanked = sc->sc_curenb = 0;
287 
288 	if (ri->ri_depth == 8) {
289 		sc->sc_hwops.visible = bt459visible;
290 		sc->sc_hwops.locate = bt459locate;
291 		sc->sc_hwops.shape = bt459shape;
292 		sc->sc_hwops.color = bt459color;
293 		sc->sc_hwops.setlut = bt459setlut;
294 		sc->sc_hwops.getlut = noplut;
295 	} else {
296 		sc->sc_hwops.visible = sfbpvisible;
297 		sc->sc_hwops.locate = sfbplocate;
298 		sc->sc_hwops.shape = sfbpshape;
299 		sc->sc_hwops.color = bt463color;
300 		sc->sc_hwops.setlut = noplut;
301 		sc->sc_hwops.getlut = noplut;
302 	}
303 	sfbp_cmap_init(sc);
304 
305         tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
306 
307 	asic = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
308 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
309 	*(u_int32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
310 
311 	waa.console = console;
312 	waa.scrdata = &sfb_screenlist;
313 	waa.accessops = &sfb_accessops;
314 	waa.accesscookie = sc;
315 
316 	config_found(self, &waa, wsemuldisplaydevprint);
317 }
318 
319 static void
320 sfbp_cmap_init(struct sfbp_softc *sc)
321 {
322 	struct hwcmap256 *cm;
323 	const u_int8_t *p;
324 	int index;
325 
326 	if (sc->sc_ri->ri_depth != 8)
327 		return;
328 
329 	cm = &sc->sc_cmap;
330 	p = rasops_cmap;
331 	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
332 		cm->r[index] = p[0];
333 		cm->g[index] = p[1];
334 		cm->b[index] = p[2];
335 	}
336 }
337 
338 static void
339 sfbp_common_init(struct rasops_info *ri)
340 {
341 	void *base, *asic;
342 	int i, depth, hsetup, vsetup, vbase, cookie;
343 
344 	base = (void *)ri->ri_hw;
345 	asic = base + SFB_ASIC_OFFSET;
346 	hsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
347 	vsetup = *(u_int32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
348 	i = *(u_int32_t *)(asic + SFB_ASIC_DEEP);
349 	depth = (i & 01) ? 32 : 8;
350 
351 	/*
352 	 * - neglect 0,1 cases of hsetup register.
353 	 * - observed 804x600?, 644x480? values.
354 	 */
355 
356 	*(u_int32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
357 	vbase *= (i & 0x20) ? 2048 : 4096;	/* VRAM chip size */
358 	if (i & 1) vbase *= 4;			/* bytes per pixel */
359 
360 	*(u_int32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
361 	*(u_int32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
362 	*(u_int32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
363 	*(u_int32_t *)(asic + SFB_ASIC_ROP) = 3;	/* ROP_COPY */
364 
365 	/* initialize colormap and cursor hardware */
366 	if (depth != 32) {
367 		*(u_int32_t *)(asic + 0x180000) = 0;	/* Bt459 reset */
368 		bt459init(base + SFB_RAMDAC_OFFSET);
369 	}
370 	else {
371 		bt463init(base + SFB_RAMDAC_OFFSET);
372 	}
373 
374 	ri->ri_flg = RI_CENTER;
375 	ri->ri_flg = 0;			/* XXX 32bpp RI_CENTER fails XXX */
376 	ri->ri_depth = depth;
377 	ri->ri_width = (hsetup & 0x1ff) << 2;
378 	ri->ri_height = (vsetup & 0x7ff);
379 	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
380 	ri->ri_bits = base + 0x800000 + vbase;
381 
382 	if (depth == 32) {
383 		ri->ri_rnum = 8;
384 		ri->ri_gnum = 8;
385 		ri->ri_bnum = 8;
386 		ri->ri_rpos = 16;
387 		ri->ri_gpos = 8;
388 		ri->ri_bpos = 0;
389 	}
390 
391 	/* clear the screen */
392 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
393 
394 	wsfont_init();
395 	/* prefer 12 pixel wide font */
396 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
397 	    WSDISPLAY_FONTORDER_L2R);
398 	if (cookie <= 0)
399 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
400 		    WSDISPLAY_FONTORDER_L2R);
401 	if (cookie <= 0) {
402 		printf("sfbp: font table is empty\n");
403 		return;
404 	}
405 
406 	/* the accelerated sfbp_putchar() needs LSbit left */
407 	if (wsfont_lock(cookie, &ri->ri_font)) {
408 		printf("sfb: couldn't lock font\n");
409 		return;
410 	}
411 	ri->ri_wsfcookie = cookie;
412 
413 	rasops_init(ri, 34, 80);
414 
415 	/* add our accelerated functions */
416 	ri->ri_ops.putchar = sfbp_putchar;
417 	ri->ri_ops.erasecols = sfbp_erasecols;
418 	ri->ri_ops.copyrows = sfbp_copyrows;
419 	ri->ri_ops.eraserows = sfbp_eraserows;
420 
421 	/* XXX shouldn't be global */
422 	sfbp_stdscreen.nrows = ri->ri_rows;
423 	sfbp_stdscreen.ncols = ri->ri_cols;
424 	sfbp_stdscreen.textops = &ri->ri_ops;
425 	sfbp_stdscreen.capabilities = ri->ri_caps;
426 	/* our accelerated putchar can't underline */
427 	sfbp_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE;
428 }
429 
430 static int
431 sfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct proc *p)
432 {
433 	struct sfbp_softc *sc = v;
434 	struct rasops_info *ri = sc->sc_ri;
435 	int turnoff, s;
436 
437 	switch (cmd) {
438 	case WSDISPLAYIO_GTYPE:
439 		*(u_int *)data = WSDISPLAY_TYPE_SFBP;
440 		return (0);
441 
442 	case WSDISPLAYIO_GINFO:
443 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
444 		wsd_fbip->height = ri->ri_height;
445 		wsd_fbip->width = ri->ri_width;
446 		wsd_fbip->depth = ri->ri_depth;
447 		wsd_fbip->cmsize = CMAP_SIZE;	/* XXX */
448 #undef fbt
449 		return (0);
450 
451 	case WSDISPLAYIO_GETCMAP:
452 		return get_cmap(sc, (struct wsdisplay_cmap *)data);
453 
454 	case WSDISPLAYIO_PUTCMAP:
455 		return set_cmap(sc, (struct wsdisplay_cmap *)data);
456 
457 	case WSDISPLAYIO_SVIDEO:
458 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
459 		if ((sc->sc_blanked == 0) ^ turnoff) {
460 			sc->sc_blanked = turnoff;
461 #if 0 /* XXX later XXX */
462 	Low order 3bit control visibilities of screen and builtin cursor.
463 #endif	/* XXX XXX XXX */
464 		}
465 		return (0);
466 
467 	case WSDISPLAYIO_GVIDEO:
468 		*(u_int *)data = sc->sc_blanked ?
469 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
470 		return (0);
471 
472 	case WSDISPLAYIO_GCURPOS:
473 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
474 		return (0);
475 
476 	case WSDISPLAYIO_SCURPOS:
477 		s = spltty();
478 		set_curpos(sc, (struct wsdisplay_curpos *)data);
479 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
480 		splx(s);
481 		return (0);
482 
483 	case WSDISPLAYIO_GCURMAX:
484 		((struct wsdisplay_curpos *)data)->x =
485 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
486 		return (0);
487 
488 	case WSDISPLAYIO_GCURSOR:
489 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
490 
491 	case WSDISPLAYIO_SCURSOR:
492 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
493 
494 	case WSDISPLAYIO_SMODE:
495 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
496 			s = spltty();
497 			sfbp_cmap_init(sc);
498 			sc->sc_curenb = 0;
499 			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
500 			    WSDISPLAY_CMAP_DOLUT);
501 			splx(s);
502 		}
503 		return (0);
504 	}
505 	}
506 	return (EPASSTHROUGH);
507 }
508 
509 paddr_t
510 sfbmmap(void *v, void *vs, off_t offset, int prot)
511 {
512 	struct sfbp_softc *sc = v;
513 
514 	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
515 		return (-1);
516 	return machine_btop(sc->sc_vaddr + offset);
517 }
518 
519 static int
520 sfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
521     int *curxp, int *curyp, long *attrp)
522 {
523 	struct sfbp_softc *sc = v;
524 	struct rasops_info *ri = sc->sc_ri;
525 	long defattr;
526 
527 	if (sc->nscreens > 0)
528 		return (ENOMEM);
529 
530 	*cookiep = ri;		 /* one and only for now */
531 	*curxp = 0;
532 	*curyp = 0;
533 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
534 	*attrp = defattr;
535 	sc->nscreens++;
536 	return (0);
537 }
538 
539 void
540 sfb_free_screen(void *v, void *cookie)
541 {
542 	struct sfbp_softc *sc = v;
543 
544 	if (sc->sc_ri == &sfbp_console_ri)
545 		panic("sfb_free_screen: console");
546 
547 	sc->nscreens--;
548 }
549 
550 static int
551 sfb_show_screen(void *v, void *cookie, int waitok,
552     void (*cb)(void *, int, int), void *cbarg)
553 {
554 
555 	return (0);
556 }
557 
558 int
559 sfbp_cnattach(tc_addr_t addr)
560 {
561 	struct rasops_info *ri;
562 	long defattr;
563 
564 	ri = &sfbp_console_ri;
565 	ri->ri_hw = (void *)addr;
566 	sfbp_common_init(ri);
567 	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
568 	wsdisplay_cnattach(&sfbp_stdscreen, ri, 0, 0, defattr);
569 	sfbp_consaddr = addr;
570 	return (0);
571 }
572 
573 static int
574 sfbpintr(void *arg)
575 {
576 #define	cc (&sc->sc_cursor)
577 	struct sfbp_softc *sc = arg;
578 	void *base, *asic;
579 	u_int32_t sisr;
580 	int v;
581 
582 	base = (void *)sc->sc_ri->ri_hw;
583 	asic = base + SFB_ASIC_OFFSET;
584 	sisr = *((u_int32_t *)asic + TGA_REG_SISR);
585 	*(u_int32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
586 
587 	if (sc->sc_changed == 0)
588 		goto done;
589 
590 	v = sc->sc_changed;
591 	if (v & WSDISPLAY_CURSOR_DOCUR)
592 		(*sc->sc_hwops.visible)(base, sc->sc_curenb);
593 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT))
594 		(*sc->sc_hwops.locate)(base, cc);
595 	if (v & WSDISPLAY_CURSOR_DOCMAP)
596 		(*sc->sc_hwops.color)(base, cc->cc_color);
597 	if (v & WSDISPLAY_CURSOR_DOSHAPE)
598 		(*sc->sc_hwops.shape)(base, &cc->cc_size, cc->cc_image);
599 	if (v & WSDISPLAY_CMAP_DOLUT)
600 		(*sc->sc_hwops.setlut)(base, &sc->sc_cmap);
601 	sc->sc_changed = 0;
602 done:
603 	*((u_int32_t *)asic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
604 	return (1);
605 #undef cc
606 }
607 
608 static void
609 bt459init(void *vdac)
610 {
611 	const u_int8_t *p;
612 	int i;
613 
614 	SELECT(vdac, BT459_IREG_COMMAND_0);
615 	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
616 	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
617 	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
618 	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
619 	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
620 	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
621 	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
622 	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
623 	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
624 	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
625 	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
626 
627 	SELECT(vdac, BT459_IREG_CCR);
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 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
640 	REG(vdac, bt_reg) = 0x0;	tc_wmb();
641 
642 	/* build sane colormap */
643 	SELECT(vdac, 0);
644 	p = rasops_cmap;
645 	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
646 		REG(vdac, bt_cmap) = p[0];	tc_wmb();
647 		REG(vdac, bt_cmap) = p[1];	tc_wmb();
648 		REG(vdac, bt_cmap) = p[2];	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 }
674 
675 static void
676 bt463init(void *vdac)
677 {
678 	int i;
679 
680 	SELECT(vdac, BT463_IREG_COMMAND_0);
681 	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
682 	REG(vdac, bt_reg) = 0x48;	tc_wmb();	/* CMD 1 */
683 	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
684 	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
685 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
686 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
687 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
688 	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
689 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
690 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
691 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
692 	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
693 	REG(vdac, bt_reg) = 0x00;	tc_wmb();
694 
695 	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
696 	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
697 		REG(vdac, bt_reg) = 0x00;	/*   0:7  */
698 		REG(vdac, bt_reg) = 0xe1;	/*   8:15 */
699 		REG(vdac, bt_reg) = 0x81; 	/*  16:23 */
700 	}
701 }
702 
703 static int
704 get_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
705 {
706 	u_int index = p->index, count = p->count;
707 	int error;
708 
709 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
710 		return (EINVAL);
711 
712 	error = copyout(&sc->sc_cmap.r[index], p->red, count);
713 	if (error)
714 		return error;
715 	error = copyout(&sc->sc_cmap.g[index], p->green, count);
716 	if (error)
717 		return error;
718 	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
719 	return error;
720 }
721 
722 static int
723 set_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
724 {
725 	struct hwcmap256 cmap;
726 	u_int index = p->index, count = p->count;
727 	int error, s;
728 
729 	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
730 		return (EINVAL);
731 
732 	error = copyin(p->red, &cmap.r[index], count);
733 	if (error)
734 		return error;
735 	error = copyin(p->green, &cmap.g[index], count);
736 	if (error)
737 		return error;
738 	error = copyin(p->blue, &cmap.b[index], count);
739 	if (error)
740 		return error;
741 
742 	s = spltty();
743 	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
744 	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
745 	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
746 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
747 	splx(s);
748 	return (0);
749 }
750 
751 static int
752 set_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
753 {
754 #define	cc (&sc->sc_cursor)
755 	u_int v, index = 0, count = 0, icount = 0;
756 	uint8_t r[2], g[2], b[2], image[512], mask[512];
757 	int error, s;
758 
759 	v = p->which;
760 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
761 		index = p->cmap.index;
762 		count = p->cmap.count;
763 		if (index >= 2 || (index + count) > 2)
764 			return (EINVAL);
765 		error = copyin(p->cmap.red, &r[index], count);
766 		if (error)
767 			return error;
768 		error = copyin(p->cmap.green, &g[index], count);
769 		if (error)
770 			return error;
771 		error = copyin(p->cmap.blue, &b[index], count);
772 		if (error)
773 			return error;
774 	}
775 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
776 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
777 			return (EINVAL);
778 		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
779 		error = copyin(p->image, image, icount);
780 		if (error)
781 			return error;
782 		error = copyin(p->mask, mask, icount);
783 		if (error)
784 			return error;
785 	}
786 
787 	s = spltty();
788 	if (v & WSDISPLAY_CURSOR_DOCUR)
789 		sc->sc_curenb = p->enable;
790 	if (v & WSDISPLAY_CURSOR_DOPOS)
791 		set_curpos(sc, &p->pos);
792 	if (v & WSDISPLAY_CURSOR_DOHOT)
793 		cc->cc_hot = p->hot;
794 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
795 		memcpy(&cc->cc_color[index], &r[index], count);
796 		memcpy(&cc->cc_color[index + 2], &g[index], count);
797 		memcpy(&cc->cc_color[index + 4], &b[index], count);
798 	}
799 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
800 		cc->cc_size = p->size;
801 		memset(cc->cc_image, 0, sizeof cc->cc_image);
802 		memcpy(cc->cc_image, image, icount);
803 		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
804 		memcpy(cc->cc_mask, mask, icount);
805 	}
806 	sc->sc_changed |= v;
807 	splx(s);
808 
809 	return (0);
810 #undef cc
811 }
812 
813 static int
814 get_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
815 {
816 	return (EPASSTHROUGH); /* XXX */
817 }
818 
819 static void
820 set_curpos(struct sfbp_softc *sc, struct wsdisplay_curpos *curpos)
821 {
822 	struct rasops_info *ri = sc->sc_ri;
823 	int x = curpos->x, y = curpos->y;
824 
825 	if (y < 0)
826 		y = 0;
827 	else if (y > ri->ri_height)
828 		y = ri->ri_height;
829 	if (x < 0)
830 		x = 0;
831 	else if (x > ri->ri_width)
832 		x = ri->ri_width;
833 	sc->sc_cursor.cc_pos.x = x;
834 	sc->sc_cursor.cc_pos.y = y;
835 }
836 
837 static void
838 bt459visible(void *hw, int on)
839 {
840 	hw += SFB_RAMDAC_OFFSET;
841 	SELECT(hw, BT459_IREG_CCR);
842 	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
843 	tc_wmb();
844 }
845 
846 static void
847 sfbpvisible(void *hw, int on)
848 {
849 	/* XXX use SFBplus ASIC XX */
850 }
851 
852 static void
853 bt459locate(void *hw, struct hwcursor64 *cc)
854 {
855 	int x, y, s;
856 
857 	x = cc->cc_pos.x - cc->cc_hot.x;
858 	y = cc->cc_pos.y - cc->cc_hot.y;
859 	x += cc->cc_magic.x;
860 	y += cc->cc_magic.y;
861 
862 	hw += SFB_RAMDAC_OFFSET;
863 
864 	s = spltty();
865 	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
866 	REG(hw, bt_reg) = x;		tc_wmb();
867 	REG(hw, bt_reg) = x >> 8;	tc_wmb();
868 	REG(hw, bt_reg) = y;		tc_wmb();
869 	REG(hw, bt_reg) = y >> 8;	tc_wmb();
870 	splx(s);
871 }
872 
873 static void
874 sfbplocate(void *hw, struct hwcursor64 *cc)
875 {
876 	int x, y;
877 
878 	x = cc->cc_pos.x - cc->cc_hot.x;
879 	y = cc->cc_pos.y - cc->cc_hot.y;
880 
881 	hw += SFB_ASIC_OFFSET;
882 	*((u_int32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
883 	tc_wmb();
884 }
885 
886 static void
887 bt459color(void *hw, u_int8_t *cp)
888 {
889 
890 	hw += SFB_RAMDAC_OFFSET;
891 
892 	SELECT(hw, BT459_IREG_CCOLOR_2);
893 	REG(hw, bt_reg) = cp[1]; tc_wmb();
894 	REG(hw, bt_reg) = cp[3]; tc_wmb();
895 	REG(hw, bt_reg) = cp[5]; tc_wmb();
896 
897 	REG(hw, bt_reg) = cp[0]; tc_wmb();
898 	REG(hw, bt_reg) = cp[2]; tc_wmb();
899 	REG(hw, bt_reg) = cp[4]; tc_wmb();
900 }
901 
902 static void
903 bt463color(void *hw, u_int8_t *cp)
904 {
905 }
906 
907 static void
908 bt459shape(void *hw, struct wsdisplay_curpos *size, u_int64_t *image)
909 {
910 	u_int8_t *ip, *mp, img, msk;
911 	u_int8_t u;
912 	int bcnt;
913 
914 	hw += SFB_RAMDAC_OFFSET;
915 	ip = (u_int8_t *)image;
916 	mp = (u_int8_t *)(image + CURSOR_MAX_SIZE);
917 
918 	bcnt = 0;
919 	SELECT(hw, BT459_IREG_CRAM_BASE+0);
920 	/* 64 pixel scan line is consisted with 16 byte cursor ram */
921 	while (bcnt < size->y * 16) {
922 		/* pad right half 32 pixel when smaller than 33 */
923 		if ((bcnt & 0x8) && size->x < 33) {
924 			REG(hw, bt_reg) = 0; tc_wmb();
925 			REG(hw, bt_reg) = 0; tc_wmb();
926 		}
927 		else {
928 			img = *ip++;
929 			msk = *mp++;
930 			img &= msk;	/* cookie off image */
931 			u = (msk & 0x0f) << 4 | (img & 0x0f);
932 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
933 			u = (msk & 0xf0) | (img & 0xf0) >> 4;
934 			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
935 		}
936 		bcnt += 2;
937 	}
938 	/* pad unoccupied scan lines */
939 	while (bcnt < CURSOR_MAX_SIZE * 16) {
940 		REG(hw, bt_reg) = 0; tc_wmb();
941 		REG(hw, bt_reg) = 0; tc_wmb();
942 		bcnt += 2;
943 	}
944 }
945 
946 static void
947 sfbpshape(void *hw, struct wsdisplay_curpos *size, u_int64_t *image)
948 {
949 	/* XXX use SFBplus ASIC XXX */
950 }
951 
952 static void
953 bt459setlut(void *hw, struct hwcmap265 *cm)
954 {
955 	int index;
956 
957 	hw += SFB_RAMDAC_OFFSET;
958 	SELECT(hw, 0);
959 	for (index = 0; index < CMAP_SIZE; index++) {
960 		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
961 		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
962 		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
963 	}
964 }
965 
966 static void
967 noplut(void *hw, struct hwcmap265 *cm)
968 {
969 }
970 
971 #define SFBBPP 32
972 
973 #define	MODE_SIMPLE		0
974 #define	MODE_OPAQUESTIPPLE	1
975 #define	MODE_OPAQUELINE		2
976 #define	MODE_TRANSPARENTSTIPPLE	5
977 #define	MODE_TRANSPARENTLINE	6
978 #define	MODE_COPY		7
979 
980 #if SFBBPP == 8
981 /* parameters for 8bpp configuration */
982 #define	SFBALIGNMASK		0x7
983 #define	SFBPIXELBYTES		1
984 #define	SFBSTIPPLEALL1		0xffffffff
985 #define	SFBSTIPPLEBITS		32
986 #define	SFBSTIPPLEBITMASK	0x1f
987 #define	SFBSTIPPLEBYTESDONE	32
988 #define	SFBCOPYALL1		0xffffffff
989 #define	SFBCOPYBITS		32
990 #define	SFBCOPYBITMASK		0x1f
991 #define	SFBCOPYBYTESDONE	32
992 
993 #elif SFBBPP == 32
994 /* parameters for 32bpp configuration */
995 #define	SFBALIGNMASK		0x7
996 #define	SFBPIXELBYTES		4
997 #define	SFBSTIPPLEALL1		0x0000ffff
998 #define	SFBSTIPPLEBITS		16
999 #define	SFBSTIPPLEBITMASK	0xf
1000 #define	SFBSTIPPLEBYTESDONE	32
1001 #define	SFBCOPYALL1		0x000000ff
1002 #define	SFBCOPYBITS		8
1003 #define	SFBCOPYBITMASK		0x3
1004 #define	SFBCOPYBYTESDONE	32
1005 #endif
1006 
1007 #ifdef pmax
1008 #define	WRITE_MB()
1009 #define	BUMP(p) (p)
1010 #endif
1011 
1012 #ifdef alpha
1013 #define	WRITE_MB() tc_wmb()
1014 /* registers is replicated in 1KB stride; rap round 4th iteration */
1015 #define	BUMP(p) ((p) = (void *)(((long)(p) + 0x400) & ~0x1000))
1016 #endif
1017 
1018 #define	SFBMODE(p, v) \
1019 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
1020 #define	SFBROP(p, v) \
1021 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
1022 #define	SFBPLANEMASK(p, v) \
1023 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
1024 #define	SFBPIXELMASK(p, v) \
1025 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
1026 #define	SFBADDRESS(p, v) \
1027 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
1028 #define	SFBSTART(p, v) \
1029 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
1030 #define	SFBPIXELSHIFT(p, v) \
1031 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
1032 #define	SFBFG(p, v) \
1033 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
1034 #define	SFBBG(p, v) \
1035 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
1036 #define	SFBBCONT(p, v) \
1037 		(*(u_int32_t *)(BUMP(p) + SFB_ASIC_BCONT) = (v))
1038 
1039 #define	SFBDATA(p, v) \
1040 		(*((u_int32_t *)BUMP(p) + TGA_REG_GDAR) = (v))
1041 
1042 #define	SFBCOPY64BYTESDONE	8
1043 #define	SFBCOPY64BITS		64
1044 #define	SFBCOPY64SRC(p, v) \
1045 		(*((u_int32_t *)BUMP(p) + TGA_REG_GCSR) = (long)(v))
1046 #define	SFBCOPY64DST(p, v) \
1047 		(*((u_int32_t *)BUMP(p) + TGA_REG_GCDR) = (long)(v))
1048 
1049 /*
1050  * Actually write a string to the frame buffer.
1051  */
1052 static void
1053 sfbp_putchar(void *id, int row, int col, u_int uc, long attr)
1054 {
1055 	struct rasops_info *ri = id;
1056 	void *sfb, *p;
1057 	int scanspan, height, width, align, x, y;
1058 	u_int32_t lmask, rmask, glyph;
1059 	u_int8_t *g;
1060 
1061 	x = col * ri->ri_font->fontwidth;
1062 	y = row * ri->ri_font->fontheight;
1063 	scanspan = ri->ri_stride;
1064 	height = ri->ri_font->fontheight;
1065 	uc -= ri->ri_font->firstchar;
1066 	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
1067 
1068 	p = ri->ri_bits + y * scanspan + x * SFBPIXELBYTES;
1069 	align = (long)p & SFBALIGNMASK;
1070 	p -= align;
1071 	align /= SFBPIXELBYTES;
1072 	width = ri->ri_font->fontwidth + align;
1073 	lmask = SFBSTIPPLEALL1 << align;
1074 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1075 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1076 
1077 	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
1078 	SFBPLANEMASK(sfb, ~0);
1079 	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
1080 	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1081 	SFBROP(sfb, (3 << 8) | 3); /* ROP_COPY24 */
1082 	*((u_int32_t *)sfb + TGA_REG_GPXR_P) = lmask & rmask;
1083 
1084 	/* XXX 2B stride fonts only XXX */
1085 	while (height > 0) {
1086 		glyph = *(u_int16_t *)g;		/* XXX */
1087 		*(u_int32_t *)p = glyph << align;
1088 		p += scanspan;
1089 		g += 2;					/* XXX */
1090 		height--;
1091 	}
1092 	SFBMODE(sfb, MODE_SIMPLE);
1093 	*((u_int32_t *)sfb + TGA_REG_GPXR_P) = ~0;
1094 }
1095 
1096 #undef	SFBSTIPPLEALL1
1097 #undef	SFBSTIPPLEBITS
1098 #undef	SFBSTIPPLEBITMASK
1099 #define	SFBSTIPPLEALL1		SFBCOPYALL1
1100 #define	SFBSTIPPLEBITS		SFBCOPYBITS
1101 #define	SFBSTIPPLEBITMASK	SFBCOPYBITMASK
1102 
1103 /*
1104  * Clear characters in a line.
1105  */
1106 static void
1107 sfbp_erasecols(void *id, int row, int startcol, int ncols, long attr)
1108 {
1109 	struct rasops_info *ri = id;
1110 	void *sfb, *p;
1111 	int scanspan, startx, height, width, align, w, y;
1112 	u_int32_t lmask, rmask;
1113 
1114 	scanspan = ri->ri_stride;
1115 	y = row * ri->ri_font->fontheight;
1116 	startx = startcol * ri->ri_font->fontwidth;
1117 	height = ri->ri_font->fontheight;
1118 	w = ri->ri_font->fontwidth * ncols;
1119 
1120 	p = ri->ri_bits + y * scanspan + startx * SFBPIXELBYTES;
1121 	align = (long)p & SFBALIGNMASK;
1122 	align /= SFBPIXELBYTES;
1123 	p -= align;
1124 	width = w + align;
1125 	lmask = SFBSTIPPLEALL1 << align;
1126 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1127 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1128 
1129 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1130 	SFBPLANEMASK(sfb, ~0);
1131 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1132 	if (width <= SFBSTIPPLEBITS) {
1133 		lmask = lmask & rmask;
1134 		while (height > 0) {
1135 			*(u_int32_t *)p = lmask;
1136 			p += scanspan;
1137 			height--;
1138 		}
1139 	}
1140 	else {
1141 		void *q = p;
1142 		while (height > 0) {
1143 			*(u_int32_t *)p = lmask;
1144 			WRITE_MB();
1145 			width -= 2 * SFBSTIPPLEBITS;
1146 			while (width > 0) {
1147 				p += SFBSTIPPLEBYTESDONE;
1148 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1149 				WRITE_MB();
1150 				width -= SFBSTIPPLEBITS;
1151 			}
1152 			p += SFBSTIPPLEBYTESDONE;
1153 			*(u_int32_t *)p = rmask;
1154 			WRITE_MB();
1155 
1156 			p = (q += scanspan);
1157 			width = w + align;
1158 			height--;
1159 		}
1160 	}
1161 	SFBMODE(sfb, MODE_SIMPLE);
1162 }
1163 
1164 #if 1
1165 /*
1166  * Copy lines.
1167  */
1168 static void
1169 sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1170 {
1171 	struct rasops_info *ri = id;
1172 	void *sfb, *p;
1173 	int scanspan, offset, srcy, height, width, align, w;
1174 	u_int32_t lmask, rmask;
1175 
1176 	scanspan = ri->ri_stride;
1177 	height = ri->ri_font->fontheight * nrows;
1178 	offset = (dstrow - srcrow) * ri->ri_yscale;
1179 	srcy = ri->ri_font->fontheight * srcrow;
1180 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1181 		scanspan = -scanspan;
1182 		srcy += height;
1183 	}
1184 
1185 	p = ri->ri_bits + srcy * ri->ri_stride;
1186 	align = (long)p & SFBALIGNMASK;
1187 	p -= align;
1188 	align /= SFBPIXELBYTES;
1189 	w = ri->ri_emuwidth;
1190 	width = w + align;
1191 	lmask = SFBCOPYALL1 << align;
1192 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1193 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1194 
1195 	SFBMODE(sfb, MODE_COPY);
1196 	SFBPLANEMASK(sfb, ~0);
1197 	SFBPIXELSHIFT(sfb, 0);
1198 	if (width <= SFBCOPYBITS) {
1199 		/* never happens */;
1200 	}
1201 	else {
1202 		void *q = p;
1203 		while (height > 0) {
1204 			*(u_int32_t *)p = lmask;
1205 			*(u_int32_t *)(p + offset) = lmask;
1206 			width -= 2 * SFBCOPYBITS;
1207 			while (width > 0) {
1208 				p += SFBCOPYBYTESDONE;
1209 				*(u_int32_t *)p = SFBCOPYALL1;
1210 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1211 				width -= SFBCOPYBITS;
1212 			}
1213 			p += SFBCOPYBYTESDONE;
1214 			*(u_int32_t *)p = rmask;
1215 			*(u_int32_t *)(p + offset) = rmask;
1216 
1217 			p = (q += scanspan);
1218 			width = w + align;
1219 			height--;
1220 		}
1221 	}
1222 	SFBMODE(sfb, MODE_SIMPLE);
1223 }
1224 
1225 #else
1226 
1227 
1228 static void
1229 sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1230 {
1231 	struct rasops_info *ri = id;
1232 	void *sfb, *p, *q;
1233 	int scanspan, offset, srcy, height, width, w, align;
1234 	u_int32_t rmask, lmask;
1235 
1236 	scanspan = ri->ri_stride;
1237 	height = ri->ri_font->fontheight * nrows;
1238 	offset = (dstrow - srcrow) * ri->ri_yscale;
1239 	srcy = ri->ri_font->fontheight * srcrow;
1240 	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1241 		scanspan = -scanspan;
1242 		srcy += height;
1243 	}
1244 
1245 	p = ri->ri_bits + srcy * ri->ri_stride;
1246 	align = (long)p & SFBALIGNMASK;
1247 	w = ri->ri_emuwidth;
1248 	width = w + align;
1249 	lmask = SFBCOPYALL1 << align;
1250 	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1251 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1252 	q = p;
1253 
1254 	SFBMODE(sfb, MODE_COPY);
1255 	SFBPLANEMASK(sfb, ~0);
1256 	SFBPIXELSHIFT(sfb, 0);
1257 
1258 	if (width <= SFBCOPYBITS)
1259 		; /* never happens */
1260 	else if (width < SFBCOPY64BITS) {
1261 		; /* unlikely happens */
1262 
1263 	}
1264 	else {
1265 		while (height > 0) {
1266 			while (width >= SFBCOPY64BITS) {
1267 				SFBCOPY64SRC(sfb, *p);
1268 				SFBCOPY64DST(sfb, *p + offset);
1269 				p += SFBCOPY64BYTESDONE;
1270 				width -= SFBCOPY64BITS;
1271 			}
1272 			if (width >= SFBCOPYBITS) {
1273 				*(u_int32_t *)p = SFBCOPYALL1;
1274 				*(u_int32_t *)(p + offset) = SFBCOPYALL1;
1275 				p += SFBCOPYBYTESDONE;
1276 				width -= SFBCOPYBITS;
1277 			}
1278 			if (width > 0) {
1279 				*(u_int32_t *)p = rmask;
1280 				*(u_int32_t *)(p + offset) = rmask;
1281 			}
1282 
1283 			p = (q += scanspan);
1284 			width = w;
1285 			height--;
1286 		}
1287 	}
1288 	SFBMODE(sfb, MODE_SIMPLE);
1289 }
1290 #endif
1291 
1292 /*
1293  * Erase lines.
1294  */
1295 static void
1296 sfbp_eraserows(void *id, int startrow, int nrows, long attr)
1297 {
1298 	struct rasops_info *ri = id;
1299 	void *sfb, *p;
1300 	int scanspan, starty, height, width, align, w;
1301 	u_int32_t lmask, rmask;
1302 
1303 	scanspan = ri->ri_stride;
1304 	starty = ri->ri_font->fontheight * startrow;
1305 	height = ri->ri_font->fontheight * nrows;
1306 
1307 	p = ri->ri_bits + starty * scanspan;
1308 	align = (long)p & SFBALIGNMASK;
1309 	p -= align;
1310 	align /= SFBPIXELBYTES;
1311 	w = ri->ri_emuwidth * SFBPIXELBYTES;
1312 	width = w + align;
1313 	lmask = SFBSTIPPLEALL1 << align;
1314 	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1315 	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1316 
1317 	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1318 	SFBPLANEMASK(sfb, ~0);
1319 	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1320 	if (width <= SFBSTIPPLEBITS) {
1321 		/* never happens */;
1322 	}
1323 	else {
1324 		void *q = p;
1325 		while (height > 0) {
1326 			*(u_int32_t *)p = lmask;
1327 			WRITE_MB();
1328 			width -= 2 * SFBSTIPPLEBITS;
1329 			while (width > 0) {
1330 				p += SFBSTIPPLEBYTESDONE;
1331 				*(u_int32_t *)p = SFBSTIPPLEALL1;
1332 				WRITE_MB();
1333 				width -= SFBSTIPPLEBITS;
1334 			}
1335 			p += SFBSTIPPLEBYTESDONE;
1336 			*(u_int32_t *)p = rmask;
1337 			WRITE_MB();
1338 
1339 			p = (q += scanspan);
1340 			width = w + align;
1341 			height--;
1342 		}
1343 	}
1344 	SFBMODE(sfb, MODE_SIMPLE);
1345 }
1346