From 5ef76da644bf346d29200007d8d3779e7009dabb Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 2 Aug 2013 14:05:20 +0200 Subject: fbdev: simplefb: add init through platform_data If we create proper platform-devices in x86 boot-code, we can use simplefb for VBE or EFI framebuffers, too. However, there is normally no OF support so we introduce a platform_data object so x86 boot-code can pass the parameters via plain old platform-data. This also removes the OF dependency as it is not needed. The headers provide proper dummies for the case OF is disabled. Furthermore, we move the FORMAT-definitions to the common platform header so initialization code can use it to transform "struct screen_info" to the right format-name. Signed-off-by: David Herrmann Link: http://lkml.kernel.org/r/1375445127-15480-2-git-send-email-dh.herrmann@gmail.com Reviewed-by: Stephen Warren Signed-off-by: H. Peter Anvin diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 4cf1e1d..34c3d96 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2457,7 +2457,7 @@ config FB_HYPERV config FB_SIMPLE bool "Simple framebuffer support" - depends on (FB = y) && OF + depends on (FB = y) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2469,8 +2469,7 @@ config FB_SIMPLE pre-allocated frame buffer surface. Configuration re: surface address, size, and format must be provided - through device tree, or potentially plain old platform data in the - future. + through device tree, or plain old platform data. source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index e2e9e3e..5886989 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -24,6 +24,7 @@ #include #include #include +#include #include static struct fb_fix_screeninfo simplefb_fix = { @@ -73,18 +74,7 @@ static struct fb_ops simplefb_ops = { .fb_imageblit = cfb_imageblit, }; -struct simplefb_format { - const char *name; - u32 bits_per_pixel; - struct fb_bitfield red; - struct fb_bitfield green; - struct fb_bitfield blue; - struct fb_bitfield transp; -}; - -static struct simplefb_format simplefb_formats[] = { - { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} }, -}; +static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS; struct simplefb_params { u32 width; @@ -139,6 +129,33 @@ static int simplefb_parse_dt(struct platform_device *pdev, return 0; } +static int simplefb_parse_pd(struct platform_device *pdev, + struct simplefb_params *params) +{ + struct simplefb_platform_data *pd = pdev->dev.platform_data; + int i; + + params->width = pd->width; + params->height = pd->height; + params->stride = pd->stride; + + params->format = NULL; + for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) { + if (strcmp(pd->format, simplefb_formats[i].name)) + continue; + + params->format = &simplefb_formats[i]; + break; + } + + if (!params->format) { + dev_err(&pdev->dev, "Invalid format value\n"); + return -EINVAL; + } + + return 0; +} + static int simplefb_probe(struct platform_device *pdev) { int ret; @@ -149,7 +166,12 @@ static int simplefb_probe(struct platform_device *pdev) if (fb_get_options("simplefb", NULL)) return -ENODEV; - ret = simplefb_parse_dt(pdev, ¶ms); + ret = -ENODEV; + if (pdev->dev.platform_data) + ret = simplefb_parse_pd(pdev, ¶ms); + else if (pdev->dev.of_node) + ret = simplefb_parse_dt(pdev, ¶ms); + if (ret) return ret; diff --git a/include/linux/platform_data/simplefb.h b/include/linux/platform_data/simplefb.h new file mode 100644 index 0000000..5fa2c5e --- /dev/null +++ b/include/linux/platform_data/simplefb.h @@ -0,0 +1,56 @@ +/* + * simplefb.h - Simple Framebuffer Device + * + * Copyright (C) 2013 David Herrmann + * + * 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. + */ + +#ifndef __PLATFORM_DATA_SIMPLEFB_H__ +#define __PLATFORM_DATA_SIMPLEFB_H__ + +#include +#include +#include + +/* format array, use it to initialize a "struct simplefb_format" array */ +#define SIMPLEFB_FORMATS \ +{ \ + { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, \ +} + +/* + * Data-Format for Simple-Framebuffers + * @name: unique 0-terminated name that can be used to identify the mode + * @red,green,blue: Offsets and sizes of the single RGB parts + * @transp: Offset and size of the alpha bits. length=0 means no alpha + * @fourcc: 32bit DRM four-CC code (see drm_fourcc.h) + */ +struct simplefb_format { + const char *name; + u32 bits_per_pixel; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + u32 fourcc; +}; + +/* + * Simple-Framebuffer description + * If the arch-boot code creates simple-framebuffers without DT support, it + * can pass the width, height, stride and format via this platform-data object. + * The framebuffer location must be given as IORESOURCE_MEM resource. + * @format must be a format as described in "struct simplefb_format" above. + */ +struct simplefb_platform_data { + u32 width; + u32 height; + u32 stride; + const char *format; +}; + +#endif /* __PLATFORM_DATA_SIMPLEFB_H__ */ -- cgit v0.10.2 From df0960ab2d95543a7c162b04b2064991666adbad Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 2 Aug 2013 14:05:21 +0200 Subject: fbdev: simplefb: mark as fw and allocate apertures fbdev-core uses FBINFO_MISC_FIRMWARE to mark drivers that use firmware framebuffers. Furthermore, we now allocate apertures for the fbinfo device. Both information is used by remove_conflicting_framebuffers() to remove a fbdev device whenever a real driver is loaded. This is used heavily on x86 for VGA/vesa/EFI framebuffers, but is also of great use for all other systems. Especially with x86 support for simplefb, this information is needed to unload simplefb before a real hw-driver (like i915, radeon, nouveau) is loaded. Signed-off-by: David Herrmann Link: http://lkml.kernel.org/r/1375445127-15480-3-git-send-email-dh.herrmann@gmail.com Tested-by: Stephen Warren Signed-off-by: H. Peter Anvin diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index 5886989..8d78106 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -202,8 +202,16 @@ static int simplefb_probe(struct platform_device *pdev) info->var.blue = params.format->blue; info->var.transp = params.format->transp; + info->apertures = alloc_apertures(1); + if (!info->apertures) { + framebuffer_release(info); + return -ENOMEM; + } + info->apertures->ranges[0].base = info->fix.smem_start; + info->apertures->ranges[0].size = info->fix.smem_len; + info->fbops = &simplefb_ops; - info->flags = FBINFO_DEFAULT; + info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE; info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) { -- cgit v0.10.2 From e3263ab389a7bc9398c3d366819d6f39b9cfd677 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 2 Aug 2013 14:05:22 +0200 Subject: 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 Link: http://lkml.kernel.org/r/1375445127-15480-4-git-send-email-dh.herrmann@gmail.com Tested-by: Stephen Warren Signed-off-by: H. Peter Anvin diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b32ebf9..5c56559 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2270,6 +2270,32 @@ config RAPIDIO source "drivers/rapidio/Kconfig" +config X86_SYSFB + bool "Mark VGA/VBE/EFI FB as generic system framebuffer" + help + Firmwares often provide initial graphics framebuffers so the BIOS, + bootloader or kernel can show basic video-output during boot for + user-guidance and debugging. Historically, x86 used the VESA BIOS + Extensions and EFI-framebuffers for this, which are mostly limited + to x86. + This option, if enabled, marks VGA/VBE/EFI framebuffers as generic + framebuffers so the new generic system-framebuffer drivers can be + used on x86. If the framebuffer is not compatible with the generic + modes, it is adverticed as fallback platform framebuffer so legacy + drivers like efifb, vesafb and uvesafb can pick it up. + If this option is not selected, all system framebuffers are always + marked as fallback platform framebuffers as usual. + + Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will + not be able to pick up generic system framebuffers if this option + is selected. You are highly encouraged to enable simplefb as + replacement if you select this option. simplefb can correctly deal + with generic system framebuffers. But you should still keep vesafb + and others enabled as fallback if a system framebuffer is + incompatible with simplefb. + + If unsure, say Y. + endmenu diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h new file mode 100644 index 0000000..2395fe0 --- /dev/null +++ b/arch/x86/include/asm/sysfb.h @@ -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 + * + * 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 +#include +#include + +#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 */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 88d99ea..90ecdc5 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -103,6 +103,8 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_UPROBES) += uprobes.o +obj-y += sysfb.o +obj-$(CONFIG_X86_SYSFB) += sysfb_simplefb.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c new file mode 100644 index 0000000..7f30e19 --- /dev/null +++ b/arch/x86/kernel/sysfb.c @@ -0,0 +1,71 @@ +/* + * Generic System Framebuffers on x86 + * Copyright (c) 2012-2013 David Herrmann + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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); diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c new file mode 100644 index 0000000..22513e9 --- /dev/null +++ b/arch/x86/kernel/sysfb_simplefb.c @@ -0,0 +1,95 @@ +/* + * Generic System Framebuffers on x86 + * Copyright (c) 2012-2013 David Herrmann + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +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; +} -- cgit v0.10.2 From 2995e506276bfdc7311eb02db8b2aa1a61a4b849 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 2 Aug 2013 14:05:23 +0200 Subject: x86: sysfb: move EFI quirks from efifb to sysfb The EFI FB quirks from efifb.c are useful for simple-framebuffer devices as well. Apply them by default so we can convert efifb.c to use efi-framebuffer platform devices. Signed-off-by: David Herrmann Link: http://lkml.kernel.org/r/1375445127-15480-5-git-send-email-dh.herrmann@gmail.com Signed-off-by: H. Peter Anvin diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h index 2395fe0..2aeb3e2 100644 --- a/arch/x86/include/asm/sysfb.h +++ b/arch/x86/include/asm/sysfb.h @@ -15,6 +15,63 @@ #include #include +enum { + M_I17, /* 17-Inch iMac */ + M_I20, /* 20-Inch iMac */ + M_I20_SR, /* 20-Inch iMac (Santa Rosa) */ + M_I24, /* 24-Inch iMac */ + M_I24_8_1, /* 24-Inch iMac, 8,1th gen */ + M_I24_10_1, /* 24-Inch iMac, 10,1th gen */ + M_I27_11_1, /* 27-Inch iMac, 11,1th gen */ + M_MINI, /* Mac Mini */ + M_MINI_3_1, /* Mac Mini, 3,1th gen */ + M_MINI_4_1, /* Mac Mini, 4,1th gen */ + M_MB, /* MacBook */ + M_MB_2, /* MacBook, 2nd rev. */ + M_MB_3, /* MacBook, 3rd rev. */ + M_MB_5_1, /* MacBook, 5th rev. */ + M_MB_6_1, /* MacBook, 6th rev. */ + M_MB_7_1, /* MacBook, 7th rev. */ + M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */ + M_MBA, /* MacBook Air */ + M_MBA_3, /* Macbook Air, 3rd rev */ + M_MBP, /* MacBook Pro */ + M_MBP_2, /* MacBook Pro 2nd gen */ + M_MBP_2_2, /* MacBook Pro 2,2nd gen */ + M_MBP_SR, /* MacBook Pro (Santa Rosa) */ + M_MBP_4, /* MacBook Pro, 4th gen */ + M_MBP_5_1, /* MacBook Pro, 5,1th gen */ + M_MBP_5_2, /* MacBook Pro, 5,2th gen */ + M_MBP_5_3, /* MacBook Pro, 5,3rd gen */ + M_MBP_6_1, /* MacBook Pro, 6,1th gen */ + M_MBP_6_2, /* MacBook Pro, 6,2th gen */ + M_MBP_7_1, /* MacBook Pro, 7,1th gen */ + M_MBP_8_2, /* MacBook Pro, 8,2nd gen */ + M_UNKNOWN /* placeholder */ +}; + +struct efifb_dmi_info { + char *optname; + unsigned long base; + int stride; + int width; + int height; + int flags; +}; + +#ifdef CONFIG_EFI + +extern struct efifb_dmi_info efifb_dmi_list[]; +void sysfb_apply_efi_quirks(void); + +#else /* CONFIG_EFI */ + +static inline void sysfb_apply_efi_quirks(void) +{ +} + +#endif /* CONFIG_EFI */ + #ifdef CONFIG_X86_SYSFB bool parse_mode(const struct screen_info *si, diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 90ecdc5..a5408b9 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_UPROBES) += uprobes.o obj-y += sysfb.o obj-$(CONFIG_X86_SYSFB) += sysfb_simplefb.o +obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c index 7f30e19..193ec2c 100644 --- a/arch/x86/kernel/sysfb.c +++ b/arch/x86/kernel/sysfb.c @@ -47,6 +47,8 @@ static __init int sysfb_init(void) bool compatible; int ret; + sysfb_apply_efi_quirks(); + /* try to create a simple-framebuffer device */ compatible = parse_mode(si, &mode); if (compatible) { @@ -68,4 +70,5 @@ static __init int sysfb_init(void) return IS_ERR(pd) ? PTR_ERR(pd) : 0; } +/* must execute after PCI subsystem for EFI quirks */ device_initcall(sysfb_init); diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c new file mode 100644 index 0000000..b285d4e --- /dev/null +++ b/arch/x86/kernel/sysfb_efi.c @@ -0,0 +1,214 @@ +/* + * Generic System Framebuffers on x86 + * Copyright (c) 2012-2013 David Herrmann + * + * EFI Quirks Copyright (c) 2006 Edgar Hucek + * + * 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. + */ + +/* + * EFI Quirks + * Several EFI systems do not correctly advertise their boot framebuffers. + * Hence, we use this static table of known broken machines and fix up the + * information so framebuffer drivers can load corectly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include