1 /* $NetBSD: genfb.c,v 1.27 2009/08/20 02:51:27 macallan Exp $ */
4 * Copyright (c) 2007 Michael Lorenz
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.27 2009/08/20 02:51:27 macallan Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
37 #include <sys/mutex.h>
38 #include <sys/ioctl.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/rasops/rasops.h>
46 #include <dev/wsfont/wsfont.h>
48 #include <dev/wscons/wsdisplay_vconsvar.h>
50 #include <dev/wsfb/genfbvar.h>
52 #include "opt_genfb.h"
58 #define GPRINTF aprint_verbose
61 static int genfb_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
62 static paddr_t
genfb_mmap(void *, void *, off_t
, int);
63 static void genfb_init_screen(void *, struct vcons_screen
*, int, long *);
65 static int genfb_putcmap(struct genfb_softc
*, struct wsdisplay_cmap
*);
66 static int genfb_getcmap(struct genfb_softc
*, struct wsdisplay_cmap
*);
67 static int genfb_putpalreg(struct genfb_softc
*, uint8_t, uint8_t,
70 extern const u_char rasops_cmap
[768];
72 static int genfb_cnattach_called
= 0;
73 static int genfb_enabled
= 1;
75 struct wsdisplay_accessops genfb_accessops
= {
78 NULL
, /* alloc_screen */
79 NULL
, /* free_screen */
80 NULL
, /* show_screen */
86 static struct genfb_softc
*genfb_softc
= NULL
;
89 genfb_init(struct genfb_softc
*sc
)
91 prop_dictionary_t dict
;
92 uint64_t cmap_cb
, pmf_cb
;
95 dict
= device_properties(&sc
->sc_dev
);
97 printf(prop_dictionary_externalize(dict
));
99 if (!prop_dictionary_get_uint32(dict
, "width", &sc
->sc_width
)) {
100 GPRINTF("no width property\n");
103 if (!prop_dictionary_get_uint32(dict
, "height", &sc
->sc_height
)) {
104 GPRINTF("no height property\n");
107 if (!prop_dictionary_get_uint32(dict
, "depth", &sc
->sc_depth
)) {
108 GPRINTF("no depth property\n");
112 /* XXX should be a 64bit value */
113 if (!prop_dictionary_get_uint32(dict
, "address", &fboffset
)) {
114 GPRINTF("no address property\n");
118 sc
->sc_fboffset
= fboffset
;
120 if (!prop_dictionary_get_uint32(dict
, "linebytes", &sc
->sc_stride
))
121 sc
->sc_stride
= (sc
->sc_width
* sc
->sc_depth
) >> 3;
124 * deal with a bug in the Raptor firmware which always sets
125 * stride = width even when depth != 8
127 if (sc
->sc_stride
< sc
->sc_width
* (sc
->sc_depth
>> 3))
128 sc
->sc_stride
= sc
->sc_width
* (sc
->sc_depth
>> 3);
130 sc
->sc_fbsize
= sc
->sc_height
* sc
->sc_stride
;
132 /* optional colour map callback */
134 if (prop_dictionary_get_uint64(dict
, "cmap_callback", &cmap_cb
)) {
136 sc
->sc_cmcb
= (void *)(vaddr_t
)cmap_cb
;
138 /* optional pmf callback */
140 if (prop_dictionary_get_uint64(dict
, "pmf_callback", &pmf_cb
)) {
142 sc
->sc_pmfcb
= (void *)(vaddr_t
)pmf_cb
;
147 genfb_attach(struct genfb_softc
*sc
, struct genfb_ops
*ops
)
149 struct wsemuldisplaydev_attach_args aa
;
150 prop_dictionary_t dict
;
151 struct rasops_info
*ri
;
157 dict
= device_properties(&sc
->sc_dev
);
158 prop_dictionary_get_bool(dict
, "is_console", &console
);
160 if (prop_dictionary_get_uint16(dict
, "cursor-row", &crow
) == false)
162 if (prop_dictionary_get_bool(dict
, "clear-screen", &sc
->sc_want_clear
)
164 sc
->sc_want_clear
= true;
166 /* do not attach when we're not console */
168 aprint_normal_dev(&sc
->sc_dev
, "no console, unable to continue\n");
172 aprint_verbose_dev(&sc
->sc_dev
, "framebuffer at %p, size %dx%d, depth %d, "
174 sc
->sc_fboffset
? (void *)(intptr_t)sc
->sc_fboffset
: sc
->sc_fbaddr
,
175 sc
->sc_width
, sc
->sc_height
, sc
->sc_depth
, sc
->sc_stride
);
177 sc
->sc_defaultscreen_descr
= (struct wsscreen_descr
){
182 WSSCREEN_WSCOLORS
| WSSCREEN_HILIT
,
185 sc
->sc_screens
[0] = &sc
->sc_defaultscreen_descr
;
186 sc
->sc_screenlist
= (struct wsscreen_list
){1, sc
->sc_screens
};
187 memcpy(&sc
->sc_ops
, ops
, sizeof(struct genfb_ops
));
188 sc
->sc_mode
= WSDISPLAYIO_MODE_EMUL
;
190 sc
->sc_shadowfb
= kmem_alloc(sc
->sc_fbsize
, KM_SLEEP
);
191 if (sc
->sc_want_clear
== false && sc
->sc_shadowfb
!= NULL
)
192 memcpy(sc
->sc_shadowfb
, sc
->sc_fbaddr
, sc
->sc_fbsize
);
194 vcons_init(&sc
->vd
, sc
, &sc
->sc_defaultscreen_descr
,
196 sc
->vd
.init_screen
= genfb_init_screen
;
198 /* Do not print anything between this point and the screen
199 * clear operation below. Otherwise it will be lost. */
201 ri
= &sc
->sc_console_screen
.scr_ri
;
203 vcons_init_screen(&sc
->vd
, &sc
->sc_console_screen
, 1,
205 sc
->sc_console_screen
.scr_flags
|= VCONS_SCREEN_IS_STATIC
;
207 sc
->sc_defaultscreen_descr
.textops
= &ri
->ri_ops
;
208 sc
->sc_defaultscreen_descr
.capabilities
= ri
->ri_caps
;
209 sc
->sc_defaultscreen_descr
.nrows
= ri
->ri_rows
;
210 sc
->sc_defaultscreen_descr
.ncols
= ri
->ri_cols
;
211 wsdisplay_cnattach(&sc
->sc_defaultscreen_descr
, ri
, 0, crow
,
214 /* Clear the whole screen to bring it to a known state. */
215 if (sc
->sc_want_clear
)
216 (*ri
->ri_ops
.eraserows
)(ri
, 0, ri
->ri_rows
, defattr
);
219 for (i
= 0; i
< min(1 << sc
->sc_depth
, 256); i
++) {
221 sc
->sc_cmap_red
[i
] = rasops_cmap
[j
];
222 sc
->sc_cmap_green
[i
] = rasops_cmap
[j
+ 1];
223 sc
->sc_cmap_blue
[i
] = rasops_cmap
[j
+ 2];
224 genfb_putpalreg(sc
, i
, rasops_cmap
[j
], rasops_cmap
[j
+ 1],
229 vcons_replay_msgbuf(&sc
->sc_console_screen
);
231 if (genfb_softc
== NULL
)
234 aa
.console
= console
;
235 aa
.scrdata
= &sc
->sc_screenlist
;
236 aa
.accessops
= &genfb_accessops
;
237 aa
.accesscookie
= &sc
->vd
;
239 config_found(&sc
->sc_dev
, &aa
, wsemuldisplaydevprint
);
245 genfb_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
,
248 struct vcons_data
*vd
= v
;
249 struct genfb_softc
*sc
= vd
->cookie
;
250 struct wsdisplay_fbinfo
*wdf
;
251 struct vcons_screen
*ms
= vd
->active
;
255 case WSDISPLAYIO_GINFO
:
259 wdf
->height
= ms
->scr_ri
.ri_height
;
260 wdf
->width
= ms
->scr_ri
.ri_width
;
261 wdf
->depth
= ms
->scr_ri
.ri_depth
;
265 case WSDISPLAYIO_GETCMAP
:
266 return genfb_getcmap(sc
,
267 (struct wsdisplay_cmap
*)data
);
269 case WSDISPLAYIO_PUTCMAP
:
270 return genfb_putcmap(sc
,
271 (struct wsdisplay_cmap
*)data
);
273 case WSDISPLAYIO_LINEBYTES
:
274 *(u_int
*)data
= sc
->sc_stride
;
277 case WSDISPLAYIO_SMODE
:
278 new_mode
= *(int *)data
;
280 /* notify the bus backend */
282 if (sc
->sc_ops
.genfb_ioctl
)
283 error
= sc
->sc_ops
.genfb_ioctl(sc
, vs
,
288 if (new_mode
!= sc
->sc_mode
) {
289 sc
->sc_mode
= new_mode
;
290 if (new_mode
== WSDISPLAYIO_MODE_EMUL
) {
291 genfb_restore_palette(sc
);
292 vcons_redraw_screen(ms
);
297 if (sc
->sc_ops
.genfb_ioctl
)
298 return sc
->sc_ops
.genfb_ioctl(sc
, vs
, cmd
,
305 genfb_mmap(void *v
, void *vs
, off_t offset
, int prot
)
307 struct vcons_data
*vd
= v
;
308 struct genfb_softc
*sc
= vd
->cookie
;
310 if (sc
->sc_ops
.genfb_mmap
)
311 return sc
->sc_ops
.genfb_mmap(sc
, vs
, offset
, prot
);
317 genfb_init_screen(void *cookie
, struct vcons_screen
*scr
,
318 int existing
, long *defattr
)
320 struct genfb_softc
*sc
= cookie
;
321 struct rasops_info
*ri
= &scr
->scr_ri
;
323 ri
->ri_depth
= sc
->sc_depth
;
324 ri
->ri_width
= sc
->sc_width
;
325 ri
->ri_height
= sc
->sc_height
;
326 ri
->ri_stride
= sc
->sc_stride
;
327 ri
->ri_flg
= RI_CENTER
;
328 if (sc
->sc_want_clear
)
329 ri
->ri_flg
|= RI_FULLCLEAR
;
331 if (sc
->sc_shadowfb
!= NULL
) {
333 ri
->ri_hwbits
= (char *)sc
->sc_fbaddr
;
334 ri
->ri_bits
= (char *)sc
->sc_shadowfb
;
336 ri
->ri_bits
= (char *)sc
->sc_fbaddr
;
338 if (existing
&& sc
->sc_want_clear
) {
339 ri
->ri_flg
|= RI_CLEAR
;
342 rasops_init(ri
, sc
->sc_height
/ 8, sc
->sc_width
/ 8);
343 ri
->ri_caps
= WSSCREEN_WSCOLORS
;
345 rasops_reconfig(ri
, sc
->sc_height
/ ri
->ri_font
->fontheight
,
346 sc
->sc_width
/ ri
->ri_font
->fontwidth
);
348 /* TODO: actually center output */
353 genfb_putcmap(struct genfb_softc
*sc
, struct wsdisplay_cmap
*cm
)
356 u_int index
= cm
->index
;
357 u_int count
= cm
->count
;
359 u_char rbuf
[256], gbuf
[256], bbuf
[256];
362 aprint_debug("putcmap: %d %d\n",index
, count
);
364 if (cm
->index
>= 256 || cm
->count
> 256 ||
365 (cm
->index
+ cm
->count
) > 256)
367 error
= copyin(cm
->red
, &rbuf
[index
], count
);
370 error
= copyin(cm
->green
, &gbuf
[index
], count
);
373 error
= copyin(cm
->blue
, &bbuf
[index
], count
);
377 memcpy(&sc
->sc_cmap_red
[index
], &rbuf
[index
], count
);
378 memcpy(&sc
->sc_cmap_green
[index
], &gbuf
[index
], count
);
379 memcpy(&sc
->sc_cmap_blue
[index
], &bbuf
[index
], count
);
381 r
= &sc
->sc_cmap_red
[index
];
382 g
= &sc
->sc_cmap_green
[index
];
383 b
= &sc
->sc_cmap_blue
[index
];
385 for (i
= 0; i
< count
; i
++) {
386 genfb_putpalreg(sc
, index
, *r
, *g
, *b
);
394 genfb_getcmap(struct genfb_softc
*sc
, struct wsdisplay_cmap
*cm
)
396 u_int index
= cm
->index
;
397 u_int count
= cm
->count
;
400 if (index
>= 255 || count
> 256 || index
+ count
> 256)
403 error
= copyout(&sc
->sc_cmap_red
[index
], cm
->red
, count
);
406 error
= copyout(&sc
->sc_cmap_green
[index
], cm
->green
, count
);
409 error
= copyout(&sc
->sc_cmap_blue
[index
], cm
->blue
, count
);
417 genfb_restore_palette(struct genfb_softc
*sc
)
421 if (sc
->sc_depth
<= 8) {
422 for (i
= 0; i
< (1 << sc
->sc_depth
); i
++) {
423 genfb_putpalreg(sc
, i
, sc
->sc_cmap_red
[i
],
424 sc
->sc_cmap_green
[i
], sc
->sc_cmap_blue
[i
]);
430 genfb_putpalreg(struct genfb_softc
*sc
, uint8_t idx
, uint8_t r
, uint8_t g
,
436 sc
->sc_cmcb
->gcc_set_mapreg(sc
->sc_cmcb
->gcc_cookie
,
445 genfb_cnattach_called
= 1;
455 genfb_is_console(void)
457 return genfb_cnattach_called
;
461 genfb_is_enabled(void)
463 return genfb_enabled
;
467 genfb_borrow(bus_addr_t addr
, bus_space_handle_t
*hdlp
)
469 struct genfb_softc
*sc
= genfb_softc
;
471 if (sc
&& sc
->sc_ops
.genfb_borrow
)
472 return sc
->sc_ops
.genfb_borrow(sc
, addr
, hdlp
);