firmware: coreboot: Add coreboot framebuffer driver
authorSamuel Holland <samuel@sholland.org>
Thu, 25 Jan 2018 01:41:20 +0000 (19:41 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 23 Apr 2018 11:37:19 +0000 (13:37 +0200)
Register a simplefb framebuffer when the coreboot table contains a
framebuffer entry.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/firmware/google/Kconfig
drivers/firmware/google/Makefile
drivers/firmware/google/coreboot_table.h
drivers/firmware/google/framebuffer-coreboot.c [new file with mode: 0644]

index f16b381a569cb2a59bec2c1b7032acc1fd2ceee1..a456a000048b9fc4e3761626328f3d42475be848 100644 (file)
@@ -55,6 +55,14 @@ config GOOGLE_MEMCONSOLE_X86_LEGACY
          the EBDA on Google servers.  If found, this log is exported to
          userland in the file /sys/firmware/log.
 
+config GOOGLE_FRAMEBUFFER_COREBOOT
+       tristate "Coreboot Framebuffer"
+       depends on FB_SIMPLE
+       depends on GOOGLE_COREBOOT_TABLE
+       help
+         This option enables the kernel to search for a framebuffer in
+         the coreboot table.  If found, it is registered with simplefb.
+
 config GOOGLE_MEMCONSOLE_COREBOOT
        tristate "Firmware Memory Console"
        depends on GOOGLE_COREBOOT_TABLE
index dcd3675efcfc72f5cc7e68f6e1b0fa50531c8fac..d0b3fba961947cd9036d63f46c47bf7a29ec400d 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_GOOGLE_SMI)                += gsmi.o
 obj-$(CONFIG_GOOGLE_COREBOOT_TABLE)        += coreboot_table.o
 obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI)   += coreboot_table-acpi.o
 obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF)     += coreboot_table-of.o
+obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT)  += framebuffer-coreboot.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE)            += memconsole.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT)   += memconsole-coreboot.o
 obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
index 26a3f3f3ac9cee12fe4e80dd13cfe297a2526646..8ad95a94481b6e1511ae2e0cf1fd7c362940fd27 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Internal header for coreboot table access.
  *
+ * Copyright 2014 Gerd Hoffmann <kraxel@redhat.com>
  * Copyright 2017 Google Inc.
  * Copyright 2017 Samuel Holland <samuel@sholland.org>
  *
@@ -46,12 +47,33 @@ struct lb_cbmem_ref {
        u64 cbmem_addr;
 };
 
+/* Describes framebuffer setup by coreboot */
+struct lb_framebuffer {
+       u32 tag;
+       u32 size;
+
+       u64 physical_address;
+       u32 x_resolution;
+       u32 y_resolution;
+       u32 bytes_per_line;
+       u8  bits_per_pixel;
+       u8  red_mask_pos;
+       u8  red_mask_size;
+       u8  green_mask_pos;
+       u8  green_mask_size;
+       u8  blue_mask_pos;
+       u8  blue_mask_size;
+       u8  reserved_mask_pos;
+       u8  reserved_mask_size;
+};
+
 /* A device, additionally with information from coreboot. */
 struct coreboot_device {
        struct device dev;
        union {
                struct coreboot_table_entry entry;
                struct lb_cbmem_ref cbmem_ref;
+               struct lb_framebuffer framebuffer;
        };
 };
 
diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c
new file mode 100644 (file)
index 0000000..b8b49c0
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * framebuffer-coreboot.c
+ *
+ * Memory based framebuffer accessed through coreboot table.
+ *
+ * Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ * Copyright 2017 Google Inc.
+ * Copyright 2017 Samuel Holland <samuel@sholland.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+
+#include "coreboot_table.h"
+
+#define CB_TAG_FRAMEBUFFER 0x12
+
+static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+
+static int framebuffer_probe(struct coreboot_device *dev)
+{
+       int i;
+       u32 length;
+       struct lb_framebuffer *fb = &dev->framebuffer;
+       struct platform_device *pdev;
+       struct resource res;
+       struct simplefb_platform_data pdata = {
+               .width = fb->x_resolution,
+               .height = fb->y_resolution,
+               .stride = fb->bytes_per_line,
+               .format = NULL,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (fb->bits_per_pixel     == formats[i].bits_per_pixel &&
+                   fb->red_mask_pos       == formats[i].red.offset &&
+                   fb->red_mask_size      == formats[i].red.length &&
+                   fb->green_mask_pos     == formats[i].green.offset &&
+                   fb->green_mask_size    == formats[i].green.length &&
+                   fb->blue_mask_pos      == formats[i].blue.offset &&
+                   fb->blue_mask_size     == formats[i].blue.length &&
+                   fb->reserved_mask_pos  == formats[i].transp.offset &&
+                   fb->reserved_mask_size == formats[i].transp.length)
+                       pdata.format = formats[i].name;
+       }
+       if (!pdata.format)
+               return -ENODEV;
+
+       memset(&res, 0, sizeof(res));
+       res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       res.name = "Coreboot Framebuffer";
+       res.start = fb->physical_address;
+       length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);
+       res.end = res.start + length - 1;
+       if (res.end <= res.start)
+               return -EINVAL;
+
+       pdev = platform_device_register_resndata(&dev->dev,
+                                                "simple-framebuffer", 0,
+                                                &res, 1, &pdata,
+                                                sizeof(pdata));
+       if (IS_ERR(pdev))
+               pr_warn("coreboot: could not register framebuffer\n");
+       else
+               dev_set_drvdata(&dev->dev, pdev);
+
+       return PTR_ERR_OR_ZERO(pdev);
+}
+
+static int framebuffer_remove(struct coreboot_device *dev)
+{
+       struct platform_device *pdev = dev_get_drvdata(&dev->dev);
+
+       platform_device_unregister(pdev);
+
+       return 0;
+}
+
+static struct coreboot_driver framebuffer_driver = {
+       .probe = framebuffer_probe,
+       .remove = framebuffer_remove,
+       .drv = {
+               .name = "framebuffer",
+       },
+       .tag = CB_TAG_FRAMEBUFFER,
+};
+
+static int __init coreboot_framebuffer_init(void)
+{
+       return coreboot_driver_register(&framebuffer_driver);
+}
+
+static void coreboot_framebuffer_exit(void)
+{
+       coreboot_driver_unregister(&framebuffer_driver);
+}
+
+module_init(coreboot_framebuffer_init);
+module_exit(coreboot_framebuffer_exit);
+
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_LICENSE("GPL");