sfb.c revision 1.13 1 /* $NetBSD: sfb.c,v 1.13 1999/03/24 05:51:21 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1998 Tohru Nishimura. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tohru Nishimura
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34
35 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.13 1999/03/24 05:51:21 mrg Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt459reg.h>
57 #include <dev/tc/sfbreg.h>
58
59 #include <uvm/uvm_extern.h>
60
61 /* XXX BUS'IFYING XXX */
62
63 #if defined(pmax)
64 #define machine_btop(x) mips_btop(x)
65 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
66 #endif
67
68 #if defined(__alpha__) || defined(alpha)
69 #define machine_btop(x) alpha_btop(x)
70 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
71 #endif
72
73 /*
74 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
75 * obscure register layout such as 2nd and 3rd Bt459 registers are
76 * adjacent each other in a word, i.e.,
77 * struct bt459triplet {
78 * struct {
79 * u_int8_t u0;
80 * u_int8_t u1;
81 * u_int8_t u2;
82 * unsigned :8;
83 * } bt_lo;
84 * ...
85 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
86 */
87 struct bt459reg {
88 u_int32_t bt_lo;
89 u_int32_t bt_hi;
90 u_int32_t bt_reg;
91 u_int32_t bt_cmap;
92 };
93
94 /* XXX XXX XXX */
95
96 struct fb_devconfig {
97 vaddr_t dc_vaddr; /* memory space virtual base address */
98 paddr_t dc_paddr; /* memory space physical base address */
99 vsize_t dc_size; /* size of slot memory */
100 int dc_wid; /* width of frame buffer */
101 int dc_ht; /* height of frame buffer */
102 int dc_depth; /* depth, bits per pixel */
103 int dc_rowbytes; /* bytes in a FB scan line */
104 vaddr_t dc_videobase; /* base of flat frame buffer */
105 struct raster dc_raster; /* raster description */
106 struct rcons dc_rcons; /* raster blitter control info */
107 int dc_blanked; /* currently has video disabled */
108 };
109
110 struct hwcmap {
111 #define CMAP_SIZE 256 /* 256 R/G/B entries */
112 u_int8_t r[CMAP_SIZE];
113 u_int8_t g[CMAP_SIZE];
114 u_int8_t b[CMAP_SIZE];
115 };
116
117 struct hwcursor {
118 struct wsdisplay_curpos cc_pos;
119 struct wsdisplay_curpos cc_hot;
120 struct wsdisplay_curpos cc_size;
121 #define CURSOR_MAX_SIZE 64
122 u_int8_t cc_color[6];
123 u_int64_t cc_image[64 + 64];
124 };
125
126 struct sfb_softc {
127 struct device sc_dev;
128 struct fb_devconfig *sc_dc; /* device configuration */
129 struct hwcmap sc_cmap; /* software copy of colormap */
130 struct hwcursor sc_cursor; /* software copy of cursor */
131 int sc_curenb; /* cursor sprite enabled */
132 int sc_changed; /* need update of colormap */
133 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
134 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
135 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
136 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
137 #define DATA_ALL_CHANGED 0x0f
138 int nscreens;
139 short magic_x, magic_y; /* HX cursor location offset */
140 #define HX_MAGIC_X 368
141 #define HX_MAGIC_Y 38
142 };
143
144 int sfbmatch __P((struct device *, struct cfdata *, void *));
145 void sfbattach __P((struct device *, struct device *, void *));
146
147 struct cfattach sfb_ca = {
148 sizeof(struct sfb_softc), sfbmatch, sfbattach,
149 };
150
151 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
152 struct fb_devconfig sfb_console_dc;
153 tc_addr_t sfb_consaddr;
154
155 void sfb_cursor __P((void *, int, int, int));
156 int sfb_mapchar __P((void *, int, unsigned int *));
157 void sfb_putchar __P((void *, int, int, u_int, long));
158 void sfb_copycols __P((void *, int, int, int, int));
159 void sfb_erasecols __P((void *, int, int, int, long));
160 void sfb_copyrows __P((void *, int, int, int));
161 void sfb_eraserows __P((void *, int, int, long));
162 int sfb_alloc_attr __P((void *, int, int, int, long *));
163 #define rcons_alloc_attr sfb_alloc_attr
164
165 struct wsdisplay_emulops sfb_emulops = {
166 sfb_cursor, /* could use hardware cursor; punt */
167 sfb_mapchar,
168 sfb_putchar,
169 sfb_copycols,
170 sfb_erasecols,
171 sfb_copyrows,
172 sfb_eraserows,
173 sfb_alloc_attr
174 };
175
176 struct wsscreen_descr sfb_stdscreen = {
177 "std", 0, 0,
178 &sfb_emulops,
179 0, 0,
180 0
181 };
182
183 const struct wsscreen_descr *_sfb_scrlist[] = {
184 &sfb_stdscreen,
185 };
186
187 struct wsscreen_list sfb_screenlist = {
188 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
189 };
190
191 int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
192 int sfbmmap __P((void *, off_t, int));
193
194 int sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
195 void **, int *, int *, long *));
196 void sfb_free_screen __P((void *, void *));
197 void sfb_show_screen __P((void *, void *));
198
199 struct wsdisplay_accessops sfb_accessops = {
200 sfbioctl,
201 sfbmmap,
202 sfb_alloc_screen,
203 sfb_free_screen,
204 sfb_show_screen,
205 0 /* load_font */
206 };
207
208 int sfb_cnattach __P((tc_addr_t));
209 int sfbintr __P((void *));
210 void sfbinit __P((struct fb_devconfig *));
211
212 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
213 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
214 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
215 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
216 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
217 static void bt459_set_curpos __P((struct sfb_softc *));
218
219 /* XXX XXX XXX */
220 #define BT459_SELECT(vdac, regno) do { \
221 vdac->bt_lo = (regno) & 0x00ff; \
222 vdac->bt_hi = ((regno)& 0x0f00) >> 8; \
223 tc_wmb(); \
224 } while (0)
225 /* XXX XXX XXX */
226
227 /*
228 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
229 * M M M M I I I I M I M I M I M I
230 * [ before ] [ after ]
231 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
232 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
233 */
234 const static u_int8_t shuffle[256] = {
235 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
236 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
237 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
238 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
239 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
240 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
241 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
242 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
243 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
244 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
245 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
246 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
247 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
248 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
249 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
250 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
251 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
252 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
253 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
254 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
255 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
256 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
257 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
258 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
259 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
260 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
261 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
262 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
263 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
264 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
265 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
266 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
267 };
268
269 int
270 sfbmatch(parent, match, aux)
271 struct device *parent;
272 struct cfdata *match;
273 void *aux;
274 {
275 struct tc_attach_args *ta = aux;
276
277 if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
278 return (0);
279
280 return (1);
281 }
282
283 void
284 sfb_getdevconfig(dense_addr, dc)
285 tc_addr_t dense_addr;
286 struct fb_devconfig *dc;
287 {
288 struct raster *rap;
289 struct rcons *rcp;
290 caddr_t sfbasic;
291 int i, hsetup, vsetup, vbase;
292
293 dc->dc_vaddr = dense_addr;
294 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
295
296 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
297 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
298 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
299 vbase = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
300
301 dc->dc_wid = (hsetup & 0x1ff) << 2;
302 dc->dc_ht = (vsetup & 0x7ff);
303 dc->dc_depth = 8;
304 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
305 dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
306 dc->dc_blanked = 0;
307
308 /* initialize colormap and cursor resource */
309 sfbinit(dc);
310
311 /* clear the screen */
312 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
313 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
314
315 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
316
317 /* initialize the raster */
318 rap = &dc->dc_raster;
319 rap->width = dc->dc_wid;
320 rap->height = dc->dc_ht;
321 rap->depth = dc->dc_depth;
322 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
323 rap->pixels = (u_int32_t *)dc->dc_videobase;
324 rap->data = sfbasic;
325
326 /* initialize the raster console blitter */
327 rcp = &dc->dc_rcons;
328 rcp->rc_sp = rap;
329 rcp->rc_crow = rcp->rc_ccol = -1;
330 rcp->rc_crowp = &rcp->rc_crow;
331 rcp->rc_ccolp = &rcp->rc_ccol;
332 rcons_init(rcp, 34, 80);
333
334 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
335 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
336 }
337
338 void
339 sfbattach(parent, self, aux)
340 struct device *parent, *self;
341 void *aux;
342 {
343 struct sfb_softc *sc = (struct sfb_softc *)self;
344 struct tc_attach_args *ta = aux;
345 struct wsemuldisplaydev_attach_args waa;
346 struct hwcmap *cm;
347 caddr_t sfbasic;
348 int console, i;
349
350 console = (ta->ta_addr == sfb_consaddr);
351 if (console) {
352 sc->sc_dc = &sfb_console_dc;
353 sc->nscreens = 1;
354 }
355 else {
356 sc->sc_dc = (struct fb_devconfig *)
357 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
358 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
359 }
360 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
361 sc->sc_dc->dc_depth);
362
363 cm = &sc->sc_cmap;
364 cm->r[0] = cm->g[0] = cm->b[0] = 0;
365 for (i = 1; i < CMAP_SIZE; i++) {
366 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
367 }
368 sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
369
370 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
371
372 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
373 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
374 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
375
376 waa.console = console;
377 waa.scrdata = &sfb_screenlist;
378 waa.accessops = &sfb_accessops;
379 waa.accesscookie = sc;
380
381 config_found(self, &waa, wsemuldisplaydevprint);
382 }
383
384 int
385 sfbioctl(v, cmd, data, flag, p)
386 void *v;
387 u_long cmd;
388 caddr_t data;
389 int flag;
390 struct proc *p;
391 {
392 struct sfb_softc *sc = v;
393 struct fb_devconfig *dc = sc->sc_dc;
394 int turnoff;
395
396 switch (cmd) {
397 case WSDISPLAYIO_GTYPE:
398 *(u_int *)data = WSDISPLAY_TYPE_SFB;
399 return (0);
400
401 case WSDISPLAYIO_GINFO:
402 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
403 wsd_fbip->height = sc->sc_dc->dc_ht;
404 wsd_fbip->width = sc->sc_dc->dc_wid;
405 wsd_fbip->depth = sc->sc_dc->dc_depth;
406 wsd_fbip->cmsize = CMAP_SIZE;
407 #undef fbt
408 return (0);
409
410 case WSDISPLAYIO_GETCMAP:
411 return get_cmap(sc, (struct wsdisplay_cmap *)data);
412
413 case WSDISPLAYIO_PUTCMAP:
414 return set_cmap(sc, (struct wsdisplay_cmap *)data);
415
416 case WSDISPLAYIO_SVIDEO:
417 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
418 if ((dc->dc_blanked == 0) ^ turnoff) {
419 dc->dc_blanked = turnoff;
420 /* XXX later XXX */
421 }
422 return (0);
423
424 case WSDISPLAYIO_GVIDEO:
425 *(u_int *)data = dc->dc_blanked ?
426 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
427 return (0);
428
429 case WSDISPLAYIO_GCURPOS:
430 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
431 return (0);
432
433 case WSDISPLAYIO_SCURPOS:
434 set_curpos(sc, (struct wsdisplay_curpos *)data);
435 bt459_set_curpos(sc);
436 return (0);
437
438 case WSDISPLAYIO_GCURMAX:
439 ((struct wsdisplay_curpos *)data)->x =
440 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
441 return (0);
442
443 case WSDISPLAYIO_GCURSOR:
444 return get_cursor(sc, (struct wsdisplay_cursor *)data);
445
446 case WSDISPLAYIO_SCURSOR:
447 return set_cursor(sc, (struct wsdisplay_cursor *)data);
448 }
449 return ENOTTY;
450 }
451
452 int
453 sfbmmap(v, offset, prot)
454 void *v;
455 off_t offset;
456 int prot;
457 {
458 struct sfb_softc *sc = v;
459
460 if (offset >= SFB_SIZE || offset < 0)
461 return (-1);
462 return machine_btop(sc->sc_dc->dc_paddr + offset);
463 }
464
465 int
466 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
467 void *v;
468 const struct wsscreen_descr *type;
469 void **cookiep;
470 int *curxp, *curyp;
471 long *attrp;
472 {
473 struct sfb_softc *sc = v;
474 long defattr;
475
476 if (sc->nscreens > 0)
477 return (ENOMEM);
478
479 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
480 *curxp = 0;
481 *curyp = 0;
482 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
483 *attrp = defattr;
484 sc->nscreens++;
485 return (0);
486 }
487
488 void
489 sfb_free_screen(v, cookie)
490 void *v;
491 void *cookie;
492 {
493 struct sfb_softc *sc = v;
494
495 if (sc->sc_dc == &sfb_console_dc)
496 panic("sfb_free_screen: console");
497
498 sc->nscreens--;
499 }
500
501 void
502 sfb_show_screen(v, cookie)
503 void *v;
504 void *cookie;
505 {
506 }
507
508 int
509 sfb_cnattach(addr)
510 tc_addr_t addr;
511 {
512 struct fb_devconfig *dcp = &sfb_console_dc;
513 long defattr;
514
515 sfb_getdevconfig(addr, dcp);
516
517 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
518
519 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
520 0, 0, defattr);
521 sfb_consaddr = addr;
522 return(0);
523 }
524
525 int
526 sfbintr(arg)
527 void *arg;
528 {
529 struct sfb_softc *sc = arg;
530 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
531 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
532 struct bt459reg *vdac;
533 int v;
534
535 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
536 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
537
538 if (sc->sc_changed == 0)
539 return (1);
540
541 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
542 v = sc->sc_changed;
543 sc->sc_changed = 0;
544
545 if (v & DATA_ENB_CHANGED) {
546 BT459_SELECT(vdac, BT459_REG_CCR);
547 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
548 }
549 if (v & DATA_CURCMAP_CHANGED) {
550 u_int8_t *cp = sc->sc_cursor.cc_color;
551
552 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
553 vdac->bt_reg = cp[1]; tc_wmb();
554 vdac->bt_reg = cp[3]; tc_wmb();
555 vdac->bt_reg = cp[5]; tc_wmb();
556
557 vdac->bt_reg = cp[0]; tc_wmb();
558 vdac->bt_reg = cp[2]; tc_wmb();
559 vdac->bt_reg = cp[4]; tc_wmb();
560 }
561 if (v & DATA_CURSHAPE_CHANGED) {
562 u_int8_t *ip, *mp, img, msk;
563 u_int8_t u;
564 int bcnt;
565
566 ip = (u_int8_t *)sc->sc_cursor.cc_image;
567 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
568
569 bcnt = 0;
570 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
571 /* 64 pixel scan line is consisted with 16 byte cursor ram */
572 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
573 /* pad right half 32 pixel when smaller than 33 */
574 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
575 vdac->bt_reg = 0; tc_wmb();
576 vdac->bt_reg = 0; tc_wmb();
577 }
578 else {
579 img = *ip++;
580 msk = *mp++;
581 img &= msk; /* cookie off image */
582 u = (msk & 0x0f) << 4 | (img & 0x0f);
583 vdac->bt_reg = shuffle[u]; tc_wmb();
584 u = (msk & 0xf0) | (img & 0xf0) >> 4;
585 vdac->bt_reg = shuffle[u]; tc_wmb();
586 }
587 bcnt += 2;
588 }
589 /* pad unoccupied scan lines */
590 while (bcnt < CURSOR_MAX_SIZE * 16) {
591 vdac->bt_reg = 0; tc_wmb();
592 vdac->bt_reg = 0; tc_wmb();
593 bcnt += 2;
594 }
595 }
596 if (v & DATA_CMAP_CHANGED) {
597 struct hwcmap *cm = &sc->sc_cmap;
598 int index;
599
600 BT459_SELECT(vdac, 0);
601 for (index = 0; index < CMAP_SIZE; index++) {
602 vdac->bt_cmap = cm->r[index]; tc_wmb();
603 vdac->bt_cmap = cm->g[index]; tc_wmb();
604 vdac->bt_cmap = cm->b[index]; tc_wmb();
605 }
606 }
607 return (1);
608 }
609
610 void
611 sfbinit(dc)
612 struct fb_devconfig *dc;
613 {
614 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
615 struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
616 int i;
617
618 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 0;
619 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
620 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
621 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
622 *(u_int32_t *)(sfbasic + SFB_ASIC_ROP) = 3;
623
624 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
625
626 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
627 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
628 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
629 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
630 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
631 vdac->bt_reg = 0; /* 205 */ tc_wmb();
632 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
633 vdac->bt_reg = 0; /* 207 */ tc_wmb();
634 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
635 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
636 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
637 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
638
639 BT459_SELECT(vdac, BT459_REG_CCR);
640 vdac->bt_reg = 0x0; tc_wmb();
641 vdac->bt_reg = 0x0; tc_wmb();
642 vdac->bt_reg = 0x0; tc_wmb();
643 vdac->bt_reg = 0x0; tc_wmb();
644 vdac->bt_reg = 0x0; tc_wmb();
645 vdac->bt_reg = 0x0; tc_wmb();
646 vdac->bt_reg = 0x0; tc_wmb();
647 vdac->bt_reg = 0x0; tc_wmb();
648 vdac->bt_reg = 0x0; tc_wmb();
649 vdac->bt_reg = 0x0; tc_wmb();
650 vdac->bt_reg = 0x0; tc_wmb();
651 vdac->bt_reg = 0x0; tc_wmb();
652 vdac->bt_reg = 0x0; tc_wmb();
653
654 /* build sane colormap */
655 BT459_SELECT(vdac, 0);
656 vdac->bt_cmap = 0; tc_wmb();
657 vdac->bt_cmap = 0; tc_wmb();
658 vdac->bt_cmap = 0; tc_wmb();
659 for (i = 1; i < CMAP_SIZE; i++) {
660 vdac->bt_cmap = 0xff; tc_wmb();
661 vdac->bt_cmap = 0xff; tc_wmb();
662 vdac->bt_cmap = 0xff; tc_wmb();
663 }
664
665 /* clear out cursor image */
666 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
667 for (i = 0; i < 1024; i++)
668 vdac->bt_reg = 0xff; tc_wmb();
669
670 /*
671 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
672 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
673 * image color. CCOLOR_1 will be never used.
674 */
675 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
676 vdac->bt_reg = 0xff; tc_wmb();
677 vdac->bt_reg = 0xff; tc_wmb();
678 vdac->bt_reg = 0xff; tc_wmb();
679
680 vdac->bt_reg = 0; tc_wmb();
681 vdac->bt_reg = 0; tc_wmb();
682 vdac->bt_reg = 0; tc_wmb();
683
684 vdac->bt_reg = 0xff; tc_wmb();
685 vdac->bt_reg = 0xff; tc_wmb();
686 vdac->bt_reg = 0xff; tc_wmb();
687 }
688
689 static int
690 get_cmap(sc, p)
691 struct sfb_softc *sc;
692 struct wsdisplay_cmap *p;
693 {
694 u_int index = p->index, count = p->count;
695
696 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
697 return (EINVAL);
698
699 if (!uvm_useracc(p->red, count, B_WRITE) ||
700 !uvm_useracc(p->green, count, B_WRITE) ||
701 !uvm_useracc(p->blue, count, B_WRITE))
702 return (EFAULT);
703
704 copyout(&sc->sc_cmap.r[index], p->red, count);
705 copyout(&sc->sc_cmap.g[index], p->green, count);
706 copyout(&sc->sc_cmap.b[index], p->blue, count);
707
708 return (0);
709 }
710
711 static int
712 set_cmap(sc, p)
713 struct sfb_softc *sc;
714 struct wsdisplay_cmap *p;
715 {
716 u_int index = p->index, count = p->count;
717
718 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
719 return (EINVAL);
720
721 if (!uvm_useracc(p->red, count, B_READ) ||
722 !uvm_useracc(p->green, count, B_READ) ||
723 !uvm_useracc(p->blue, count, B_READ))
724 return (EFAULT);
725
726 copyin(p->red, &sc->sc_cmap.r[index], count);
727 copyin(p->green, &sc->sc_cmap.g[index], count);
728 copyin(p->blue, &sc->sc_cmap.b[index], count);
729
730 sc->sc_changed |= DATA_CMAP_CHANGED;
731
732 return (0);
733 }
734
735
736 static int
737 set_cursor(sc, p)
738 struct sfb_softc *sc;
739 struct wsdisplay_cursor *p;
740 {
741 #define cc (&sc->sc_cursor)
742 int v, index, count, icount;
743
744 v = p->which;
745 if (v & WSDISPLAY_CURSOR_DOCMAP) {
746 index = p->cmap.index;
747 count = p->cmap.count;
748 if (index >= 2 || (index + count) > 2)
749 return (EINVAL);
750 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
751 !uvm_useracc(p->cmap.green, count, B_READ) ||
752 !uvm_useracc(p->cmap.blue, count, B_READ))
753 return (EFAULT);
754 }
755 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
756 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
757 return (EINVAL);
758 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
759 if (!uvm_useracc(p->image, icount, B_READ) ||
760 !uvm_useracc(p->mask, icount, B_READ))
761 return (EFAULT);
762 }
763 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
764 if (v & WSDISPLAY_CURSOR_DOCUR)
765 cc->cc_hot = p->hot;
766 if (v & WSDISPLAY_CURSOR_DOPOS)
767 set_curpos(sc, &p->pos);
768 bt459_set_curpos(sc);
769 }
770
771 sc->sc_changed = 0;
772 if (v & WSDISPLAY_CURSOR_DOCUR) {
773 sc->sc_curenb = p->enable;
774 sc->sc_changed |= DATA_ENB_CHANGED;
775 }
776 if (v & WSDISPLAY_CURSOR_DOCMAP) {
777 copyin(p->cmap.red, &cc->cc_color[index], count);
778 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
779 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
780 sc->sc_changed |= DATA_CURCMAP_CHANGED;
781 }
782 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
783 cc->cc_size = p->size;
784 memset(cc->cc_image, 0, sizeof cc->cc_image);
785 copyin(p->image, cc->cc_image, icount);
786 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
787 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
788 }
789
790 return (0);
791 #undef cc
792 }
793
794 static int
795 get_cursor(sc, p)
796 struct sfb_softc *sc;
797 struct wsdisplay_cursor *p;
798 {
799 return (ENOTTY); /* XXX */
800 }
801
802 static void
803 set_curpos(sc, curpos)
804 struct sfb_softc *sc;
805 struct wsdisplay_curpos *curpos;
806 {
807 struct fb_devconfig *dc = sc->sc_dc;
808 int x = curpos->x, y = curpos->y;
809
810 if (y < 0)
811 y = 0;
812 else if (y > dc->dc_ht)
813 y = dc->dc_ht;
814 if (x < 0)
815 x = 0;
816 else if (x > dc->dc_wid)
817 x = dc->dc_wid;
818 sc->sc_cursor.cc_pos.x = x;
819 sc->sc_cursor.cc_pos.y = y;
820 }
821
822 static void
823 bt459_set_curpos(sc)
824 struct sfb_softc *sc;
825 {
826 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
827 struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
828 int x, y, s;
829
830 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
831 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
832 x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
833
834 s = spltty();
835
836 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
837 vdac->bt_reg = x; tc_wmb();
838 vdac->bt_reg = x >> 8; tc_wmb();
839 vdac->bt_reg = y; tc_wmb();
840 vdac->bt_reg = y >> 8; tc_wmb();
841
842 splx(s);
843 }
844
845 #define MODE_SIMPLE 0
846 #define MODE_OPAQUESTIPPLE 1
847 #define MODE_OPAQUELINE 2
848 #define MODE_TRANSPARENTSTIPPLE 5
849 #define MODE_TRANSPARENTLINE 6
850 #define MODE_COPY 7
851
852 #define SFBALIGNMASK 0x7
853 #define SFBSTIPPLEALL1 0xffffffff
854 #define SFBSTIPPLEBITS 32
855 #define SFBSTIPPLEBITMASK 0x1f
856 #define SFBSTIPPLEBYTESDONE 32
857
858 /*
859 * Paint (or unpaint) the cursor.
860 */
861 void
862 sfb_cursor(id, on, row, col)
863 void *id;
864 int on, row, col;
865 {
866 struct rcons *rc = id;
867 int x, y;
868
869 /* turn the cursor off */
870 if (!on) {
871 /* make sure it's on */
872 if ((rc->rc_bits & RC_CURSOR) == 0)
873 return;
874
875 row = *rc->rc_crowp;
876 col = *rc->rc_ccolp;
877 } else {
878 /* unpaint the old copy. */
879 *rc->rc_crowp = row;
880 *rc->rc_ccolp = col;
881 }
882
883 x = col * rc->rc_font->width + rc->rc_xorigin;
884 y = row * rc->rc_font->height + rc->rc_yorigin;
885
886 raster_op(rc->rc_sp, x, y,
887 rc->rc_font->width, rc->rc_font->height,
888 RAS_INVERT,
889 (struct raster *) 0, 0, 0);
890
891 rc->rc_bits ^= RC_CURSOR;
892 }
893
894 /*
895 * Actually write a string to the frame buffer.
896 */
897 int
898 sfb_mapchar(id, uni, index)
899 void *id;
900 int uni;
901 unsigned int *index;
902 {
903 if (uni < 128) {
904 *index = uni;
905 return (5);
906 }
907 *index = ' ';
908 return (0);
909 }
910
911 /*
912 * Actually write a string to the frame buffer.
913 */
914 void
915 sfb_putchar(id, row, col, uc, attr)
916 void *id;
917 int row, col;
918 u_int uc;
919 long attr;
920 {
921 struct rcons *rc = id;
922 int x, y, op;
923 u_char help;
924
925 x = col * rc->rc_font->width + rc->rc_xorigin;
926 y = row * rc->rc_font->height + rc->rc_font_ascent + rc->rc_yorigin;
927
928 op = RAS_SRC;
929 if ((attr != 0) ^ ((rc->rc_bits & RC_INVERT) != 0))
930 op = RAS_NOT(op);
931 help = uc & 0xff;
932 raster_textn(rc->rc_sp, x, y, op, rc->rc_font, &help, 1);
933 }
934
935 /*
936 * Copy columns (characters) in a row (line).
937 */
938 void
939 sfb_copycols(id, row, srccol, dstcol, ncols)
940 void *id;
941 int row, srccol, dstcol, ncols;
942 {
943 struct rcons *rc = id;
944 int y, srcx, dstx, nx;
945
946 y = rc->rc_yorigin + rc->rc_font->height * row;
947 srcx = rc->rc_xorigin + rc->rc_font->width * srccol;
948 dstx = rc->rc_xorigin + rc->rc_font->width * dstcol;
949 nx = rc->rc_font->width * ncols;
950
951 raster_op(rc->rc_sp, dstx, y,
952 nx, rc->rc_font->height, RAS_SRC,
953 rc->rc_sp, srcx, y);
954 }
955
956 /*
957 * Clear columns (characters) in a row (line).
958 */
959 void
960 sfb_erasecols(id, row, startcol, ncols, fillattr)
961 void *id;
962 int row, startcol, ncols;
963 long fillattr;
964 {
965 struct rcons *rc = id;
966 struct raster *rap = rc->rc_sp;
967 caddr_t sfb, p;
968 int scanspan, startx, height, width, align, w, y;
969 u_int32_t lmask, rmask;
970
971 scanspan = rap->linelongs * 4;
972 y = rc->rc_yorigin + rc->rc_font->height * row;
973 startx = rc->rc_xorigin + rc->rc_font->width * startcol;
974 height = rc->rc_font->height;
975 w = rc->rc_font->width * ncols;
976
977 p = (caddr_t)rap->pixels + y * scanspan + startx;
978 align = (long)p & SFBALIGNMASK;
979 p -= align;
980 width = w + align;
981 lmask = SFBSTIPPLEALL1 << align;
982 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
983 sfb = rap->data;
984 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
985 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
986 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
987 if (width <= SFBSTIPPLEBITS) {
988 while (height > 0) {
989 *(u_int32_t *)(sfb + SFB_ASIC_ADDRESS) = (long)p;
990 *(u_int32_t *)(sfb + SFB_ASIC_START) = lmask & rmask;
991 p += scanspan;
992 height--;
993 }
994 }
995 else {
996 caddr_t q = p;
997 while (height > 0) {
998 *(u_int32_t *)p = lmask;
999 width -= 2 * SFBSTIPPLEBITS;
1000 while (width > 0) {
1001 p += SFBSTIPPLEBYTESDONE;
1002 *(u_int32_t *)p = SFBSTIPPLEALL1;
1003 width -= SFBSTIPPLEBITS;
1004 }
1005 p += SFBSTIPPLEBYTESDONE;
1006 *(u_int32_t *)p = rmask;
1007
1008 p = (q += scanspan);
1009 width = w + align;
1010 height--;
1011 }
1012 }
1013 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1014 }
1015
1016 /*
1017 * Copy rows (lines).
1018 */
1019 void
1020 sfb_copyrows(id, srcrow, dstrow, nrows)
1021 void *id;
1022 int srcrow, dstrow, nrows;
1023 {
1024 struct rcons *rc = id;
1025 struct raster *rap = rc->rc_sp;
1026 caddr_t sfb, p;
1027 int scanspan, offset, srcy, height, width, align, w;
1028 u_int32_t lmask, rmask;
1029
1030 scanspan = rap->linelongs * 4;
1031 height = rc->rc_font->height * nrows;
1032 offset = (dstrow - srcrow) * scanspan * rc->rc_font->height;
1033 srcy = rc->rc_yorigin + rc->rc_font->height * srcrow;
1034 if (srcrow < dstrow && srcrow + nrows > dstrow) {
1035 scanspan = -scanspan;
1036 srcy += height;
1037 }
1038
1039 p = (caddr_t)(rap->pixels + srcy * rap->linelongs) + rc->rc_xorigin;
1040 align = (long)p & SFBALIGNMASK;
1041 p -= align;
1042 w = rc->rc_font->width * rc->rc_maxcol;
1043 width = w + align;
1044 lmask = SFBSTIPPLEALL1 << align;
1045 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1046 sfb = rap->data;
1047 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_COPY;
1048 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1049 *(u_int32_t *)(sfb + SFB_ASIC_PIXELSHIFT) = 0;
1050 if (width <= SFBSTIPPLEBITS) {
1051 /* never happens */;
1052 }
1053 else {
1054 caddr_t q = p;
1055 while (height > 0) {
1056 *(u_int32_t *)p = lmask;
1057 *(u_int32_t *)(p + offset) = lmask;
1058 width -= 2 * SFBSTIPPLEBITS;
1059 while (width > 0) {
1060 p += SFBSTIPPLEBYTESDONE;
1061 *(u_int32_t *)p = SFBSTIPPLEALL1;
1062 *(u_int32_t *)(p + offset) = SFBSTIPPLEALL1;
1063 width -= SFBSTIPPLEBITS;
1064 }
1065 p += SFBSTIPPLEBYTESDONE;
1066 *(u_int32_t *)p = rmask;
1067 *(u_int32_t *)(p + offset) = rmask;
1068
1069 p = (q += scanspan);
1070 width = w + align;
1071 height--;
1072 }
1073 }
1074 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1075 }
1076
1077 /*
1078 * Erase rows (lines).
1079 */
1080 void
1081 sfb_eraserows(id, startrow, nrows, fillattr)
1082 void *id;
1083 int startrow, nrows;
1084 long fillattr;
1085 {
1086 struct rcons *rc = id;
1087 struct raster *rap = rc->rc_sp;
1088 caddr_t sfb, p;
1089 int scanspan, starty, height, width, align, w;
1090 u_int32_t lmask, rmask;
1091
1092 scanspan = rap->linelongs * 4;
1093 starty = rc->rc_yorigin + rc->rc_font->height * startrow;
1094 height = rc->rc_font->height * nrows;
1095
1096 p = (caddr_t)rap->pixels + starty * scanspan + rc->rc_xorigin;
1097 align = (long)p & SFBALIGNMASK;
1098 p -= align;
1099 w = rc->rc_font->width * rc->rc_maxcol;
1100 width = w + align;
1101 lmask = SFBSTIPPLEALL1 << align;
1102 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1103 sfb = rap->data;
1104 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
1105 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1106 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
1107 if (width <= SFBSTIPPLEBITS) {
1108 /* never happens */;
1109 }
1110 else {
1111 caddr_t q = p;
1112 while (height > 0) {
1113 *(u_int32_t *)p = lmask;
1114 width -= 2 * SFBSTIPPLEBITS;
1115 while (width > 0) {
1116 p += SFBSTIPPLEBYTESDONE;
1117 *(u_int32_t *)p = SFBSTIPPLEALL1;
1118 width -= SFBSTIPPLEBITS;
1119 }
1120 p += SFBSTIPPLEBYTESDONE;
1121 *(u_int32_t *)p = rmask;
1122
1123 p = (q += scanspan);
1124 width = w + align;
1125 height--;
1126 }
1127 }
1128 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1129 }
1130
1131 int
1132 sfb_alloc_attr(id, fg, bg, flags, attrp)
1133 void *id;
1134 int fg, bg, flags;
1135 long *attrp;
1136 {
1137 if (flags & (WSATTR_HILIT | WSATTR_BLINK |
1138 WSATTR_UNDERLINE | WSATTR_WSCOLORS))
1139 return (EINVAL);
1140 if (flags & WSATTR_REVERSE)
1141 *attrp = 1;
1142 else
1143 *attrp = 0;
1144 return (0);
1145 }
1146