-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
x86: provide platform-devices for boot-framebuffers
The current situation regarding boot-framebuffers (VGA, VESA/VBE, EFI) on x86 causes troubles when loading multiple fbdev drivers. The global "struct screen_info" does not provide any state-tracking about which drivers use the FBs. request_mem_region() theoretically works, but unfortunately vesafb/efifb ignore it due to quirks for broken boards. Avoid this by creating a platform framebuffer devices with a pointer to the "struct screen_info" as platform-data. Drivers can now create platform-drivers and the driver-core will refuse multiple drivers being active simultaneously. We keep the screen_info available for backwards-compatibility. Drivers can be converted in follow-up patches. Different devices are created for VGA/VESA/EFI FBs to allow multiple drivers to be loaded on distro kernels. We create: - "vesa-framebuffer" for VBE/VESA graphics FBs - "efi-framebuffer" for EFI FBs - "platform-framebuffer" for everything else This allows to load vesafb, efifb and others simultaneously and each picks up only the supported FB types. Apart from platform-framebuffer devices, this also introduces a compatibility option for "simple-framebuffer" drivers which recently got introduced for OF based systems. If CONFIG_X86_SYSFB is selected, we try to match the screen_info against a simple-framebuffer supported format. If we succeed, we create a "simple-framebuffer" device instead of a platform-framebuffer. This allows to reuse the simplefb.c driver across architectures and also to introduce a SimpleDRM driver. There is no need to have vesafb.c, efifb.c, simplefb.c and more just to have architecture specific quirks in their setup-routines. Instead, we now move the architecture specific quirks into x86-setup and provide a generic simple-framebuffer. For backwards-compatibility (if strange formats are used), we still allow vesafb/efifb to be loaded simultaneously and pick up all remaining devices. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Link: http://lkml.kernel.org/r/1375445127-15480-4-git-send-email-dh.herrmann@gmail.com Tested-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
- Loading branch information
David Herrmann
authored and
H. Peter Anvin
committed
Aug 2, 2013
1 parent
df0960a
commit e3263ab
Showing
5 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef _ARCH_X86_KERNEL_SYSFB_H | ||
#define _ARCH_X86_KERNEL_SYSFB_H | ||
|
||
/* | ||
* Generic System Framebuffers on x86 | ||
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by the Free | ||
* Software Foundation; either version 2 of the License, or (at your option) | ||
* any later version. | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/platform_data/simplefb.h> | ||
#include <linux/screen_info.h> | ||
|
||
#ifdef CONFIG_X86_SYSFB | ||
|
||
bool parse_mode(const struct screen_info *si, | ||
struct simplefb_platform_data *mode); | ||
int create_simplefb(const struct screen_info *si, | ||
const struct simplefb_platform_data *mode); | ||
|
||
#else /* CONFIG_X86_SYSFB */ | ||
|
||
static inline bool parse_mode(const struct screen_info *si, | ||
struct simplefb_platform_data *mode) | ||
{ | ||
return false; | ||
} | ||
|
||
static inline int create_simplefb(const struct screen_info *si, | ||
const struct simplefb_platform_data *mode) | ||
{ | ||
return -EINVAL; | ||
} | ||
|
||
#endif /* CONFIG_X86_SYSFB */ | ||
|
||
#endif /* _ARCH_X86_KERNEL_SYSFB_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Generic System Framebuffers on x86 | ||
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by the Free | ||
* Software Foundation; either version 2 of the License, or (at your option) | ||
* any later version. | ||
*/ | ||
|
||
/* | ||
* Simple-Framebuffer support for x86 systems | ||
* Create a platform-device for any available boot framebuffer. The | ||
* simple-framebuffer platform device is already available on DT systems, so | ||
* this module parses the global "screen_info" object and creates a suitable | ||
* platform device compatible with the "simple-framebuffer" DT object. If | ||
* the framebuffer is incompatible, we instead create a legacy | ||
* "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and | ||
* pass the screen_info as platform_data. This allows legacy drivers | ||
* to pick these devices up without messing with simple-framebuffer drivers. | ||
* The global "screen_info" is still valid at all times. | ||
* | ||
* If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer" | ||
* platform devices, but only use legacy framebuffer devices for | ||
* backwards compatibility. | ||
* | ||
* TODO: We set the dev_id field of all platform-devices to 0. This allows | ||
* other x86 OF/DT parsers to create such devices, too. However, they must | ||
* start at offset 1 for this to work. | ||
*/ | ||
|
||
#include <linux/err.h> | ||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/mm.h> | ||
#include <linux/platform_data/simplefb.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/screen_info.h> | ||
#include <asm/sysfb.h> | ||
|
||
static __init int sysfb_init(void) | ||
{ | ||
struct screen_info *si = &screen_info; | ||
struct simplefb_platform_data mode; | ||
struct platform_device *pd; | ||
const char *name; | ||
bool compatible; | ||
int ret; | ||
|
||
/* try to create a simple-framebuffer device */ | ||
compatible = parse_mode(si, &mode); | ||
if (compatible) { | ||
ret = create_simplefb(si, &mode); | ||
if (!ret) | ||
return 0; | ||
} | ||
|
||
/* if the FB is incompatible, create a legacy framebuffer device */ | ||
if (si->orig_video_isVGA == VIDEO_TYPE_EFI) | ||
name = "efi-framebuffer"; | ||
else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB) | ||
name = "vesa-framebuffer"; | ||
else | ||
name = "platform-framebuffer"; | ||
|
||
pd = platform_device_register_resndata(NULL, name, 0, | ||
NULL, 0, si, sizeof(*si)); | ||
return IS_ERR(pd) ? PTR_ERR(pd) : 0; | ||
} | ||
|
||
device_initcall(sysfb_init); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Generic System Framebuffers on x86 | ||
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by the Free | ||
* Software Foundation; either version 2 of the License, or (at your option) | ||
* any later version. | ||
*/ | ||
|
||
/* | ||
* simple-framebuffer probing | ||
* Try to convert "screen_info" into a "simple-framebuffer" compatible mode. | ||
* If the mode is incompatible, we return "false" and let the caller create | ||
* legacy nodes instead. | ||
*/ | ||
|
||
#include <linux/err.h> | ||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/mm.h> | ||
#include <linux/platform_data/simplefb.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/screen_info.h> | ||
#include <asm/sysfb.h> | ||
|
||
static const char simplefb_resname[] = "BOOTFB"; | ||
static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; | ||
|
||
/* try parsing x86 screen_info into a simple-framebuffer mode struct */ | ||
__init bool parse_mode(const struct screen_info *si, | ||
struct simplefb_platform_data *mode) | ||
{ | ||
const struct simplefb_format *f; | ||
__u8 type; | ||
unsigned int i; | ||
|
||
type = si->orig_video_isVGA; | ||
if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI) | ||
return false; | ||
|
||
for (i = 0; i < ARRAY_SIZE(formats); ++i) { | ||
f = &formats[i]; | ||
if (si->lfb_depth == f->bits_per_pixel && | ||
si->red_size == f->red.length && | ||
si->red_pos == f->red.offset && | ||
si->green_size == f->green.length && | ||
si->green_pos == f->green.offset && | ||
si->blue_size == f->blue.length && | ||
si->blue_pos == f->blue.offset && | ||
si->rsvd_size == f->transp.length && | ||
si->rsvd_pos == f->transp.offset) { | ||
mode->format = f->name; | ||
mode->width = si->lfb_width; | ||
mode->height = si->lfb_height; | ||
mode->stride = si->lfb_linelength; | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
__init int create_simplefb(const struct screen_info *si, | ||
const struct simplefb_platform_data *mode) | ||
{ | ||
struct platform_device *pd; | ||
struct resource res; | ||
unsigned long len; | ||
|
||
/* don't use lfb_size as it may contain the whole VMEM instead of only | ||
* the part that is occupied by the framebuffer */ | ||
len = mode->height * mode->stride; | ||
len = PAGE_ALIGN(len); | ||
if (len > si->lfb_size << 16) { | ||
printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n"); | ||
return -EINVAL; | ||
} | ||
|
||
/* setup IORESOURCE_MEM as framebuffer memory */ | ||
memset(&res, 0, sizeof(res)); | ||
res.flags = IORESOURCE_MEM; | ||
res.name = simplefb_resname; | ||
res.start = si->lfb_base; | ||
res.end = si->lfb_base + len - 1; | ||
if (res.end <= res.start) | ||
return -EINVAL; | ||
|
||
pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0, | ||
&res, 1, mode, sizeof(*mode)); | ||
if (IS_ERR(pd)) | ||
return PTR_ERR(pd); | ||
|
||
return 0; | ||
} |