xref: /netbsd-src/sys/arch/sparc64/dev/ffb.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: ffb.c,v 1.2 2003/06/11 22:50:12 petrov Exp $	*/
2 /*	$OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $	*/
3 
4 /*
5  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Jason L. Wright
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/conf.h>
41 
42 #include <machine/bus.h>
43 #include <machine/autoconf.h>
44 #include <machine/openfirm.h>
45 
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wscons_raster.h>
49 #include <dev/rasops/rasops.h>
50 
51 #include <sparc64/dev/ffbreg.h>
52 #include <sparc64/dev/ffbvar.h>
53 
54 struct wsscreen_descr ffb_stdscreen = {
55 	"std",
56 	0, 0,	/* will be filled in -- XXX shouldn't, it's global. */
57 	0,
58 	0, 0,
59 	WSSCREEN_REVERSE | WSSCREEN_WSCOLORS
60 };
61 
62 const struct wsscreen_descr *ffb_scrlist[] = {
63 	&ffb_stdscreen,
64 	/* XXX other formats? */
65 };
66 
67 struct wsscreen_list ffb_screenlist = {
68 	sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *),
69 	    ffb_scrlist
70 };
71 
72 int	ffb_ioctl(void *, u_long, caddr_t, int, struct proc *);
73 int	ffb_alloc_screen(void *, const struct wsscreen_descr *, void **,
74 	    int *, int *, long *);
75 void	ffb_free_screen(void *, void *);
76 int	ffb_show_screen(void *, void *, int, void (*cb)(void *, int, int),
77 	    void *);
78 paddr_t ffb_mmap(void *, off_t, int);
79 static int a2int(char *, int);
80 void	ffb_ras_fifo_wait(struct ffb_softc *, int);
81 void	ffb_ras_wait(struct ffb_softc *);
82 void	ffb_ras_init(struct ffb_softc *);
83 void	ffb_ras_copyrows(void *, int, int, int);
84 void	ffb_ras_erasecols(void *, int, int, int, long int);
85 void	ffb_ras_eraserows(void *, int, int, long int);
86 void	ffb_ras_do_cursor(struct rasops_info *);
87 void	ffb_ras_fill(struct ffb_softc *);
88 void	ffb_ras_setfg(struct ffb_softc *, int32_t);
89 
90 struct wsdisplay_accessops ffb_accessops = {
91 	ffb_ioctl,
92 	ffb_mmap,
93 	ffb_alloc_screen,
94 	ffb_free_screen,
95 	ffb_show_screen,
96 	NULL,	/* load font */
97 	NULL,	/* scrollback */
98 	NULL,	/* getchar */
99 	NULL,	/* burner */
100 };
101 
102 void
103 ffb_attach(struct ffb_softc *sc)
104 {
105 	struct wsemuldisplaydev_attach_args waa;
106 	char *model;
107 	int btype;
108 
109 	printf(":");
110 
111 	if (sc->sc_type == FFB_CREATOR) {
112 		btype = PROM_getpropint(sc->sc_node, "board_type", 0);
113 		if ((btype & 7) == 3)
114 			printf(" Creator3D");
115 		else
116 			printf(" Creator");
117 	} else
118 		printf(" Elite3D");
119 
120 	model = PROM_getpropstring(sc->sc_node, "model");
121 	if (model == NULL || strlen(model) == 0)
122 		model = "unknown";
123 
124 	printf(", model %s\n", model);
125 
126 	sc->sc_depth = 24;
127 	sc->sc_linebytes = 8192;
128 	sc->sc_height = PROM_getpropint(sc->sc_node, "height", 0);
129 	sc->sc_width = PROM_getpropint(sc->sc_node, "width", 0);
130 
131 	sc->sc_rasops.ri_depth = 32;
132 	sc->sc_rasops.ri_stride = sc->sc_linebytes;
133 	sc->sc_rasops.ri_flg = RI_CENTER;
134 	sc->sc_rasops.ri_bits = (void *)bus_space_vaddr(sc->sc_bt,
135 	    sc->sc_pixel_h);
136 
137 	sc->sc_rasops.ri_width = sc->sc_width;
138 	sc->sc_rasops.ri_height = sc->sc_height;
139 	sc->sc_rasops.ri_hw = sc;
140 
141 	rasops_init(&sc->sc_rasops,
142 	    a2int(PROM_getpropstring(optionsnode, "screen-#rows"), 34),
143 	    a2int(PROM_getpropstring(optionsnode, "screen-#columns"), 80));
144 
145 	if ((sc->sc_dv.dv_cfdata->cf_flags & FFB_CFFLAG_NOACCEL) == 0) {
146 		sc->sc_rasops.ri_hw = sc;
147 		sc->sc_rasops.ri_ops.eraserows = ffb_ras_eraserows;
148 		sc->sc_rasops.ri_ops.erasecols = ffb_ras_erasecols;
149 		sc->sc_rasops.ri_ops.copyrows = ffb_ras_copyrows;
150 		ffb_ras_init(sc);
151 	}
152 
153 	ffb_stdscreen.nrows = sc->sc_rasops.ri_rows;
154 	ffb_stdscreen.ncols = sc->sc_rasops.ri_cols;
155 	ffb_stdscreen.textops = &sc->sc_rasops.ri_ops;
156 
157 	if (sc->sc_console) {
158 		int *ccolp, *crowp;
159 		long defattr;
160 
161 		if (romgetcursoraddr(&crowp, &ccolp))
162 			ccolp = crowp = NULL;
163 		if (ccolp != NULL)
164 			sc->sc_rasops.ri_ccol = *ccolp;
165 		if (crowp != NULL)
166 			sc->sc_rasops.ri_crow = *crowp;
167 
168 		sc->sc_rasops.ri_ops.allocattr(&sc->sc_rasops,
169 		    0, 0, 0, &defattr);
170 
171 		wsdisplay_cnattach(&ffb_stdscreen, &sc->sc_rasops,
172 		    sc->sc_rasops.ri_ccol, sc->sc_rasops.ri_crow, defattr);
173 	}
174 
175 	waa.console = sc->sc_console;
176 	waa.scrdata = &ffb_screenlist;
177 	waa.accessops = &ffb_accessops;
178 	waa.accesscookie = sc;
179 	config_found(&sc->sc_dv, &waa, wsemuldisplaydevprint);
180 }
181 
182 int
183 ffb_ioctl(v, cmd, data, flags, p)
184 	void *v;
185 	u_long cmd;
186 	caddr_t data;
187 	int flags;
188 	struct proc *p;
189 {
190 	struct ffb_softc *sc = v;
191 	struct wsdisplay_fbinfo *wdf;
192 
193 #ifdef FFBDEBUG
194 	printf("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n",
195 	       sc->sc_dv.dv_xname,
196 	       (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "",
197 	       (char)IOCGROUP(cmd), cmd & 0xff);
198 #endif
199 
200 	switch (cmd) {
201 	case WSDISPLAYIO_GTYPE:
202 		*(u_int *)data = WSDISPLAY_TYPE_SUN24;
203 		break;
204 	case WSDISPLAYIO_SMODE:
205 		sc->sc_mode = *(u_int *)data;
206 		break;
207 	case WSDISPLAYIO_GINFO:
208 		wdf = (void *)data;
209 		wdf->height = sc->sc_height;
210 		wdf->width  = sc->sc_width;
211 		wdf->depth  = 32;
212 		wdf->cmsize = 256; /* XXX */
213 		break;
214 #ifdef WSDISPLAYIO_LINEBYTES
215 	case WSDISPLAYIO_LINEBYTES:
216 		*(u_int *)data = sc->sc_linebytes;
217 		break;
218 #endif
219 	case WSDISPLAYIO_GETCMAP:
220 		break;/* XXX */
221 
222 	case WSDISPLAYIO_PUTCMAP:
223 		break;/* XXX */
224 
225 	case WSDISPLAYIO_SVIDEO:
226 	case WSDISPLAYIO_GVIDEO:
227 	case WSDISPLAYIO_GCURPOS:
228 	case WSDISPLAYIO_SCURPOS:
229 	case WSDISPLAYIO_GCURMAX:
230 	case WSDISPLAYIO_GCURSOR:
231 	case WSDISPLAYIO_SCURSOR:
232 	default:
233 		return -1; /* not supported yet */
234         }
235 
236 	return (0);
237 }
238 
239 int
240 ffb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
241 	void *v;
242 	const struct wsscreen_descr *type;
243 	void **cookiep;
244 	int *curxp, *curyp;
245 	long *attrp;
246 {
247 	struct ffb_softc *sc = v;
248 
249 	if (sc->sc_nscreens > 0)
250 		return (ENOMEM);
251 
252 	*cookiep = &sc->sc_rasops;
253 	*curyp = 0;
254 	*curxp = 0;
255 
256 	sc->sc_rasops.ri_ops.allocattr(&sc->sc_rasops, 0, 0, 0, attrp);
257 
258 	sc->sc_nscreens++;
259 	return (0);
260 }
261 
262 void
263 ffb_free_screen(v, cookie)
264 	void *v;
265 	void *cookie;
266 {
267 	struct ffb_softc *sc = v;
268 
269 	sc->sc_nscreens--;
270 }
271 
272 int
273 ffb_show_screen(v, cookie, waitok, cb, cbarg)
274 	void *v;
275 	void *cookie;
276 	int waitok;
277 	void (*cb)(void *, int, int);
278 	void *cbarg;
279 {
280 	return (0);
281 }
282 
283 paddr_t
284 ffb_mmap(vsc, off, prot)
285 	void *vsc;
286 	off_t off;
287 	int prot;
288 {
289 	struct ffb_softc *sc = vsc;
290 	int i;
291 
292 	switch (sc->sc_mode) {
293 	case WSDISPLAYIO_MODE_MAPPED:
294 		for (i = 0; i < sc->sc_nreg; i++) {
295 			/* Before this set? */
296 			if (off < sc->sc_addrs[i])
297 				continue;
298 			/* After this set? */
299 			if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i]))
300 				continue;
301 
302 			return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i],
303 			    off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR));
304 		}
305 		break;
306 #ifdef WSDISPLAYIO_MODE_DUMBFB
307 	case WSDISPLAYIO_MODE_DUMBFB:
308 		if (sc->sc_nreg < FFB_REG_DFB24)
309 			break;
310 		if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24])
311 			return (bus_space_mmap(sc->sc_bt,
312 			    sc->sc_addrs[FFB_REG_DFB24], off, prot,
313 			    BUS_SPACE_MAP_LINEAR));
314 		break;
315 #endif
316 	}
317 
318 	return (-1);
319 }
320 
321 static int
322 a2int(char *cp, int deflt)
323 {
324 	int i = 0;
325 
326 	if (*cp == '\0')
327 		return (deflt);
328 	while (*cp != '\0')
329 		i = i * 10 + *cp++ - '0';
330 	return (i);
331 }
332 
333 void
334 ffb_ras_fifo_wait(sc, n)
335 	struct ffb_softc *sc;
336 	int n;
337 {
338 	int32_t cache = sc->sc_fifo_cache;
339 
340 	if (cache < n) {
341 		do {
342 			cache = FBC_READ(sc, FFB_FBC_UCSR);
343 			cache = (cache & FBC_UCSR_FIFO_MASK) - 8;
344 		} while (cache < n);
345 	}
346 	sc->sc_fifo_cache = cache - n;
347 }
348 
349 void
350 ffb_ras_wait(sc)
351 	struct ffb_softc *sc;
352 {
353 	u_int32_t ucsr, r;
354 
355 	while (1) {
356 		ucsr = FBC_READ(sc, FFB_FBC_UCSR);
357 		if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0)
358 			break;
359 		r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL);
360 		if (r != 0)
361 			FBC_WRITE(sc, FFB_FBC_UCSR, r);
362 	}
363 }
364 
365 void
366 ffb_ras_init(sc)
367 	struct ffb_softc *sc;
368 {
369 	ffb_ras_fifo_wait(sc, 7);
370 	FBC_WRITE(sc, FFB_FBC_PPC,
371 	    FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE |
372 	    FBC_PPC_APE_DIS | FBC_PPC_CS_CONST);
373 	FBC_WRITE(sc, FFB_FBC_FBC,
374 	    FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH |
375 	    FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK);
376 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
377 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
378 	FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff);
379 	FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000);
380 	sc->sc_fg_cache = 0;
381 	FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache);
382 	ffb_ras_wait(sc);
383 }
384 
385 void
386 ffb_ras_eraserows(cookie, row, n, attr)
387 	void *cookie;
388 	int row, n;
389 	long int attr;
390 {
391 	struct rasops_info *ri = cookie;
392 	struct ffb_softc *sc = ri->ri_hw;
393 
394 	if (row < 0) {
395 		n += row;
396 		row = 0;
397 	}
398 	if (row + n > ri->ri_rows)
399 		n = ri->ri_rows - row;
400 	if (n <= 0)
401 		return;
402 
403 	ffb_ras_fill(sc);
404 	ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
405 	ffb_ras_fifo_wait(sc, 4);
406 	if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) {
407 		FBC_WRITE(sc, FFB_FBC_BY, 0);
408 		FBC_WRITE(sc, FFB_FBC_BX, 0);
409 		FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height);
410 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width);
411 	} else {
412 		row *= ri->ri_font->fontheight;
413 		FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
414 		FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
415 		FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight);
416 		FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
417 	}
418 	ffb_ras_wait(sc);
419 }
420 
421 void
422 ffb_ras_erasecols(cookie, row, col, n, attr)
423 	void *cookie;
424 	int row, col, n;
425 	long int attr;
426 {
427 	struct rasops_info *ri = cookie;
428 	struct ffb_softc *sc = ri->ri_hw;
429 
430 	if ((row < 0) || (row >= ri->ri_rows))
431 		return;
432 	if (col < 0) {
433 		n += col;
434 		col = 0;
435 	}
436 	if (col + n > ri->ri_cols)
437 		n = ri->ri_cols - col;
438 	if (n <= 0)
439 		return;
440 	n *= ri->ri_font->fontwidth;
441 	col *= ri->ri_font->fontwidth;
442 	row *= ri->ri_font->fontheight;
443 
444 	ffb_ras_fill(sc);
445 	ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]);
446 	ffb_ras_fifo_wait(sc, 4);
447 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row);
448 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col);
449 	FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight);
450 	FBC_WRITE(sc, FFB_FBC_BW, n - 1);
451 	ffb_ras_wait(sc);
452 }
453 
454 void
455 ffb_ras_fill(sc)
456 	struct ffb_softc *sc;
457 {
458 	ffb_ras_fifo_wait(sc, 2);
459 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW);
460 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
461 	ffb_ras_wait(sc);
462 }
463 
464 void
465 ffb_ras_copyrows(cookie, src, dst, n)
466 	void *cookie;
467 	int src, dst, n;
468 {
469 	struct rasops_info *ri = cookie;
470 	struct ffb_softc *sc = ri->ri_hw;
471 
472 	if (dst == src)
473 		return;
474 	if (src < 0) {
475 		n += src;
476 		src = 0;
477 	}
478 	if ((src + n) > ri->ri_rows)
479 		n = ri->ri_rows - src;
480 	if (dst < 0) {
481 		n += dst;
482 		dst = 0;
483 	}
484 	if ((dst + n) > ri->ri_rows)
485 		n = ri->ri_rows - dst;
486 	if (n <= 0)
487 		return;
488 	n *= ri->ri_font->fontheight;
489 	src *= ri->ri_font->fontheight;
490 	dst *= ri->ri_font->fontheight;
491 
492 	ffb_ras_fifo_wait(sc, 8);
493 	FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8));
494 	FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL);
495 	FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src);
496 	FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin);
497 	FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst);
498 	FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin);
499 	FBC_WRITE(sc, FFB_FBC_BH, n);
500 	FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth);
501 	ffb_ras_wait(sc);
502 }
503 
504 void
505 ffb_ras_setfg(sc, fg)
506 	struct ffb_softc *sc;
507 	int32_t fg;
508 {
509 	ffb_ras_fifo_wait(sc, 1);
510 	if (fg == sc->sc_fg_cache)
511 		return;
512 	sc->sc_fg_cache = fg;
513 	FBC_WRITE(sc, FFB_FBC_FG, fg);
514 	ffb_ras_wait(sc);
515 }
516