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