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