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