2 * Copyright (c) 2011 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
34 #include <dev/vt/vt.h>
35 #include <dev/vt/colors/vt_termcolors.h>
40 #include <machine/bus.h>
42 #include <machine/bus_private.h>
45 #include <dev/ofw/openfirm.h>
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_pci.h>
56 bus_space_tag_t sc_memt;
58 uint32_t sc_colormap[16];
61 static vd_init_t ofwfb_init;
62 static vd_blank_t ofwfb_blank;
63 static vd_bitbltchr_t ofwfb_bitbltchr;
65 static const struct vt_driver vt_ofwfb_driver = {
66 .vd_init = ofwfb_init,
67 .vd_blank = ofwfb_blank,
68 .vd_bitbltchr = ofwfb_bitbltchr,
69 .vd_priority = VD_PRIORITY_GENERIC+1,
72 static struct ofwfb_softc ofwfb_conssoftc;
73 VT_CONSDEV_DECLARE(vt_ofwfb_driver, PIXEL_WIDTH(1920), PIXEL_HEIGHT(1200),
75 /* XXX: hardcoded max size */
78 ofwfb_blank(struct vt_device *vd, term_color_t color)
80 struct ofwfb_softc *sc = vd->vd_softc;
84 size = sc->sc_stride * vd->vd_height;
85 switch (sc->sc_depth) {
87 c = (color << 24) | (color << 16) | (color << 8) | color;
88 for (ofs = 0; ofs < size/4; ofs++)
89 *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
92 c = sc->sc_colormap[color];
93 for (ofs = 0; ofs < size; ofs++)
94 *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
103 ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
104 int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
105 unsigned int height, term_color_t fg, term_color_t bg)
107 struct ofwfb_softc *sc = vd->vd_softc;
113 fgc = sc->sc_colormap[fg];
114 bgc = sc->sc_colormap[bg];
117 /* Don't try to put off screen pixels */
118 if (((left + width) > vd->vd_width) || ((top + height) >
122 line = (sc->sc_stride * top) + left * sc->sc_depth/8;
123 for (; height > 0; height--) {
124 for (c = 0; c < width; c++) {
134 /* Skip pixel write, if mask has no bit set. */
138 switch(sc->sc_depth) {
140 *(uint8_t *)(sc->sc_addr + line + c) =
144 *(uint32_t *)(sc->sc_addr + line + 4*c) =
145 (b & 0x80) ? fgc : bgc;
152 line += sc->sc_stride;
157 ofwfb_initialize(struct vt_device *vd)
159 struct ofwfb_softc *sc = vd->vd_softc;
166 /* Open display device, thereby initializing it */
167 memset(name, 0, sizeof(name));
168 OF_package_to_path(sc->sc_node, name, sizeof(name));
172 * Set up the color map
175 switch (sc->sc_depth) {
177 vt_generate_vga_palette(sc->sc_colormap, COLOR_FORMAT_RGB, 255,
180 for (i = 0; i < 16; i++) {
181 OF_call_method("color!", ih, 4, 1,
182 (cell_t)((sc->sc_colormap[i] >> 16) & 0xff),
183 (cell_t)((sc->sc_colormap[i] >> 8) & 0xff),
184 (cell_t)((sc->sc_colormap[i] >> 0) & 0xff),
191 * We bypass the usual bus_space_() accessors here, mostly
192 * for performance reasons. In particular, we don't want
193 * any barrier operations that may be performed and handle
194 * endianness slightly different. Figure out the host-view
195 * endianness of the frame buffer.
197 oldpix = bus_space_read_4(sc->sc_memt, sc->sc_addr, 0);
198 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, 0xff000000);
199 if (*(uint8_t *)(sc->sc_addr) == 0xff)
200 vt_generate_vga_palette(sc->sc_colormap,
201 COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
203 vt_generate_vga_palette(sc->sc_colormap,
204 COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
205 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, oldpix);
209 panic("Unknown color space depth %d", sc->sc_depth);
213 /* Clear the screen. */
214 ofwfb_blank(vd, TC_BLACK);
218 ofwfb_init(struct vt_device *vd)
220 struct ofwfb_softc *sc = vd->vd_softc;
225 uint32_t depth, height, width;
226 struct ofw_pci_register pciaddrs[8];
231 static struct bus_space_tag ofwfb_memt[1];
236 chosen = OF_finddevice("/chosen");
237 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
238 node = OF_instance_to_package(stdout);
241 * The "/chosen/stdout" does not exist try
242 * using "screen" directly.
244 node = OF_finddevice("screen");
246 OF_getprop(node, "device_type", type, sizeof(type));
247 if (strcmp(type, "display") != 0)
250 /* Keep track of the OF node */
253 /* Make sure we have needed properties */
254 if (OF_getproplen(node, "height") != sizeof(height) ||
255 OF_getproplen(node, "width") != sizeof(width) ||
256 OF_getproplen(node, "depth") != sizeof(depth) ||
257 OF_getproplen(node, "linebytes") != sizeof(sc->sc_stride))
260 /* Only support 8 and 32-bit framebuffers */
261 OF_getprop(node, "depth", &depth, sizeof(depth));
262 if (depth != 8 && depth != 32)
264 sc->sc_depth = depth;
266 OF_getprop(node, "height", &height, sizeof(height));
267 OF_getprop(node, "width", &width, sizeof(width));
268 OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
270 vd->vd_height = height;
271 vd->vd_width = width;
274 * Get the PCI addresses of the adapter, if present. The node may be the
275 * child of the PCI device: in that case, try the parent for
276 * the assigned-addresses property.
278 len = OF_getprop(node, "assigned-addresses", pciaddrs,
281 len = OF_getprop(OF_parent(node), "assigned-addresses",
282 pciaddrs, sizeof(pciaddrs));
286 n_pciaddrs = len / sizeof(struct ofw_pci_register);
289 * Grab the physical address of the framebuffer, and then map it
290 * into our memory space. If the MMU is not yet up, it will be
291 * remapped for us when relocation turns on.
293 if (OF_getproplen(node, "address") == sizeof(fb_phys)) {
294 /* XXX We assume #address-cells is 1 at this point. */
295 OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
297 #if defined(__powerpc__)
298 sc->sc_memt = &bs_be_tag;
299 bus_space_map(sc->sc_memt, fb_phys, height * sc->sc_stride,
300 BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr);
301 #elif defined(__sparc64__)
302 OF_decode_addr(node, 0, &space, &phys);
303 sc->sc_memt = &ofwfb_memt[0];
304 sc->sc_addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
306 #error Unsupported platform!
310 * Some IBM systems don't have an address property. Try to
311 * guess the framebuffer region from the assigned addresses.
312 * This is ugly, but there doesn't seem to be an alternative.
313 * Linux does the same thing.
316 fb_phys = n_pciaddrs;
317 for (i = 0; i < n_pciaddrs; i++) {
318 /* If it is too small, not the framebuffer */
319 if (pciaddrs[i].size_lo < sc->sc_stride*height)
321 /* If it is not memory, it isn't either */
322 if (!(pciaddrs[i].phys_hi &
323 OFW_PCI_PHYS_HI_SPACE_MEM32))
326 /* This could be the framebuffer */
329 /* If it is prefetchable, it certainly is */
330 if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE)
334 if (fb_phys == n_pciaddrs) /* No candidates found */
337 #if defined(__powerpc__)
338 OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->sc_addr);
339 #elif defined(__sparc64__)
340 OF_decode_addr(node, fb_phys, &space, &phys);
341 sc->sc_memt = &ofwfb_memt[0];
342 sc->sc_addr = sparc64_fake_bustag(space, phys, sc->sc_memt);
346 ofwfb_initialize(vd);
348 return (CN_INTERNAL);