xref: /OK3568_Linux_fs/kernel/drivers/firmware/google/framebuffer-coreboot.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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