1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Generic System Framebuffers on x86
4 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
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.
14 #include <linux/err.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
18 #include <linux/platform_data/simplefb.h>
19 #include <linux/platform_device.h>
20 #include <linux/screen_info.h>
21 #include <asm/sysfb.h>
23 static const char simplefb_resname
[] = "BOOTFB";
24 static const struct simplefb_format formats
[] = SIMPLEFB_FORMATS
;
26 /* try parsing x86 screen_info into a simple-framebuffer mode struct */
27 __init
bool parse_mode(const struct screen_info
*si
,
28 struct simplefb_platform_data
*mode
)
30 const struct simplefb_format
*f
;
34 type
= si
->orig_video_isVGA
;
35 if (type
!= VIDEO_TYPE_VLFB
&& type
!= VIDEO_TYPE_EFI
)
38 for (i
= 0; i
< ARRAY_SIZE(formats
); ++i
) {
40 if (si
->lfb_depth
== f
->bits_per_pixel
&&
41 si
->red_size
== f
->red
.length
&&
42 si
->red_pos
== f
->red
.offset
&&
43 si
->green_size
== f
->green
.length
&&
44 si
->green_pos
== f
->green
.offset
&&
45 si
->blue_size
== f
->blue
.length
&&
46 si
->blue_pos
== f
->blue
.offset
&&
47 si
->rsvd_size
== f
->transp
.length
&&
48 si
->rsvd_pos
== f
->transp
.offset
) {
49 mode
->format
= f
->name
;
50 mode
->width
= si
->lfb_width
;
51 mode
->height
= si
->lfb_height
;
52 mode
->stride
= si
->lfb_linelength
;
60 __init
int create_simplefb(const struct screen_info
*si
,
61 const struct simplefb_platform_data
*mode
)
63 struct platform_device
*pd
;
69 * If the 64BIT_BASE capability is set, ext_lfb_base will contain the
70 * upper half of the base address. Assemble the address, then make sure
71 * it is valid and we can actually access it.
74 if (si
->capabilities
& VIDEO_CAPABILITY_64BIT_BASE
)
75 base
|= (u64
)si
->ext_lfb_base
<< 32;
76 if (!base
|| (u64
)(resource_size_t
)base
!= base
) {
77 printk(KERN_DEBUG
"sysfb: inaccessible VRAM base\n");
82 * Don't use lfb_size as IORESOURCE size, since it may contain the
83 * entire VMEM, and thus require huge mappings. Use just the part we
84 * need, that is, the part where the framebuffer is located. But verify
85 * that it does not exceed the advertised VMEM.
86 * Note that in case of VBE, the lfb_size is shifted by 16 bits for
90 if (si
->orig_video_isVGA
== VIDEO_TYPE_VLFB
)
92 length
= mode
->height
* mode
->stride
;
94 printk(KERN_WARNING
"sysfb: VRAM smaller than advertised\n");
97 length
= PAGE_ALIGN(length
);
99 /* setup IORESOURCE_MEM as framebuffer memory */
100 memset(&res
, 0, sizeof(res
));
101 res
.flags
= IORESOURCE_MEM
| IORESOURCE_BUSY
;
102 res
.name
= simplefb_resname
;
104 res
.end
= res
.start
+ length
- 1;
105 if (res
.end
<= res
.start
)
108 pd
= platform_device_register_resndata(NULL
, "simple-framebuffer", 0,
109 &res
, 1, mode
, sizeof(*mode
));
110 return PTR_ERR_OR_ZERO(pd
);