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