Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/sysfb_simplefb.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Generic System Framebuffers
4
* Copyright (c) 2012-2013 David Herrmann <[email protected]>
5
*/
6
7
/*
8
* simple-framebuffer probing
9
* Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
10
* If the mode is incompatible, we return "false" and let the caller create
11
* legacy nodes instead.
12
*/
13
14
#include <linux/err.h>
15
#include <linux/init.h>
16
#include <linux/kernel.h>
17
#include <linux/mm.h>
18
#include <linux/platform_data/simplefb.h>
19
#include <linux/platform_device.h>
20
#include <linux/screen_info.h>
21
#include <linux/sysfb.h>
22
23
static const char simplefb_resname[] = "BOOTFB";
24
static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
25
26
/* try parsing screen_info into a simple-framebuffer mode struct */
27
__init bool sysfb_parse_mode(const struct screen_info *si,
28
struct simplefb_platform_data *mode)
29
{
30
__u8 type;
31
u32 bits_per_pixel;
32
unsigned int i;
33
34
type = si->orig_video_isVGA;
35
if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
36
return false;
37
38
bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
39
40
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
41
const struct simplefb_format *f = &formats[i];
42
43
if (f->transp.length)
44
continue; /* transparent formats are unsupported by VESA/EFI */
45
46
if (bits_per_pixel == f->bits_per_pixel &&
47
si->red_size == f->red.length &&
48
si->red_pos == f->red.offset &&
49
si->green_size == f->green.length &&
50
si->green_pos == f->green.offset &&
51
si->blue_size == f->blue.length &&
52
si->blue_pos == f->blue.offset) {
53
mode->format = f->name;
54
mode->width = si->lfb_width;
55
mode->height = si->lfb_height;
56
mode->stride = si->lfb_linelength;
57
return true;
58
}
59
}
60
61
return false;
62
}
63
64
__init struct platform_device *sysfb_create_simplefb(const struct screen_info *si,
65
const struct simplefb_platform_data *mode,
66
struct device *parent)
67
{
68
struct platform_device *pd;
69
struct resource res;
70
u64 base, size;
71
u32 length;
72
int ret;
73
74
/*
75
* If the 64BIT_BASE capability is set, ext_lfb_base will contain the
76
* upper half of the base address. Assemble the address, then make sure
77
* it is valid and we can actually access it.
78
*/
79
base = si->lfb_base;
80
if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)
81
base |= (u64)si->ext_lfb_base << 32;
82
if (!base || (u64)(resource_size_t)base != base) {
83
printk(KERN_DEBUG "sysfb: inaccessible VRAM base\n");
84
return ERR_PTR(-EINVAL);
85
}
86
87
/*
88
* Don't use lfb_size as IORESOURCE size, since it may contain the
89
* entire VMEM, and thus require huge mappings. Use just the part we
90
* need, that is, the part where the framebuffer is located. But verify
91
* that it does not exceed the advertised VMEM.
92
* Note that in case of VBE, the lfb_size is shifted by 16 bits for
93
* historical reasons.
94
*/
95
size = si->lfb_size;
96
if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
97
size <<= 16;
98
length = mode->height * mode->stride;
99
if (length > size) {
100
printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
101
return ERR_PTR(-EINVAL);
102
}
103
length = PAGE_ALIGN(length);
104
105
/* setup IORESOURCE_MEM as framebuffer memory */
106
memset(&res, 0, sizeof(res));
107
res.flags = IORESOURCE_MEM;
108
res.name = simplefb_resname;
109
res.start = base;
110
res.end = res.start + length - 1;
111
if (res.end <= res.start)
112
return ERR_PTR(-EINVAL);
113
114
pd = platform_device_alloc("simple-framebuffer", 0);
115
if (!pd)
116
return ERR_PTR(-ENOMEM);
117
118
pd->dev.parent = parent;
119
120
sysfb_set_efifb_fwnode(pd);
121
122
ret = platform_device_add_resources(pd, &res, 1);
123
if (ret)
124
goto err_put_device;
125
126
ret = platform_device_add_data(pd, mode, sizeof(*mode));
127
if (ret)
128
goto err_put_device;
129
130
ret = platform_device_add(pd);
131
if (ret)
132
goto err_put_device;
133
134
return pd;
135
136
err_put_device:
137
platform_device_put(pd);
138
139
return ERR_PTR(ret);
140
}
141
142