vt_early_fb.c revision 271117
1/*- 2 * Copyright (c) 2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Aleksandr Rybalko under sponsorship from the 6 * FreeBSD Foundation. 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 AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_early_fb.c 271117 2014-09-04 18:43:40Z emaste $ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_early_fb.c 271117 2014-09-04 18:43:40Z emaste $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/fbio.h> 39 40#include "opt_platform.h" 41 42#ifdef FDT 43#include <dev/fdt/fdt_common.h> 44#include <dev/ofw/ofw_bus.h> 45#include <dev/ofw/ofw_bus_subr.h> 46#include <dev/ofw/ofw_pci.h> 47#include <machine/fdt.h> 48#endif 49 50#include <dev/vt/vt.h> 51#include <dev/vt/hw/fb/vt_fb.h> 52#include <dev/vt/colors/vt_termcolors.h> 53 54static vd_init_t vt_efb_init; 55static vd_probe_t vt_efb_probe; 56 57static struct vt_driver vt_fb_early_driver = { 58 .vd_name = "efb", 59 .vd_probe = vt_efb_probe, 60 .vd_init = vt_efb_init, 61 .vd_blank = vt_fb_blank, 62 .vd_bitbltchr = vt_fb_bitbltchr, 63 .vd_priority = VD_PRIORITY_GENERIC, 64}; 65 66static struct fb_info local_info; 67VT_DRIVER_DECLARE(vt_efb, vt_fb_early_driver); 68 69static void 70#ifdef FDT 71vt_efb_initialize(struct fb_info *info, phandle_t node) 72#else 73vt_efb_initialize(struct fb_info *info) 74#endif 75{ 76#ifdef FDT 77 char name[64]; 78 cell_t retval; 79 ihandle_t ih; 80 int i; 81 82 /* Open display device, thereby initializing it */ 83 memset(name, 0, sizeof(name)); 84 OF_package_to_path(node, name, sizeof(name)); 85 ih = OF_open(name); 86#endif 87 88 /* 89 * Set up the color map 90 */ 91 switch (info->fb_depth) { 92 case 8: 93 vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB, 94 0x7, 5, 0x7, 2, 0x3, 0); 95 break; 96 case 15: 97 vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB, 98 0x1f, 10, 0x1f, 5, 0x1f, 0); 99 break; 100 case 16: 101 vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB, 102 0x1f, 11, 0x3f, 5, 0x1f, 0); 103 break; 104 case 24: 105 case 32: 106#if BYTE_ORDER == BIG_ENDIAN 107 vt_generate_cons_palette(info->fb_cmap, 108 COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); 109#else 110 vt_generate_cons_palette(info->fb_cmap, 111 COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); 112#endif 113#ifdef FDT 114 for (i = 0; i < 16; i++) { 115 OF_call_method("color!", ih, 4, 1, 116 (cell_t)((info->fb_cmap[i] >> 16) & 0xff), 117 (cell_t)((info->fb_cmap[i] >> 8) & 0xff), 118 (cell_t)((info->fb_cmap[i] >> 0) & 0xff), 119 (cell_t)i, &retval); 120 } 121#endif 122 break; 123 124 default: 125 panic("Unknown color space fb_depth %d", info->fb_depth); 126 break; 127 } 128} 129 130static phandle_t 131vt_efb_get_fbnode() 132{ 133 phandle_t chosen, node; 134 ihandle_t stdout; 135 char type[64]; 136 137 chosen = OF_finddevice("/chosen"); 138 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 139 node = OF_instance_to_package(stdout); 140 if (node != -1) { 141 /* The "/chosen/stdout" present. */ 142 OF_getprop(node, "device_type", type, sizeof(type)); 143 /* Check if it has "display" type. */ 144 if (strcmp(type, "display") == 0) 145 return (node); 146 } 147 /* Try device with name "screen". */ 148 node = OF_finddevice("screen"); 149 150 return (node); 151} 152 153static int 154vt_efb_probe(struct vt_device *vd) 155{ 156 phandle_t node; 157 158 node = vt_efb_get_fbnode(); 159 if (node == -1) 160 return (CN_DEAD); 161 162 if ((OF_getproplen(node, "height") <= 0) || 163 (OF_getproplen(node, "width") <= 0) || 164 (OF_getproplen(node, "depth") <= 0) || 165 (OF_getproplen(node, "linebytes") <= 0)) 166 return (CN_DEAD); 167 168 return (CN_INTERNAL); 169} 170 171static int 172vt_efb_init(struct vt_device *vd) 173{ 174 struct ofw_pci_register pciaddrs[8]; 175 struct fb_info *info; 176 int i, len, n_pciaddrs; 177 phandle_t node; 178 179 if (vd->vd_softc == NULL) 180 vd->vd_softc = (void *)&local_info; 181 182 info = vd->vd_softc; 183 184 node = vt_efb_get_fbnode(); 185 if (node == -1) 186 return (CN_DEAD); 187 188#define GET(name, var) \ 189 if (OF_getproplen(node, (name)) != sizeof(info->fb_##var)) \ 190 return (CN_DEAD); \ 191 OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \ 192 if (info->fb_##var == 0) \ 193 return (CN_DEAD); 194 195 GET("height", height) 196 GET("width", width) 197 GET("depth", depth) 198 GET("linebytes", stride) 199#undef GET 200 201 info->fb_size = info->fb_height * info->fb_stride; 202 203 /* 204 * Get the PCI addresses of the adapter, if present. The node may be the 205 * child of the PCI device: in that case, try the parent for 206 * the assigned-addresses property. 207 */ 208 len = OF_getprop(node, "assigned-addresses", pciaddrs, 209 sizeof(pciaddrs)); 210 if (len == -1) { 211 len = OF_getprop(OF_parent(node), "assigned-addresses", 212 pciaddrs, sizeof(pciaddrs)); 213 } 214 if (len == -1) 215 len = 0; 216 n_pciaddrs = len / sizeof(struct ofw_pci_register); 217 218 /* 219 * Grab the physical address of the framebuffer, and then map it 220 * into our memory space. If the MMU is not yet up, it will be 221 * remapped for us when relocation turns on. 222 */ 223 if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) { 224 /* XXX We assume #address-cells is 1 at this point. */ 225 OF_getencprop(node, "address", &info->fb_pbase, 226 sizeof(info->fb_pbase)); 227 228 #if defined(__powerpc__) 229 sc->sc_memt = &bs_be_tag; 230 bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size, 231 BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase); 232 #elif defined(__sparc64__) 233 OF_decode_addr(node, 0, &space, &phys); 234 sc->sc_memt = &vt_efb_memt[0]; 235 info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt); 236 #else 237 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 238 BUS_SPACE_MAP_PREFETCHABLE, 239 (bus_space_handle_t *)&info->fb_vbase); 240 #endif 241 } else { 242 /* 243 * Some IBM systems don't have an address property. Try to 244 * guess the framebuffer region from the assigned addresses. 245 * This is ugly, but there doesn't seem to be an alternative. 246 * Linux does the same thing. 247 */ 248 249 info->fb_pbase = n_pciaddrs; 250 for (i = 0; i < n_pciaddrs; i++) { 251 /* If it is too small, not the framebuffer */ 252 if (pciaddrs[i].size_lo < info->fb_size) 253 continue; 254 /* If it is not memory, it isn't either */ 255 if (!(pciaddrs[i].phys_hi & 256 OFW_PCI_PHYS_HI_SPACE_MEM32)) 257 continue; 258 259 /* This could be the framebuffer */ 260 info->fb_pbase = i; 261 262 /* If it is prefetchable, it certainly is */ 263 if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) 264 break; 265 } 266 267 if (info->fb_pbase == n_pciaddrs) /* No candidates found */ 268 return (CN_DEAD); 269 270 #if defined(__powerpc__) 271 OF_decode_addr(node, info->fb_pbase, &sc->sc_memt, 272 &info->fb_vbase); 273 #elif defined(__sparc64__) 274 OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase); 275 sc->sc_memt = &vt_efb_memt[0]; 276 info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase, 277 sc->sc_memt); 278 #else 279 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 280 BUS_SPACE_MAP_PREFETCHABLE, 281 (bus_space_handle_t *)&info->fb_vbase); 282 #endif 283 } 284 285 /* blank full size */ 286 len = info->fb_size / 4; 287 for (i = 0; i < len; i++) { 288 ((uint32_t *)info->fb_vbase)[i] = 0; 289 } 290 291 /* Get pixel storage size. */ 292 info->fb_bpp = info->fb_stride / info->fb_width * 8; 293 294#ifdef FDT 295 vt_efb_initialize(info, node); 296#else 297 vt_efb_initialize(info); 298#endif 299 vt_fb_init(vd); 300 301 return (CN_INTERNAL); 302} 303