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