tfb.c revision 1.3 1 /* $NetBSD: tfb.c,v 1.3 1998/11/09 03:58:06 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: tfb.c,v 1.3 1998/11/09 03:58:06 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 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt463reg.h>
57 #include <dev/ic/bt431reg.h>
58
59 #include "opt_uvm.h"
60 #if defined(UVM)
61 #include <uvm/uvm_extern.h>
62 #define useracc uvm_useracc
63 #endif
64
65 /* XXX BUS'IFYING XXX */
66
67 #if defined(__pmax__)
68 #define machine_btop(x) mips_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
70
71 struct bt463reg {
72 u_int8_t bt_lo;
73 unsigned : 24;
74 u_int8_t bt_hi;
75 unsigned : 24;
76 u_int8_t bt_reg;
77 unsigned : 24;
78 u_int8_t bt_cmap;
79 };
80
81 /* it's really painful to manipulate 'twined' registers... */
82 struct bt431reg {
83 u_int16_t bt_lo;
84 unsigned : 16;
85 u_int16_t bt_hi;
86 unsigned : 16;
87 u_int16_t bt_ram;
88 unsigned : 16;
89 u_int16_t bt_ctl;
90 };
91 #endif
92
93 #if defined(__alpha__) || defined(alpha)
94 #define machine_btop(x) alpha_btop(x)
95 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
96
97 struct bt463reg {
98 u_int32_t bt_lo;
99 u_int32_t bt_hi;
100 u_int32_t bt_reg;
101 u_int32_t bt_cmap;
102 };
103
104 /*
105 * N.B. a paif of Bt431s are located adjascently.
106 * struct bt431twin {
107 * struct {
108 * u_int8_t u0; for sprite image
109 * u_int8_t u1; for sprite mask
110 * unsigned :16;
111 * } bt_lo;
112 * ...
113 */
114 struct bt431reg {
115 u_int32_t bt_lo;
116 u_int32_t bt_hi;
117 u_int32_t bt_ram;
118 u_int32_t bt_ctl;
119 };
120 #endif
121
122 /* XXX XXX XXX */
123
124 struct fb_devconfig {
125 vaddr_t dc_vaddr; /* memory space virtual base address */
126 paddr_t dc_paddr; /* memory space physical base address */
127 vsize_t dc_size; /* size of slot memory */
128 int dc_wid; /* width of frame buffer */
129 int dc_ht; /* height of frame buffer */
130 int dc_depth; /* depth, bits per pixel */
131 int dc_rowbytes; /* bytes in a FB scan line */
132 vaddr_t dc_videobase; /* base of flat frame buffer */
133 struct raster dc_raster; /* raster description */
134 struct rcons dc_rcons; /* raster blitter control info */
135 int dc_blanked; /* currently has video disabled */
136 };
137
138 struct hwcmap {
139 #define CMAP_SIZE 256 /* R/G/B entries */
140 u_int8_t r[CMAP_SIZE];
141 u_int8_t g[CMAP_SIZE];
142 u_int8_t b[CMAP_SIZE];
143 };
144
145 struct hwcursor {
146 struct wsdisplay_curpos cc_pos;
147 struct wsdisplay_curpos cc_hot;
148 struct wsdisplay_curpos cc_size;
149 #define CURSOR_MAX_SIZE 64
150 u_int8_t cc_color[6];
151 u_int64_t cc_image[64 + 64];
152 };
153
154 struct tfb_softc {
155 struct device sc_dev;
156 struct fb_devconfig *sc_dc; /* device configuration */
157 struct hwcmap sc_cmap; /* software copy of colormap */
158 struct hwcursor sc_cursor; /* software copy of cursor */
159 int sc_curenb; /* cursor sprite enabled */
160 int sc_changed; /* need update of colormap */
161 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
162 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
163 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
164 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
165 #define DATA_ALL_CHANGED 0x0f
166 int nscreens;
167 short magic_x, magic_y; /* TX cursor location offset */
168 #define TX_MAGIC_X 220
169 #define TX_MAGIC_Y 35
170 };
171
172 #define TX_BT463_OFFSET 0x040000
173 #define TX_BT431_OFFSET 0x040010
174 #define TX_CONTROL 0x040030
175 #define TX_MAP_REGISTER 0x040030
176 #define TX_PIP_OFFSET 0x0800c0
177 #define TX_SELECTION 0x100000
178 #define TX_8FB_OFFSET 0x200000
179 #define TX_8FB_SIZE 0x100000
180 #define TX_24FB_OFFSET 0x400000
181 #define TX_24FB_SIZE 0x400000
182 #define TX_VIDEO_ENABLE 0xa00000
183
184 #define TX_CTL_VIDEO_ON 0x80
185 #define TX_CTL_INT_ENA 0x40
186 #define TX_CTL_INT_PEND 0x20
187 #define TX_CTL_SEG_ENA 0x10
188 #define TX_CTL_SEG 0x0f
189
190 int tfbmatch __P((struct device *, struct cfdata *, void *));
191 void tfbattach __P((struct device *, struct device *, void *));
192
193 struct cfattach tfb_ca = {
194 sizeof(struct tfb_softc), tfbmatch, tfbattach,
195 };
196
197 void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
198 struct fb_devconfig tfb_console_dc;
199 tc_addr_t tfb_consaddr;
200
201 struct wsdisplay_emulops tfb_emulops = {
202 rcons_cursor, /* could use hardware cursor; punt */
203 rcons_mapchar,
204 rcons_putchar,
205 rcons_copycols,
206 rcons_erasecols,
207 rcons_copyrows,
208 rcons_eraserows,
209 rcons_alloc_attr
210 };
211
212 struct wsscreen_descr tfb_stdscreen = {
213 "std", 0, 0,
214 &tfb_emulops,
215 0, 0,
216 0
217 };
218
219 const struct wsscreen_descr *_tfb_scrlist[] = {
220 &tfb_stdscreen,
221 };
222
223 struct wsscreen_list tfb_screenlist = {
224 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
225 };
226
227 int tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
228 int tfbmmap __P((void *, off_t, int));
229
230 int tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
231 void **, int *, int *, long *));
232 void tfb_free_screen __P((void *, void *));
233 void tfb_show_screen __P((void *, void *));
234 int tfb_load_font __P((void *, void *, int, int, int, void *));
235
236 struct wsdisplay_accessops tfb_accessops = {
237 tfbioctl,
238 tfbmmap,
239 tfb_alloc_screen,
240 tfb_free_screen,
241 tfb_show_screen,
242 tfb_load_font
243 };
244
245 int tfb_cnattach __P((tc_addr_t));
246 int tfbintr __P((void *));
247 void tfbinit __P((struct fb_devconfig *));
248
249 static int get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
250 static int set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
251 static int set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
252 static int get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
253 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
254 static void bt431_set_curpos __P((struct tfb_softc *));
255
256 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
257 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
258
259 /* XXX XXX XXX */
260 #define BT431_SELECT(curs, regno) do { \
261 u_int16_t twin; \
262 curs->bt_lo = TWIN_LO(regno); \
263 curs->bt_hi = TWIN_HI(regno); \
264 tc_wmb(); \
265 } while (0)
266
267 #define BT463_SELECT(vdac, regno) do { \
268 vdac->bt_lo = (regno) & 0x00ff; \
269 vdac->bt_hi = ((regno)& 0xff00) >> 8; \
270 tc_wmb(); \
271 } while (0)
272 /* XXX XXX XXX */
273
274 /* bit order reverse */
275 const static 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 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 void
326 tfb_getdevconfig(dense_addr, dc)
327 tc_addr_t dense_addr;
328 struct fb_devconfig *dc;
329 {
330 struct raster *rap;
331 struct rcons *rcp;
332 int i;
333
334 dc->dc_vaddr = dense_addr;
335 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
336
337 dc->dc_wid = 1280;
338 dc->dc_ht = 1024;
339 dc->dc_depth = 8;
340 dc->dc_rowbytes = 1280;
341 dc->dc_videobase = dc->dc_vaddr + TX_8FB_OFFSET;
342 dc->dc_blanked = 0;
343
344 /* initialize colormap and cursor resource */
345 tfbinit(dc);
346
347 /* clear the screen */
348 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
349 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
350
351 /* initialize the raster */
352 rap = &dc->dc_raster;
353 rap->width = dc->dc_wid;
354 rap->height = dc->dc_ht;
355 rap->depth = dc->dc_depth;
356 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
357 rap->pixels = (u_int32_t *)dc->dc_videobase;
358
359 /* initialize the raster console blitter */
360 rcp = &dc->dc_rcons;
361 rcp->rc_sp = rap;
362 rcp->rc_crow = rcp->rc_ccol = -1;
363 rcp->rc_crowp = &rcp->rc_crow;
364 rcp->rc_ccolp = &rcp->rc_ccol;
365 rcons_init(rcp, 34, 80);
366
367 tfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
368 tfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
369 }
370
371 void
372 tfbattach(parent, self, aux)
373 struct device *parent, *self;
374 void *aux;
375 {
376 struct tfb_softc *sc = (struct tfb_softc *)self;
377 struct tc_attach_args *ta = aux;
378 struct wsemuldisplaydev_attach_args waa;
379 struct hwcmap *cm;
380 int console, i;
381
382 console = (ta->ta_addr == tfb_consaddr);
383 if (console) {
384 sc->sc_dc = &tfb_console_dc;
385 sc->nscreens = 1;
386 }
387 else {
388 sc->sc_dc = (struct fb_devconfig *)
389 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
390 tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
391 }
392 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
393 sc->sc_dc->dc_depth);
394
395 cm = &sc->sc_cmap;
396 cm->r[0] = cm->g[0] = cm->b[0] = 0;
397 for (i = 1; i < CMAP_SIZE; i++) {
398 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
399 }
400 sc->magic_x = TX_MAGIC_X; sc->magic_y = TX_MAGIC_Y;
401
402 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
403 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
404 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
405
406 waa.console = console;
407 waa.scrdata = &tfb_screenlist;
408 waa.accessops = &tfb_accessops;
409 waa.accesscookie = sc;
410
411 config_found(self, &waa, wsemuldisplaydevprint);
412 }
413
414 int
415 tfbioctl(v, cmd, data, flag, p)
416 void *v;
417 u_long cmd;
418 caddr_t data;
419 int flag;
420 struct proc *p;
421 {
422 struct tfb_softc *sc = v;
423 struct fb_devconfig *dc = sc->sc_dc;
424 int turnoff;
425
426 switch (cmd) {
427 case WSDISPLAYIO_GTYPE:
428 *(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
429 return (0);
430
431 case WSDISPLAYIO_GINFO:
432 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
433 wsd_fbip->height = sc->sc_dc->dc_ht;
434 wsd_fbip->width = sc->sc_dc->dc_wid;
435 wsd_fbip->depth = sc->sc_dc->dc_depth;
436 wsd_fbip->cmsize = CMAP_SIZE;
437 #undef fbt
438 return (0);
439
440 case WSDISPLAYIO_GETCMAP:
441 return get_cmap(sc, (struct wsdisplay_cmap *)data);
442
443 case WSDISPLAYIO_PUTCMAP:
444 return set_cmap(sc, (struct wsdisplay_cmap *)data);
445
446 case WSDISPLAYIO_SVIDEO:
447 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
448 if ((dc->dc_blanked == 0) ^ turnoff) {
449 dc->dc_blanked = turnoff;
450 /* XXX later XXX */
451 }
452 return (0);
453
454 case WSDISPLAYIO_GVIDEO:
455 *(u_int *)data = dc->dc_blanked ?
456 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
457 return (0);
458
459 case WSDISPLAYIO_GCURPOS:
460 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
461 return (0);
462
463 case WSDISPLAYIO_SCURPOS:
464 set_curpos(sc, (struct wsdisplay_curpos *)data);
465 bt431_set_curpos(sc);
466 return (0);
467
468 case WSDISPLAYIO_GCURMAX:
469 ((struct wsdisplay_curpos *)data)->x =
470 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
471 return (0);
472
473 case WSDISPLAYIO_GCURSOR:
474 return get_cursor(sc, (struct wsdisplay_cursor *)data);
475
476 case WSDISPLAYIO_SCURSOR:
477 return set_cursor(sc, (struct wsdisplay_cursor *)data);
478 }
479 return ENOTTY;
480 }
481
482 int
483 tfbmmap(v, offset, prot)
484 void *v;
485 off_t offset;
486 int prot;
487 {
488 struct tfb_softc *sc = v;
489
490 if (offset > TX_8FB_SIZE) /* XXX */
491 return (-1);
492 return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
493 }
494
495 int
496 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
497 void *v;
498 const struct wsscreen_descr *type;
499 void **cookiep;
500 int *curxp, *curyp;
501 long *attrp;
502 {
503 struct tfb_softc *sc = v;
504 long defattr;
505
506 if (sc->nscreens > 0)
507 return (ENOMEM);
508
509 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
510 *curxp = 0;
511 *curyp = 0;
512 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
513 *attrp = defattr;
514 sc->nscreens++;
515 return (0);
516 }
517
518 void
519 tfb_free_screen(v, cookie)
520 void *v;
521 void *cookie;
522 {
523 struct tfb_softc *sc = v;
524
525 if (sc->sc_dc == &tfb_console_dc)
526 panic("tfb_free_screen: console");
527
528 sc->nscreens--;
529 }
530
531 void
532 tfb_show_screen(v, cookie)
533 void *v;
534 void *cookie;
535 {
536 }
537
538 int
539 tfb_load_font(v, cookie, first, num, stride, data)
540 void *v;
541 void *cookie;
542 int first, num, stride;
543 void *data;
544 {
545 return (EINVAL);
546 }
547
548 int
549 tfb_cnattach(addr)
550 tc_addr_t addr;
551 {
552 struct fb_devconfig *dcp = &tfb_console_dc;
553 long defattr;
554
555 tfb_getdevconfig(addr, dcp);
556
557 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
558
559 wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
560 0, 0, defattr);
561 tfb_consaddr = addr;
562 return(0);
563 }
564
565 int
566 tfbintr(arg)
567 void *arg;
568 {
569 struct tfb_softc *sc = arg;
570 caddr_t tfbbase;
571 struct bt463reg *vdac;
572 struct bt431reg *curs;
573 int v;
574
575 if (sc->sc_changed == 0)
576 return (1);
577
578 tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
579 vdac = (void *)(tfbbase + TX_BT463_OFFSET);
580 curs = (void *)(tfbbase + TX_BT431_OFFSET);
581 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
582 v = sc->sc_changed;
583 sc->sc_changed = 0;
584 if (v & DATA_ENB_CHANGED) {
585 BT431_SELECT(curs, BT431_REG_COMMAND);
586 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 BT463_SELECT(vdac, BT463_IREG_CURSOR_COLOR_0);
592 vdac->bt_reg = cp[1]; tc_wmb();
593 vdac->bt_reg = cp[3]; tc_wmb();
594 vdac->bt_reg = cp[5]; tc_wmb();
595
596 vdac->bt_reg = cp[0]; tc_wmb();
597 vdac->bt_reg = cp[2]; tc_wmb();
598 vdac->bt_reg = cp[4]; tc_wmb();
599
600 vdac->bt_reg = cp[1]; tc_wmb();
601 vdac->bt_reg = cp[3]; tc_wmb();
602 vdac->bt_reg = cp[5]; tc_wmb();
603
604 vdac->bt_reg = cp[1]; tc_wmb();
605 vdac->bt_reg = cp[3]; tc_wmb();
606 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
615 bcnt = 0;
616 BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
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 curs->bt_ram = 0;
622 tc_wmb();
623 }
624 else {
625 img = *ip++;
626 msk = *mp++;
627 img &= msk; /* cookie off image */
628 curs->bt_ram = (flip[msk] << 8) | flip[img];
629 tc_wmb();
630 }
631 bcnt += 2;
632 }
633 /* pad unoccupied scan lines */
634 while (bcnt < CURSOR_MAX_SIZE * 16) {
635 curs->bt_ram = 0;
636 tc_wmb();
637 bcnt += 2;
638 }
639 }
640 if (v & DATA_CMAP_CHANGED) {
641 struct hwcmap *cm = &sc->sc_cmap;
642 int index;
643
644 BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
645 for (index = 0; index < CMAP_SIZE; index++) {
646 vdac->bt_cmap = cm->r[index];
647 vdac->bt_cmap = cm->g[index];
648 vdac->bt_cmap = cm->b[index];
649 }
650 }
651 *(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
652 return (1);
653 }
654
655 void
656 tfbinit(dc)
657 struct fb_devconfig *dc;
658 {
659 caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
660 struct bt463reg *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
661 struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
662 int i;
663
664 BT463_SELECT(vdac, BT463_IREG_COMMAND_0);
665 vdac->bt_reg = 0x40; tc_wmb();
666 vdac->bt_reg = 0x46; tc_wmb();
667 vdac->bt_reg = 0xc0; tc_wmb();
668 vdac->bt_reg = 0; tc_wmb(); /* !? 204 !? */
669 vdac->bt_reg = 0xff; tc_wmb(); /* plane 0:7 */
670 vdac->bt_reg = 0xff; tc_wmb(); /* plane 8:15 */
671 vdac->bt_reg = 0xff; tc_wmb(); /* plane 16:23 */
672 vdac->bt_reg = 0xff; tc_wmb(); /* plane 24:27 */
673 vdac->bt_reg = 0x00; tc_wmb(); /* blink 0:7 */
674 vdac->bt_reg = 0x00; tc_wmb(); /* blink 8:15 */
675 vdac->bt_reg = 0x00; tc_wmb(); /* blink 16:23 */
676 vdac->bt_reg = 0x00; tc_wmb(); /* blink 24:27 */
677 vdac->bt_reg = 0x00; tc_wmb();
678
679 BT463_SELECT(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
680 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
681 vdac->bt_reg = /* ??? */ 0;
682 vdac->bt_reg = /* ??? */ 0;
683 vdac->bt_reg = /* ??? */ 0;
684 }
685
686 BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
687 vdac->bt_cmap = 0; tc_wmb();
688 vdac->bt_cmap = 0; tc_wmb();
689 vdac->bt_cmap = 0; tc_wmb();
690 for (i = 1; i < BT463_NCMAP_ENTRIES; i++) {
691 vdac->bt_cmap = 0xff; tc_wmb();
692 vdac->bt_cmap = 0xff; tc_wmb();
693 vdac->bt_cmap = 0xff; tc_wmb();
694 }
695
696 BT431_SELECT(curs, BT431_REG_COMMAND);
697 curs->bt_ctl = 0x0404; tc_wmb();
698 curs->bt_ctl = 0; tc_wmb();
699 curs->bt_ctl = 0; tc_wmb();
700 curs->bt_ctl = 0; tc_wmb();
701 curs->bt_ctl = 0; tc_wmb();
702 curs->bt_ctl = 0; tc_wmb();
703 curs->bt_ctl = 0; tc_wmb();
704 curs->bt_ctl = 0; tc_wmb();
705 curs->bt_ctl = 0; tc_wmb();
706 curs->bt_ctl = 0; tc_wmb();
707 curs->bt_ctl = 0; tc_wmb();
708 curs->bt_ctl = 0; tc_wmb();
709 curs->bt_ctl = 0; tc_wmb();
710 }
711
712 static int
713 get_cmap(sc, p)
714 struct tfb_softc *sc;
715 struct wsdisplay_cmap *p;
716 {
717 u_int index = p->index, count = p->count;
718
719 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
720 return (EINVAL);
721
722 if (!useracc(p->red, count, B_WRITE) ||
723 !useracc(p->green, count, B_WRITE) ||
724 !useracc(p->blue, count, B_WRITE))
725 return (EFAULT);
726
727 copyout(&sc->sc_cmap.r[index], p->red, count);
728 copyout(&sc->sc_cmap.g[index], p->green, count);
729 copyout(&sc->sc_cmap.b[index], p->blue, count);
730
731 return (0);
732 }
733
734 static int
735 set_cmap(sc, p)
736 struct tfb_softc *sc;
737 struct wsdisplay_cmap *p;
738 {
739 u_int index = p->index, count = p->count;
740
741 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
742 return (EINVAL);
743
744 if (!useracc(p->red, count, B_READ) ||
745 !useracc(p->green, count, B_READ) ||
746 !useracc(p->blue, count, B_READ))
747 return (EFAULT);
748
749 copyin(p->red, &sc->sc_cmap.r[index], count);
750 copyin(p->green, &sc->sc_cmap.g[index], count);
751 copyin(p->blue, &sc->sc_cmap.b[index], count);
752
753 sc->sc_changed |= DATA_CMAP_CHANGED;
754
755 return (0);
756 }
757
758 static int
759 set_cursor(sc, p)
760 struct tfb_softc *sc;
761 struct wsdisplay_cursor *p;
762 {
763 #define cc (&sc->sc_cursor)
764 int v, index, count;
765
766 v = p->which;
767 if (v & WSDISPLAY_CURSOR_DOCMAP) {
768 index = p->cmap.index;
769 count = p->cmap.count;
770 if (index >= 2 || (index + count) > 2)
771 return (EINVAL);
772 if (!useracc(p->cmap.red, count, B_READ) ||
773 !useracc(p->cmap.green, count, B_READ) ||
774 !useracc(p->cmap.blue, count, B_READ))
775 return (EFAULT);
776 }
777 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
778 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
779 return (EINVAL);
780 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
781 if (!useracc(p->image, count, B_READ) ||
782 !useracc(p->mask, count, B_READ))
783 return (EFAULT);
784 }
785 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
786 if (v & WSDISPLAY_CURSOR_DOCUR)
787 cc->cc_hot = p->hot;
788 if (v & WSDISPLAY_CURSOR_DOPOS)
789 set_curpos(sc, &p->pos);
790 bt431_set_curpos(sc);
791 }
792
793 sc->sc_changed = 0;
794 if (v & WSDISPLAY_CURSOR_DOCUR) {
795 sc->sc_curenb = p->enable;
796 sc->sc_changed |= DATA_ENB_CHANGED;
797 }
798 if (v & WSDISPLAY_CURSOR_DOCMAP) {
799 count = p->cmap.count;
800 copyin(p->cmap.red, &cc->cc_color[index], count);
801 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
802 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
803 sc->sc_changed |= DATA_CURCMAP_CHANGED;
804 }
805 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
806 cc->cc_size = p->size;
807 memset(cc->cc_image, 0, sizeof cc->cc_image);
808 copyin(p->image, cc->cc_image, count);
809 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
810 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
811 }
812
813 return (0);
814 #undef cc
815 }
816
817 static int
818 get_cursor(sc, p)
819 struct tfb_softc *sc;
820 struct wsdisplay_cursor *p;
821 {
822 return (ENOTTY); /* XXX */
823 }
824
825 static void
826 set_curpos(sc, curpos)
827 struct tfb_softc *sc;
828 struct wsdisplay_curpos *curpos;
829 {
830 struct fb_devconfig *dc = sc->sc_dc;
831 int x = curpos->x, y = curpos->y;
832
833 if (y < 0)
834 y = 0;
835 else if (y > dc->dc_ht)
836 y = dc->dc_ht;
837 if (x < 0)
838 x = 0;
839 else if (x > dc->dc_wid)
840 x = dc->dc_wid;
841 sc->sc_cursor.cc_pos.x = x;
842 sc->sc_cursor.cc_pos.y = y;
843 }
844
845 static void
846 bt431_set_curpos(sc)
847 struct tfb_softc *sc;
848 {
849 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
850 struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
851 u_int16_t twin;
852 int x, y, s;
853
854 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
855 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
856 x += sc->magic_x; y += sc->magic_y; /* magic offset of TX coordinate */
857
858 s = spltty();
859
860 BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
861 curs->bt_ctl = TWIN_LO(x); tc_wmb();
862 curs->bt_ctl = TWIN_HI(x); tc_wmb();
863 curs->bt_ctl = TWIN_LO(y); tc_wmb();
864 curs->bt_ctl = TWIN_HI(y); tc_wmb();
865
866 splx(s);
867 }
868