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
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_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
315static void
316sfbp_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
334static void
335sfbp_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, WSFONT_FIND_BITMAP);
396	if (cookie <= 0)
397		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
398		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
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
428static int
429sfbioctl(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
506paddr_t
507sfbmmap(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
516static int
517sfb_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
536void
537sfb_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
547static int
548sfb_show_screen(void *v, void *cookie, int waitok,
549    void (*cb)(void *, int, int), void *cbarg)
550{
551
552	return (0);
553}
554
555int
556sfbp_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
570static int
571sfbpintr(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;
599done:
600	*((uint32_t *)asic + TGA_REG_SISR) = sisr = 0x00000001; tc_wmb();
601	return (1);
602#undef cc
603}
604
605static void
606bt459init(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
672static void
673bt463init(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
700static int
701get_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
719static int
720set_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
748static int
749set_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
810static int
811get_cursor(struct sfbp_softc *sc, struct wsdisplay_cursor *p)
812{
813	return (EPASSTHROUGH); /* XXX */
814}
815
816static void
817set_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
834static void
835bt459visible(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
843static void
844sfbpvisible(void *hw, int on)
845{
846	/* XXX use SFBplus ASIC XX */
847}
848
849static void
850bt459locate(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
870static void
871sfbplocate(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
883static void
884bt459color(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
899static void
900bt463color(void *hw, uint8_t *cp)
901{
902}
903
904static void
905bt459shape(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
943static void
944sfbpshape(void *hw, struct wsdisplay_curpos *size, uint64_t *image)
945{
946	/* XXX use SFBplus ASIC XXX */
947}
948
949static void
950bt459setlut(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
963static void
964noplut(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 */
1049static void
1050sfbp_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 */
1103static void
1104sfbp_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 */
1165static void
1166sfbp_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
1225static void
1226sfbp_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 */
1292static void
1293sfbp_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