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