sfb.c revision 1.86 1 /* $NetBSD: sfb.c,v 1.86 2019/11/10 21:16:37 chs 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.86 2019/11/10 21:16:37 chs 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
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
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);
301 }
302
303 static void
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
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
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_GINFO:
401 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
402 wsd_fbip->height = ri->ri_height;
403 wsd_fbip->width = ri->ri_width;
404 wsd_fbip->depth = ri->ri_depth;
405 wsd_fbip->cmsize = CMAP_SIZE;
406 #undef fbt
407 return (0);
408
409 case WSDISPLAYIO_GETCMAP:
410 return get_cmap(sc, (struct wsdisplay_cmap *)data);
411
412 case WSDISPLAYIO_PUTCMAP:
413 return set_cmap(sc, (struct wsdisplay_cmap *)data);
414
415 case WSDISPLAYIO_SVIDEO:
416 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
417 if (sc->sc_blanked != turnoff) {
418 sc->sc_blanked = turnoff;
419 sfb_screenblank(sc);
420 }
421 return (0);
422
423 case WSDISPLAYIO_GVIDEO:
424 *(u_int *)data = sc->sc_blanked ?
425 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
426 return (0);
427
428 case WSDISPLAYIO_GCURPOS:
429 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
430 return (0);
431
432 case WSDISPLAYIO_SCURPOS:
433 s = spltty();
434 set_curpos(sc, (struct wsdisplay_curpos *)data);
435 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
436 splx(s);
437 return (0);
438
439 case WSDISPLAYIO_GCURMAX:
440 ((struct wsdisplay_curpos *)data)->x =
441 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
442 return (0);
443
444 case WSDISPLAYIO_GCURSOR:
445 return get_cursor(sc, (struct wsdisplay_cursor *)data);
446
447 case WSDISPLAYIO_SCURSOR:
448 return set_cursor(sc, (struct wsdisplay_cursor *)data);
449
450 case WSDISPLAYIO_SMODE:
451 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
452 s = spltty();
453 sfb_cmap_init(sc);
454 sc->sc_curenb = 0;
455 sc->sc_blanked = 0;
456 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
457 WSDISPLAY_CMAP_DOLUT);
458 splx(s);
459 sfb_screenblank(sc);
460 }
461 return (0);
462 }
463 return (EPASSTHROUGH);
464 }
465
466 static void
467 sfb_screenblank(struct sfb_softc *sc)
468 {
469 struct rasops_info *ri;
470 char *asic;
471
472 ri = sc->sc_ri;
473 asic = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
474 SFBWRITE32(asic, SFB_ASIC_VIDEO_VALID, !sc->sc_blanked);
475 tc_wmb();
476 }
477
478 static paddr_t
479 sfbmmap(void *v, void *vs, off_t offset, int prot)
480 {
481 struct sfb_softc *sc = v;
482
483 if (offset >= SFB_SIZE || offset < 0)
484 return (-1);
485 return machine_btop(sc->sc_vaddr + offset);
486 }
487
488 static int
489 sfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
490 int *curxp, int *curyp, long *attrp)
491 {
492 struct sfb_softc *sc = v;
493 struct rasops_info *ri = sc->sc_ri;
494 long defattr;
495
496 if (sc->nscreens > 0)
497 return (ENOMEM);
498
499 *cookiep = ri; /* one and only for now */
500 *curxp = 0;
501 *curyp = 0;
502 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
503 *attrp = defattr;
504 sc->nscreens++;
505 return (0);
506 }
507
508 static void
509 sfb_free_screen(void *v, void *cookie)
510 {
511 struct sfb_softc *sc = v;
512
513 if (sc->sc_ri == &sfb_console_ri)
514 panic("sfb_free_screen: console");
515
516 sc->nscreens--;
517 }
518
519 static int
520 sfb_show_screen(void *v, void *cookie, int waitok,
521 void (*cb)(void *, int, int), void *cbarg)
522 {
523
524 return (0);
525 }
526
527 /* EXPORT */ int
528 sfb_cnattach(tc_addr_t addr)
529 {
530 struct rasops_info *ri;
531 long defattr;
532
533 ri = &sfb_console_ri;
534 ri->ri_hw = (void *)addr;
535 sfb_common_init(ri);
536 (*ri->ri_ops.allocattr)(&ri, 0, 0, 0, &defattr);
537 wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
538 sfb_consaddr = addr;
539 return (0);
540 }
541
542 static int
543 sfbintr(void *arg)
544 {
545 struct sfb_softc *sc = arg;
546 char *base, *asic, *vdac;
547 int v;
548
549 base = (void *)sc->sc_ri->ri_hw;
550 asic = base + SFB_ASIC_OFFSET;
551 SFBWRITE32(asic, SFB_ASIC_CLEAR_INTR, 0);
552 /* SFBWRITE32(asic, SFB_ASIC_ENABLE_INTR, 1); */
553
554 if (sc->sc_changed == 0)
555 goto done;
556
557 vdac = base + SFB_RAMDAC_OFFSET;
558 v = sc->sc_changed;
559 if (v & WSDISPLAY_CURSOR_DOCUR) {
560 int onoff;
561
562 onoff = (sc->sc_curenb) ? 0xc0 : 0x00;
563 VDACSELECT(vdac, BT459_IREG_CCR);
564 REGWRITE32(vdac, bt_reg, onoff);
565 }
566 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
567 int x, y;
568
569 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
570 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
571 x += sc->sc_cursor.cc_magic.x;
572 y += sc->sc_cursor.cc_magic.y;
573
574 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
575 REGWRITE32(vdac, bt_reg, x);
576 REGWRITE32(vdac, bt_reg, x >> 8);
577 REGWRITE32(vdac, bt_reg, y);
578 REGWRITE32(vdac, bt_reg, y >> 8);
579 }
580 if (v & WSDISPLAY_CURSOR_DOCMAP) {
581 uint8_t *cp = sc->sc_cursor.cc_color;
582
583 VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
584 REGWRITE32(vdac, bt_reg, cp[1]);
585 REGWRITE32(vdac, bt_reg, cp[3]);
586 REGWRITE32(vdac, bt_reg, cp[5]);
587
588 REGWRITE32(vdac, bt_reg, cp[0]);
589 REGWRITE32(vdac, bt_reg, cp[2]);
590 REGWRITE32(vdac, bt_reg, cp[4]);
591 }
592 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
593 uint8_t *ip, *mp, img, msk;
594 uint8_t u;
595 int bcnt;
596
597 ip = (uint8_t *)sc->sc_cursor.cc_image;
598 mp = (uint8_t *)sc->sc_cursor.cc_mask;
599
600 bcnt = 0;
601 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
602 /* 64 pixel scan line is consisted with 16 byte cursor ram */
603 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
604 /* pad right half 32 pixel when smaller than 33 */
605 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
606 REGWRITE32(vdac, bt_reg, 0);
607 REGWRITE32(vdac, bt_reg, 0);
608 }
609 else {
610 img = *ip++;
611 msk = *mp++;
612 img &= msk; /* cookie off image */
613 u = (msk & 0x0f) << 4 | (img & 0x0f);
614 REGWRITE32(vdac, bt_reg, shuffle[u]);
615 u = (msk & 0xf0) | (img & 0xf0) >> 4;
616 REGWRITE32(vdac, bt_reg, shuffle[u]);
617 }
618 bcnt += 2;
619 }
620 /* pad unoccupied scan lines */
621 while (bcnt < CURSOR_MAX_SIZE * 16) {
622 REGWRITE32(vdac, bt_reg, 0);
623 REGWRITE32(vdac, bt_reg, 0);
624 bcnt += 2;
625 }
626 }
627 if (v & WSDISPLAY_CMAP_DOLUT) {
628 struct hwcmap256 *cm = &sc->sc_cmap;
629 int index;
630
631 VDACSELECT(vdac, 0);
632 for (index = 0; index < CMAP_SIZE; index++) {
633 REGWRITE32(vdac, bt_cmap, cm->r[index]);
634 REGWRITE32(vdac, bt_cmap, cm->g[index]);
635 REGWRITE32(vdac, bt_cmap, cm->b[index]);
636 }
637 }
638 sc->sc_changed = 0;
639 done:
640 return (1);
641 }
642
643 static void
644 sfbhwinit(void *base)
645 {
646 char *vdac = (char *)base + SFB_RAMDAC_OFFSET;
647 const uint8_t *p;
648 int i;
649
650 VDACSELECT(vdac, BT459_IREG_COMMAND_0);
651 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
652 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */
653 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
654 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
655 REGWRITE32(vdac, bt_reg, 0); /* 205 */
656 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */
657 REGWRITE32(vdac, bt_reg, 0); /* 207 */
658 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */
659 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */
660 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */
661 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */
662
663 VDACSELECT(vdac, BT459_IREG_CCR);
664 REGWRITE32(vdac, bt_reg, 0x0);
665 REGWRITE32(vdac, bt_reg, 0x0);
666 REGWRITE32(vdac, bt_reg, 0x0);
667 REGWRITE32(vdac, bt_reg, 0x0);
668 REGWRITE32(vdac, bt_reg, 0x0);
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
678 /* build sane colormap */
679 VDACSELECT(vdac, 0);
680 p = rasops_cmap;
681 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
682 REGWRITE32(vdac, bt_cmap, p[0]);
683 REGWRITE32(vdac, bt_cmap, p[1]);
684 REGWRITE32(vdac, bt_cmap, p[2]);
685 }
686
687 /* clear out cursor image */
688 VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
689 for (i = 0; i < 1024; i++)
690 REGWRITE32(vdac, bt_reg, 0xff);
691
692 /*
693 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
694 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
695 * image color. CCOLOR_1 will be never used.
696 */
697 VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
698 REGWRITE32(vdac, bt_reg, 0xff);
699 REGWRITE32(vdac, bt_reg, 0xff);
700 REGWRITE32(vdac, bt_reg, 0xff);
701
702 REGWRITE32(vdac, bt_reg, 0);
703 REGWRITE32(vdac, bt_reg, 0);
704 REGWRITE32(vdac, bt_reg, 0);
705
706 REGWRITE32(vdac, bt_reg, 0xff);
707 REGWRITE32(vdac, bt_reg, 0xff);
708 REGWRITE32(vdac, bt_reg, 0xff);
709 }
710
711 static int
712 get_cmap(struct sfb_softc *sc, struct wsdisplay_cmap *p)
713 {
714 u_int index = p->index, count = p->count;
715 int error;
716
717 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
718 return (EINVAL);
719
720 error = copyout(&sc->sc_cmap.r[index], p->red, count);
721 if (error)
722 return error;
723 error = copyout(&sc->sc_cmap.g[index], p->green, count);
724 if (error)
725 return error;
726 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
727 return error;
728 }
729
730 static int
731 set_cmap(struct sfb_softc *sc, struct wsdisplay_cmap *p)
732 {
733 struct hwcmap256 cmap;
734 u_int index = p->index, count = p->count;
735 int error, s;
736
737 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
738 return (EINVAL);
739
740 error = copyin(p->red, &cmap.r[index], count);
741 if (error)
742 return error;
743 error = copyin(p->green, &cmap.g[index], count);
744 if (error)
745 return error;
746 error = copyin(p->blue, &cmap.b[index], count);
747 if (error)
748 return error;
749
750 s = spltty();
751 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
752 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
753 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
754 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
755 splx(s);
756 return (0);
757 }
758
759 static int
760 set_cursor(struct sfb_softc *sc, struct wsdisplay_cursor *p)
761 {
762 #define cc (&sc->sc_cursor)
763 u_int v, index = 0, count = 0, icount = 0;
764 uint8_t r[2], g[2], b[2], image[512], mask[512];
765 int error, s;
766
767 v = p->which;
768 if (v & WSDISPLAY_CURSOR_DOCMAP) {
769 index = p->cmap.index;
770 count = p->cmap.count;
771 if (index >= 2 || count > 2 - index)
772 return (EINVAL);
773 error = copyin(p->cmap.red, &r[index], count);
774 if (error)
775 return error;
776 error = copyin(p->cmap.green, &g[index], count);
777 if (error)
778 return error;
779 error = copyin(p->cmap.blue, &b[index], count);
780 if (error)
781 return error;
782 }
783 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
784 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
785 return (EINVAL);
786 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
787 error = copyin(p->image, image, icount);
788 if (error)
789 return error;
790 error = copyin(p->mask, mask, icount);
791 if (error)
792 return error;
793 }
794
795 s = spltty();
796 if (v & WSDISPLAY_CURSOR_DOCUR)
797 sc->sc_curenb = p->enable;
798 if (v & WSDISPLAY_CURSOR_DOPOS)
799 set_curpos(sc, &p->pos);
800 if (v & WSDISPLAY_CURSOR_DOHOT)
801 cc->cc_hot = p->hot;
802 if (v & WSDISPLAY_CURSOR_DOCMAP) {
803 memcpy(&cc->cc_color[index], &r[index], count);
804 memcpy(&cc->cc_color[index + 2], &g[index], count);
805 memcpy(&cc->cc_color[index + 4], &b[index], count);
806 }
807 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
808 cc->cc_size = p->size;
809 memset(cc->cc_image, 0, sizeof cc->cc_image);
810 memcpy(cc->cc_image, image, icount);
811 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
812 memcpy(cc->cc_mask, mask, icount);
813 }
814 sc->sc_changed |= v;
815 splx(s);
816
817 return (0);
818 #undef cc
819 }
820
821 static int
822 get_cursor(struct sfb_softc *sc, struct wsdisplay_cursor *p)
823 {
824
825 return (EPASSTHROUGH); /* XXX */
826 }
827
828 static void
829 set_curpos(struct sfb_softc *sc, struct wsdisplay_curpos *curpos)
830 {
831 struct rasops_info *ri = sc->sc_ri;
832 int x = curpos->x, y = curpos->y;
833
834 if (y < 0)
835 y = 0;
836 else if (y > ri->ri_height)
837 y = ri->ri_height;
838 if (x < 0)
839 x = 0;
840 else if (x > ri->ri_width)
841 x = ri->ri_width;
842 sc->sc_cursor.cc_pos.x = x;
843 sc->sc_cursor.cc_pos.y = y;
844 }
845
846 #define MODE_SIMPLE 0
847 #define MODE_OPAQUESTIPPLE 1
848 #define MODE_OPAQUELINE 2
849 #define MODE_TRANSPARENTSTIPPLE 5
850 #define MODE_TRANSPARENTLINE 6
851 #define MODE_COPY 7
852
853 /* parameters for 8bpp configuration */
854 #define SFBALIGNMASK 0x7
855 #define SFBSTIPPLEALL1 0xffffffff
856 #define SFBSTIPPLEBITS 32
857 #define SFBSTIPPLEBITMASK 0x1f
858 #define SFBSTIPPLEBYTESDONE 32
859 #define SFBCOPYALL1 0xffffffff
860 #define SFBCOPYBITS 32
861 #define SFBCOPYBITMASK 0x1f
862 #define SFBCOPYBYTESDONE 32
863
864 #if defined(pmax)
865 #define WRITE_MB()
866 #define BUMP(p) (p)
867 #endif
868
869 #if defined(alpha)
870 #define WRITE_MB() tc_wmb()
871 /* SFB registers replicated in 128B stride; cycle after eight iterations */
872 #define BUMP(p) ((p) = (void *)(((long)(p) + 0x80) & ~0x400))
873 #endif
874
875 #define SFBMODE(p, v) \
876 SFBWRITE32(BUMP(p), SFB_ASIC_MODE, (v))
877 #define SFBROP(p, v) \
878 SFBWRITE32(BUMP(p), SFB_ASIC_ROP, (v))
879 #define SFBPLANEMASK(p, v) \
880 SFBWRITE32(BUMP(p), SFB_ASIC_PLANEMASK, (v))
881 #define SFBPIXELMASK(p, v) \
882 SFBWRITE32(BUMP(p), SFB_ASIC_PIXELMASK, (v))
883 #define SFBADDRESS(p, v) \
884 SFBWRITE32(BUMP(p), SFB_ASIC_ADDRESS, (v))
885 #define SFBSTART(p, v) \
886 SFBWRITE32(BUMP(p), SFB_ASIC_START, (v))
887 #define SFBPIXELSHIFT(p, v) \
888 SFBWRITE32(BUMP(p), SFB_ASIC_PIXELSHIFT, (v))
889 #define SFBFG(p, v) \
890 SFBWRITE32(BUMP(p), SFB_ASIC_FG, (v))
891 #define SFBBG(p, v) \
892 SFBWRITE32(BUMP(p), SFB_ASIC_BG, (v))
893
894 /*
895 * Paint the cursor.
896 */
897 static void
898 sfb_do_cursor(struct rasops_info *ri)
899 {
900 char *sfb, *p;
901 int scanspan, height, width, align, x, y;
902 uint32_t lmask, rmask;
903
904 x = ri->ri_ccol * ri->ri_font->fontwidth;
905 y = ri->ri_crow * ri->ri_font->fontheight;
906 scanspan = ri->ri_stride;
907 height = ri->ri_font->fontheight;
908
909 p = ri->ri_bits + y * scanspan + x;
910 align = (long)p & SFBALIGNMASK;
911 p -= align;
912 width = ri->ri_font->fontwidth + align;
913 lmask = SFBSTIPPLEALL1 << align;
914 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
915 sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
916
917 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
918 SFBPLANEMASK(sfb, ~0);
919 SFBROP(sfb, 6); /* ROP_XOR */
920 SFBFG(sfb, ~0);
921
922 lmask = lmask & rmask;
923 while (height > 0) {
924 SFBADDRESS(sfb, (long)p);
925 SFBSTART(sfb, lmask);
926 p += scanspan;
927 height--;
928 }
929 SFBMODE(sfb, MODE_SIMPLE);
930 SFBROP(sfb, 3); /* ROP_COPY */
931 }
932
933 /*
934 * Paint a character.
935 */
936 static void
937 sfb_putchar(void *id, int row, int col, u_int uc, long attr)
938 {
939 struct rasops_info *ri = id;
940 char *sfb, *p;
941 int scanspan, height, width, align, x, y;
942 uint32_t lmask, rmask, glyph;
943 uint8_t *g;
944
945 x = col * ri->ri_font->fontwidth;
946 y = row * ri->ri_font->fontheight;
947 scanspan = ri->ri_stride;
948 height = ri->ri_font->fontheight;
949 uc -= ri->ri_font->firstchar;
950 g = (u_char *)ri->ri_font->data + uc * ri->ri_fontscale;
951
952 p = ri->ri_bits + y * scanspan + x;
953 align = (long)p & SFBALIGNMASK;
954 p -= align;
955 width = ri->ri_font->fontwidth + align;
956 lmask = SFBSTIPPLEALL1 << align;
957 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
958 sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
959
960 SFBMODE(sfb, MODE_OPAQUESTIPPLE);
961 SFBPLANEMASK(sfb, ~0);
962 SFBFG(sfb, ri->ri_devcmap[(attr >> 24) & 15]);
963 SFBBG(sfb, ri->ri_devcmap[(attr >> 16) & 15]);
964
965 /* XXX 2B stride fonts only XXX */
966 lmask = lmask & rmask;
967 while (height > 0) {
968 glyph = *(uint16_t *)g; /* XXX */
969 SFBPIXELMASK(sfb, lmask);
970 SFBADDRESS(sfb, (long)p);
971 SFBSTART(sfb, glyph << align);
972 p += scanspan;
973 g += 2; /* XXX */
974 height--;
975 }
976 if (attr & 1 /* UNDERLINE */) {
977 p -= scanspan * 2;
978 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
979 SFBADDRESS(sfb, (long)p);
980 SFBSTART(sfb, lmask);
981 }
982
983 SFBMODE(sfb, MODE_SIMPLE);
984 SFBPIXELMASK(sfb, ~0); /* entire pixel */
985 }
986
987 #if 0
988 /*
989 * Copy characters in a line.
990 */
991 static void
992 sfb_copycols(void *id, int row, int srccol, int dstcol, int ncols)
993 {
994 struct rasops_info *ri = id;
995 void *sp, *dp, *basex, *sfb;
996 int scanspan, height, width, aligns, alignd, shift, w, y;
997 uint32_t lmaskd, rmaskd;
998
999 scanspan = ri->ri_stride;
1000 y = row * ri->ri_font->fontheight;
1001 basex = ri->ri_bits + y * scanspan;
1002 height = ri->ri_font->fontheight;
1003 w = ri->ri_font->fontwidth * ncols;
1004
1005 sp = basex + ri->ri_font->fontwidth * srccol;
1006 aligns = (long)sp & SFBALIGNMASK;
1007 dp = basex + ri->ri_font->fontwidth * dstcol;
1008 alignd = (long)dp & SFBALIGNMASK;
1009 sfb = (void *)ri->ri_hw + SFB_ASIC_OFFSET;
1010
1011 SFBMODE(sfb, MODE_COPY);
1012 SFBPLANEMASK(sfb, ~0);
1013 /* small enough to fit in a single 32bit */
1014 if ((aligns + w) <= SFBCOPYBITS && (alignd + w) <= SFBCOPYBITS) {
1015 SFBPIXELSHIFT(sfb, alignd - aligns);
1016 lmaskd = SFBCOPYALL1 << alignd;
1017 rmaskd = SFBCOPYALL1 >> (-(alignd + w) & SFBCOPYBITMASK);
1018 lmaskd = lmaskd & rmaskd;
1019 sp -= aligns;
1020 dp -= alignd;
1021 while (height > 0) {
1022 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1023 MEMWRITE32(dp, lmaskd); WRITE_MB();
1024 sp += scanspan;
1025 dp += scanspan;
1026 height--;
1027 }
1028 }
1029 /* copy forward (left-to-right) */
1030 else if (dstcol < srccol || srccol + ncols < dstcol) {
1031 void *sq, dq;
1032
1033 shift = alignd - aligns;
1034 if (shift < 0) {
1035 shift = 8 + shift; /* enforce right rotate */
1036 alignd += 8; /* bearing on left edge */
1037 }
1038 width = alignd + w;
1039 lmaskd = SFBCOPYALL1 << alignd;
1040 rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1041 sp -= aligns;
1042 dp -= alignd;
1043
1044 SFBPIXELSHIFT(sfb, shift);
1045 w = width;
1046 sq = sp;
1047 dq = dp;
1048 while (height > 0) {
1049 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1050 MEMWRITE32(dp, lmaskd); WRITE_MB();
1051 width -= 2 * SFBCOPYBITS;
1052 while (width > 0) {
1053 sp += SFBCOPYBYTESDONE;
1054 dp += SFBCOPYBYTESDONE;
1055 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1056 MEMWRITE32(dp, SFBCOPYALL1); WRITE_MB();
1057 width -= SFBCOPYBITS;
1058 }
1059 sp += SFBCOPYBYTESDONE;
1060 dp += SFBCOPYBYTESDONE;
1061 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1062 MEMWRITE32(dp, rmaskd); WRITE_MB();
1063 sp = (sq += scanspan);
1064 dp = (dq += scanspan);
1065 width = w;
1066 height--;
1067 }
1068 }
1069 /* copy backward (right-to-left) */
1070 else {
1071 void *sq, dq;
1072
1073 shift = alignd - aligns;
1074 if (shift > 0) {
1075 shift = shift - 8; /* force left rotate */
1076 alignd += 24;
1077 }
1078 width = alignd + w;
1079 lmaskd = SFBCOPYALL1 << alignd;
1080 rmaskd = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1081 sp -= aligns;
1082 dp -= alignd;
1083
1084 SFBPIXELSHIFT(sfb, shift);
1085 w = width;
1086 sq = sp += (((aligns + w) - 1) & ~31);
1087 dq = dp += (((alignd + w) - 1) & ~31);
1088 while (height > 0) {
1089 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1090 MEMWRITE32(dp, rmaskd); WRITE_MB();
1091 width -= 2 * SFBCOPYBITS;
1092 while (width > 0) {
1093 sp -= SFBCOPYBYTESDONE;
1094 dp -= SFBCOPYBYTESDONE;
1095 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1096 MEMWRITE32(dp, SFBCOPYALL1); WRITE_MB();
1097 width -= SFBCOPYBITS;
1098 }
1099 sp -= SFBCOPYBYTESDONE;
1100 dp -= SFBCOPYBYTESDONE;
1101 MEMWRITE32(sp, SFBCOPYALL1); WRITE_MB();
1102 MEMWRITE32(dp, lmaskd); WRITE_MB();
1103
1104 sp = (sq += scanspan);
1105 dp = (dq += scanspan);
1106 width = w;
1107 height--;
1108 }
1109 }
1110 SFBMODE(sfb, MODE_SIMPLE);
1111 SFBPIXELSHIFT(sfb, 0);
1112 }
1113 #endif
1114
1115 /*
1116 * Clear characters in a line.
1117 */
1118 static void
1119 sfb_erasecols(void *id, int row, int startcol, int ncols, long attr)
1120 {
1121 struct rasops_info *ri = id;
1122 char *sfb, *p;
1123 int scanspan, startx, height, width, align, w, y;
1124 uint32_t lmask, rmask;
1125
1126 scanspan = ri->ri_stride;
1127 y = row * ri->ri_font->fontheight;
1128 startx = startcol * ri->ri_font->fontwidth;
1129 height = ri->ri_font->fontheight;
1130 w = ri->ri_font->fontwidth * ncols;
1131
1132 p = ri->ri_bits + y * scanspan + startx;
1133 align = (long)p & SFBALIGNMASK;
1134 p -= align;
1135 width = w + align;
1136 lmask = SFBSTIPPLEALL1 << align;
1137 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1138 sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1139
1140 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1141 SFBPLANEMASK(sfb, ~0);
1142 SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1143 if (width <= SFBSTIPPLEBITS) {
1144 lmask = lmask & rmask;
1145 while (height > 0) {
1146 SFBADDRESS(sfb, (long)p);
1147 SFBSTART(sfb, lmask);
1148 p += scanspan;
1149 height--;
1150 }
1151 }
1152 else {
1153 char *q = p;
1154 while (height > 0) {
1155 MEMWRITE32(p, lmask); WRITE_MB();
1156 width -= 2 * SFBSTIPPLEBITS;
1157 while (width > 0) {
1158 p += SFBSTIPPLEBYTESDONE;
1159 MEMWRITE32(p, SFBSTIPPLEALL1); WRITE_MB();
1160 width -= SFBSTIPPLEBITS;
1161 }
1162 p += SFBSTIPPLEBYTESDONE;
1163 MEMWRITE32(p, rmask); WRITE_MB();
1164 WRITE_MB();
1165
1166 p = (q += scanspan);
1167 width = w + align;
1168 height--;
1169 }
1170 }
1171 SFBMODE(sfb, MODE_SIMPLE);
1172 }
1173
1174 /*
1175 * Copy lines.
1176 */
1177 static void
1178 sfb_copyrows(void *id, int srcrow, int dstrow, int nrows)
1179 {
1180 struct rasops_info *ri = id;
1181 char *sfb, *p;
1182 int scanspan, offset, srcy, height, width, align, w;
1183 uint32_t lmask, rmask;
1184
1185 scanspan = ri->ri_stride;
1186 height = ri->ri_font->fontheight * nrows;
1187 offset = (dstrow - srcrow) * ri->ri_yscale;
1188 srcy = ri->ri_font->fontheight * srcrow;
1189 if (srcrow < dstrow && srcrow + nrows > dstrow) {
1190 scanspan = -scanspan;
1191 srcy += height;
1192 }
1193
1194 p = ri->ri_bits + srcy * ri->ri_stride;
1195 align = (long)p & SFBALIGNMASK;
1196 p -= align;
1197 w = ri->ri_emuwidth;
1198 width = w + align;
1199 lmask = SFBCOPYALL1 << align;
1200 rmask = SFBCOPYALL1 >> (-width & SFBCOPYBITMASK);
1201 sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1202
1203 SFBMODE(sfb, MODE_COPY);
1204 SFBPLANEMASK(sfb, ~0);
1205 SFBPIXELSHIFT(sfb, 0);
1206 if (width <= SFBCOPYBITS) {
1207 /* never happens */;
1208 }
1209 else {
1210 char *q = p;
1211 while (height > 0) {
1212 MEMWRITE32(p, lmask);
1213 MEMWRITE32(p + offset, lmask);
1214 width -= 2 * SFBCOPYBITS;
1215 while (width > 0) {
1216 p += SFBCOPYBYTESDONE;
1217 MEMWRITE32(p, SFBCOPYALL1);
1218 MEMWRITE32(p + offset, SFBCOPYALL1);
1219 width -= SFBCOPYBITS;
1220 }
1221 p += SFBCOPYBYTESDONE;
1222 MEMWRITE32(p, rmask);
1223 MEMWRITE32(p + offset, rmask);
1224
1225 p = (q += scanspan);
1226 width = w + align;
1227 height--;
1228 }
1229 }
1230 SFBMODE(sfb, MODE_SIMPLE);
1231 }
1232
1233 /*
1234 * Erase lines.
1235 */
1236 void
1237 sfb_eraserows(void *id, int startrow, int nrows, long attr)
1238 {
1239 struct rasops_info *ri = id;
1240 char *sfb, *p;
1241 int scanspan, starty, height, width, align, w;
1242 uint32_t lmask, rmask;
1243
1244 scanspan = ri->ri_stride;
1245 starty = ri->ri_font->fontheight * startrow;
1246 height = ri->ri_font->fontheight * nrows;
1247
1248 p = ri->ri_bits + starty * scanspan;
1249 align = (long)p & SFBALIGNMASK;
1250 p -= align;
1251 w = ri->ri_emuwidth;
1252 width = w + align;
1253 lmask = SFBSTIPPLEALL1 << align;
1254 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1255 sfb = (char *)ri->ri_hw + SFB_ASIC_OFFSET;
1256
1257 SFBMODE(sfb, MODE_TRANSPARENTSTIPPLE);
1258 SFBPLANEMASK(sfb, ~0);
1259 SFBFG(sfb, ri->ri_devcmap[(attr >> 16) & 15]); /* fill with bg */
1260 if (width <= SFBSTIPPLEBITS) {
1261 /* never happens */;
1262 }
1263 else {
1264 char *q = p;
1265 while (height > 0) {
1266 MEMWRITE32(p, lmask); WRITE_MB();
1267 width -= 2 * SFBSTIPPLEBITS;
1268 while (width > 0) {
1269 p += SFBSTIPPLEBYTESDONE;
1270 MEMWRITE32(p, SFBSTIPPLEALL1); WRITE_MB();
1271 width -= SFBSTIPPLEBITS;
1272 }
1273 p += SFBSTIPPLEBYTESDONE;
1274 MEMWRITE32(p, rmask); WRITE_MB();
1275
1276 p = (q += scanspan);
1277 width = w + align;
1278 height--;
1279 }
1280 }
1281 SFBMODE(sfb, MODE_SIMPLE);
1282 }
1283