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