summaryrefslogtreecommitdiff
path: root/drivers/firmware/google/memconsole-coreboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/google/memconsole-coreboot.c')
-rw-r--r--drivers/firmware/google/memconsole-coreboot.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c
new file mode 100644
index 000000000000..21210144def7
--- /dev/null
+++ b/drivers/firmware/google/memconsole-coreboot.c
@@ -0,0 +1,109 @@
+/*
+ * memconsole-coreboot.c
+ *
+ * Memory based BIOS console accessed through coreboot table.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "memconsole.h"
+#include "coreboot_table.h"
+
+#define CB_TAG_CBMEM_CONSOLE 0x17
+
+/* CBMEM firmware console log descriptor. */
+struct cbmem_cons {
+ u32 buffer_size;
+ u32 buffer_cursor;
+ u8 buffer_body[0];
+} __packed;
+
+static struct cbmem_cons __iomem *cbmem_console;
+
+static int memconsole_coreboot_init(phys_addr_t physaddr)
+{
+ struct cbmem_cons __iomem *tmp_cbmc;
+
+ tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB);
+
+ if (!tmp_cbmc)
+ return -ENOMEM;
+
+ cbmem_console = memremap(physaddr,
+ tmp_cbmc->buffer_size + sizeof(*cbmem_console),
+ MEMREMAP_WB);
+ memunmap(tmp_cbmc);
+
+ if (!cbmem_console)
+ return -ENOMEM;
+
+ memconsole_setup(cbmem_console->buffer_body,
+ min(cbmem_console->buffer_cursor, cbmem_console->buffer_size));
+
+ return 0;
+}
+
+static int memconsole_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct lb_cbmem_ref entry;
+
+ ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry));
+ if (ret)
+ return ret;
+
+ ret = memconsole_coreboot_init(entry.cbmem_addr);
+ if (ret)
+ return ret;
+
+ return memconsole_sysfs_init();
+}
+
+static int memconsole_remove(struct platform_device *pdev)
+{
+ memconsole_exit();
+
+ if (cbmem_console)
+ memunmap(cbmem_console);
+
+ return 0;
+}
+
+static struct platform_driver memconsole_driver = {
+ .probe = memconsole_probe,
+ .remove = memconsole_remove,
+ .driver = {
+ .name = "memconsole",
+ },
+};
+
+static int __init platform_memconsole_init(void)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
+ if (pdev == NULL)
+ return -ENODEV;
+
+ platform_driver_register(&memconsole_driver);
+
+ return 0;
+}
+
+module_init(platform_memconsole_init);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");