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