vt_early_fb.c revision 265397
1257726Sray/*- 2257726Sray * Copyright (c) 2013 The FreeBSD Foundation 3257726Sray * All rights reserved. 4257726Sray * 5257726Sray * This software was developed by Aleksandr Rybalko under sponsorship from the 6257726Sray * FreeBSD Foundation. 7257726Sray * 8257726Sray * Redistribution and use in source and binary forms, with or without 9257726Sray * modification, are permitted provided that the following conditions 10257726Sray * are met: 11257726Sray * 1. Redistributions of source code must retain the above copyright 12257726Sray * notice, this list of conditions and the following disclaimer. 13257726Sray * 2. Redistributions in binary form must reproduce the above copyright 14257726Sray * notice, this list of conditions and the following disclaimer in the 15257726Sray * documentation and/or other materials provided with the distribution. 16257726Sray * 17257726Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18257726Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19257726Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20257726Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21257726Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22257726Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23257726Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24257726Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25257726Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26257726Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27257726Sray * SUCH DAMAGE. 28257726Sray * 29257726Sray * $FreeBSD: head/sys/dev/vt/hw/fb/vt_early_fb.c 265397 2014-05-05 21:48:19Z ray $ 30257726Sray */ 31257726Sray 32257726Sray#include <sys/cdefs.h> 33257726Sray__FBSDID("$FreeBSD: head/sys/dev/vt/hw/fb/vt_early_fb.c 265397 2014-05-05 21:48:19Z ray $"); 34257726Sray 35257726Sray#include <sys/param.h> 36257726Sray#include <sys/systm.h> 37257726Sray#include <sys/kernel.h> 38257726Sray#include <sys/fbio.h> 39257726Sray 40257726Sray#include "opt_platform.h" 41257726Sray 42257726Sray#ifdef FDT 43257726Sray#include <dev/fdt/fdt_common.h> 44257726Sray#include <dev/ofw/ofw_bus.h> 45257726Sray#include <dev/ofw/ofw_bus_subr.h> 46257726Sray#include <dev/ofw/ofw_pci.h> 47264182Srpaulo#include <machine/fdt.h> 48257726Sray#endif 49257726Sray 50257726Sray#include <dev/vt/vt.h> 51257726Sray#include <dev/vt/hw/fb/vt_fb.h> 52257726Sray#include <dev/vt/colors/vt_termcolors.h> 53257726Sray 54257726Sraystatic vd_init_t vt_efb_init; 55265397Sraystatic vd_probe_t vt_efb_probe; 56257726Sray 57257726Sraystatic struct vt_driver vt_fb_early_driver = { 58265397Sray .vd_name = "efb", 59265397Sray .vd_probe = vt_efb_probe, 60257726Sray .vd_init = vt_efb_init, 61257726Sray .vd_blank = vt_fb_blank, 62257726Sray .vd_bitbltchr = vt_fb_bitbltchr, 63257726Sray .vd_priority = VD_PRIORITY_GENERIC, 64257726Sray}; 65257726Sray 66265397Sraystatic struct fb_info local_info; 67265397SrayVT_DRIVER_DECLARE(vt_efb, vt_fb_early_driver); 68257726Sray 69257726Sraystatic void 70257726Sray#ifdef FDT 71257726Srayvt_efb_initialize(struct fb_info *info, phandle_t node) 72257726Sray#else 73257726Srayvt_efb_initialize(struct fb_info *info) 74257726Sray#endif 75257726Sray{ 76257726Sray#ifdef FDT 77257726Sray char name[64]; 78257726Sray cell_t retval; 79257726Sray ihandle_t ih; 80257726Sray int i; 81257726Sray 82257726Sray /* Open display device, thereby initializing it */ 83257726Sray memset(name, 0, sizeof(name)); 84257726Sray OF_package_to_path(node, name, sizeof(name)); 85257726Sray ih = OF_open(name); 86257726Sray#endif 87257726Sray 88257726Sray /* 89257726Sray * Set up the color map 90257726Sray */ 91257726Sray switch (info->fb_depth) { 92257726Sray case 8: 93257726Sray vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 94257726Sray 0x7, 5, 0x7, 2, 0x3, 0); 95257726Sray break; 96257726Sray case 15: 97257726Sray vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 98257726Sray 0x1f, 10, 0x1f, 5, 0x1f, 0); 99257726Sray break; 100257726Sray case 16: 101257726Sray vt_generate_vga_palette(info->fb_cmap, COLOR_FORMAT_RGB, 102257726Sray 0x1f, 11, 0x3f, 5, 0x1f, 0); 103257726Sray break; 104257726Sray case 24: 105257726Sray case 32: 106257726Sray#if BYTE_ORDER == BIG_ENDIAN 107257726Sray vt_generate_vga_palette(info->fb_cmap, 108257726Sray COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); 109257726Sray#else 110257726Sray vt_generate_vga_palette(info->fb_cmap, 111257726Sray COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); 112257726Sray#endif 113257726Sray#ifdef FDT 114257726Sray for (i = 0; i < 16; i++) { 115257726Sray OF_call_method("color!", ih, 4, 1, 116257726Sray (cell_t)((info->fb_cmap[i] >> 16) & 0xff), 117257726Sray (cell_t)((info->fb_cmap[i] >> 8) & 0xff), 118257726Sray (cell_t)((info->fb_cmap[i] >> 0) & 0xff), 119257726Sray (cell_t)i, &retval); 120257726Sray } 121257726Sray#endif 122257726Sray break; 123257726Sray 124257726Sray default: 125257726Sray panic("Unknown color space fb_depth %d", info->fb_depth); 126257726Sray break; 127257726Sray } 128257726Sray} 129257726Sray 130265397Sraystatic phandle_t 131265397Srayvt_efb_get_fbnode() 132257726Sray{ 133257726Sray phandle_t chosen, node; 134257726Sray ihandle_t stdout; 135257726Sray char type[64]; 136257726Sray 137257726Sray chosen = OF_finddevice("/chosen"); 138257726Sray OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); 139257726Sray node = OF_instance_to_package(stdout); 140265397Sray if (node != -1) { 141265397Sray /* The "/chosen/stdout" present. */ 142265397Sray OF_getprop(node, "device_type", type, sizeof(type)); 143265397Sray /* Check if it has "display" type. */ 144265397Sray if (strcmp(type, "display") == 0) 145265397Sray return (node); 146257726Sray } 147265397Sray /* Try device with name "screen". */ 148265397Sray node = OF_finddevice("screen"); 149265397Sray 150265397Sray return (node); 151265397Sray} 152265397Sray 153265397Sraystatic int 154265397Srayvt_efb_probe(struct vt_device *vd) 155265397Sray{ 156265397Sray phandle_t node; 157265397Sray 158265397Sray node = vt_efb_get_fbnode(); 159265397Sray if (node == -1) 160257726Sray return (CN_DEAD); 161257726Sray 162265397Sray if ((OF_getproplen(node, "height") <= 0) || 163265397Sray (OF_getproplen(node, "width") <= 0) || 164265397Sray (OF_getproplen(node, "depth") <= 0) || 165265397Sray (OF_getproplen(node, "linebytes") <= 0)) 166265397Sray return (CN_DEAD); 167265397Sray 168265397Sray return (CN_INTERNAL); 169265397Sray} 170265397Sray 171265397Sraystatic int 172265397Srayvt_efb_init(struct vt_device *vd) 173265397Sray{ 174265397Sray struct ofw_pci_register pciaddrs[8]; 175265397Sray struct fb_info *info; 176265397Sray int i, len, n_pciaddrs; 177265397Sray phandle_t node; 178265397Sray 179265397Sray if (vd->vd_softc == NULL) 180265397Sray vd->vd_softc = (void *)&local_info; 181265397Sray 182265397Sray info = vd->vd_softc; 183265397Sray 184265397Sray node = vt_efb_get_fbnode(); 185265397Sray if (node == -1) 186265397Sray return (CN_DEAD); 187265397Sray 188257726Sray#define GET(name, var) \ 189257726Sray if (OF_getproplen(node, (name)) != sizeof(info->fb_##var)) \ 190257726Sray return (CN_DEAD); \ 191257726Sray OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \ 192257726Sray if (info->fb_##var == 0) \ 193257726Sray return (CN_DEAD); 194257726Sray 195257726Sray GET("height", height) 196257726Sray GET("width", width) 197257726Sray GET("depth", depth) 198257726Sray GET("linebytes", stride) 199257726Sray#undef GET 200257726Sray 201257726Sray info->fb_size = info->fb_height * info->fb_stride; 202257726Sray 203257726Sray /* 204257726Sray * Get the PCI addresses of the adapter, if present. The node may be the 205257726Sray * child of the PCI device: in that case, try the parent for 206257726Sray * the assigned-addresses property. 207257726Sray */ 208257726Sray len = OF_getprop(node, "assigned-addresses", pciaddrs, 209257726Sray sizeof(pciaddrs)); 210257726Sray if (len == -1) { 211257726Sray len = OF_getprop(OF_parent(node), "assigned-addresses", 212257726Sray pciaddrs, sizeof(pciaddrs)); 213257726Sray } 214257726Sray if (len == -1) 215257726Sray len = 0; 216257726Sray n_pciaddrs = len / sizeof(struct ofw_pci_register); 217257726Sray 218257726Sray /* 219257726Sray * Grab the physical address of the framebuffer, and then map it 220257726Sray * into our memory space. If the MMU is not yet up, it will be 221257726Sray * remapped for us when relocation turns on. 222257726Sray */ 223257726Sray if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) { 224257726Sray /* XXX We assume #address-cells is 1 at this point. */ 225257726Sray OF_getencprop(node, "address", &info->fb_pbase, 226257726Sray sizeof(info->fb_pbase)); 227257726Sray 228257726Sray #if defined(__powerpc__) 229257726Sray sc->sc_memt = &bs_be_tag; 230257726Sray bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size, 231257726Sray BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase); 232257726Sray #elif defined(__sparc64__) 233257726Sray OF_decode_addr(node, 0, &space, &phys); 234257726Sray sc->sc_memt = &vt_efb_memt[0]; 235257726Sray info->addr = sparc64_fake_bustag(space, fb_phys, sc->sc_memt); 236257726Sray #else 237257726Sray bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 238257726Sray BUS_SPACE_MAP_PREFETCHABLE, 239257726Sray (bus_space_handle_t *)&info->fb_vbase); 240257726Sray #endif 241257726Sray } else { 242257726Sray /* 243257726Sray * Some IBM systems don't have an address property. Try to 244257726Sray * guess the framebuffer region from the assigned addresses. 245257726Sray * This is ugly, but there doesn't seem to be an alternative. 246257726Sray * Linux does the same thing. 247257726Sray */ 248257726Sray 249257726Sray info->fb_pbase = n_pciaddrs; 250257726Sray for (i = 0; i < n_pciaddrs; i++) { 251257726Sray /* If it is too small, not the framebuffer */ 252257726Sray if (pciaddrs[i].size_lo < info->fb_size) 253257726Sray continue; 254257726Sray /* If it is not memory, it isn't either */ 255257726Sray if (!(pciaddrs[i].phys_hi & 256257726Sray OFW_PCI_PHYS_HI_SPACE_MEM32)) 257257726Sray continue; 258257726Sray 259257726Sray /* This could be the framebuffer */ 260257726Sray info->fb_pbase = i; 261257726Sray 262257726Sray /* If it is prefetchable, it certainly is */ 263257726Sray if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) 264257726Sray break; 265257726Sray } 266257726Sray 267257726Sray if (info->fb_pbase == n_pciaddrs) /* No candidates found */ 268257726Sray return (CN_DEAD); 269257726Sray 270257726Sray #if defined(__powerpc__) 271257726Sray OF_decode_addr(node, info->fb_pbase, &sc->sc_memt, 272257726Sray &info->fb_vbase); 273257726Sray #elif defined(__sparc64__) 274257726Sray OF_decode_addr(node, info->fb_pbase, &space, &info->fb_pbase); 275257726Sray sc->sc_memt = &vt_efb_memt[0]; 276257726Sray info->fb_vbase = sparc64_fake_bustag(space, info->fb_pbase, 277257726Sray sc->sc_memt); 278257726Sray #else 279257726Sray bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, 280257726Sray BUS_SPACE_MAP_PREFETCHABLE, 281257726Sray (bus_space_handle_t *)&info->fb_vbase); 282257726Sray #endif 283257726Sray } 284257726Sray 285257726Sray /* blank full size */ 286257726Sray len = info->fb_size / 4; 287257726Sray for (i = 0; i < len; i++) { 288257726Sray ((uint32_t *)info->fb_vbase)[i] = 0; 289257726Sray } 290257726Sray 291257726Sray /* Get pixel storage size. */ 292257726Sray info->fb_bpp = info->fb_stride / info->fb_width * 8; 293257726Sray 294257726Sray /* 295257726Sray * Early FB driver work with static window buffer 80x25, so reduce 296257726Sray * size to 640x480. 297257726Sray */ 298257726Sray info->fb_width = VT_FB_DEFAULT_WIDTH; 299257726Sray info->fb_height = VT_FB_DEFAULT_HEIGHT; 300257726Sray 301257726Sray#ifdef FDT 302257726Sray vt_efb_initialize(info, node); 303257726Sray#else 304257726Sray vt_efb_initialize(info); 305257726Sray#endif 306257726Sray fb_probe(info); 307257726Sray vt_fb_init(vd); 308257726Sray 309257726Sray return (CN_INTERNAL); 310257726Sray} 311