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>
52 struct ofw_pci_register sc_pciaddrs[8];
60 bus_space_tag_t sc_memt;
62 uint32_t sc_colormap[16];
65 static vd_probe_t ofwfb_probe;
66 static vd_init_t ofwfb_init;
67 static vd_blank_t ofwfb_blank;
68 static vd_bitbltchr_t ofwfb_bitbltchr;
69 static vd_fb_mmap_t ofwfb_mmap;
71 static const struct vt_driver vt_ofwfb_driver = {
73 .vd_probe = ofwfb_probe,
74 .vd_init = ofwfb_init,
75 .vd_blank = ofwfb_blank,
76 .vd_bitbltchr = ofwfb_bitbltchr,
77 .vd_maskbitbltchr = ofwfb_bitbltchr,
78 .vd_fb_mmap = ofwfb_mmap,
79 .vd_priority = VD_PRIORITY_GENERIC+1,
82 static struct ofwfb_softc ofwfb_conssoftc;
83 VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver);
86 ofwfb_probe(struct vt_device *vd)
88 phandle_t chosen, node;
92 chosen = OF_finddevice("/chosen");
93 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
94 node = OF_instance_to_package(stdout);
97 * The "/chosen/stdout" does not exist try
98 * using "screen" directly.
100 node = OF_finddevice("screen");
102 OF_getprop(node, "device_type", type, sizeof(type));
103 if (strcmp(type, "display") != 0)
107 return (CN_INTERNAL);
111 ofwfb_blank(struct vt_device *vd, term_color_t color)
113 struct ofwfb_softc *sc = vd->vd_softc;
117 size = sc->sc_stride * vd->vd_height;
118 switch (sc->sc_depth) {
120 c = (color << 24) | (color << 16) | (color << 8) | color;
121 for (ofs = 0; ofs < size/4; ofs++)
122 *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
125 c = sc->sc_colormap[color];
126 for (ofs = 0; ofs < size; ofs++)
127 *(uint32_t *)(sc->sc_addr + 4*ofs) = c;
136 ofwfb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask,
137 int bpl, vt_axis_t top, vt_axis_t left, unsigned int width,
138 unsigned int height, term_color_t fg, term_color_t bg)
140 struct ofwfb_softc *sc = vd->vd_softc;
150 fgc = sc->sc_colormap[fg];
151 bgc = sc->sc_colormap[bg];
154 /* Don't try to put off screen pixels */
155 if (((left + width) > vd->vd_width) || ((top + height) >
159 line = (sc->sc_stride * top) + left * sc->sc_depth/8;
160 if (mask == NULL && sc->sc_depth == 8 && (width % 8 == 0)) {
161 for (; height > 0; height--) {
162 for (c = 0; c < width; c += 8) {
166 * Assume that there is more background than
167 * foreground in characters and init accordingly
169 ch1.l = ch2.l = (bg << 24) | (bg << 16) |
173 * Calculate 2 x 4-chars at a time, and then
176 if (b & 0x80) ch1.c[0] = fg;
177 if (b & 0x40) ch1.c[1] = fg;
178 if (b & 0x20) ch1.c[2] = fg;
179 if (b & 0x10) ch1.c[3] = fg;
181 if (b & 0x08) ch2.c[0] = fg;
182 if (b & 0x04) ch2.c[1] = fg;
183 if (b & 0x02) ch2.c[2] = fg;
184 if (b & 0x01) ch2.c[3] = fg;
186 *(uint32_t *)(sc->sc_addr + line + c) = ch1.l;
187 *(uint32_t *)(sc->sc_addr + line + c + 4) =
190 line += sc->sc_stride;
193 for (; height > 0; height--) {
194 for (c = 0; c < width; c++) {
204 /* Skip pixel write, if mask not set. */
208 switch(sc->sc_depth) {
210 *(uint8_t *)(sc->sc_addr + line + c) =
214 *(uint32_t *)(sc->sc_addr + line + 4*c)
215 = (b & 0x80) ? fgc : bgc;
222 line += sc->sc_stride;
228 ofwfb_initialize(struct vt_device *vd)
230 struct ofwfb_softc *sc = vd->vd_softc;
237 /* Open display device, thereby initializing it */
238 memset(name, 0, sizeof(name));
239 OF_package_to_path(sc->sc_node, name, sizeof(name));
243 * Set up the color map
246 switch (sc->sc_depth) {
248 vt_generate_vga_palette(sc->sc_colormap, COLOR_FORMAT_RGB, 255,
251 for (i = 0; i < 16; i++) {
252 OF_call_method("color!", ih, 4, 1,
253 (cell_t)((sc->sc_colormap[i] >> 16) & 0xff),
254 (cell_t)((sc->sc_colormap[i] >> 8) & 0xff),
255 (cell_t)((sc->sc_colormap[i] >> 0) & 0xff),
262 * We bypass the usual bus_space_() accessors here, mostly
263 * for performance reasons. In particular, we don't want
264 * any barrier operations that may be performed and handle
265 * endianness slightly different. Figure out the host-view
266 * endianness of the frame buffer.
268 oldpix = bus_space_read_4(sc->sc_memt, sc->sc_addr, 0);
269 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, 0xff000000);
270 if (*(uint8_t *)(sc->sc_addr) == 0xff)
271 vt_generate_vga_palette(sc->sc_colormap,
272 COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0);
274 vt_generate_vga_palette(sc->sc_colormap,
275 COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16);
276 bus_space_write_4(sc->sc_memt, sc->sc_addr, 0, oldpix);
280 panic("Unknown color space depth %d", sc->sc_depth);
284 /* Clear the screen. */
285 ofwfb_blank(vd, TC_BLACK);
289 ofwfb_init(struct vt_device *vd)
291 struct ofwfb_softc *sc;
296 uint32_t depth, height, width;
300 static struct bus_space_tag ofwfb_memt[1];
305 /* Initialize softc */
306 vd->vd_softc = sc = &ofwfb_conssoftc;
308 chosen = OF_finddevice("/chosen");
309 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout));
310 node = OF_instance_to_package(stdout);
313 * The "/chosen/stdout" does not exist try
314 * using "screen" directly.
316 node = OF_finddevice("screen");
318 OF_getprop(node, "device_type", type, sizeof(type));
319 if (strcmp(type, "display") != 0)
322 /* Keep track of the OF node */
325 /* Make sure we have needed properties */
326 if (OF_getproplen(node, "height") != sizeof(height) ||
327 OF_getproplen(node, "width") != sizeof(width) ||
328 OF_getproplen(node, "depth") != sizeof(depth) ||
329 OF_getproplen(node, "linebytes") != sizeof(sc->sc_stride))
332 /* Only support 8 and 32-bit framebuffers */
333 OF_getprop(node, "depth", &depth, sizeof(depth));
334 if (depth != 8 && depth != 32)
336 sc->sc_depth = depth;
338 OF_getprop(node, "height", &height, sizeof(height));
339 OF_getprop(node, "width", &width, sizeof(width));
340 OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride));
342 vd->vd_height = height;
343 vd->vd_width = width;
346 * Get the PCI addresses of the adapter, if present. The node may be the
347 * child of the PCI device: in that case, try the parent for
348 * the assigned-addresses property.
350 len = OF_getprop(node, "assigned-addresses", sc->sc_pciaddrs,
351 sizeof(sc->sc_pciaddrs));
353 len = OF_getprop(OF_parent(node), "assigned-addresses",
354 sc->sc_pciaddrs, sizeof(sc->sc_pciaddrs));
358 sc->sc_num_pciaddrs = len / sizeof(struct ofw_pci_register);
361 * Grab the physical address of the framebuffer, and then map it
362 * into our memory space. If the MMU is not yet up, it will be
363 * remapped for us when relocation turns on.
365 if (OF_getproplen(node, "address") == sizeof(fb_phys)) {
366 /* XXX We assume #address-cells is 1 at this point. */
367 OF_getprop(node, "address", &fb_phys, sizeof(fb_phys));
369 #if defined(__powerpc__)
370 sc->sc_memt = &bs_be_tag;
371 bus_space_map(sc->sc_memt, fb_phys, height * sc->sc_stride,
372 BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr);
373 #elif defined(__sparc64__)
374 OF_decode_addr(node, 0, &space, &phys);
375 sc->sc_memt = &ofwfb_memt[0];
376 sc->sc_addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt);
378 #error Unsupported platform!
382 * Some IBM systems don't have an address property. Try to
383 * guess the framebuffer region from the assigned addresses.
384 * This is ugly, but there doesn't seem to be an alternative.
385 * Linux does the same thing.
388 fb_phys = sc->sc_num_pciaddrs;
389 for (i = 0; i < sc->sc_num_pciaddrs; i++) {
390 /* If it is too small, not the framebuffer */
391 if (sc->sc_pciaddrs[i].size_lo < sc->sc_stride*height)
393 /* If it is not memory, it isn't either */
394 if (!(sc->sc_pciaddrs[i].phys_hi &
395 OFW_PCI_PHYS_HI_SPACE_MEM32))
398 /* This could be the framebuffer */
401 /* If it is prefetchable, it certainly is */
402 if (sc->sc_pciaddrs[i].phys_hi &
403 OFW_PCI_PHYS_HI_PREFETCHABLE)
407 if (fb_phys == sc->sc_num_pciaddrs) /* No candidates found */
410 #if defined(__powerpc__)
411 OF_decode_addr(node, fb_phys, &sc->sc_memt, &sc->sc_addr);
412 #elif defined(__sparc64__)
413 OF_decode_addr(node, fb_phys, &space, &phys);
414 sc->sc_memt = &ofwfb_memt[0];
415 sc->sc_addr = sparc64_fake_bustag(space, phys, sc->sc_memt);
419 ofwfb_initialize(vd);
421 return (CN_INTERNAL);
425 ofwfb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr,
426 int prot, vm_memattr_t *memattr)
428 struct ofwfb_softc *sc = vd->vd_softc;
432 * Make sure the requested address lies within the PCI device's
435 for (i = 0; i < sc->sc_num_pciaddrs; i++)
436 if (offset >= sc->sc_pciaddrs[i].phys_lo &&
437 offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo))
440 * If this is a prefetchable BAR, we can (and should)
441 * enable write-combining.
443 if (sc->sc_pciaddrs[i].phys_hi &
444 OFW_PCI_PHYS_HI_PREFETCHABLE)
445 *memattr = VM_MEMATTR_WRITE_COMBINING;