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