tfb.c revision 1.27 1 /* $NetBSD: tfb.c,v 1.27 2000/09/13 02:11:15 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998, 1999 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: tfb.c,v 1.27 2000/09/13 02:11:15 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
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50
51 #include <dev/rasops/rasops.h>
52 #include <dev/wsfont/wsfont.h>
53
54 #include <dev/tc/tcvar.h>
55 #include <dev/ic/bt463reg.h>
56 #include <dev/ic/bt431reg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 #if defined(pmax)
61 #define machine_btop(x) mips_btop(x)
62 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
63
64 /*
65 * struct bt463reg {
66 * u_int8_t bt_lo;
67 * unsigned : 24;
68 * u_int8_t bt_hi;
69 * unsigned : 24;
70 * u_int8_t bt_reg;
71 * unsigned : 24;
72 * u_int8_t bt_cmap;
73 * };
74 *
75 * N.B. a pair of Bt431s are located adjascently.
76 * struct bt431twin {
77 * struct {
78 * u_int8_t u0; for sprite mask
79 * u_int8_t u1; for sprite image
80 * unsigned :16;
81 * } bt_lo;
82 * ...
83 *
84 * struct bt431reg {
85 * u_int16_t bt_lo;
86 * unsigned : 16;
87 * u_int16_t bt_hi;
88 * unsigned : 16;
89 * u_int16_t bt_ram;
90 * unsigned : 16;
91 * u_int16_t bt_ctl;
92 * };
93 */
94
95 #define BYTE(base, index) *((u_int8_t *)(base) + ((index)<<2))
96 #define HALF(base, index) *((u_int16_t *)(base) + ((index)<<1))
97
98 #endif
99
100 #if defined(__alpha__) || defined(alpha)
101 #define machine_btop(x) alpha_btop(x)
102 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
103
104 /*
105 * struct bt463reg {
106 * u_int32_t bt_lo;
107 * u_int32_t bt_hi;
108 * u_int32_t bt_reg;
109 * u_int32_t bt_cmap;
110 * };
111 *
112 * struct bt431reg {
113 * u_int32_t bt_lo;
114 * u_int32_t bt_hi;
115 * u_int32_t bt_ram;
116 * u_int32_t bt_ctl;
117 * };
118 */
119
120 #define BYTE(base, index) *((u_int32_t *)(base) + (index))
121 #define HALF(base, index) *((u_int32_t *)(base) + (index))
122
123 #endif
124
125 /* Bt463 hardware registers */
126 #define bt_lo 0
127 #define bt_hi 1
128 #define bt_reg 2
129 #define bt_cmap 3
130
131 /* Bt431 hardware registers */
132 #define bt_ram 2
133 #define bt_ctl 3
134
135 #define SELECT463(vdac, regno) do { \
136 BYTE(vdac, bt_lo) = (regno) & 0x00ff; \
137 BYTE(vdac, bt_hi) = ((regno)& 0xff00) >> 8; \
138 tc_wmb(); \
139 } while (0)
140
141 #define TWIN(x) ((x) | ((x) << 8))
142 #define TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
143 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
144
145 #define SELECT431(curs, regno) do { \
146 HALF(curs, bt_lo) = TWIN(regno);\
147 HALF(curs, bt_hi) = 0; \
148 tc_wmb(); \
149 } while (0)
150
151 struct fb_devconfig {
152 vaddr_t dc_vaddr; /* memory space virtual base address */
153 paddr_t dc_paddr; /* memory space physical base address */
154 vsize_t dc_size; /* size of slot memory */
155 int dc_wid; /* width of frame buffer */
156 int dc_ht; /* height of frame buffer */
157 int dc_depth; /* depth, bits per pixel */
158 int dc_rowbytes; /* bytes in a FB scan line */
159 vaddr_t dc_videobase; /* base of flat frame buffer */
160 int dc_blanked; /* currently has video disabled */
161
162 struct rasops_info rinfo;
163 };
164
165 struct hwcmap256 {
166 #define CMAP_SIZE 256 /* R/G/B entries */
167 u_int8_t r[CMAP_SIZE];
168 u_int8_t g[CMAP_SIZE];
169 u_int8_t b[CMAP_SIZE];
170 };
171
172 struct hwcursor64 {
173 struct wsdisplay_curpos cc_pos;
174 struct wsdisplay_curpos cc_hot;
175 struct wsdisplay_curpos cc_size;
176 struct wsdisplay_curpos cc_magic;
177 #define CURSOR_MAX_SIZE 64
178 u_int8_t cc_color[6];
179 u_int64_t cc_image[64 + 64];
180 };
181
182 struct tfb_softc {
183 struct device sc_dev;
184 struct fb_devconfig *sc_dc; /* device configuration */
185 struct hwcmap256 sc_cmap; /* software copy of colormap */
186 struct hwcursor64 sc_cursor; /* software copy of cursor */
187 int sc_curenb; /* cursor sprite enabled */
188 int sc_changed; /* need update of colormap */
189 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
190 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
191 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
192 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
193 #define DATA_ALL_CHANGED 0x0f
194 int nscreens;
195 };
196
197 #define TX_MAGIC_X 360
198 #define TX_MAGIC_Y 36
199
200 #define TX_BT463_OFFSET 0x040000
201 #define TX_BT431_OFFSET 0x040010
202 #define TX_CONTROL 0x040030
203 #define TX_MAP_REGISTER 0x040030
204 #define TX_PIP_OFFSET 0x0800c0
205 #define TX_SELECTION 0x100000
206 #define TX_8BPP_OFFSET 0x200000
207 #define TX_8BPP_SIZE 0x200000
208 #define TX_24BPP_OFFSET 0x400000
209 #define TX_24BPP_SIZE 0x600000
210 #define TX_VIDEO_ENABLE 0xa00000
211
212 #define TX_CTL_VIDEO_ON 0x80
213 #define TX_CTL_INT_ENA 0x40
214 #define TX_CTL_INT_PEND 0x20
215 #define TX_CTL_SEG_ENA 0x10
216 #define TX_CTL_SEG 0x0f
217
218 static int tfbmatch __P((struct device *, struct cfdata *, void *));
219 static void tfbattach __P((struct device *, struct device *, void *));
220
221 const struct cfattach tfb_ca = {
222 sizeof(struct tfb_softc), tfbmatch, tfbattach,
223 };
224
225 static void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
226 static struct fb_devconfig tfb_console_dc;
227 static tc_addr_t tfb_consaddr;
228
229 static struct wsscreen_descr tfb_stdscreen = {
230 "std", 0, 0,
231 0, /* textops */
232 0, 0,
233 WSSCREEN_REVERSE
234 };
235
236 static const struct wsscreen_descr *_tfb_scrlist[] = {
237 &tfb_stdscreen,
238 };
239
240 static const struct wsscreen_list tfb_screenlist = {
241 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
242 };
243
244 static int tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
245 static paddr_t tfbmmap __P((void *, off_t, int));
246
247 static int tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
248 void **, int *, int *, long *));
249 static void tfb_free_screen __P((void *, void *));
250 static int tfb_show_screen __P((void *, void *, int,
251 void (*) (void *, int, int), void *));
252
253 static const struct wsdisplay_accessops tfb_accessops = {
254 tfbioctl,
255 tfbmmap,
256 tfb_alloc_screen,
257 tfb_free_screen,
258 tfb_show_screen,
259 0 /* load_font */
260 };
261
262 int tfb_cnattach __P((tc_addr_t));
263 static int tfbintr __P((void *));
264 static void tfbinit __P((struct fb_devconfig *));
265
266 static int get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
267 static int set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
268 static int set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
269 static int get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
270 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
271 static void bt431_set_curpos __P((struct tfb_softc *));
272
273 /* bit order reverse */
274 static const u_int8_t flip[256] = {
275 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
276 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
277 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
278 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
279 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
280 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
281 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
282 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
283 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
284 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
285 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
286 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
287 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
288 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
289 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
290 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
291 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
292 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
293 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
294 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
295 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
296 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
297 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
298 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
299 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
300 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
301 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
302 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
303 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
304 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
305 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
306 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
307 };
308
309 static int
310 tfbmatch(parent, match, aux)
311 struct device *parent;
312 struct cfdata *match;
313 void *aux;
314 {
315 struct tc_attach_args *ta = aux;
316
317 if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
318 && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
319 return (0);
320
321 return (1);
322 }
323
324 static void
325 tfb_getdevconfig(dense_addr, dc)
326 tc_addr_t dense_addr;
327 struct fb_devconfig *dc;
328 {
329 int i, cookie;
330
331 dc->dc_vaddr = dense_addr;
332 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
333
334 dc->dc_wid = 1280;
335 dc->dc_ht = 1024;
336 dc->dc_depth = 8;
337 dc->dc_rowbytes = 1280;
338 dc->dc_videobase = dc->dc_vaddr + TX_8BPP_OFFSET;
339 dc->dc_blanked = 0;
340
341 /* initialize colormap and cursor resource */
342 tfbinit(dc);
343
344 /* clear the screen */
345 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
346 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
347
348 dc->rinfo.ri_flg = RI_CENTER;
349 dc->rinfo.ri_depth = dc->dc_depth;
350 dc->rinfo.ri_bits = (void *)dc->dc_videobase;
351 dc->rinfo.ri_width = dc->dc_wid;
352 dc->rinfo.ri_height = dc->dc_ht;
353 dc->rinfo.ri_stride = dc->dc_rowbytes;
354
355 wsfont_init();
356 /* prefer 8 pixel wide font */
357 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
358 cookie = wsfont_find(NULL, 0, 0, 0);
359 if (cookie <= 0) {
360 printf("tfb: font table is empty\n");
361 return;
362 }
363
364 if (wsfont_lock(cookie, &dc->rinfo.ri_font,
365 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
366 printf("tfb: couldn't lock font\n");
367 return;
368 }
369 dc->rinfo.ri_wsfcookie = cookie;
370
371 rasops_init(&dc->rinfo, 34, 80);
372
373 /* XXX shouldn't be global */
374 tfb_stdscreen.nrows = dc->rinfo.ri_rows;
375 tfb_stdscreen.ncols = dc->rinfo.ri_cols;
376 tfb_stdscreen.textops = &dc->rinfo.ri_ops;
377 tfb_stdscreen.capabilities = dc->rinfo.ri_caps;
378 }
379
380 static void
381 tfbattach(parent, self, aux)
382 struct device *parent, *self;
383 void *aux;
384 {
385 struct tfb_softc *sc = (struct tfb_softc *)self;
386 struct tc_attach_args *ta = aux;
387 struct wsemuldisplaydev_attach_args waa;
388 int console;
389
390 console = (ta->ta_addr == tfb_consaddr);
391 if (console) {
392 sc->sc_dc = &tfb_console_dc;
393 sc->nscreens = 1;
394 }
395 else {
396 sc->sc_dc = (struct fb_devconfig *)
397 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
398 tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
399 }
400 printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
401
402 memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
403
404 sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
405 sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
406
407 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
408
409 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
410 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
411
412 waa.console = console;
413 waa.scrdata = &tfb_screenlist;
414 waa.accessops = &tfb_accessops;
415 waa.accesscookie = sc;
416
417 config_found(self, &waa, wsemuldisplaydevprint);
418 }
419
420 static int
421 tfbioctl(v, cmd, data, flag, p)
422 void *v;
423 u_long cmd;
424 caddr_t data;
425 int flag;
426 struct proc *p;
427 {
428 struct tfb_softc *sc = v;
429 struct fb_devconfig *dc = sc->sc_dc;
430 int turnoff;
431
432 switch (cmd) {
433 case WSDISPLAYIO_GTYPE:
434 *(u_int *)data = WSDISPLAY_TYPE_TX;
435 return (0);
436
437 case WSDISPLAYIO_GINFO:
438 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
439 wsd_fbip->height = sc->sc_dc->dc_ht;
440 wsd_fbip->width = sc->sc_dc->dc_wid;
441 wsd_fbip->depth = sc->sc_dc->dc_depth;
442 wsd_fbip->cmsize = CMAP_SIZE;
443 #undef fbt
444 return (0);
445
446 case WSDISPLAYIO_GETCMAP:
447 return get_cmap(sc, (struct wsdisplay_cmap *)data);
448
449 case WSDISPLAYIO_PUTCMAP:
450 return set_cmap(sc, (struct wsdisplay_cmap *)data);
451
452 case WSDISPLAYIO_SVIDEO:
453 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
454 if ((dc->dc_blanked == 0) ^ turnoff) {
455 dc->dc_blanked = turnoff;
456 #if 0 /* XXX later XXX */
457 To turn off;
458 - clear the MSB of TX control register; &= ~0x80,
459 - assign Bt431 register #0 with value 0x4 to hide sprite cursor.
460 #endif /* XXX XXX XXX */
461 }
462 return (0);
463
464 case WSDISPLAYIO_GVIDEO:
465 *(u_int *)data = dc->dc_blanked ?
466 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
467 return (0);
468
469 case WSDISPLAYIO_GCURPOS:
470 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
471 return (0);
472
473 case WSDISPLAYIO_SCURPOS:
474 set_curpos(sc, (struct wsdisplay_curpos *)data);
475 bt431_set_curpos(sc);
476 return (0);
477
478 case WSDISPLAYIO_GCURMAX:
479 ((struct wsdisplay_curpos *)data)->x =
480 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
481 return (0);
482
483 case WSDISPLAYIO_GCURSOR:
484 return get_cursor(sc, (struct wsdisplay_cursor *)data);
485
486 case WSDISPLAYIO_SCURSOR:
487 return set_cursor(sc, (struct wsdisplay_cursor *)data);
488 }
489 return (ENOTTY);
490 }
491
492 static paddr_t
493 tfbmmap(v, offset, prot)
494 void *v;
495 off_t offset;
496 int prot;
497 {
498 struct tfb_softc *sc = v;
499
500 if (offset >= TX_8BPP_SIZE || offset < 0)
501 return (-1);
502 return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset);
503 }
504
505 static int
506 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
507 void *v;
508 const struct wsscreen_descr *type;
509 void **cookiep;
510 int *curxp, *curyp;
511 long *attrp;
512 {
513 struct tfb_softc *sc = v;
514 long defattr;
515
516 if (sc->nscreens > 0)
517 return (ENOMEM);
518
519 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
520 *curxp = 0;
521 *curyp = 0;
522 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
523 *attrp = defattr;
524 sc->nscreens++;
525 return (0);
526 }
527
528 static void
529 tfb_free_screen(v, cookie)
530 void *v;
531 void *cookie;
532 {
533 struct tfb_softc *sc = v;
534
535 if (sc->sc_dc == &tfb_console_dc)
536 panic("tfb_free_screen: console");
537
538 sc->nscreens--;
539 }
540
541 static int
542 tfb_show_screen(v, cookie, waitok, cb, cbarg)
543 void *v;
544 void *cookie;
545 int waitok;
546 void (*cb) __P((void *, int, int));
547 void *cbarg;
548 {
549
550 return (0);
551 }
552
553 /* EXPORT */ int
554 tfb_cnattach(addr)
555 tc_addr_t addr;
556 {
557 struct fb_devconfig *dcp = &tfb_console_dc;
558 long defattr;
559
560 tfb_getdevconfig(addr, dcp);
561 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
562 wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
563 tfb_consaddr = addr;
564 return (0);
565 }
566
567 static int
568 tfbintr(arg)
569 void *arg;
570 {
571 struct tfb_softc *sc = arg;
572 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
573 void *vdac, *curs;
574 int v;
575
576 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
577 if (sc->sc_changed == 0)
578 goto done;
579
580 vdac = (void *)(tfbbase + TX_BT463_OFFSET);
581 curs = (void *)(tfbbase + TX_BT431_OFFSET);
582 v = sc->sc_changed;
583 sc->sc_changed = 0;
584 if (v & DATA_ENB_CHANGED) {
585 SELECT431(curs, BT431_REG_COMMAND);
586 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
587 }
588 if (v & DATA_CURCMAP_CHANGED) {
589 u_int8_t *cp = sc->sc_cursor.cc_color;
590
591 SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
592 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
593 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
594 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
595
596 BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
597 BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
598 BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
599
600 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
601 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
602 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
603
604 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
605 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
606 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
607 }
608 if (v & DATA_CURSHAPE_CHANGED) {
609 u_int8_t *ip, *mp, img, msk;
610 int bcnt;
611
612 ip = (u_int8_t *)sc->sc_cursor.cc_image;
613 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
614 bcnt = 0;
615 SELECT431(curs, BT431_REG_CRAM_BASE);
616
617 /* 64 pixel scan line is consisted with 16 byte cursor ram */
618 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
619 /* pad right half 32 pixel when smaller than 33 */
620 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
621 HALF(curs, bt_ram) = 0;
622 tc_wmb();
623 }
624 else {
625 img = *ip++;
626 msk = *mp++;
627 img &= msk; /* cookie off image */
628 HALF(curs, bt_ram)
629 = (flip[img] << 8) | flip[msk];
630 tc_wmb();
631 }
632 bcnt += 2;
633 }
634 /* pad unoccupied scan lines */
635 while (bcnt < CURSOR_MAX_SIZE * 16) {
636 HALF(curs, bt_ram) = 0;
637 tc_wmb();
638 bcnt += 2;
639 }
640 }
641 if (v & DATA_CMAP_CHANGED) {
642 struct hwcmap256 *cm = &sc->sc_cmap;
643 int index;
644
645 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
646 for (index = 0; index < CMAP_SIZE; index++) {
647 BYTE(vdac, bt_cmap) = cm->r[index];
648 BYTE(vdac, bt_cmap) = cm->g[index];
649 BYTE(vdac, bt_cmap) = cm->b[index];
650 }
651 }
652 done:
653 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40; /* !? Eeeh !? */
654 *(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
655 return (1);
656 }
657
658 static void
659 tfbinit(dc)
660 struct fb_devconfig *dc;
661 {
662 caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
663 void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
664 void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
665 int i;
666
667 SELECT463(vdac, BT463_IREG_COMMAND_0);
668 BYTE(vdac, bt_reg) = 0x40; tc_wmb(); /* CMD 0 */
669 BYTE(vdac, bt_reg) = 0x46; tc_wmb(); /* CMD 1 */
670 BYTE(vdac, bt_reg) = 0xc0; tc_wmb(); /* CMD 2 */
671 BYTE(vdac, bt_reg) = 0; tc_wmb(); /* !? 204 !? */
672 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 0:7 */
673 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 8:15 */
674 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 16:23 */
675 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 24:27 */
676 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 0:7 */
677 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 8:15 */
678 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 16:23 */
679 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 24:27 */
680 BYTE(vdac, bt_reg) = 0x00; tc_wmb();
681
682 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
683 {
684 static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
686 };
687
688 SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
689 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
690 BYTE(vdac, bt_reg) = windowtype[i]; /* 0:7 */
691 BYTE(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */
692 BYTE(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */
693 }
694 }
695 #endif
696
697 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
698 for (i = 0; i < 256; i++) {
699 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
700 tc_wmb();
701 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
702 tc_wmb();
703 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
704 tc_wmb();
705 }
706
707 /* !? Eeeh !? */
708 SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
709 for (i = 0; i < 256; i++) {
710 BYTE(vdac, bt_cmap) = i; tc_wmb();
711 BYTE(vdac, bt_cmap) = i; tc_wmb();
712 BYTE(vdac, bt_cmap) = i; tc_wmb();
713 }
714
715 SELECT431(curs, BT431_REG_COMMAND);
716 HALF(curs, bt_ctl) = 0x0404; tc_wmb();
717 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb();
718 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb();
719 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb();
720 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb();
721 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb();
722 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb();
723 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
724 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
725 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb();
726 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb();
727 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb();
728 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb();
729
730 SELECT431(curs, BT431_REG_CRAM_BASE);
731 for (i = 0; i < 512; i++) {
732 HALF(curs, bt_ram) = 0; tc_wmb();
733 }
734 }
735
736 static int
737 get_cmap(sc, p)
738 struct tfb_softc *sc;
739 struct wsdisplay_cmap *p;
740 {
741 u_int index = p->index, count = p->count;
742
743 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
744 return (EINVAL);
745
746 if (!uvm_useracc(p->red, count, B_WRITE) ||
747 !uvm_useracc(p->green, count, B_WRITE) ||
748 !uvm_useracc(p->blue, count, B_WRITE))
749 return (EFAULT);
750
751 copyout(&sc->sc_cmap.r[index], p->red, count);
752 copyout(&sc->sc_cmap.g[index], p->green, count);
753 copyout(&sc->sc_cmap.b[index], p->blue, count);
754
755 return (0);
756 }
757
758 static int
759 set_cmap(sc, p)
760 struct tfb_softc *sc;
761 struct wsdisplay_cmap *p;
762 {
763 u_int index = p->index, count = p->count;
764
765 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
766 return (EINVAL);
767
768 if (!uvm_useracc(p->red, count, B_READ) ||
769 !uvm_useracc(p->green, count, B_READ) ||
770 !uvm_useracc(p->blue, count, B_READ))
771 return (EFAULT);
772
773 copyin(p->red, &sc->sc_cmap.r[index], count);
774 copyin(p->green, &sc->sc_cmap.g[index], count);
775 copyin(p->blue, &sc->sc_cmap.b[index], count);
776
777 sc->sc_changed |= DATA_CMAP_CHANGED;
778
779 return (0);
780 }
781
782 static int
783 set_cursor(sc, p)
784 struct tfb_softc *sc;
785 struct wsdisplay_cursor *p;
786 {
787 #define cc (&sc->sc_cursor)
788 int v, index, count, icount;
789
790 v = p->which;
791 if (v & WSDISPLAY_CURSOR_DOCMAP) {
792 index = p->cmap.index;
793 count = p->cmap.count;
794 if (index >= 2 || (index + count) > 2)
795 return (EINVAL);
796 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
797 !uvm_useracc(p->cmap.green, count, B_READ) ||
798 !uvm_useracc(p->cmap.blue, count, B_READ))
799 return (EFAULT);
800 }
801 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
802 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
803 return (EINVAL);
804 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
805 if (!uvm_useracc(p->image, icount, B_READ) ||
806 !uvm_useracc(p->mask, icount, B_READ))
807 return (EFAULT);
808 }
809 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
810 if (v & WSDISPLAY_CURSOR_DOCUR)
811 cc->cc_hot = p->hot;
812 if (v & WSDISPLAY_CURSOR_DOPOS)
813 set_curpos(sc, &p->pos);
814 bt431_set_curpos(sc);
815 }
816
817 sc->sc_changed = 0;
818 if (v & WSDISPLAY_CURSOR_DOCUR) {
819 sc->sc_curenb = p->enable;
820 sc->sc_changed |= DATA_ENB_CHANGED;
821 }
822 if (v & WSDISPLAY_CURSOR_DOCMAP) {
823 copyin(p->cmap.red, &cc->cc_color[index], count);
824 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
825 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
826 sc->sc_changed |= DATA_CURCMAP_CHANGED;
827 }
828 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
829 cc->cc_size = p->size;
830 memset(cc->cc_image, 0, sizeof cc->cc_image);
831 copyin(p->image, cc->cc_image, icount);
832 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
833 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
834 }
835
836 return (0);
837 #undef cc
838 }
839
840 static int
841 get_cursor(sc, p)
842 struct tfb_softc *sc;
843 struct wsdisplay_cursor *p;
844 {
845 return (ENOTTY); /* XXX */
846 }
847
848 static void
849 set_curpos(sc, curpos)
850 struct tfb_softc *sc;
851 struct wsdisplay_curpos *curpos;
852 {
853 struct fb_devconfig *dc = sc->sc_dc;
854 int x = curpos->x, y = curpos->y;
855
856 if (y < 0)
857 y = 0;
858 else if (y > dc->dc_ht)
859 y = dc->dc_ht;
860 if (x < 0)
861 x = 0;
862 else if (x > dc->dc_wid)
863 x = dc->dc_wid;
864 sc->sc_cursor.cc_pos.x = x;
865 sc->sc_cursor.cc_pos.y = y;
866 }
867
868 static void
869 bt431_set_curpos(sc)
870 struct tfb_softc *sc;
871 {
872 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
873 void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
874 u_int16_t twin;
875 int x, y, s;
876
877 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
878 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
879
880 x += sc->sc_cursor.cc_magic.x;
881 y += sc->sc_cursor.cc_magic.y;
882
883 s = spltty();
884
885 SELECT431(curs, BT431_REG_CURSOR_X_LOW);
886 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb();
887 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb();
888 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb();
889 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb();
890
891 splx(s);
892 }
893