bcm2835_fbd.c revision 298383
1239709Srwatson/*- 2239709Srwatson * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3239709Srwatson * Copyright (c) 2012, 2013 The FreeBSD Foundation 4239709Srwatson * All rights reserved. 5239709Srwatson * 6239709Srwatson * Portions of this software were developed by Oleksandr Rybalko 7239709Srwatson * under sponsorship from the FreeBSD Foundation. 8239709Srwatson * 9239709Srwatson * Redistribution and use in source and binary forms, with or without 10239709Srwatson * modification, are permitted provided that the following conditions 11239709Srwatson * are met: 12239709Srwatson * 1. Redistributions of source code must retain the above copyright 13239709Srwatson * notice, this list of conditions and the following disclaimer. 14239709Srwatson * 2. Redistributions in binary form must reproduce the above copyright 15239709Srwatson * notice, this list of conditions and the following disclaimer in the 16239709Srwatson * documentation and/or other materials provided with the distribution. 17239709Srwatson * 18239709Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19239709Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20239709Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21239709Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22239709Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23239709Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24239709Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25239709Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26239709Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27239709Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28239709Srwatson * SUCH DAMAGE. 29239709Srwatson * 30239709Srwatson */ 31239709Srwatson#include <sys/cdefs.h> 32239709Srwatson__FBSDID("$FreeBSD: head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c 298383 2016-04-20 22:38:00Z gonzo $"); 33239709Srwatson 34239709Srwatson#include <sys/param.h> 35239709Srwatson#include <sys/systm.h> 36239709Srwatson#include <sys/bio.h> 37239709Srwatson#include <sys/bus.h> 38239709Srwatson#include <sys/fbio.h> 39239709Srwatson#include <sys/kernel.h> 40239709Srwatson#include <sys/malloc.h> 41239709Srwatson#include <sys/module.h> 42239709Srwatson 43239709Srwatson#include <vm/vm.h> 44239709Srwatson#include <vm/pmap.h> 45239709Srwatson 46245380Srwatson#include <dev/fdt/fdt_common.h> 47245380Srwatson#include <dev/ofw/ofw_bus.h> 48239709Srwatson#include <dev/ofw/ofw_bus_subr.h> 49239709Srwatson 50239709Srwatson#include <dev/fb/fbreg.h> 51239709Srwatson#include <dev/vt/vt.h> 52239709Srwatson#include <dev/vt/colors/vt_termcolors.h> 53239709Srwatson 54239709Srwatson#include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h> 55239709Srwatson 56239709Srwatson#include "fb_if.h" 57239709Srwatson#include "mbox_if.h" 58239709Srwatson 59239709Srwatson#define FB_DEPTH 24 60239709Srwatson 61239709Srwatsonstruct bcmsc_softc { 62239709Srwatson struct fb_info info; 63239709Srwatson int fbswap; 64239709Srwatson struct bcm2835_fb_config fb; 65239709Srwatson device_t dev; 66239709Srwatson}; 67239709Srwatson 68239709Srwatsonstatic int bcm_fb_probe(device_t); 69239709Srwatsonstatic int bcm_fb_attach(device_t); 70239709Srwatson 71239709Srwatsonstatic int 72239709Srwatsonbcm_fb_init(struct bcmsc_softc *sc, struct bcm2835_fb_config *fb) 73239709Srwatson{ 74239709Srwatson int err; 75239709Srwatson 76239709Srwatson err = 0; 77239709Srwatson 78239709Srwatson memset(fb, 0, sizeof(*fb)); 79239709Srwatson if (bcm2835_mbox_fb_get_w_h(fb) != 0) 80239709Srwatson return (ENXIO); 81239709Srwatson fb->bpp = FB_DEPTH; 82239709Srwatson 83239709Srwatson fb->vxres = fb->xres; 84239709Srwatson fb->vyres = fb->yres; 85239709Srwatson fb->xoffset = fb->yoffset = 0; 86239709Srwatson 87239709Srwatson if ((err = bcm2835_mbox_fb_init(fb)) != 0) { 88239709Srwatson device_printf(sc->dev, "bcm2835_mbox_fb_init failed, err=%d\n", err); 89239709Srwatson return (ENXIO); 90239709Srwatson } 91239709Srwatson 92239709Srwatson return (0); 93239709Srwatson} 94239709Srwatson 95239709Srwatsonstatic int 96239709Srwatsonbcm_fb_setup_fbd(struct bcmsc_softc *sc) 97239709Srwatson{ 98239709Srwatson struct bcm2835_fb_config fb; 99239709Srwatson device_t fbd; 100239709Srwatson int err; 101239709Srwatson 102239709Srwatson err = bcm_fb_init(sc, &fb); 103239709Srwatson if (err) 104239709Srwatson return (err); 105239709Srwatson 106239709Srwatson memset(&sc->info, 0, sizeof(sc->info)); 107239709Srwatson sc->info.fb_name = device_get_nameunit(sc->dev); 108239709Srwatson 109239709Srwatson sc->info.fb_vbase = (intptr_t)pmap_mapdev(fb.base, fb.size); 110239709Srwatson sc->info.fb_pbase = fb.base; 111239709Srwatson sc->info.fb_size = fb.size; 112239709Srwatson sc->info.fb_bpp = sc->info.fb_depth = fb.bpp; 113239709Srwatson sc->info.fb_stride = fb.pitch; 114239709Srwatson sc->info.fb_width = fb.xres; 115239709Srwatson sc->info.fb_height = fb.yres; 116239709Srwatson 117239709Srwatson if (sc->fbswap) { 118239709Srwatson switch (sc->info.fb_bpp) { 119239709Srwatson case 24: 120239709Srwatson vt_generate_cons_palette(sc->info.fb_cmap, 121239709Srwatson COLOR_FORMAT_RGB, 0xff, 0, 0xff, 8, 0xff, 16); 122239709Srwatson sc->info.fb_cmsize = 16; 123239709Srwatson break; 124239709Srwatson case 32: 125239709Srwatson vt_generate_cons_palette(sc->info.fb_cmap, 126239709Srwatson COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0); 127239709Srwatson sc->info.fb_cmsize = 16; 128239709Srwatson break; 129239709Srwatson } 130239709Srwatson } 131239709Srwatson 132239709Srwatson fbd = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev)); 133239709Srwatson if (fbd == NULL) { 134239709Srwatson device_printf(sc->dev, "Failed to add fbd child\n"); 135239709Srwatson pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size); 136239709Srwatson return (ENXIO); 137239709Srwatson } else if (device_probe_and_attach(fbd) != 0) { 138239709Srwatson device_printf(sc->dev, "Failed to attach fbd device\n"); 139239709Srwatson device_delete_child(sc->dev, fbd); 140239709Srwatson pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size); 141239709Srwatson return (ENXIO); 142239709Srwatson } 143239709Srwatson 144239709Srwatson device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres, 145239709Srwatson fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp); 146239709Srwatson device_printf(sc->dev, 147239709Srwatson "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n", 148239709Srwatson sc->fbswap, fb.pitch, fb.base, fb.size); 149239709Srwatson 150239709Srwatson return (0); 151239709Srwatson} 152239709Srwatson 153239709Srwatsonstatic int 154239709Srwatsonbcm_fb_resync_sysctl(SYSCTL_HANDLER_ARGS) 155239709Srwatson{ 156239709Srwatson struct bcmsc_softc *sc = arg1; 157239709Srwatson struct bcm2835_fb_config fb; 158239709Srwatson int val; 159239709Srwatson int err; 160239709Srwatson 161239709Srwatson val = 0; 162239709Srwatson err = sysctl_handle_int(oidp, &val, 0, req); 163239709Srwatson if (err || !req->newptr) /* error || read request */ 164239709Srwatson return (err); 165239709Srwatson 166239709Srwatson bcm_fb_init(sc, &fb); 167239709Srwatson 168239709Srwatson return (0); 169239709Srwatson} 170239709Srwatson 171239709Srwatsonstatic void 172239709Srwatsonbcm_fb_sysctl_init(struct bcmsc_softc *sc) 173239709Srwatson{ 174239709Srwatson struct sysctl_ctx_list *ctx; 175239709Srwatson struct sysctl_oid *tree_node; 176239709Srwatson struct sysctl_oid_list *tree; 177239709Srwatson 178239709Srwatson /* 179239709Srwatson * Add system sysctl tree/handlers. 180239709Srwatson */ 181239709Srwatson ctx = device_get_sysctl_ctx(sc->dev); 182239709Srwatson tree_node = device_get_sysctl_tree(sc->dev); 183239709Srwatson tree = SYSCTL_CHILDREN(tree_node); 184239709Srwatson SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "resync", 185239709Srwatson CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc), 186239709Srwatson bcm_fb_resync_sysctl, "IU", "Set to resync framebuffer with VC"); 187239709Srwatson} 188239709Srwatson 189239709Srwatsonstatic int 190239709Srwatsonbcm_fb_probe(device_t dev) 191{ 192 if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb")) 193 return (ENXIO); 194 195 device_set_desc(dev, "BCM2835 VT framebuffer driver"); 196 197 return (BUS_PROBE_DEFAULT); 198} 199 200static int 201bcm_fb_attach(device_t dev) 202{ 203 char bootargs[2048], *n, *p, *v; 204 int err; 205 phandle_t chosen; 206 struct bcmsc_softc *sc; 207 208 sc = device_get_softc(dev); 209 sc->dev = dev; 210 211 /* Newer firmware versions needs an inverted color palette. */ 212 sc->fbswap = 0; 213 chosen = OF_finddevice("/chosen"); 214 if (chosen != 0 && 215 OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) { 216 p = bootargs; 217 while ((v = strsep(&p, " ")) != NULL) { 218 if (*v == '\0') 219 continue; 220 n = strsep(&v, "="); 221 if (strcmp(n, "bcm2708_fb.fbswap") == 0 && v != NULL) 222 if (*v == '1') 223 sc->fbswap = 1; 224 } 225 } 226 227 bcm_fb_sysctl_init(sc); 228 229 err = bcm_fb_setup_fbd(sc); 230 if (err) 231 return (err); 232 233 return (0); 234} 235 236static struct fb_info * 237bcm_fb_helper_getinfo(device_t dev) 238{ 239 struct bcmsc_softc *sc; 240 241 sc = device_get_softc(dev); 242 243 return (&sc->info); 244} 245 246static device_method_t bcm_fb_methods[] = { 247 /* Device interface */ 248 DEVMETHOD(device_probe, bcm_fb_probe), 249 DEVMETHOD(device_attach, bcm_fb_attach), 250 251 /* Framebuffer service methods */ 252 DEVMETHOD(fb_getinfo, bcm_fb_helper_getinfo), 253 254 DEVMETHOD_END 255}; 256 257static devclass_t bcm_fb_devclass; 258 259static driver_t bcm_fb_driver = { 260 "fb", 261 bcm_fb_methods, 262 sizeof(struct bcmsc_softc), 263}; 264 265DRIVER_MODULE(bcm2835fb, ofwbus, bcm_fb_driver, bcm_fb_devclass, 0, 0); 266