1/* $NetBSD: sfbplus.c,v 1.42 2021/12/06 17:43:50 abs 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.42 2021/12/06 17:43:50 abs 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
80struct 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
87struct 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
98struct 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
107struct 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
124static int  sfbpmatch(device_t, cfdata_t, void *);
125static void sfbpattach(device_t, device_t, void *);
126
127CFATTACH_DECL_NEW(sfbp, sizeof(struct sfbp_softc),
128    sfbpmatch, sfbpattach, NULL, NULL);
129
130static void sfbp_common_init(struct rasops_info *);
131static struct rasops_info sfbp_console_ri;
132static tc_addr_t sfbp_consaddr;
133
134static struct wsscreen_descr sfbp_stdscreen = {
135	"std", 0, 0,
136	NULL, /* textops */
137	0, 0,
138	WSSCREEN_REVERSE
139};
140
141static const struct wsscreen_descr *_sfb_scrlist[] = {
142	&sfbp_stdscreen,
143};
144
145static const struct wsscreen_list sfb_screenlist = {
146	sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
147};
148
149static int	sfbioctl(void *, void *, u_long, void *, int, struct lwp *);
150static paddr_t	sfbmmap(void *, void *, off_t, int);
151
152static int	sfb_alloc_screen(void *, const struct wsscreen_descr *,
153				      void **, int *, int *, long *);
154static void	sfb_free_screen(void *, void *);
155static int	sfb_show_screen(void *, void *, int,
156				     void (*) (void *, int, int), void *);
157static void sfbp_putchar(void *, int, int, u_int, long);
158static void sfbp_erasecols(void *, int, int, int, long);
159static void sfbp_eraserows(void *, int, int, long);
160static void sfbp_copyrows(void *, int, int, int);
161
162static 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
171static void bt459init(void *);
172static void bt459visible(void *, int);
173static void bt459locate(void *, struct hwcursor64 *);
174static void bt459shape(void *, struct wsdisplay_curpos *, uint64_t *);
175static void bt459color(void *, uint8_t *);
176static void bt459setlut(void *, struct hwcmap256 *);
177
178static void sfbpvisible(void *, int);
179static void sfbplocate(void *, struct hwcursor64 *);
180static void sfbpshape(void *, struct wsdisplay_curpos *, uint64_t *);
181static void bt463init(void *);
182static void bt463color(void *, uint8_t *);
183static void noplut(void *, struct hwcmap256 *);
184
185/* EXPORT */ int sfbp_cnattach(tc_addr_t);
186static int  sfbpintr(void *);
187static void sfbp_cmap_init(struct sfbp_softc *);
188
189static int  get_cmap(struct sfbp_softc *, struct wsdisplay_cmap *);
190static int  set_cmap(struct sfbp_softc *, struct wsdisplay_cmap *);
191static int  set_cursor(struct sfbp_softc *, struct wsdisplay_cursor *);
192static int  get_cursor(struct sfbp_softc *, struct wsdisplay_cursor *);
193static 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 */
202static 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
237static int
238sfbpmatch(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
248static void
249sfbpattach(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_WAITOK | M_ZERO);
266		ri->ri_hw = (void *)ta->ta_addr;
267		sfbp_common_init(ri);
268		sc->sc_ri = ri;
269	}
270	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height,
271	    (ri->ri_depth != 32) ? 8 : 24);
272
273	sc->sc_vaddr = ta->ta_addr;
274	sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
275	sc->sc_cursor.cc_magic.y = HX_MAGIC_Y;
276	sc->sc_blanked = sc->sc_curenb = 0;
277
278	if (ri->ri_depth == 8) {
279		sc->sc_hwops.visible = bt459visible;
280		sc->sc_hwops.locate = bt459locate;
281		sc->sc_hwops.shape = bt459shape;
282		sc->sc_hwops.color = bt459color;
283		sc->sc_hwops.setlut = bt459setlut;
284		sc->sc_hwops.getlut = noplut;
285	} else {
286		sc->sc_hwops.visible = sfbpvisible;
287		sc->sc_hwops.locate = sfbplocate;
288		sc->sc_hwops.shape = sfbpshape;
289		sc->sc_hwops.color = bt463color;
290		sc->sc_hwops.setlut = noplut;
291		sc->sc_hwops.getlut = noplut;
292	}
293	sfbp_cmap_init(sc);
294
295        tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, sfbpintr, sc);
296
297	asic = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
298	*(uint32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
299	*(uint32_t *)(asic + SFB_ASIC_ENABLE_INTR) = 1;
300
301	waa.console = console;
302	waa.scrdata = &sfb_screenlist;
303	waa.accessops = &sfb_accessops;
304	waa.accesscookie = sc;
305
306	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
307}
308
309static void
310sfbp_cmap_init(struct sfbp_softc *sc)
311{
312	struct hwcmap256 *cm;
313	const uint8_t *p;
314	int index;
315
316	if (sc->sc_ri->ri_depth != 8)
317		return;
318
319	cm = &sc->sc_cmap;
320	p = rasops_cmap;
321	for (index = 0; index < CMAP_SIZE; index++, p += 3) {
322		cm->r[index] = p[0];
323		cm->g[index] = p[1];
324		cm->b[index] = p[2];
325	}
326}
327
328static void
329sfbp_common_init(struct rasops_info *ri)
330{
331	char *base, *asic;
332	int i, depth, hsetup, vsetup, vbase, cookie;
333
334	base = ri->ri_hw;
335	asic = base + SFB_ASIC_OFFSET;
336	hsetup = *(uint32_t *)(asic + SFB_ASIC_VIDEO_HSETUP);
337	vsetup = *(uint32_t *)(asic + SFB_ASIC_VIDEO_VSETUP);
338	i = *(uint32_t *)(asic + SFB_ASIC_DEEP);
339	depth = (i & 01) ? 32 : 8;
340
341	/*
342	 * - neglect 0,1 cases of hsetup register.
343	 * - observed 804x600?, 644x480? values.
344	 */
345
346	*(uint32_t *)(asic + SFB_ASIC_VIDEO_BASE) = vbase = 1;
347	vbase *= (i & 0x20) ? 2048 : 4096;	/* VRAM chip size */
348	if (i & 1) vbase *= 4;			/* bytes per pixel */
349
350	*(uint32_t *)(asic + SFB_ASIC_PLANEMASK) = ~0;
351	*(uint32_t *)(asic + SFB_ASIC_PIXELMASK) = ~0;
352	*(uint32_t *)(asic + SFB_ASIC_MODE) = 0;	/* MODE_SIMPLE */
353	*(uint32_t *)(asic + SFB_ASIC_ROP) = 3;		/* ROP_COPY */
354
355	/* initialize colormap and cursor hardware */
356	if (depth != 32) {
357		*(uint32_t *)(asic + 0x180000) = 0;	/* Bt459 reset */
358		bt459init(base + SFB_RAMDAC_OFFSET);
359	}
360	else {
361		bt463init(base + SFB_RAMDAC_OFFSET);
362	}
363
364	ri->ri_flg = RI_CENTER;
365	if (ri == &sfbp_console_ri)
366		ri->ri_flg |= RI_NO_AUTO;
367	ri->ri_flg = 0;			/* XXX 32bpp RI_CENTER fails XXX */
368	ri->ri_depth = depth;
369	ri->ri_width = (hsetup & 0x1ff) << 2;
370	ri->ri_height = (vsetup & 0x7ff);
371	ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
372	ri->ri_bits = base + 0x800000 + vbase;
373
374	if (depth == 32) {
375		ri->ri_rnum = 8;
376		ri->ri_gnum = 8;
377		ri->ri_bnum = 8;
378		ri->ri_rpos = 16;
379		ri->ri_gpos = 8;
380		ri->ri_bpos = 0;
381	}
382
383	/* clear the screen */
384	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
385
386	wsfont_init();
387	/* prefer 12 pixel wide font */
388	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
389	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
390	if (cookie <= 0)
391		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
392		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
393	if (cookie <= 0) {
394		printf("sfbp: font table is empty\n");
395		return;
396	}
397
398	/* the accelerated sfbp_putchar() needs LSbit left */
399	if (wsfont_lock(cookie, &ri->ri_font)) {
400		printf("sfb: couldn't lock font\n");
401		return;
402	}
403	ri->ri_wsfcookie = cookie;
404
405	rasops_init(ri, 34, 80);
406
407	/* add our accelerated functions */
408	ri->ri_ops.putchar = sfbp_putchar;
409	ri->ri_ops.erasecols = sfbp_erasecols;
410	ri->ri_ops.copyrows = sfbp_copyrows;
411	ri->ri_ops.eraserows = sfbp_eraserows;
412
413	/* XXX shouldn't be global */
414	sfbp_stdscreen.nrows = ri->ri_rows;
415	sfbp_stdscreen.ncols = ri->ri_cols;
416	sfbp_stdscreen.textops = &ri->ri_ops;
417	sfbp_stdscreen.capabilities = ri->ri_caps;
418	/* our accelerated putchar can't underline */
419	sfbp_stdscreen.capabilities &= ~WSSCREEN_UNDERLINE;
420}
421
422static int
423sfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
424{
425	struct sfbp_softc *sc = v;
426	struct rasops_info *ri = sc->sc_ri;
427	int turnoff, s;
428
429	switch (cmd) {
430	case WSDISPLAYIO_GTYPE:
431		*(u_int *)data = WSDISPLAY_TYPE_SFBP;
432		return (0);
433
434	case WSDISPLAYIO_GET_FBINFO: {
435		struct wsdisplayio_fbinfo *fbi = data;
436		return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
437	}
438
439	case WSDISPLAYIO_GINFO:
440#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
441		wsd_fbip->height = ri->ri_height;
442		wsd_fbip->width = ri->ri_width;
443		wsd_fbip->depth = ri->ri_depth;
444		wsd_fbip->cmsize = CMAP_SIZE;	/* XXX */
445#undef fbt
446		return (0);
447
448	case WSDISPLAYIO_GETCMAP:
449		return get_cmap(sc, (struct wsdisplay_cmap *)data);
450
451	case WSDISPLAYIO_PUTCMAP:
452		return set_cmap(sc, (struct wsdisplay_cmap *)data);
453
454	case WSDISPLAYIO_SVIDEO:
455		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
456		if ((sc->sc_blanked == 0) ^ turnoff) {
457			sc->sc_blanked = turnoff;
458#if 0 /* XXX later XXX */
459	Low order 3bit control visibilities of screen and builtin cursor.
460#endif	/* XXX XXX XXX */
461		}
462		return (0);
463
464	case WSDISPLAYIO_GVIDEO:
465		*(u_int *)data = sc->sc_blanked ?
466		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
467		return (0);
468
469	case WSDISPLAYIO_GCURPOS:
470		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
471		return (0);
472
473	case WSDISPLAYIO_SCURPOS:
474		s = spltty();
475		set_curpos(sc, (struct wsdisplay_curpos *)data);
476		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
477		splx(s);
478		return (0);
479
480	case WSDISPLAYIO_GCURMAX:
481		((struct wsdisplay_curpos *)data)->x =
482		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
483		return (0);
484
485	case WSDISPLAYIO_GCURSOR:
486		return get_cursor(sc, (struct wsdisplay_cursor *)data);
487
488	case WSDISPLAYIO_SCURSOR:
489		return set_cursor(sc, (struct wsdisplay_cursor *)data);
490
491	case WSDISPLAYIO_SMODE:
492		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
493			s = spltty();
494			sfbp_cmap_init(sc);
495			sc->sc_curenb = 0;
496			sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
497			    WSDISPLAY_CMAP_DOLUT);
498			splx(s);
499		}
500		return (0);
501	}
502	return (EPASSTHROUGH);
503}
504
505paddr_t
506sfbmmap(void *v, void *vs, off_t offset, int prot)
507{
508	struct sfbp_softc *sc = v;
509
510	if (offset >= 0x1000000 || offset < 0) /* XXX 16MB XXX */
511		return (-1);
512	return machine_btop(sc->sc_vaddr + offset);
513}
514
515static int
516sfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
517    int *curxp, int *curyp, long *attrp)
518{
519	struct sfbp_softc *sc = v;
520	struct rasops_info *ri = sc->sc_ri;
521	long defattr;
522
523	if (sc->nscreens > 0)
524		return (ENOMEM);
525
526	*cookiep = ri;		 /* one and only for now */
527	*curxp = 0;
528	*curyp = 0;
529	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
530	*attrp = defattr;
531	sc->nscreens++;
532	return (0);
533}
534
535void
536sfb_free_screen(void *v, void *cookie)
537{
538	struct sfbp_softc *sc = v;
539
540	if (sc->sc_ri == &sfbp_console_ri)
541		panic("sfb_free_screen: console");
542
543	sc->nscreens--;
544}
545
546static int
547sfb_show_screen(void *v, void *cookie, int waitok,
548    void (*cb)(void *, int, int), void *cbarg)
549{
550
551	return (0);
552}
553
554int
555sfbp_cnattach(tc_addr_t addr)
556{
557	struct rasops_info *ri;
558	long defattr;
559
560	ri = &sfbp_console_ri;
561	ri->ri_hw = (void *)addr;
562	sfbp_common_init(ri);
563	(*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
564	wsdisplay_cnattach(&sfbp_stdscreen, ri, 0, 0, defattr);
565	sfbp_consaddr = addr;
566	return (0);
567}
568
569static int
570sfbpintr(void *arg)
571{
572#define	cc (&sc->sc_cursor)
573	struct sfbp_softc *sc = arg;
574	char *base, *asic;
575	uint32_t sisr;
576	int v;
577
578	base = sc->sc_ri->ri_hw;
579	asic = base + SFB_ASIC_OFFSET;
580	sisr = *((uint32_t *)asic + TGA_REG_SISR);
581	*(uint32_t *)(asic + SFB_ASIC_CLEAR_INTR) = 0;
582
583	if (sc->sc_changed == 0)
584		goto done;
585
586	v = sc->sc_changed;
587	if (v & WSDISPLAY_CURSOR_DOCUR)
588		(*sc->sc_hwops.visible)(base, sc->sc_curenb);
589	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT))
590		(*sc->sc_hwops.locate)(base, cc);
591	if (v & WSDISPLAY_CURSOR_DOCMAP)
592		(*sc->sc_hwops.color)(base, cc->cc_color);
593	if (v & WSDISPLAY_CURSOR_DOSHAPE)
594		(*sc->sc_hwops.shape)(base, &cc->cc_size, cc->cc_image);
595	if (v & WSDISPLAY_CMAP_DOLUT)
596		(*sc->sc_hwops.setlut)(base, &sc->sc_cmap);
597	sc->sc_changed = 0;
598done:
599	*((uint32_t *)asic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
600	return (1);
601#undef cc
602}
603
604static void
605bt459init(void *vdac)
606{
607	const uint8_t *p;
608	int i;
609
610	SELECT(vdac, BT459_IREG_COMMAND_0);
611	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
612	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
613	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
614	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
615	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
616	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
617	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
618	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
619	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
620	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
621	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
622
623	SELECT(vdac, BT459_IREG_CCR);
624	REG(vdac, bt_reg) = 0x0;	tc_wmb();
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
638	/* build sane colormap */
639	SELECT(vdac, 0);
640	p = rasops_cmap;
641	for (i = 0; i < CMAP_SIZE; i++, p += 3) {
642		REG(vdac, bt_cmap) = p[0];	tc_wmb();
643		REG(vdac, bt_cmap) = p[1];	tc_wmb();
644		REG(vdac, bt_cmap) = p[2];	tc_wmb();
645	}
646
647	/* clear out cursor image */
648	SELECT(vdac, BT459_IREG_CRAM_BASE);
649	for (i = 0; i < 1024; i++)
650		REG(vdac, bt_reg) = 0xff;	tc_wmb();
651
652	/*
653	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
654	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
655	 * image color.  CCOLOR_1 will be never used.
656	 */
657	SELECT(vdac, BT459_IREG_CCOLOR_1);
658	REG(vdac, bt_reg) = 0xff;	tc_wmb();
659	REG(vdac, bt_reg) = 0xff;	tc_wmb();
660	REG(vdac, bt_reg) = 0xff;	tc_wmb();
661
662	REG(vdac, bt_reg) = 0;		tc_wmb();
663	REG(vdac, bt_reg) = 0;		tc_wmb();
664	REG(vdac, bt_reg) = 0;		tc_wmb();
665
666	REG(vdac, bt_reg) = 0xff;	tc_wmb();
667	REG(vdac, bt_reg) = 0xff;	tc_wmb();
668	REG(vdac, bt_reg) = 0xff;	tc_wmb();
669}
670
671static void
672bt463init(void *vdac)
673{
674	int i;
675
676	SELECT(vdac, BT463_IREG_COMMAND_0);
677	REG(vdac, bt_reg) = 0x40;	tc_wmb();	/* CMD 0 */
678	REG(vdac, bt_reg) = 0x48;	tc_wmb();	/* CMD 1 */
679	REG(vdac, bt_reg) = 0xc0;	tc_wmb();	/* CMD 2 */
680	REG(vdac, bt_reg) = 0;		tc_wmb();	/* !? 204 !? */
681	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  0:7  */
682	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane  8:15 */
683	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 16:23 */
684	REG(vdac, bt_reg) = 0xff;	tc_wmb();	/* plane 24:27 */
685	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  0:7  */
686	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink  8:15 */
687	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 16:23 */
688	REG(vdac, bt_reg) = 0x00;	tc_wmb();	/* blink 24:27 */
689	REG(vdac, bt_reg) = 0x00;	tc_wmb();
690
691	SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
692	for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
693		REG(vdac, bt_reg) = 0x00;	/*   0:7  */
694		REG(vdac, bt_reg) = 0xe1;	/*   8:15 */
695		REG(vdac, bt_reg) = 0x81; 	/*  16:23 */
696	}
697}
698
699static int
700get_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
701{
702	u_int index = p->index, count = p->count;
703	int error;
704
705	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
706		return (EINVAL);
707
708	error = copyout(&sc->sc_cmap.r[index], p->red, count);
709	if (error)
710		return error;
711	error = copyout(&sc->sc_cmap.g[index], p->green, count);
712	if (error)
713		return error;
714	error = copyout(&sc->sc_cmap.b[index], p->blue, count);
715	return error;
716}
717
718static int
719set_cmap(struct sfbp_softc *sc, struct wsdisplay_cmap *p)
720{
721	struct hwcmap256 cmap;
722	u_int index = p->index, count = p->count;
723	int error, s;
724
725	if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
726		return (EINVAL);
727
728	error = copyin(p->red, &cmap.r[index], count);
729	if (error)
730		return error;
731	error = copyin(p->green, &cmap.g[index], count);
732	if (error)
733		return error;
734	error = copyin(p->blue, &cmap.b[index], count);
735	if (error)
736		return error;
737
738	s = spltty();
739	memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
740	memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
741	memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
742	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
743	splx(s);
744	return (0);
745}
746
747static int
748set_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
749{
750#define	cc (&sc->sc_cursor)
751	u_int v, index = 0, count = 0, icount = 0;
752	uint8_t r[2], g[2], b[2], image[512], mask[512];
753	int error, s;
754
755	v = p->which;
756	if (v & WSDISPLAY_CURSOR_DOCMAP) {
757		index = p->cmap.index;
758		count = p->cmap.count;
759		if (index >= 2 || count > 2 - index)
760			return (EINVAL);
761		error = copyin(p->cmap.red, &r[index], count);
762		if (error)
763			return error;
764		error = copyin(p->cmap.green, &g[index], count);
765		if (error)
766			return error;
767		error = copyin(p->cmap.blue, &b[index], count);
768		if (error)
769			return error;
770	}
771	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
772		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
773			return (EINVAL);
774		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
775		error = copyin(p->image, image, icount);
776		if (error)
777			return error;
778		error = copyin(p->mask, mask, icount);
779		if (error)
780			return error;
781	}
782
783	s = spltty();
784	if (v & WSDISPLAY_CURSOR_DOCUR)
785		sc->sc_curenb = p->enable;
786	if (v & WSDISPLAY_CURSOR_DOPOS)
787		set_curpos(sc, &p->pos);
788	if (v & WSDISPLAY_CURSOR_DOHOT)
789		cc->cc_hot = p->hot;
790	if (v & WSDISPLAY_CURSOR_DOCMAP) {
791		memcpy(&cc->cc_color[index], &r[index], count);
792		memcpy(&cc->cc_color[index + 2], &g[index], count);
793		memcpy(&cc->cc_color[index + 4], &b[index], count);
794	}
795	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
796		cc->cc_size = p->size;
797		memset(cc->cc_image, 0, sizeof cc->cc_image);
798		memcpy(cc->cc_image, image, icount);
799		memset(cc->cc_mask, 0, sizeof cc->cc_mask);
800		memcpy(cc->cc_mask, mask, icount);
801	}
802	sc->sc_changed |= v;
803	splx(s);
804
805	return (0);
806#undef cc
807}
808
809static int
810get_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
811{
812	return (EPASSTHROUGH); /* XXX */
813}
814
815static void
816set_curpos(struct sfbp_softc *sc, struct wsdisplay_curpos *curpos)
817{
818	struct rasops_info *ri = sc->sc_ri;
819	int x = curpos->x, y = curpos->y;
820
821	if (y < 0)
822		y = 0;
823	else if (y > ri->ri_height)
824		y = ri->ri_height;
825	if (x < 0)
826		x = 0;
827	else if (x > ri->ri_width)
828		x = ri->ri_width;
829	sc->sc_cursor.cc_pos.x = x;
830	sc->sc_cursor.cc_pos.y = y;
831}
832
833static void
834bt459visible(void *hw, int on)
835{
836	hw = (char *)hw + SFB_RAMDAC_OFFSET;
837	SELECT(hw, BT459_IREG_CCR);
838	REG(hw, bt_reg) = (on) ? 0xc0 : 0x00;
839	tc_wmb();
840}
841
842static void
843sfbpvisible(void *hw, int on)
844{
845	/* XXX use SFBplus ASIC XX */
846}
847
848static void
849bt459locate(void *hw, struct hwcursor64 *cc)
850{
851	int x, y, s;
852
853	x = cc->cc_pos.x - cc->cc_hot.x;
854	y = cc->cc_pos.y - cc->cc_hot.y;
855	x += cc->cc_magic.x;
856	y += cc->cc_magic.y;
857
858	hw = (char *)hw + SFB_RAMDAC_OFFSET;
859
860	s = spltty();
861	SELECT(hw, BT459_IREG_CURSOR_X_LOW);
862	REG(hw, bt_reg) = x;		tc_wmb();
863	REG(hw, bt_reg) = x >> 8;	tc_wmb();
864	REG(hw, bt_reg) = y;		tc_wmb();
865	REG(hw, bt_reg) = y >> 8;	tc_wmb();
866	splx(s);
867}
868
869static void
870sfbplocate(void *hw, struct hwcursor64 *cc)
871{
872	int x, y;
873
874	x = cc->cc_pos.x - cc->cc_hot.x;
875	y = cc->cc_pos.y - cc->cc_hot.y;
876
877	hw = (char *)hw + SFB_ASIC_OFFSET;
878	*((uint32_t *)hw + TGA_REG_CXYR) = ((y & 0xfff) << 12) | (x & 0xfff);
879	tc_wmb();
880}
881
882static void
883bt459color(void *hw, uint8_t *cp)
884{
885
886	hw = (char *)hw + SFB_RAMDAC_OFFSET;
887
888	SELECT(hw, BT459_IREG_CCOLOR_2);
889	REG(hw, bt_reg) = cp[1]; tc_wmb();
890	REG(hw, bt_reg) = cp[3]; tc_wmb();
891	REG(hw, bt_reg) = cp[5]; tc_wmb();
892
893	REG(hw, bt_reg) = cp[0]; tc_wmb();
894	REG(hw, bt_reg) = cp[2]; tc_wmb();
895	REG(hw, bt_reg) = cp[4]; tc_wmb();
896}
897
898static void
899bt463color(void *hw, uint8_t *cp)
900{
901}
902
903static void
904bt459shape(void *hw, struct wsdisplay_curpos *size, uint64_t *image)
905{
906	uint8_t *ip, *mp, img, msk;
907	uint8_t u;
908	int bcnt;
909
910	hw = (char *)hw + SFB_RAMDAC_OFFSET;
911	ip = (uint8_t *)image;
912	mp = (uint8_t *)(image + CURSOR_MAX_SIZE);
913
914	bcnt = 0;
915	SELECT(hw, BT459_IREG_CRAM_BASE+0);
916	/* 64 pixel scan line is consisted with 16 byte cursor ram */
917	while (bcnt < size->y * 16) {
918		/* pad right half 32 pixel when smaller than 33 */
919		if ((bcnt & 0x8) && size->x < 33) {
920			REG(hw, bt_reg) = 0; tc_wmb();
921			REG(hw, bt_reg) = 0; tc_wmb();
922		}
923		else {
924			img = *ip++;
925			msk = *mp++;
926			img &= msk;	/* cookie off image */
927			u = (msk & 0x0f) << 4 | (img & 0x0f);
928			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
929			u = (msk & 0xf0) | (img & 0xf0) >> 4;
930			REG(hw, bt_reg) = shuffle[u];	tc_wmb();
931		}
932		bcnt += 2;
933	}
934	/* pad unoccupied scan lines */
935	while (bcnt < CURSOR_MAX_SIZE * 16) {
936		REG(hw, bt_reg) = 0; tc_wmb();
937		REG(hw, bt_reg) = 0; tc_wmb();
938		bcnt += 2;
939	}
940}
941
942static void
943sfbpshape(void *hw, struct wsdisplay_curpos *size, uint64_t *image)
944{
945	/* XXX use SFBplus ASIC XXX */
946}
947
948static void
949bt459setlut(void *hw, struct hwcmap256 *cm)
950{
951	int index;
952
953	hw = (char *)hw + SFB_RAMDAC_OFFSET;
954	SELECT(hw, 0);
955	for (index = 0; index < CMAP_SIZE; index++) {
956		REG(hw, bt_cmap) = cm->r[index];	tc_wmb();
957		REG(hw, bt_cmap) = cm->g[index];	tc_wmb();
958		REG(hw, bt_cmap) = cm->b[index];	tc_wmb();
959	}
960}
961
962static void
963noplut(void *hw, struct hwcmap256 *cm)
964{
965}
966
967#define SFBBPP 32
968
969#define	MODE_SIMPLE		0
970#define	MODE_OPAQUESTIPPLE	1
971#define	MODE_OPAQUELINE		2
972#define	MODE_TRANSPARENTSTIPPLE	5
973#define	MODE_TRANSPARENTLINE	6
974#define	MODE_COPY		7
975
976#if SFBBPP == 8
977/* parameters for 8bpp configuration */
978#define	SFBALIGNMASK		0x7
979#define	SFBPIXELBYTES		1
980#define	SFBSTIPPLEALL1		0xffffffff
981#define	SFBSTIPPLEBITS		32
982#define	SFBSTIPPLEBITMASK	0x1f
983#define	SFBSTIPPLEBYTESDONE	32
984#define	SFBCOPYALL1		0xffffffff
985#define	SFBCOPYBITS		32
986#define	SFBCOPYBITMASK		0x1f
987#define	SFBCOPYBYTESDONE	32
988
989#elif SFBBPP == 32
990/* parameters for 32bpp configuration */
991#define	SFBALIGNMASK		0x7
992#define	SFBPIXELBYTES		4
993#define	SFBSTIPPLEALL1		0x0000ffff
994#define	SFBSTIPPLEBITS		16
995#define	SFBSTIPPLEBITMASK	0xf
996#define	SFBSTIPPLEBYTESDONE	32
997#define	SFBCOPYALL1		0x000000ff
998#define	SFBCOPYBITS		8
999#define	SFBCOPYBITMASK		0x3
1000#define	SFBCOPYBYTESDONE	32
1001#endif
1002
1003#ifdef pmax
1004#define	WRITE_MB()
1005#define	BUMP(p) (p)
1006#endif
1007
1008#ifdef alpha
1009#define	WRITE_MB() tc_wmb()
1010/* registers is replicated in 1KB stride; rap round 4th iteration */
1011#define	BUMP(p) ((p) = (void *)(((long)(p) + 0x400) & ~0x1000))
1012#endif
1013
1014#define	SFBMODE(p, v) \
1015		(*(uint32_t *)(BUMP(p) + SFB_ASIC_MODE) = (v))
1016#define	SFBROP(p, v) \
1017		(*(uint32_t *)(BUMP(p) + SFB_ASIC_ROP) = (v))
1018#define	SFBPLANEMASK(p, v) \
1019		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PLANEMASK) = (v))
1020#define	SFBPIXELMASK(p, v) \
1021		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PIXELMASK) = (v))
1022#define	SFBADDRESS(p, v) \
1023		(*(uint32_t *)(BUMP(p) + SFB_ASIC_ADDRESS) = (v))
1024#define	SFBSTART(p, v) \
1025		(*(uint32_t *)(BUMP(p) + SFB_ASIC_START) = (v))
1026#define	SFBPIXELSHIFT(p, v) \
1027		(*(uint32_t *)(BUMP(p) + SFB_ASIC_PIXELSHIFT) = (v))
1028#define	SFBFG(p, v) \
1029		(*(uint32_t *)(BUMP(p) + SFB_ASIC_FG) = (v))
1030#define	SFBBG(p, v) \
1031		(*(uint32_t *)(BUMP(p) + SFB_ASIC_BG) = (v))
1032#define	SFBBCONT(p, v) \
1033		(*(uint32_t *)(BUMP(p) + SFB_ASIC_BCONT) = (v))
1034
1035#define	SFBDATA(p, v) \
1036		(*((uint32_t *)BUMP(p) + TGA_REG_GDAR) = (v))
1037
1038#define	SFBCOPY64BYTESDONE	8
1039#define	SFBCOPY64BITS		64
1040#define	SFBCOPY64SRC(p, v) \
1041		(*((uint32_t *)BUMP(p) + TGA_REG_GCSR) = (long)(v))
1042#define	SFBCOPY64DST(p, v) \
1043		(*((uint32_t *)BUMP(p) + TGA_REG_GCDR) = (long)(v))
1044
1045/*
1046 * Actually write a string to the frame buffer.
1047 */
1048static void
1049sfbp_putchar(void *id, int row, int col, u_int uc, long attr)
1050{
1051	struct rasops_info *ri = id;
1052	char *sfb, *p;
1053	int scanspan, height, width, align, x, y;
1054	uint32_t lmask, rmask, glyph;
1055	uint8_t *g;
1056
1057	x = col * ri->ri_font->fontwidth;
1058	y = row * ri->ri_font->fontheight;
1059	scanspan = ri->ri_stride;
1060	height = ri->ri_font->fontheight;
1061	uc -= ri->ri_font->firstchar;
1062	g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
1063
1064	p = ri->ri_bits + y * scanspan + x * SFBPIXELBYTES;
1065	align = (long)p & SFBALIGNMASK;
1066	p -= align;
1067	align /= SFBPIXELBYTES;
1068	width = ri->ri_font->fontwidth + align;
1069	lmask = SFBSTIPPLEALL1 << align;
1070	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1071	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1072
1073	SFBMODE(sfb, MODE_OPAQUESTIPPLE);
1074	SFBPLANEMASK(sfb, ~0);
1075	SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
1076	SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1077	SFBROP(sfb, (3 << 8) | 3); /* ROP_COPY24 */
1078	*((uint32_t *)sfb + TGA_REG_GPXR_P) = lmask & rmask;
1079
1080	/* XXX 2B stride fonts only XXX */
1081	while (height > 0) {
1082		glyph = *(uint16_t *)g;			/* XXX */
1083		*(uint32_t *)p = glyph << align;
1084		p += scanspan;
1085		g += 2;					/* XXX */
1086		height--;
1087	}
1088	SFBMODE(sfb, MODE_SIMPLE);
1089	*((uint32_t *)sfb + TGA_REG_GPXR_P) = ~0;
1090}
1091
1092#undef	SFBSTIPPLEALL1
1093#undef	SFBSTIPPLEBITS
1094#undef	SFBSTIPPLEBITMASK
1095#define	SFBSTIPPLEALL1		SFBCOPYALL1
1096#define	SFBSTIPPLEBITS		SFBCOPYBITS
1097#define	SFBSTIPPLEBITMASK	SFBCOPYBITMASK
1098
1099/*
1100 * Clear characters in a line.
1101 */
1102static void
1103sfbp_erasecols(void *id, int row, int startcol, int ncols, long attr)
1104{
1105	struct rasops_info *ri = id;
1106	char *sfb, *p;
1107	int scanspan, startx, height, width, align, w, y;
1108	uint32_t lmask, rmask;
1109
1110	scanspan = ri->ri_stride;
1111	y = row * ri->ri_font->fontheight;
1112	startx = startcol * ri->ri_font->fontwidth;
1113	height = ri->ri_font->fontheight;
1114	w = ri->ri_font->fontwidth * ncols;
1115
1116	p = ri->ri_bits + y * scanspan + startx * SFBPIXELBYTES;
1117	align = (long)p & SFBALIGNMASK;
1118	align /= SFBPIXELBYTES;
1119	p -= align;
1120	width = w + align;
1121	lmask = SFBSTIPPLEALL1 << align;
1122	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1123	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1124
1125	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1126	SFBPLANEMASK(sfb, ~0);
1127	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1128	if (width <= SFBSTIPPLEBITS) {
1129		lmask = lmask & rmask;
1130		while (height > 0) {
1131			*(uint32_t *)p = lmask;
1132			p += scanspan;
1133			height--;
1134		}
1135	}
1136	else {
1137		char *q = p;
1138		while (height > 0) {
1139			*(uint32_t *)p = lmask;
1140			WRITE_MB();
1141			width -= 2 * SFBSTIPPLEBITS;
1142			while (width > 0) {
1143				p += SFBSTIPPLEBYTESDONE;
1144				*(uint32_t *)p = SFBSTIPPLEALL1;
1145				WRITE_MB();
1146				width -= SFBSTIPPLEBITS;
1147			}
1148			p += SFBSTIPPLEBYTESDONE;
1149			*(uint32_t *)p = rmask;
1150			WRITE_MB();
1151
1152			p = (q += scanspan);
1153			width = w + align;
1154			height--;
1155		}
1156	}
1157	SFBMODE(sfb, MODE_SIMPLE);
1158}
1159
1160#if 1
1161/*
1162 * Copy lines.
1163 */
1164static void
1165sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1166{
1167	struct rasops_info *ri = id;
1168	char *sfb, *p;
1169	int scanspan, offset, srcy, height, width, align, w;
1170	uint32_t lmask, rmask;
1171
1172	scanspan = ri->ri_stride;
1173	height = ri->ri_font->fontheight * nrows;
1174	offset = (dstrow - srcrow) * ri->ri_yscale;
1175	srcy = ri->ri_font->fontheight * srcrow;
1176	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1177		scanspan = -scanspan;
1178		srcy += height;
1179	}
1180
1181	p = ri->ri_bits + srcy * ri->ri_stride;
1182	align = (long)p & SFBALIGNMASK;
1183	p -= align;
1184	align /= SFBPIXELBYTES;
1185	w = ri->ri_emuwidth;
1186	width = w + align;
1187	lmask = SFBCOPYALL1 << align;
1188	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1189	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1190
1191	SFBMODE(sfb, MODE_COPY);
1192	SFBPLANEMASK(sfb, ~0);
1193	SFBPIXELSHIFT(sfb, 0);
1194	if (width <= SFBCOPYBITS) {
1195		/* never happens */;
1196	}
1197	else {
1198		char *q = p;
1199		while (height > 0) {
1200			*(uint32_t *)p = lmask;
1201			*(uint32_t *)(p + offset) = lmask;
1202			width -= 2 * SFBCOPYBITS;
1203			while (width > 0) {
1204				p += SFBCOPYBYTESDONE;
1205				*(uint32_t *)p = SFBCOPYALL1;
1206				*(uint32_t *)(p + offset) = SFBCOPYALL1;
1207				width -= SFBCOPYBITS;
1208			}
1209			p += SFBCOPYBYTESDONE;
1210			*(uint32_t *)p = rmask;
1211			*(uint32_t *)(p + offset) = rmask;
1212
1213			p = (q += scanspan);
1214			width = w + align;
1215			height--;
1216		}
1217	}
1218	SFBMODE(sfb, MODE_SIMPLE);
1219}
1220
1221#else
1222
1223
1224static void
1225sfbp_copyrows(void *id, int srcrow, int dstrow, int nrows)
1226{
1227	struct rasops_info *ri = id;
1228	void *sfb, *p, *q;
1229	int scanspan, offset, srcy, height, width, w, align;
1230	uint32_t rmask, lmask;
1231
1232	scanspan = ri->ri_stride;
1233	height = ri->ri_font->fontheight * nrows;
1234	offset = (dstrow - srcrow) * ri->ri_yscale;
1235	srcy = ri->ri_font->fontheight * srcrow;
1236	if (srcrow < dstrow && srcrow + nrows > dstrow) {
1237		scanspan = -scanspan;
1238		srcy += height;
1239	}
1240
1241	p = ri->ri_bits + srcy * ri->ri_stride;
1242	align = (long)p & SFBALIGNMASK;
1243	w = ri->ri_emuwidth;
1244	width = w + align;
1245	lmask = SFBCOPYALL1 << align;
1246	rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1247	sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1248	q = p;
1249
1250	SFBMODE(sfb, MODE_COPY);
1251	SFBPLANEMASK(sfb, ~0);
1252	SFBPIXELSHIFT(sfb, 0);
1253
1254	if (width <= SFBCOPYBITS)
1255		; /* never happens */
1256	else if (width < SFBCOPY64BITS) {
1257		; /* unlikely happens */
1258
1259	}
1260	else {
1261		while (height > 0) {
1262			while (width >= SFBCOPY64BITS) {
1263				SFBCOPY64SRC(sfb, *p);
1264				SFBCOPY64DST(sfb, *p + offset);
1265				p += SFBCOPY64BYTESDONE;
1266				width -= SFBCOPY64BITS;
1267			}
1268			if (width >= SFBCOPYBITS) {
1269				*(uint32_t *)p = SFBCOPYALL1;
1270				*(uint32_t *)(p + offset) = SFBCOPYALL1;
1271				p += SFBCOPYBYTESDONE;
1272				width -= SFBCOPYBITS;
1273			}
1274			if (width > 0) {
1275				*(uint32_t *)p = rmask;
1276				*(uint32_t *)(p + offset) = rmask;
1277			}
1278
1279			p = (q += scanspan);
1280			width = w;
1281			height--;
1282		}
1283	}
1284	SFBMODE(sfb, MODE_SIMPLE);
1285}
1286#endif
1287
1288/*
1289 * Erase lines.
1290 */
1291static void
1292sfbp_eraserows(void *id, int startrow, int nrows, long attr)
1293{
1294	struct rasops_info *ri = id;
1295	char *sfb, *p;
1296	int scanspan, starty, height, width, align, w;
1297	uint32_t lmask, rmask;
1298
1299	scanspan = ri->ri_stride;
1300	starty = ri->ri_font->fontheight * startrow;
1301	height = ri->ri_font->fontheight * nrows;
1302
1303	p = ri->ri_bits + starty * scanspan;
1304	align = (long)p & SFBALIGNMASK;
1305	p -= align;
1306	align /= SFBPIXELBYTES;
1307	w = ri->ri_emuwidth * SFBPIXELBYTES;
1308	width = w + align;
1309	lmask = SFBSTIPPLEALL1 << align;
1310	rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1311	sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1312
1313	SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1314	SFBPLANEMASK(sfb, ~0);
1315	SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
1316	if (width <= SFBSTIPPLEBITS) {
1317		/* never happens */;
1318	}
1319	else {
1320		char *q = p;
1321		while (height > 0) {
1322			*(uint32_t *)p = lmask;
1323			WRITE_MB();
1324			width -= 2 * SFBSTIPPLEBITS;
1325			while (width > 0) {
1326				p += SFBSTIPPLEBYTESDONE;
1327				*(uint32_t *)p = SFBSTIPPLEALL1;
1328				WRITE_MB();
1329				width -= SFBSTIPPLEBITS;
1330			}
1331			p += SFBSTIPPLEBYTESDONE;
1332			*(uint32_t *)p = rmask;
1333			WRITE_MB();
1334
1335			p = (q += scanspan);
1336			width = w + align;
1337			height--;
1338		}
1339	}
1340	SFBMODE(sfb, MODE_SIMPLE);
1341}
1342