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