1 /* 2 * framebuffer-coreboot.c 3 * 4 * Memory based framebuffer accessed through coreboot table. 5 * 6 * Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com> 7 * Copyright 2017 Google Inc. 8 * Copyright 2017 Samuel Holland <samuel@sholland.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License v2.0 as published by 12 * the Free Software Foundation. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20 #include <linux/device.h> 21 #include <linux/kernel.h> 22 #include <linux/mm.h> 23 #include <linux/module.h> 24 #include <linux/platform_data/simplefb.h> 25 #include <linux/platform_device.h> 26 27 #include "coreboot_table.h" 28 29 #define CB_TAG_FRAMEBUFFER 0x12 30 31 static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; 32 33 static int framebuffer_probe(struct coreboot_device *dev) 34 { 35 int i; 36 u32 length; 37 struct lb_framebuffer *fb = &dev->framebuffer; 38 struct platform_device *pdev; 39 struct resource res; 40 struct simplefb_platform_data pdata = { 41 .width = fb->x_resolution, 42 .height = fb->y_resolution, 43 .stride = fb->bytes_per_line, 44 .format = NULL, 45 }; 46 47 for (i = 0; i < ARRAY_SIZE(formats); ++i) { 48 if (fb->bits_per_pixel == formats[i].bits_per_pixel && 49 fb->red_mask_pos == formats[i].red.offset && 50 fb->red_mask_size == formats[i].red.length && 51 fb->green_mask_pos == formats[i].green.offset && 52 fb->green_mask_size == formats[i].green.length && 53 fb->blue_mask_pos == formats[i].blue.offset && 54 fb->blue_mask_size == formats[i].blue.length && 55 fb->reserved_mask_pos == formats[i].transp.offset && 56 fb->reserved_mask_size == formats[i].transp.length) 57 pdata.format = formats[i].name; 58 } 59 if (!pdata.format) 60 return -ENODEV; 61 62 memset(&res, 0, sizeof(res)); 63 res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; 64 res.name = "Coreboot Framebuffer"; 65 res.start = fb->physical_address; 66 length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line); 67 res.end = res.start + length - 1; 68 if (res.end <= res.start) 69 return -EINVAL; 70 71 pdev = platform_device_register_resndata(&dev->dev, 72 "simple-framebuffer", 0, 73 &res, 1, &pdata, 74 sizeof(pdata)); 75 if (IS_ERR(pdev)) 76 pr_warn("coreboot: could not register framebuffer\n"); 77 else 78 dev_set_drvdata(&dev->dev, pdev); 79 80 return PTR_ERR_OR_ZERO(pdev); 81 } 82 83 static int framebuffer_remove(struct coreboot_device *dev) 84 { 85 struct platform_device *pdev = dev_get_drvdata(&dev->dev); 86 87 platform_device_unregister(pdev); 88 89 return 0; 90 } 91 92 static struct coreboot_driver framebuffer_driver = { 93 .probe = framebuffer_probe, 94 .remove = framebuffer_remove, 95 .drv = { 96 .name = "framebuffer", 97 }, 98 .tag = CB_TAG_FRAMEBUFFER, 99 }; 100 101 static int __init coreboot_framebuffer_init(void) 102 { 103 return coreboot_driver_register(&framebuffer_driver); 104 } 105 106 static void coreboot_framebuffer_exit(void) 107 { 108 coreboot_driver_unregister(&framebuffer_driver); 109 } 110 111 module_init(coreboot_framebuffer_init); 112 module_exit(coreboot_framebuffer_exit); 113 114 MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); 115 MODULE_LICENSE("GPL"); 116