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