sfb.c revision 1.15 1 /* $NetBSD: sfb.c,v 1.15 1999/05/07 08:00:31 nisimura 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.15 1999/05/07 08:00:31 nisimura 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
54 #include <dev/tc/tcvar.h>
55 #include <dev/ic/bt459reg.h>
56 #include <dev/tc/sfbreg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 /* XXX BUS'IFYING XXX */
61
62 #if defined(pmax)
63 #define machine_btop(x) mips_btop(x)
64 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
65 #endif
66
67 #if defined(__alpha__) || defined(alpha)
68 #define machine_btop(x) alpha_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
70 #endif
71
72 /*
73 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
74 * obscure register layout such as 2nd and 3rd Bt459 registers are
75 * adjacent each other in a word, i.e.,
76 * struct bt459triplet {
77 * struct {
78 * u_int8_t u0;
79 * u_int8_t u1;
80 * u_int8_t u2;
81 * unsigned :8;
82 * } bt_lo;
83 * ...
84 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
85 */
86 struct bt459reg {
87 u_int32_t bt_lo;
88 u_int32_t bt_hi;
89 u_int32_t bt_reg;
90 u_int32_t bt_cmap;
91 };
92
93 /* XXX XXX XXX */
94
95 struct fb_devconfig {
96 vaddr_t dc_vaddr; /* memory space virtual base address */
97 paddr_t dc_paddr; /* memory space physical base address */
98 vsize_t dc_size; /* size of slot memory */
99 int dc_wid; /* width of frame buffer */
100 int dc_ht; /* height of frame buffer */
101 int dc_depth; /* depth, bits per pixel */
102 int dc_rowbytes; /* bytes in a FB scan line */
103 vaddr_t dc_videobase; /* base of flat frame buffer */
104 struct raster dc_raster; /* raster description */
105 struct rcons dc_rcons; /* raster blitter control info */
106 int dc_blanked; /* currently has video disabled */
107 };
108
109 struct hwcmap256 {
110 #define CMAP_SIZE 256 /* 256 R/G/B entries */
111 u_int8_t r[CMAP_SIZE];
112 u_int8_t g[CMAP_SIZE];
113 u_int8_t b[CMAP_SIZE];
114 };
115
116 struct hwcursor64 {
117 struct wsdisplay_curpos cc_pos;
118 struct wsdisplay_curpos cc_hot;
119 struct wsdisplay_curpos cc_size;
120 struct wsdisplay_curpos cc_magic;
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 hwcmap256 sc_cmap; /* software copy of colormap */
130 struct hwcursor64 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 };
140
141 #define HX_MAGIC_X 368
142 #define HX_MAGIC_Y 38
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 hwcmap256 *cm;
347 caddr_t sfbasic;
348 int console;
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 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */
365 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */
366
367 sc->sc_cursor.cc_magic.x = HX_MAGIC_X;
368 sc->sc_cursor.cc_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 hwcmap256 *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
833 x += sc->sc_cursor.cc_magic.x;
834 y += sc->sc_cursor.cc_magic.y;
835
836 s = spltty();
837
838 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
839 vdac->bt_reg = x; tc_wmb();
840 vdac->bt_reg = x >> 8; tc_wmb();
841 vdac->bt_reg = y; tc_wmb();
842 vdac->bt_reg = y >> 8; tc_wmb();
843
844 splx(s);
845 }
846
847 #define MODE_SIMPLE 0
848 #define MODE_OPAQUESTIPPLE 1
849 #define MODE_OPAQUELINE 2
850 #define MODE_TRANSPARENTSTIPPLE 5
851 #define MODE_TRANSPARENTLINE 6
852 #define MODE_COPY 7
853
854 #define SFBALIGNMASK 0x7
855 #define SFBSTIPPLEALL1 0xffffffff
856 #define SFBSTIPPLEBITS 32
857 #define SFBSTIPPLEBITMASK 0x1f
858 #define SFBSTIPPLEBYTESDONE 32
859
860 /*
861 * Paint (or unpaint) the cursor.
862 */
863 void
864 sfb_cursor(id, on, row, col)
865 void *id;
866 int on, row, col;
867 {
868 struct rcons *rc = id;
869 int x, y;
870
871 /* turn the cursor off */
872 if (!on) {
873 /* make sure it's on */
874 if ((rc->rc_bits & RC_CURSOR) == 0)
875 return;
876
877 row = *rc->rc_crowp;
878 col = *rc->rc_ccolp;
879 } else {
880 /* unpaint the old copy. */
881 *rc->rc_crowp = row;
882 *rc->rc_ccolp = col;
883 }
884
885 x = col * rc->rc_font->width + rc->rc_xorigin;
886 y = row * rc->rc_font->height + rc->rc_yorigin;
887
888 raster_op(rc->rc_sp, x, y,
889 rc->rc_font->width, rc->rc_font->height,
890 RAS_INVERT,
891 (struct raster *) 0, 0, 0);
892
893 rc->rc_bits ^= RC_CURSOR;
894 }
895
896 /*
897 * Actually write a string to the frame buffer.
898 */
899 int
900 sfb_mapchar(id, uni, index)
901 void *id;
902 int uni;
903 unsigned int *index;
904 {
905 if (uni < 128) {
906 *index = uni;
907 return (5);
908 }
909 *index = ' ';
910 return (0);
911 }
912
913 /*
914 * Actually write a string to the frame buffer.
915 */
916 void
917 sfb_putchar(id, row, col, uc, attr)
918 void *id;
919 int row, col;
920 u_int uc;
921 long attr;
922 {
923 struct rcons *rc = id;
924 int x, y, op;
925 u_char help;
926
927 x = col * rc->rc_font->width + rc->rc_xorigin;
928 y = row * rc->rc_font->height + rc->rc_font_ascent + rc->rc_yorigin;
929
930 op = RAS_SRC;
931 if ((attr != 0) ^ ((rc->rc_bits & RC_INVERT) != 0))
932 op = RAS_NOT(op);
933 help = uc & 0xff;
934 raster_textn(rc->rc_sp, x, y, op, rc->rc_font, &help, 1);
935 }
936
937 /*
938 * Copy columns (characters) in a row (line).
939 */
940 void
941 sfb_copycols(id, row, srccol, dstcol, ncols)
942 void *id;
943 int row, srccol, dstcol, ncols;
944 {
945 struct rcons *rc = id;
946 int y, srcx, dstx, nx;
947
948 y = rc->rc_yorigin + rc->rc_font->height * row;
949 srcx = rc->rc_xorigin + rc->rc_font->width * srccol;
950 dstx = rc->rc_xorigin + rc->rc_font->width * dstcol;
951 nx = rc->rc_font->width * ncols;
952
953 raster_op(rc->rc_sp, dstx, y,
954 nx, rc->rc_font->height, RAS_SRC,
955 rc->rc_sp, srcx, y);
956 }
957
958 /*
959 * Clear columns (characters) in a row (line).
960 */
961 void
962 sfb_erasecols(id, row, startcol, ncols, fillattr)
963 void *id;
964 int row, startcol, ncols;
965 long fillattr;
966 {
967 struct rcons *rc = id;
968 struct raster *rap = rc->rc_sp;
969 caddr_t sfb, p;
970 int scanspan, startx, height, width, align, w, y;
971 u_int32_t lmask, rmask;
972
973 scanspan = rap->linelongs * 4;
974 y = rc->rc_yorigin + rc->rc_font->height * row;
975 startx = rc->rc_xorigin + rc->rc_font->width * startcol;
976 height = rc->rc_font->height;
977 w = rc->rc_font->width * ncols;
978
979 p = (caddr_t)rap->pixels + y * scanspan + startx;
980 align = (long)p & SFBALIGNMASK;
981 p -= align;
982 width = w + align;
983 lmask = SFBSTIPPLEALL1 << align;
984 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
985 sfb = rap->data;
986 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
987 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
988 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
989 if (width <= SFBSTIPPLEBITS) {
990 while (height > 0) {
991 *(u_int32_t *)(sfb + SFB_ASIC_ADDRESS) = (long)p;
992 *(u_int32_t *)(sfb + SFB_ASIC_START) = lmask & rmask;
993 p += scanspan;
994 height--;
995 }
996 }
997 else {
998 caddr_t q = p;
999 while (height > 0) {
1000 *(u_int32_t *)p = lmask;
1001 width -= 2 * SFBSTIPPLEBITS;
1002 while (width > 0) {
1003 p += SFBSTIPPLEBYTESDONE;
1004 *(u_int32_t *)p = SFBSTIPPLEALL1;
1005 width -= SFBSTIPPLEBITS;
1006 }
1007 p += SFBSTIPPLEBYTESDONE;
1008 *(u_int32_t *)p = rmask;
1009
1010 p = (q += scanspan);
1011 width = w + align;
1012 height--;
1013 }
1014 }
1015 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1016 }
1017
1018 /*
1019 * Copy rows (lines).
1020 */
1021 void
1022 sfb_copyrows(id, srcrow, dstrow, nrows)
1023 void *id;
1024 int srcrow, dstrow, nrows;
1025 {
1026 struct rcons *rc = id;
1027 struct raster *rap = rc->rc_sp;
1028 caddr_t sfb, p;
1029 int scanspan, offset, srcy, height, width, align, w;
1030 u_int32_t lmask, rmask;
1031
1032 scanspan = rap->linelongs * 4;
1033 height = rc->rc_font->height * nrows;
1034 offset = (dstrow - srcrow) * scanspan * rc->rc_font->height;
1035 srcy = rc->rc_yorigin + rc->rc_font->height * srcrow;
1036 if (srcrow < dstrow && srcrow + nrows > dstrow) {
1037 scanspan = -scanspan;
1038 srcy += height;
1039 }
1040
1041 p = (caddr_t)(rap->pixels + srcy * rap->linelongs) + rc->rc_xorigin;
1042 align = (long)p & SFBALIGNMASK;
1043 p -= align;
1044 w = rc->rc_font->width * rc->rc_maxcol;
1045 width = w + align;
1046 lmask = SFBSTIPPLEALL1 << align;
1047 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1048 sfb = rap->data;
1049 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_COPY;
1050 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1051 *(u_int32_t *)(sfb + SFB_ASIC_PIXELSHIFT) = 0;
1052 if (width <= SFBSTIPPLEBITS) {
1053 /* never happens */;
1054 }
1055 else {
1056 caddr_t q = p;
1057 while (height > 0) {
1058 *(u_int32_t *)p = lmask;
1059 *(u_int32_t *)(p + offset) = lmask;
1060 width -= 2 * SFBSTIPPLEBITS;
1061 while (width > 0) {
1062 p += SFBSTIPPLEBYTESDONE;
1063 *(u_int32_t *)p = SFBSTIPPLEALL1;
1064 *(u_int32_t *)(p + offset) = SFBSTIPPLEALL1;
1065 width -= SFBSTIPPLEBITS;
1066 }
1067 p += SFBSTIPPLEBYTESDONE;
1068 *(u_int32_t *)p = rmask;
1069 *(u_int32_t *)(p + offset) = rmask;
1070
1071 p = (q += scanspan);
1072 width = w + align;
1073 height--;
1074 }
1075 }
1076 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1077 }
1078
1079 /*
1080 * Erase rows (lines).
1081 */
1082 void
1083 sfb_eraserows(id, startrow, nrows, fillattr)
1084 void *id;
1085 int startrow, nrows;
1086 long fillattr;
1087 {
1088 struct rcons *rc = id;
1089 struct raster *rap = rc->rc_sp;
1090 caddr_t sfb, p;
1091 int scanspan, starty, height, width, align, w;
1092 u_int32_t lmask, rmask;
1093
1094 scanspan = rap->linelongs * 4;
1095 starty = rc->rc_yorigin + rc->rc_font->height * startrow;
1096 height = rc->rc_font->height * nrows;
1097
1098 p = (caddr_t)rap->pixels + starty * scanspan + rc->rc_xorigin;
1099 align = (long)p & SFBALIGNMASK;
1100 p -= align;
1101 w = rc->rc_font->width * rc->rc_maxcol;
1102 width = w + align;
1103 lmask = SFBSTIPPLEALL1 << align;
1104 rmask = SFBSTIPPLEALL1 >> (-width & SFBSTIPPLEBITMASK);
1105 sfb = rap->data;
1106 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_TRANSPARENTSTIPPLE;
1107 *(u_int32_t *)(sfb + SFB_ASIC_PLANEMASK) = ~0;
1108 *(u_int32_t *)(sfb + SFB_ASIC_FG) = 0;
1109 if (width <= SFBSTIPPLEBITS) {
1110 /* never happens */;
1111 }
1112 else {
1113 caddr_t q = p;
1114 while (height > 0) {
1115 *(u_int32_t *)p = lmask;
1116 width -= 2 * SFBSTIPPLEBITS;
1117 while (width > 0) {
1118 p += SFBSTIPPLEBYTESDONE;
1119 *(u_int32_t *)p = SFBSTIPPLEALL1;
1120 width -= SFBSTIPPLEBITS;
1121 }
1122 p += SFBSTIPPLEBYTESDONE;
1123 *(u_int32_t *)p = rmask;
1124
1125 p = (q += scanspan);
1126 width = w + align;
1127 height--;
1128 }
1129 }
1130 *(u_int32_t *)(sfb + SFB_ASIC_MODE) = MODE_SIMPLE;
1131 }
1132
1133 int
1134 sfb_alloc_attr(id, fg, bg, flags, attrp)
1135 void *id;
1136 int fg, bg, flags;
1137 long *attrp;
1138 {
1139 if (flags & (WSATTR_HILIT | WSATTR_BLINK |
1140 WSATTR_UNDERLINE | WSATTR_WSCOLORS))
1141 return (EINVAL);
1142 if (flags & WSATTR_REVERSE)
1143 *attrp = 1;
1144 else
1145 *attrp = 0;
1146 return (0);
1147 }
1148