tfb.c revision 1.24.4.1 1 /* $NetBSD: tfb.c,v 1.24.4.1 2000/06/30 16:27:52 simonb 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.24.4.1 2000/06/30 16:27:52 simonb 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 paddr_t 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_flg = RI_CENTER;
350 dc->rinfo.ri_depth = dc->dc_depth;
351 dc->rinfo.ri_bits = (void *)dc->dc_videobase;
352 dc->rinfo.ri_width = dc->dc_wid;
353 dc->rinfo.ri_height = dc->dc_ht;
354 dc->rinfo.ri_stride = dc->dc_rowbytes;
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 int console;
390
391 console = (ta->ta_addr == tfb_consaddr);
392 if (console) {
393 sc->sc_dc = &tfb_console_dc;
394 sc->nscreens = 1;
395 }
396 else {
397 sc->sc_dc = (struct fb_devconfig *)
398 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
399 tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
400 }
401 printf(": %d x %d, 8,24bpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht);
402
403 memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
404
405 sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
406 sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
407
408 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
409
410 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
411 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
412
413 waa.console = console;
414 waa.scrdata = &tfb_screenlist;
415 waa.accessops = &tfb_accessops;
416 waa.accesscookie = sc;
417
418 config_found(self, &waa, wsemuldisplaydevprint);
419 }
420
421 static int
422 tfbioctl(v, cmd, data, flag, p)
423 void *v;
424 u_long cmd;
425 caddr_t data;
426 int flag;
427 struct proc *p;
428 {
429 struct tfb_softc *sc = v;
430 struct fb_devconfig *dc = sc->sc_dc;
431 int turnoff;
432
433 switch (cmd) {
434 case WSDISPLAYIO_GTYPE:
435 *(u_int *)data = WSDISPLAY_TYPE_TX;
436 return (0);
437
438 case WSDISPLAYIO_GINFO:
439 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
440 wsd_fbip->height = sc->sc_dc->dc_ht;
441 wsd_fbip->width = sc->sc_dc->dc_wid;
442 wsd_fbip->depth = sc->sc_dc->dc_depth;
443 wsd_fbip->cmsize = CMAP_SIZE;
444 #undef fbt
445 return (0);
446
447 case WSDISPLAYIO_GETCMAP:
448 return get_cmap(sc, (struct wsdisplay_cmap *)data);
449
450 case WSDISPLAYIO_PUTCMAP:
451 return set_cmap(sc, (struct wsdisplay_cmap *)data);
452
453 case WSDISPLAYIO_SVIDEO:
454 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
455 if ((dc->dc_blanked == 0) ^ turnoff) {
456 dc->dc_blanked = turnoff;
457 #if 0 /* XXX later XXX */
458 To turn off;
459 - clear the MSB of TX control register; &= ~0x80,
460 - assign Bt431 register #0 with value 0x4 to hide sprite cursor.
461 #endif /* XXX XXX XXX */
462 }
463 return (0);
464
465 case WSDISPLAYIO_GVIDEO:
466 *(u_int *)data = dc->dc_blanked ?
467 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
468 return (0);
469
470 case WSDISPLAYIO_GCURPOS:
471 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
472 return (0);
473
474 case WSDISPLAYIO_SCURPOS:
475 set_curpos(sc, (struct wsdisplay_curpos *)data);
476 bt431_set_curpos(sc);
477 return (0);
478
479 case WSDISPLAYIO_GCURMAX:
480 ((struct wsdisplay_curpos *)data)->x =
481 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
482 return (0);
483
484 case WSDISPLAYIO_GCURSOR:
485 return get_cursor(sc, (struct wsdisplay_cursor *)data);
486
487 case WSDISPLAYIO_SCURSOR:
488 return set_cursor(sc, (struct wsdisplay_cursor *)data);
489 }
490 return (ENOTTY);
491 }
492
493 static paddr_t
494 tfbmmap(v, offset, prot)
495 void *v;
496 off_t offset;
497 int prot;
498 {
499 struct tfb_softc *sc = v;
500
501 if (offset >= TX_8BPP_SIZE || offset < 0)
502 return (-1);
503 return machine_btop(sc->sc_dc->dc_paddr + TX_8BPP_OFFSET + offset);
504 }
505
506 static int
507 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
508 void *v;
509 const struct wsscreen_descr *type;
510 void **cookiep;
511 int *curxp, *curyp;
512 long *attrp;
513 {
514 struct tfb_softc *sc = v;
515 long defattr;
516
517 if (sc->nscreens > 0)
518 return (ENOMEM);
519
520 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
521 *curxp = 0;
522 *curyp = 0;
523 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
524 *attrp = defattr;
525 sc->nscreens++;
526 return (0);
527 }
528
529 static void
530 tfb_free_screen(v, cookie)
531 void *v;
532 void *cookie;
533 {
534 struct tfb_softc *sc = v;
535
536 if (sc->sc_dc == &tfb_console_dc)
537 panic("tfb_free_screen: console");
538
539 sc->nscreens--;
540 }
541
542 static int
543 tfb_show_screen(v, cookie, waitok, cb, cbarg)
544 void *v;
545 void *cookie;
546 int waitok;
547 void (*cb) __P((void *, int, int));
548 void *cbarg;
549 {
550
551 return (0);
552 }
553
554 /* EXPORT */ int
555 tfb_cnattach(addr)
556 tc_addr_t addr;
557 {
558 struct fb_devconfig *dcp = &tfb_console_dc;
559 long defattr;
560
561 tfb_getdevconfig(addr, dcp);
562 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
563 wsdisplay_cnattach(&tfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
564 tfb_consaddr = addr;
565 return (0);
566 }
567
568 static int
569 tfbintr(arg)
570 void *arg;
571 {
572 struct tfb_softc *sc = arg;
573 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
574 void *vdac, *curs;
575 int v;
576
577 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
578 if (sc->sc_changed == 0)
579 goto done;
580
581 vdac = (void *)(tfbbase + TX_BT463_OFFSET);
582 curs = (void *)(tfbbase + TX_BT431_OFFSET);
583 v = sc->sc_changed;
584 sc->sc_changed = 0;
585 if (v & DATA_ENB_CHANGED) {
586 SELECT431(curs, BT431_REG_COMMAND);
587 HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
588 }
589 if (v & DATA_CURCMAP_CHANGED) {
590 u_int8_t *cp = sc->sc_cursor.cc_color;
591
592 SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
593 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
594 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
595 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
596
597 BYTE(vdac, bt_reg) = cp[0]; tc_wmb();
598 BYTE(vdac, bt_reg) = cp[2]; tc_wmb();
599 BYTE(vdac, bt_reg) = cp[4]; tc_wmb();
600
601 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
602 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
603 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
604
605 BYTE(vdac, bt_reg) = cp[1]; tc_wmb();
606 BYTE(vdac, bt_reg) = cp[3]; tc_wmb();
607 BYTE(vdac, bt_reg) = cp[5]; tc_wmb();
608 }
609 if (v & DATA_CURSHAPE_CHANGED) {
610 u_int8_t *ip, *mp, img, msk;
611 int bcnt;
612
613 ip = (u_int8_t *)sc->sc_cursor.cc_image;
614 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
615 bcnt = 0;
616 SELECT431(curs, BT431_REG_CRAM_BASE);
617
618 /* 64 pixel scan line is consisted with 16 byte cursor ram */
619 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
620 /* pad right half 32 pixel when smaller than 33 */
621 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
622 HALF(curs, bt_ram) = 0;
623 tc_wmb();
624 }
625 else {
626 img = *ip++;
627 msk = *mp++;
628 img &= msk; /* cookie off image */
629 HALF(curs, bt_ram)
630 = (flip[img] << 8) | flip[msk];
631 tc_wmb();
632 }
633 bcnt += 2;
634 }
635 /* pad unoccupied scan lines */
636 while (bcnt < CURSOR_MAX_SIZE * 16) {
637 HALF(curs, bt_ram) = 0;
638 tc_wmb();
639 bcnt += 2;
640 }
641 }
642 if (v & DATA_CMAP_CHANGED) {
643 struct hwcmap256 *cm = &sc->sc_cmap;
644 int index;
645
646 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
647 for (index = 0; index < CMAP_SIZE; index++) {
648 BYTE(vdac, bt_cmap) = cm->r[index];
649 BYTE(vdac, bt_cmap) = cm->g[index];
650 BYTE(vdac, bt_cmap) = cm->b[index];
651 }
652 }
653 done:
654 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40; /* !? Eeeh !? */
655 *(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
656 return (1);
657 }
658
659 static void
660 tfbinit(dc)
661 struct fb_devconfig *dc;
662 {
663 caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
664 void *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
665 void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
666 int i;
667
668 SELECT463(vdac, BT463_IREG_COMMAND_0);
669 BYTE(vdac, bt_reg) = 0x40; tc_wmb(); /* CMD 0 */
670 BYTE(vdac, bt_reg) = 0x46; tc_wmb(); /* CMD 1 */
671 BYTE(vdac, bt_reg) = 0xc0; tc_wmb(); /* CMD 2 */
672 BYTE(vdac, bt_reg) = 0; tc_wmb(); /* !? 204 !? */
673 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 0:7 */
674 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 8:15 */
675 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 16:23 */
676 BYTE(vdac, bt_reg) = 0xff; tc_wmb(); /* plane 24:27 */
677 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 0:7 */
678 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 8:15 */
679 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 16:23 */
680 BYTE(vdac, bt_reg) = 0x00; tc_wmb(); /* blink 24:27 */
681 BYTE(vdac, bt_reg) = 0x00; tc_wmb();
682
683 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
684 {
685 static u_int32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
686 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
687 };
688
689 SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
690 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
691 BYTE(vdac, bt_reg) = windowtype[i]; /* 0:7 */
692 BYTE(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */
693 BYTE(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */
694 }
695 }
696 #endif
697
698 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
699 for (i = 0; i < 256; i++) {
700 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
701 tc_wmb();
702 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
703 tc_wmb();
704 BYTE(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
705 tc_wmb();
706 }
707
708 /* !? Eeeh !? */
709 SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
710 for (i = 0; i < 256; i++) {
711 BYTE(vdac, bt_cmap) = i; tc_wmb();
712 BYTE(vdac, bt_cmap) = i; tc_wmb();
713 BYTE(vdac, bt_cmap) = i; tc_wmb();
714 }
715
716 SELECT431(curs, BT431_REG_COMMAND);
717 HALF(curs, bt_ctl) = 0x0404; tc_wmb();
718 HALF(curs, bt_ctl) = 0; /* XLO */ tc_wmb();
719 HALF(curs, bt_ctl) = 0; /* XHI */ tc_wmb();
720 HALF(curs, bt_ctl) = 0; /* YLO */ tc_wmb();
721 HALF(curs, bt_ctl) = 0; /* YHI */ tc_wmb();
722 HALF(curs, bt_ctl) = 0; /* XWLO */ tc_wmb();
723 HALF(curs, bt_ctl) = 0; /* XWHI */ tc_wmb();
724 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
725 HALF(curs, bt_ctl) = 0; /* WYLO */ tc_wmb();
726 HALF(curs, bt_ctl) = 0; /* WWLO */ tc_wmb();
727 HALF(curs, bt_ctl) = 0; /* WWHI */ tc_wmb();
728 HALF(curs, bt_ctl) = 0; /* WHLO */ tc_wmb();
729 HALF(curs, bt_ctl) = 0; /* WHHI */ tc_wmb();
730
731 SELECT431(curs, BT431_REG_CRAM_BASE);
732 for (i = 0; i < 512; i++) {
733 HALF(curs, bt_ram) = 0; tc_wmb();
734 }
735 }
736
737 static int
738 get_cmap(sc, p)
739 struct tfb_softc *sc;
740 struct wsdisplay_cmap *p;
741 {
742 u_int index = p->index, count = p->count;
743
744 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
745 return (EINVAL);
746
747 if (!uvm_useracc(p->red, count, B_WRITE) ||
748 !uvm_useracc(p->green, count, B_WRITE) ||
749 !uvm_useracc(p->blue, count, B_WRITE))
750 return (EFAULT);
751
752 copyout(&sc->sc_cmap.r[index], p->red, count);
753 copyout(&sc->sc_cmap.g[index], p->green, count);
754 copyout(&sc->sc_cmap.b[index], p->blue, count);
755
756 return (0);
757 }
758
759 static int
760 set_cmap(sc, p)
761 struct tfb_softc *sc;
762 struct wsdisplay_cmap *p;
763 {
764 u_int index = p->index, count = p->count;
765
766 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
767 return (EINVAL);
768
769 if (!uvm_useracc(p->red, count, B_READ) ||
770 !uvm_useracc(p->green, count, B_READ) ||
771 !uvm_useracc(p->blue, count, B_READ))
772 return (EFAULT);
773
774 copyin(p->red, &sc->sc_cmap.r[index], count);
775 copyin(p->green, &sc->sc_cmap.g[index], count);
776 copyin(p->blue, &sc->sc_cmap.b[index], count);
777
778 sc->sc_changed |= DATA_CMAP_CHANGED;
779
780 return (0);
781 }
782
783 static int
784 set_cursor(sc, p)
785 struct tfb_softc *sc;
786 struct wsdisplay_cursor *p;
787 {
788 #define cc (&sc->sc_cursor)
789 int v, index, count, icount;
790
791 v = p->which;
792 if (v & WSDISPLAY_CURSOR_DOCMAP) {
793 index = p->cmap.index;
794 count = p->cmap.count;
795 if (index >= 2 || (index + count) > 2)
796 return (EINVAL);
797 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
798 !uvm_useracc(p->cmap.green, count, B_READ) ||
799 !uvm_useracc(p->cmap.blue, count, B_READ))
800 return (EFAULT);
801 }
802 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
803 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
804 return (EINVAL);
805 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
806 if (!uvm_useracc(p->image, icount, B_READ) ||
807 !uvm_useracc(p->mask, icount, B_READ))
808 return (EFAULT);
809 }
810 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
811 if (v & WSDISPLAY_CURSOR_DOCUR)
812 cc->cc_hot = p->hot;
813 if (v & WSDISPLAY_CURSOR_DOPOS)
814 set_curpos(sc, &p->pos);
815 bt431_set_curpos(sc);
816 }
817
818 sc->sc_changed = 0;
819 if (v & WSDISPLAY_CURSOR_DOCUR) {
820 sc->sc_curenb = p->enable;
821 sc->sc_changed |= DATA_ENB_CHANGED;
822 }
823 if (v & WSDISPLAY_CURSOR_DOCMAP) {
824 copyin(p->cmap.red, &cc->cc_color[index], count);
825 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
826 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
827 sc->sc_changed |= DATA_CURCMAP_CHANGED;
828 }
829 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
830 cc->cc_size = p->size;
831 memset(cc->cc_image, 0, sizeof cc->cc_image);
832 copyin(p->image, cc->cc_image, icount);
833 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
834 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
835 }
836
837 return (0);
838 #undef cc
839 }
840
841 static int
842 get_cursor(sc, p)
843 struct tfb_softc *sc;
844 struct wsdisplay_cursor *p;
845 {
846 return (ENOTTY); /* XXX */
847 }
848
849 static void
850 set_curpos(sc, curpos)
851 struct tfb_softc *sc;
852 struct wsdisplay_curpos *curpos;
853 {
854 struct fb_devconfig *dc = sc->sc_dc;
855 int x = curpos->x, y = curpos->y;
856
857 if (y < 0)
858 y = 0;
859 else if (y > dc->dc_ht)
860 y = dc->dc_ht;
861 if (x < 0)
862 x = 0;
863 else if (x > dc->dc_wid)
864 x = dc->dc_wid;
865 sc->sc_cursor.cc_pos.x = x;
866 sc->sc_cursor.cc_pos.y = y;
867 }
868
869 static void
870 bt431_set_curpos(sc)
871 struct tfb_softc *sc;
872 {
873 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
874 void *curs = (void *)(tfbbase + TX_BT431_OFFSET);
875 u_int16_t twin;
876 int x, y, s;
877
878 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
879 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
880
881 x += sc->sc_cursor.cc_magic.x;
882 y += sc->sc_cursor.cc_magic.y;
883
884 s = spltty();
885
886 SELECT431(curs, BT431_REG_CURSOR_X_LOW);
887 HALF(curs, bt_ctl) = TWIN_LO(x); tc_wmb();
888 HALF(curs, bt_ctl) = TWIN_HI(x); tc_wmb();
889 HALF(curs, bt_ctl) = TWIN_LO(y); tc_wmb();
890 HALF(curs, bt_ctl) = TWIN_HI(y); tc_wmb();
891
892 splx(s);
893 }
894