Here is a fun little driver that supports the framebuffer that u-boot
sets up for us on the sunxi platform.  The mainbus(4) changes are
necessary, because the framebuffer device tree node actually lives
under /chosen, so we don't pick it up during the normal device tree
walk.  The most common 15/16 bpp, 24 bpp and 32 bpp modes are
supported, although I think u-boot always uses 32 bpp on sunxi
hardware.  No console support (yet) so simplefb is not added to
RAMDISK kernels.

On other plaforms (imx for example) u-boot does set up the
framebuffer, but doesn't add the appropriate simplefb nodes to the
device tree.  That could be added though and I wouldn't expect this to
be a big effort.

ok?


Index: arch/arm/mainbus/mainbus.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/mainbus/mainbus.c,v
retrieving revision 1.13
diff -u -p -r1.13 mainbus.c
--- arch/arm/mainbus/mainbus.c  6 Aug 2016 00:04:39 -0000       1.13
+++ arch/arm/mainbus/mainbus.c  2 Jan 2017 22:07:42 -0000
@@ -30,6 +30,7 @@ int mainbus_match(struct device *, void 
 void mainbus_attach(struct device *, struct device *, void *);
 
 void mainbus_attach_node(struct device *, int);
+void mainbus_attach_framebuffer(struct device *);
 
 int mainbus_legacy_search(struct device *, void *, void *);
 
@@ -133,12 +134,10 @@ mainbus_attach(struct device *parent, st
        }
 
        /* Scan the whole tree. */
-       for (node = OF_child(node);
-           node != 0;
-           node = OF_peer(node))
-       {
+       for (node = OF_child(node); node != 0; node = OF_peer(node))
                mainbus_attach_node(self, node);
-       }
+
+       mainbus_attach_framebuffer(self);
 }
 
 /*
@@ -212,6 +211,18 @@ mainbus_attach_node(struct device *self,
 
        free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
        free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
+}
+
+void
+mainbus_attach_framebuffer(struct device *self)
+{
+       int node = OF_finddevice("/chosen");
+
+       if (node == 0)
+               return;
+
+       for (node = OF_child(node); node != 0; node = OF_peer(node))
+               mainbus_attach_node(self, node);
 }
 
 /*
Index: arch/armv7/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v
retrieving revision 1.69
diff -u -p -r1.69 GENERIC
--- arch/armv7/conf/GENERIC     23 Oct 2016 18:50:34 -0000      1.69
+++ arch/armv7/conf/GENERIC     2 Jan 2017 22:07:42 -0000
@@ -108,6 +108,9 @@ virtio*             at fdt?
 
 psci*          at fdt?
 
+simplefb*      at fdt?
+wsdisplay*     at simplefb?
+
 # Exynos
 exynos0                at mainbus?
 exdisplay*     at exynos?
Index: arch/armv7/conf/files.armv7
===================================================================
RCS file: /cvs/src/sys/arch/armv7/conf/files.armv7,v
retrieving revision 1.28
diff -u -p -r1.28 files.armv7
--- arch/armv7/conf/files.armv7 9 Oct 2016 23:46:23 -0000       1.28
+++ arch/armv7/conf/files.armv7 2 Jan 2017 22:07:42 -0000
@@ -65,6 +65,9 @@ include "dev/gpio/files.gpio"
 # Machine-independent 1-Wire drivers
 include "dev/onewire/files.onewire"
 
+# Machine-independent FDT drivers
+include "dev/fdt/files.fdt"
+
 # SoC includes
 include "arch/armv7/imx/files.imx"
 include "arch/armv7/omap/files.omap"
Index: dev/fdt/files.fdt
===================================================================
RCS file: dev/fdt/files.fdt
diff -N dev/fdt/files.fdt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/fdt/files.fdt   2 Jan 2017 22:07:45 -0000
@@ -0,0 +1,8 @@
+#      $OpenBSD$
+#
+# Config file and device description for machine-independent FDT code.
+# Included by ports that need it.
+
+device simplefb: wsemuldisplaydev, rasops15, rasops16, rasops24, rasops32
+attach simplefb at fdt
+file   dev/fdt/simplefb.c              simplefb
Index: dev/fdt/simplefb.c
===================================================================
RCS file: dev/fdt/simplefb.c
diff -N dev/fdt/simplefb.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/fdt/simplefb.c  2 Jan 2017 22:07:45 -0000
@@ -0,0 +1,243 @@
+/*     $OpenBSD$       */
+/*
+ * Copyright (c) 2016 Mark Kettenis
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/fdt.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+
+struct simplefb_format {
+       const char *format;
+       int depth;
+       int rpos, rnum;
+       int gpos, gnum;
+       int bpos, bnum;
+};
+
+/*
+ * Supported pixel formats.  Layout ommitted when it matches the
+ * rasops defaults.
+ */
+struct simplefb_format simplefb_formats[] = {
+       { "r5g6b5", 16 },
+       { "x1r5g5b5", 15 },
+       { "a1r5g5b5", 15 },
+       { "r8g8b8", 24 },
+       { "x8r8g8b8", 32 },
+       { "a8r8g8b8", 32 },
+       { "a8b8g8r8", 32, 0, 8, 8, 8, 16, 8 }
+};
+
+struct simplefb_softc {
+       struct device           sc_dev;
+       bus_space_tag_t         sc_iot;
+       bus_space_handle_t      sc_ioh;
+
+       struct rasops_info      sc_ri;
+       struct wsscreen_descr   sc_wsd;
+       struct wsscreen_list    sc_wsl;
+       struct wsscreen_descr   *sc_scrlist[1];
+
+       struct simplefb_format  *sc_format;
+       paddr_t                 sc_paddr;
+       psize_t                 sc_psize;
+};
+
+int    simplefb_match(struct device *, void *, void *);
+void   simplefb_attach(struct device *, struct device *, void *);
+
+struct cfattach simplefb_ca = {
+       sizeof(struct simplefb_softc), simplefb_match, simplefb_attach
+};
+
+struct cfdriver simplefb_cd = {
+       NULL, "simplefb", DV_DULL
+};
+
+int    simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t        simplefb_wsmmap(void *, off_t, int);
+int    simplefb_alloc_screen(void *, const struct wsscreen_descr *,
+           void **, int *, int *, long *);
+
+struct wsdisplay_accessops simplefb_accessops = {
+       .ioctl = simplefb_wsioctl,
+       .mmap = simplefb_wsmmap,
+       .alloc_screen = simplefb_alloc_screen,
+       .free_screen = rasops_free_screen,
+       .show_screen = rasops_show_screen,
+       .getchar = rasops_getchar,
+       .load_font = rasops_load_font,
+       .list_font = rasops_list_font,
+};
+
+int
+simplefb_match(struct device *parent, void *match, void *aux)
+{
+       struct fdt_attach_args *faa = aux;
+
+       return OF_is_compatible(faa->fa_node, "simple-framebuffer");
+}
+
+void
+simplefb_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct simplefb_softc *sc = (struct simplefb_softc *)self;
+       struct fdt_attach_args *faa = aux;
+       struct rasops_info *ri = &sc->sc_ri;
+       struct wsemuldisplaydev_attach_args waa;
+       char format[16];
+       int i;
+
+       if (faa->fa_nreg < 1)
+               return;
+
+       format[0] = 0;
+       OF_getprop(faa->fa_node, "format", format, sizeof(format));
+       format[sizeof(format) - 1] = 0;
+
+       for (i = 0; i < nitems(simplefb_formats); i++) {
+               if (strcmp(format, simplefb_formats[i].format) == 0) {
+                       sc->sc_format = &simplefb_formats[i];
+                       break;
+               }
+       }
+       if (sc->sc_format == NULL) {
+               printf(": unsupported format \"%s\"\n", format);
+               return;
+       }
+
+       sc->sc_iot = faa->fa_iot;
+       sc->sc_paddr = faa->fa_reg[0].addr;
+       sc->sc_psize = faa->fa_reg[0].size;
+       if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize,
+           BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh))
+               panic("%s: bus_space_map failed!", __func__);
+
+       ri->ri_width = OF_getpropint(faa->fa_node, "width", 0);
+       ri->ri_height = OF_getpropint(faa->fa_node, "height", 0);
+       ri->ri_stride = OF_getpropint(faa->fa_node, "stride", 0);
+       ri->ri_depth = sc->sc_format->depth;
+       ri->ri_rpos = sc->sc_format->rpos;
+       ri->ri_rnum = sc->sc_format->rnum;
+       ri->ri_gpos = sc->sc_format->gpos;
+       ri->ri_gnum = sc->sc_format->gnum;
+       ri->ri_bpos = sc->sc_format->bpos;
+       ri->ri_bnum = sc->sc_format->bnum;
+       ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR;
+       ri->ri_flg |= RI_VCONS | RI_WRONLY;
+       ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
+       ri->ri_hw = sc;
+
+       printf(": %dx%d\n", ri->ri_width, ri->ri_height);
+
+       rasops_init(ri, 160, 160);
+
+       strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
+       sc->sc_wsd.capabilities = ri->ri_caps;
+       sc->sc_wsd.nrows = ri->ri_rows;
+       sc->sc_wsd.ncols = ri->ri_cols;
+       sc->sc_wsd.textops = &ri->ri_ops;
+       sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
+       sc->sc_wsd.fontheight = ri->ri_font->fontheight;
+
+       sc->sc_scrlist[0] = &sc->sc_wsd;
+       sc->sc_wsl.nscreens = 1;
+       sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
+
+       memset(&waa, 0, sizeof(waa));
+       waa.scrdata = &sc->sc_wsl;
+       waa.accessops = &simplefb_accessops;
+       waa.accesscookie = ri;
+
+       config_found_sm(self, &waa, wsemuldisplaydevprint,
+           wsemuldisplaydevsubmatch);
+}
+
+int
+simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+       struct rasops_info *ri = v;
+       struct wsdisplay_fbinfo *wdf;
+
+       switch (cmd) {
+       case WSDISPLAYIO_GTYPE:
+               *(int *)data = WSDISPLAY_TYPE_EFIFB;
+               return 0;
+       case WSDISPLAYIO_GINFO:
+               wdf = (struct wsdisplay_fbinfo *)data;
+               wdf->width = ri->ri_width;
+               wdf->height = ri->ri_height;
+               wdf->depth = ri->ri_depth;
+               wdf->cmsize = 0;        /* color map is unavailable */
+               break;
+       case WSDISPLAYIO_LINEBYTES:
+               *(u_int *)data = ri->ri_stride;
+               break;
+       case WSDISPLAYIO_SMODE:
+               break;
+       case WSDISPLAYIO_GETSUPPORTEDDEPTH:
+               switch (ri->ri_depth) {
+               case 32:
+                       *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
+                       break;
+               case 24:
+                       *(u_int *)data = WSDISPLAYIO_DEPTH_24_24;
+                       break;
+               case 16:
+                       *(u_int *)data = WSDISPLAYIO_DEPTH_16;
+                       break;
+               case 15:
+                       *(u_int *)data = WSDISPLAYIO_DEPTH_15;
+                       break;
+               default:
+                       return -1;
+               }
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+paddr_t
+simplefb_wsmmap(void *v, off_t off, int prot)
+{
+       struct rasops_info *ri = v;
+       struct simplefb_softc *sc = ri->ri_hw;
+
+       if (off < 0 || off >= sc->sc_psize)
+               return -1;
+
+       return sc->sc_paddr + off;
+}
+
+int
+simplefb_alloc_screen(void *v, const struct wsscreen_descr *type,
+    void **cookiep, int *curxp, int *curyp, long *attrp)
+{
+       return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp);
+}

Reply via email to