1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * framebuffer-coreboot.c 4 * 5 * Memory based framebuffer accessed through coreboot table. 6 * 7 * Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com> 8 * Copyright 2017 Google Inc. 9 * Copyright 2017 Samuel Holland <samuel@sholland.org> 10 */ 11 12 #include <linux/device.h> 13 #include <linux/kernel.h> 14 #include <linux/mm.h> 15 #include <linux/module.h> 16 #include <linux/platform_data/simplefb.h> 17 #include <linux/platform_device.h> 18 19 #include "coreboot_table.h" 20 21 #define CB_TAG_FRAMEBUFFER 0x12 22 23 static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; 24 25 static int framebuffer_probe(struct coreboot_device *dev) 26 { 27 int i; 28 u32 length; 29 struct lb_framebuffer *fb = &dev->framebuffer; 30 struct platform_device *pdev; 31 struct resource res; 32 struct simplefb_platform_data pdata = { 33 .width = fb->x_resolution, 34 .height = fb->y_resolution, 35 .stride = fb->bytes_per_line, 36 .format = NULL, 37 }; 38 39 if (!fb->physical_address) 40 return -ENODEV; 41 42 for (i = 0; i < ARRAY_SIZE(formats); ++i) { 43 if (fb->bits_per_pixel == formats[i].bits_per_pixel && 44 fb->red_mask_pos == formats[i].red.offset && 45 fb->red_mask_size == formats[i].red.length && 46 fb->green_mask_pos == formats[i].green.offset && 47 fb->green_mask_size == formats[i].green.length && 48 fb->blue_mask_pos == formats[i].blue.offset && 49 fb->blue_mask_size == formats[i].blue.length) 50 pdata.format = formats[i].name; 51 } 52 if (!pdata.format) 53 return -ENODEV; 54 55 memset(&res, 0, sizeof(res)); 56 res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; 57 res.name = "Coreboot Framebuffer"; 58 res.start = fb->physical_address; 59 length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line); 60 res.end = res.start + length - 1; 61 if (res.end <= res.start) 62 return -EINVAL; 63 64 pdev = platform_device_register_resndata(&dev->dev, 65 "simple-framebuffer", 0, 66 &res, 1, &pdata, 67 sizeof(pdata)); 68 if (IS_ERR(pdev)) 69 pr_warn("coreboot: could not register framebuffer\n"); 70 else 71 dev_set_drvdata(&dev->dev, pdev); 72 73 return PTR_ERR_OR_ZERO(pdev); 74 } 75 76 static void framebuffer_remove(struct coreboot_device *dev) 77 { 78 struct platform_device *pdev = dev_get_drvdata(&dev->dev); 79 80 platform_device_unregister(pdev); 81 } 82 83 static const struct coreboot_device_id framebuffer_ids[] = { 84 { .tag = CB_TAG_FRAMEBUFFER }, 85 { /* sentinel */ } 86 }; 87 MODULE_DEVICE_TABLE(coreboot, framebuffer_ids); 88 89 static struct coreboot_driver framebuffer_driver = { 90 .probe = framebuffer_probe, 91 .remove = framebuffer_remove, 92 .drv = { 93 .name = "framebuffer", 94 }, 95 .id_table = framebuffer_ids, 96 }; 97 module_coreboot_driver(framebuffer_driver); 98 99 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); 100 MODULE_LICENSE("GPL"); 101