ofwfb.c revision 230440
1/*- 2 * Copyright (c) 2011 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c 219888 2011-03-22 21:31:31Z ed $"); 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/systm.h> 33 34#include <dev/vt/vt.h> 35 36#include <vm/vm.h> 37#include <vm/pmap.h> 38 39#include <machine/bus.h> 40#ifdef __sparc64__ 41#include <machine/bus_private.h> 42#endif 43 44#include <dev/ofw/openfirm.h> 45#include <dev/ofw/ofw_bus.h> 46#include <dev/ofw/ofw_pci.h> 47 48struct ofwfb_softc { 49 phandle_t sc_node; 50 51 intptr_t sc_addr; 52 int sc_depth; 53 int sc_stride; 54 55#ifdef __sparc64__ 56 bus_space_tag_t sc_memt; 57#endif 58}; 59 60static vd_init_t ofwfb_init; 61static vd_blank_t ofwfb_blank; 62static vd_bitblt_t ofwfb_bitblt; 63 64static const struct vt_driver vt_ofwfb_driver = { 65 .vd_init = ofwfb_init, 66 .vd_blank = ofwfb_blank, 67 .vd_bitblt = ofwfb_bitblt, 68}; 69 70static struct ofwfb_softc ofwfb_conssoftc; 71VT_CONSDEV_DECLARE(vt_ofwfb_driver, PIXEL_WIDTH(1920), PIXEL_HEIGHT(1200), 72 &ofwfb_conssoftc); 73/* XXX: hardcoded max size */ 74 75static const uint32_t colormap[] = { 76 0x00000000, /* Black */ 77 0x00ff0000, /* Red */ 78 0x0000ff00, /* Green */ 79 0x00c0c000, /* Brown */ 80 0x000000ff, /* Blue */ 81 0x00c000c0, /* Magenta */ 82 0x0000c0c0, /* Cyan */ 83 0x00c0c0c0, /* Light grey */ 84 0x00808080, /* Dark grey */ 85 0x00ff8080, /* Light red */ 86 0x0080ff80, /* Light green */ 87 0x00ffff80, /* Yellow */ 88 0x008080ff, /* Light blue */ 89 0x00ff80ff, /* Light magenta */ 90 0x0080ffff, /* Light cyan */ 91 0x00ffffff, /* White */ 92}; 93 94static void 95ofwfb_blank(struct vt_device *vd, term_color_t color) 96{ 97 struct ofwfb_softc *sc = vd->vd_softc; 98 u_int ofs; 99 uint32_t c; 100 101 switch (sc->sc_depth) { 102 case 8: 103 for (ofs = 0; ofs < sc->sc_stride*vd->vd_height; ofs++) 104 *(uint8_t *)(sc->sc_addr + ofs) = color; 105 break; 106 case 32: 107 c = colormap[color]; 108 for (ofs = 0; ofs < sc->sc_stride*vd->vd_height; ofs++) 109 *(uint32_t *)(sc->sc_addr + 4*ofs) = c; 110 break; 111 default: 112 /* panic? */ 113 break; 114 } 115} 116 117static void 118ofwfb_bitblt(struct vt_device *vd, const uint8_t *src, 119 vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height, 120 term_color_t fg, term_color_t bg) 121{ 122 struct ofwfb_softc *sc = vd->vd_softc; 123 u_long line; 124 uint32_t fgc, bgc; 125 int c; 126 uint8_t b = 0; 127 128 fgc = colormap[fg]; 129 bgc = colormap[bg]; 130 131 line = (sc->sc_stride * top) + left * sc->sc_depth/8; 132 for (; height > 0; height--) { 133 line += sc->sc_stride; 134 for (c = 0; c < width; c++) { 135 if (c % 8 == 0) 136 b = *src++; 137 else 138 b <<= 1; 139 switch(sc->sc_depth) { 140 case 8: 141 *(uint8_t *)(sc->sc_addr + line + c) = 142 b & 0x80 ? fg : bg; 143 break; 144 case 32: 145 *(uint32_t *)(sc->sc_addr + line + 4*c) = 146 (b & 0x80) ? fgc : bgc; 147 break; 148 default: 149 /* panic? */ 150 break; 151 } 152 } 153 } 154} 155 156static void 157ofwfb_initialize(struct vt_device *vd) 158{ 159 struct ofwfb_softc *sc = vd->vd_softc; 160 char name[64]; 161 ihandle_t ih; 162 int i; 163 cell_t retval; 164 165 /* Open display device, thereby initializing it */ 166 memset(name, 0, sizeof(name)); 167 OF_package_to_path(sc->sc_node, name, sizeof(name)); 168 ih = OF_open(name); 169 170 if (sc->sc_depth == 8) { 171 /* 172 * Install the color map 173 */ 174 for (i = 0; i < 16; i++) { 175 OF_call_method("color!", ih, 4, 1, 176 (cell_t)((colormap[i] >> 16) & 0xff), 177 (cell_t)((colormap[i] >> 8) & 0xff), 178 (cell_t)((colormap[i] >> 0) & 0xff), 179 (cell_t)i, &retval); 180 } 181 } 182 183 /* Clear the screen. */ 184 ofwfb_blank(vd, TC_BLACK); 185} 186 187static int 188ofwfb_init(struct vt_device *vd) 189{ 190 struct ofwfb_softc *sc = vd->vd_softc; 191 char type[64]; 192 phandle_t chosen; 193 ihandle_t stdout; 194 phandle_t node; 195 uint32_t depth, height, width; 196 uint32_t fb_phys; 197#ifdef __sparc64__ 198 static struct bus_space_tag ofwfb_memt[1]; 199 bus_addr_t phys; 200 int space; 201#endif 202 203 chosen = OF_finddevice("/chosen"); 204 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 205 node = OF_instance_to_package(stdout); 206 if (node == -1) { 207 /* 208 * The "/chosen/stdout" does not exist try 209 * using "screen" directly. 210 */ 211 node = OF_finddevice("screen"); 212 } 213 OF_getprop(node, "device_type", type, sizeof(type)); 214 if (strcmp(type, "display") != 0) 215 return (CN_DEAD); 216 217 /* Keep track of the OF node */ 218 sc->sc_node = node; 219 220 /* Only support 8 and 32-bit framebuffers */ 221 OF_getprop(node, "depth", &depth, sizeof(depth)); 222 sc->sc_depth = depth; 223 224 OF_getprop(node, "height", &height, sizeof(height)); 225 OF_getprop(node, "width", &width, sizeof(width)); 226 OF_getprop(node, "linebytes", &sc->sc_stride, sizeof(sc->sc_stride)); 227 228 vd->vd_height = height; 229 vd->vd_width = width; 230 231 /* 232 * Grab the physical address of the framebuffer, and then map it 233 * into our memory space. If the MMU is not yet up, it will be 234 * remapped for us when relocation turns on. 235 */ 236 237 /* XXX We assume #address-cells is 1 at this point. */ 238 OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); 239 240#if defined(__powerpc__) 241 bus_space_map(&bs_be_tag, fb_phys, height * sc->sc_stride, 242 BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr); 243#elif defined(__sparc64__) 244 OF_decode_addr(node, 0, &space, &phys); 245 sc->sc_memt = &ofwfb_memt[0]; 246 sc->sc_addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt); 247#else 248 #error Unsupported platform! 249#endif 250 251 ofwfb_initialize(vd); 252 253 return (CN_INTERNAL); 254} 255 256