xref: /openbsd/sys/arch/sparc64/dev/fb.c (revision 9593dc34)
1 /*	$OpenBSD: fb.c,v 1.31 2024/09/04 07:54:52 mglocker Exp $	*/
2 /*	$NetBSD: fb.c,v 1.23 1997/07/07 23:30:22 pk Exp $ */
3 
4 /*
5  * Copyright (c) 2002, 2004, 2008  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 #include <machine/openfirm.h>
82 
83 #include <dev/wscons/wsdisplayvar.h>
84 #include <dev/rasops/rasops.h>
85 #include <machine/fbvar.h>
86 
87 #include "wsdisplay.h"
88 
89 /*
90  * Sun specific color indexes.
91  * Black is not really 7, but rather ~0; to fit within the 8 ANSI color
92  * palette we are using on console, we pick (~0) & 0x07 instead.
93  * This essentially swaps WSCOL_BLACK and WSCOL_WHITE.
94  */
95 #define	WSCOL_SUN_WHITE		0
96 #define	WSCOL_SUN_BLACK		7
97 
98 /*
99  * emergency unblank code
100  * XXX should be somewhat moved to wscons MI code
101  */
102 
103 void (*fb_burner)(void *, u_int, u_int);
104 void *fb_cookie;
105 
106 void
fb_unblank(void)107 fb_unblank(void)
108 {
109 	if (fb_burner != NULL)
110 		(*fb_burner)(fb_cookie, 1, 0);
111 }
112 
113 #if NWSDISPLAY > 0
114 
115 static int a2int(char *, int);
116 int	fb_get_console_metrics(int *, int *, int *, int *);
117 void	fb_initwsd(struct sunfb *);
118 void	fb_updatecursor(struct rasops_info *);
119 
120 int	fb_alloc_screen(void *, const struct wsscreen_descr *, void **,
121 	    int *, int *, uint32_t *);
122 void	fb_free_screen(void *, void *);
123 int	fb_show_screen(void *, void *, int, void (*)(void *, int, int),
124 	    void *);
125 int	fb_load_font(void *, void *, struct wsdisplay_font *);
126 int	fb_list_font(void *, struct wsdisplay_font *);
127 
128 void
fb_setsize(struct sunfb * sf,int def_depth,int def_width,int def_height,int node,int unused)129 fb_setsize(struct sunfb *sf, int def_depth, int def_width, int def_height,
130     int node, int unused)
131 {
132 	int def_linebytes;
133 
134 	/*
135 	 * Some PCI devices lack the `depth' property, but have a `depth '
136 	 * property (with a trailing space) instead.
137 	 */
138 	sf->sf_depth = getpropint(node, "depth",
139 	    getpropint(node, "depth ", def_depth));
140 	sf->sf_width = getpropint(node, "width", def_width);
141 	sf->sf_height = getpropint(node, "height", def_height);
142 
143 	def_linebytes =
144 	    roundup(sf->sf_width, sf->sf_depth) * sf->sf_depth / 8;
145 	sf->sf_linebytes = getpropint(node, "linebytes", def_linebytes);
146 
147 	/*
148 	 * XXX If we are configuring a board in a wider depth level
149 	 * than the mode it is currently operating in, the PROM will
150 	 * return a linebytes property tied to the current depth value,
151 	 * which is NOT what we are relying upon!
152 	 */
153 	if (sf->sf_linebytes < (sf->sf_width * sf->sf_depth) / 8)
154 		sf->sf_linebytes = def_linebytes;
155 
156 	sf->sf_fbsize = sf->sf_height * sf->sf_linebytes;
157 }
158 
159 static int
a2int(char * cp,int deflt)160 a2int(char *cp, int deflt)
161 {
162 	int i = 0;
163 
164 	if (*cp == '\0')
165 		return (deflt);
166 	while (*cp != '\0')
167 		i = i * 10 + *cp++ - '0';
168 	return (i);
169 }
170 
171 /* setup the embedded wsscreen_descr structure from rasops settings */
172 void
fb_initwsd(struct sunfb * sf)173 fb_initwsd(struct sunfb *sf)
174 {
175 	strlcpy(sf->sf_wsd.name, "std", sizeof(sf->sf_wsd.name));
176 	sf->sf_wsd.capabilities = sf->sf_ro.ri_caps;
177 	sf->sf_wsd.nrows = sf->sf_ro.ri_rows;
178 	sf->sf_wsd.ncols = sf->sf_ro.ri_cols;
179 	sf->sf_wsd.textops = &sf->sf_ro.ri_ops;
180 }
181 
182 void
fb_updatecursor(struct rasops_info * ri)183 fb_updatecursor(struct rasops_info *ri)
184 {
185 	struct sunfb *sf = (struct sunfb *)ri->ri_hw;
186 
187 	if (sf->sf_crowp != NULL)
188 		*sf->sf_crowp = ri->ri_crow;
189 	if (sf->sf_ccolp != NULL)
190 		*sf->sf_ccolp = ri->ri_ccol;
191 }
192 
193 void
fbwscons_init(struct sunfb * sf,int flags,int isconsole)194 fbwscons_init(struct sunfb *sf, int flags, int isconsole)
195 {
196 	struct rasops_info *ri = &sf->sf_ro;
197 	int cols, rows, fw, fh, wt, wl;
198 
199 	/* ri_hw and ri_bits must have already been setup by caller */
200 	ri->ri_flg = RI_FULLCLEAR | flags;
201 	ri->ri_depth = sf->sf_depth;
202 	ri->ri_stride = sf->sf_linebytes;
203 	ri->ri_width = sf->sf_width;
204 	ri->ri_height = sf->sf_height;
205 
206 	rows = a2int(getpropstring(optionsnode, "screen-#rows"), 34);
207 	cols = a2int(getpropstring(optionsnode, "screen-#columns"), 80);
208 
209 	/*
210 	 * If the framebuffer width is under 960 pixels, rasops will
211 	 * switch from the 12x22 font to the more adequate 8x16 font
212 	 * here.
213 	 * If we are the console device, we need to adjust two things:
214 	 * - the display row should be overridden from the current PROM
215 	 *   metrics, since it will not match the PROM reality anymore.
216 	 * - the screen needs to be cleared.
217 	 *
218 	 * However, to accommodate laptops with specific small fonts,
219 	 * it is necessary to compare the resolution with the actual
220 	 * font metrics.
221 	 */
222 
223 	if (isconsole) {
224 		if (fb_get_console_metrics(&fw, &fh, &wt, &wl) != 0) {
225 			/*
226 			 * Assume a 12x22 prom font and a centered
227 			 * 80x34 console window.
228 			 */
229 			fw = 12; fh = 22;
230 			wt = wl = 0;
231 		} else {
232 			/*
233 			 * Make sure window-top and window-left
234 			 * values are consistent with the font metrics.
235 			 */
236 			if (wt <= 0 || wt > sf->sf_height - rows * fh ||
237 			    wl <= 0 || wl > sf->sf_width - cols * fw)
238 				wt = wl = 0;
239 		}
240 		if (wt == 0 /* || wl == 0 */) {
241 			ri->ri_flg |= RI_CENTER;
242 
243 			/*
244 			 * Since the console window might not be
245 			 * centered (e.g. on a 1280x1024 vigra
246 			 * VS-12 frame buffer), have rasops
247 			 * clear the margins even if the screen is
248 			 * not cleared.
249 			 */
250 			ri->ri_flg |= RI_CLEARMARGINS;
251 		}
252 
253 		if (ri->ri_wsfcookie != 0) {
254 			/* driver handles font issues. do nothing. */
255 		} else {
256 			/*
257 			 * If the PROM uses a different font than the
258 			 * one we are expecting it to use, or if the
259 			 * display is shorter than 960 pixels wide,
260 			 * we'll force a screen clear.
261 			 */
262 			if (fw != 12 || sf->sf_width < 12 * 80)
263 				ri->ri_flg |= RI_CLEAR | RI_CENTER;
264 		}
265 	} else {
266 		ri->ri_flg |= RI_CLEAR | RI_CENTER;
267 	}
268 
269 	/* ifb(4) doesn't set ri_bits at the moment */
270 	if (ri->ri_bits == NULL)
271 		ri->ri_flg &= ~(RI_CLEAR | RI_CLEARMARGINS);
272 
273 	rasops_init(ri, rows, cols);
274 
275 	/*
276 	 * If this is the console display and there is no font change,
277 	 * adjust our terminal window to the position of the PROM
278 	 * window - in case it is not exactly centered.
279 	 */
280 	if ((ri->ri_flg & RI_CENTER) == 0) {
281 		/* code above made sure wt and wl are initialized */
282 		ri->ri_bits += wt * ri->ri_stride;
283 		if (ri->ri_depth >= 8)	/* for 15bpp to compute ok */
284 			ri->ri_bits += wl * ri->ri_pelbytes;
285 		else
286 			ri->ri_bits += (wl * ri->ri_depth) >> 3;
287 
288 		ri->ri_xorigin = wl;
289 		ri->ri_yorigin = wt;
290 	}
291 
292 	if (sf->sf_depth == 8) {
293 		/*
294 		 * If we are running with an indexed palette, compensate
295 		 * the swap of black and white through ri_devcmap.
296 		 */
297 		ri->ri_devcmap[WSCOL_SUN_BLACK] = 0;
298 		ri->ri_devcmap[WSCOL_SUN_WHITE] = 0xffffffff;
299 	} else if (sf->sf_depth > 8) {
300 		/*
301 		 * If we are running on a direct color frame buffer,
302 		 * make the ``normal'' white the same as the highlighted
303 		 * white.
304 		 */
305 		ri->ri_devcmap[WSCOL_WHITE] = ri->ri_devcmap[WSCOL_WHITE + 8];
306 	}
307 }
308 
309 void
fbwscons_console_init(struct sunfb * sf,int row)310 fbwscons_console_init(struct sunfb *sf, int row)
311 {
312 	struct rasops_info *ri = &sf->sf_ro;
313 	void *cookie;
314 	uint32_t defattr;
315 
316 	if (romgetcursoraddr(&sf->sf_crowp, &sf->sf_ccolp))
317 		sf->sf_ccolp = sf->sf_crowp = NULL;
318 	if (sf->sf_ccolp != NULL)
319 		ri->ri_ccol = *sf->sf_ccolp;
320 
321 	if (ri->ri_flg & RI_CLEAR) {
322 		/*
323 		 * If we have cleared the screen, this is because either
324 		 * we are not the console display, or the font has been
325 		 * changed.
326 		 * In this case, choose not to keep pointers to the PROM
327 		 * cursor position, as the values are likely to be inaccurate
328 		 * upon shutdown...
329 		 */
330 		sf->sf_crowp = sf->sf_ccolp = NULL;
331 		row = 0;
332 	}
333 
334 	if (row < 0) /* no override */ {
335 		if (sf->sf_crowp != NULL)
336 			ri->ri_crow = *sf->sf_crowp;
337 		else
338 			/* assume last row */
339 			ri->ri_crow = ri->ri_rows - 1;
340 	} else {
341 		ri->ri_crow = row;
342 	}
343 
344 	/*
345 	 * Scale back rows and columns if the font would not otherwise
346 	 * fit on this display. Without this we would panic later.
347 	 */
348 	if (ri->ri_crow >= ri->ri_rows)
349 		ri->ri_crow = ri->ri_rows - 1;
350 	if (ri->ri_ccol >= ri->ri_cols)
351 		ri->ri_ccol = ri->ri_cols - 1;
352 
353 	/*
354 	 * Take care of updating the PROM cursor position as well if we can.
355 	 */
356 	if (ri->ri_updatecursor != NULL &&
357 	    (sf->sf_ccolp != NULL || sf->sf_crowp != NULL))
358 		ri->ri_updatecursor = fb_updatecursor;
359 
360 	if (ri->ri_flg & RI_VCONS)
361 		cookie = ri->ri_active;
362 	else
363 		cookie = ri;
364 
365 	if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
366 		ri->ri_ops.pack_attr(cookie,
367 		    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &defattr);
368 	else
369 		ri->ri_ops.pack_attr(cookie, 0, 0, 0, &defattr);
370 
371 	fb_initwsd(sf);
372 	wsdisplay_cnattach(&sf->sf_wsd, cookie,
373 	    ri->ri_ccol, ri->ri_crow, defattr);
374 }
375 
376 void
fbwscons_setcolormap(struct sunfb * sf,void (* setcolor)(void *,u_int,u_int8_t,u_int8_t,u_int8_t))377 fbwscons_setcolormap(struct sunfb *sf,
378     void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
379 {
380 	int i;
381 	const u_char *color;
382 
383 	if (sf->sf_depth <= 8 && setcolor != NULL) {
384 		for (i = 0; i < 16; i++) {
385 			color = &rasops_cmap[i * 3];
386 			setcolor(sf, i, color[0], color[1], color[2]);
387 		}
388 		for (i = 240; i < 256; i++) {
389 			color = &rasops_cmap[i * 3];
390 			setcolor(sf, i, color[0], color[1], color[2]);
391 		}
392 		/*
393 		 * Compensate for BoW default hardware palette: existing
394 		 * output (which we do not want to affect) is black on
395 		 * white with color index 0 being white and 0xff being
396 		 * black.
397 		 */
398 		setcolor(sf, WSCOL_SUN_WHITE, 0xff, 0xff, 0xff);
399 		setcolor(sf, 0xff ^ WSCOL_SUN_WHITE, 0, 0, 0);
400 		setcolor(sf, WSCOL_SUN_BLACK, 0, 0, 0);
401 		setcolor(sf, 0xff ^ (WSCOL_SUN_BLACK), 0xff, 0xff, 0xff);
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 	if (op->load_font == NULL) {
426 		op->load_font = fb_load_font;
427 		op->list_font = fb_list_font;
428 	}
429 
430 	sf->sf_scrlist[0] = &sf->sf_wsd;
431 	sf->sf_wsl.nscreens = 1;
432 	sf->sf_wsl.screens = (const struct wsscreen_descr **)sf->sf_scrlist;
433 
434 	waa.console = isconsole;
435 	waa.scrdata = &sf->sf_wsl;
436 	waa.accessops = op;
437 	waa.accesscookie = sf;
438 	waa.defaultscreens = 0;
439 	config_found(&sf->sf_dev, &waa, wsemuldisplaydevprint);
440 }
441 
442 /*
443  * Common wsdisplay_accessops routines.
444  */
445 int
fb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,uint32_t * attrp)446 fb_alloc_screen(void *v, const struct wsscreen_descr *type,
447     void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
448 {
449 	struct sunfb *sf = v;
450 	struct rasops_info *ri = &sf->sf_ro;
451 	void *cookie;
452 
453 	if (sf->sf_nscreens > 0)
454 		return (ENOMEM);
455 
456 	if (ri->ri_flg & RI_VCONS)
457 		cookie = ri->ri_active;
458 	else
459 		cookie = ri;
460 
461 	*cookiep = cookie;
462 	*curyp = 0;
463 	*curxp = 0;
464 	if (ISSET(ri->ri_caps, WSSCREEN_WSCOLORS))
465 		ri->ri_ops.pack_attr(cookie,
466 		    WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
467 	else
468 		ri->ri_ops.pack_attr(cookie, 0, 0, 0, attrp);
469 	sf->sf_nscreens++;
470 	return (0);
471 }
472 
473 void
fb_free_screen(void * v,void * cookie)474 fb_free_screen(void *v, void *cookie)
475 {
476 	struct sunfb *sf = v;
477 
478 	sf->sf_nscreens--;
479 }
480 
481 int
fb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)482 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int),
483     void *cbarg)
484 {
485 	return (0);
486 }
487 
488 int
fb_load_font(void * v,void * emulcookie,struct wsdisplay_font * font)489 fb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
490 {
491 	struct sunfb *sf = v;
492 	struct rasops_info *ri = &sf->sf_ro;
493 
494 	return rasops_load_font(ri, emulcookie, font);
495 }
496 
497 int
fb_list_font(void * v,struct wsdisplay_font * font)498 fb_list_font(void *v, struct wsdisplay_font *font)
499 {
500 	struct sunfb *sf = v;
501 	struct rasops_info *ri = &sf->sf_ro;
502 
503 	return rasops_list_font(ri, font);
504 }
505 
506 int
fb_get_console_metrics(int * fontwidth,int * fontheight,int * wtop,int * wleft)507 fb_get_console_metrics(int *fontwidth, int *fontheight, int *wtop, int *wleft)
508 {
509 	cell_t romheight, romwidth, windowtop, windowleft;
510 
511 	/*
512 	 * Get the PROM font metrics and address
513 	 */
514 	OF_interpret("stdout @ is my-self "
515 	    "addr char-height addr char-width "
516 	    "addr window-top addr window-left",
517 	    4, &windowleft, &windowtop, &romwidth, &romheight);
518 
519 	if (romheight == 0 || romwidth == 0 ||
520 	    windowtop == 0 || windowleft == 0)
521 		return (1);
522 
523 	*fontwidth = (int)*(uint64_t *)romwidth;
524 	*fontheight = (int)*(uint64_t *)romheight;
525 	*wtop = (int)*(uint64_t *)windowtop;
526 	*wleft = (int)*(uint64_t *)windowleft;
527 
528 	return (0);
529 }
530 
531 #endif	/* NWSDISPLAY */
532