Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH 2/9] video: sysfb: new vbefb device type
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

From: David Herrmann <dh.herrmann@googlemail.com>

This adds the VESA BIOS Extension (VBE) device type. Platform code needs
to provide the "vbefb" platform-device with a screen_info structure as
platform code.

All drivers that depend on VBE can now register as bus drivers and bind
to SYSFB_VBE devices. There is no distinction between graphics
framebuffers or plain text VGA. Drivers ought to inspect the screen_info
and return -ENODEV during probe() is they cannot make use of the device.

Only one framebuffer of type SYSFB_VBE is available on a system at a time.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/video/sysfb.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sysfb.h |  5 +++-
 2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
index 8249006..5b47a9a 100644
--- a/drivers/video/sysfb.c
+++ b/drivers/video/sysfb.c
@@ -205,6 +205,72 @@ void sysfb_taint(struct sysfb_device *sdev, bool set)
 }
 EXPORT_SYMBOL(sysfb_taint);
 
+static void sysfb_dev_release(struct device *dev)
+{
+	struct sysfb_device *sdev = to_sysfb_device(dev);
+
+	kfree(sdev);
+}
+
+static struct sysfb_device *sysfb_dev_new(struct device *parent)
+{
+	struct sysfb_device *sdev;
+
+	sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+	if (!sdev)
+		return NULL;
+
+	device_initialize(&sdev->dev);
+	sdev->dev.release = sysfb_dev_release;
+	sdev->dev.bus = &sysfb_bus_type;
+	sdev->dev.parent = parent;
+
+	return sdev;
+}
+
+static int sysfb_vbe_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sysfb_device *sdev;
+
+	sdev = sysfb_dev_new(&pdev->dev);
+	if (!sdev)
+		return -ENOMEM;
+
+	dev_set_name(&sdev->dev, "vbefb");
+	sdev->type = SYSFB_VBE;
+	sdev->screen = pdev->dev.platform_data;
+
+	ret = device_add(&sdev->dev);
+	if (ret)
+		goto err_free;
+
+	platform_set_drvdata(pdev, sdev);
+	return 0;
+
+err_free:
+	put_device(&sdev->dev);
+	return ret;
+}
+
+static int sysfb_vbe_remove(struct platform_device *pdev)
+{
+	struct sysfb_device *sdev = platform_get_drvdata(pdev);
+
+	device_del(&sdev->dev);
+	put_device(&sdev->dev);
+	return 0;
+}
+
+static struct platform_driver sysfb_vbe_driver = {
+	.driver = {
+		.name = "vbefb",
+		.owner = THIS_MODULE,
+	},
+	.probe = sysfb_vbe_probe,
+	.remove = sysfb_vbe_remove,
+};
+
 static int __init sysfb_init(void)
 {
 	int ret;
@@ -215,11 +281,22 @@ static int __init sysfb_init(void)
 		return ret;
 	}
 
+	ret = platform_driver_register(&sysfb_vbe_driver);
+	if (ret) {
+		pr_err("cannot register VBE framebuffer driver\n");
+		goto err_bus;
+	}
+
 	return 0;
+
+err_bus:
+	bus_unregister(&sysfb_bus_type);
+	return ret;
 }
 
 static void __exit sysfb_exit(void)
 {
+	platform_driver_unregister(&sysfb_vbe_driver);
 	bus_unregister(&sysfb_bus_type);
 }
 
diff --git a/include/linux/sysfb.h b/include/linux/sysfb.h
index 6cd3c24..1796c1e 100644
--- a/include/linux/sysfb.h
+++ b/include/linux/sysfb.h
@@ -20,6 +20,7 @@
 
 /**
  * sysfb_type
+ * @SYSFB_VBE: VESA BIOS Extension compatible device (includes VGA devices)
  *
  * Different types of available framebuffer devices. Only one device of each
  * type can be available at a time. In most systems there even is only one
@@ -29,7 +30,9 @@
  * devices.
  */
 enum sysfb_type {
-	SYSFB_TYPES = 0,
+	SYSFB_VBE = 0x01,
+
+	SYSFB_TYPES = SYSFB_VBE,
 };
 
 /**
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 3/9] video: sysfb: always provide vbefb device
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

From: David Herrmann <dh.herrmann@googlemail.com>

HACK: This should be provided by architecture setup code. But to show how it is
supposed to work, we now simply add a "vbefb" device during initialization.

The better way to do this is by moving this into arch-code. So for instance the
x86 boot initialization should create this platform-device after VBE/VESA screen
detection. Other architectures can do the same or introduce other framebuffer
types than SYSFB_VBE.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/video/sysfb.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/video/sysfb.c b/drivers/video/sysfb.c
index 5b47a9a..0c0a4e7 100644
--- a/drivers/video/sysfb.c
+++ b/drivers/video/sysfb.c
@@ -271,6 +271,8 @@ static struct platform_driver sysfb_vbe_driver = {
 	.remove = sysfb_vbe_remove,
 };
 
+static struct platform_device *sysfb_vbe_device;
+
 static int __init sysfb_init(void)
 {
 	int ret;
@@ -287,6 +289,12 @@ static int __init sysfb_init(void)
 		goto err_bus;
 	}
 
+	sysfb_vbe_device = platform_device_register_data(NULL, "vbefb", -1,
+							 &screen_info,
+							 sizeof(screen_info));
+	if (!sysfb_vbe_device)
+		pr_warn("cannot create vbefb device\n");
+
 	return 0;
 
 err_bus:
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 4/9] video: vesafb: allow building as module
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

From: David Herrmann <dh.herrmann@googlemail.com>

Fix the vesafb module to no longer use any static __init data. Also add a
module_exit() function that destroys the platform device.

Note that fbdev hotplugging is broken and the self-reference actually
prevents sane module-unloading. Anyway, this at least allows delayed
module loading of vesafb and helps debugging vesafb a lot.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/video/Kconfig  |   2 +-
 drivers/video/vesafb.c | 100 +++++++++++++++++++++++++++++++------------------
 2 files changed, 64 insertions(+), 38 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index eac56ef..d5723c2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -770,7 +770,7 @@ config FB_UVESA
 	  If unsure, say N.
 
 config FB_VESA
-	bool "VESA VGA graphics support"
+	tristate "VESA VGA graphics support"
 	depends on (FB = y) && X86
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 501b340..4ad7b40 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -29,27 +29,10 @@
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vesafb_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 vesafb_fix __initdata = {
-	.id	= "VESA VGA",
-	.type	= FB_TYPE_PACKED_PIXELS,
-	.accel	= FB_ACCEL_NONE,
-};
-
 static int   inverse    __read_mostly;
 static int   mtrr       __read_mostly;		/* disable mtrr */
-static int   vram_remap __initdata;		/* Set amount of memory to be used */
-static int   vram_total __initdata;		/* Set total amount of memory */
+static int   vram_remap;			/* Set amount of memory to be used */
+static int   vram_total;			/* Set total amount of memory */
 static int   pmi_setpal __read_mostly = 1;	/* pmi for palette changes ??? */
 static int   ypan       __read_mostly;		/* 0..nothing, 1..ypan, 2..ywrap */
 static void  (*pmi_start)(void) __read_mostly;
@@ -58,6 +41,11 @@ static int   depth      __read_mostly;
 static int   vga_compat __read_mostly;
 /* --------------------------------------------------------------------- */
 
+struct vesafb_par {
+	struct fb_ops ops;
+	u32 palette[256];
+};
+
 static int vesafb_pan_display(struct fb_var_screeninfo *var,
                               struct fb_info *info)
 {
@@ -182,7 +170,7 @@ static void vesafb_destroy(struct fb_info *info)
 	framebuffer_release(info);
 }
 
-static struct fb_ops vesafb_ops = {
+static const struct fb_ops vesafb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_destroy     = vesafb_destroy,
 	.fb_setcolreg	= vesafb_setcolreg,
@@ -192,7 +180,7 @@ static struct fb_ops vesafb_ops = {
 	.fb_imageblit	= cfb_imageblit,
 };
 
-static int __init vesafb_setup(char *options)
+static int vesafb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -226,13 +214,29 @@ static int __init vesafb_setup(char *options)
 	return 0;
 }
 
-static int __init vesafb_probe(struct platform_device *dev)
+static int vesafb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
+	struct vesafb_par *par;
 	int i, err;
 	unsigned int size_vmode;
 	unsigned int size_remap;
 	unsigned int size_total;
+	struct fb_var_screeninfo vesafb_defined = {
+		.activate	= FB_ACTIVATE_NOW,
+		.height		= -1,
+		.width		= -1,
+		.right_margin	= 32,
+		.upper_margin	= 16,
+		.lower_margin	= 4,
+		.vsync_len	= 4,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	};
+	struct fb_fix_screeninfo vesafb_fix = {
+		.id	= "VESA VGA",
+		.type	= FB_TYPE_PACKED_PIXELS,
+		.accel	= FB_ACCEL_NONE,
+	};
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
 		return -ENODEV;
@@ -287,13 +291,14 @@ static int __init vesafb_probe(struct platform_device *dev)
 		   spaces our resource handlers simply don't know about */
 	}
 
-	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+	info = framebuffer_alloc(sizeof(struct vesafb_par), &dev->dev);
 	if (!info) {
 		release_mem_region(vesafb_fix.smem_start, size_total);
 		return -ENOMEM;
 	}
-	info->pseudo_palette = info->par;
-	info->par = NULL;
+	par = info->par;
+	par->ops = vesafb_ops;
+	info->pseudo_palette = par->palette;
 
 	/* set vesafb aperture size for generic probing */
 	info->apertures = alloc_apertures(1);
@@ -466,7 +471,7 @@ static int __init vesafb_probe(struct platform_device *dev)
 	       vesafb_fix.smem_start, info->screen_base,
 	       size_remap/1024, size_total/1024);
 
-	info->fbops = &vesafb_ops;
+	info->fbops = &par->ops;
 	info->var = vesafb_defined;
 	info->fix = vesafb_fix;
 	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
@@ -486,6 +491,7 @@ static int __init vesafb_probe(struct platform_device *dev)
 	}
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       info->node, info->fix.id);
+	platform_set_drvdata(dev, info);
 	return 0;
 err:
 	if (info->screen_base)
@@ -495,7 +501,17 @@ err:
 	return err;
 }
 
+static int vesafb_remove(struct platform_device *dev)
+{
+	struct fb_info *info = platform_get_drvdata(dev);
+
+	unregister_framebuffer(info);
+	return 0;
+}
+
 static struct platform_driver vesafb_driver = {
+	.probe = vesafb_probe,
+	.remove = vesafb_remove,
 	.driver	= {
 		.name	= "vesafb",
 	},
@@ -512,24 +528,34 @@ static int __init vesafb_init(void)
 	fb_get_options("vesafb", &option);
 	vesafb_setup(option);
 
-	vesafb_device = platform_device_alloc("vesafb", 0);
+	vesafb_device = platform_device_alloc("vesafb", -1);
 	if (!vesafb_device)
 		return -ENOMEM;
 
+	ret = platform_driver_register(&vesafb_driver);
+	if (ret)
+		goto err_dev;
+
 	ret = platform_device_add(vesafb_device);
-	if (!ret) {
-		ret = platform_driver_probe(&vesafb_driver, vesafb_probe);
-		if (ret)
-			platform_device_del(vesafb_device);
-	}
+	if (ret)
+		goto err_drv;
 
-	if (ret) {
-		platform_device_put(vesafb_device);
-		vesafb_device = NULL;
-	}
+	return 0;
 
+err_drv:
+	platform_driver_unregister(&vesafb_driver);
+err_dev:
+	platform_device_put(vesafb_device);
 	return ret;
 }
-module_init(vesafb_init);
 
+static void __exit vesafb_exit(void)
+{
+	platform_device_del(vesafb_device);
+	platform_device_put(vesafb_device);
+	platform_driver_unregister(&vesafb_driver);
+}
+
+module_init(vesafb_init);
+module_exit(vesafb_exit);
 MODULE_LICENSE("GPL");
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 5/9] video: vesafb: use sysfb bus
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

Instead of using our own platform device, we now register as sysfb driver
and get notified whenever we are loaded on a system VBE device. This
allows other VBE drivers to be loaded at the same time and users can
bind/unbind drivers via sysfs. We also no longer need to fake a
platform-device because the sysfb bus provides all devices now.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/video/Kconfig  |  1 +
 drivers/video/vesafb.c | 49 +++++++++++++++----------------------------------
 2 files changed, 16 insertions(+), 34 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d5723c2..5c23d32 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -776,6 +776,7 @@ config FB_VESA
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select FB_BOOT_VESA_SUPPORT
+	select SYSFB
 	help
 	  This is the frame buffer device driver for generic VESA 2.0
 	  compliant graphic cards. The older VESA 1.2 cards are not supported.
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 4ad7b40..652858f 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/screen_info.h>
+#include <linux/sysfb.h>
 
 #include <video/vga.h>
 #include <asm/io.h>
@@ -214,7 +215,7 @@ static int vesafb_setup(char *options)
 	return 0;
 }
 
-static int vesafb_probe(struct platform_device *dev)
+static int vesafb_probe(struct sysfb_device *dev)
 {
 	struct fb_info *info;
 	struct vesafb_par *par;
@@ -491,7 +492,7 @@ static int vesafb_probe(struct platform_device *dev)
 	}
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
 	       info->node, info->fix.id);
-	platform_set_drvdata(dev, info);
+	dev_set_drvdata(&dev->dev, info);
 	return 0;
 err:
 	if (info->screen_base)
@@ -501,59 +502,39 @@ err:
 	return err;
 }
 
-static int vesafb_remove(struct platform_device *dev)
+static void vesafb_remove(struct sysfb_device *dev)
 {
-	struct fb_info *info = platform_get_drvdata(dev);
+	struct fb_info *info = dev_get_drvdata(&dev->dev);
 
 	unregister_framebuffer(info);
-	return 0;
 }
 
-static struct platform_driver vesafb_driver = {
+static struct sysfb_driver vesafb_driver = {
+	.type_mask = SYSFB_VBE,
+	.allow_tainted = false,
+	.driver = {
+		.name = "vesafb",
+		.owner = THIS_MODULE,
+		.mod_name = KBUILD_MODNAME,
+	},
 	.probe = vesafb_probe,
 	.remove = vesafb_remove,
-	.driver	= {
-		.name	= "vesafb",
-	},
 };
 
-static struct platform_device *vesafb_device;
-
 static int __init vesafb_init(void)
 {
-	int ret;
 	char *option = NULL;
 
 	/* ignore error return of fb_get_options */
 	fb_get_options("vesafb", &option);
 	vesafb_setup(option);
 
-	vesafb_device = platform_device_alloc("vesafb", -1);
-	if (!vesafb_device)
-		return -ENOMEM;
-
-	ret = platform_driver_register(&vesafb_driver);
-	if (ret)
-		goto err_dev;
-
-	ret = platform_device_add(vesafb_device);
-	if (ret)
-		goto err_drv;
-
-	return 0;
-
-err_drv:
-	platform_driver_unregister(&vesafb_driver);
-err_dev:
-	platform_device_put(vesafb_device);
-	return ret;
+	return sysfb_register_driver(&vesafb_driver);
 }
 
 static void __exit vesafb_exit(void)
 {
-	platform_device_del(vesafb_device);
-	platform_device_put(vesafb_device);
-	platform_driver_unregister(&vesafb_driver);
+	sysfb_unregister_driver(&vesafb_driver);
 }
 
 module_init(vesafb_init);
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 6/9] drm: new sysfb DRM bus module
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

This provides a new DRM bus helper for the system framebuffer bus. It is
very similar in its functionality to the DRM_USB helper. It allows to
write DRM drivers that register as SYSFB drivers to the system.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/Kconfig     |   5 ++
 drivers/gpu/drm/Makefile    |   1 +
 drivers/gpu/drm/drm_sysfb.c | 145 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drmP.h          |   4 ++
 include/drm/drm_sysfb.h     |  35 +++++++++++
 5 files changed, 190 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_sysfb.c
 create mode 100644 include/drm/drm_sysfb.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 18321b68b..2df448e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -25,6 +25,11 @@ config DRM_USB
 	depends on USB_SUPPORT && USB_ARCH_HAS_HCD
 	select USB
 
+config DRM_SYSFB
+	tristate
+	depends on DRM
+	select SYSFB
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 2ff5cef..9249b66 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -29,6 +29,7 @@ CFLAGS_drm_trace_points.o := -I$(src)
 
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_USB)   += drm_usb.o
+obj-$(CONFIG_DRM_SYSFB) += drm_sysfb.o
 obj-$(CONFIG_DRM_TTM)	+= ttm/
 obj-$(CONFIG_DRM_TDFX)	+= tdfx/
 obj-$(CONFIG_DRM_R128)	+= r128/
diff --git a/drivers/gpu/drm/drm_sysfb.c b/drivers/gpu/drm/drm_sysfb.c
new file mode 100644
index 0000000..4e8a823
--- /dev/null
+++ b/drivers/gpu/drm/drm_sysfb.c
@@ -0,0 +1,145 @@
+/*
+ * DRM Bus for sysfb drivers
+ *
+ * Copyright 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/sysfb.h>
+#include <drm/drmP.h>
+
+int drm_get_sysfb_dev(struct sysfb_device *sdev,
+		      struct drm_driver *driver)
+{
+	struct drm_device *dev;
+	int ret;
+
+	DRM_DEBUG("\n");
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&sdev->dev, dev);
+	dev->sysfbdev = sdev;
+	dev->dev = &sdev->dev;
+
+	mutex_lock(&drm_global_mutex);
+
+	ret = drm_fill_in_dev(dev, NULL, driver);
+	if (ret) {
+		DRM_ERROR("drm_fill_in_dev failed\n");
+		goto err_unlock;
+	}
+
+	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
+		if (ret)
+			goto err_unlock;
+	}
+
+	ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
+	if (ret)
+		goto err_ctrl;
+
+	if (dev->driver->load) {
+		ret = dev->driver->load(dev, 0);
+		if (ret)
+			goto err_primary;
+	}
+
+	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		ret = drm_mode_group_init_legacy_group(dev,
+				&dev->primary->mode_group);
+		if (ret)
+			goto err_primary;
+	}
+
+	list_add_tail(&dev->driver_item, &driver->device_list);
+
+	mutex_unlock(&drm_global_mutex);
+
+	DRM_INFO("initialized %s %d.%d.%d %s on minor %d\n",
+		 driver->name, driver->major, driver->minor, driver->patchlevel,
+		 driver->date, dev->primary->index);
+
+	return 0;
+
+err_primary:
+	drm_put_minor(&dev->primary);
+err_ctrl:
+	if (drm_core_check_feature(dev, DRIVER_MODESET))
+		drm_put_minor(&dev->control);
+err_unlock:
+	mutex_unlock(&drm_global_mutex);
+	kfree(dev);
+	return ret;
+}
+EXPORT_SYMBOL(drm_get_sysfb_dev);
+
+static int drm_sysfb_get_irq(struct drm_device *dev)
+{
+	return 0;
+}
+
+static const char *drm_sysfb_get_name(struct drm_device *dev)
+{
+	return dev_name(&dev->sysfbdev->dev);
+}
+
+static int drm_sysfb_set_busid(struct drm_device *dev,
+			       struct drm_master *master)
+{
+	return 0;
+}
+
+static struct drm_bus drm_sysfb_bus = {
+	.bus_type = DRIVER_BUS_SYSFB,
+	.get_irq = drm_sysfb_get_irq,
+	.get_name = drm_sysfb_get_name,
+	.set_busid = drm_sysfb_set_busid,
+};
+
+int drm_sysfb_init(struct drm_driver *driver, struct sysfb_driver *sdrv)
+{
+	DRM_DEBUG("\n");
+
+	INIT_LIST_HEAD(&driver->device_list);
+	driver->kdriver.sysfb = sdrv;
+	driver->bus = &drm_sysfb_bus;
+
+	return sysfb_register_driver(sdrv);
+}
+EXPORT_SYMBOL(drm_sysfb_init);
+
+void drm_sysfb_exit(struct drm_driver *driver, struct sysfb_driver *sdrv)
+{
+	DRM_DEBUG("\n");
+
+	sysfb_unregister_driver(sdrv);
+	DRM_INFO("module unloaded\n");
+}
+EXPORT_SYMBOL(drm_sysfb_exit);
+
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("DRM sysfb support");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3fd8280..e5d73fe 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -71,6 +71,7 @@
 #endif
 #include <linux/workqueue.h>
 #include <linux/poll.h>
+#include <linux/sysfb.h>
 #include <asm/pgalloc.h>
 #include <drm/drm.h>
 #include <drm/drm_sarea.h>
@@ -157,6 +158,7 @@ int drm_err(const char *func, const char *format, ...);
 #define DRIVER_BUS_PCI 0x1
 #define DRIVER_BUS_PLATFORM 0x2
 #define DRIVER_BUS_USB 0x3
+#define DRIVER_BUS_SYSFB 0x4
 
 /***********************************************************************/
 /** \name Begin the DRM... */
@@ -953,6 +955,7 @@ struct drm_driver {
 		struct pci_driver *pci;
 		struct platform_device *platform_device;
 		struct usb_driver *usb;
+		struct sysfb_driver *sysfb;
 	} kdriver;
 	struct drm_bus *bus;
 
@@ -1173,6 +1176,7 @@ struct drm_device {
 
 	struct platform_device *platformdev; /**< Platform device struture */
 	struct usb_device *usbdev;
+	struct sysfb_device *sysfbdev;
 
 	struct drm_sg_mem *sg;	/**< Scatter gather memory */
 	unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
diff --git a/include/drm/drm_sysfb.h b/include/drm/drm_sysfb.h
new file mode 100644
index 0000000..ced54d7
--- /dev/null
+++ b/include/drm/drm_sysfb.h
@@ -0,0 +1,35 @@
+#ifndef __DRM_SYSFB_H
+#define __DRM_SYSFB_H
+/*
+ * DRM Bus for sysfb drivers
+ *
+ * Copyright 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <drmP.h>
+#include <linux/sysfb.h>
+
+int drm_sysfb_init(struct drm_driver *driver, struct sysfb_driver *sdrv);
+void drm_sysfb_exit(struct drm_driver *driver, struct sysfb_driver *sdrv);
+int drm_get_sysfb_dev(struct sysfb_device *sdev,
+		      struct drm_driver *driver);
+
+#endif /* __DRM_SYSFB_H */
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 7/9] drm: new VESA BIOS Extension DRM driver stub
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

This driver uses the VESA BIOS Extensions to control the display device.
Modesetting has to be done during the boot-process by the architecture
code (same way as vesafb requires it). No runtime modesetting is allowed
due to RealMode/ProtectedMode restrictions.

This patch only introduces the stub DRM driver without any VESA/VBE
backend that actually touches the hardware.

The driver simply provides a single crtc+encoder+connector combination
that user-space can use to access the VBE framebuffer. No page-flips are
supported and users must explicitly mark buffers as dirty to get them
copied into the framebuffer.

All buffer objects are backed by shmem so we can later add PRIME support.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/Kconfig          |   2 +
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/dvbe/Kconfig     |  28 +++
 drivers/gpu/drm/dvbe/Makefile    |   4 +
 drivers/gpu/drm/dvbe/dvbe.h      |  73 +++++++
 drivers/gpu/drm/dvbe/dvbe_drv.c  | 104 ++++++++++
 drivers/gpu/drm/dvbe/dvbe_main.c | 399 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/dvbe/dvbe_mem.c  | 269 ++++++++++++++++++++++++++
 8 files changed, 880 insertions(+)
 create mode 100644 drivers/gpu/drm/dvbe/Kconfig
 create mode 100644 drivers/gpu/drm/dvbe/Makefile
 create mode 100644 drivers/gpu/drm/dvbe/dvbe.h
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_drv.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_main.c
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_mem.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 2df448e..fbbdabc 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -215,3 +215,5 @@ source "drivers/gpu/drm/mgag200/Kconfig"
 source "drivers/gpu/drm/cirrus/Kconfig"
 
 source "drivers/gpu/drm/shmobile/Kconfig"
+
+source "drivers/gpu/drm/dvbe/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9249b66..ec91ae8 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -49,4 +49,5 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
+obj-$(CONFIG_DRM_DVBE) += dvbe/
 obj-y			+= i2c/
diff --git a/drivers/gpu/drm/dvbe/Kconfig b/drivers/gpu/drm/dvbe/Kconfig
new file mode 100644
index 0000000..bb3aa7b
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/Kconfig
@@ -0,0 +1,28 @@
+config DRM_DVBE
+	tristate "VESA BIOS Extension DRM Driver"
+	depends on DRM
+	select DRM_KMS_HELPER
+	select DRM_SYSFB
+	help
+	  This is a DRM/KMS driver for VESA BIOS Extension (VBE) compatible
+	  cards. At least VBE 2.0 is needed. Older VBE 1.2 cards are not
+	  supported.
+	  Nearly all modern x86 graphics cards support VBE 2.0 so this driver
+	  should work with all those graphics cards. However, it does not allow
+	  mode-switching during runtime but requires the kernel to setup the
+	  mode with the vga= kernel command line option. If you want full
+	  support for your graphics card, please select a driver for your
+	  specific model.
+
+	  This driver can be enabled together with any other DRM graphics
+	  driver. If another driver probes a device that conflicts with DVBE,
+	  then DVBE will automatically drop the device and let the
+	  model-specific driver take precedence.
+
+	  This driver replaces the old vesafb framebuffer driver and provides
+	  full backwards compatibility.
+
+	  If unsure, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dvbe.
diff --git a/drivers/gpu/drm/dvbe/Makefile b/drivers/gpu/drm/dvbe/Makefile
new file mode 100644
index 0000000..b053da3
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/Makefile
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+
+dvbe-y := dvbe_drv.o dvbe_main.o dvbe_mem.o
+obj-$(CONFIG_DRM_DVBE) := dvbe.o
diff --git a/drivers/gpu/drm/dvbe/dvbe.h b/drivers/gpu/drm/dvbe/dvbe.h
new file mode 100644
index 0000000..0235a95
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe.h
@@ -0,0 +1,73 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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.
+ */
+
+#ifndef DVBE_DRV_H
+#define DVBE_DRV_H
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+
+/* dvbe devices */
+
+struct dvbe_device {
+	struct drm_device *ddev;
+
+	/* mode-setting objects */
+	struct drm_crtc crtc;
+	struct drm_encoder enc;
+	struct drm_connector conn;
+	struct drm_display_mode *mode;
+};
+
+int dvbe_drm_load(struct drm_device *ddev, unsigned long flags);
+int dvbe_drm_unload(struct drm_device *ddev);
+int dvbe_drm_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* dvbe gem objects */
+
+struct dvbe_gem_object {
+	struct drm_gem_object base;
+	struct page **pages;
+	uint8_t *vmapping;
+};
+
+#define to_dvbe_bo(x) container_of(x, struct dvbe_gem_object, base)
+
+int dvbe_gem_init_object(struct drm_gem_object *obj);
+void dvbe_gem_free_object(struct drm_gem_object *obj);
+int dvbe_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+int dvbe_gem_vmap(struct dvbe_gem_object *obj);
+void dvbe_gem_vunmap(struct dvbe_gem_object *obj);
+
+/* dumb buffers */
+
+int dvbe_dumb_create(struct drm_file *file_priv, struct drm_device *ddev,
+		     struct drm_mode_create_dumb *arg);
+int dvbe_dumb_destroy(struct drm_file *file_priv, struct drm_device *ddev,
+		      uint32_t handle);
+int dvbe_dumb_map_offset(struct drm_file *file_priv, struct drm_device *ddev,
+			 uint32_t handle, uint64_t *offset);
+
+/* dvbe framebuffers */
+
+struct dvbe_framebuffer {
+	struct drm_framebuffer base;
+	struct dvbe_gem_object *obj;
+};
+
+#define to_dvbe_fb(x) container_of(x, struct dvbe_framebuffer, base)
+
+#endif /* DVBE_DRV_H */
diff --git a/drivers/gpu/drm/dvbe/dvbe_drv.c b/drivers/gpu/drm/dvbe/dvbe_drv.c
new file mode 100644
index 0000000..98d4d37
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe_drv.c
@@ -0,0 +1,104 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/sysfb.h>
+#include <drm/drmP.h>
+#include <drm/drm_sysfb.h>
+#include "dvbe.h"
+
+static const struct vm_operations_struct dvbe_gem_vm_ops = {
+	.fault = dvbe_gem_fault,
+	.open = drm_gem_vm_open,
+	.close = drm_gem_vm_close,
+};
+
+static const struct file_operations dvbe_drm_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.mmap = dvbe_drm_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl = drm_ioctl,
+	.release = drm_release,
+	.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.llseek = noop_llseek,
+};
+
+static struct drm_driver dvbe_drm_driver = {
+	.driver_features = DRIVER_MODESET | DRIVER_GEM,
+	.load = dvbe_drm_load,
+	.unload = dvbe_drm_unload,
+	.fops = &dvbe_drm_fops,
+
+	.gem_init_object = dvbe_gem_init_object,
+	.gem_free_object = dvbe_gem_free_object,
+	.gem_vm_ops = &dvbe_gem_vm_ops,
+
+	.dumb_create = dvbe_dumb_create,
+	.dumb_map_offset = dvbe_dumb_map_offset,
+	.dumb_destroy = dvbe_dumb_destroy,
+
+	.name = "dvbe",
+	.desc = "DRM VESA BIOS Extension Driver",
+	.date = "20130127",
+	.major = 0,
+	.minor = 0,
+	.patchlevel = 1,
+};
+
+static int dvbe_sysfb_probe(struct sysfb_device *sdev)
+{
+	return drm_get_sysfb_dev(sdev, &dvbe_drm_driver);
+}
+
+static void dvbe_sysfb_remove(struct sysfb_device *sdev)
+{
+	struct drm_device *ddev = dev_get_drvdata(&sdev->dev);
+
+	drm_unplug_dev(ddev);
+}
+
+static struct sysfb_driver dvbe_sysfb_driver = {
+	.type_mask = SYSFB_VBE,
+	.allow_tainted = false,
+	.driver = {
+		.name = "dvbe",
+		.owner = THIS_MODULE,
+		.mod_name = KBUILD_MODNAME,
+	},
+	.probe = dvbe_sysfb_probe,
+	.remove = dvbe_sysfb_remove,
+};
+
+static int __init dvbe_init(void)
+{
+	return drm_sysfb_init(&dvbe_drm_driver, &dvbe_sysfb_driver);
+}
+
+static void __exit dvbe_exit(void)
+{
+	drm_sysfb_exit(&dvbe_drm_driver, &dvbe_sysfb_driver);
+}
+
+module_init(dvbe_init);
+module_exit(dvbe_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("DRM VESA BIOS Extension Driver");
diff --git a/drivers/gpu/drm/dvbe/dvbe_main.c b/drivers/gpu/drm/dvbe/dvbe_main.c
new file mode 100644
index 0000000..e73c77e
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe_main.c
@@ -0,0 +1,399 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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.
+ */
+
+/*
+ * Main Modesetting and Control
+ * We register exactly one CRTC, encoder and connector on initialization. This
+ * simplifies the logic a lot. The actual device control is not implemented
+ * here. This file only provides the interaction with DRM core.
+ *
+ * Userspace has only one valid CRTC+encoder+connector combination which
+ * corresponds to the VESA framebuffer that we detected. The initial mode is
+ * deduced from the initial VESA configuration and should be used by user-space.
+ * Real mode-setting (i.e., changing display resolution) requires the processor
+ * to be in RealMode, which we cannot do in the kernel so it is not provided.
+ * Driver-specific ioctls may be used to allow userspace to perform mode-setting
+ * themself.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include "dvbe.h"
+
+/* crtcs */
+
+static void dvbe_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	/* There is no way to tell DRM core that we do not support DPMS.
+	 * Therefore, simply make this a no-op and always be online. */
+}
+
+static bool dvbe_crtc_mode_fixup(struct drm_crtc *crtc,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	drm_mode_copy(adjusted_mode, mode);
+	return true;
+}
+
+static void dvbe_crtc_prepare(struct drm_crtc *crtc)
+{
+	/* nothing to prepare */
+}
+
+static void dvbe_crtc_commit(struct drm_crtc *crtc)
+{
+	/* all work already done by immediate mode-set */
+}
+
+static int dvbe_crtc_mode_set(struct drm_crtc *crtc,
+			      struct drm_display_mode *mode,
+			      struct drm_display_mode *adjusted_mode,
+			      int x, int y,
+			      struct drm_framebuffer *old_fb)
+{
+	struct dvbe_framebuffer *dfb = to_dvbe_fb(crtc->fb);
+
+	/* We can scan out any framebuffer that is given. The framebuffer
+	 * allocation guarantees that it is a valid framebuffer. If the x/y
+	 * corrdinates are out of bounds, we fail. We don't care whether the
+	 * framebuffer is bigger/smaller than the real screen. The
+	 * blit-functions clip it correctly.
+	 * The mode was already checked by mode_fixup above so we can savely let
+	 * it pass. */
+
+	if (x >= dfb->base.width || y >= dfb->base.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Shortcut if no full mode-set is needed but only the offsets or framebuffer
+ * parameters changed. See @mode_set for details.
+ */
+static int dvbe_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+				   struct drm_framebuffer *fb)
+{
+	struct dvbe_framebuffer *dfb = to_dvbe_fb(crtc->fb);
+
+	if (x >= dfb->base.width || y >= dfb->base.height)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct drm_crtc_helper_funcs dvbe_crtc_helper_ops = {
+	.dpms = dvbe_crtc_dpms,
+	.mode_fixup = dvbe_crtc_mode_fixup,
+	.prepare = dvbe_crtc_prepare,
+	.commit = dvbe_crtc_commit,
+	.mode_set = dvbe_crtc_mode_set,
+	.mode_set_base = dvbe_crtc_mode_set_base,
+};
+
+static const struct drm_crtc_funcs dvbe_crtc_ops = {
+	.destroy = drm_crtc_cleanup,
+	.set_config = drm_crtc_helper_set_config,
+};
+
+/* encoders */
+
+static void dvbe_enc_dpms(struct drm_encoder *enc, int mode)
+{
+	/* DPMS is done by the CRTC */
+}
+
+static bool dvbe_enc_mode_fixup(struct drm_encoder *enc,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	/* mode-fixup is done by the CRTC */
+	return true;
+}
+
+static void dvbe_enc_prepare(struct drm_encoder *enc)
+{
+	/* no preparation to do */
+}
+
+static void dvbe_enc_mode_set(struct drm_encoder *enc,
+			      struct drm_display_mode *mode,
+			      struct drm_display_mode *adjusted_mode)
+{
+	/* mode-setting is done by the CRTC */
+}
+
+static void dvbe_enc_commit(struct drm_encoder *enc)
+{
+	/* committing mode changes is done by the CRTC */
+}
+
+static const struct drm_encoder_helper_funcs dvbe_enc_helper_ops = {
+	.dpms = dvbe_enc_dpms,
+	.mode_fixup = dvbe_enc_mode_fixup,
+	.prepare = dvbe_enc_prepare,
+	.mode_set = dvbe_enc_mode_set,
+	.commit = dvbe_enc_commit,
+};
+
+static const struct drm_encoder_funcs dvbe_enc_ops = {
+	.destroy = drm_encoder_cleanup,
+};
+
+/* connectors */
+
+static int dvbe_conn_get_modes(struct drm_connector *conn)
+{
+	return 0;
+}
+
+static int dvbe_conn_mode_valid(struct drm_connector *conn,
+				struct drm_display_mode *mode)
+{
+	/* every mode of our own is valid */
+	return MODE_OK;
+}
+
+static struct drm_encoder *dvbe_conn_best_encoder(struct drm_connector *conn)
+{
+	struct dvbe_device *dvbe = conn->dev->dev_private;
+
+	/* We only have a single encoder for the VBE device. Hence, return it
+	 * as best-encoder so it is always used. There is no real encoder that
+	 * we control as VBE doesn't provide such information. */
+	return &dvbe->enc;
+}
+
+static const struct drm_connector_helper_funcs dvbe_conn_helper_ops = {
+	.get_modes = dvbe_conn_get_modes,
+	.mode_valid = dvbe_conn_mode_valid,
+	.best_encoder = dvbe_conn_best_encoder,
+};
+
+static enum drm_connector_status dvbe_conn_detect(struct drm_connector *conn,
+						  bool force)
+{
+	/* We simulate an always connected monitor. The VESA ABI doesn't
+	 * provide any way to detect whether the connector is active. Hence,
+	 * signal DRM core that it is always connected. */
+	return connector_status_connected;
+}
+
+static void dvbe_conn_destroy(struct drm_connector *conn)
+{
+	/* Remove the fake-connector from sysfs and then let the DRM core
+	 * clean up all associated resources. */
+	if (device_is_registered(&conn->kdev))
+		drm_sysfs_connector_remove(conn);
+	drm_connector_cleanup(conn);
+}
+
+static const struct drm_connector_funcs dvbe_conn_ops = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = dvbe_conn_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = dvbe_conn_destroy,
+};
+
+/* framebuffers */
+
+static int dvbe_fb_create_handle(struct drm_framebuffer *fb,
+				 struct drm_file *dfile,
+				 unsigned int *handle)
+{
+	struct dvbe_framebuffer *dfb = to_dvbe_fb(fb);
+
+	return drm_gem_handle_create(dfile, &dfb->obj->base, handle);
+}
+
+static int dvbe_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file,
+			 unsigned int flags, unsigned int color,
+			 struct drm_clip_rect *clips, unsigned int num)
+{
+	struct dvbe_device *dvbe = fb->dev->dev_private;
+
+	if (dvbe->crtc.fb != fb)
+		return 0;
+
+	return 0;
+}
+
+static void dvbe_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct dvbe_framebuffer *dfb = to_dvbe_fb(fb);
+
+	drm_framebuffer_cleanup(fb);
+	drm_gem_object_unreference_unlocked(&dfb->obj->base);
+	kfree(dfb);
+}
+
+static const struct drm_framebuffer_funcs dvbe_fb_ops = {
+	.create_handle = dvbe_fb_create_handle,
+	.dirty = dvbe_fb_dirty,
+	.destroy = dvbe_fb_destroy,
+};
+
+static struct drm_framebuffer *dvbe_fb_create(struct drm_device *ddev,
+					      struct drm_file *dfile,
+					      struct drm_mode_fb_cmd2 *cmd)
+{
+	struct dvbe_framebuffer *dfb;
+	int ret;
+	struct drm_gem_object *dobj;
+	unsigned int Bpp;
+	size_t siz;
+	void *err;
+
+	if (cmd->flags)
+		return ERR_PTR(-EINVAL);
+
+	switch (cmd->pixel_format) {
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_BGR565:
+		Bpp = 2;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		Bpp = 4;
+		break;
+	default:
+		return ERR_PTR(-EINVAL);
+	}
+
+	siz = cmd->pitches[0] * (cmd->height - 1) +
+	      Bpp * cmd->width + cmd->offsets[0];
+
+	dobj = drm_gem_object_lookup(ddev, dfile, cmd->handles[0]);
+	if (!dobj)
+		return ERR_PTR(-EINVAL);
+	if (dobj->size < siz) {
+		err = ERR_PTR(-ENOMEM);
+		goto err_unref;
+	}
+
+	dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
+	if (!dfb) {
+		err = ERR_PTR(-ENOMEM);
+		goto err_unref;
+	}
+	dfb->obj = to_dvbe_bo(dobj);
+
+	ret = drm_helper_mode_fill_fb_struct(&dfb->base, cmd);
+	if (ret < 0) {
+		err = ERR_PTR(ret);
+		goto err_free;
+	}
+
+	ret = drm_framebuffer_init(ddev, &dfb->base, &dvbe_fb_ops);
+	if (ret < 0) {
+		err = ERR_PTR(ret);
+		goto err_free;
+	}
+
+	return &dfb->base;
+
+err_free:
+	kfree(dfb);
+err_unref:
+	drm_gem_object_unreference_unlocked(dobj);
+	return err;
+}
+
+static const struct drm_mode_config_funcs dvbe_mode_config_ops = {
+	.fb_create = dvbe_fb_create,
+};
+
+/* initialization */
+
+int dvbe_drm_load(struct drm_device *ddev, unsigned long flags)
+{
+	struct dvbe_device *dvbe;
+	int ret;
+
+	dvbe = kzalloc(sizeof(*dvbe), GFP_KERNEL);
+	if (!dvbe)
+		return -ENOMEM;
+
+	dvbe->ddev = ddev;
+	ddev->dev_private = dvbe;
+
+	drm_mode_config_init(ddev);
+	ddev->mode_config.min_width = 0;
+	ddev->mode_config.min_height = 0;
+	ddev->mode_config.max_width = 4095;
+	ddev->mode_config.max_height = 4095;
+	ddev->mode_config.funcs = &dvbe_mode_config_ops;
+
+	ret = drm_mode_create_dirty_info_property(ddev);
+	if (ret)
+		goto err_cleanup;
+
+	ret = drm_crtc_init(ddev, &dvbe->crtc, &dvbe_crtc_ops);
+	if (ret)
+		goto err_cleanup;
+	drm_crtc_helper_add(&dvbe->crtc, &dvbe_crtc_helper_ops);
+
+	dvbe->enc.possible_crtcs = 1;
+	dvbe->enc.possible_clones = 0;
+	ret = drm_encoder_init(ddev, &dvbe->enc, &dvbe_enc_ops,
+			       DRM_MODE_ENCODER_VIRTUAL);
+	if (ret)
+		goto err_cleanup;
+	drm_encoder_helper_add(&dvbe->enc, &dvbe_enc_helper_ops);
+
+	dvbe->conn.display_info.width_mm = 0;
+	dvbe->conn.display_info.height_mm = 0;
+	dvbe->conn.interlace_allowed = false;
+	dvbe->conn.doublescan_allowed = false;
+	dvbe->conn.polled = 0;
+	ret = drm_connector_init(ddev, &dvbe->conn, &dvbe_conn_ops,
+				 DRM_MODE_CONNECTOR_VIRTUAL);
+	if (ret)
+		goto err_cleanup;
+	drm_connector_helper_add(&dvbe->conn, &dvbe_conn_helper_ops);
+
+	drm_object_attach_property(&dvbe->conn.base,
+				   ddev->mode_config.dirty_info_property, 1);
+
+	ret = drm_mode_connector_attach_encoder(&dvbe->conn, &dvbe->enc);
+	if (ret)
+		goto err_cleanup;
+
+	ret = drm_sysfs_connector_add(&dvbe->conn);
+	if (ret)
+		goto err_cleanup;
+
+	return 0;
+
+err_cleanup:
+	drm_mode_config_cleanup(ddev);
+	kfree(dvbe);
+	return ret;
+}
+
+int dvbe_drm_unload(struct drm_device *ddev)
+{
+	struct dvbe_device *dvbe = ddev->dev_private;
+
+	drm_mode_config_cleanup(ddev);
+	kfree(dvbe);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/dvbe/dvbe_mem.c b/drivers/gpu/drm/dvbe/dvbe_mem.c
new file mode 100644
index 0000000..211aebf
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe_mem.c
@@ -0,0 +1,269 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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.
+ */
+
+/*
+ * DVBA Memory Objects
+ * Due to the limited functionality of the VESA ABI, we support only one memory
+ * object type which is the framebuffer object. To allow file-descriptors for
+ * frambuffers we use shmem storage for all gem objects.
+ *
+ * Furthermore, we use lazy storage allocation. As long as the storage isn't
+ * mapped or accessed, we do not allocate it. If it is mapped, we allocate an
+ * array of pointers to the pages so we can easily vmap/vunmap it for CPU
+ * access.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/shmem_fs.h>
+#include <linux/string.h>
+#include <drm/drmP.h>
+#include <drm/drm_mem_util.h>
+#include "dvbe.h"
+
+static struct dvbe_gem_object *dvbe_gem_alloc_object(struct drm_device *ddev,
+						     size_t size)
+{
+	struct dvbe_gem_object *obj;
+
+	BUG_ON((size & (PAGE_SIZE - 1)) != 0);
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (!obj)
+		return NULL;
+
+	if (drm_gem_object_init(ddev, &obj->base, size)) {
+		kfree(obj);
+		return NULL;
+	}
+
+	return obj;
+}
+
+/*
+ * First time user-space requests access to a gem object, we allocate an array
+ * of all backing pages so our page-fault handler can map them efficiently.
+ * shmem_read_mapping_page_gfp allocates missing pages with the given GFP mask
+ * which we deduce from the tmpfs-dentry object.
+ */
+static int dvbe_gem_get_pages(struct dvbe_gem_object *obj)
+{
+	size_t i, page_count = obj->base.size / PAGE_SIZE;
+	struct page *page;
+	struct address_space *mapping;
+	gfp_t gfp;
+
+	if (obj->pages)
+		return 0;
+
+	obj->pages = drm_malloc_ab(page_count, sizeof(struct page*));
+	if (!obj->pages)
+		return -ENOMEM;
+
+	mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
+	gfp = mapping_gfp_mask(mapping) | GFP_KERNEL;
+
+	for (i = 0; i < page_count; ++i) {
+		page = shmem_read_mapping_page_gfp(mapping, i, gfp);
+		if (IS_ERR(page))
+			goto err_pages;
+
+		obj->pages[i] = page;
+	}
+
+	return 0;
+
+err_pages:
+	while (i--)
+		page_cache_release(obj->pages[i]);
+	drm_free_large(obj->pages);
+	obj->pages = NULL;
+	return PTR_ERR(page);
+}
+
+static void dvbe_gem_put_pages(struct dvbe_gem_object *obj)
+{
+	size_t i, page_count = obj->base.size / PAGE_SIZE;
+
+	if (!obj->pages)
+		return;
+
+	for (i = 0; i < page_count; ++i)
+		page_cache_release(obj->pages[i]);
+
+	drm_free_large(obj->pages);
+	obj->pages = NULL;
+}
+
+int dvbe_gem_vmap(struct dvbe_gem_object *obj)
+{
+	int ret, page_count = obj->base.size / PAGE_SIZE;
+
+	if (obj->vmapping)
+		return 0;
+
+	ret = dvbe_gem_get_pages(obj);
+	if (ret)
+		return ret;
+
+	obj->vmapping = vmap(obj->pages, page_count, 0, PAGE_KERNEL);
+	if (!obj->vmapping)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void dvbe_gem_vunmap(struct dvbe_gem_object *obj)
+{
+	if (!obj->vmapping)
+		return;
+
+	vunmap(obj->vmapping);
+	obj->vmapping = NULL;
+}
+
+/* drm_gem_object_alloc() is not supported */
+int dvbe_gem_init_object(struct drm_gem_object *gobj)
+{
+	BUG();
+
+	return -EINVAL;
+}
+
+void dvbe_gem_free_object(struct drm_gem_object *gobj)
+{
+	struct dvbe_gem_object *obj = to_dvbe_bo(gobj);
+
+	if (gobj->map_list.map)
+		drm_gem_free_mmap_offset(gobj);
+	dvbe_gem_vunmap(obj);
+	dvbe_gem_put_pages(obj);
+	drm_gem_object_release(gobj);
+	kfree(obj);
+}
+
+/*
+ * On page-faults we need to calculate the page-offset ourself as the vma-offset
+ * is based on the fake-offset of drm_mmap() instead of any real offset.
+ * We simply insert the page via vm_insert_page() as it has been marked as
+ * VM_MIXEDMAP in the vma.
+ */
+int dvbe_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct dvbe_gem_object *obj = to_dvbe_bo(vma->vm_private_data);
+	unsigned long off, vaddr;
+	int ret;
+
+	if (!obj->pages)
+		return VM_FAULT_SIGBUS;
+
+	vaddr = (unsigned long)vmf->virtual_address;
+	off = (vaddr - vma->vm_start) >> PAGE_SHIFT;
+
+	ret = vm_insert_page(vma, vaddr, obj->pages[off]);
+	switch (ret) {
+	case -ENOMEM:
+		return VM_FAULT_OOM;
+	case -EAGAIN:
+		set_need_resched();
+		/* fallthrough */
+	case -ERESTARTSYS:
+	case 0:
+		return VM_FAULT_NOPAGE;
+	}
+
+	return VM_FAULT_SIGBUS;
+}
+
+int dvbe_dumb_create(struct drm_file *dfile, struct drm_device *ddev,
+		     struct drm_mode_create_dumb *args)
+{
+	struct dvbe_gem_object *obj;
+	int ret;
+
+	args->pitch = args->width * ((args->bpp + 7) / 8);
+	args->size = args->pitch * args->height;
+
+	if (!args->size)
+		return -EINVAL;
+
+	args->size = roundup(args->size, PAGE_SIZE);
+	obj = dvbe_gem_alloc_object(ddev, args->size);
+	if (!obj)
+		return -ENOMEM;
+
+	ret = drm_gem_handle_create(dfile, &obj->base, &args->handle);
+	if (ret) {
+		drm_gem_object_unreference(&obj->base);
+		return ret;
+	}
+
+	drm_gem_object_unreference(&obj->base);
+	return 0;
+}
+
+int dvbe_dumb_destroy(struct drm_file *dfile, struct drm_device *ddev,
+		      uint32_t handle)
+{
+	return drm_gem_handle_delete(dfile, handle);
+}
+
+int dvbe_dumb_map_offset(struct drm_file *dfile, struct drm_device *ddev,
+			 uint32_t handle, uint64_t *offset)
+{
+	struct dvbe_gem_object *obj;
+	struct drm_gem_object *gobj;
+	int ret;
+
+	mutex_lock(&ddev->struct_mutex);
+	gobj = drm_gem_object_lookup(ddev, dfile, handle);
+	if (!gobj) {
+		ret = -ENOENT;
+		goto out_unlock;
+	}
+	obj = to_dvbe_bo(gobj);
+
+	ret = dvbe_gem_get_pages(obj);
+	if (ret)
+		goto out_unref;
+
+	if (!gobj->map_list.map) {
+		ret = drm_gem_create_mmap_offset(gobj);
+		if (ret)
+			goto out_unref;
+	}
+
+	*offset = gobj->map_list.hash.key << PAGE_SHIFT;
+
+out_unref:
+	drm_gem_object_unreference(gobj);
+out_unlock:
+	mutex_unlock(&ddev->struct_mutex);
+	return ret;
+}
+
+int dvbe_drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	int ret;
+
+	ret = drm_gem_mmap(filp, vma);
+	if (ret)
+		return ret;
+
+	vma->vm_flags &= ~VM_PFNMAP;
+	vma->vm_flags |= VM_MIXEDMAP;
+	vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+	return ret;
+}
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 8/9] drm: dvbe: implement VBE/VESA blitting backend
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

Extend the dvbe core driver by a VESA/VBE backend that simply blits the
data from a framebuffer into the hardware framebuffer on damage.
Modesetting has to be done during the boot-process by the architecture
code (same way as vesafb requires it). No runtime modesetting is allowed
due to RealMode/ProtectedMode restrictions.

On dirty-ioctls we simply vmap the framebuffer memory and copy each pixel
into the target framebuffer. Unfortunately, the VBE bpp/depth combinations
cannot easily be forwarded to the user via the DRM API as it allows a lot
more combinations. Hence, we need to convert each pixel from the user's
buffer format into the target format while blitting.
Fast-paths for xrgb32/etc. could be implemented if we want to improve
blitting performance.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/dvbe/Kconfig     |   1 +
 drivers/gpu/drm/dvbe/Makefile    |   2 +-
 drivers/gpu/drm/dvbe/dvbe.h      |  25 ++++
 drivers/gpu/drm/dvbe/dvbe_main.c |  39 +++++-
 drivers/gpu/drm/dvbe/dvbe_vesa.c | 263 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 325 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_vesa.c

diff --git a/drivers/gpu/drm/dvbe/Kconfig b/drivers/gpu/drm/dvbe/Kconfig
index bb3aa7b..e49df10 100644
--- a/drivers/gpu/drm/dvbe/Kconfig
+++ b/drivers/gpu/drm/dvbe/Kconfig
@@ -3,6 +3,7 @@ config DRM_DVBE
 	depends on DRM
 	select DRM_KMS_HELPER
 	select DRM_SYSFB
+	select FB_BOOT_VESA_SUPPORT
 	help
 	  This is a DRM/KMS driver for VESA BIOS Extension (VBE) compatible
 	  cards. At least VBE 2.0 is needed. Older VBE 1.2 cards are not
diff --git a/drivers/gpu/drm/dvbe/Makefile b/drivers/gpu/drm/dvbe/Makefile
index b053da3..f6fb888 100644
--- a/drivers/gpu/drm/dvbe/Makefile
+++ b/drivers/gpu/drm/dvbe/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
 
-dvbe-y := dvbe_drv.o dvbe_main.o dvbe_mem.o
+dvbe-y := dvbe_drv.o dvbe_main.o dvbe_mem.o dvbe_vesa.o
 obj-$(CONFIG_DRM_DVBE) := dvbe.o
diff --git a/drivers/gpu/drm/dvbe/dvbe.h b/drivers/gpu/drm/dvbe/dvbe.h
index 0235a95..68fd452 100644
--- a/drivers/gpu/drm/dvbe/dvbe.h
+++ b/drivers/gpu/drm/dvbe/dvbe.h
@@ -25,6 +25,23 @@
 struct dvbe_device {
 	struct drm_device *ddev;
 
+	/* vbe information */
+	unsigned long vbe_addr;
+	unsigned long vbe_vsize;
+	unsigned long vbe_size;
+	unsigned int vbe_depth;
+	unsigned int vbe_bpp;
+	unsigned int vbe_width;
+	unsigned int vbe_height;
+	unsigned int vbe_stride;
+	uint8_t vbe_red_size;
+	uint8_t vbe_red_pos;
+	uint8_t vbe_green_size;
+	uint8_t vbe_green_pos;
+	uint8_t vbe_blue_size;
+	uint8_t vbe_blue_pos;
+	uint8_t *vbe_map;
+
 	/* mode-setting objects */
 	struct drm_crtc crtc;
 	struct drm_encoder enc;
@@ -70,4 +87,12 @@ struct dvbe_framebuffer {
 
 #define to_dvbe_fb(x) container_of(x, struct dvbe_framebuffer, base)
 
+/* vesa helpers */
+
+int dvbe_vesa_init(struct dvbe_device *dvbe);
+void dvbe_vesa_cleanup(struct dvbe_device *dvbe);
+int dvbe_vesa_damage(struct dvbe_device *dvbe, struct dvbe_framebuffer *fb,
+		     unsigned int flags, unsigned int color,
+		     struct drm_clip_rect *clips, unsigned int num);
+
 #endif /* DVBE_DRV_H */
diff --git a/drivers/gpu/drm/dvbe/dvbe_main.c b/drivers/gpu/drm/dvbe/dvbe_main.c
index e73c77e..c418310 100644
--- a/drivers/gpu/drm/dvbe/dvbe_main.c
+++ b/drivers/gpu/drm/dvbe/dvbe_main.c
@@ -46,6 +46,15 @@ static bool dvbe_crtc_mode_fixup(struct drm_crtc *crtc,
 				 const struct drm_display_mode *mode,
 				 struct drm_display_mode *adjusted_mode)
 {
+	struct dvbe_device *dvbe = crtc->dev->dev_private;
+
+	if (mode->hdisplay != dvbe->vbe_width ||
+	    mode->vdisplay != dvbe->vbe_height) {
+		dev_dbg(dvbe->ddev->dev, "invalid mode %ux%u\n",
+			mode->hdisplay, mode->vdisplay);
+		return false;
+	}
+
 	drm_mode_copy(adjusted_mode, mode);
 	return true;
 }
@@ -66,6 +75,7 @@ static int dvbe_crtc_mode_set(struct drm_crtc *crtc,
 			      int x, int y,
 			      struct drm_framebuffer *old_fb)
 {
+	struct dvbe_device *dvbe = crtc->dev->dev_private;
 	struct dvbe_framebuffer *dfb = to_dvbe_fb(crtc->fb);
 
 	/* We can scan out any framebuffer that is given. The framebuffer
@@ -79,7 +89,7 @@ static int dvbe_crtc_mode_set(struct drm_crtc *crtc,
 	if (x >= dfb->base.width || y >= dfb->base.height)
 		return -EINVAL;
 
-	return 0;
+	return dvbe_vesa_damage(dvbe, dfb, 0, 0, NULL, 0);
 }
 
 /*
@@ -89,12 +99,13 @@ static int dvbe_crtc_mode_set(struct drm_crtc *crtc,
 static int dvbe_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 				   struct drm_framebuffer *fb)
 {
+	struct dvbe_device *dvbe = crtc->dev->dev_private;
 	struct dvbe_framebuffer *dfb = to_dvbe_fb(crtc->fb);
 
 	if (x >= dfb->base.width || y >= dfb->base.height)
 		return -EINVAL;
 
-	return 0;
+	return dvbe_vesa_damage(dvbe, dfb, 0, 0, NULL, 0);
 }
 
 static const struct drm_crtc_helper_funcs dvbe_crtc_helper_ops = {
@@ -159,7 +170,19 @@ static const struct drm_encoder_funcs dvbe_enc_ops = {
 
 static int dvbe_conn_get_modes(struct drm_connector *conn)
 {
-	return 0;
+	struct dvbe_device *dvbe = conn->dev->dev_private;
+	struct drm_display_mode *mode;
+
+	mode = drm_gtf_mode(dvbe->ddev, dvbe->vbe_width, dvbe->vbe_height,
+			    60, 0, 0);
+	if (!mode)
+		return 0;
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(conn, mode);
+	dvbe->mode = mode;
+
+	return 1;
 }
 
 static int dvbe_conn_mode_valid(struct drm_connector *conn,
@@ -226,11 +249,12 @@ static int dvbe_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file,
 			 struct drm_clip_rect *clips, unsigned int num)
 {
 	struct dvbe_device *dvbe = fb->dev->dev_private;
+	struct dvbe_framebuffer *dfb = to_dvbe_fb(fb);
 
 	if (dvbe->crtc.fb != fb)
 		return 0;
 
-	return 0;
+	return dvbe_vesa_damage(dvbe, dfb, flags, color, clips, num);
 }
 
 static void dvbe_fb_destroy(struct drm_framebuffer *fb)
@@ -334,6 +358,10 @@ int dvbe_drm_load(struct drm_device *ddev, unsigned long flags)
 	dvbe->ddev = ddev;
 	ddev->dev_private = dvbe;
 
+	ret = dvbe_vesa_init(dvbe);
+	if (ret)
+		goto err_free;
+
 	drm_mode_config_init(ddev);
 	ddev->mode_config.min_width = 0;
 	ddev->mode_config.min_height = 0;
@@ -384,6 +412,8 @@ int dvbe_drm_load(struct drm_device *ddev, unsigned long flags)
 
 err_cleanup:
 	drm_mode_config_cleanup(ddev);
+	dvbe_vesa_cleanup(dvbe);
+err_free:
 	kfree(dvbe);
 	return ret;
 }
@@ -393,6 +423,7 @@ int dvbe_drm_unload(struct drm_device *ddev)
 	struct dvbe_device *dvbe = ddev->dev_private;
 
 	drm_mode_config_cleanup(ddev);
+	dvbe_vesa_cleanup(dvbe);
 	kfree(dvbe);
 
 	return 0;
diff --git a/drivers/gpu/drm/dvbe/dvbe_vesa.c b/drivers/gpu/drm/dvbe/dvbe_vesa.c
new file mode 100644
index 0000000..c3f96a0
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe_vesa.c
@@ -0,0 +1,263 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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.
+ */
+
+/*
+ * VESA BIOS Extension Layer
+ * This layer provides access to the VBE data for the dvbe driver. It reads the
+ * mode information from the initial boot screen_info and initializes the
+ * framebuffer for user-mode access.
+ *
+ * This driver requires the VESA mode to be a TRUECOLOR format with a bpp value
+ * of 8, 15, 16 or 32. All other layouts are unsupported.
+ */
+
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/screen_info.h>
+#include <drm/drmP.h>
+#include "dvbe.h"
+
+static void dvbe_vesa_read(const uint8_t *src, unsigned int format,
+			   uint8_t *r, uint8_t *g, uint8_t *b)
+{
+	uint32_t val;
+
+	switch (format) {
+	case DRM_FORMAT_RGB565:
+		val = *(uint16_t*)src;
+		*r = (val & 0xf800) >> 11;
+		*g = (val & 0x07e0) >> 5;
+		*b = (val & 0x001f) >> 0;
+		break;
+	case DRM_FORMAT_BGR565:
+		val = *(uint16_t*)src;
+		*b = (val & 0xf800) >> 11;
+		*g = (val & 0x07e0) >> 5;
+		*r = (val & 0x001f) >> 0;
+		break;
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ARGB8888:
+		val = *(uint32_t*)src;
+		*r = (val & 0x00ff0000) >> 16;
+		*g = (val & 0x0000ff00) >> 8;
+		*b = (val & 0x000000ff) >> 0;
+		break;
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ABGR8888:
+		val = *(uint32_t*)src;
+		*b = (val & 0x00ff0000) >> 16;
+		*g = (val & 0x0000ff00) >> 8;
+		*r = (val & 0x000000ff) >> 0;
+		break;
+	default:
+		*r = 0;
+		*g = 0;
+		*b = 0;
+	}
+}
+
+static void dvbe_vesa_write(struct dvbe_device *dvbe, uint8_t *dst,
+			    uint8_t r, uint8_t g, uint8_t b)
+{
+	uint32_t val;
+
+	val = (r >> (8 - dvbe->vbe_red_size)) << dvbe->vbe_red_pos;
+	val |= (g >> (8 - dvbe->vbe_green_size)) << dvbe->vbe_green_pos;
+	val |= (b >> (8 - dvbe->vbe_blue_size)) << dvbe->vbe_blue_pos;
+
+	switch (dvbe->vbe_bpp) {
+	case 8:
+		*dst = val & 0xff;
+		break;
+	case 16:
+		*((uint16_t*)dst) = val & 0xffff;
+		break;
+	case 32:
+		*((uint32_t*)dst) = val & 0xffffffff;
+		break;
+	}
+}
+
+static void dvbe_vesa_blit(struct dvbe_device *dvbe, const uint8_t *src,
+			   unsigned int src_stride, unsigned int src_f,
+			   unsigned int src_bpp, unsigned int x, unsigned int y,
+			   unsigned int width, unsigned int height)
+{
+	uint8_t *dst, *d, r, g, b;
+	const uint8_t *s;
+	unsigned int i, j, sBpp, dBpp;
+
+	sBpp = src_bpp / 8;
+	dBpp = dvbe->vbe_bpp / 8;
+	src = src + y * src_stride + x * sBpp;
+	dst = dvbe->vbe_map + y * dvbe->vbe_stride + x * dBpp;
+
+	for (i = 0; i < height; ++i) {
+		s = src;
+		d = dst;
+		for (j = 0; j < width; ++j) {
+			dvbe_vesa_read(src, src_f, &r, &g, &b);
+			dvbe_vesa_write(dvbe, d, r, g, b);
+			s += sBpp;
+			d += dBpp;
+		}
+
+		src += src_stride;
+		dst += dvbe->vbe_stride;
+	}
+}
+
+int dvbe_vesa_damage(struct dvbe_device *dvbe, struct dvbe_framebuffer *fb,
+		     unsigned int flags, unsigned int color,
+		     struct drm_clip_rect *clips, unsigned int num)
+{
+	unsigned int i, maxw, maxh;
+	unsigned int width, height, ret;
+	uint8_t *src;
+	bool annotated;
+
+	ret = dvbe_gem_vmap(fb->obj);
+	if (ret)
+		return ret;
+
+	annotated = flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY;
+	src = fb->obj->vmapping + fb->base.offsets[0];
+	maxw = min(fb->base.width, dvbe->vbe_width);
+	maxh = min(fb->base.height, dvbe->vbe_height);
+
+	if (!num) {
+		dvbe_vesa_blit(dvbe, src, fb->base.pitches[0],
+			       fb->base.pixel_format, fb->base.bits_per_pixel,
+			       0, 0, maxw, maxh);
+		return 0;
+	}
+
+	for (i = 0; i < num; ++i) {
+		if (annotated && !(i & 0x1))
+			continue;
+		if (clips[i].x2 <= clips[i].x1 || clips[i].y2 <= clips[i].y1)
+			continue;
+
+		/* clip to framebuffer size */
+		if (clips[i].x1 >= maxw ||
+		    clips[i].y1 >= maxh)
+			continue;
+		if (clips[i].x2 > maxw)
+			width = maxw - clips[i].x1;
+		else
+			width = clips[i].x2 - clips[i].x1;
+		if (clips[i].y2 > maxh)
+			height = maxh - clips[i].y1;
+		else
+			height = clips[i].y2 - clips[i].y1;
+
+		dvbe_vesa_blit(dvbe, src, fb->base.pitches[0],
+			       fb->base.pixel_format, fb->base.bits_per_pixel,
+			       clips[i].x1, clips[i].y1, width, height);
+	}
+
+	return 0;
+}
+
+int dvbe_vesa_init(struct dvbe_device *dvbe)
+{
+	int ret;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) {
+		dev_info(dvbe->ddev->dev, "no VBE capable device found\n");
+		return -ENODEV;
+	}
+
+	dvbe->vbe_addr = (unsigned long)screen_info.lfb_base;
+	dvbe->vbe_width = screen_info.lfb_width;
+	dvbe->vbe_height = screen_info.lfb_height;
+	dvbe->vbe_stride = screen_info.lfb_linelength;
+	dvbe->vbe_depth = screen_info.lfb_depth;
+	dvbe->vbe_bpp = (dvbe->vbe_depth = 15) ? 16 : dvbe->vbe_depth;
+	dvbe->vbe_size = dvbe->vbe_height * dvbe->vbe_stride;
+	dvbe->vbe_vsize = screen_info.lfb_size * 0x10000;
+	if (dvbe->vbe_vsize < dvbe->vbe_size)
+		dvbe->vbe_vsize = dvbe->vbe_size;
+
+	dev_info(dvbe->ddev->dev, "VMEM at: %ld vsize: %ld rsize: %ld\n",
+		 dvbe->vbe_addr, dvbe->vbe_vsize, dvbe->vbe_size);
+	dev_info(dvbe->ddev->dev, "width: %d height: %d stride: %d bpp: %d\n",
+		 dvbe->vbe_width, dvbe->vbe_height, dvbe->vbe_stride,
+		 dvbe->vbe_bpp);
+
+	if (dvbe->vbe_bpp != 8 && dvbe->vbe_bpp != 16 && dvbe->vbe_bpp != 32) {
+		dev_err(dvbe->ddev->dev, "unsupported bpp value %d\n",
+			dvbe->vbe_bpp);
+		return -ENODEV;
+	}
+	if (!screen_info.red_pos && !screen_info.green_pos &&
+	    !screen_info.blue_pos) {
+		dev_err(dvbe->ddev->dev, "hardware not truecolor capable\n");
+		return -ENODEV;
+	}
+	if (!screen_info.red_size && !screen_info.green_size &&
+	    !screen_info.blue_size) {
+		dev_err(dvbe->ddev->dev, "hardware not truecolor capable\n");
+		return -ENODEV;
+	}
+
+	dvbe->vbe_red_size = screen_info.red_size;
+	dvbe->vbe_red_pos = screen_info.red_pos;
+	dvbe->vbe_green_size = screen_info.green_size;
+	dvbe->vbe_green_pos = screen_info.green_pos;
+	dvbe->vbe_blue_size = screen_info.blue_size;
+	dvbe->vbe_blue_pos = screen_info.blue_pos;
+
+	dev_info(dvbe->ddev->dev, "color %d:%d r: %d:%d g: %d:%d b: %d:%d\n",
+		 dvbe->vbe_depth, dvbe->vbe_bpp,
+		 dvbe->vbe_red_pos, dvbe->vbe_red_size,
+		 dvbe->vbe_green_pos, dvbe->vbe_green_size,
+		 dvbe->vbe_blue_pos, dvbe->vbe_blue_size);
+
+	if (!request_mem_region(dvbe->vbe_addr, dvbe->vbe_vsize, "dvbe")) {
+		dev_err(dvbe->ddev->dev, "cannot reserve VMEM\n");
+		return -EIO;
+	}
+
+	if (!request_region(0x3c0, 32, "dvbe")) {
+		dev_err(dvbe->ddev->dev, "cannot reserve VBIOS\n");
+		ret = -EIO;
+		goto err_mem_region;
+	}
+
+	dvbe->vbe_map = ioremap(dvbe->vbe_addr, dvbe->vbe_size);
+	if (!dvbe->vbe_map) {
+		dev_err(dvbe->ddev->dev, "cannot remap VMEM\n");
+		ret = -EIO;
+		goto err_region;
+	}
+
+	dev_info(dvbe->ddev->dev, "initialized VBE mode to %ux%u at %p\n",
+		 dvbe->vbe_width, dvbe->vbe_height, dvbe->vbe_map);
+
+	return 0;
+
+err_region:
+	release_region(0x3c0, 32);
+err_mem_region:
+	release_mem_region(dvbe->vbe_addr, dvbe->vbe_vsize);
+	return -ENODEV;
+}
+
+void dvbe_vesa_cleanup(struct dvbe_device *dvbe)
+{
+	dev_info(dvbe->ddev->dev, "VBE cleanup\n");
+	iounmap(dvbe->vbe_map);
+	release_region(0x3c0, 32);
+	release_mem_region(dvbe->vbe_addr, dvbe->vbe_vsize);
+}
-- 
1.8.1.3


^ permalink raw reply related

* [PATCH 9/9] drm: dvbe: add optional fbdev frontend
From: David Herrmann @ 2013-02-17 17:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Florian Tobias Schandinat, linux-fbdev, David Airlie, dri-devel,
	David Herrmann
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

This adds a new fbdev frontend to the dvbe driver. It allows userspace to
access the dvbe driver via an fbdev frontend.

It is disabled by default so you can use dvbe without CONFIG_FB. It should
only be used for backwards-compatibility. Use the DRM dumb API to access
dvbe buffers properly.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
 drivers/gpu/drm/dvbe/Kconfig      |  18 +++
 drivers/gpu/drm/dvbe/Makefile     |   1 +
 drivers/gpu/drm/dvbe/dvbe.h       |  23 ++++
 drivers/gpu/drm/dvbe/dvbe_fbdev.c | 235 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/dvbe/dvbe_main.c  |   2 +
 5 files changed, 279 insertions(+)
 create mode 100644 drivers/gpu/drm/dvbe/dvbe_fbdev.c

diff --git a/drivers/gpu/drm/dvbe/Kconfig b/drivers/gpu/drm/dvbe/Kconfig
index e49df10..ca27455 100644
--- a/drivers/gpu/drm/dvbe/Kconfig
+++ b/drivers/gpu/drm/dvbe/Kconfig
@@ -27,3 +27,21 @@ config DRM_DVBE
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called dvbe.
+
+config DRM_DVBE_FBDEV
+	bool "VESA BIOS Extension DRM fbdev Compatibility Layer"
+	depends on DRM_DVBE && FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This provides an fbdev frontend (via /dev/fbX) for the DVBE VESA
+	  driver. Old userspace that depends on the fbdev API can access the
+	  DVBE driver this way. It provides full backwards compatibility to the
+	  old vesafb driver.
+
+	  Newer userspace accesses graphics devices via the DRM API and the old
+	  fbdev compatibility layer is not needed. Activate it only if you
+	  really need to run old userspace programs.
+
+	  If unsure, say N.
diff --git a/drivers/gpu/drm/dvbe/Makefile b/drivers/gpu/drm/dvbe/Makefile
index f6fb888..e01aaa1 100644
--- a/drivers/gpu/drm/dvbe/Makefile
+++ b/drivers/gpu/drm/dvbe/Makefile
@@ -1,4 +1,5 @@
 ccflags-y := -Iinclude/drm
 
 dvbe-y := dvbe_drv.o dvbe_main.o dvbe_mem.o dvbe_vesa.o
+dvbe-$(CONFIG_DRM_DVBE_FBDEV) += dvbe_fbdev.o
 obj-$(CONFIG_DRM_DVBE) := dvbe.o
diff --git a/drivers/gpu/drm/dvbe/dvbe.h b/drivers/gpu/drm/dvbe/dvbe.h
index 68fd452..dfe7c20 100644
--- a/drivers/gpu/drm/dvbe/dvbe.h
+++ b/drivers/gpu/drm/dvbe/dvbe.h
@@ -14,6 +14,7 @@
 #define DVBE_DRV_H
 
 #include <linux/errno.h>
+#include <linux/fb.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/module.h>
@@ -47,6 +48,9 @@ struct dvbe_device {
 	struct drm_encoder enc;
 	struct drm_connector conn;
 	struct drm_display_mode *mode;
+
+	/* fbdev */
+	void *fbdev;
 };
 
 int dvbe_drm_load(struct drm_device *ddev, unsigned long flags);
@@ -95,4 +99,23 @@ int dvbe_vesa_damage(struct dvbe_device *dvbe, struct dvbe_framebuffer *fb,
 		     unsigned int flags, unsigned int color,
 		     struct drm_clip_rect *clips, unsigned int num);
 
+/* fbdev helpers */
+
+#ifdef CONFIG_DRM_DVBE_FBDEV
+
+void dvbe_fbdev_init(struct dvbe_device *dvbe);
+void dvbe_fbdev_cleanup(struct dvbe_device *dvbe);
+
+#else /* CONFIG_DRM_DVBE_FBDEV */
+
+static inline void dvbe_fbdev_init(struct dvbe_device *dvbe)
+{
+}
+
+static inline void dvbe_fbdev_cleanup(struct dvbe_device *dvbe)
+{
+}
+
+#endif /* CONFIG_DRM_DVBE_FBDEV */
+
 #endif /* DVBE_DRV_H */
diff --git a/drivers/gpu/drm/dvbe/dvbe_fbdev.c b/drivers/gpu/drm/dvbe/dvbe_fbdev.c
new file mode 100644
index 0000000..0e22e12
--- /dev/null
+++ b/drivers/gpu/drm/dvbe/dvbe_fbdev.c
@@ -0,0 +1,235 @@
+/*
+ * DRM VESA BIOS Extension Driver
+ * 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.
+ */
+
+/*
+ * fbdev compatibility layer
+ * This provides an fbdev framebuffer device for the DVBE driver. It is
+ * based on the old vesafb.c driver:
+ *   (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include "dvbe.h"
+
+struct dvbe_fbdev {
+	struct dvbe_device *dvbe;
+	u32 palette[256];
+};
+
+static int dvbe_fbdev_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 (info->var.bits_per_pixel = 8)
+		return -EINVAL;
+	if (regno >= 16)
+		return 0;
+
+	switch (info->var.bits_per_pixel) {
+	case 16:
+		if (info->var.red.offset = 10) {
+			/* 1:5:5:5 */
+			((u32*) (info->pseudo_palette))[regno] +				((red   & 0xf800) >>  1) |
+				((green & 0xf800) >>  6) |
+				((blue  & 0xf800) >> 11);
+		} else {
+			/* 0:5:6:5 */
+			((u32*) (info->pseudo_palette))[regno] +				((red   & 0xf800)      ) |
+				((green & 0xfc00) >>  5) |
+				((blue  & 0xf800) >> 11);
+		}
+		break;
+	case 24:
+	case 32:
+		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);
+		break;
+	}
+
+	return 0;
+}
+
+static void dvbe_fbdev_free(struct dvbe_device *dvbe, struct fb_info *info)
+{
+	dev_info(dvbe->ddev->dev, "fbdev cleanup\n");
+	fb_dealloc_cmap(&info->cmap);
+	framebuffer_release(info);
+}
+
+static void dvbe_fbdev_destroy(struct fb_info *info)
+{
+	struct dvbe_fbdev *fb = info->par;
+	struct dvbe_device *dvbe = fb->dvbe;
+
+	mutex_lock(&dvbe->ddev->struct_mutex);
+	info = dvbe->fbdev;
+	dvbe->fbdev = NULL;
+	mutex_unlock(&dvbe->ddev->struct_mutex);
+
+	if (info)
+		dvbe_fbdev_free(dvbe, info);
+}
+
+static struct fb_ops dvbe_fbdev_ops = {
+	.owner		= THIS_MODULE,
+	.fb_destroy	= dvbe_fbdev_destroy,
+	.fb_setcolreg	= dvbe_fbdev_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+void dvbe_fbdev_init(struct dvbe_device *dvbe)
+{
+	struct dvbe_fbdev *fb;
+	struct fb_info *info;
+	int ret;
+
+	info = framebuffer_alloc(sizeof(struct dvbe_fbdev), dvbe->ddev->dev);
+	if (!info) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	fb = info->par;
+	fb->dvbe = dvbe;
+	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
+	info->pseudo_palette = fb->palette;
+	info->screen_base = dvbe->vbe_map;
+	info->fbops = &dvbe_fbdev_ops;
+
+	strncpy(info->fix.id, "dvbedrmfb", 15);
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fix.smem_start = (unsigned long)dvbe->vbe_addr;
+	info->fix.smem_len = dvbe->vbe_size;
+	info->fix.line_length = dvbe->vbe_stride;
+
+	if (dvbe->vbe_bpp = 8)
+		info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.vmode = FB_VMODE_NONINTERLACED;
+	info->var.bits_per_pixel = dvbe->vbe_bpp;
+	info->var.xres = dvbe->vbe_width;
+	info->var.yres = dvbe->vbe_height;
+	info->var.xres_virtual = info->var.xres;
+	info->var.yres_virtual = info->var.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	info->var.pixclock = 10000000 / info->var.xres * 1000 / info->var.yres;
+	info->var.left_margin = (info->var.xres / 8) & 0xf8;
+	info->var.right_margin = 32;
+	info->var.upper_margin = 16;
+	info->var.lower_margin = 4;
+	info->var.hsync_len = (info->var.xres / 8) & 0xf8;
+	info->var.vsync_len = 4;
+
+	info->var.red.offset    = dvbe->vbe_red_pos;
+	info->var.red.length    = dvbe->vbe_red_size;
+	info->var.green.offset  = dvbe->vbe_green_pos;
+	info->var.green.length  = dvbe->vbe_green_size;
+	info->var.blue.offset   = dvbe->vbe_blue_pos;
+	info->var.blue.length   = dvbe->vbe_blue_size;
+
+	if (info->var.bits_per_pixel <= 8) {
+		info->var.red.length = info->var.bits_per_pixel;
+		info->var.green.length = info->var.bits_per_pixel;
+		info->var.blue.length = info->var.bits_per_pixel;
+	}
+
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+	info->apertures->ranges[0].base = (unsigned long)dvbe->vbe_addr;
+	info->apertures->ranges[0].size = dvbe->vbe_vsize;
+
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret < 0)
+		goto err_free;
+
+	/*
+	 * TODO: Fix register_framebuffer() to not reset refcounts!
+	 * So register_framebuffer() resets the refcnt of \info to 1. However,
+	 * any other context might call remove_conflicting_framebuffers()
+	 * before our call to register_framebuffer() returns.
+	 * remove_conflicting_framebuffers() calls unregister_framebuffer()
+	 * which then calls put_fb_info() and destroys \info by calling our
+	 * fb_destroy() callback.
+	 * To summarize, \info might be dead after register_framebuffer()
+	 * returns so don't access it afterwards. There is _no_ reliable way to
+	 * detect that so don't use \info at all now.
+	 * Instead we lock all accesses around dvbe->fbdev and the first one who
+	 * resets it is responsible of freeing it.
+	 */
+
+	dvbe->fbdev = info;
+	ret = register_framebuffer(info);
+	if (ret < 0)
+		goto err_cmap;
+
+	mutex_lock(&dvbe->ddev->struct_mutex);
+	if (dvbe->fbdev)
+		dev_info(dvbe->ddev->dev, "fbdev frontend %s as fb%d\n",
+			 info->fix.id, info->node);
+	mutex_unlock(&dvbe->ddev->struct_mutex);
+
+	return;
+
+err_cmap:
+	fb_dealloc_cmap(&info->cmap);
+err_free:
+	framebuffer_release(info);
+err_out:
+	dev_warn(dvbe->ddev->dev, "cannot create fbdev frontend (%d)\n", ret);
+}
+
+void dvbe_fbdev_cleanup(struct dvbe_device *dvbe)
+{
+	struct fb_info *info;
+
+	mutex_lock(&dvbe->ddev->struct_mutex);
+	info = dvbe->fbdev;
+	dvbe->fbdev = NULL;
+	mutex_unlock(&dvbe->ddev->struct_mutex);
+
+	if (!info)
+		return;
+
+	unregister_framebuffer(info);
+	dvbe_fbdev_free(dvbe, info);
+}
diff --git a/drivers/gpu/drm/dvbe/dvbe_main.c b/drivers/gpu/drm/dvbe/dvbe_main.c
index c418310..95241a6 100644
--- a/drivers/gpu/drm/dvbe/dvbe_main.c
+++ b/drivers/gpu/drm/dvbe/dvbe_main.c
@@ -408,6 +408,7 @@ int dvbe_drm_load(struct drm_device *ddev, unsigned long flags)
 	if (ret)
 		goto err_cleanup;
 
+	dvbe_fbdev_init(dvbe);
 	return 0;
 
 err_cleanup:
@@ -422,6 +423,7 @@ int dvbe_drm_unload(struct drm_device *ddev)
 {
 	struct dvbe_device *dvbe = ddev->dev_private;
 
+	dvbe_fbdev_cleanup(dvbe);
 	drm_mode_config_cleanup(ddev);
 	dvbe_vesa_cleanup(dvbe);
 	kfree(dvbe);
-- 
1.8.1.3


^ permalink raw reply related

* RE: [PATCH RFC] video: Add Hyper-V Synthetic Video Frame Buffer Driver
From: Haiyang Zhang @ 2013-02-17 19:10 UTC (permalink / raw)
  To: Olaf Hering
  Cc: FlorianSchandinat@gmx.de, linux-fbdev@vger.kernel.org,
	KY Srinivasan, jasowang@redhat.com, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org
In-Reply-To: <20130217143223.GA11543@aepfle.de>

> From: Olaf Hering
> Sent: Sunday, February 17, 2013 9:32 AM
> To: Haiyang Zhang
> Cc: FlorianSchandinat@gmx.de; linux-fbdev@vger.kernel.org; KY Srinivasan; jasowang@redhat.com; linux-kernel@vger.kernel.org; devel@linuxdriverproject.org
> Subject: Re: [PATCH RFC] video: Add Hyper-V Synthetic Video Frame Buffer Driver

> On Fri, Feb 15, Haiyang Zhang wrote:

> +config HYPERV_FB

> This should probably be FB_HYPERB to follow the naming of all other
> drivers.

Will do.

Thanks,
- Haiyang

^ permalink raw reply

* Re: [PATCH 0/9] System Framebuffer Bus (sysfb)
From: Dave Airlie @ 2013-02-17 22:02 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-fbdev, linux-kernel, dri-devel, Florian Tobias Schandinat
In-Reply-To: <1361123951-587-1-git-send-email-dh.herrmann@gmail.com>

>
> This series tries to fix the mess with global system framebuffer access in
> device drivers. Currently, architecture initialization sets the "screen_info"
> object according to the system framebuffer that was detected during boot. The
> device driver that can map VMEM first gets access to it. There is no way to give
> a specific driver access to the device and no _proper_ way to revoke access
> again. In fact, some drivers don't even check whether they mapped the VMEM
> successfully, letting multiple drivers to access the system framebuffer at the
> same time.

I'm unsure if I like this or not, and I don't see why its greatly more
useful than the interface we have now.

It doesn't solve the main problem with the current interface, which is
that if somebody opens has vesafb /dev/fb0, mmaps it, and modprobes a
real driver, things will fail either miserably or crappy from a users
pov.

The internal reference counts stop vesafb from unloading due to the
mmaps, then i915 loads anyways and one bashes the other, or we fix so
i915 doesn't load and the user gets fail.

Dave.

^ permalink raw reply

* Re: [PATCH 0/9] System Framebuffer Bus (sysfb)
From: David Herrmann @ 2013-02-17 23:35 UTC (permalink / raw)
  To: Dave Airlie
  Cc: linux-fbdev, linux-kernel, dri-devel, Florian Tobias Schandinat
In-Reply-To: <CAPM=9txQtJ6FLFTEFr_Wi6RK=W9y3gKYxV_+zPCo6kLi4nM8eA@mail.gmail.com>

Hi Dave

On Sun, Feb 17, 2013 at 11:02 PM, Dave Airlie <airlied@gmail.com> wrote:
>>
>> This series tries to fix the mess with global system framebuffer access in
>> device drivers. Currently, architecture initialization sets the "screen_info"
>> object according to the system framebuffer that was detected during boot. The
>> device driver that can map VMEM first gets access to it. There is no way to give
>> a specific driver access to the device and no _proper_ way to revoke access
>> again. In fact, some drivers don't even check whether they mapped the VMEM
>> successfully, letting multiple drivers to access the system framebuffer at the
>> same time.
>
> I'm unsure if I like this or not, and I don't see why its greatly more
> useful than the interface we have now.

This interface at least solves the problem with having vesafb,
uvesafb, vgacon, vga16fb, efifb, dvbe, defi and all other similar
drivers from accessing the system framebuffer simultaneously. And
provides a sane way of registering devices and drivers for it.

It also provides a way for real drivers to unload these drivers
(sysfb_claim()) instead of using remove_conflicting_framebuffers(),
which is horribly broken and has lots of race-conditions. (I tried
fixing the fbdev refcounting/locking, but every time I tried, some
driver broke because they worked around the bug. And fixing all
drivers is just a lot of work...).
And remove_conflicting_framebuffers() also doesn't work with
vgacon/etc. which do _not_ use fbdev.

We could simplify this approach by removing the bus and just providing
the platform-device for vbefb/etc. from the arch-code. But I thought
the bus-infrastructure allows nice rebinding of drivers if we need it
at almost no cost.

You could even register an oops/panic-screen as driver there and
switch to it if necessary.

> It doesn't solve the main problem with the current interface, which is
> that if somebody opens has vesafb /dev/fb0, mmaps it, and modprobes a
> real driver, things will fail either miserably or crappy from a users
> pov.
>
> The internal reference counts stop vesafb from unloading due to the
> mmaps, then i915 loads anyways and one bashes the other, or we fix so
> i915 doesn't load and the user gets fail.

It's not the mmap that prevents vesafb from unloading, it's the
open-file instead. If a user does open(), mmap(), close(), they can
still access the mapped memory but vesafb might get unloaded (this is,
in fact, used by several user-space apps). So it's not about whether
vesafb is still loaded, but rather what to do about users which have
vesafb mmaped but don't expect it to go away.

So what do you propose to detect this case? Keep track of every user
who mmap's vesafb? How can we detect when they unmap the memory? I
think the only way to detect this is to wait for the pages'
"mmap-count" to drop to zero and then release the memory.

So lets compare this to other subsystems. If you unlink a file that is
still mmaped, I think the file isn't removed from memory until the
last user unmaps it. However, the memory-mapping is 'dead' in that it
doesn't have any effect on real files.
So why not copy that behavior to framebuffers? When a real DRM driver
is loaded, simply reserve the VBE framebuffer-memory in VMEM until the
last user unmaps it. But mark it 'dead' so it doesn't really belong to
a _real_ framebuffer.
So any access to the mmap'ed framebuffers will be a no-op as it just
modifies 'dead' framebuffers.

Another idea is copying the VBE framebuffer into the DRM driver so all
old memory-maps are still valid. However, this prevents us from doing
any kind of mode-setting in the DRM driver until the last fbdev user
is gone (because there is no way to notify fbdev users of
mode-setting).
So in this case we are also stuck in a situation where we need to wait
for all users to unmap their framebuffers.

Any comments? If you have a plan on how it is supposed to work (or
what the user-space semantics should be), tell me and I will try to
make it work.
I still think a central system-framebuffer registry like sysfb-bus
(which does _not_ explicitly depend on fbdev) is the way to go.
Whether it's a bus or not is just a matter of taste. I am willing to
rework this.

Thanks
David

^ permalink raw reply

* Re: [PATCH 0/9] System Framebuffer Bus (sysfb)
From: Dave Airlie @ 2013-02-17 23:47 UTC (permalink / raw)
  To: David Herrmann
  Cc: linux-kernel, Florian Tobias Schandinat, linux-fbdev,
	David Airlie, dri-devel
In-Reply-To: <CANq1E4TTB-Lp+eVRPpzOMnS7XNbzHJRTicwCcwXw3AUs11XFMw@mail.gmail.com>

>> I'm unsure if I like this or not, and I don't see why its greatly more
>> useful than the interface we have now.
>
> This interface at least solves the problem with having vesafb,
> uvesafb, vgacon, vga16fb, efifb, dvbe, defi and all other similar
> drivers from accessing the system framebuffer simultaneously. And
> provides a sane way of registering devices and drivers for it.

But do we have the problem now? or is it more when we get dvbe/defi?

Also vgacon is kinda different since fbcon kicks it off, not a driver,

> It also provides a way for real drivers to unload these drivers
> (sysfb_claim()) instead of using remove_conflicting_framebuffers(),
> which is horribly broken and has lots of race-conditions. (I tried
> fixing the fbdev refcounting/locking, but every time I tried, some
> driver broke because they worked around the bug. And fixing all
> drivers is just a lot of work...).
> And remove_conflicting_framebuffers() also doesn't work with
> vgacon/etc. which do _not_ use fbdev.

but vgacon is always kicked off by fbcon, so I'm not sure what etc there
is apart from it. I'd like to make fbcon a bool as well, so we don't
have to deal with it appearing after the drivers.

> We could simplify this approach by removing the bus and just providing
> the platform-device for vbefb/etc. from the arch-code. But I thought
> the bus-infrastructure allows nice rebinding of drivers if we need it
> at almost no cost.

I suspect a platform device is the right answer, since vesafb is that,

I think we should resolve vesafb vs dvbe by just making them not
config compatible, and dvbe vs defi seems like the same solution
as vesafb vs efi.

I'm just trying to work out what exactly you are fixing here, the
problems we have now don't seem to be addressed by this, if
it addresses future problems then it needs to be more upfront.

>> It doesn't solve the main problem with the current interface, which is
>> that if somebody opens has vesafb /dev/fb0, mmaps it, and modprobes a
>> real driver, things will fail either miserably or crappy from a users
>> pov.
>>
>> The internal reference counts stop vesafb from unloading due to the
>> mmaps, then i915 loads anyways and one bashes the other, or we fix so
>> i915 doesn't load and the user gets fail.
>
> It's not the mmap that prevents vesafb from unloading, it's the
> open-file instead. If a user does open(), mmap(), close(), they can
> still access the mapped memory but vesafb might get unloaded (this is,
> in fact, used by several user-space apps). So it's not about whether
> vesafb is still loaded, but rather what to do about users which have
> vesafb mmaped but don't expect it to go away.

In theory we'd have to do like GEM/TTM, and unmap_mapping_range for
all the open fd's mmaps and just point them to map something useless
or even just return -EFAULT, because really userspace needs to be told
something :-)

> So what do you propose to detect this case? Keep track of every user
> who mmap's vesafb? How can we detect when they unmap the memory? I
> think the only way to detect this is to wait for the pages'
> "mmap-count" to drop to zero and then release the memory.
>
> So lets compare this to other subsystems. If you unlink a file that is
> still mmaped, I think the file isn't removed from memory until the
> last user unmaps it. However, the memory-mapping is 'dead' in that it
> doesn't have any effect on real files.
> So why not copy that behavior to framebuffers? When a real DRM driver
> is loaded, simply reserve the VBE framebuffer-memory in VMEM until the
> last user unmaps it. But mark it 'dead' so it doesn't really belong to
> a _real_ framebuffer.
> So any access to the mmap'ed framebuffers will be a no-op as it just
> modifies 'dead' framebuffers.
>
> Another idea is copying the VBE framebuffer into the DRM driver so all
> old memory-maps are still valid. However, this prevents us from doing
> any kind of mode-setting in the DRM driver until the last fbdev user
> is gone (because there is no way to notify fbdev users of
> mode-setting).
> So in this case we are also stuck in a situation where we need to wait
> for all users to unmap their framebuffers.

It all kinda sucks, from the problems we've had previously with things
like plymouth
racing, (which all this will make much worse if we have kms vbe devices) really
what we want the system to do is give the user the proper driver asap, stalling
waiting for endless other things to let go is just going to screw
users, so I think
we need to be as upfront and brutal in the userspace interface if people mmaping
vesafb or efifb or any generic interface then expect to load a real driver, then
their old apps get killed.

> Any comments? If you have a plan on how it is supposed to work (or
> what the user-space semantics should be), tell me and I will try to
> make it work.
> I still think a central system-framebuffer registry like sysfb-bus
> (which does _not_ explicitly depend on fbdev) is the way to go.
> Whether it's a bus or not is just a matter of taste. I am willing to
> rework this.

As I said maybe I'm concentrating on the problem you aren't trying to fix,
but then I'm not sure I've enough information on the problem you are
trying to fix,

remove_confilicting_framebuffers might be ugly but it does 90% of what we want,
I just want to understand why this will make it better,

Dave.

^ permalink raw reply

* [PATCH 1/5 RESEND] video: s3c-fb: use ARCH_ dependancy
From: Jingoo Han @ 2013-02-18  5:13 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'

This patch uses ARCH_ dependancy when using s3c-fb.
S3C_DEV_FB, S5P_DEV_FIMD0 cannot be enabled on EXYNOS5.
So, ARCH_ should be used as dependancy for s3c-fb.

Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 drivers/video/Kconfig |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e7068c5..049fff1 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2025,7 +2025,8 @@ config FB_TMIO_ACCELL
 
 config FB_S3C
 	tristate "Samsung S3C framebuffer support"
-	depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
+	depends on FB && (CPU_S3C2416 || ARCH_S3C64XX || ARCH_S5P64X0 || \
+		ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 2/5 RESEND] video: s3c-fb: remove duplicated S3C_FB_MAX_WIN
From: Jingoo Han @ 2013-02-18  5:14 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'
In-Reply-To: <000201ce0d96$9fa550b0$deeff210$%han@samsung.com>

S3C_FB_MAX_WIN is already defined in 'plat-samsung/include/plat/fb.h'.
So, this definition in 'include/video/samsung_fimd.h' should be
removed to avoid the duplication.

Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 include/video/samsung_fimd.h |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
index e755448..0865256 100644
--- a/include/video/samsung_fimd.h
+++ b/include/video/samsung_fimd.h
@@ -438,8 +438,6 @@
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
 
-#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
-
 /* Notes on per-window bpp settings
  *
  * Value	Win0	 Win1	  Win2	   Win3	    Win 4
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 3/5 RESEND] video: s3c-fb: remove unnecessary brackets
From: Jingoo Han @ 2013-02-18  5:15 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'
In-Reply-To: <000201ce0d96$9fa550b0$deeff210$%han@samsung.com>

This patch removes unnecessary brackets and the duplicated
VIDTCON2 definition.

Also, header comment is modified, because EXYNOS series is
supported and <mach/regs-fb.h> is not available.

Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 include/video/samsung_fimd.h |  199 ++++++++++++++++++++---------------------
 1 files changed, 97 insertions(+), 102 deletions(-)

diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
index 0865256..be7b853 100644
--- a/include/video/samsung_fimd.h
+++ b/include/video/samsung_fimd.h
@@ -8,12 +8,8 @@
  * S3C Platform - new-style fimd and framebuffer register definitions
  *
  * This is the register set for the fimd and new style framebuffer interface
- * found from the S3C2443 onwards into the S3C2416, S3C2450 and the
- * S3C64XX series such as the S3C6400 and S3C6410.
- *
- * The file does not contain the cpu specific items which are based on
- * whichever architecture is selected, it only contains the core of the
- * register set. See <mach/regs-fb.h> to get the specifics.
+ * found from the S3C2443 onwards into the S3C2416, S3C2450, the
+ * S3C64XX series such as the S3C6400 and S3C6410, and EXYNOS series.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -22,10 +18,10 @@
 
 /* VIDCON0 */
 
-#define VIDCON0					(0x00)
+#define VIDCON0					0x00
 #define VIDCON0_INTERLACE			(1 << 29)
 #define VIDCON0_VIDOUT_MASK			(0x7 << 26)
-#define VIDCON0_VIDOUT_SHIFT			(26)
+#define VIDCON0_VIDOUT_SHIFT			26
 #define VIDCON0_VIDOUT_RGB			(0x0 << 26)
 #define VIDCON0_VIDOUT_TV			(0x1 << 26)
 #define VIDCON0_VIDOUT_I80_LDI0			(0x2 << 26)
@@ -35,7 +31,7 @@
 #define VIDCON0_VIDOUT_WB_I80_LDI1		(0x7 << 26)
 
 #define VIDCON0_L1_DATA_MASK			(0x7 << 23)
-#define VIDCON0_L1_DATA_SHIFT			(23)
+#define VIDCON0_L1_DATA_SHIFT			23
 #define VIDCON0_L1_DATA_16BPP			(0x0 << 23)
 #define VIDCON0_L1_DATA_18BPP16			(0x1 << 23)
 #define VIDCON0_L1_DATA_18BPP9			(0x2 << 23)
@@ -44,7 +40,7 @@
 #define VIDCON0_L1_DATA_16BPP8			(0x5 << 23)
 
 #define VIDCON0_L0_DATA_MASK			(0x7 << 20)
-#define VIDCON0_L0_DATA_SHIFT			(20)
+#define VIDCON0_L0_DATA_SHIFT			20
 #define VIDCON0_L0_DATA_16BPP			(0x0 << 20)
 #define VIDCON0_L0_DATA_18BPP16			(0x1 << 20)
 #define VIDCON0_L0_DATA_18BPP9			(0x2 << 20)
@@ -53,7 +49,7 @@
 #define VIDCON0_L0_DATA_16BPP8			(0x5 << 20)
 
 #define VIDCON0_PNRMODE_MASK			(0x3 << 17)
-#define VIDCON0_PNRMODE_SHIFT			(17)
+#define VIDCON0_PNRMODE_SHIFT			17
 #define VIDCON0_PNRMODE_RGB			(0x0 << 17)
 #define VIDCON0_PNRMODE_BGR			(0x1 << 17)
 #define VIDCON0_PNRMODE_SERIAL_RGB		(0x2 << 17)
@@ -61,14 +57,14 @@
 
 #define VIDCON0_CLKVALUP			(1 << 16)
 #define VIDCON0_CLKVAL_F_MASK			(0xff << 6)
-#define VIDCON0_CLKVAL_F_SHIFT			(6)
-#define VIDCON0_CLKVAL_F_LIMIT			(0xff)
+#define VIDCON0_CLKVAL_F_SHIFT			6
+#define VIDCON0_CLKVAL_F_LIMIT			0xff
 #define VIDCON0_CLKVAL_F(_x)			((_x) << 6)
 #define VIDCON0_VLCKFREE			(1 << 5)
 #define VIDCON0_CLKDIR				(1 << 4)
 
 #define VIDCON0_CLKSEL_MASK			(0x3 << 2)
-#define VIDCON0_CLKSEL_SHIFT			(2)
+#define VIDCON0_CLKSEL_SHIFT			2
 #define VIDCON0_CLKSEL_HCLK			(0x0 << 2)
 #define VIDCON0_CLKSEL_LCD			(0x1 << 2)
 #define VIDCON0_CLKSEL_27M			(0x3 << 2)
@@ -76,13 +72,13 @@
 #define VIDCON0_ENVID				(1 << 1)
 #define VIDCON0_ENVID_F				(1 << 0)
 
-#define VIDCON1					(0x04)
+#define VIDCON1					0x04
 #define VIDCON1_LINECNT_MASK			(0x7ff << 16)
-#define VIDCON1_LINECNT_SHIFT			(16)
+#define VIDCON1_LINECNT_SHIFT			16
 #define VIDCON1_LINECNT_GET(_v)			(((_v) >> 16) & 0x7ff)
 #define VIDCON1_FSTATUS_EVEN			(1 << 15)
 #define VIDCON1_VSTATUS_MASK			(0x3 << 13)
-#define VIDCON1_VSTATUS_SHIFT			(13)
+#define VIDCON1_VSTATUS_SHIFT			13
 #define VIDCON1_VSTATUS_VSYNC			(0x0 << 13)
 #define VIDCON1_VSTATUS_BACKPORCH		(0x1 << 13)
 #define VIDCON1_VSTATUS_ACTIVE			(0x2 << 13)
@@ -98,12 +94,12 @@
 
 /* VIDCON2 */
 
-#define VIDCON2					(0x08)
+#define VIDCON2					0x08
 #define VIDCON2_EN601				(1 << 23)
 #define VIDCON2_TVFMTSEL_SW			(1 << 14)
 
 #define VIDCON2_TVFMTSEL1_MASK			(0x3 << 12)
-#define VIDCON2_TVFMTSEL1_SHIFT			(12)
+#define VIDCON2_TVFMTSEL1_SHIFT			12
 #define VIDCON2_TVFMTSEL1_RGB			(0x0 << 12)
 #define VIDCON2_TVFMTSEL1_YUV422		(0x1 << 12)
 #define VIDCON2_TVFMTSEL1_YUV444		(0x2 << 12)
@@ -115,74 +111,73 @@
  * Might not be present in the S3C6410 documentation,
  * but tests prove it's there almost for sure; shouldn't hurt in any case.
  */
-#define PRTCON					(0x0c)
+#define PRTCON					0x0c
 #define PRTCON_PROTECT				(1 << 11)
 
 /* VIDTCON0 */
 
-#define VIDTCON0				(0x10)
+#define VIDTCON0				0x10
 #define VIDTCON0_VBPDE_MASK			(0xff << 24)
-#define VIDTCON0_VBPDE_SHIFT			(24)
-#define VIDTCON0_VBPDE_LIMIT			(0xff)
+#define VIDTCON0_VBPDE_SHIFT			24
+#define VIDTCON0_VBPDE_LIMIT			0xff
 #define VIDTCON0_VBPDE(_x)			((_x) << 24)
 
 #define VIDTCON0_VBPD_MASK			(0xff << 16)
-#define VIDTCON0_VBPD_SHIFT			(16)
-#define VIDTCON0_VBPD_LIMIT			(0xff)
+#define VIDTCON0_VBPD_SHIFT			16
+#define VIDTCON0_VBPD_LIMIT			0xff
 #define VIDTCON0_VBPD(_x)			((_x) << 16)
 
 #define VIDTCON0_VFPD_MASK			(0xff << 8)
-#define VIDTCON0_VFPD_SHIFT			(8)
-#define VIDTCON0_VFPD_LIMIT			(0xff)
+#define VIDTCON0_VFPD_SHIFT			8
+#define VIDTCON0_VFPD_LIMIT			0xff
 #define VIDTCON0_VFPD(_x)			((_x) << 8)
 
 #define VIDTCON0_VSPW_MASK			(0xff << 0)
-#define VIDTCON0_VSPW_SHIFT			(0)
-#define VIDTCON0_VSPW_LIMIT			(0xff)
+#define VIDTCON0_VSPW_SHIFT			0
+#define VIDTCON0_VSPW_LIMIT			0xff
 #define VIDTCON0_VSPW(_x)			((_x) << 0)
 
 /* VIDTCON1 */
 
-#define VIDTCON1				(0x14)
+#define VIDTCON1				0x14
 #define VIDTCON1_VFPDE_MASK			(0xff << 24)
-#define VIDTCON1_VFPDE_SHIFT			(24)
-#define VIDTCON1_VFPDE_LIMIT			(0xff)
+#define VIDTCON1_VFPDE_SHIFT			24
+#define VIDTCON1_VFPDE_LIMIT			0xff
 #define VIDTCON1_VFPDE(_x)			((_x) << 24)
 
 #define VIDTCON1_HBPD_MASK			(0xff << 16)
-#define VIDTCON1_HBPD_SHIFT			(16)
-#define VIDTCON1_HBPD_LIMIT			(0xff)
+#define VIDTCON1_HBPD_SHIFT			16
+#define VIDTCON1_HBPD_LIMIT			0xff
 #define VIDTCON1_HBPD(_x)			((_x) << 16)
 
 #define VIDTCON1_HFPD_MASK			(0xff << 8)
-#define VIDTCON1_HFPD_SHIFT			(8)
-#define VIDTCON1_HFPD_LIMIT			(0xff)
+#define VIDTCON1_HFPD_SHIFT			8
+#define VIDTCON1_HFPD_LIMIT			0xff
 #define VIDTCON1_HFPD(_x)			((_x) << 8)
 
 #define VIDTCON1_HSPW_MASK			(0xff << 0)
-#define VIDTCON1_HSPW_SHIFT			(0)
-#define VIDTCON1_HSPW_LIMIT			(0xff)
+#define VIDTCON1_HSPW_SHIFT			0
+#define VIDTCON1_HSPW_LIMIT			0xff
 #define VIDTCON1_HSPW(_x)			((_x) << 0)
 
-#define VIDTCON2				(0x18)
-#define VIDTCON2				(0x18)
+#define VIDTCON2				0x18
 #define VIDTCON2_LINEVAL_E(_x)			((((_x) & 0x800) >> 11) << 23)
 #define VIDTCON2_LINEVAL_MASK			(0x7ff << 11)
-#define VIDTCON2_LINEVAL_SHIFT			(11)
-#define VIDTCON2_LINEVAL_LIMIT			(0x7ff)
+#define VIDTCON2_LINEVAL_SHIFT			11
+#define VIDTCON2_LINEVAL_LIMIT			0x7ff
 #define VIDTCON2_LINEVAL(_x)			(((_x) & 0x7ff) << 11)
 
 #define VIDTCON2_HOZVAL_E(_x)			((((_x) & 0x800) >> 11) << 22)
 #define VIDTCON2_HOZVAL_MASK			(0x7ff << 0)
-#define VIDTCON2_HOZVAL_SHIFT			(0)
-#define VIDTCON2_HOZVAL_LIMIT			(0x7ff)
+#define VIDTCON2_HOZVAL_SHIFT			0
+#define VIDTCON2_HOZVAL_LIMIT			0x7ff
 #define VIDTCON2_HOZVAL(_x)			(((_x) & 0x7ff) << 0)
 
 /* WINCONx */
 
 #define WINCON(_win)				(0x20 + ((_win) * 4))
 #define WINCONx_CSCWIDTH_MASK			(0x3 << 26)
-#define WINCONx_CSCWIDTH_SHIFT			(26)
+#define WINCONx_CSCWIDTH_SHIFT			26
 #define WINCONx_CSCWIDTH_WIDE			(0x0 << 26)
 #define WINCONx_CSCWIDTH_NARROW			(0x3 << 26)
 #define WINCONx_ENLOCAL				(1 << 22)
@@ -195,14 +190,14 @@
 #define WINCONx_WSWP				(1 << 15)
 #define WINCONx_YCbCr				(1 << 13)
 #define WINCONx_BURSTLEN_MASK			(0x3 << 9)
-#define WINCONx_BURSTLEN_SHIFT			(9)
+#define WINCONx_BURSTLEN_SHIFT			9
 #define WINCONx_BURSTLEN_16WORD			(0x0 << 9)
 #define WINCONx_BURSTLEN_8WORD			(0x1 << 9)
 #define WINCONx_BURSTLEN_4WORD			(0x2 << 9)
 #define WINCONx_ENWIN				(1 << 0)
 
 #define WINCON0_BPPMODE_MASK			(0xf << 2)
-#define WINCON0_BPPMODE_SHIFT			(2)
+#define WINCON0_BPPMODE_SHIFT			2
 #define WINCON0_BPPMODE_1BPP			(0x0 << 2)
 #define WINCON0_BPPMODE_2BPP			(0x1 << 2)
 #define WINCON0_BPPMODE_4BPP			(0x2 << 2)
@@ -215,7 +210,7 @@
 #define WINCON1_LOCALSEL_CAMIF			(1 << 23)
 #define WINCON1_BLD_PIX				(1 << 6)
 #define WINCON1_BPPMODE_MASK			(0xf << 2)
-#define WINCON1_BPPMODE_SHIFT			(2)
+#define WINCON1_BPPMODE_SHIFT			2
 #define WINCON1_BPPMODE_1BPP			(0x0 << 2)
 #define WINCON1_BPPMODE_2BPP			(0x1 << 2)
 #define WINCON1_BPPMODE_4BPP			(0x2 << 2)
@@ -234,7 +229,7 @@
 #define WINCON1_ALPHA_SEL			(1 << 1)
 
 /* S5PV210 */
-#define SHADOWCON				(0x34)
+#define SHADOWCON				0x34
 #define SHADOWCON_WINx_PROTECT(_win)		(1 << (10 + (_win)))
 /* DMA channels (all windows) */
 #define SHADOWCON_CHx_ENABLE(_win)		(1 << (_win))
@@ -243,52 +238,52 @@
 
 /* VIDOSDx */
 
-#define VIDOSD_BASE				(0x40)
+#define VIDOSD_BASE				0x40
 #define VIDOSDxA_TOPLEFT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxA_TOPLEFT_X_MASK			(0x7ff << 11)
-#define VIDOSDxA_TOPLEFT_X_SHIFT		(11)
-#define VIDOSDxA_TOPLEFT_X_LIMIT		(0x7ff)
+#define VIDOSDxA_TOPLEFT_X_SHIFT		11
+#define VIDOSDxA_TOPLEFT_X_LIMIT		0x7ff
 #define VIDOSDxA_TOPLEFT_X(_x)			(((_x) & 0x7ff) << 11)
 
 #define VIDOSDxA_TOPLEFT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxA_TOPLEFT_Y_MASK			(0x7ff << 0)
-#define VIDOSDxA_TOPLEFT_Y_SHIFT		(0)
-#define VIDOSDxA_TOPLEFT_Y_LIMIT		(0x7ff)
+#define VIDOSDxA_TOPLEFT_Y_SHIFT		0
+#define VIDOSDxA_TOPLEFT_Y_LIMIT		0x7ff
 #define VIDOSDxA_TOPLEFT_Y(_x)			(((_x) & 0x7ff) << 0)
 
 #define VIDOSDxB_BOTRIGHT_X_E(_x)		((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxB_BOTRIGHT_X_MASK		(0x7ff << 11)
-#define VIDOSDxB_BOTRIGHT_X_SHIFT		(11)
-#define VIDOSDxB_BOTRIGHT_X_LIMIT		(0x7ff)
+#define VIDOSDxB_BOTRIGHT_X_SHIFT		11
+#define VIDOSDxB_BOTRIGHT_X_LIMIT		0x7ff
 #define VIDOSDxB_BOTRIGHT_X(_x)			(((_x) & 0x7ff) << 11)
 
 #define VIDOSDxB_BOTRIGHT_Y_E(_x)		((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxB_BOTRIGHT_Y_MASK		(0x7ff << 0)
-#define VIDOSDxB_BOTRIGHT_Y_SHIFT		(0)
-#define VIDOSDxB_BOTRIGHT_Y_LIMIT		(0x7ff)
+#define VIDOSDxB_BOTRIGHT_Y_SHIFT		0
+#define VIDOSDxB_BOTRIGHT_Y_LIMIT		0x7ff
 #define VIDOSDxB_BOTRIGHT_Y(_x)			(((_x) & 0x7ff) << 0)
 
 /* For VIDOSD[1..4]C */
 #define VIDISD14C_ALPHA0_R(_x)			((_x) << 20)
 #define VIDISD14C_ALPHA0_G_MASK			(0xf << 16)
-#define VIDISD14C_ALPHA0_G_SHIFT		(16)
-#define VIDISD14C_ALPHA0_G_LIMIT		(0xf)
+#define VIDISD14C_ALPHA0_G_SHIFT		16
+#define VIDISD14C_ALPHA0_G_LIMIT		0xf
 #define VIDISD14C_ALPHA0_G(_x)			((_x) << 16)
 #define VIDISD14C_ALPHA0_B_MASK			(0xf << 12)
-#define VIDISD14C_ALPHA0_B_SHIFT		(12)
-#define VIDISD14C_ALPHA0_B_LIMIT		(0xf)
+#define VIDISD14C_ALPHA0_B_SHIFT		12
+#define VIDISD14C_ALPHA0_B_LIMIT		0xf
 #define VIDISD14C_ALPHA0_B(_x)			((_x) << 12)
 #define VIDISD14C_ALPHA1_R_MASK			(0xf << 8)
-#define VIDISD14C_ALPHA1_R_SHIFT		(8)
-#define VIDISD14C_ALPHA1_R_LIMIT		(0xf)
+#define VIDISD14C_ALPHA1_R_SHIFT		8
+#define VIDISD14C_ALPHA1_R_LIMIT		0xf
 #define VIDISD14C_ALPHA1_R(_x)			((_x) << 8)
 #define VIDISD14C_ALPHA1_G_MASK			(0xf << 4)
-#define VIDISD14C_ALPHA1_G_SHIFT		(4)
-#define VIDISD14C_ALPHA1_G_LIMIT		(0xf)
+#define VIDISD14C_ALPHA1_G_SHIFT		4
+#define VIDISD14C_ALPHA1_G_LIMIT		0xf
 #define VIDISD14C_ALPHA1_G(_x)			((_x) << 4)
 #define VIDISD14C_ALPHA1_B_MASK			(0xf << 0)
-#define VIDISD14C_ALPHA1_B_SHIFT		(0)
-#define VIDISD14C_ALPHA1_B_LIMIT		(0xf)
+#define VIDISD14C_ALPHA1_B_SHIFT		0
+#define VIDISD14C_ALPHA1_B_LIMIT		0xf
 #define VIDISD14C_ALPHA1_B(_x)			((_x) << 0)
 
 /* Video buffer addresses */
@@ -300,22 +295,22 @@
 
 #define VIDW_BUF_SIZE_OFFSET_E(_x)		((((_x) & 0x2000) >> 13) << 27)
 #define VIDW_BUF_SIZE_OFFSET_MASK		(0x1fff << 13)
-#define VIDW_BUF_SIZE_OFFSET_SHIFT		(13)
-#define VIDW_BUF_SIZE_OFFSET_LIMIT		(0x1fff)
+#define VIDW_BUF_SIZE_OFFSET_SHIFT		13
+#define VIDW_BUF_SIZE_OFFSET_LIMIT		0x1fff
 #define VIDW_BUF_SIZE_OFFSET(_x)		(((_x) & 0x1fff) << 13)
 
 #define VIDW_BUF_SIZE_PAGEWIDTH_E(_x)		((((_x) & 0x2000) >> 13) << 26)
 #define VIDW_BUF_SIZE_PAGEWIDTH_MASK		(0x1fff << 0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT		(0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT		(0x1fff)
+#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT		0
+#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT		0x1fff
 #define VIDW_BUF_SIZE_PAGEWIDTH(_x)		(((_x) & 0x1fff) << 0)
 
 /* Interrupt controls and status */
 
-#define VIDINTCON0				(0x130)
+#define VIDINTCON0				0x130
 #define VIDINTCON0_FIFOINTERVAL_MASK		(0x3f << 20)
-#define VIDINTCON0_FIFOINTERVAL_SHIFT		(20)
-#define VIDINTCON0_FIFOINTERVAL_LIMIT		(0x3f)
+#define VIDINTCON0_FIFOINTERVAL_SHIFT		20
+#define VIDINTCON0_FIFOINTERVAL_LIMIT		0x3f
 #define VIDINTCON0_FIFOINTERVAL(_x)		((_x) << 20)
 
 #define VIDINTCON0_INT_SYSMAINCON		(1 << 19)
@@ -323,7 +318,7 @@
 #define VIDINTCON0_INT_I80IFDONE		(1 << 17)
 
 #define VIDINTCON0_FRAMESEL0_MASK		(0x3 << 15)
-#define VIDINTCON0_FRAMESEL0_SHIFT		(15)
+#define VIDINTCON0_FRAMESEL0_SHIFT		15
 #define VIDINTCON0_FRAMESEL0_BACKPORCH		(0x0 << 15)
 #define VIDINTCON0_FRAMESEL0_VSYNC		(0x1 << 15)
 #define VIDINTCON0_FRAMESEL0_ACTIVE		(0x2 << 15)
@@ -338,7 +333,7 @@
 
 #define VIDINTCON0_INT_FRAME			(1 << 12)
 #define VIDINTCON0_FIFIOSEL_MASK		(0x7f << 5)
-#define VIDINTCON0_FIFIOSEL_SHIFT		(5)
+#define VIDINTCON0_FIFIOSEL_SHIFT		5
 #define VIDINTCON0_FIFIOSEL_WINDOW0		(0x1 << 5)
 #define VIDINTCON0_FIFIOSEL_WINDOW1		(0x2 << 5)
 #define VIDINTCON0_FIFIOSEL_WINDOW2		(0x10 << 5)
@@ -346,7 +341,7 @@
 #define VIDINTCON0_FIFIOSEL_WINDOW4		(0x40 << 5)
 
 #define VIDINTCON0_FIFOLEVEL_MASK		(0x7 << 2)
-#define VIDINTCON0_FIFOLEVEL_SHIFT		(2)
+#define VIDINTCON0_FIFOLEVEL_SHIFT		2
 #define VIDINTCON0_FIFOLEVEL_TO25PC		(0x0 << 2)
 #define VIDINTCON0_FIFOLEVEL_TO50PC		(0x1 << 2)
 #define VIDINTCON0_FIFOLEVEL_TO75PC		(0x2 << 2)
@@ -354,46 +349,46 @@
 #define VIDINTCON0_FIFOLEVEL_FULL		(0x4 << 2)
 
 #define VIDINTCON0_INT_FIFO_MASK		(0x3 << 0)
-#define VIDINTCON0_INT_FIFO_SHIFT		(0)
+#define VIDINTCON0_INT_FIFO_SHIFT		0
 #define VIDINTCON0_INT_ENABLE			(1 << 0)
 
-#define VIDINTCON1				(0x134)
+#define VIDINTCON1				0x134
 #define VIDINTCON1_INT_I180			(1 << 2)
 #define VIDINTCON1_INT_FRAME			(1 << 1)
 #define VIDINTCON1_INT_FIFO			(1 << 0)
 
 /* Window colour-key control registers */
-#define WKEYCON					(0x140)	/* 6410,V210 */
+#define WKEYCON					0x140
 
-#define WKEYCON0				(0x00)
-#define WKEYCON1				(0x04)
+#define WKEYCON0				0x00
+#define WKEYCON1				0x04
 
 #define WxKEYCON0_KEYBL_EN			(1 << 26)
 #define WxKEYCON0_KEYEN_F			(1 << 25)
 #define WxKEYCON0_DIRCON			(1 << 24)
 #define WxKEYCON0_COMPKEY_MASK			(0xffffff << 0)
-#define WxKEYCON0_COMPKEY_SHIFT			(0)
-#define WxKEYCON0_COMPKEY_LIMIT			(0xffffff)
+#define WxKEYCON0_COMPKEY_SHIFT			0
+#define WxKEYCON0_COMPKEY_LIMIT			0xffffff
 #define WxKEYCON0_COMPKEY(_x)			((_x) << 0)
 #define WxKEYCON1_COLVAL_MASK			(0xffffff << 0)
-#define WxKEYCON1_COLVAL_SHIFT			(0)
-#define WxKEYCON1_COLVAL_LIMIT			(0xffffff)
+#define WxKEYCON1_COLVAL_SHIFT			0
+#define WxKEYCON1_COLVAL_LIMIT			0xffffff
 #define WxKEYCON1_COLVAL(_x)			((_x) << 0)
 
 /* Dithering control */
-#define DITHMODE				(0x170)
+#define DITHMODE				0x170
 #define DITHMODE_R_POS_MASK			(0x3 << 5)
-#define DITHMODE_R_POS_SHIFT			(5)
+#define DITHMODE_R_POS_SHIFT			5
 #define DITHMODE_R_POS_8BIT			(0x0 << 5)
 #define DITHMODE_R_POS_6BIT			(0x1 << 5)
 #define DITHMODE_R_POS_5BIT			(0x2 << 5)
 #define DITHMODE_G_POS_MASK			(0x3 << 3)
-#define DITHMODE_G_POS_SHIFT			(3)
+#define DITHMODE_G_POS_SHIFT			3
 #define DITHMODE_G_POS_8BIT			(0x0 << 3)
 #define DITHMODE_G_POS_6BIT			(0x1 << 3)
 #define DITHMODE_G_POS_5BIT			(0x2 << 3)
 #define DITHMODE_B_POS_MASK			(0x3 << 1)
-#define DITHMODE_B_POS_SHIFT			(1)
+#define DITHMODE_B_POS_SHIFT			1
 #define DITHMODE_B_POS_8BIT			(0x0 << 1)
 #define DITHMODE_B_POS_6BIT			(0x1 << 1)
 #define DITHMODE_B_POS_5BIT			(0x2 << 1)
@@ -403,18 +398,18 @@
 #define WINxMAP(_win)				(0x180 + ((_win) * 4))
 #define WINxMAP_MAP				(1 << 24)
 #define WINxMAP_MAP_COLOUR_MASK			(0xffffff << 0)
-#define WINxMAP_MAP_COLOUR_SHIFT		(0)
-#define WINxMAP_MAP_COLOUR_LIMIT		(0xffffff)
+#define WINxMAP_MAP_COLOUR_SHIFT		0
+#define WINxMAP_MAP_COLOUR_LIMIT		0xffffff
 #define WINxMAP_MAP_COLOUR(_x)			((_x) << 0)
 
 /* Winodw palette control */
-#define WPALCON					(0x1A0)
+#define WPALCON					0x1A0
 #define WPALCON_PAL_UPDATE			(1 << 9)
 #define WPALCON_W4PAL_16BPP_A555		(1 << 8)
 #define WPALCON_W3PAL_16BPP_A555		(1 << 7)
 #define WPALCON_W2PAL_16BPP_A555		(1 << 6)
 #define WPALCON_W1PAL_MASK			(0x7 << 3)
-#define WPALCON_W1PAL_SHIFT			(3)
+#define WPALCON_W1PAL_SHIFT			3
 #define WPALCON_W1PAL_25BPP_A888		(0x0 << 3)
 #define WPALCON_W1PAL_24BPP			(0x1 << 3)
 #define WPALCON_W1PAL_19BPP_A666		(0x2 << 3)
@@ -423,7 +418,7 @@
 #define WPALCON_W1PAL_16BPP_A555		(0x5 << 3)
 #define WPALCON_W1PAL_16BPP_565			(0x6 << 3)
 #define WPALCON_W0PAL_MASK			(0x7 << 0)
-#define WPALCON_W0PAL_SHIFT			(0)
+#define WPALCON_W0PAL_SHIFT			0
 #define WPALCON_W0PAL_25BPP_A888		(0x0 << 0)
 #define WPALCON_W0PAL_24BPP			(0x1 << 0)
 #define WPALCON_W0PAL_19BPP_A666		(0x2 << 0)
@@ -433,7 +428,7 @@
 #define WPALCON_W0PAL_16BPP_565			(0x6 << 0)
 
 /* Blending equation control */
-#define BLENDCON				(0x260)
+#define BLENDCON				0x260
 #define BLENDCON_NEW_MASK			(1 << 0)
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
@@ -460,8 +455,8 @@
 */
 
 /* FIMD Version 8 register offset definitions */
-#define FIMD_V8_VIDTCON0	(0x20010)
-#define FIMD_V8_VIDTCON1	(0x20014)
-#define FIMD_V8_VIDTCON2	(0x20018)
-#define FIMD_V8_VIDTCON3	(0x2001C)
-#define FIMD_V8_VIDCON1		(0x20004)
+#define FIMD_V8_VIDTCON0	0x20010
+#define FIMD_V8_VIDTCON1	0x20014
+#define FIMD_V8_VIDTCON2	0x20018
+#define FIMD_V8_VIDTCON3	0x2001C
+#define FIMD_V8_VIDCON1		0x20004
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 4/5 RESEND] video: s3c-fb: add the bit definitions for CSC EQ709 and EQ601
From: Jingoo Han @ 2013-02-18  5:16 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'
In-Reply-To: <000201ce0d96$9fa550b0$deeff210$%han@samsung.com>

This patch adds the bit definitions for CSC EQ709 and EQ601.
These definitons are used to control the CSC parameter such as
equation 709 and equation 601.

Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 include/video/samsung_fimd.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
index be7b853..2f95d9a 100644
--- a/include/video/samsung_fimd.h
+++ b/include/video/samsung_fimd.h
@@ -176,6 +176,8 @@
 /* WINCONx */
 
 #define WINCON(_win)				(0x20 + ((_win) * 4))
+#define WINCONx_CSCCON_EQ601			(0x0 << 28)
+#define WINCONx_CSCCON_EQ709			(0x1 << 28)
 #define WINCONx_CSCWIDTH_MASK			(0x3 << 26)
 #define WINCONx_CSCWIDTH_SHIFT			26
 #define WINCONx_CSCWIDTH_WIDE			(0x0 << 26)
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 5/5 RESEND] video: s3c-fb: Fix typo in definition of VIDCON1_VSTATUS_FRONTPORCH value
From: Jingoo Han @ 2013-02-18  5:18 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'
In-Reply-To: <000201ce0d96$9fa550b0$deeff210$%han@samsung.com>

From: Tomasz Figa <t.figa@samsung.com>

The correct value for VIDCON1_VSTATUS_FRONTPORCH is 3, not 0.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 include/video/samsung_fimd.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
index 2f95d9a..b039320 100644
--- a/include/video/samsung_fimd.h
+++ b/include/video/samsung_fimd.h
@@ -82,7 +82,7 @@
 #define VIDCON1_VSTATUS_VSYNC			(0x0 << 13)
 #define VIDCON1_VSTATUS_BACKPORCH		(0x1 << 13)
 #define VIDCON1_VSTATUS_ACTIVE			(0x2 << 13)
-#define VIDCON1_VSTATUS_FRONTPORCH		(0x0 << 13)
+#define VIDCON1_VSTATUS_FRONTPORCH		(0x3 << 13)
 #define VIDCON1_VCLK_MASK			(0x3 << 9)
 #define VIDCON1_VCLK_HOLD			(0x0 << 9)
 #define VIDCON1_VCLK_RUN			(0x1 << 9)
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 1/2 RESEND] video: exynos_dp: add missing of_node_put()
From: Jingoo Han @ 2013-02-18  5:24 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'

of_find_node_by_name() returns a node pointer with refcount
incremented, use of_node_put() on it when done.

of_find_node_by_name() will call of_node_put() against
the node pass to from parameter, thus we also need to call
of_node_get(from) before calling of_find_node_by_name().

Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 drivers/video/exynos/exynos_dp_core.c |   19 +++++++++++++------
 1 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index 2ed9776..c7374c0 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -965,10 +965,11 @@ static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
 
 static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
 {
-	struct device_node *dp_phy_node;
+	struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
 	u32 phy_base;
+	int ret = 0;
 
-	dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy");
+	dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
 	if (!dp_phy_node) {
 		dev_err(dp->dev, "could not find dptx-phy node\n");
 		return -ENODEV;
@@ -976,22 +977,28 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
 
 	if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
 		dev_err(dp->dev, "faild to get reg for dptx-phy\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
 				&dp->enable_mask)) {
 		dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	dp->phy_addr = ioremap(phy_base, SZ_4);
 	if (!dp->phy_addr) {
 		dev_err(dp->dev, "failed to ioremap dp-phy\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err;
 	}
 
-	return 0;
+err:
+	of_node_put(dp_phy_node);
+
+	return ret;
 }
 
 static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-- 
1.7.2.5



^ permalink raw reply related

* [PATCH 2/2 RESEND] video: exynos_dp: move disable_irq() to exynos_dp_suspend()
From: Jingoo Han @ 2013-02-18  5:25 UTC (permalink / raw)
  To: 'Andrew Morton'
  Cc: linux-kernel, linux-fbdev, 'Florian Tobias Schandinat',
	'Jingoo Han'
In-Reply-To: <000801ce0d98$2e103fd0$8a30bf70$%han@samsung.com>

From: Ajay Kumar <ajaykumar.rs@samsung.com>

disable_irq() should be moved to exynos_dp_suspend(), because
enable_irq() is called at exynos_dp_resume().

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
---
 drivers/video/exynos/exynos_dp_core.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index c7374c0..de9d4da 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -1124,8 +1124,6 @@ static int exynos_dp_remove(struct platform_device *pdev)
 	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
 	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
-	disable_irq(dp->irq);
-
 	flush_work(&dp->hotplug_work);
 
 	if (pdev->dev.of_node) {
@@ -1148,6 +1146,8 @@ static int exynos_dp_suspend(struct device *dev)
 	struct exynos_dp_platdata *pdata = dev->platform_data;
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
+	disable_irq(dp->irq);
+
 	flush_work(&dp->hotplug_work);
 
 	if (dev->of_node) {
-- 
1.7.2.5



^ permalink raw reply related

* Re: [PATCH 16/33] OMAPDSS: acx565akm panel: handle gpios in panel driver
From: Archit Taneja @ 2013-02-18  7:45 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Aaro Koskinen, linux-omap, linux-fbdev
In-Reply-To: <511C8B16.5060605@ti.com>

On Thursday 14 February 2013 12:28 PM, Tomi Valkeinen wrote:
> On 2013-02-14 08:51, Archit Taneja wrote:
>> On Wednesday 13 February 2013 10:59 PM, Aaro Koskinen wrote:
>>> Hi,
>>>
>>> On Wed, Feb 13, 2013 at 07:52:08PM +0530, Archit Taneja wrote:
>>>> +static struct panel_acx565akm_data *get_panel_data(struct
>>>> omap_dss_device *dssdev)
>>>> +{
>>>> +    return (struct panel_acx565akm_data *) dssdev->data;
>>>> +}
>>>> +
>>>>    static int acx_panel_probe(struct omap_dss_device *dssdev)
>>>>    {
>>>>        int r;
>>>>        struct acx565akm_device *md = &acx_dev;
>>>> +    struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
>>>
>>> Why the get_panel_data function is needed, isn't the cast unnecessary?
>>
>> the 'data' member of omap_dss_device has the type 'void *', we need to
>> cast it to access the panel_acx565akm_data struct pointer.
>
> You don't need an explicit cast to assign a void pointer to a pointer to
> something else (or vice versa, I think).
>
> I remember us having similar constructs in some other panel drivers
> also. I think they are unnecessary also.

I was considering keeping the get_panel_data() funcs in the panel 
drivers though. This way, whenever the way of retrieving platform data 
changes because of DT or CDF or something else, we would just need to 
modify the get_panel_data func.

Archit


^ permalink raw reply

* Re: [PATCH 16/33] OMAPDSS: acx565akm panel: handle gpios in panel driver
From: Tomi Valkeinen @ 2013-02-18  8:11 UTC (permalink / raw)
  To: Archit Taneja; +Cc: Aaro Koskinen, linux-omap, linux-fbdev
In-Reply-To: <5121D941.3060609@ti.com>

[-- Attachment #1: Type: text/plain, Size: 1895 bytes --]

On 2013-02-18 09:33, Archit Taneja wrote:
> On Thursday 14 February 2013 12:28 PM, Tomi Valkeinen wrote:
>> On 2013-02-14 08:51, Archit Taneja wrote:
>>> On Wednesday 13 February 2013 10:59 PM, Aaro Koskinen wrote:
>>>> Hi,
>>>>
>>>> On Wed, Feb 13, 2013 at 07:52:08PM +0530, Archit Taneja wrote:
>>>>> +static struct panel_acx565akm_data *get_panel_data(struct
>>>>> omap_dss_device *dssdev)
>>>>> +{
>>>>> +    return (struct panel_acx565akm_data *) dssdev->data;
>>>>> +}
>>>>> +
>>>>>    static int acx_panel_probe(struct omap_dss_device *dssdev)
>>>>>    {
>>>>>        int r;
>>>>>        struct acx565akm_device *md = &acx_dev;
>>>>> +    struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
>>>>
>>>> Why the get_panel_data function is needed, isn't the cast unnecessary?
>>>
>>> the 'data' member of omap_dss_device has the type 'void *', we need to
>>> cast it to access the panel_acx565akm_data struct pointer.
>>
>> You don't need an explicit cast to assign a void pointer to a pointer to
>> something else (or vice versa, I think).
>>
>> I remember us having similar constructs in some other panel drivers
>> also. I think they are unnecessary also.
> 
> I was considering keeping the get_panel_data() funcs in the panel
> drivers though. This way, whenever the way of retrieving platform data
> changes because of DT or CDF or something else, we would just need to
> modify the get_panel_data func.

I think it's simpler if we manage the fetching of the platform data in
probe one, and just store a struct panel_acx565akm_data or such to the
panel driver's data.

For DT we don't have platform data, but we can create the same platform
data struct from the DT properties.

So the above would become something like:

struct acx565akm_device *md = &acx_dev;
struct panel_acx565akm_data *panel_data = md->pdata;

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* Re: [PATCH v2] fbdev: Add Renesas vdc4 framebuffer driver
From: phil.edworthy @ 2013-02-18  8:14 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1347267372-22949-1-git-send-email-phil.edworthy@renesas.com>

Hi Simon,

> On Fri, Oct 05, 2012 at 05:34:54PM +0100, phil.edworthy@renesas.com 
wrote:
> > Hi,
> > 
> > Any news on this patch?
> 
> Phil, did this patch get merged in the end?
No, I sent a couple of emails to try to get some response but nothing. I 
suspect that it was my fault in that I only realised somewhat later that I 
wasn't signed up to the fbdev ml.

Phil

> > > From: Jingoo Han <jg1.han@samsung.com>
> > > To: "'Phil Edworthy'" <phil.edworthy@renesas.com>, 
> > > Cc: "'Florian Tobias Schandinat'" <FlorianSchandinat@gmx.de>, linux-
> > > fbdev@vger.kernel.org, linux-sh@vger.kernel.org, "'Jingoo Han'" 
> > > <jg1.han@samsung.com>
> > > Date: 11/09/2012 03:31
> > > Subject: Re: [PATCH v2] fbdev: Add Renesas vdc4 framebuffer driver
> > > 
> > > On Monday, September 10, 2012 5:56 PM Phil Edworthy wrote
> > > > 
> > > > The vdc4 display hardware is found on the sh7269 device.
> > > > 
> > > > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> > > 
> > > 
> > > Reviewed-by: Jingoo Han <jg1.han@samsung.com>
> > > 
> > > Best regards,
> > > Jingoo Han
> > > 
> > > 
> > > > ---
> > > > v2:
> > > >  * Use devm_ variants of clk_get, ioremap_nocache, request_irq.
> > > >  * Replace spaces with tabs.
> > > >  * Check ren_vdc4_start return value.
> > > >  * Fix headers used.
> > > > 
> > > >  drivers/video/Kconfig      |   10 +
> > > >  drivers/video/Makefile     |    1 +
> > > >  drivers/video/ren_vdc4fb.c |  641 +++++++++++++++++++++++++++++++
> > > +++++++++++++
> > > >  include/video/ren_vdc4fb.h |   19 ++
> > > >  4 files changed, 671 insertions(+), 0 deletions(-)
> > > >  create mode 100644 drivers/video/ren_vdc4fb.c
> > > >  create mode 100644 include/video/ren_vdc4fb.h
> > > 
> > > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > 


^ permalink raw reply

* Re: [PATCH 16/33] OMAPDSS: acx565akm panel: handle gpios in panel driver
From: Archit Taneja @ 2013-02-18  8:35 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Aaro Koskinen, linux-omap, linux-fbdev
In-Reply-To: <5121E24A.6090502@ti.com>

On Monday 18 February 2013 01:41 PM, Tomi Valkeinen wrote:
> On 2013-02-18 09:33, Archit Taneja wrote:
>> On Thursday 14 February 2013 12:28 PM, Tomi Valkeinen wrote:
>>> On 2013-02-14 08:51, Archit Taneja wrote:
>>>> On Wednesday 13 February 2013 10:59 PM, Aaro Koskinen wrote:
>>>>> Hi,
>>>>>
>>>>> On Wed, Feb 13, 2013 at 07:52:08PM +0530, Archit Taneja wrote:
>>>>>> +static struct panel_acx565akm_data *get_panel_data(struct
>>>>>> omap_dss_device *dssdev)
>>>>>> +{
>>>>>> +    return (struct panel_acx565akm_data *) dssdev->data;
>>>>>> +}
>>>>>> +
>>>>>>     static int acx_panel_probe(struct omap_dss_device *dssdev)
>>>>>>     {
>>>>>>         int r;
>>>>>>         struct acx565akm_device *md = &acx_dev;
>>>>>> +    struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
>>>>>
>>>>> Why the get_panel_data function is needed, isn't the cast unnecessary?
>>>>
>>>> the 'data' member of omap_dss_device has the type 'void *', we need to
>>>> cast it to access the panel_acx565akm_data struct pointer.
>>>
>>> You don't need an explicit cast to assign a void pointer to a pointer to
>>> something else (or vice versa, I think).
>>>
>>> I remember us having similar constructs in some other panel drivers
>>> also. I think they are unnecessary also.
>>
>> I was considering keeping the get_panel_data() funcs in the panel
>> drivers though. This way, whenever the way of retrieving platform data
>> changes because of DT or CDF or something else, we would just need to
>> modify the get_panel_data func.
>
> I think it's simpler if we manage the fetching of the platform data in
> probe one, and just store a struct panel_acx565akm_data or such to the
> panel driver's data.
>
> For DT we don't have platform data, but we can create the same platform
> data struct from the DT properties.
>
> So the above would become something like:
>
> struct acx565akm_device *md = &acx_dev;
> struct panel_acx565akm_data *panel_data = md->pdata;

okay, that seems to be a better way.

Archit


^ permalink raw reply

* Re: [PATCH] OMAPDSS: tpo-td043 panel: fix data passing between SPI/DSS parts
From: Tomi Valkeinen @ 2013-02-18  8:40 UTC (permalink / raw)
  To: Grazvydas Ignotas; +Cc: linux-fbdev, linux-omap, Archit Taneja
In-Reply-To: <1361061792-2350-1-git-send-email-notasas@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]

On 2013-02-17 02:43, Grazvydas Ignotas wrote:
> This driver uses omap_dss_device that it gets from a board file through
> SPI platfrom_data pointer to pass data from SPI to DSS portion of the
> driver by using dev_set_drvdata(). However this trick no longer works,
> as DSS core no longer uses omap_dss_device from a board file to create
> the real device, so use a global pointer to accomplish this instead,
> like other SPI panel drivers do.

Thanks, looks fine to me.

As a side note, I'm working on removing the omap_dss_device stuff, and
after that change this driver can be a plain SPI driver. That should
make things simpler.

 Tomi



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]

^ permalink raw reply

* [PATCH v2] mfd: as3711: add OF support
From: Guennadi Liakhovetski @ 2013-02-18  9:57 UTC (permalink / raw)
  To: linux-kernel
  Cc: Magnus Damm, Simon Horman, devicetree-discuss, Samuel Ortiz,
	Mark Brown, Liam Girdwood, Richard Purdie, Andrew Morton,
	linux-fbdev

Add device-tree bindings to the AS3711 regulator and backlight drivers.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

v2:
1. remove of_device_is_available() - it breaks compilation with CONFIG_OF 
disabled and is redundant anyway - I2C devices are only registered for 
available devoces
2. add parenthesis to eliminate a compiler warning

 Documentation/devicetree/bindings/mfd/as3711.txt |   73 +++++++++++++
 drivers/mfd/as3711.c                             |   27 ++++-
 drivers/regulator/as3711-regulator.c             |   69 ++++++++++++-
 drivers/video/backlight/as3711_bl.c              |  118 +++++++++++++++++++++-
 4 files changed, 279 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/as3711.txt

diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt
new file mode 100644
index 0000000..d98cf18
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/as3711.txt
@@ -0,0 +1,73 @@
+AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
+supplies, a battery charger and an RTC. So far only bindings for the two stepup
+DCDC converters are defined. Other DCDC and LDO supplies are configured, using
+standard regulator properties, they must belong to a sub-node, called
+"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
+configuration should be placed in a subnode, called "backlight."
+
+Compulsory properties:
+- compatible		: must be "ams,as3711"
+- reg			: specifies the I2C address
+
+To use the SU1 converter as a backlight source the following two properties must
+be provided:
+- su1-dev		: framebuffer phandle
+- su1-max-uA		: maximum current
+
+To use the SU2 converter as a backlight source the following two properties must
+be provided:
+- su2-dev		: framebuffer phandle
+- su1-max-uA		: maximum current
+
+Additionally one of these properties must be provided to select the type of
+feedback used:
+- su2-feedback-voltage	: voltage feedback is used
+- su2-feedback-curr1	: CURR1 input used for current feedback
+- su2-feedback-curr2	: CURR2 input used for current feedback
+- su2-feedback-curr3	: CURR3 input used for current feedback
+- su2-feedback-curr-auto: automatic current feedback selection
+
+and one of these to select the over-voltage protection pin
+- su2-fbprot-lx-sd4	: LX_SD4 is used for over-voltage protection
+- su2-fbprot-gpio2	: GPIO2 is used for over-voltage protection
+- su2-fbprot-gpio3	: GPIO3 is used for over-voltage protection
+- su2-fbprot-gpio4	: GPIO4 is used for over-voltage protection
+
+If "su2-feedback-curr-auto" is selected, one or more of the following properties
+have to be specified:
+- su2-auto-curr1	: use CURR1 input for current feedback
+- su2-auto-curr2	: use CURR2 input for current feedback
+- su2-auto-curr3	: use CURR3 input for current feedback
+
+Example:
+
+as3711@40 {
+	compatible = "ams,as3711";
+	reg = <0x40>;
+
+	regulators {
+		sd4 {
+			regulator-name = "1.215V";
+			regulator-min-microvolt = <1215000>;
+			regulator-max-microvolt = <1235000>;
+		};
+		ldo2 {
+			regulator-name = "2.8V CPU";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			regulator-always-on;
+			regulator-boot-on;
+		};
+	};
+
+	backlight {
+		compatible = "ams,as3711-bl";
+		su2-dev = <&lcdc>;
+		su2-max-uA = <36000>;
+		su2-feedback-curr-auto;
+		su2-fbprot-gpio4;
+		su2-auto-curr1;
+		su2-auto-curr2;
+		su2-auto-curr3;
+	};
+};
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c
index e994c96..01e4141 100644
--- a/drivers/mfd/as3711.c
+++ b/drivers/mfd/as3711.c
@@ -112,16 +112,34 @@ static const struct regmap_config as3711_regmap_config = {
 	.cache_type = REGCACHE_RBTREE,
 };
 
+#ifdef CONFIG_OF
+static struct of_device_id as3711_of_match[] = {
+	{.compatible = "ams,as3711",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, as3711_of_match);
+#endif
+
 static int as3711_i2c_probe(struct i2c_client *client,
 			    const struct i2c_device_id *id)
 {
 	struct as3711 *as3711;
-	struct as3711_platform_data *pdata = client->dev.platform_data;
+	struct as3711_platform_data *pdata;
 	unsigned int id1, id2;
 	int ret;
 
-	if (!pdata)
-		dev_dbg(&client->dev, "Platform data not found\n");
+	if (!client->dev.of_node) {
+		pdata = client->dev.platform_data;
+		if (!pdata)
+			dev_dbg(&client->dev, "Platform data not found\n");
+	} else {
+		pdata = devm_kzalloc(&client->dev,
+				     sizeof(*pdata), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "Failed to allocate pdata\n");
+			return -ENOMEM;
+		}
+	}
 
 	as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
 	if (!as3711) {
@@ -193,7 +211,8 @@ static struct i2c_driver as3711_i2c_driver = {
 	.driver = {
 		   .name = "as3711",
 		   .owner = THIS_MODULE,
-		   },
+		   .of_match_table = of_match_ptr(as3711_of_match),
+	},
 	.probe = as3711_i2c_probe,
 	.remove = as3711_i2c_remove,
 	.id_table = as3711_i2c_id,
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index f0ba8c4..cf145fc 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -13,9 +13,11 @@
 #include <linux/init.h>
 #include <linux/mfd/as3711.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/slab.h>
 
 struct as3711_regulator_info {
@@ -276,6 +278,57 @@ static struct as3711_regulator_info as3711_reg_info[] = {
 
 #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
 
+static const char *as3711_regulator_of_names[AS3711_REGULATOR_NUM] = {
+	[AS3711_REGULATOR_SD_1] = "sd1",
+	[AS3711_REGULATOR_SD_2] = "sd2",
+	[AS3711_REGULATOR_SD_3] = "sd3",
+	[AS3711_REGULATOR_SD_4] = "sd4",
+	[AS3711_REGULATOR_LDO_1] = "ldo1",
+	[AS3711_REGULATOR_LDO_2] = "ldo2",
+	[AS3711_REGULATOR_LDO_3] = "ldo3",
+	[AS3711_REGULATOR_LDO_4] = "ldo4",
+	[AS3711_REGULATOR_LDO_5] = "ldo5",
+	[AS3711_REGULATOR_LDO_6] = "ldo6",
+	[AS3711_REGULATOR_LDO_7] = "ldo7",
+	[AS3711_REGULATOR_LDO_8] = "ldo8",
+};
+
+static int as3711_regulator_parse_dt(struct device *dev)
+{
+	struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
+	struct device_node *regulators +		of_find_node_by_name(dev->parent->of_node, "regulators");
+	struct of_regulator_match *matches, *match;
+	const int count = AS3711_REGULATOR_NUM;
+	int ret, i;
+
+	if (!regulators) {
+		dev_err(dev, "regulator node not found\n");
+		return -ENODEV;
+	}
+
+	matches = devm_kzalloc(dev, sizeof(*matches) * count, GFP_KERNEL);
+	if (!matches)
+		return -ENOMEM;
+
+	for (i = 0, match = matches; i < count; i++, match++) {
+		match->name = as3711_regulator_of_names[i];
+		match->driver_data = as3711_reg_info + i;
+	}
+
+	ret = of_regulator_match(dev->parent, regulators, matches, count);
+	if (ret < 0) {
+		dev_err(dev, "Error parsing regulator init data: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0, match = matches; i < count; i++, match++)
+		if (match->of_node)
+			pdata->init_data[i] = match->init_data;
+
+	return 0;
+}
+
 static int as3711_regulator_probe(struct platform_device *pdev)
 {
 	struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -289,8 +342,18 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 	int ret;
 	int id;
 
-	if (!pdata)
-		dev_dbg(&pdev->dev, "No platform data...\n");
+	if (!pdata) {
+		dev_err(&pdev->dev, "No platform data...\n");
+		return -ENODEV;
+	}
+
+	if (pdev->dev.parent->of_node) {
+		ret = as3711_regulator_parse_dt(&pdev->dev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+			return ret;
+		}
+	}
 
 	regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
 			sizeof(struct as3711_regulator), GFP_KERNEL);
@@ -300,7 +363,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
 	}
 
 	for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
-		reg_data = pdata ? pdata->init_data[id] : NULL;
+		reg_data = pdata->init_data[id];
 
 		/* No need to register if there is no regulator data */
 		if (!reg_data)
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index c6bc65d..c78e4cb 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -257,6 +257,109 @@ static int as3711_bl_register(struct platform_device *pdev,
 	return 0;
 }
 
+static int as3711_backlight_parse_dt(struct device *dev)
+{
+	struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
+	struct device_node *bl +		of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+	int ret;
+
+	if (!bl) {
+		dev_dbg(dev, "backlight node not found\n");
+		return -ENODEV;
+	}
+
+	fb = of_parse_phandle(bl, "su1-dev", 0);
+	if (fb) {
+		pdata->su1_fb = fb->full_name;
+
+		ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
+		if (pdata->su1_max_uA <= 0)
+			ret = -EINVAL;
+		if (ret < 0)
+			return ret;
+	}
+
+	fb = of_parse_phandle(bl, "su2-dev", 0);
+	if (fb) {
+		int count = 0;
+
+		pdata->su2_fb = fb->full_name;
+
+		ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
+		if (pdata->su2_max_uA <= 0)
+			ret = -EINVAL;
+		if (ret < 0)
+			return ret;
+
+		if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_VOLTAGE;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr1", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR1;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr2", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR2;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr3", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR3;
+			count++;
+		}
+		if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) {
+			pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
+			count++;
+		}
+		if (count != 1)
+			return -EINVAL;
+
+		count = 0;
+		if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_LX_SD4;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO2;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO3;
+			count++;
+		}
+		if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) {
+			pdata->su2_fbprot = AS3711_SU2_GPIO4;
+			count++;
+		}
+		if (count != 1)
+			return -EINVAL;
+
+		count = 0;
+		if (of_find_property(bl, "su2-auto-curr1", NULL)) {
+			pdata->su2_auto_curr1 = true;
+			count++;
+		}
+		if (of_find_property(bl, "su2-auto-curr2", NULL)) {
+			pdata->su2_auto_curr2 = true;
+			count++;
+		}
+		if (of_find_property(bl, "su2-auto-curr3", NULL)) {
+			pdata->su2_auto_curr3 = true;
+			count++;
+		}
+
+		/*
+		 * At least one su2-auto-curr* must be specified iff
+		 * AS3711_SU2_CURR_AUTO is used
+		 */
+		if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int as3711_backlight_probe(struct platform_device *pdev)
 {
 	struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -266,11 +369,24 @@ static int as3711_backlight_probe(struct platform_device *pdev)
 	unsigned int max_brightness;
 	int ret;
 
-	if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
+	if (!pdata) {
 		dev_err(&pdev->dev, "No platform data, exiting...\n");
 		return -ENODEV;
 	}
 
+	if (pdev->dev.parent->of_node) {
+		ret = as3711_backlight_parse_dt(&pdev->dev);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (!pdata->su1_fb && !pdata->su2_fb) {
+		dev_err(&pdev->dev, "No framebuffer specified\n");
+		return -EINVAL;
+	}
+
 	/*
 	 * Due to possible hardware damage I chose to block all modes,
 	 * unsupported on my hardware. Anyone, wishing to use any of those modes
-- 
1.7.2.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox