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$ 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 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 #endif 48 49 #include <dev/vt/vt.h> 50 #include <dev/vt/hw/fb/vt_fb.h> 51 #include <dev/vt/colors/vt_termcolors.h> 52 53 static vd_init_t vt_efb_init; 54 55 static struct vt_driver vt_fb_early_driver = { 56 .vd_init = vt_efb_init, 57 .vd_blank = vt_fb_blank, 58 .vd_bitbltchr = vt_fb_bitbltchr, 59 .vd_priority = VD_PRIORITY_GENERIC, 60 }; 61 62 static struct fb_info info; 63 VT_CONSDEV_DECLARE(vt_fb_early_driver, 64 MAX(80, PIXEL_WIDTH(VT_FB_DEFAULT_WIDTH)), 65 MAX(25, PIXEL_HEIGHT(VT_FB_DEFAULT_HEIGHT)), &info); 66 67 static void 68 #ifdef FDT 69 vt_efb_initialize(struct fb_info *info, phandle_t node) 70 #else 71 vt_efb_initialize(struct fb_info *info) 72 #endif 73 { 74 #ifdef FDT 75 char name[64]; 76 cell_t retval; 77 ihandle_t ih; 78 int i; 79 80 /* Open display device, thereby initializing it */ 81 memset(name, 0, sizeof(name)); 82 OF_package_to_path(node, name, sizeof(name)); 83 ih = OF_open(name); 84 #endif 85 86 /* 87 * Set up the color map 88 */ 89 switch (info->fb_depth) { 90 case 8: 91 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 92 0x7, 5, 0x7, 2, 0x3, 0); 93 break; 94 case 15: 95 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 96 0x1f, 10, 0x1f, 5, 0x1f, 0); 97 break; 98 case 16: 99 vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 100 0x1f, 11, 0x3f, 5, 0x1f, 0); 101 break; 102 case 24: 103 case 32: 104 #if BYTE_ORDER == BIG_ENDIAN 105 vt_generate_vga_palette(info->fb_cmap, 106 COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); 107 #else 108 vt_generate_vga_palette(info->fb_cmap, 109 COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); 110 #endif 111 #ifdef FDT 112 for (i = 0; i < 16; i++) { 113 OF_call_method("color!", ih, 4, 1, 114 (cell_t)((info->fb_cmap[i] >> 16) & 0xff), 115 (cell_t)((info->fb_cmap[i] >> 8) & 0xff), 116 (cell_t)((info->fb_cmap[i] >> 0) & 0xff), 117 (cell_t)i, &retval); 118 } 119 #endif 120 break; 121 122 default: 123 panic("Unknown color space fb_depth %d", info->fb_depth); 124 break; 125 } 126 } 127 128 static int 129 vt_efb_init(struct vt_device *vd) 130 { 131 struct ofw_pci_register pciaddrs[8]; 132 struct fb_info *info; 133 int i, len, n_pciaddrs; 134 phandle_t chosen, node; 135 ihandle_t stdout; 136 char type[64]; 137 138 info = vd->vd_softc; 139 140 chosen = OF_finddevice("/chosen"); 141 OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 142 node = OF_instance_to_package(stdout); 143 if (node == -1) { 144 /* 145 * The "/chosen/stdout" does not exist try 146 * using "screen" directly. 147 */ 148 node = OF_finddevice("screen"); 149 } 150 OF_getprop(node, "device_type", type, sizeof(type)); 151 if (strcmp(type, "display") != 0) 152 return (CN_DEAD); 153 154 #define GET(name, var) \ 155 if (OF_getproplen(node, (name)) != sizeof(info->fb_##var)) \ 156 return (CN_DEAD); \ 157 OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \ 158 if (info->fb_##var == 0) \ 159 return (CN_DEAD); 160 161 GET("height", height) 162 GET("width", width) 163 GET("depth", depth) 164 GET("linebytes", stride) 165 #undef GET 166 167 info->fb_size = info->fb_height * info->fb_stride; 168 169 /* 170 * Get the PCI addresses of the adapter, if present. The node may be the 171 * child of the PCI device: in that case, try the parent for 172 * the assigned-addresses property. 173 */ 174 len = OF_getprop(node, "assigned-addresses", pciaddrs, 175 sizeof(pciaddrs)); 176 if (len == -1) { 177 len = OF_getprop(OF_parent(node), "assigned-addresses", 178 pciaddrs, sizeof(pciaddrs)); 179 } 180 if (len == -1) 181 len = 0; 182 n_pciaddrs = len / sizeof(struct ofw_pci_register); 183 184 /* 185 * Grab the physical address of the framebuffer, and then map it 186 * into our memory space. If the MMU is not yet up, it will be 187 * remapped for us when relocation turns on. 188 */ 189 if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) { 190 /* XXX We assume #address-cells is 1 at this point. */ 191 OF_getencprop(node, "address", &info->fb_pbase, 192 sizeof(info->fb_pbase)); 193 194 #if defined(__powerpc__) 195 sc->sc_memt = &bs_be_tag; 196 bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size, 197 BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase); 198 #elif defined(__sparc64__) 199 OF_decode_addr(node, 0, &space, &phys); 200 sc->sc_memt = &vt_efb_memt[0]; 201 info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt); 202 #else 203 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 204 BUS_SPACE_MAP_PREFETCHABLE, 205 (bus_space_handle_t *)&info->fb_vbase); 206 #endif 207 } else { 208 /* 209 * Some IBM systems don't have an address property. Try to 210 * guess the framebuffer region from the assigned addresses. 211 * This is ugly, but there doesn't seem to be an alternative. 212 * Linux does the same thing. 213 */ 214 215 info->fb_pbase = n_pciaddrs; 216 for (i = 0; i < n_pciaddrs; i++) { 217 /* If it is too small, not the framebuffer */ 218 if (pciaddrs[i].size_lo < info->fb_size) 219 continue; 220 /* If it is not memory, it isn't either */ 221 if (!(pciaddrs[i].phys_hi & 222 OFW_PCI_PHYS_HI_SPACE_MEM32)) 223 continue; 224 225 /* This could be the framebuffer */ 226 info->fb_pbase = i; 227 228 /* If it is prefetchable, it certainly is */ 229 if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) 230 break; 231 } 232 233 if (info->fb_pbase == n_pciaddrs) /* No candidates found */ 234 return (CN_DEAD); 235 236 #if defined(__powerpc__) 237 OF_decode_addr(node, info->fb_pbase, &sc->sc_memt, 238 &info->fb_vbase); 239 #elif defined(__sparc64__) 240 OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase); 241 sc->sc_memt = &vt_efb_memt[0]; 242 info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase, 243 sc->sc_memt); 244 #else 245 bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 246 BUS_SPACE_MAP_PREFETCHABLE, 247 (bus_space_handle_t *)&info->fb_vbase); 248 #endif 249 } 250 251 252 /* blank full size */ 253 len = info->fb_size / 4; 254 for (i = 0; i < len; i++) { 255 ((uint32_t *)info->fb_vbase)[i] = 0; 256 } 257 258 /* Get pixel storage size. */ 259 info->fb_bpp = info->fb_stride / info->fb_width * 8; 260 261 /* 262 * Early FB driver work with static window buffer 80x25, so reduce 263 * size to 640x480. 264 */ 265 info->fb_width = VT_FB_DEFAULT_WIDTH; 266 info->fb_height = VT_FB_DEFAULT_HEIGHT; 267 268 #ifdef FDT 269 vt_efb_initialize(info, node); 270 #else 271 vt_efb_initialize(info); 272 #endif 273 fb_probe(info); 274 vt_fb_init(vd); 275 276 277 return (CN_INTERNAL); 278 } 279