1 /*	$OpenBSD: fb.c,v 1.43 2006/12/03 22:10:30 miod Exp $	*/
2 /*	$NetBSD: fb.c,v 1.23 1997/07/07 23:30:22 pk Exp $ */
3 
4 /*
5  * Copyright (c) 2002, 2004  Miodrag Vallat.
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  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  *
30  * Copyright (c) 1992, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * This software was developed by the Computer Systems Engineering group
34  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
35  * contributed to Berkeley.
36  *
37  * All advertising materials mentioning features or use of this software
38  * must display the following acknowledgement:
39  *	This product includes software developed by the University of
40  *	California, Lawrence Berkeley Laboratory.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  *	@(#)fb.c	8.1 (Berkeley) 6/11/93
67  */
68 
69 /*
70  * Common wsdisplay framebuffer drivers helpers.
71  */
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/device.h>
76 #include <sys/proc.h>
77 #include <sys/conf.h>
78 
79 #include <machine/autoconf.h>
80 #include <machine/conf.h>
81 #if defined(SUN4)
82 #include <machine/eeprom.h>
83 #include <sparc/dev/pfourreg.h>
84 #endif
85 
86 #include <dev/wscons/wsdisplayvar.h>
87 #include <dev/rasops/rasops.h>
88 #include <machine/fbvar.h>
89 
90 #include "wsdisplay.h"
91 
92 /*
93  * emergency unblank code
94  * XXX should be somewhat moved to wscons MI code
95  */
96 
97 void (*fb_burner)(void *, u_int, u_int);
98 void *fb_cookie;
99 
100 void
fb_unblank()101 fb_unblank()
102 {
103 	if (fb_burner != NULL)
104 		(*fb_burner)(fb_cookie, 1, 0);
105 }
106 
107 #if NWSDISPLAY > 0
108 
109 #if defined(SUN4C) || defined(SUN4M)
110 static int a2int(char *, int);
111 #endif
112 static void fb_initwsd(struct sunfb *);
113 static void fb_updatecursor(struct rasops_info *);
114 int	fb_alloc_screen(void *, const struct wsscreen_descr *, void **,
115 	    int *, int *, long *);
116 void	fb_free_screen(void *, void *);
117 int	fb_show_screen(void *, void *, int, void (*)(void *, int, int),
118 	    void *);
119 
120 void
fb_setsize(struct sunfb * sf,int def_depth,int def_width,int def_height,int node,int bustype)121 fb_setsize(struct sunfb *sf, int def_depth, int def_width, int def_height,
122     int node, int bustype)
123 {
124 	int def_linebytes;
125 
126 	switch (bustype) {
127 	case BUS_VME16:
128 	case BUS_VME32:
129 	case BUS_OBIO:
130 #if defined(SUN4M)
131 		/* 4m may have SBus-like framebuffer on obio */
132 		if (CPU_ISSUN4M) {
133 			goto obpsize;
134 		}
135 #endif
136 		/* Set up some defaults. */
137 		sf->sf_width = def_width;
138 		sf->sf_height = def_height;
139 		sf->sf_depth = def_depth;
140 
141 #if defined(SUN4)
142 		/*
143 		 * This is not particularly useful on Sun 4 VME framebuffers.
144 		 * The EEPROM only contains info about the built-in.
145 		 */
146 		if (CPU_ISSUN4 && bustype == BUS_OBIO) {
147 			struct eeprom *eep = (struct eeprom *)eeprom_va;
148 
149 			if (ISSET(sf->sf_flags, FB_PFOUR)) {
150 				volatile u_int32_t pfour;
151 				u_int size;
152 
153 				pfour = *sf->sf_pfour;
154 
155 				/*
156 				 * Use the pfour register to determine
157 				 * the size.  Note that the cgsix and
158 				 * cgeight don't use this size encoding.
159 				 * In this case, we have to settle
160 				 * for the defaults we were provided
161 				 * with.
162 				 */
163 				if ((PFOUR_ID(pfour) == PFOUR_ID_COLOR24) ||
164 				    (PFOUR_ID(pfour) == PFOUR_ID_FASTCOLOR))
165 					size = 0x00; /* invalid */
166 				else
167 					size = PFOUR_SIZE(pfour);
168 
169 				switch (size) {
170 				case PFOUR_SIZE_1152X900:
171 					sf->sf_width = 1152;
172 					sf->sf_height = 900;
173 					break;
174 				case PFOUR_SIZE_1024X1024:
175 					sf->sf_width = 1024;
176 					sf->sf_height = 1024;
177 					break;
178 				case PFOUR_SIZE_1280X1024:
179 					sf->sf_width = 1280;
180 					sf->sf_height = 1024;
181 					break;
182 				case PFOUR_SIZE_1600X1280:
183 					sf->sf_width = 1600;
184 					sf->sf_height = 1280;
185 					break;
186 				case PFOUR_SIZE_1440X1440:
187 					sf->sf_width = 1440;
188 					sf->sf_height = 1440;
189 					break;
190 				case PFOUR_SIZE_640X480:
191 					sf->sf_width = 640;
192 					sf->sf_height = 480;
193 					break;
194 				}
195 			} else if (eep != NULL) {
196 				switch (eep->eeScreenSize) {
197 				case EE_SCR_1152X900:
198 					sf->sf_width = 1152;
199 					sf->sf_height = 900;
200 					break;
201 				case EE_SCR_1024X1024:
202 					sf->sf_width = 1024;
203 					sf->sf_height = 1024;
204 					break;
205 				case EE_SCR_1600X1280:
206 					sf->sf_width = 1600;
207 					sf->sf_height = 1280;
208 					break;
209 				case EE_SCR_1440X1440:
210 					sf->sf_width = 1440;
211 					sf->sf_height = 1440;
212 					break;
213 				}
214 			}
215 		}
216 #endif /* SUN4 */
217 #if defined(SUN4M)
218 		if (CPU_ISSUN4M) {
219 			/* XXX: need code to find 4/600 vme screen size */
220 		}
221 #endif /* SUN4M */
222 
223 		sf->sf_linebytes = (sf->sf_width * sf->sf_depth) / 8;
224 		break;
225 
226 	case BUS_SBUS:
227 #if defined(SUN4M)
228 obpsize:
229 #endif
230 		sf->sf_depth = getpropint(node, "depth", def_depth);
231 		sf->sf_width = getpropint(node, "width", def_width);
232 		sf->sf_height = getpropint(node, "height", def_height);
233 
234 		def_linebytes =
235 		    roundup(sf->sf_width, sf->sf_depth) * sf->sf_depth / 8;
236 		sf->sf_linebytes = getpropint(node, "linebytes", def_linebytes);
237 
238 		/*
239 		 * XXX If we are configuring a board in a wider depth level
240 		 * than the mode it is currently operating in, the PROM will
241 		 * return a linebytes property tied to the current depth value,
242 		 * which is NOT what we are relying upon!
243 		 */
244 		if (sf->sf_linebytes < (sf->sf_width * sf->sf_depth) / 8)
245 			sf->sf_linebytes = def_linebytes;
246 
247 		break;
248 	}
249 
250 	sf->sf_fbsize = sf->sf_height * sf->sf_linebytes;
251 }
252 
253 #if defined(SUN4C) || defined(SUN4M)
254 static int
a2int(char * cp,int deflt)255 a2int(char *cp, int deflt)
256 {
257 	int i = 0;
258 
259 	if (*cp == '\0')
260 		return (deflt);
261 	while (*cp != '\0')
262 		i = i * 10 + *cp++ - '0';
263 	return (i);
264 }
265 #endif
266 
267 /* setup the embedded wsscreen_descr structure from rasops settings */
268 static void
fb_initwsd(struct sunfb * sf)269 fb_initwsd(struct sunfb *sf)
270 {
271 	strlcpy(sf->sf_wsd.name, "std", sizeof(sf->sf_wsd.name));
272 	sf->sf_wsd.capabilities = sf->sf_ro.ri_caps;
273 	sf->sf_wsd.nrows = sf->sf_ro.ri_rows;
274 	sf->sf_wsd.ncols = sf->sf_ro.ri_cols;
275 	sf->sf_wsd.textops = &sf->sf_ro.ri_ops;
276 }
277 
278 static void
fb_updatecursor(struct rasops_info * ri)279 fb_updatecursor(struct rasops_info *ri)
280 {
281 	struct sunfb *sf = (struct sunfb *)ri->ri_hw;
282 
283 	if (sf->sf_crowp != NULL)
284 		*sf->sf_crowp = ri->ri_crow;
285 	if (sf->sf_ccolp != NULL)
286 		*sf->sf_ccolp = ri->ri_ccol;
287 }
288 
289 void
fbwscons_init(struct sunfb * sf,int flags)290 fbwscons_init(struct sunfb *sf, int flags)
291 {
292 	struct rasops_info *ri = &sf->sf_ro;
293 	int cols, rows;
294 
295 	/* ri_hw and ri_bits must have already been setup by caller */
296 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR | flags;
297 	ri->ri_depth = sf->sf_depth;
298 	ri->ri_stride = sf->sf_linebytes;
299 	ri->ri_width = sf->sf_width;
300 	ri->ri_height = sf->sf_height;
301 
302 #if defined(SUN4C) || defined(SUN4M)
303 	if (CPU_ISSUN4COR4M) {
304 		rows = a2int(getpropstring(optionsnode, "screen-#rows"), 34);
305 		cols = a2int(getpropstring(optionsnode, "screen-#columns"), 80);
306 	}
307 #endif
308 #if defined(SUN4)
309 	if (CPU_ISSUN4) {
310 		struct eeprom *ep = (struct eeprom *)eeprom_va;
311 
312 		if (ep != NULL) {
313 			rows = (u_short)ep->eeTtyRows;
314 			cols = (u_short)ep->eeTtyCols;
315 			/* deal with broken nvram contents... */
316 			if (rows <= 0)
317 				rows = 34;
318 			if (cols <= 0)
319 				cols = 80;
320 		} else {
321 			rows = 34;
322 			cols = 80;
323 		}
324 	}
325 #endif
326 
327 	rasops_init(ri, rows, cols);
328 }
329 
330 void
fbwscons_console_init(struct sunfb * sf,int row)331 fbwscons_console_init(struct sunfb *sf, int row)
332 {
333 	struct rasops_info *ri = &sf->sf_ro;
334 	long defattr;
335 
336 	if (CPU_ISSUN4 || romgetcursoraddr(&sf->sf_crowp, &sf->sf_ccolp))
337 		sf->sf_ccolp = sf->sf_crowp = NULL;
338 	if (sf->sf_ccolp != NULL)
339 		ri->ri_ccol = *sf->sf_ccolp;
340 
341 	if (row < 0) {
342 		if (sf->sf_crowp != NULL)
343 			ri->ri_crow = *sf->sf_crowp;
344 		else
345 			/* assume last row */
346 			ri->ri_crow = ri->ri_rows - 1;
347 	} else {
348 		/*
349 		 * If we force the display row, this is because the screen
350 		 * has been cleared or the font has been changed.
351 		 * In this case, choose not to keep pointers to the PROM
352 		 * cursor position, as the values are likely to be inaccurate
353 		 * upon shutdown...
354 		 */
355 		sf->sf_crowp = sf->sf_ccolp = NULL;
356 		ri->ri_crow = row;
357 	}
358 
359 	/*
360 	 * Scale back rows and columns if the font would not otherwise
361 	 * fit on this display. Without this we would panic later.
362 	 */
363 	if (ri->ri_crow >= ri->ri_rows)
364 		ri->ri_crow = ri->ri_rows - 1;
365 	if (ri->ri_ccol >= ri->ri_cols)
366 		ri->ri_ccol = ri->ri_cols - 1;
367 
368 	/*
369 	 * Take care of updating the PROM cursor position as well if we can.
370 	 */
371 	if (ri->ri_updatecursor == NULL &&
372 	    (sf->sf_ccolp != NULL || sf->sf_crowp != NULL))
373 		ri->ri_updatecursor = fb_updatecursor;
374 
375 	if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
376 		ri->ri_ops.alloc_attr(ri,
377 		    WSCOL_WHITE, WSCOL_BLACK, WSATTR_WSCOLORS, &defattr);
378 	else
379 		ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
380 
381 	fb_initwsd(sf);
382 	wsdisplay_cnattach(&sf->sf_wsd, ri,
383 	    ri->ri_ccol, ri->ri_crow, defattr);
384 }
385 
386 void
fbwscons_setcolormap(struct sunfb * sf,void (* setcolor)(void *,u_int,u_int8_t,u_int8_t,u_int8_t))387 fbwscons_setcolormap(struct sunfb *sf,
388     void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
389 {
390 	int i;
391 	const u_char *color;
392 
393 	if (sf->sf_depth <= 8 && setcolor != NULL) {
394 		for (i = 0; i < 16; i++) {
395 			color = &rasops_cmap[i * 3];
396 			setcolor(sf, i, color[0], color[1], color[2]);
397 		}
398 		for (i = 240; i < 256; i++) {
399 			color = &rasops_cmap[i * 3];
400 			setcolor(sf, i, color[0], color[1], color[2]);
401 		}
402 	}
403 }
404 
405 void
fbwscons_attach(struct sunfb * sf,struct wsdisplay_accessops * op,int isconsole)406 fbwscons_attach(struct sunfb *sf, struct wsdisplay_accessops *op, int isconsole)
407 {
408 	struct wsemuldisplaydev_attach_args waa;
409 
410 	if (isconsole == 0) {
411 		/* done in wsdisplay_cnattach() earlier if console */
412 		fb_initwsd(sf);
413 	} else {
414 		/* remember screen burner routine */
415 		fb_burner = op->burn_screen;
416 		fb_cookie = sf;
417 	}
418 
419 	/* plug common wsdisplay_accessops if necessary */
420 	if (op->alloc_screen == NULL) {
421 		op->alloc_screen = fb_alloc_screen;
422 		op->free_screen = fb_free_screen;
423 		op->show_screen = fb_show_screen;
424 	}
425 
426 	sf->sf_scrlist[0] = &sf->sf_wsd;
427 	sf->sf_wsl.nscreens = 1;
428 	sf->sf_wsl.screens = (const struct wsscreen_descr **)sf->sf_scrlist;
429 
430 	waa.console = isconsole;
431 	waa.scrdata = &sf->sf_wsl;
432 	waa.accessops = op;
433 	waa.accesscookie = sf;
434 	waa.defaultscreens = 0;
435 	config_found(&sf->sf_dev, &waa, wsemuldisplaydevprint);
436 }
437 
438 /*
439  * Common wsdisplay_accessops routines.
440  */
441 int
fb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)442 fb_alloc_screen(void *v, const struct wsscreen_descr *type,
443     void **cookiep, int *curxp, int *curyp, long *attrp)
444 {
445 	struct sunfb *sf = v;
446 	struct rasops_info *ri = &sf->sf_ro;
447 
448 	if (sf->sf_nscreens > 0)
449 		return (ENOMEM);
450 
451 	*cookiep = ri;
452 	*curyp = 0;
453 	*curxp = 0;
454 	if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
455 		ri->ri_ops.alloc_attr(ri,
456 		    WSCOL_WHITE, WSCOL_BLACK, WSATTR_WSCOLORS, attrp);
457 	else
458 		ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
459 	sf->sf_nscreens++;
460 	return (0);
461 }
462 
463 void
fb_free_screen(void * v,void * cookie)464 fb_free_screen(void *v, void *cookie)
465 {
466 	struct sunfb *sf = v;
467 
468 	sf->sf_nscreens--;
469 }
470 
471 int
fb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)472 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
473     void *cbarg)
474 {
475 	return (0);
476 }
477 
478 #if defined(SUN4)
479 
480 /*
481  * Support routines for P4 framebuffers.
482  */
483 
484 /*
485  * Probe for a P4 framebuffer.  Return values:
486  *	PFOUR_NOTPFOUR		framebuffer is not a P4 framebuffer
487  *	otherwise returns P4 ID
488  */
489 int
fb_pfour_id(void * va)490 fb_pfour_id(void *va)
491 {
492 	volatile u_int32_t val, save, *pfour = va;
493 
494 	/* Read the pfour register. */
495 	save = *pfour;
496 
497 	/*
498 	 * Try to modify the type code.  If it changes, put the
499 	 * original value back, and notify the caller that it's
500 	 * not a pfour framebuffer.
501 	 */
502 	val = save & ~PFOUR_REG_RESET;
503 	*pfour = (val ^ PFOUR_FBTYPE_MASK);
504 	if ((*pfour ^ val) & PFOUR_FBTYPE_MASK) {
505 		*pfour = save;
506 		return (PFOUR_NOTPFOUR);
507 	}
508 
509 	return (PFOUR_ID(val));
510 }
511 
512 /*
513  * Screen burner routine for P4
514  */
515 void
fb_pfour_burner(void * v,u_int enable,u_int flags)516 fb_pfour_burner(void *v, u_int enable, u_int flags)
517 {
518 	struct sunfb *sf = (struct sunfb *)v;
519 	volatile u_int32_t pfour;
520 
521 	pfour = *sf->sf_pfour & ~(PFOUR_REG_INTCLR | PFOUR_REG_VIDEO);
522 	*sf->sf_pfour = pfour | (enable ? PFOUR_REG_VIDEO : 0);
523 }
524 
525 #endif /* SUN4 */
526 
527 #endif	/* NWSDISPLAY */
528