linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add new linearfb driver
@ 2010-08-25 14:11 Colin Watson
  2010-08-25 15:03 ` Peter Jones
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Colin Watson @ 2010-08-25 14:11 UTC (permalink / raw)
  To: linux-fbdev, linux-kernel; +Cc: Peter Jones, Matthew Garrett

Split out linearfb from efifb so that boot loaders can program it as a
simple linear framebuffer on non-EFI systems.  This is useful for boot
loaders with their own graphics drivers, e.g. GRUB 2, since in some
cases on x86 they can set up non-VESA modes and thus can't program
vesafb.

efifb is reworked on top of this common code, and it should be possible
to do the same with some other framebuffer drivers in future.

Signed-off-by: Colin Watson <cjwatson@canonical.com>
Acked-by: Matthew Garrett <mjg@redhat.com>
Cc: Peter Jones <pjones@redhat.com>
---
 drivers/video/Kconfig       |   17 ++-
 drivers/video/Makefile      |    1 +
 drivers/video/efifb.c       |  222 +----------------------------
 drivers/video/linearfb.c    |  332 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/fb.h          |    8 +
 include/linux/screen_info.h |    2 +
 6 files changed, 364 insertions(+), 218 deletions(-)
 create mode 100644 drivers/video/linearfb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 59c51d9..a7735ec 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -721,13 +721,24 @@ config FB_VESA
 	  You will get a boot time penguin logo at no additional cost. Please
 	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
 
-config FB_EFI
-	bool "EFI-based Framebuffer Support"
-	depends on (FB = y) && X86 && EFI
+config FB_LINEAR
+	bool "Simple linear framebuffer support"
+	depends on FB
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	help
+	  This is a simple linear frame buffer device driver. It has no
+	  hardware-specific programming capability, but must be programmed
+	  by the boot loader or by another frame buffer driver.
+
+	  If unsure, say N.
+
+config FB_EFI
+	bool "EFI-based Framebuffer Support"
+	depends on (FB = y) && X86 && EFI
+	select FB_LINEAR
+	help
 	  This is the EFI frame buffer device driver. If the firmware on
 	  your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
 	  using the EFI framebuffer as your console.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ddc2af2..ad74d3b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_FB_MSM)              += msm/
 obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 
 # Platform or fallback drivers go here
+obj-$(CONFIG_FB_LINEAR)           += linearfb.o
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_EFI)              += efifb.o
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 4a56f46..72e5873 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -16,24 +16,6 @@
 
 #include <video/vga.h>
 
-static struct fb_var_screeninfo efifb_defined __initdata = {
-	.activate		= FB_ACTIVATE_NOW,
-	.height			= -1,
-	.width			= -1,
-	.right_margin		= 32,
-	.upper_margin		= 16,
-	.lower_margin		= 4,
-	.vsync_len		= 4,
-	.vmode			= FB_VMODE_NONINTERLACED,
-};
-
-static struct fb_fix_screeninfo efifb_fix __initdata = {
-	.id			= "EFI VGA",
-	.type			= FB_TYPE_PACKED_PIXELS,
-	.accel			= FB_ACCEL_NONE,
-	.visual			= FB_VISUAL_TRUECOLOR,
-};
-
 enum {
 	M_I17,		/* 17-Inch iMac */
 	M_I20,		/* 20-Inch iMac */
@@ -138,49 +120,6 @@ static int set_system(const struct dmi_system_id *id)
 	return 0;
 }
 
-static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   struct fb_info *info)
-{
-	/*
-	 *  Set a single color register. The values supplied are
-	 *  already rounded down to the hardware's capabilities
-	 *  (according to the entries in the `var' structure). Return
-	 *  != 0 for invalid regno.
-	 */
-
-	if (regno >= info->cmap.len)
-		return 1;
-
-	if (regno < 16) {
-		red   >>= 8;
-		green >>= 8;
-		blue  >>= 8;
-		((u32 *)(info->pseudo_palette))[regno] -			(red   << info->var.red.offset)   |
-			(green << info->var.green.offset) |
-			(blue  << info->var.blue.offset);
-	}
-	return 0;
-}
-
-static void efifb_destroy(struct fb_info *info)
-{
-	if (info->screen_base)
-		iounmap(info->screen_base);
-	release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
-	framebuffer_release(info);
-}
-
-static struct fb_ops efifb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_destroy	= efifb_destroy,
-	.fb_setcolreg	= efifb_setcolreg,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-};
-
 static int __init efifb_setup(char *options)
 {
 	char *this_opt;
@@ -215,171 +154,24 @@ static int __init efifb_setup(char *options)
 
 static int __devinit efifb_probe(struct platform_device *dev)
 {
-	struct fb_info *info;
 	int err;
-	unsigned int size_vmode;
-	unsigned int size_remap;
-	unsigned int size_total;
-	int request_succeeded = 0;
-
-	if (!screen_info.lfb_depth)
-		screen_info.lfb_depth = 32;
-	if (!screen_info.pages)
-		screen_info.pages = 1;
-	if (!screen_info.lfb_base) {
-		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
-		return -ENODEV;
-	}
-	printk(KERN_INFO "efifb: probing for efifb\n");
-
-	/* just assume they're all unset if any are */
-	if (!screen_info.blue_size) {
-		screen_info.blue_size = 8;
-		screen_info.blue_pos = 0;
-		screen_info.green_size = 8;
-		screen_info.green_pos = 8;
-		screen_info.red_size = 8;
-		screen_info.red_pos = 16;
-		screen_info.rsvd_size = 8;
-		screen_info.rsvd_pos = 24;
-	}
-
-	efifb_fix.smem_start = screen_info.lfb_base;
-	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
-	efifb_defined.xres = screen_info.lfb_width;
-	efifb_defined.yres = screen_info.lfb_height;
-	efifb_fix.line_length = screen_info.lfb_linelength;
-
-	/*   size_vmode -- that is the amount of memory needed for the
-	 *                 used video mode, i.e. the minimum amount of
-	 *                 memory we need. */
-	size_vmode = efifb_defined.yres * efifb_fix.line_length;
-
-	/*   size_total -- all video memory we have. Used for
-	 *                 entries, ressource allocation and bounds
-	 *                 checking. */
-	size_total = screen_info.lfb_size;
-	if (size_total < size_vmode)
-		size_total = size_vmode;
-
-	/*   size_remap -- the amount of video memory we are going to
-	 *                 use for efifb.  With modern cards it is no
-	 *                 option to simply use size_total as that
-	 *                 wastes plenty of kernel address space. */
-	size_remap  = size_vmode * 2;
-	if (size_remap > size_total)
-		size_remap = size_total;
-	if (size_remap % PAGE_SIZE)
-		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
-	efifb_fix.smem_len = size_remap;
-
-	if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
-		request_succeeded = 1;
-	} else {
-		/* We cannot make this fatal. Sometimes this comes from magic
-		   spaces our resource handlers simply don't know about */
-		printk(KERN_WARNING
-		       "efifb: cannot reserve video memory at 0x%lx\n",
-			efifb_fix.smem_start);
-	}
-
-	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
-	if (!info) {
-		printk(KERN_ERR "efifb: cannot allocate framebuffer\n");
-		err = -ENOMEM;
-		goto err_release_mem;
-	}
-	info->pseudo_palette = info->par;
-	info->par = NULL;
-
-	info->apertures = alloc_apertures(1);
-	if (!info->apertures) {
-		err = -ENOMEM;
-		goto err_release_fb;
-	}
-	info->apertures->ranges[0].base = efifb_fix.smem_start;
-	info->apertures->ranges[0].size = size_remap;
-
-	info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
-	if (!info->screen_base) {
-		printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
-				"0x%x @ 0x%lx\n",
-			efifb_fix.smem_len, efifb_fix.smem_start);
-		err = -EIO;
-		goto err_release_fb;
-	}
-
-	printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
-	       "using %dk, total %dk\n",
-	       efifb_fix.smem_start, info->screen_base,
-	       size_remap/1024, size_total/1024);
-	printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
-	       efifb_defined.xres, efifb_defined.yres,
-	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
-	       screen_info.pages);
-
-	efifb_defined.xres_virtual = efifb_defined.xres;
-	efifb_defined.yres_virtual = efifb_fix.smem_len /
-					efifb_fix.line_length;
-	printk(KERN_INFO "efifb: scrolling: redraw\n");
-	efifb_defined.yres_virtual = efifb_defined.yres;
-
-	/* some dummy values for timing to make fbset happy */
-	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
-					1000 / efifb_defined.yres;
-	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
-	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
-
-	efifb_defined.red.offset    = screen_info.red_pos;
-	efifb_defined.red.length    = screen_info.red_size;
-	efifb_defined.green.offset  = screen_info.green_pos;
-	efifb_defined.green.length  = screen_info.green_size;
-	efifb_defined.blue.offset   = screen_info.blue_pos;
-	efifb_defined.blue.length   = screen_info.blue_size;
-	efifb_defined.transp.offset = screen_info.rsvd_pos;
-	efifb_defined.transp.length = screen_info.rsvd_size;
-
-	printk(KERN_INFO "efifb: %s: "
-	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-	       "Truecolor",
-	       screen_info.rsvd_size,
-	       screen_info.red_size,
-	       screen_info.green_size,
-	       screen_info.blue_size,
-	       screen_info.rsvd_pos,
-	       screen_info.red_pos,
-	       screen_info.green_pos,
-	       screen_info.blue_pos);
-
-	efifb_fix.ypanstep  = 0;
-	efifb_fix.ywrapstep = 0;
+	struct fb_info *info;
 
-	info->fbops = &efifb_ops;
-	info->var = efifb_defined;
-	info->fix = efifb_fix;
-	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
+	if ((err = linearfb_get_info(dev, &info)) < 0)
+		return err;
 
-	if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
-		printk(KERN_ERR "efifb: cannot allocate colormap\n");
-		goto err_unmap;
-	}
+	strcpy(info->fix.id, "EFI VGA");
 	if ((err = register_framebuffer(info)) < 0) {
 		printk(KERN_ERR "efifb: cannot register framebuffer\n");
-		goto err_fb_dealoc;
+		goto err_fb_dealloc;
 	}
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 		info->node, info->fix.id);
 	return 0;
 
-err_fb_dealoc:
+err_fb_dealloc:
 	fb_dealloc_cmap(&info->cmap);
-err_unmap:
-	iounmap(info->screen_base);
-err_release_fb:
-	framebuffer_release(info);
-err_release_mem:
-	if (request_succeeded)
-		release_mem_region(efifb_fix.smem_start, size_total);
+	linearfb_destroy(info);
 	return err;
 }
 
diff --git a/drivers/video/linearfb.c b/drivers/video/linearfb.c
new file mode 100644
index 0000000..c93eaac
--- /dev/null
+++ b/drivers/video/linearfb.c
@@ -0,0 +1,332 @@
+/*
+ * Simple linear framebuffer driver
+ *
+ * This driver does not have any real probing capability; using it requires
+ * programming, either by the boot loader or by another framebuffer driver.
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * Split out to linearfb by Colin Watson <cjwatson@ubuntu.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+
+#include <video/vga.h>
+
+static struct fb_var_screeninfo linearfb_defined __initdata = {
+	.activate		= FB_ACTIVATE_NOW,
+	.height			= -1,
+	.width			= -1,
+	.right_margin		= 32,
+	.upper_margin		= 16,
+	.lower_margin		= 4,
+	.vsync_len		= 4,
+	.vmode			= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo linearfb_fix __initdata = {
+	.id			= "Linear",
+	.type			= FB_TYPE_PACKED_PIXELS,
+	.accel			= FB_ACCEL_NONE,
+	.visual			= FB_VISUAL_TRUECOLOR,
+};
+
+static int linearfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16) {
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] +			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	}
+	return 0;
+}
+
+void linearfb_destroy(struct fb_info *info)
+{
+	if (info->screen_base)
+		iounmap(info->screen_base);
+	release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
+	framebuffer_release(info);
+}
+EXPORT_SYMBOL(linearfb_destroy);
+
+static struct fb_ops linearfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_destroy	= linearfb_destroy,
+	.fb_setcolreg	= linearfb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init linearfb_setup(char *options)
+{
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+
+		if (!strncmp(this_opt, "base:", 5))
+			screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "stride:", 7))
+			screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+		else if (!strncmp(this_opt, "height:", 7))
+			screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "width:", 6))
+			screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+	}
+	return 0;
+}
+
+int linearfb_get_info(struct platform_device *dev, struct fb_info **p_info)
+{
+	int err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+	int request_succeeded = 0;
+	struct fb_info *info;
+
+	if (!screen_info.lfb_depth)
+		screen_info.lfb_depth = 32;
+	if (!screen_info.pages)
+		screen_info.pages = 1;
+	if (!screen_info.lfb_base) {
+		printk(KERN_DEBUG "linearfb: invalid framebuffer address\n");
+		return -ENODEV;
+	}
+	printk(KERN_INFO "linearfb: probing for linearfb\n");
+
+	/* just assume they're all unset if any are */
+	if (!screen_info.blue_size) {
+		screen_info.blue_size = 8;
+		screen_info.blue_pos = 0;
+		screen_info.green_size = 8;
+		screen_info.green_pos = 8;
+		screen_info.red_size = 8;
+		screen_info.red_pos = 16;
+		screen_info.rsvd_size = 8;
+		screen_info.rsvd_pos = 24;
+	}
+
+	linearfb_fix.smem_start = screen_info.lfb_base;
+	linearfb_defined.bits_per_pixel = screen_info.lfb_depth;
+	linearfb_defined.xres = screen_info.lfb_width;
+	linearfb_defined.yres = screen_info.lfb_height;
+	linearfb_fix.line_length = screen_info.lfb_linelength;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = linearfb_defined.yres * linearfb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	size_total = screen_info.lfb_size;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for linearfb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	if (size_remap % PAGE_SIZE)
+		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
+	linearfb_fix.smem_len = size_remap;
+
+	if (request_mem_region(linearfb_fix.smem_start, size_remap,
+	    "linearfb")) {
+		request_succeeded = 1;
+	} else {
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+		printk(KERN_WARNING
+		       "linearfb: cannot reserve video memory at 0x%lx\n",
+			linearfb_fix.smem_start);
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+	if (!info) {
+		printk(KERN_ERR "linearfb: cannot allocate framebuffer\n");
+		err = -ENOMEM;
+		goto err_release_mem;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures) {
+		err = -ENOMEM;
+		goto err_release_fb;
+	}
+	info->apertures->ranges[0].base = linearfb_fix.smem_start;
+	info->apertures->ranges[0].size = size_remap;
+
+	info->screen_base = ioremap(linearfb_fix.smem_start,
+				    linearfb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR "linearfb: abort, cannot ioremap video memory "
+				"0x%x @ 0x%lx\n",
+			linearfb_fix.smem_len, linearfb_fix.smem_start);
+		err = -EIO;
+		goto err_release_fb;
+	}
+
+	printk(KERN_INFO "linearfb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       linearfb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO
+	       "linearfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       linearfb_defined.xres, linearfb_defined.yres,
+	       linearfb_defined.bits_per_pixel, linearfb_fix.line_length,
+	       screen_info.pages);
+
+	linearfb_defined.xres_virtual = linearfb_defined.xres;
+	linearfb_defined.yres_virtual = linearfb_fix.smem_len /
+					linearfb_fix.line_length;
+	printk(KERN_INFO "linearfb: scrolling: redraw\n");
+	linearfb_defined.yres_virtual = linearfb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	linearfb_defined.pixclock     = 10000000 / linearfb_defined.xres *
+					1000 / linearfb_defined.yres;
+	linearfb_defined.left_margin  = (linearfb_defined.xres / 8) & 0xf8;
+	linearfb_defined.hsync_len    = (linearfb_defined.xres / 8) & 0xf8;
+
+	linearfb_defined.red.offset    = screen_info.red_pos;
+	linearfb_defined.red.length    = screen_info.red_size;
+	linearfb_defined.green.offset  = screen_info.green_pos;
+	linearfb_defined.green.length  = screen_info.green_size;
+	linearfb_defined.blue.offset   = screen_info.blue_pos;
+	linearfb_defined.blue.length   = screen_info.blue_size;
+	linearfb_defined.transp.offset = screen_info.rsvd_pos;
+	linearfb_defined.transp.length = screen_info.rsvd_size;
+
+	printk(KERN_INFO "linearfb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       "Truecolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	linearfb_fix.ypanstep  = 0;
+	linearfb_fix.ywrapstep = 0;
+
+	info->fbops = &linearfb_ops;
+	info->var = linearfb_defined;
+	info->fix = linearfb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
+
+	if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
+		printk(KERN_ERR "linearfb: cannot allocate colormap\n");
+		goto err_unmap;
+	}
+	*p_info = info;
+	return 0;
+
+err_unmap:
+	iounmap(info->screen_base);
+err_release_fb:
+	framebuffer_release(info);
+err_release_mem:
+	if (request_succeeded)
+		release_mem_region(linearfb_fix.smem_start, size_total);
+	return err;
+}
+EXPORT_SYMBOL(linearfb_get_info);
+
+static int linearfb_probe(struct platform_device *dev)
+{
+	int err;
+	struct fb_info *info;
+
+	if ((err = linearfb_get_info(dev, &info)) < 0)
+		return err;
+
+	if ((err = register_framebuffer(info)) < 0) {
+		printk(KERN_ERR "linearfb: cannot register framebuffer\n");
+		goto err_fb_dealloc;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+		info->node, info->fix.id);
+	return 0;
+
+err_fb_dealloc:
+	fb_dealloc_cmap(&info->cmap);
+	linearfb_destroy(info);
+	return err;
+}
+
+static struct platform_driver linearfb_driver = {
+	.probe	= linearfb_probe,
+	.driver	= {
+		.name	= "linearfb",
+	},
+};
+
+static struct platform_device linearfb_device = {
+	.name	= "linearfb",
+};
+
+static int __init linearfb_init(void)
+{
+	int ret;
+	char *option = NULL;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_LINEAR)
+		return -ENODEV;
+
+	if (fb_get_options("linearfb", &option))
+		return -ENODEV;
+	linearfb_setup(option);
+
+	if (!screen_info.lfb_linelength)
+		return -ENODEV;
+
+	ret = platform_driver_register(&linearfb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&linearfb_device);
+		if (ret)
+			platform_driver_unregister(&linearfb_driver);
+	}
+	return ret;
+}
+module_init(linearfb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 8e5a9df..0913385 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -1137,6 +1137,14 @@ extern int fb_find_mode(struct fb_var_screeninfo *var,
 			const struct fb_videomode *default_mode,
 			unsigned int default_bpp);
 
+#ifdef CONFIG_FB_LINEAR
+struct platform_device;
+
+extern void linearfb_destroy(struct fb_info *info);
+extern int linearfb_get_info(struct platform_device *dev,
+			     struct fb_info **p_info);
+#endif /* CONFIG_FB_LINEAR */
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_FB_H */
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index 899fbb4..129f533 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -66,6 +66,8 @@ struct screen_info {
 
 #define VIDEO_TYPE_EFI		0x70	/* EFI graphic mode		*/
 
+#define VIDEO_TYPE_LINEAR	0x80	/* Simple linear frame bufffer	*/
+
 #define VIDEO_FLAGS_NOCURSOR	(1 << 0) /* The video mode has no cursor set */
 
 #ifdef __KERNEL__
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add new linearfb driver
  2010-08-25 14:11 [PATCH] Add new linearfb driver Colin Watson
@ 2010-08-25 15:03 ` Peter Jones
  2010-08-25 17:04 ` Bruno Prémont
  2010-08-25 20:22 ` Geert Uytterhoeven
  2 siblings, 0 replies; 6+ messages in thread
From: Peter Jones @ 2010-08-25 15:03 UTC (permalink / raw)
  To: Colin Watson; +Cc: linux-fbdev, linux-kernel, Matthew Garrett

On 08/25/2010 10:11 AM, Colin Watson wrote:
> Split out linearfb from efifb so that boot loaders can program it as a
> simple linear framebuffer on non-EFI systems.  This is useful for boot
> loaders with their own graphics drivers, e.g. GRUB 2, since in some
> cases on x86 they can set up non-VESA modes and thus can't program
> vesafb.
> 
> efifb is reworked on top of this common code, and it should be possible
> to do the same with some other framebuffer drivers in future.
> 
> Signed-off-by: Colin Watson <cjwatson@canonical.com>
> Acked-by: Matthew Garrett <mjg@redhat.com>
> Cc: Peter Jones <pjones@redhat.com>

Looks reasonable to me.

Acked-by: Peter Jones <pjones@redhat.com>

> ---
>  drivers/video/Kconfig       |   17 ++-
>  drivers/video/Makefile      |    1 +
>  drivers/video/efifb.c       |  222 +----------------------------
>  drivers/video/linearfb.c    |  332 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fb.h          |    8 +
>  include/linux/screen_info.h |    2 +
>  6 files changed, 364 insertions(+), 218 deletions(-)
>  create mode 100644 drivers/video/linearfb.c
> 
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 59c51d9..a7735ec 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -721,13 +721,24 @@ config FB_VESA
>  	  You will get a boot time penguin logo at no additional cost. Please
>  	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
>  
> -config FB_EFI
> -	bool "EFI-based Framebuffer Support"
> -	depends on (FB = y) && X86 && EFI
> +config FB_LINEAR
> +	bool "Simple linear framebuffer support"
> +	depends on FB
>  	select FB_CFB_FILLRECT
>  	select FB_CFB_COPYAREA
>  	select FB_CFB_IMAGEBLIT
>  	help
> +	  This is a simple linear frame buffer device driver. It has no
> +	  hardware-specific programming capability, but must be programmed
> +	  by the boot loader or by another frame buffer driver.
> +
> +	  If unsure, say N.
> +
> +config FB_EFI
> +	bool "EFI-based Framebuffer Support"
> +	depends on (FB = y) && X86 && EFI
> +	select FB_LINEAR
> +	help
>  	  This is the EFI frame buffer device driver. If the firmware on
>  	  your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
>  	  using the EFI framebuffer as your console.
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index ddc2af2..ad74d3b 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -133,6 +133,7 @@ obj-$(CONFIG_FB_MSM)              += msm/
>  obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
>  
>  # Platform or fallback drivers go here
> +obj-$(CONFIG_FB_LINEAR)           += linearfb.o
>  obj-$(CONFIG_FB_UVESA)            += uvesafb.o
>  obj-$(CONFIG_FB_VESA)             += vesafb.o
>  obj-$(CONFIG_FB_EFI)              += efifb.o
> diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
> index 4a56f46..72e5873 100644
> --- a/drivers/video/efifb.c
> +++ b/drivers/video/efifb.c
> @@ -16,24 +16,6 @@
>  
>  #include <video/vga.h>
>  
> -static struct fb_var_screeninfo efifb_defined __initdata = {
> -	.activate		= FB_ACTIVATE_NOW,
> -	.height			= -1,
> -	.width			= -1,
> -	.right_margin		= 32,
> -	.upper_margin		= 16,
> -	.lower_margin		= 4,
> -	.vsync_len		= 4,
> -	.vmode			= FB_VMODE_NONINTERLACED,
> -};
> -
> -static struct fb_fix_screeninfo efifb_fix __initdata = {
> -	.id			= "EFI VGA",
> -	.type			= FB_TYPE_PACKED_PIXELS,
> -	.accel			= FB_ACCEL_NONE,
> -	.visual			= FB_VISUAL_TRUECOLOR,
> -};
> -
>  enum {
>  	M_I17,		/* 17-Inch iMac */
>  	M_I20,		/* 20-Inch iMac */
> @@ -138,49 +120,6 @@ static int set_system(const struct dmi_system_id *id)
>  	return 0;
>  }
>  
> -static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
> -			   unsigned blue, unsigned transp,
> -			   struct fb_info *info)
> -{
> -	/*
> -	 *  Set a single color register. The values supplied are
> -	 *  already rounded down to the hardware's capabilities
> -	 *  (according to the entries in the `var' structure). Return
> -	 *  != 0 for invalid regno.
> -	 */
> -
> -	if (regno >= info->cmap.len)
> -		return 1;
> -
> -	if (regno < 16) {
> -		red   >>= 8;
> -		green >>= 8;
> -		blue  >>= 8;
> -		((u32 *)(info->pseudo_palette))[regno] > -			(red   << info->var.red.offset)   |
> -			(green << info->var.green.offset) |
> -			(blue  << info->var.blue.offset);
> -	}
> -	return 0;
> -}
> -
> -static void efifb_destroy(struct fb_info *info)
> -{
> -	if (info->screen_base)
> -		iounmap(info->screen_base);
> -	release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
> -	framebuffer_release(info);
> -}
> -
> -static struct fb_ops efifb_ops = {
> -	.owner		= THIS_MODULE,
> -	.fb_destroy	= efifb_destroy,
> -	.fb_setcolreg	= efifb_setcolreg,
> -	.fb_fillrect	= cfb_fillrect,
> -	.fb_copyarea	= cfb_copyarea,
> -	.fb_imageblit	= cfb_imageblit,
> -};
> -
>  static int __init efifb_setup(char *options)
>  {
>  	char *this_opt;
> @@ -215,171 +154,24 @@ static int __init efifb_setup(char *options)
>  
>  static int __devinit efifb_probe(struct platform_device *dev)
>  {
> -	struct fb_info *info;
>  	int err;
> -	unsigned int size_vmode;
> -	unsigned int size_remap;
> -	unsigned int size_total;
> -	int request_succeeded = 0;
> -
> -	if (!screen_info.lfb_depth)
> -		screen_info.lfb_depth = 32;
> -	if (!screen_info.pages)
> -		screen_info.pages = 1;
> -	if (!screen_info.lfb_base) {
> -		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
> -		return -ENODEV;
> -	}
> -	printk(KERN_INFO "efifb: probing for efifb\n");
> -
> -	/* just assume they're all unset if any are */
> -	if (!screen_info.blue_size) {
> -		screen_info.blue_size = 8;
> -		screen_info.blue_pos = 0;
> -		screen_info.green_size = 8;
> -		screen_info.green_pos = 8;
> -		screen_info.red_size = 8;
> -		screen_info.red_pos = 16;
> -		screen_info.rsvd_size = 8;
> -		screen_info.rsvd_pos = 24;
> -	}
> -
> -	efifb_fix.smem_start = screen_info.lfb_base;
> -	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
> -	efifb_defined.xres = screen_info.lfb_width;
> -	efifb_defined.yres = screen_info.lfb_height;
> -	efifb_fix.line_length = screen_info.lfb_linelength;
> -
> -	/*   size_vmode -- that is the amount of memory needed for the
> -	 *                 used video mode, i.e. the minimum amount of
> -	 *                 memory we need. */
> -	size_vmode = efifb_defined.yres * efifb_fix.line_length;
> -
> -	/*   size_total -- all video memory we have. Used for
> -	 *                 entries, ressource allocation and bounds
> -	 *                 checking. */
> -	size_total = screen_info.lfb_size;
> -	if (size_total < size_vmode)
> -		size_total = size_vmode;
> -
> -	/*   size_remap -- the amount of video memory we are going to
> -	 *                 use for efifb.  With modern cards it is no
> -	 *                 option to simply use size_total as that
> -	 *                 wastes plenty of kernel address space. */
> -	size_remap  = size_vmode * 2;
> -	if (size_remap > size_total)
> -		size_remap = size_total;
> -	if (size_remap % PAGE_SIZE)
> -		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
> -	efifb_fix.smem_len = size_remap;
> -
> -	if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
> -		request_succeeded = 1;
> -	} else {
> -		/* We cannot make this fatal. Sometimes this comes from magic
> -		   spaces our resource handlers simply don't know about */
> -		printk(KERN_WARNING
> -		       "efifb: cannot reserve video memory at 0x%lx\n",
> -			efifb_fix.smem_start);
> -	}
> -
> -	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
> -	if (!info) {
> -		printk(KERN_ERR "efifb: cannot allocate framebuffer\n");
> -		err = -ENOMEM;
> -		goto err_release_mem;
> -	}
> -	info->pseudo_palette = info->par;
> -	info->par = NULL;
> -
> -	info->apertures = alloc_apertures(1);
> -	if (!info->apertures) {
> -		err = -ENOMEM;
> -		goto err_release_fb;
> -	}
> -	info->apertures->ranges[0].base = efifb_fix.smem_start;
> -	info->apertures->ranges[0].size = size_remap;
> -
> -	info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
> -	if (!info->screen_base) {
> -		printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
> -				"0x%x @ 0x%lx\n",
> -			efifb_fix.smem_len, efifb_fix.smem_start);
> -		err = -EIO;
> -		goto err_release_fb;
> -	}
> -
> -	printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
> -	       "using %dk, total %dk\n",
> -	       efifb_fix.smem_start, info->screen_base,
> -	       size_remap/1024, size_total/1024);
> -	printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
> -	       efifb_defined.xres, efifb_defined.yres,
> -	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
> -	       screen_info.pages);
> -
> -	efifb_defined.xres_virtual = efifb_defined.xres;
> -	efifb_defined.yres_virtual = efifb_fix.smem_len /
> -					efifb_fix.line_length;
> -	printk(KERN_INFO "efifb: scrolling: redraw\n");
> -	efifb_defined.yres_virtual = efifb_defined.yres;
> -
> -	/* some dummy values for timing to make fbset happy */
> -	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
> -					1000 / efifb_defined.yres;
> -	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
> -	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
> -
> -	efifb_defined.red.offset    = screen_info.red_pos;
> -	efifb_defined.red.length    = screen_info.red_size;
> -	efifb_defined.green.offset  = screen_info.green_pos;
> -	efifb_defined.green.length  = screen_info.green_size;
> -	efifb_defined.blue.offset   = screen_info.blue_pos;
> -	efifb_defined.blue.length   = screen_info.blue_size;
> -	efifb_defined.transp.offset = screen_info.rsvd_pos;
> -	efifb_defined.transp.length = screen_info.rsvd_size;
> -
> -	printk(KERN_INFO "efifb: %s: "
> -	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
> -	       "Truecolor",
> -	       screen_info.rsvd_size,
> -	       screen_info.red_size,
> -	       screen_info.green_size,
> -	       screen_info.blue_size,
> -	       screen_info.rsvd_pos,
> -	       screen_info.red_pos,
> -	       screen_info.green_pos,
> -	       screen_info.blue_pos);
> -
> -	efifb_fix.ypanstep  = 0;
> -	efifb_fix.ywrapstep = 0;
> +	struct fb_info *info;
>  
> -	info->fbops = &efifb_ops;
> -	info->var = efifb_defined;
> -	info->fix = efifb_fix;
> -	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
> +	if ((err = linearfb_get_info(dev, &info)) < 0)
> +		return err;
>  
> -	if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
> -		printk(KERN_ERR "efifb: cannot allocate colormap\n");
> -		goto err_unmap;
> -	}
> +	strcpy(info->fix.id, "EFI VGA");
>  	if ((err = register_framebuffer(info)) < 0) {
>  		printk(KERN_ERR "efifb: cannot register framebuffer\n");
> -		goto err_fb_dealoc;
> +		goto err_fb_dealloc;
>  	}
>  	printk(KERN_INFO "fb%d: %s frame buffer device\n",
>  		info->node, info->fix.id);
>  	return 0;
>  
> -err_fb_dealoc:
> +err_fb_dealloc:
>  	fb_dealloc_cmap(&info->cmap);
> -err_unmap:
> -	iounmap(info->screen_base);
> -err_release_fb:
> -	framebuffer_release(info);
> -err_release_mem:
> -	if (request_succeeded)
> -		release_mem_region(efifb_fix.smem_start, size_total);
> +	linearfb_destroy(info);
>  	return err;
>  }
>  
> diff --git a/drivers/video/linearfb.c b/drivers/video/linearfb.c
> new file mode 100644
> index 0000000..c93eaac
> --- /dev/null
> +++ b/drivers/video/linearfb.c
> @@ -0,0 +1,332 @@
> +/*
> + * Simple linear framebuffer driver
> + *
> + * This driver does not have any real probing capability; using it requires
> + * programming, either by the boot loader or by another framebuffer driver.
> + *
> + * (c) 2006 Edgar Hucek <gimli@dark-green.com>
> + * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
> + * Split out to linearfb by Colin Watson <cjwatson@ubuntu.com>
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/fb.h>
> +#include <linux/platform_device.h>
> +#include <linux/screen_info.h>
> +
> +#include <video/vga.h>
> +
> +static struct fb_var_screeninfo linearfb_defined __initdata = {
> +	.activate		= FB_ACTIVATE_NOW,
> +	.height			= -1,
> +	.width			= -1,
> +	.right_margin		= 32,
> +	.upper_margin		= 16,
> +	.lower_margin		= 4,
> +	.vsync_len		= 4,
> +	.vmode			= FB_VMODE_NONINTERLACED,
> +};
> +
> +static struct fb_fix_screeninfo linearfb_fix __initdata = {
> +	.id			= "Linear",
> +	.type			= FB_TYPE_PACKED_PIXELS,
> +	.accel			= FB_ACCEL_NONE,
> +	.visual			= FB_VISUAL_TRUECOLOR,
> +};
> +
> +static int linearfb_setcolreg(unsigned regno, unsigned red, unsigned green,
> +			      unsigned blue, unsigned transp,
> +			      struct fb_info *info)
> +{
> +	/*
> +	 *  Set a single color register. The values supplied are
> +	 *  already rounded down to the hardware's capabilities
> +	 *  (according to the entries in the `var' structure). Return
> +	 *  != 0 for invalid regno.
> +	 */
> +
> +	if (regno >= info->cmap.len)
> +		return 1;
> +
> +	if (regno < 16) {
> +		red   >>= 8;
> +		green >>= 8;
> +		blue  >>= 8;
> +		((u32 *)(info->pseudo_palette))[regno] > +			(red   << info->var.red.offset)   |
> +			(green << info->var.green.offset) |
> +			(blue  << info->var.blue.offset);
> +	}
> +	return 0;
> +}
> +
> +void linearfb_destroy(struct fb_info *info)
> +{
> +	if (info->screen_base)
> +		iounmap(info->screen_base);
> +	release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
> +	framebuffer_release(info);
> +}
> +EXPORT_SYMBOL(linearfb_destroy);
> +
> +static struct fb_ops linearfb_ops = {
> +	.owner		= THIS_MODULE,
> +	.fb_destroy	= linearfb_destroy,
> +	.fb_setcolreg	= linearfb_setcolreg,
> +	.fb_fillrect	= cfb_fillrect,
> +	.fb_copyarea	= cfb_copyarea,
> +	.fb_imageblit	= cfb_imageblit,
> +};
> +
> +static int __init linearfb_setup(char *options)
> +{
> +	char *this_opt;
> +
> +	if (!options || !*options)
> +		return 0;
> +
> +	while ((this_opt = strsep(&options, ",")) != NULL) {
> +		if (!*this_opt) continue;
> +
> +		if (!strncmp(this_opt, "base:", 5))
> +			screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
> +		else if (!strncmp(this_opt, "stride:", 7))
> +			screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
> +		else if (!strncmp(this_opt, "height:", 7))
> +			screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
> +		else if (!strncmp(this_opt, "width:", 6))
> +			screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
> +	}
> +	return 0;
> +}
> +
> +int linearfb_get_info(struct platform_device *dev, struct fb_info **p_info)
> +{
> +	int err;
> +	unsigned int size_vmode;
> +	unsigned int size_remap;
> +	unsigned int size_total;
> +	int request_succeeded = 0;
> +	struct fb_info *info;
> +
> +	if (!screen_info.lfb_depth)
> +		screen_info.lfb_depth = 32;
> +	if (!screen_info.pages)
> +		screen_info.pages = 1;
> +	if (!screen_info.lfb_base) {
> +		printk(KERN_DEBUG "linearfb: invalid framebuffer address\n");
> +		return -ENODEV;
> +	}
> +	printk(KERN_INFO "linearfb: probing for linearfb\n");
> +
> +	/* just assume they're all unset if any are */
> +	if (!screen_info.blue_size) {
> +		screen_info.blue_size = 8;
> +		screen_info.blue_pos = 0;
> +		screen_info.green_size = 8;
> +		screen_info.green_pos = 8;
> +		screen_info.red_size = 8;
> +		screen_info.red_pos = 16;
> +		screen_info.rsvd_size = 8;
> +		screen_info.rsvd_pos = 24;
> +	}
> +
> +	linearfb_fix.smem_start = screen_info.lfb_base;
> +	linearfb_defined.bits_per_pixel = screen_info.lfb_depth;
> +	linearfb_defined.xres = screen_info.lfb_width;
> +	linearfb_defined.yres = screen_info.lfb_height;
> +	linearfb_fix.line_length = screen_info.lfb_linelength;
> +
> +	/*   size_vmode -- that is the amount of memory needed for the
> +	 *                 used video mode, i.e. the minimum amount of
> +	 *                 memory we need. */
> +	size_vmode = linearfb_defined.yres * linearfb_fix.line_length;
> +
> +	/*   size_total -- all video memory we have. Used for
> +	 *                 entries, ressource allocation and bounds
> +	 *                 checking. */
> +	size_total = screen_info.lfb_size;
> +	if (size_total < size_vmode)
> +		size_total = size_vmode;
> +
> +	/*   size_remap -- the amount of video memory we are going to
> +	 *                 use for linearfb.  With modern cards it is no
> +	 *                 option to simply use size_total as that
> +	 *                 wastes plenty of kernel address space. */
> +	size_remap  = size_vmode * 2;
> +	if (size_remap > size_total)
> +		size_remap = size_total;
> +	if (size_remap % PAGE_SIZE)
> +		size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
> +	linearfb_fix.smem_len = size_remap;
> +
> +	if (request_mem_region(linearfb_fix.smem_start, size_remap,
> +	    "linearfb")) {
> +		request_succeeded = 1;
> +	} else {
> +		/* We cannot make this fatal. Sometimes this comes from magic
> +		   spaces our resource handlers simply don't know about */
> +		printk(KERN_WARNING
> +		       "linearfb: cannot reserve video memory at 0x%lx\n",
> +			linearfb_fix.smem_start);
> +	}
> +
> +	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
> +	if (!info) {
> +		printk(KERN_ERR "linearfb: cannot allocate framebuffer\n");
> +		err = -ENOMEM;
> +		goto err_release_mem;
> +	}
> +	info->pseudo_palette = info->par;
> +	info->par = NULL;
> +
> +	info->apertures = alloc_apertures(1);
> +	if (!info->apertures) {
> +		err = -ENOMEM;
> +		goto err_release_fb;
> +	}
> +	info->apertures->ranges[0].base = linearfb_fix.smem_start;
> +	info->apertures->ranges[0].size = size_remap;
> +
> +	info->screen_base = ioremap(linearfb_fix.smem_start,
> +				    linearfb_fix.smem_len);
> +	if (!info->screen_base) {
> +		printk(KERN_ERR "linearfb: abort, cannot ioremap video memory "
> +				"0x%x @ 0x%lx\n",
> +			linearfb_fix.smem_len, linearfb_fix.smem_start);
> +		err = -EIO;
> +		goto err_release_fb;
> +	}
> +
> +	printk(KERN_INFO "linearfb: framebuffer at 0x%lx, mapped to 0x%p, "
> +	       "using %dk, total %dk\n",
> +	       linearfb_fix.smem_start, info->screen_base,
> +	       size_remap/1024, size_total/1024);
> +	printk(KERN_INFO
> +	       "linearfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
> +	       linearfb_defined.xres, linearfb_defined.yres,
> +	       linearfb_defined.bits_per_pixel, linearfb_fix.line_length,
> +	       screen_info.pages);
> +
> +	linearfb_defined.xres_virtual = linearfb_defined.xres;
> +	linearfb_defined.yres_virtual = linearfb_fix.smem_len /
> +					linearfb_fix.line_length;
> +	printk(KERN_INFO "linearfb: scrolling: redraw\n");
> +	linearfb_defined.yres_virtual = linearfb_defined.yres;
> +
> +	/* some dummy values for timing to make fbset happy */
> +	linearfb_defined.pixclock     = 10000000 / linearfb_defined.xres *
> +					1000 / linearfb_defined.yres;
> +	linearfb_defined.left_margin  = (linearfb_defined.xres / 8) & 0xf8;
> +	linearfb_defined.hsync_len    = (linearfb_defined.xres / 8) & 0xf8;
> +
> +	linearfb_defined.red.offset    = screen_info.red_pos;
> +	linearfb_defined.red.length    = screen_info.red_size;
> +	linearfb_defined.green.offset  = screen_info.green_pos;
> +	linearfb_defined.green.length  = screen_info.green_size;
> +	linearfb_defined.blue.offset   = screen_info.blue_pos;
> +	linearfb_defined.blue.length   = screen_info.blue_size;
> +	linearfb_defined.transp.offset = screen_info.rsvd_pos;
> +	linearfb_defined.transp.length = screen_info.rsvd_size;
> +
> +	printk(KERN_INFO "linearfb: %s: "
> +	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
> +	       "Truecolor",
> +	       screen_info.rsvd_size,
> +	       screen_info.red_size,
> +	       screen_info.green_size,
> +	       screen_info.blue_size,
> +	       screen_info.rsvd_pos,
> +	       screen_info.red_pos,
> +	       screen_info.green_pos,
> +	       screen_info.blue_pos);
> +
> +	linearfb_fix.ypanstep  = 0;
> +	linearfb_fix.ywrapstep = 0;
> +
> +	info->fbops = &linearfb_ops;
> +	info->var = linearfb_defined;
> +	info->fix = linearfb_fix;
> +	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
> +
> +	if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
> +		printk(KERN_ERR "linearfb: cannot allocate colormap\n");
> +		goto err_unmap;
> +	}
> +	*p_info = info;
> +	return 0;
> +
> +err_unmap:
> +	iounmap(info->screen_base);
> +err_release_fb:
> +	framebuffer_release(info);
> +err_release_mem:
> +	if (request_succeeded)
> +		release_mem_region(linearfb_fix.smem_start, size_total);
> +	return err;
> +}
> +EXPORT_SYMBOL(linearfb_get_info);
> +
> +static int linearfb_probe(struct platform_device *dev)
> +{
> +	int err;
> +	struct fb_info *info;
> +
> +	if ((err = linearfb_get_info(dev, &info)) < 0)
> +		return err;
> +
> +	if ((err = register_framebuffer(info)) < 0) {
> +		printk(KERN_ERR "linearfb: cannot register framebuffer\n");
> +		goto err_fb_dealloc;
> +	}
> +	printk(KERN_INFO "fb%d: %s frame buffer device\n",
> +		info->node, info->fix.id);
> +	return 0;
> +
> +err_fb_dealloc:
> +	fb_dealloc_cmap(&info->cmap);
> +	linearfb_destroy(info);
> +	return err;
> +}
> +
> +static struct platform_driver linearfb_driver = {
> +	.probe	= linearfb_probe,
> +	.driver	= {
> +		.name	= "linearfb",
> +	},
> +};
> +
> +static struct platform_device linearfb_device = {
> +	.name	= "linearfb",
> +};
> +
> +static int __init linearfb_init(void)
> +{
> +	int ret;
> +	char *option = NULL;
> +
> +	if (screen_info.orig_video_isVGA != VIDEO_TYPE_LINEAR)
> +		return -ENODEV;
> +
> +	if (fb_get_options("linearfb", &option))
> +		return -ENODEV;
> +	linearfb_setup(option);
> +
> +	if (!screen_info.lfb_linelength)
> +		return -ENODEV;
> +
> +	ret = platform_driver_register(&linearfb_driver);
> +
> +	if (!ret) {
> +		ret = platform_device_register(&linearfb_device);
> +		if (ret)
> +			platform_driver_unregister(&linearfb_driver);
> +	}
> +	return ret;
> +}
> +module_init(linearfb_init);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index 8e5a9df..0913385 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -1137,6 +1137,14 @@ extern int fb_find_mode(struct fb_var_screeninfo *var,
>  			const struct fb_videomode *default_mode,
>  			unsigned int default_bpp);
>  
> +#ifdef CONFIG_FB_LINEAR
> +struct platform_device;
> +
> +extern void linearfb_destroy(struct fb_info *info);
> +extern int linearfb_get_info(struct platform_device *dev,
> +			     struct fb_info **p_info);
> +#endif /* CONFIG_FB_LINEAR */
> +
>  #endif /* __KERNEL__ */
>  
>  #endif /* _LINUX_FB_H */
> diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
> index 899fbb4..129f533 100644
> --- a/include/linux/screen_info.h
> +++ b/include/linux/screen_info.h
> @@ -66,6 +66,8 @@ struct screen_info {
>  
>  #define VIDEO_TYPE_EFI		0x70	/* EFI graphic mode		*/
>  
> +#define VIDEO_TYPE_LINEAR	0x80	/* Simple linear frame bufffer	*/
> +
>  #define VIDEO_FLAGS_NOCURSOR	(1 << 0) /* The video mode has no cursor set */
>  
>  #ifdef __KERNEL__


-- 
        Peter

I'd like to start a religion. That's where the money is.
		-- L. Ron Hubbard to Lloyd Eshbach, in 1949;
			quoted by Eshbach in _Over My Shoulder_.

01234567890123456789012345678901234567890123456789012345678901234567890123456789

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add new linearfb driver
  2010-08-25 14:11 [PATCH] Add new linearfb driver Colin Watson
  2010-08-25 15:03 ` Peter Jones
@ 2010-08-25 17:04 ` Bruno Prémont
  2010-08-25 17:24   ` Peter Jones
  2010-08-25 17:28   ` Colin Watson
  2010-08-25 20:22 ` Geert Uytterhoeven
  2 siblings, 2 replies; 6+ messages in thread
From: Bruno Prémont @ 2010-08-25 17:04 UTC (permalink / raw)
  To: Colin Watson; +Cc: linux-fbdev, linux-kernel, Peter Jones, Matthew Garrett

On Wed, 25 August 2010 Colin Watson <cjwatson@canonical.com> wrote:
> Split out linearfb from efifb so that boot loaders can program it as a
> simple linear framebuffer on non-EFI systems.  This is useful for boot
> loaders with their own graphics drivers, e.g. GRUB 2, since in some
> cases on x86 they can set up non-VESA modes and thus can't program
> vesafb.
> 
> efifb is reworked on top of this common code, and it should be possible
> to do the same with some other framebuffer drivers in future.
> 
> Signed-off-by: Colin Watson <cjwatson@canonical.com>
> Acked-by: Matthew Garrett <mjg@redhat.com>
> Cc: Peter Jones <pjones@redhat.com>
> ---
>  drivers/video/Kconfig       |   17 ++-
>  drivers/video/Makefile      |    1 +
>  drivers/video/efifb.c       |  222 +----------------------------
>  drivers/video/linearfb.c    |  332 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fb.h          |    8 +
>  include/linux/screen_info.h |    2 +
>  6 files changed, 364 insertions(+), 218 deletions(-)
>  create mode 100644 drivers/video/linearfb.c
> 
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 59c51d9..a7735ec 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -721,13 +721,24 @@ config FB_VESA
>  	  You will get a boot time penguin logo at no additional cost. Please
>  	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
>  
> -config FB_EFI
> -	bool "EFI-based Framebuffer Support"
> -	depends on (FB = y) && X86 && EFI
> +config FB_LINEAR
> +	bool "Simple linear framebuffer support"
> +	depends on FB
>  	select FB_CFB_FILLRECT
>  	select FB_CFB_COPYAREA
>  	select FB_CFB_IMAGEBLIT
        ^^^^^^^^^^^^^^^^^^^^^^^

>  	help
> +	  This is a simple linear frame buffer device driver. It has no
> +	  hardware-specific programming capability, but must be programmed
> +	  by the boot loader or by another frame buffer driver.
> +
> +	  If unsure, say N.
> +
> +config FB_EFI
> +	bool "EFI-based Framebuffer Support"
> +	depends on (FB = y) && X86 && EFI
> +	select FB_LINEAR
        ^^^^^^^^^^^^^^^^
  Has kconfig been adjusted to process select recursively?
  If not the selects from FB_LINEAR will have to be copied here.

  Bruno


> +	help
>  	  This is the EFI frame buffer device driver. If the firmware on
>  	  your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
>  	  using the EFI framebuffer as your console.
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index ddc2af2..ad74d3b 100644

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add new linearfb driver
  2010-08-25 17:04 ` Bruno Prémont
@ 2010-08-25 17:24   ` Peter Jones
  2010-08-25 17:28   ` Colin Watson
  1 sibling, 0 replies; 6+ messages in thread
From: Peter Jones @ 2010-08-25 17:24 UTC (permalink / raw)
  To: Bruno Prémont
  Cc: Colin Watson, linux-fbdev, linux-kernel, Matthew Garrett

On 08/25/2010 01:04 PM, Bruno Prémont wrote:
> On Wed, 25 August 2010 Colin Watson <cjwatson@canonical.com> wrote:
>> Split out linearfb from efifb so that boot loaders can program it as a
>> simple linear framebuffer on non-EFI systems.  This is useful for boot
>> loaders with their own graphics drivers, e.g. GRUB 2, since in some
>> cases on x86 they can set up non-VESA modes and thus can't program
>> vesafb.
>>
>> efifb is reworked on top of this common code, and it should be possible
>> to do the same with some other framebuffer drivers in future.
>>
>> Signed-off-by: Colin Watson <cjwatson@canonical.com>
>> Acked-by: Matthew Garrett <mjg@redhat.com>
>> Cc: Peter Jones <pjones@redhat.com>
>> ---
>>  drivers/video/Kconfig       |   17 ++-
>>  drivers/video/Makefile      |    1 +
>>  drivers/video/efifb.c       |  222 +----------------------------
>>  drivers/video/linearfb.c    |  332 +++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/fb.h          |    8 +
>>  include/linux/screen_info.h |    2 +
>>  6 files changed, 364 insertions(+), 218 deletions(-)
>>  create mode 100644 drivers/video/linearfb.c
>>
>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>> index 59c51d9..a7735ec 100644
>> --- a/drivers/video/Kconfig
>> +++ b/drivers/video/Kconfig
>> @@ -721,13 +721,24 @@ config FB_VESA
>>  	  You will get a boot time penguin logo at no additional cost. Please
>>  	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
>>  
>> -config FB_EFI
>> -	bool "EFI-based Framebuffer Support"
>> -	depends on (FB = y) && X86 && EFI
>> +config FB_LINEAR
>> +	bool "Simple linear framebuffer support"
>> +	depends on FB
>>  	select FB_CFB_FILLRECT
>>  	select FB_CFB_COPYAREA
>>  	select FB_CFB_IMAGEBLIT
>         ^^^^^^^^^^^^^^^^^^^^^^^
> 
>>  	help
>> +	  This is a simple linear frame buffer device driver. It has no
>> +	  hardware-specific programming capability, but must be programmed
>> +	  by the boot loader or by another frame buffer driver.
>> +
>> +	  If unsure, say N.
>> +
>> +config FB_EFI
>> +	bool "EFI-based Framebuffer Support"
>> +	depends on (FB = y) && X86 && EFI
>> +	select FB_LINEAR
>         ^^^^^^^^^^^^^^^^
>   Has kconfig been adjusted to process select recursively?
>   If not the selects from FB_LINEAR will have to be copied here.

This could also be solved by just making it depend on FB_LINEAR instead of
using "select".

-- 
        Peter

I number the Linux folks among my personal heroes.
		-- Donald Knuth

01234567890123456789012345678901234567890123456789012345678901234567890123456789

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add new linearfb driver
  2010-08-25 17:04 ` Bruno Prémont
  2010-08-25 17:24   ` Peter Jones
@ 2010-08-25 17:28   ` Colin Watson
  1 sibling, 0 replies; 6+ messages in thread
From: Colin Watson @ 2010-08-25 17:28 UTC (permalink / raw)
  To: Bruno Prémont
  Cc: linux-fbdev, linux-kernel, Peter Jones, Matthew Garrett

On Wed, Aug 25, 2010 at 07:04:38PM +0200, Bruno Prémont wrote:
> On Wed, 25 August 2010 Colin Watson <cjwatson@canonical.com> wrote:
> > -config FB_EFI
> > -	bool "EFI-based Framebuffer Support"
> > -	depends on (FB = y) && X86 && EFI
> > +config FB_LINEAR
> > +	bool "Simple linear framebuffer support"
> > +	depends on FB
> >  	select FB_CFB_FILLRECT
> >  	select FB_CFB_COPYAREA
> >  	select FB_CFB_IMAGEBLIT
>         ^^^^^^^^^^^^^^^^^^^^^^^
> 
> > +config FB_EFI
> > +	bool "EFI-based Framebuffer Support"
> > +	depends on (FB = y) && X86 && EFI
> > +	select FB_LINEAR
>         ^^^^^^^^^^^^^^^^
>   Has kconfig been adjusted to process select recursively?
>   If not the selects from FB_LINEAR will have to be copied here.

When I start with a consistent .config with FB_CFB_FILLRECT unset, then
'make menuconfig' and enable FB_EFI, the resulting .config has
CONFIG_FB_CFB_FILLRECT=y.  That should be a sufficient test, shouldn't
it?

Thanks,

-- 
Colin Watson                                    [cjwatson@canonical.com]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Add new linearfb driver
  2010-08-25 14:11 [PATCH] Add new linearfb driver Colin Watson
  2010-08-25 15:03 ` Peter Jones
  2010-08-25 17:04 ` Bruno Prémont
@ 2010-08-25 20:22 ` Geert Uytterhoeven
  2 siblings, 0 replies; 6+ messages in thread
From: Geert Uytterhoeven @ 2010-08-25 20:22 UTC (permalink / raw)
  To: Colin Watson; +Cc: linux-fbdev, linux-kernel, Peter Jones, Matthew Garrett

On Wed, Aug 25, 2010 at 16:11, Colin Watson <cjwatson@canonical.com> wrote:
> Split out linearfb from efifb so that boot loaders can program it as a
> simple linear framebuffer on non-EFI systems.  This is useful for boot
> loaders with their own graphics drivers, e.g. GRUB 2, since in some
> cases on x86 they can set up non-VESA modes and thus can't program
> vesafb.

Nice! I guess offb and a few other old drivers could use it, too.

> diff --git a/drivers/video/linearfb.c b/drivers/video/linearfb.c
> new file mode 100644
> index 0000000..c93eaac
> --- /dev/null
> +++ b/drivers/video/linearfb.c

> +int linearfb_get_info(struct platform_device *dev, struct fb_info **p_info)
> +{
> +       int err;
> +       unsigned int size_vmode;
> +       unsigned int size_remap;
> +       unsigned int size_total;
> +       int request_succeeded = 0;
> +       struct fb_info *info;
> +
> +       if (!screen_info.lfb_depth)
> +               screen_info.lfb_depth = 32;
> +       if (!screen_info.pages)
> +               screen_info.pages = 1;
> +       if (!screen_info.lfb_base) {
> +               printk(KERN_DEBUG "linearfb: invalid framebuffer address\n");
> +               return -ENODEV;
> +       }

[...]

Wouldn't it be more logical to extract this info somewhere from the
platform_device's
platform_data? Screen_info is such a legacy thing.
That way linearfb can support multiple displays as well.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-08-25 20:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-25 14:11 [PATCH] Add new linearfb driver Colin Watson
2010-08-25 15:03 ` Peter Jones
2010-08-25 17:04 ` Bruno Prémont
2010-08-25 17:24   ` Peter Jones
2010-08-25 17:28   ` Colin Watson
2010-08-25 20:22 ` Geert Uytterhoeven

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).