xref: /netbsd-src/sys/dev/tc/tfb.c (revision ecb9191049815c59afb1757b3285c0609cb4d65b)
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