1 /* $NetBSD: tfb.c,v 1.66 2021/12/06 16:00:07 abs Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tfb.c,v 1.66 2021/12/06 16:00:07 abs Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42
43 #include <sys/bus.h>
44 #include <sys/intr.h>
45
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
51
52 #include <dev/tc/tcvar.h>
53 #include <dev/ic/bt463reg.h>
54 #include <dev/ic/bt431reg.h>
55
56 #if defined(pmax)
57 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
58 #endif
59
60 #if defined(alpha)
61 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
62 #endif
63
64 /*
65 * struct bt463reg {
66 * uint8_t bt_lo;
67 * unsigned : 24;
68 * uint8_t bt_hi;
69 * unsigned : 24;
70 * uint8_t bt_reg;
71 * unsigned : 24;
72 * uint8_t bt_cmap;
73 * };
74 *
75 * N.B. a pair of Bt431s are located adjascently.
76 * struct bt431twin {
77 * struct {
78 * uint8_t u0; for sprite mask
79 * uint8_t u1; for sprite image
80 * unsigned :16;
81 * } bt_lo;
82 * ...
83 *
84 * struct bt431reg {
85 * uint16_t bt_lo;
86 * unsigned : 16;
87 * uint16_t bt_hi;
88 * unsigned : 16;
89 * uint16_t bt_ram;
90 * unsigned : 16;
91 * uint16_t bt_ctl;
92 * };
93 */
94
95 /* Bt463 hardware registers, memory-mapped in 32bit stride */
96 #define bt_lo 0x0
97 #define bt_hi 0x4
98 #define bt_reg 0x8
99 #define bt_cmap 0xc
100
101 /* Bt431 hardware registers, memory-mapped in 32bit stride */
102 #define bt_ram 0x8
103 #define bt_ctl 0xc
104
105 #define REGWRITE32(p,i,v) do { \
106 *(volatile uint32_t *)((p) + (i)) = (v); tc_wmb(); \
107 } while (0)
108
109 #define SELECT463(p,r) do { \
110 REGWRITE32((p), bt_lo, 0xff & (r)); \
111 REGWRITE32((p), bt_hi, 0xff & ((r)>>8)); \
112 } while (0)
113
114 #define TWIN(x) ((x) | ((x) << 8))
115 #define TWIN_LO(x) (twin = (x) & 0x00ff, (twin << 8) | twin)
116 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | (twin >> 8))
117
118 #define SELECT431(p,r) do { \
119 REGWRITE32((p), bt_lo, TWIN(r)); \
120 REGWRITE32((p), bt_hi, 0); \
121 } while (0)
122
123 struct hwcmap256 {
124 #define CMAP_SIZE 256 /* R/G/B entries */
125 uint8_t r[CMAP_SIZE];
126 uint8_t g[CMAP_SIZE];
127 uint8_t b[CMAP_SIZE];
128 };
129
130 struct hwcursor64 {
131 struct wsdisplay_curpos cc_pos;
132 struct wsdisplay_curpos cc_hot;
133 struct wsdisplay_curpos cc_size;
134 struct wsdisplay_curpos cc_magic;
135 #define CURSOR_MAX_SIZE 64
136 uint8_t cc_color[6];
137 uint64_t cc_image[CURSOR_MAX_SIZE];
138 uint64_t cc_mask[CURSOR_MAX_SIZE];
139 };
140
141 struct tfb_softc {
142 vaddr_t sc_vaddr;
143 size_t sc_size;
144 struct rasops_info *sc_ri;
145 struct hwcmap256 sc_cmap; /* software copy of colormap */
146 struct hwcursor64 sc_cursor; /* software copy of cursor */
147 int sc_blanked; /* video visibility disabled */
148 int sc_curenb; /* cursor sprite enabled */
149 int sc_changed; /* need update of hardware */
150 #define WSDISPLAY_CMAP_DOLUT 0x20
151 int nscreens;
152 };
153
154 #define TX_MAGIC_X 360
155 #define TX_MAGIC_Y 36
156
157 #define TX_BT463_OFFSET 0x040000
158 #define TX_BT431_OFFSET 0x040010
159 #define TX_CONTROL 0x040030
160 #define TX_MAP_REGISTER 0x040030
161 #define TX_PIP_OFFSET 0x0800c0
162 #define TX_SELECTION 0x100000
163 #define TX_8BPP_OFFSET 0x200000
164 #define TX_8BPP_SIZE 0x200000
165 #define TX_24BPP_OFFSET 0x400000
166 #define TX_24BPP_SIZE 0x600000
167 #define TX_VIDEO_ENABLE 0xa00000
168
169 #define TX_CTL_VIDEO_ON 0x80
170 #define TX_CTL_INT_ENA 0x40
171 #define TX_CTL_INT_PEND 0x20
172 #define TX_CTL_SEG_ENA 0x10
173 #define TX_CTL_SEG 0x0f
174
175 static int tfbmatch(device_t, cfdata_t, void *);
176 static void tfbattach(device_t, device_t, void *);
177
178 CFATTACH_DECL_NEW(tfb, sizeof(struct tfb_softc),
179 tfbmatch, tfbattach, NULL, NULL);
180
181 static void tfb_common_init(struct rasops_info *);
182 static void tfb_cmap_init(struct tfb_softc *);
183 static struct rasops_info tfb_console_ri;
184 static tc_addr_t tfb_consaddr;
185
186 static struct wsscreen_descr tfb_stdscreen = {
187 "std", 0, 0,
188 0, /* textops */
189 0, 0,
190 WSSCREEN_REVERSE
191 };
192
193 static const struct wsscreen_descr *_tfb_scrlist[] = {
194 &tfb_stdscreen,
195 };
196
197 static const struct wsscreen_list tfb_screenlist = {
198 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
199 };
200
201 static int tfbioctl(void *, void *, u_long, void *, int, struct lwp *);
202 static paddr_t tfbmmap(void *, void *, off_t, int);
203
204 static int tfb_alloc_screen(void *, const struct wsscreen_descr *,
205 void **, int *, int *, long *);
206 static void tfb_free_screen(void *, void *);
207 static int tfb_show_screen(void *, void *, int,
208 void (*) (void *, int, int), void *);
209
210 static const struct wsdisplay_accessops tfb_accessops = {
211 tfbioctl,
212 tfbmmap,
213 tfb_alloc_screen,
214 tfb_free_screen,
215 tfb_show_screen,
216 0 /* load_font */
217 };
218
219 int tfb_cnattach(tc_addr_t);
220 static int tfbintr(void *);
221 static void tfbhwinit(void *);
222
223 static int get_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
224 static int set_cmap(struct tfb_softc *, struct wsdisplay_cmap *);
225 static int set_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
226 static int get_cursor(struct tfb_softc *, struct wsdisplay_cursor *);
227 static void set_curpos(struct tfb_softc *, struct wsdisplay_curpos *);
228
229 /* bit order reverse */
230 static const uint8_t flip[256] = {
231 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
232 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
233 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
234 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
235 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
236 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
237 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
238 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
239 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
240 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
241 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
242 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
243 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
244 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
245 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
246 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
247 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
248 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
249 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
250 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
251 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
252 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
253 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
254 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
255 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
256 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
257 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
258 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
259 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
260 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
261 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
262 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
263 };
264
265 static int
tfbmatch(device_t parent,cfdata_t match,void * aux)266 tfbmatch(device_t parent, cfdata_t match, void *aux)
267 {
268 struct tc_attach_args *ta = aux;
269
270 if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
271 && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
272 return (0);
273
274 return (1);
275 }
276
277
278 static void
tfbattach(device_t parent,device_t self,void * aux)279 tfbattach(device_t parent, device_t self, void *aux)
280 {
281 struct tfb_softc *sc = device_private(self);
282 struct tc_attach_args *ta = aux;
283 struct rasops_info *ri;
284 struct wsemuldisplaydev_attach_args waa;
285 int console;
286
287 console = (ta->ta_addr == tfb_consaddr);
288 if (console) {
289 sc->sc_ri = ri = &tfb_console_ri;
290 ri->ri_flg &= ~RI_NO_AUTO;
291 sc->nscreens = 1;
292 }
293 else {
294 ri = malloc(sizeof(struct rasops_info),
295 M_DEVBUF, M_WAITOK | M_ZERO);
296 ri->ri_hw = (void *)ta->ta_addr;
297 tfb_common_init(ri);
298 sc->sc_ri = ri;
299 }
300 printf(": %dx%d, 8,24bpp\n", ri->ri_width, ri->ri_height);
301
302 tfb_cmap_init(sc);
303
304 sc->sc_vaddr = ta->ta_addr;
305 sc->sc_cursor.cc_magic.x = TX_MAGIC_X;
306 sc->sc_cursor.cc_magic.y = TX_MAGIC_Y;
307 sc->sc_blanked = sc->sc_curenb = 0;
308
309 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, tfbintr, sc);
310
311 *(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) &= ~0x40;
312 *(uint8_t *)((char *)ri->ri_hw + TX_CONTROL) |= 0x40;
313
314 waa.console = console;
315 waa.scrdata = &tfb_screenlist;
316 waa.accessops = &tfb_accessops;
317 waa.accesscookie = sc;
318
319 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
320 }
321
322 static void
tfb_common_init(struct rasops_info * ri)323 tfb_common_init(struct rasops_info *ri)
324 {
325 char *base;
326 int cookie;
327
328 base = (void *)ri->ri_hw;
329
330 /* initialize colormap and cursor hardware */
331 tfbhwinit(base);
332
333 ri->ri_flg = RI_CENTER;
334 if (ri == &tfb_console_ri)
335 ri->ri_flg |= RI_NO_AUTO;
336 ri->ri_depth = 8;
337 ri->ri_width = 1280;
338 ri->ri_height = 1024;
339 ri->ri_stride = 1280;
340 ri->ri_bits = base + TX_8BPP_OFFSET;
341
342 /* clear the screen */
343 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
344
345 wsfont_init();
346 /* prefer 12 pixel wide font */
347 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
348 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
349 if (cookie <= 0)
350 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
351 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
352 if (cookie <= 0) {
353 printf("tfb: font table is empty\n");
354 return;
355 }
356
357 if (wsfont_lock(cookie, &ri->ri_font)) {
358 printf("tfb: couldn't lock font\n");
359 return;
360 }
361 ri->ri_wsfcookie = cookie;
362
363 rasops_init(ri, 34, 80);
364
365 /* XXX shouldn't be global */
366 tfb_stdscreen.nrows = ri->ri_rows;
367 tfb_stdscreen.ncols = ri->ri_cols;
368 tfb_stdscreen.textops = &ri->ri_ops;
369 tfb_stdscreen.capabilities = ri->ri_caps;
370 }
371
372 static void
tfb_cmap_init(struct tfb_softc * sc)373 tfb_cmap_init(struct tfb_softc *sc)
374 {
375 struct hwcmap256 *cm;
376 const uint8_t *p;
377 int index;
378
379 cm = &sc->sc_cmap;
380 p = rasops_cmap;
381 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
382 cm->r[index] = p[0];
383 cm->g[index] = p[1];
384 cm->b[index] = p[2];
385 }
386 }
387
388 static int
tfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)389 tfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
390 {
391 struct tfb_softc *sc = v;
392 struct rasops_info *ri = sc->sc_ri;
393 int turnoff, s;
394
395 switch (cmd) {
396 case WSDISPLAYIO_GTYPE:
397 *(u_int *)data = WSDISPLAY_TYPE_TX;
398 return (0);
399
400 case WSDISPLAYIO_GET_FBINFO: {
401 struct wsdisplayio_fbinfo *fbi = data;
402 return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
403 }
404
405 case WSDISPLAYIO_GINFO:
406 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
407 wsd_fbip->height = ri->ri_height;
408 wsd_fbip->width = ri->ri_width;
409 wsd_fbip->depth = ri->ri_depth;
410 wsd_fbip->cmsize = CMAP_SIZE;
411 #undef fbt
412 return (0);
413
414 case WSDISPLAYIO_GETCMAP:
415 return get_cmap(sc, (struct wsdisplay_cmap *)data);
416
417 case WSDISPLAYIO_PUTCMAP:
418 return set_cmap(sc, (struct wsdisplay_cmap *)data);
419
420 case WSDISPLAYIO_SVIDEO:
421 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
422 if (sc->sc_blanked != turnoff) {
423 sc->sc_blanked = turnoff;
424 #if 0 /* XXX later XXX */
425 To turn off;
426 - clear the MSB of TX control register; &= ~0x80,
427 - assign Bt431 register #0 with value 0x4 to hide sprite cursor.
428 #endif /* XXX XXX XXX */
429 }
430 return (0);
431
432 case WSDISPLAYIO_GVIDEO:
433 *(u_int *)data = sc->sc_blanked ?
434 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
435 return (0);
436
437 case WSDISPLAYIO_GCURPOS:
438 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
439 return (0);
440
441 case WSDISPLAYIO_SCURPOS:
442 s = spltty();
443 set_curpos(sc, (struct wsdisplay_curpos *)data);
444 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
445 splx(s);
446 return (0);
447
448 case WSDISPLAYIO_GCURMAX:
449 ((struct wsdisplay_curpos *)data)->x =
450 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
451 return (0);
452
453 case WSDISPLAYIO_GCURSOR:
454 return get_cursor(sc, (struct wsdisplay_cursor *)data);
455
456 case WSDISPLAYIO_SCURSOR:
457 return set_cursor(sc, (struct wsdisplay_cursor *)data);
458
459 case WSDISPLAYIO_SMODE:
460 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
461 s = spltty();
462 tfb_cmap_init(sc);
463 sc->sc_curenb = 0;
464 sc->sc_blanked = 0;
465 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
466 WSDISPLAY_CMAP_DOLUT);
467 splx(s);
468 }
469 return (0);
470 }
471 return (EPASSTHROUGH);
472 }
473
474 static paddr_t
tfbmmap(void * v,void * vs,off_t offset,int prot)475 tfbmmap(void *v, void *vs, off_t offset, int prot)
476 {
477 struct tfb_softc *sc = v;
478
479 if (offset >= TX_8BPP_SIZE || offset < 0) /* XXX 24bpp XXX */
480 return (-1);
481 return machine_btop(sc->sc_vaddr + TX_8BPP_OFFSET + offset);
482 }
483
484 static int
tfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)485 tfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
486 int *curxp, int *curyp, long *attrp)
487 {
488 struct tfb_softc *sc = v;
489 struct rasops_info *ri = sc->sc_ri;
490 long defattr;
491
492 if (sc->nscreens > 0)
493 return (ENOMEM);
494
495 *cookiep = ri; /* one and only for now */
496 *curxp = 0;
497 *curyp = 0;
498 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
499 *attrp = defattr;
500 sc->nscreens++;
501 return (0);
502 }
503
504 static void
tfb_free_screen(void * v,void * cookie)505 tfb_free_screen(void *v, void *cookie)
506 {
507 struct tfb_softc *sc = v;
508
509 if (sc->sc_ri == &tfb_console_ri)
510 panic("tfb_free_screen: console");
511
512 sc->nscreens--;
513 }
514
515 static int
tfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)516 tfb_show_screen(void *v, void *cookie, int waitok,
517 void (*cb)(void *, int, int), void *cbarg)
518 {
519
520 return (0);
521 }
522
523 /* EXPORT */ int
tfb_cnattach(tc_addr_t addr)524 tfb_cnattach(tc_addr_t addr)
525 {
526 struct rasops_info *ri;
527 long defattr;
528
529 ri = &tfb_console_ri;
530 ri->ri_hw = (void *)addr;
531 tfb_common_init(ri);
532 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
533 wsdisplay_cnattach(&tfb_stdscreen, ri, 0, 0, defattr);
534 tfb_consaddr = addr;
535 return (0);
536 }
537
538 static int
tfbintr(void * arg)539 tfbintr(void *arg)
540 {
541 struct tfb_softc *sc = arg;
542 char *base, *vdac, *curs;
543 int v;
544
545 base = (void *)sc->sc_ri->ri_hw;
546 *(uint8_t *)(base + TX_CONTROL) &= ~0x40;
547 if (sc->sc_changed == 0)
548 goto done;
549
550 vdac = base + TX_BT463_OFFSET;
551 curs = base + TX_BT431_OFFSET;
552 v = sc->sc_changed;
553 if (v & WSDISPLAY_CURSOR_DOCUR) {
554 int onoff;
555
556 onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
557 SELECT431(curs, BT431_REG_COMMAND);
558 REGWRITE32(curs, bt_ctl, onoff);
559 }
560 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
561 int x, y;
562 uint32_t twin;
563
564 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
565 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
566
567 x += sc->sc_cursor.cc_magic.x;
568 y += sc->sc_cursor.cc_magic.y;
569
570 SELECT431(curs, BT431_REG_CURSOR_X_LOW);
571 REGWRITE32(curs, bt_ctl, TWIN_LO(x));
572 REGWRITE32(curs, bt_ctl, TWIN_HI(x));
573 REGWRITE32(curs, bt_ctl, TWIN_LO(y));
574 REGWRITE32(curs, bt_ctl, TWIN_HI(y));
575 }
576 if (v & WSDISPLAY_CURSOR_DOCMAP) {
577 uint8_t *cp = sc->sc_cursor.cc_color;
578
579 SELECT463(vdac, BT463_IREG_CURSOR_COLOR_0);
580 REGWRITE32(vdac, bt_reg, cp[1]);
581 REGWRITE32(vdac, bt_reg, cp[3]);
582 REGWRITE32(vdac, bt_reg, cp[5]);
583
584 REGWRITE32(vdac, bt_reg, cp[0]);
585 REGWRITE32(vdac, bt_reg, cp[2]);
586 REGWRITE32(vdac, bt_reg, cp[4]);
587
588 REGWRITE32(vdac, bt_reg, cp[1]);
589 REGWRITE32(vdac, bt_reg, cp[3]);
590 REGWRITE32(vdac, bt_reg, cp[5]);
591
592 REGWRITE32(vdac, bt_reg, cp[1]);
593 REGWRITE32(vdac, bt_reg, cp[3]);
594 REGWRITE32(vdac, bt_reg, cp[5]);
595 }
596 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
597 uint8_t *ip, *mp, img, msk;
598 int bcnt;
599
600 ip = (uint8_t *)sc->sc_cursor.cc_image;
601 mp = (uint8_t *)sc->sc_cursor.cc_mask;
602 bcnt = 0;
603 SELECT431(curs, BT431_REG_CRAM_BASE);
604
605 /* 64 pixel scan line is consisted with 16 byte cursor ram */
606 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
607 /* pad right half 32 pixel when smaller than 33 */
608 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
609 REGWRITE32(curs, bt_ram, 0);
610 }
611 else {
612 int half;
613 img = *ip++;
614 msk = *mp++;
615 img &= msk; /* cookie off image */
616 half = (flip[img] << 8) | flip[msk];
617 REGWRITE32(curs, bt_ram, half);
618 }
619 bcnt += 2;
620 }
621 /* pad unoccupied scan lines */
622 while (bcnt < CURSOR_MAX_SIZE * 16) {
623 REGWRITE32(curs, bt_ram, 0);
624 bcnt += 2;
625 }
626 }
627 if (v & WSDISPLAY_CMAP_DOLUT) {
628 struct hwcmap256 *cm = &sc->sc_cmap;
629 int index;
630
631 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
632 for (index = 0; index < CMAP_SIZE; index++) {
633 REGWRITE32(vdac, bt_cmap, cm->r[index]);
634 REGWRITE32(vdac, bt_cmap, cm->g[index]);
635 REGWRITE32(vdac, bt_cmap, cm->b[index]);
636 }
637 }
638 sc->sc_changed = 0;
639 done:
640 *(uint8_t *)(base + TX_CONTROL) &= ~0x40; /* !? Eeeh !? */
641 *(uint8_t *)(base + TX_CONTROL) |= 0x40;
642 return (1);
643 }
644
645 static void
tfbhwinit(void * tfbbase)646 tfbhwinit(void *tfbbase)
647 {
648 char *vdac, *curs;
649 const uint8_t *p;
650 int i;
651
652 vdac = (char *)tfbbase + TX_BT463_OFFSET;
653 curs = (char *)tfbbase + TX_BT431_OFFSET;
654 SELECT463(vdac, BT463_IREG_COMMAND_0);
655 REGWRITE32(vdac, bt_reg, 0x40); /* CMD 0 */
656 REGWRITE32(vdac, bt_reg, 0x46); /* CMD 1 */
657 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD 2 */
658 REGWRITE32(vdac, bt_reg, 0); /* !? 204 !? */
659 REGWRITE32(vdac, bt_reg, 0xff); /* plane 0:7 */
660 REGWRITE32(vdac, bt_reg, 0xff); /* plane 8:15 */
661 REGWRITE32(vdac, bt_reg, 0xff); /* plane 16:23 */
662 REGWRITE32(vdac, bt_reg, 0xff); /* plane 24:27 */
663 REGWRITE32(vdac, bt_reg, 0x00); /* blink 0:7 */
664 REGWRITE32(vdac, bt_reg, 0x00); /* blink 8:15 */
665 REGWRITE32(vdac, bt_reg, 0x00); /* blink 16:23 */
666 REGWRITE32(vdac, bt_reg, 0x00); /* blink 24:27 */
667 REGWRITE32(vdac, bt_reg, 0x00);
668
669 #if 0 /* XXX ULTRIX does initialize 16 entry window type here XXX */
670 {
671 static uint32_t windowtype[BT463_IREG_WINDOW_TYPE_TABLE] = {
672 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
673 };
674
675 SELECT463(vdac, BT463_IREG_WINDOW_TYPE_TABLE);
676 for (i = 0; i < BT463_NWTYPE_ENTRIES; i++) {
677 BYTE(vdac, bt_reg) = windowtype[i]; /* 0:7 */
678 BYTE(vdac, bt_reg) = windowtype[i] >> 8; /* 8:15 */
679 BYTE(vdac, bt_reg) = windowtype[i] >> 16; /* 16:23 */
680 }
681 }
682 #endif
683
684 SELECT463(vdac, BT463_IREG_CPALETTE_RAM);
685 p = rasops_cmap;
686 for (i = 0; i < 256; i++, p += 3) {
687 REGWRITE32(vdac, bt_cmap, p[0]);
688 REGWRITE32(vdac, bt_cmap, p[1]);
689 REGWRITE32(vdac, bt_cmap, p[2]);
690 }
691
692 /* !? Eeeh !? */
693 SELECT463(vdac, 0x0100 /* BT463_IREG_CURSOR_COLOR_0 */);
694 for (i = 0; i < 256; i++) {
695 REGWRITE32(vdac, bt_cmap, i);
696 REGWRITE32(vdac, bt_cmap, i);
697 REGWRITE32(vdac, bt_cmap, i);
698 }
699
700 SELECT431(curs, BT431_REG_COMMAND);
701 REGWRITE32(curs, bt_ctl, 0x0404);
702 REGWRITE32(curs, bt_ctl, 0); /* XLO */
703 REGWRITE32(curs, bt_ctl, 0); /* XHI */
704 REGWRITE32(curs, bt_ctl, 0); /* YLO */
705 REGWRITE32(curs, bt_ctl, 0); /* YHI */
706 REGWRITE32(curs, bt_ctl, 0); /* XWLO */
707 REGWRITE32(curs, bt_ctl, 0); /* XWHI */
708 REGWRITE32(curs, bt_ctl, 0); /* WYLO */
709 REGWRITE32(curs, bt_ctl, 0); /* WYLO */
710 REGWRITE32(curs, bt_ctl, 0); /* WWLO */
711 REGWRITE32(curs, bt_ctl, 0); /* WWHI */
712 REGWRITE32(curs, bt_ctl, 0); /* WHLO */
713 REGWRITE32(curs, bt_ctl, 0); /* WHHI */
714
715 SELECT431(curs, BT431_REG_CRAM_BASE);
716 for (i = 0; i < 512; i++) {
717 REGWRITE32(curs, bt_ram, 0);
718 }
719 }
720
721 static int
get_cmap(struct tfb_softc * sc,struct wsdisplay_cmap * p)722 get_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
723 {
724 u_int index = p->index, count = p->count;
725 int error;
726
727 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
728 return (EINVAL);
729
730 error = copyout(&sc->sc_cmap.r[index], p->red, count);
731 if (error)
732 return error;
733 error = copyout(&sc->sc_cmap.g[index], p->green, count);
734 if (error)
735 return error;
736 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
737 return error;
738 }
739
740 static int
set_cmap(struct tfb_softc * sc,struct wsdisplay_cmap * p)741 set_cmap(struct tfb_softc *sc, struct wsdisplay_cmap *p)
742 {
743 struct hwcmap256 cmap;
744 u_int index = p->index, count = p->count;
745 int error, s;
746
747 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
748 return (EINVAL);
749
750 error = copyin(p->red, &cmap.r[index], count);
751 if (error)
752 return error;
753 error = copyin(p->green, &cmap.g[index], count);
754 if (error)
755 return error;
756 error = copyin(p->blue, &cmap.b[index], count);
757 if (error)
758 return error;
759 s = spltty();
760 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
761 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
762 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
763 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
764 splx(s);
765 return (0);
766 }
767
768 static int
set_cursor(struct tfb_softc * sc,struct wsdisplay_cursor * p)769 set_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
770 {
771 #define cc (&sc->sc_cursor)
772 u_int v, index = 0, count = 0, icount = 0;
773 uint8_t r[2], g[2], b[2], image[512], mask[512];
774 int error, s;
775
776 v = p->which;
777 if (v & WSDISPLAY_CURSOR_DOCMAP) {
778 index = p->cmap.index;
779 count = p->cmap.count;
780 if (index >= 2 || count > 2 - index)
781 return (EINVAL);
782 error = copyin(p->cmap.red, &r[index], count);
783 if (error)
784 return error;
785 error = copyin(p->cmap.green, &g[index], count);
786 if (error)
787 return error;
788 error = copyin(p->cmap.blue, &b[index], count);
789 if (error)
790 return error;
791 }
792 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
793 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
794 return (EINVAL);
795 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
796 error = copyin(p->image, image, icount);
797 if (error)
798 return error;
799 error = copyin(p->mask, mask, icount);
800 if (error)
801 return error;
802 }
803
804 s = spltty();
805 if (v & WSDISPLAY_CURSOR_DOCUR)
806 sc->sc_curenb = p->enable;
807 if (v & WSDISPLAY_CURSOR_DOPOS)
808 set_curpos(sc, &p->pos);
809 if (v & WSDISPLAY_CURSOR_DOHOT)
810 cc->cc_hot = p->hot;
811 if (v & WSDISPLAY_CURSOR_DOCMAP) {
812 memcpy(&cc->cc_color[index], &r[index], count);
813 memcpy(&cc->cc_color[index + 2], &g[index], count);
814 memcpy(&cc->cc_color[index + 4], &b[index], count);
815 }
816 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
817 cc->cc_size = p->size;
818 memset(cc->cc_image, 0, sizeof cc->cc_image);
819 memcpy(cc->cc_image, image, icount);
820 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
821 memcpy(cc->cc_mask, mask, icount);
822 }
823 sc->sc_changed |= v;
824 splx(s);
825
826 return (0);
827 #undef cc
828 }
829
830 static int
get_cursor(struct tfb_softc * sc,struct wsdisplay_cursor * p)831 get_cursor(struct tfb_softc *sc, struct wsdisplay_cursor *p)
832 {
833 return (EPASSTHROUGH); /* XXX */
834 }
835
836 static void
set_curpos(struct tfb_softc * sc,struct wsdisplay_curpos * curpos)837 set_curpos(struct tfb_softc *sc, struct wsdisplay_curpos *curpos)
838 {
839 struct rasops_info *ri = sc->sc_ri;
840 int x = curpos->x, y = curpos->y;
841
842 if (y < 0)
843 y = 0;
844 else if (y > ri->ri_height)
845 y = ri->ri_height;
846 if (x < 0)
847 x = 0;
848 else if (x > ri->ri_width)
849 x = ri->ri_width;
850 sc->sc_cursor.cc_pos.x = x;
851 sc->sc_cursor.cc_pos.y = y;
852 }
853