Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Dec 2015 00:58:22 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r292483 - head/sys/arm/broadcom/bcm2835
Message-ID:  <201512200058.tBK0wM5g019482@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Sun Dec 20 00:58:22 2015
New Revision: 292483
URL: https://svnweb.freebsd.org/changeset/base/292483

Log:
  Add dev.fb.X.resync sysctl to resync ARM framebuffer with VideoCore
  
  Some applications (e.g. Kodi) use tvservice APIs to manage HDMI
  modes, power state, EDID etc. directly through VideoCore. After
  these manipulations VideoCore may loose its state and needs to be
  resynced with ARM. Under Linux this problem is worked around using
  fbset utility that recreates framebuffer. Since there is no fbset
  utility in FreeBSD we provide sysctl for userland apps to get system
  back into normal mode.

Modified:
  head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c

Modified: head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c
==============================================================================
--- head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c	Sun Dec 20 00:45:34 2015	(r292482)
+++ head/sys/arm/broadcom/bcm2835/bcm2835_fbd.c	Sun Dec 20 00:58:22 2015	(r292483)
@@ -59,13 +59,130 @@ __FBSDID("$FreeBSD$");
 #define	FB_DEPTH		24
 
 struct bcmsc_softc {
-	struct fb_info 		*info;
+	struct fb_info 			info;
+	int				fbswap;
+	struct bcm2835_fb_config	fb;
+	device_t			dev;
 };
 
 static int bcm_fb_probe(device_t);
 static int bcm_fb_attach(device_t);
 
 static int
+bcm_fb_init(struct bcmsc_softc *sc, struct bcm2835_fb_config *fb)
+{
+	int err;
+
+	err = 0;
+
+	memset(fb, 0, sizeof(*fb));
+	if (bcm2835_mbox_fb_get_w_h(fb) != 0)
+		return (ENXIO);
+	fb->bpp = FB_DEPTH;
+
+	if ((err = bcm2835_mbox_fb_init(fb)) != 0) {
+		device_printf(sc->dev, "bcm2835_mbox_fb_init failed, err=%d\n", err);
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+bcm_fb_setup_fbd(struct bcmsc_softc *sc)
+{
+	struct bcm2835_fb_config fb;
+	device_t fbd;
+	int err;
+
+	err = bcm_fb_init(sc, &fb);
+	if (err)
+		return (err);
+
+	memset(&sc->info, 0, sizeof(sc->info));
+	sc->info.fb_name = device_get_nameunit(sc->dev);
+
+	sc->info.fb_vbase = (intptr_t)pmap_mapdev(fb.base, fb.size);
+	sc->info.fb_pbase = fb.base;
+	sc->info.fb_size = fb.size;
+	sc->info.fb_bpp = sc->info.fb_depth = fb.bpp;
+	sc->info.fb_stride = fb.pitch;
+	sc->info.fb_width = fb.xres;
+	sc->info.fb_height = fb.yres;
+
+	if (sc->fbswap) {
+		switch (sc->info.fb_bpp) {
+		case 24:
+			vt_generate_cons_palette(sc->info.fb_cmap,
+			    COLOR_FORMAT_RGB, 0xff, 0, 0xff, 8, 0xff, 16);
+			sc->info.fb_cmsize = 16;
+			break;
+		case 32:
+			vt_generate_cons_palette(sc->info.fb_cmap,
+			    COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0);
+			sc->info.fb_cmsize = 16;
+			break;
+		}
+	}
+
+	fbd = device_add_child(sc->dev, "fbd", device_get_unit(sc->dev));
+	if (fbd == NULL) {
+		device_printf(sc->dev, "Failed to add fbd child\n");
+		pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size);
+		return (ENXIO);
+	} else if (device_probe_and_attach(fbd) != 0) {
+		device_printf(sc->dev, "Failed to attach fbd device\n");
+		device_delete_child(sc->dev, fbd);
+		pmap_unmapdev(sc->info.fb_vbase, sc->info.fb_size);
+		return (ENXIO);
+	}
+
+	device_printf(sc->dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
+	    fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
+	device_printf(sc->dev,
+	    "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
+	    sc->fbswap, fb.pitch, fb.base, fb.size);
+
+	return (0);
+}
+
+static int
+bcm_fb_resync_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct bcmsc_softc *sc = arg1;
+	struct bcm2835_fb_config fb;
+	int val;
+	int err;
+
+	val = 0;
+	err = sysctl_handle_int(oidp, &val, 0, req);
+	if (err || !req->newptr) /* error || read request */
+		return (err);
+
+	bcm_fb_init(sc, &fb);
+
+	return (0);
+}
+
+static void
+bcm_fb_sysctl_init(struct bcmsc_softc *sc)
+{
+	struct sysctl_ctx_list *ctx;
+	struct sysctl_oid *tree_node;
+	struct sysctl_oid_list *tree;
+
+	/*
+	 * Add system sysctl tree/handlers.
+	 */
+	ctx = device_get_sysctl_ctx(sc->dev);
+	tree_node = device_get_sysctl_tree(sc->dev);
+	tree = SYSCTL_CHILDREN(tree_node);
+	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "resync",
+	    CTLFLAG_RW | CTLTYPE_UINT, sc, sizeof(*sc),
+	    bcm_fb_resync_sysctl, "IU", "Set to resync framebuffer with VC");
+}
+
+static int
 bcm_fb_probe(device_t dev)
 {
 	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-fb"))
@@ -80,36 +197,15 @@ static int
 bcm_fb_attach(device_t dev)
 {
 	char bootargs[2048], *n, *p, *v;
-	device_t fbd;
-	int fbswap, err;
+	int err;
 	phandle_t chosen;
-	struct bcm2835_fb_config fb;
 	struct bcmsc_softc *sc;
-	struct fb_info *info;
 
 	sc = device_get_softc(dev);
-	memset(&fb, 0, sizeof(fb));
-	if (bcm2835_mbox_fb_get_w_h(&fb) != 0)
-		return (ENXIO);
-	fb.bpp = FB_DEPTH;
-	if ((err = bcm2835_mbox_fb_init(&fb)) != 0) {
-		device_printf(dev, "bcm2835_mbox_fb_init failed, err=%d\n", err);
-		return (ENXIO);
-	}
-
-	info = malloc(sizeof(struct fb_info), M_DEVBUF, M_WAITOK | M_ZERO);
-	info->fb_name = device_get_nameunit(dev);
-	info->fb_vbase = (intptr_t)pmap_mapdev(fb.base, fb.size);
-	info->fb_pbase = fb.base;
-	info->fb_size = fb.size;
-	info->fb_bpp = info->fb_depth = fb.bpp;
-	info->fb_stride = fb.pitch;
-	info->fb_width = fb.xres;
-	info->fb_height = fb.yres;
-	sc->info = info;
+	sc->dev = dev;
 
 	/* Newer firmware versions needs an inverted color palette. */
-	fbswap = 0;
+	sc->fbswap = 0;
 	chosen = OF_finddevice("/chosen");
 	if (chosen != 0 &&
 	    OF_getprop(chosen, "bootargs", &bootargs, sizeof(bootargs)) > 0) {
@@ -120,41 +216,15 @@ bcm_fb_attach(device_t dev)
 			n = strsep(&v, "=");
 			if (strcmp(n, "bcm2708_fb.fbswap") == 0 && v != NULL)
 				if (*v == '1')
-					fbswap = 1;
+					sc->fbswap = 1;
                 }
         }
-	if (fbswap) {
-		switch (info->fb_bpp) {
-		case 24:
-			vt_generate_cons_palette(info->fb_cmap,
-			    COLOR_FORMAT_RGB, 0xff, 0, 0xff, 8, 0xff, 16);
-			info->fb_cmsize = 16;
-			break;
-		case 32:
-			vt_generate_cons_palette(info->fb_cmap,
-			    COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0);
-			info->fb_cmsize = 16;
-			break;
-		}
-	}
 
-	fbd = device_add_child(dev, "fbd", device_get_unit(dev));
-	if (fbd == NULL) {
-		device_printf(dev, "Failed to add fbd child\n");
-		free(info, M_DEVBUF);
-		return (ENXIO);
-	} else if (device_probe_and_attach(fbd) != 0) {
-		device_printf(dev, "Failed to attach fbd device\n");
-		device_delete_child(dev, fbd);
-		free(info, M_DEVBUF);
-		return (ENXIO);
-	}
+	bcm_fb_sysctl_init(sc);
 
-	device_printf(dev, "%dx%d(%dx%d@%d,%d) %dbpp\n", fb.xres, fb.yres,
-	    fb.vxres, fb.vyres, fb.xoffset, fb.yoffset, fb.bpp);
-	device_printf(dev,
-	    "fbswap: %d, pitch %d, base 0x%08x, screen_size %d\n",
-	    fbswap, fb.pitch, fb.base, fb.size);
+	err = bcm_fb_setup_fbd(sc);
+	if (err)
+		return (err);
 
 	return (0);
 }
@@ -166,7 +236,7 @@ bcm_fb_helper_getinfo(device_t dev)
 
 	sc = device_get_softc(dev);
 
-	return (sc->info);
+	return (&sc->info);
 }
 
 static device_method_t bcm_fb_methods[] = {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201512200058.tBK0wM5g019482>