Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH 2/4] video: mmp fb support
From: Zhou Zhu @ 2012-08-29 10:14 UTC (permalink / raw)
  To: linux-fbdev

Added fb support for Marvell mmp display subsystem.
This driver is configured using "buffer driver mach info".
With configured name of path, this driver get path using
using exported interface of mmp display driver.
Then this driver get ovly using configured id and operates
on this ovly to show buffers on display devices.

Change-Id: I1a6fb4f89ac933e1364a4511dd3ec1463463d9c8
Signed-off-by: Zhou Zhu <zzhu3@marvell.com>
Signed-off-by: Lisa Du <cldu@marvell.com>
---
 drivers/video/mmp/Kconfig     |    4 +
 drivers/video/mmp/Makefile    |    2 +-
 drivers/video/mmp/fb/Kconfig  |   13 +
 drivers/video/mmp/fb/Makefile |    1 +
 drivers/video/mmp/fb/mmpfb.c  |  663 +++++++++++++++++++++++++++++++++++++++++
 drivers/video/mmp/fb/mmpfb.h  |   51 ++++
 6 files changed, 733 insertions(+), 1 deletions(-)
 create mode 100644 drivers/video/mmp/fb/Kconfig
 create mode 100644 drivers/video/mmp/fb/Makefile
 create mode 100644 drivers/video/mmp/fb/mmpfb.c
 create mode 100644 drivers/video/mmp/fb/mmpfb.h

diff --git a/drivers/video/mmp/Kconfig b/drivers/video/mmp/Kconfig
index 0554336..6a0b056 100644
--- a/drivers/video/mmp/Kconfig
+++ b/drivers/video/mmp/Kconfig
@@ -3,3 +3,7 @@ menuconfig MMP_DISP
         depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
         help
 	  Marvell Display Subsystem support.
+
+if MMP_DISP
+source "drivers/video/mmp/fb/Kconfig"
+endif
diff --git a/drivers/video/mmp/Makefile b/drivers/video/mmp/Makefile
index 820eb10..fdcd833 100644
--- a/drivers/video/mmp/Makefile
+++ b/drivers/video/mmp/Makefile
@@ -1 +1 @@
-obj-y += core.o
+obj-y += core.o fb/
diff --git a/drivers/video/mmp/fb/Kconfig b/drivers/video/mmp/fb/Kconfig
new file mode 100644
index 0000000..9b0141f
--- /dev/null
+++ b/drivers/video/mmp/fb/Kconfig
@@ -0,0 +1,13 @@
+if MMP_DISP
+
+config MMP_FB
+	bool "fb driver for Marvell MMP Display Subsystem"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	default y
+	help
+		fb driver for Marvell MMP Display Subsystem
+
+endif
diff --git a/drivers/video/mmp/fb/Makefile b/drivers/video/mmp/fb/Makefile
new file mode 100644
index 0000000..709fd1f
--- /dev/null
+++ b/drivers/video/mmp/fb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MMP_FB)  += mmpfb.o
diff --git a/drivers/video/mmp/fb/mmpfb.c b/drivers/video/mmp/fb/mmpfb.c
new file mode 100644
index 0000000..83e4a0c
--- /dev/null
+++ b/drivers/video/mmp/fb/mmpfb.c
@@ -0,0 +1,663 @@
+/*
+ * linux/drivers/video/mmp/fb/mmpfb.c
+ * Framebuffer driver for Marvell Display controller.
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <asm/cacheflush.h>
+#include "mmpfb.h"
+
+static int var_to_pixfmt(struct fb_var_screeninfo *var)
+{
+	/*
+	 * Pseudocolor mode?
+	 */
+	if (var->bits_per_pixel = 8)
+		return PIXFMT_PSEUDOCOLOR;
+
+	/*
+	 * Check for YUV422PLANAR.
+	 */
+	if (var->bits_per_pixel = 16 && var->red.length = 8 &&
+			var->green.length = 4 && var->blue.length = 4) {
+		if (var->green.offset >= var->blue.offset)
+			return PIXFMT_YUV422P;
+		else
+			return PIXFMT_YVU422P;
+	}
+
+	/*
+	 * Check for YUV420PLANAR.
+	 */
+	if (var->bits_per_pixel = 12 && var->red.length = 8 &&
+			var->green.length = 2 && var->blue.length = 2) {
+		if (var->green.offset >= var->blue.offset)
+			return PIXFMT_YUV420P;
+		else
+			return PIXFMT_YVU420P;
+	}
+
+	/*
+	 * Check for YUV422PACK.
+	 */
+	if (var->bits_per_pixel = 16 && var->red.length = 16 &&
+			var->green.length = 16 && var->blue.length = 16) {
+		if (var->red.offset = 0)
+			return PIXFMT_YUYV;
+		else if (var->green.offset >= var->blue.offset)
+			return PIXFMT_UYVY;
+		else
+			return PIXFMT_VYUY;
+	}
+
+	/*
+	 * Check for 565/1555.
+	 */
+	if (var->bits_per_pixel = 16 && var->red.length <= 5 &&
+			var->green.length <= 6 && var->blue.length <= 5) {
+		if (var->transp.length = 0) {
+			if (var->red.offset >= var->blue.offset)
+				return PIXFMT_RGB565;
+			else
+				return PIXFMT_BGR565;
+		}
+	}
+
+	/*
+	 * Check for 888/A888.
+	 */
+	if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
+			var->green.length <= 8 && var->blue.length <= 8) {
+		if (var->bits_per_pixel = 24 && var->transp.length = 0) {
+			if (var->red.offset >= var->blue.offset)
+				return PIXFMT_RGB888PACK;
+			else
+				return PIXFMT_BGR888PACK;
+		}
+
+		if (var->bits_per_pixel = 32 && var->transp.offset = 24) {
+			if (var->red.offset >= var->blue.offset)
+				return PIXFMT_RGBA888;
+			else
+				return PIXFMT_BGRA888;
+		} else {
+			if (var->red.offset >= var->blue.offset)
+				return PIXFMT_RGB888UNPACK;
+			else
+				return PIXFMT_BGR888UNPACK;
+		}
+
+		/* fall through */
+	}
+
+	return -EINVAL;
+
+}
+
+static void pixfmt_to_var(struct fb_var_screeninfo *var, int pix_fmt)
+{
+	switch (pix_fmt) {
+	case PIXFMT_RGB565:
+		var->bits_per_pixel = 16;
+		var->red.offset = 11;	var->red.length = 5;
+		var->green.offset = 5;   var->green.length = 6;
+		var->blue.offset = 0;	var->blue.length = 5;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_BGR565:
+		var->bits_per_pixel = 16;
+		var->red.offset = 0;	var->red.length = 5;
+		var->green.offset = 5;	 var->green.length = 6;
+		var->blue.offset = 11;	var->blue.length = 5;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_RGB888UNPACK:
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;	var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;	var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_BGR888UNPACK:
+		var->bits_per_pixel = 32;
+		var->red.offset = 0;	var->red.length = 8;
+		var->green.offset = 8;	 var->green.length = 8;
+		var->blue.offset = 16;	var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_RGBA888:
+		var->bits_per_pixel = 32;
+		var->red.offset = 16;	var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;	var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	case PIXFMT_BGRA888:
+		var->bits_per_pixel = 32;
+		var->red.offset = 0;	var->red.length = 8;
+		var->green.offset = 8;	 var->green.length = 8;
+		var->blue.offset = 16;	var->blue.length = 8;
+		var->transp.offset = 24; var->transp.length = 8;
+		break;
+	case PIXFMT_RGB888PACK:
+		var->bits_per_pixel = 24;
+		var->red.offset = 16;	var->red.length = 8;
+		var->green.offset = 8;   var->green.length = 8;
+		var->blue.offset = 0;	var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_BGR888PACK:
+		var->bits_per_pixel = 24;
+		var->red.offset = 0;	var->red.length = 8;
+		var->green.offset = 8;	 var->green.length = 8;
+		var->blue.offset = 16;	var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_YUV420P:
+		var->bits_per_pixel = 12;
+		var->red.offset = 4;	 var->red.length = 8;
+		var->green.offset = 2;   var->green.length = 2;
+		var->blue.offset = 0;   var->blue.length = 2;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_YVU420P:
+		var->bits_per_pixel = 12;
+		var->red.offset = 4;	 var->red.length = 8;
+		var->green.offset = 0;	 var->green.length = 2;
+		var->blue.offset = 2;	var->blue.length = 2;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_YUV422P:
+		var->bits_per_pixel = 16;
+		var->red.offset = 8;	 var->red.length = 8;
+		var->green.offset = 4;   var->green.length = 4;
+		var->blue.offset = 0;   var->blue.length = 4;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_YVU422P:
+		var->bits_per_pixel = 16;
+		var->red.offset = 8;	 var->red.length = 8;
+		var->green.offset = 0;	 var->green.length = 4;
+		var->blue.offset = 4;	var->blue.length = 4;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_UYVY:
+		var->bits_per_pixel = 16;
+		var->red.offset = 8;	 var->red.length = 16;
+		var->green.offset = 4;   var->green.length = 16;
+		var->blue.offset = 0;   var->blue.length = 16;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_VYUY:
+		var->bits_per_pixel = 16;
+		var->red.offset = 8;	 var->red.length = 16;
+		var->green.offset = 0;	 var->green.length = 16;
+		var->blue.offset = 4;	var->blue.length = 16;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_YUYV:
+		var->bits_per_pixel = 16;
+		var->red.offset = 0;	 var->red.length = 16;
+		var->green.offset = 4;	 var->green.length = 16;
+		var->blue.offset = 8;	var->blue.length = 16;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	case PIXFMT_PSEUDOCOLOR:
+		var->bits_per_pixel = 8;
+		var->red.offset = 0;	 var->red.length = 8;
+		var->green.offset = 0;   var->green.length = 8;
+		var->blue.offset = 0;	var->blue.length = 8;
+		var->transp.offset = 0;  var->transp.length = 0;
+		break;
+	}
+}
+
+/*
+ * fb framework has its limitation:
+ * 1. input color/output color is not seprated
+ * 2. fb_videomode not include output color
+ * so for fb usage, we keep a output format which is not changed
+ *  then it's added for mmpmode
+ */
+static void fbmode_to_mmpmode(struct mmp_mode *mode,
+		struct fb_videomode *videomode, int output_fmt)
+{
+	u64 div_result = 1000000000000ll;
+	mode->name = videomode->name;
+	mode->refresh = videomode->refresh;
+	mode->xres = videomode->xres;
+	mode->yres = videomode->yres;
+
+	do_div(div_result, videomode->pixclock);
+	mode->pixclock_freq = (u32)div_result;
+
+	mode->left_margin = videomode->left_margin;
+	mode->right_margin = videomode->right_margin;
+	mode->upper_margin = videomode->upper_margin;
+	mode->lower_margin = videomode->lower_margin;
+	mode->hsync_len = videomode->hsync_len;
+	mode->vsync_len = videomode->vsync_len;
+	mode->hsync_invert = !!(videomode->sync & FB_SYNC_HOR_HIGH_ACT);
+	mode->vsync_invert = !!(videomode->sync & FB_SYNC_VERT_HIGH_ACT);
+	/* no defined flag in fb, use vmode>>3*/
+	mode->invert_pixclock = !!(videomode->vmode & 8);
+	mode->pix_fmt_out = output_fmt;
+}
+
+static void mmpmode_to_fbmode(struct fb_videomode *videomode,
+		struct mmp_mode *mode)
+{
+	u64 div_result = 1000000000000ll;
+
+	videomode->name = mode->name;
+	videomode->refresh = mode->refresh;
+	videomode->xres = mode->xres;
+	videomode->yres = mode->yres;
+
+	do_div(div_result, mode->pixclock_freq);
+	videomode->pixclock = (u32)div_result;
+
+	videomode->left_margin = mode->left_margin;
+	videomode->right_margin = mode->right_margin;
+	videomode->upper_margin = mode->upper_margin;
+	videomode->lower_margin = mode->lower_margin;
+	videomode->hsync_len = mode->hsync_len;
+	videomode->vsync_len = mode->vsync_len;
+	videomode->sync = (mode->hsync_invert ? FB_SYNC_HOR_HIGH_ACT : 0)
+		| (mode->vsync_invert ? FB_SYNC_VERT_HIGH_ACT : 0);
+	videomode->vmode = mode->invert_pixclock ? 8 : 0;
+}
+
+
+static void *alloc_framebuffer(size_t size, dma_addr_t *dma)
+{
+	int nr, i = 0;
+	struct page **pages;
+	void *start;
+
+	nr = size >> PAGE_SHIFT;
+	start = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+	if (start = NULL)
+		return NULL;
+
+	*dma = virt_to_phys(start);
+	pages = vmalloc(sizeof(struct page *) * nr);
+	if (pages = NULL)
+		return NULL;
+
+	while (i < nr) {
+		pages[i] = phys_to_page(*dma + (i << PAGE_SHIFT));
+		i++;
+	}
+	start = vmap(pages, nr, 0, pgprot_writecombine(pgprot_kernel));
+
+	vfree(pages);
+	return start;
+}
+
+static int mmpfb_check_var(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct mmpfb_info *fbi = info->par;
+
+	if (var->bits_per_pixel = 8)
+		return -EINVAL;
+	/*
+	 * Basic geometry sanity checks.
+	 */
+	if (var->xoffset + var->xres > var->xres_virtual)
+		return -EINVAL;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		return -EINVAL;
+
+	/*
+	 * Check size of framebuffer.
+	 */
+	if (var->xres_virtual * var->yres_virtual *
+			(var->bits_per_pixel >> 3) > fbi->fb_size)
+		return -EINVAL;
+
+	return 0;
+}
+
+static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+{
+	return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static u32 to_rgb(u16 red, u16 green, u16 blue)
+{
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	return (red << 16) | (green << 8) | blue;
+}
+
+static int mmpfb_setcolreg(unsigned int regno, unsigned int red,
+		unsigned int green, unsigned int blue,
+		unsigned int trans, struct fb_info *info)
+{
+	struct mmpfb_info *fbi = info->par;
+	u32 val;
+
+	if (info->fix.visual = FB_VISUAL_TRUECOLOR && regno < 16) {
+		val =  chan_to_field(red,   &info->var.red);
+		val |= chan_to_field(green, &info->var.green);
+		val |= chan_to_field(blue , &info->var.blue);
+		fbi->pseudo_palette[regno] = val;
+	}
+
+	if (info->fix.visual = FB_VISUAL_PSEUDOCOLOR && regno < 256) {
+		val = to_rgb(red, green, blue);
+		/* TODO */
+	}
+
+	return 0;
+}
+
+static int mmpfb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct mmpfb_info *fbi = (struct mmpfb_info *)info->par;
+	struct mmp_addr addr;
+
+	addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
+		* var->bits_per_pixel / 8 + fbi->fb_start_dma;
+	mmp_ovly_set_addr(fbi->ovly, &addr);
+
+	return 0;
+}
+
+static int var_update(struct fb_info *info)
+{
+	struct mmpfb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_videomode *m;
+	int pix_fmt;
+
+	/* set pix_fmt */
+	pix_fmt = var_to_pixfmt(var);
+	if (pix_fmt < 0)
+		return -EINVAL;
+	pixfmt_to_var(var, pix_fmt);
+	fbi->pix_fmt = pix_fmt;
+
+	/* set var according to best video mode*/
+	m = (struct fb_videomode *)fb_match_mode(var, &info->modelist);
+	if (!m) {
+		dev_err(fbi->dev, "set par: no match mode, use best mode\n");
+		m = (struct fb_videomode *)fb_find_best_mode(var,
+				&info->modelist);
+		fb_videomode_to_var(var, m);
+	}
+	memcpy(&fbi->mode, m, sizeof(struct fb_videomode));
+
+	/* fix to 2* yres */
+	var->yres_virtual = var->yres * 2;
+	info->fix.visual = (pix_fmt = PIXFMT_PSEUDOCOLOR) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	info->fix.ypanstep = var->yres;
+	return 0;
+}
+
+static int mmpfb_set_par(struct fb_info *info)
+{
+	struct mmpfb_info *fbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct mmp_addr addr;
+	struct mmp_win win;
+	struct mmp_mode mode;
+
+	int ret = var_update(info);
+	if (ret != 0)
+		return ret;
+
+	/* set window/path according to new videomode */
+	fbmode_to_mmpmode(&mode, &fbi->mode, fbi->output_fmt);
+	mmp_path_set_mode(fbi->path, &mode);
+
+	win.xsrc = win.xdst = fbi->mode.xres;
+	win.ysrc = win.ydst = fbi->mode.yres;
+	win.pix_fmt = fbi->pix_fmt;
+	mmp_ovly_set_win(fbi->ovly, &win);
+
+	/* set address always */
+	addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
+		* var->bits_per_pixel / 8 + fbi->fb_start_dma;
+	mmp_ovly_set_addr(fbi->ovly, &addr);
+
+	return 0;
+}
+
+static void mmpfb_gfx_power(struct mmpfb_info *fbi, int power)
+{
+	mmp_ovly_set_onoff(fbi->ovly, power);
+}
+
+static int mmpfb_gfx_blank(int blank, struct fb_info *info)
+{
+	struct mmpfb_info *fbi = info->par;
+
+	mmpfb_gfx_power(fbi, (blank = FB_BLANK_UNBLANK));
+
+	return 0;
+}
+
+static struct fb_ops mmpfb_gfx_ops = {
+	.owner		= THIS_MODULE,
+	.fb_blank	= mmpfb_gfx_blank,
+	.fb_check_var	= mmpfb_check_var,
+	.fb_set_par	= mmpfb_set_par,
+	.fb_setcolreg	= mmpfb_setcolreg,
+	.fb_pan_display	= mmpfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __devinit mmpfb_probe(struct platform_device *pdev)
+{
+	struct mmp_buffer_driver_mach_info *mi;
+	struct fb_info *info = 0;
+	struct mmpfb_info *fbi = 0;
+	int ret, videomode_num, i;
+	struct fb_videomode *videomodes;
+	struct mmp_mode *mmp_modes;
+	struct mmp_win win;
+	struct mmp_addr addr;
+
+	mi = pdev->dev.platform_data;
+	if (mi = NULL) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	/* initialize fb */
+	info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev);
+	if (info = NULL)
+		return -ENOMEM;
+	fbi = info->par;
+	if (!fbi) {
+		ret = -EINVAL;
+		goto failed;
+	}
+
+	/* init fb */
+	fbi->fb_info = info;
+	platform_set_drvdata(pdev, fbi);
+	fbi->dev = &pdev->dev;
+	fbi->pix_fmt = mi->default_pixfmt;
+	mutex_init(&fbi->access_ok);
+
+	/* get display path by name */
+	fbi->path = mmp_get_path(mi->path_name);
+	if (!fbi->path) {
+		dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name);
+		ret = -EINVAL;
+		goto failed_destroy_mutex;
+	}
+
+	dev_info(fbi->dev, "path %s get\n", fbi->path->name);
+
+	/* get videomodes from path */
+	videomode_num = mmp_path_get_modelist(fbi->path, &mmp_modes);
+	if (!videomode_num) {
+		dev_err(&pdev->dev, "can't get videomode num\n");
+		ret = -EINVAL;
+		goto failed_destroy_mutex;
+	}
+	/* put videomode list to info structure */
+	videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num,
+			GFP_KERNEL);
+	if (!videomodes) {
+		dev_err(&pdev->dev, "can't malloc video modes\n");
+		ret = -ENOMEM;
+		goto failed_destroy_mutex;
+	}
+	for (i = 0; i < videomode_num; i++)
+		mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]);
+	fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist);
+
+	/* set videomode[0] as default mode */
+	memcpy(&fbi->mode, &videomodes[0], sizeof(struct fb_videomode));
+	fbi->output_fmt = mmp_modes[0].pix_fmt_out;
+	fb_videomode_to_var(&info->var, &fbi->mode);
+	mmp_path_set_mode(fbi->path, &mmp_modes[0]);
+	/* fix to 2* yres */
+	info->var.yres_virtual = info->var.yres * 2;
+	pixfmt_to_var(&info->var, fbi->pix_fmt);
+
+	/* Allocate framebuffer memory: size = modes xy *4 .*/
+	fbi->fb_size = PAGE_ALIGN(info->var.xres_virtual *
+		info->var.yres_virtual * info->var.bits_per_pixel / 8);
+	fbi->fb_start = alloc_framebuffer(fbi->fb_size + PAGE_SIZE,
+				&fbi->fb_start_dma);
+
+	if (fbi->fb_start = NULL) {
+		dev_err(&pdev->dev, "can't alloc framebuffer\n");
+		ret = -ENOMEM;
+		goto failed_destroy_mutex;
+	}
+	memset(fbi->fb_start, 0, fbi->fb_size);
+
+	dev_info(fbi->dev, "fb %dk allocated\n", fbi->fb_size/1024);
+
+	/* get ovly */
+	fbi->ovly = mmp_path_get_ovly(fbi->path, mi->ovly_id);
+	if (!fbi->ovly) {
+		ret = -EINVAL;
+		goto failed_destroy_mutex;
+	}
+	/* set fetch used */
+	mmp_ovly_set_fetch(fbi->ovly, mi->dmafetch_id);
+
+	/* set win */
+	memset(&win, 0, sizeof(win));
+	win.pix_fmt = fbi->pix_fmt;
+	win.xsrc = win.xdst = fbi->mode.xres;
+	win.ysrc = win.ydst = fbi->mode.yres;
+	mmp_ovly_set_win(fbi->ovly, &win);
+	/* set addr */
+	memset(&addr, 0, sizeof(addr));
+	addr.phys[0] = fbi->fb_start_dma;
+	mmp_ovly_set_addr(fbi->ovly, &addr);
+	mmp_ovly_set_onoff(fbi->ovly, 1);
+
+	/* Initialise static fb parameters.*/
+	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
+		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+	info->node = -1;
+	strcpy(info->fix.id, mi->name);
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = info->var.yres;
+	info->fix.ywrapstep = 0;
+	info->fix.accel = FB_ACCEL_NONE;
+	info->fix.smem_start = fbi->fb_start_dma;
+	info->fix.smem_len = fbi->fb_size;
+	info->fix.visual = (fbi->pix_fmt = PIXFMT_PSEUDOCOLOR) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	info->fix.line_length = info->var.xres_virtual *
+		info->var.bits_per_pixel / 8;
+	info->fbops = &mmpfb_gfx_ops;
+	info->pseudo_palette = fbi->pseudo_palette;
+	info->screen_base = fbi->fb_start;
+	info->screen_size = fbi->fb_size;
+
+	/* For FB framework: Allocate color map and Register framebuffer*/
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		ret = -ENOMEM;
+		goto failed_free_buff;
+	}
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register fb: %d\n", ret);
+		ret = -ENXIO;
+		goto failed_free_cmap;
+	}
+
+	dev_info(fbi->dev, "loaded to /dev/fb%d <%s>.\n",
+		info->node, info->fix.id);
+
+#ifdef CONFIG_ANDROID
+	if (fbi->fb_start) {
+		fb_prepare_logo(info, 0);
+		fb_show_logo(info, 0);
+	}
+#endif
+
+	return 0;
+
+failed_free_cmap:
+	fb_dealloc_cmap(&info->cmap);
+failed_free_buff:
+	vfree(fbi->fb_start);
+	kfree(videomodes);
+failed_destroy_mutex:
+	mutex_destroy(&fbi->access_ok);
+failed:
+	dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
+	platform_set_drvdata(pdev, NULL);
+
+	framebuffer_release(info);
+
+	return ret;
+}
+
+static struct platform_driver mmpfb_driver = {
+	.driver		= {
+		.name	= "mmp-fb",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= mmpfb_probe,
+};
+
+static int __devinit mmpfb_init(void)
+{
+	return platform_driver_register(&mmpfb_driver);
+}
+module_init(mmpfb_init);
+
+MODULE_AUTHOR("Zhou Zhu <zhou.zhu@marvell.com>");
+MODULE_DESCRIPTION("Framebuffer driver for Marvell displays");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mmp/fb/mmpfb.h b/drivers/video/mmp/fb/mmpfb.h
new file mode 100644
index 0000000..7f8a71d
--- /dev/null
+++ b/drivers/video/mmp/fb/mmpfb.h
@@ -0,0 +1,51 @@
+/*
+ * linux/drivers/video/mmp/fb/mmpfb.h
+ * Framebuffer driver for Marvell Display controller.
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _MMP_FB_H_
+#define _MMP_FB_H_
+
+#include <video/mmp_disp.h>
+#include <linux/fb.h>
+
+/* LCD controller private state. */
+struct mmpfb_info {
+	struct device	*dev;
+	int	id;
+
+	struct fb_info	*fb_info;
+	/* basicaly videomode is for output */
+	struct fb_videomode	mode;
+	int	pix_fmt;
+
+	void	*fb_start;
+	int	fb_size;
+	dma_addr_t	fb_start_dma;
+
+	struct mmp_ovly	*ovly;
+	struct mmp_path	*path;
+
+	struct mutex	access_ok;
+
+	unsigned int		pseudo_palette[16];
+	int output_fmt;
+};
+#endif /* _MMP_FB_H_ */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/4] video: mmp display subsystem
From: Zhou Zhu @ 2012-08-29 10:04 UTC (permalink / raw)
  To: linux-fbdev

Added mmp display subsystem to support Marvell MMP display controllers.

This subsystem contains 4 parts:
--fb folder
--core.c
--hw folder
--panel folder

1. fb folder contains implementation of fb.
fb get path and ovly from common interface and operates on these structures.

2. core.c provides common interface for a hardware abstraction.
Major parts of this interface are:
a) Path: path is a output device connected to a panel or HDMI TV.
Main operations of the path is set/get timing/output color.
fb operates output device through path structure.
b) Ovly: Ovly is a buffer shown on the path.
Ovly describes frame buffer and its source/destination size, offset, input
color, buffer address, z-order, and so on.
Each fb device maps to one ovly.

3. hw folder contains implementation of hardware operations defined by core.c.
It registers paths for fb use.

4. panel folder contains implementation of panels.
It's connected to path. Panel drivers would also regiester panels and linked
to path when probe.

Change-Id: I830e34af9aad3196c2db021b4fb90ceeafbf73d2
Signed-off-by: Zhou Zhu <zzhu3@marvell.com>
Signed-off-by: Lisa Du <cldu@marvell.com>
---
 drivers/video/Kconfig      |    1 +
 drivers/video/Makefile     |    1 +
 drivers/video/mmp/Kconfig  |    5 +
 drivers/video/mmp/Makefile |    1 +
 drivers/video/mmp/core.c   |  217 +++++++++++++++++++++++++
 include/video/mmp_disp.h   |  381 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 606 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/mmp/Kconfig
 create mode 100644 drivers/video/mmp/Makefile
 create mode 100644 drivers/video/mmp/core.c
 create mode 100644 include/video/mmp_disp.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0217f74..b71a5c9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2447,6 +2447,7 @@ config FB_PUV3_UNIGFX
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 source "drivers/video/exynos/Kconfig"
+source "drivers/video/mmp/Kconfig"
 source "drivers/video/backlight/Kconfig"
 
 if VT
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..6b0ae31 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_FB_ASILIANT)	  += asiliantfb.o
 obj-$(CONFIG_FB_PXA)		  += pxafb.o
 obj-$(CONFIG_FB_PXA168)		  += pxa168fb.o
 obj-$(CONFIG_PXA3XX_GCU)	  += pxa3xx-gcu.o
+obj-$(CONFIG_MMP_DISP)           += mmp/
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_TMIO)		  += tmiofb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
diff --git a/drivers/video/mmp/Kconfig b/drivers/video/mmp/Kconfig
new file mode 100644
index 0000000..0554336
--- /dev/null
+++ b/drivers/video/mmp/Kconfig
@@ -0,0 +1,5 @@
+menuconfig MMP_DISP
+        tristate "Marvell MMP Display Subsystem support"
+        depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+        help
+	  Marvell Display Subsystem support.
diff --git a/drivers/video/mmp/Makefile b/drivers/video/mmp/Makefile
new file mode 100644
index 0000000..820eb10
--- /dev/null
+++ b/drivers/video/mmp/Makefile
@@ -0,0 +1 @@
+obj-y += core.o
diff --git a/drivers/video/mmp/core.c b/drivers/video/mmp/core.c
new file mode 100644
index 0000000..b2e7433
--- /dev/null
+++ b/drivers/video/mmp/core.c
@@ -0,0 +1,217 @@
+/*
+ * linux/drivers/video/mmp/common.c
+ * This driver is a common framework for Marvell Display Controller
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <video/mmp_disp.h>
+
+static struct mmp_ovly *path_get_ovly(struct mmp_path *path,
+		int ovly_id)
+{
+	if (path && ovly_id < path->ovly_num)
+		return &path->ovlys[ovly_id];
+	return 0;
+}
+
+static int path_check_status(struct mmp_path *path)
+{
+	int i;
+	for (i = 0; i < path->ovly_num; i++)
+		if (path->ovlys[i].status)
+			return 1;
+
+	return 0;
+}
+
+/*
+ * Get modelist write pointer of modelist.
+ * It also returns modelist number
+ * this function fetches modelist from phy/panel:
+ *   for HDMI/parallel or dsi to hdmi cases, get from phy
+ *   or get from panel
+ */
+static int path_get_modelist(struct mmp_path *path,
+		struct mmp_mode **modelist)
+{
+	BUG_ON(!path || !modelist);
+
+	if (path->panel && path->panel->get_modelist)
+		return path->panel->get_modelist(path->panel, modelist);
+
+	return 0;
+}
+
+#define list_find(_item, _list, _field, _name) \
+	do {\
+		int found = 0;\
+		list_for_each_entry(_item, &_list, node) {\
+			dev_dbg(_item->dev, "checking %s, target %s",\
+					_item->_field, _name);\
+			if (strcmp(_name, _item->_field) = 0) {\
+				found = 1;\
+				break;\
+			} \
+		} \
+		if (!found)\
+			_item = NULL;\
+	} while (0);
+
+/*
+ * panel list is used to pair panel/path when path/panel registered
+ * path list is used for both buffer driver and platdriver
+ * plat driver do path register/unregister
+ * panel driver do panel register/unregister
+ * buffer driver get registered path
+ */
+static LIST_HEAD(panel_list);
+static LIST_HEAD(path_list);
+static DEFINE_MUTEX(disp_lock);
+
+int mmp_register_panel(struct mmp_panel *panel)
+{
+	struct mmp_path *path;
+
+	mutex_lock(&disp_lock);
+
+	/* add */
+	list_add_tail(&panel->node, &panel_list);
+
+	/* try to register to path */
+	list_find(path, path_list, name, panel->plat_path_name);
+	if (path) {
+		dev_info(panel->dev, "register to path %s\n",
+				panel->plat_path_name);
+		path->panel = panel;
+	}
+
+	mutex_unlock(&disp_lock);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(mmp_register_panel);
+
+void mmp_unregister_panel(struct mmp_panel *panel)
+{
+	mutex_lock(&disp_lock);
+	list_del(&panel->node);
+	mutex_unlock(&disp_lock);
+}
+EXPORT_SYMBOL_GPL(mmp_unregister_panel);
+
+struct mmp_path *mmp_get_path(const char *name)
+{
+	struct mmp_path *path;
+
+	mutex_lock(&disp_lock);
+	list_find(path, path_list, name, name);
+	mutex_unlock(&disp_lock);
+
+	return path;
+}
+EXPORT_SYMBOL_GPL(mmp_get_path);
+
+struct mmp_path *mmp_register_path(struct mmp_path_info *info)
+{
+	int i, size;
+	struct mmp_path *path = NULL;
+	struct mmp_panel *panel;
+
+	size = sizeof(struct mmp_path)
+		+ sizeof(struct mmp_ovly) * info->ovly_num;
+	path = kzalloc(size, GFP_KERNEL);
+	if (!path)
+		goto failed;
+
+	/* path set */
+	path->ovlys = (void *)path + sizeof(struct mmp_path);
+	mutex_init(&path->access_ok);
+	path->dev = info->dev;
+	path->id = info->id;
+	path->name = info->name;
+	path->output_type = info->output_type;
+	path->ovly_num = info->ovly_num;
+	path->plat_data = info->plat_data;
+	path->ops.set_mode = info->set_mode;
+
+	mutex_lock(&disp_lock);
+	/* get panel */
+	list_find(panel, panel_list, plat_path_name, info->name);
+	if (panel) {
+		dev_info(path->dev, "get panel %s\n", panel->name);
+		path->panel = panel;
+	}
+
+	dev_info(path->dev, "register %s, ovly_num %d\n",
+			path->name, path->ovly_num);
+
+	/* default op set: if already set by driver, never cover it */
+	if (!path->ops.check_status)
+		path->ops.check_status = path_check_status;
+	if (!path->ops.get_ovly)
+		path->ops.get_ovly = path_get_ovly;
+	if (!path->ops.get_modelist)
+		path->ops.get_modelist = path_get_modelist;
+
+	/* step3: init ovlys */
+	for (i = 0; i < path->ovly_num; i++) {
+		path->ovlys[i].path = path;
+		path->ovlys[i].id = i;
+		mutex_init(&path->ovlys[i].access_ok);
+		path->ovlys[i].ops = info->ovly_ops;
+	}
+
+	/* add to pathlist */
+	list_add_tail(&path->node, &path_list);
+
+	mutex_unlock(&disp_lock);
+	return path;
+
+failed:
+	kfree(path);
+	mutex_unlock(&disp_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mmp_register_path);
+
+void mmp_unregister_path(struct mmp_path *path)
+{
+	int i;
+
+	if (!path)
+		return;
+
+	mutex_lock(&disp_lock);
+	/* del from pathlist */
+	list_del(&path->node);
+
+	/* deinit ovlys */
+	for (i = 0; i < path->ovly_num; i++)
+		mutex_destroy(&path->ovlys[i].access_ok);
+
+	mutex_destroy(&path->access_ok);
+
+	kfree(path);
+	mutex_unlock(&disp_lock);
+
+	dev_info(path->dev, "de-register %s\n", path->name);
+}
+EXPORT_SYMBOL_GPL(mmp_unregister_path);
diff --git a/include/video/mmp_disp.h b/include/video/mmp_disp.h
new file mode 100644
index 0000000..e7318f9
--- /dev/null
+++ b/include/video/mmp_disp.h
@@ -0,0 +1,381 @@
+/*
+ * linux/include/video/mmp_disp.h
+ * Header file for Marvell MMP Display Controller
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _MMP_DISP_H_
+#define _MMP_DISP_H_
+#include <linux/kthread.h>
+
+enum {
+	PIXFMT_UYVY = 0,
+	PIXFMT_VYUY,
+	PIXFMT_YUYV,
+	PIXFMT_YUV422P,
+	PIXFMT_YVU422P,
+	PIXFMT_YUV420P,
+	PIXFMT_YVU420P,
+	PIXFMT_RGB565 = 0x100,
+	PIXFMT_BGR565,
+	PIXFMT_RGB1555,
+	PIXFMT_BGR1555,
+	PIXFMT_RGB888PACK,
+	PIXFMT_BGR888PACK,
+	PIXFMT_RGB888UNPACK,
+	PIXFMT_BGR888UNPACK,
+	PIXFMT_RGBA888,
+	PIXFMT_BGRA888,
+	PIXFMT_RGB666, /* for output usage */
+	PIXFMT_PSEUDOCOLOR = 0x200,
+};
+
+static inline int pixfmt_to_stride(int pix_fmt)
+{
+	switch (pix_fmt) {
+	case PIXFMT_RGB565:
+	case PIXFMT_BGR565:
+	case PIXFMT_RGB1555:
+	case PIXFMT_BGR1555:
+	case PIXFMT_UYVY:
+	case PIXFMT_VYUY:
+	case PIXFMT_YUYV:
+		return 2;
+	case PIXFMT_RGB888UNPACK:
+	case PIXFMT_BGR888UNPACK:
+	case PIXFMT_RGBA888:
+	case PIXFMT_BGRA888:
+		return 4;
+	case PIXFMT_RGB888PACK:
+	case PIXFMT_BGR888PACK:
+		return 3;
+	case PIXFMT_YUV422P:
+	case PIXFMT_YVU422P:
+	case PIXFMT_YUV420P:
+	case PIXFMT_YVU420P:
+	case PIXFMT_PSEUDOCOLOR:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/* parameters used by path/ovly */
+/* ovly related para: win/addr */
+struct mmp_win {
+	/* position/size of window */
+	u16	xsrc;
+	u16	ysrc;
+	u16	xdst;
+	u16	ydst;
+	u16	xpos;
+	u16	ypos;
+	u16	left_crop;
+	u16	right_crop;
+	u16	up_crop;
+	u16	bottom_crop;
+	int	pix_fmt;
+};
+
+struct mmp_addr {
+	/* phys address */
+	u32	phys[6];
+};
+
+/* path related para: mode */
+struct mmp_mode {
+	const char *name;
+	u32 refresh;
+	u32 xres;
+	u32 yres;
+	u32 left_margin;
+	u32 right_margin;
+	u32 upper_margin;
+	u32 lower_margin;
+	u32 hsync_len;
+	u32 vsync_len;
+	u32 hsync_invert;
+	u32 vsync_invert;
+	u32 invert_pixclock;
+	u32 pixclock_freq;
+	int pix_fmt_out;
+};
+
+/* main structures */
+struct mmp_path;
+struct mmp_ovly;
+struct mmp_panel;
+
+
+/* status types */
+enum {
+	mmp_OFF = 0,
+	mmp_ON,
+};
+
+static inline const char *stat_name(int stat)
+{
+	switch (stat) {
+	case mmp_OFF:
+		return "OFF";
+	case mmp_ON:
+		return "ON";
+	default:
+		return "UNKNOWNSTAT";
+	}
+}
+
+struct mmp_ovly_ops {
+	/* should be provided by driver */
+	void (*set_fetch)(struct mmp_ovly *ovly, int fetch_id);
+	void (*set_onoff)(struct mmp_ovly *ovly, int status);
+	void (*set_win)(struct mmp_ovly *ovly, struct mmp_win *win);
+	int (*set_addr)(struct mmp_ovly *ovly, struct mmp_addr *addr);
+};
+
+/* ovly describes a z-order indexed slot in each path. */
+struct mmp_ovly {
+	int id;
+	const char *name;
+	struct mmp_path *path;
+
+	/* ovly info: private data */
+	int dmafetch_id;
+	struct mmp_addr addr;
+	struct mmp_win win;
+
+	/* state */
+	int open_count;
+	int status;
+	struct mutex access_ok;
+
+	struct mmp_ovly_ops *ops;
+};
+
+/* panel type */
+enum {
+	PANELTYPE_Active = 0,
+	PANELTYPE_Smart,
+	PANELTYPE_TV,
+	PANELTYPE_DSI_CMD,
+	PANELTYPE_DSI_VIDEO,
+};
+
+enum {
+	PANEL_CMDS_SPI,
+	PANEL_CMDS_DSI,
+};
+
+/* commands for panel: commands and sleep time in ms */
+struct mmp_panel_cmds {
+	u16 *cmds;
+	int cmds_num;
+	int sleep;
+};
+
+struct mmp_spi_cfg {
+	u32 clk_cnt;
+	u32 rx_bits;
+	u32 tx_bits;
+	u32 wire_num;
+};
+
+struct mmp_panel_cmd_sets {
+	int type;
+	struct mmp_panel_cmds *on_cmds;
+	int on_cmds_num;
+	struct mmp_panel_cmds *off_cmds;
+	int off_cmds_num;
+	void  *config;
+};
+
+struct mmp_panel {
+	/* use node to register to list */
+	struct list_head node;
+	const char *name;
+	/* path name used to connect to proper path configed */
+	const char *plat_path_name;
+	struct device *dev;
+	int panel_type;
+	int (*get_modelist)(struct mmp_panel *panel,
+			struct mmp_mode **modelist);
+	void (*set_mode)(struct mmp_panel *panel,
+			struct mmp_mode *mode);
+	void (*plat_set_onoff)(int status);
+	struct mmp_panel_cmd_sets *cmd_set;
+	/* todo: add query */
+};
+
+struct mmp_path_ops {
+	int (*check_status)(struct mmp_path *path);
+	struct mmp_ovly *(*get_ovly)(struct mmp_path *path,
+			int ovly_id);
+	int (*get_modelist)(struct mmp_path *path,
+			struct mmp_mode **modelist);
+
+	/* follow ops should be provided by driver */
+	void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode);
+	void (*set_onoff)(struct mmp_path *path, int status);
+	/* todo: add query */
+};
+
+/* path output types */
+enum {
+	PATH_OUT_PARALLEL,
+	PATH_OUT_DSI,
+	PATH_OUT_HDMI,
+};
+
+/* path is main part of mmp-disp */
+struct mmp_path {
+	/* use node to register to list */
+	struct list_head node;
+
+	/* init data */
+	struct device *dev;
+
+	int id;
+	const char *name;
+	int output_type;
+	struct mmp_panel *panel;
+	void *plat_data;
+
+	/* dynamic use */
+	struct mmp_mode mode;
+
+	/* state */
+	int open_count;
+	int status;
+	struct mutex access_ok;
+
+	struct mmp_path_ops ops;
+
+	/* layers */
+	int ovly_num;
+	struct mmp_ovly *ovlys;
+};
+
+extern struct mmp_path *mmp_get_path(const char *name);
+static inline void mmp_path_set_mode(struct mmp_path *path,
+		struct mmp_mode *mode)
+{
+	if (path)
+		path->ops.set_mode(path, mode);
+}
+static inline void mmp_path_set_onoff(struct mmp_path *path, int status)
+{
+	if (path)
+		path->ops.set_onoff(path, status);
+}
+static inline int mmp_path_get_modelist(struct mmp_path *path,
+		struct mmp_mode **modelist)
+{
+	if (path)
+		return path->ops.get_modelist(path, modelist);
+	return 0;
+}
+static inline struct mmp_ovly *mmp_path_get_ovly(
+		struct mmp_path *path, int ovly_id)
+{
+	if (path)
+		return path->ops.get_ovly(path, ovly_id);
+	return NULL;
+}
+static inline void mmp_ovly_set_fetch(struct mmp_ovly *ovly,
+		int fetch_id)
+{
+	if (ovly)
+		ovly->ops->set_fetch(ovly, fetch_id);
+}
+static inline void mmp_ovly_set_onoff(struct mmp_ovly *ovly, int status)
+{
+	if (ovly)
+		ovly->ops->set_onoff(ovly, status);
+}
+static inline void mmp_ovly_set_win(struct mmp_ovly *ovly,
+		struct mmp_win *win)
+{
+	if (ovly)
+		ovly->ops->set_win(ovly, win);
+}
+static inline int mmp_ovly_set_addr(struct mmp_ovly *ovly,
+		struct mmp_addr *addr)
+{
+	if (ovly)
+		return ovly->ops->set_addr(ovly, addr);
+	return 0;
+}
+
+/*
+ * driver data is set from each detailed ctrl driver for path usage
+ * it defined a common interface that plat driver need to implement
+ */
+struct mmp_path_info {
+	/* driver data, set when registed*/
+	const char *name;
+	struct device *dev;
+	int id;
+	int output_type;
+	int ovly_num;
+	void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode);
+	void (*set_onoff)(struct mmp_path *path, int status);
+	struct mmp_ovly_ops *ovly_ops;
+	void *plat_data;
+};
+
+extern struct mmp_path *mmp_register_path(
+		struct mmp_path_info *info);
+extern void mmp_unregister_path(struct mmp_path *path);
+extern int mmp_register_panel(struct mmp_panel *panel);
+extern void mmp_unregister_panel(struct mmp_panel *panel);
+
+/* defintions for platform data */
+/* interface for buffer driver */
+struct mmp_buffer_driver_mach_info {
+	const char	*name;
+	const char	*path_name;
+	int	ovly_id;
+	int	dmafetch_id;
+	int	default_pixfmt;
+	u32	irq_mask;
+};
+
+/* interface for controllers driver */
+struct mmp_mach_path_config {
+	const char *name;
+	int ovly_num;
+	int output_type;
+	u32 path_config;
+	u32 link_config;
+};
+
+struct mmp_mach_plat_info {
+	const char *name;
+	const char *clk_name;
+	int path_num;
+	struct mmp_mach_path_config *paths;
+};
+
+/* interface for panel drivers */
+struct mmp_mach_panel_info {
+	const char *name;
+	void (*plat_set_onoff)(int status);
+	const char *plat_path_name;
+};
+#endif	/* _MMP_DISP_H_ */
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH 00/19] SH Mobile LCDC panel cleanup (including board code)
From: Simon Horman @ 2012-08-29  6:07 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1345122054-16013-1-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Laurent,

On Mon, Aug 27, 2012 at 05:35:46PM +0200, Laurent Pinchart wrote:
> Hi Simon,
> 
> On Monday 27 August 2012 17:54:52 Simon Horman wrote:
> > On Thu, Aug 16, 2012 at 03:00:35PM +0200, Laurent Pinchart wrote:
> > > Hi everybody,
> > > 
> > > As part of a general panel API implementation (more on that a bit later),
> > > I've cleaned up panel support in the LCDC driver and in the related board
> > > code. The result is 19 patches independent of the generic panel API that
> > > I would like to get reviewed by the respective board maintainers.
> > 
> > Hi Paul,
> > 
> > I'm happy for you to take all of this, including the mach-shmobile
> > portions through your tree if that works for you.
> 
> I usually push the LCDC patches through the fbdev tree. I'm fine with both 
> options though.

I'm happy for you to handle things in your normal way.

I guess that means that once the LCDC changes are in the fbdev tree
Paul should take the linux-sh changes and I should take the shmobile
changes, is that correct?

> 
> > > Laurent Pinchart (19):
> > >   fbdev: sh_mobile_lcdc: Get display dimensions from the channel
> > >     structure
> > >   fbdev: sh_mobile_lcdc: Rename mode argument to modes
> > >   fbdev: sh_mobile_lcdc: Remove priv argument from channel and overlay
> > >     init
> > >   ARM: mach-shmobile: ag5evm: Add LCDC tx_dev field to platform data
> > >   fbdev: sh_mipi_dsi: Add channel field to platform data
> > >   ARM: mach-shmobile: Initiliaze the new sh_mipi_dsi_info channel field
> > >   fbdev: sh_mipi_dsi: Use the sh_mipi_dsi_info channel field
> > >   fbdev: sh_mipi_dsi: Use the LCDC entity default mode
> > >   fbdev: sh_mipi_dsi: Remove last reference to LCDC platform data
> > >   ARM: mach-shmobile: Remove the unused sh_mipi_dsi_info lcd_chan field
> > >   fbdev: sh_mipi_dsi: Remove the unused sh_mipi_dsi_info lcd_chan field
> > >   fbdev: sh_mobile_lcdc: Store the backlight brightness internally
> > >   ARM: mach-shmobile: mackerel: Removed unused get_brightness callback
> > >   sh: ap325rxa: Remove unused get_brightness LCDC callback
> > >   sh: ecovec24: Remove unused get_brightness LCDC callback
> > >   fbdev: sh_mobile_lcdc: Remove unused get_brightness pdata callback
> > >   ARM: mach-shmobile: ag5evm: Use the backlight API for brightness
> > >     control
> > >   sh: kfr2r09: Use the backlight API for brightness control
> > >   fbdev: sh_mobile_lcdc: Make sh_mobile_lcdc_sys_bus_ops static
> > >  
> > >  arch/arm/mach-shmobile/board-ag5evm.c       |  198 +++++++++++-----------
> > >  arch/arm/mach-shmobile/board-ap4evb.c       |    4 +-
> > >  arch/arm/mach-shmobile/board-mackerel.c     |    6 -
> > >  arch/sh/boards/mach-ap325rxa/setup.c        |    6 -
> > >  arch/sh/boards/mach-ecovec24/setup.c        |    6 -
> > >  arch/sh/boards/mach-kfr2r09/lcd_wqvga.c     |   16 +--
> > >  arch/sh/boards/mach-kfr2r09/setup.c         |    7 +-
> > >  arch/sh/include/mach-kfr2r09/mach/kfr2r09.h |    6 +-
> > >  drivers/video/sh_mipi_dsi.c                 |   69 ++++------
> > >  drivers/video/sh_mobile_lcdcfb.c            |   54 ++++----
> > >  drivers/video/sh_mobile_lcdcfb.h            |    1 +
> > >  include/video/sh_mipi_dsi.h                 |    4 +-
> > >  include/video/sh_mobile_lcdc.h              |    1 -
> > >  13 files changed, 172 insertions(+), 206 deletions(-)
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> --
> 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

* [PATCH 6/9] ARM: OMAP1: move omap1_bl pdata out of arch/arm/*
From: Igor Grinberg @ 2012-08-28 23:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1346195937-6383-1-git-send-email-grinberg@compulab.co.il>

omap1 backlight platform data resides inside plat/board.h while it
should be inside include/linux/...
Move the omap1 backlight platform data to
include/linux/platform_data/.

Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: linux-fbdev@vger.kernel.org
Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
---
 arch/arm/mach-omap1/board-osk.c         |    1 +
 arch/arm/mach-omap1/board-palmte.c      |    1 +
 arch/arm/mach-omap1/board-palmtt.c      |    1 +
 arch/arm/mach-omap1/board-palmz71.c     |    1 +
 arch/arm/plat-omap/include/plat/board.h |    7 -------
 drivers/video/backlight/omap1_bl.c      |    2 +-
 include/linux/platform_data/omap1_bl.h  |   11 +++++++++++
 7 files changed, 16 insertions(+), 8 deletions(-)
 create mode 100644 include/linux/platform_data/omap1_bl.h

diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 8784705..569b687 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -39,6 +39,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/i2c/tps65010.h>
+#include <linux/platform_data/omap1_bl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
index 26bcb9d..7bf00ba 100644
--- a/arch/arm/mach-omap1/board-palmte.c
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/apm-emulation.h>
 #include <linux/omapfb.h>
+#include <linux/platform_data/omap1_bl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c
index 4d09944..2cce505 100644
--- a/arch/arm/mach-omap1/board-palmtt.c
+++ b/arch/arm/mach-omap1/board-palmtt.c
@@ -27,6 +27,7 @@
 #include <linux/omapfb.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/platform_data/omap1_bl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index 3559803..45ab9f0 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -30,6 +30,7 @@
 #include <linux/omapfb.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
+#include <linux/platform_data/omap1_bl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index 5938c72..d0bc46e 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -19,13 +19,6 @@ struct omap_lcd_config {
 	u8   data_lines;
 };
 
-struct device;
-struct fb_info;
-struct omap_backlight_config {
-	int default_intensity;
-	int (*set_power)(struct device *dev, int state);
-};
-
 /* for TI reference platforms sharing the same debug card */
 extern int debug_card_init(u32 addr, unsigned gpio);
 
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index bfdc5fb..92257ef 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -27,9 +27,9 @@
 #include <linux/fb.h>
 #include <linux/backlight.h>
 #include <linux/slab.h>
+#include <linux/platform_data/omap1_bl.h>
 
 #include <mach/hardware.h>
-#include <plat/board.h>
 #include <plat/mux.h>
 
 #define OMAPBL_MAX_INTENSITY		0xff
diff --git a/include/linux/platform_data/omap1_bl.h b/include/linux/platform_data/omap1_bl.h
new file mode 100644
index 0000000..881a8e9
--- /dev/null
+++ b/include/linux/platform_data/omap1_bl.h
@@ -0,0 +1,11 @@
+#ifndef __OMAP1_BL_H__
+#define __OMAP1_BL_H__
+
+#include <linux/device.h>
+
+struct omap_backlight_config {
+	int default_intensity;
+	int (*set_power)(struct device *dev, int state);
+};
+
+#endif
-- 
1.7.8.6


^ permalink raw reply related

* Re: [PATCH 4/5] drivers/video/msm/mddi_client_dummy.c: use devm_ functions
From: Damien Cassou @ 2012-08-28  8:42 UTC (permalink / raw)
  To: David Brown
  Cc: kernel-janitors, Daniel Walker, Bryan Huntsman,
	Florian Tobias Schandinat, linux-arm-msm, linux-fbdev,
	linux-kernel
In-Reply-To: <20120809175712.GA24215@codeaurora.org>

On Thu, Aug 9, 2012 at 7:57 PM, David Brown <davidb@codeaurora.org> wrote:
> Removing this block causes a warning:
> kernel/drivers/video/msm/mddi_client_dummy.c: In function 'mddi_dummy_probe':
> kernel/drivers/video/msm/mddi_client_dummy.c:55:6: warning: unused variable 'ret' [-Wunused-variable]
>
> Please remove the 'int ret;' line above as well.

Thank you for your feedback.
Please ignore this thread and patch. I've just sent a new email with
corrected patch.

-- 
Damien Cassou
http://damiencassou.seasidehosting.st

"Lambdas are relegated to relative obscurity until Java makes them
popular by not having them." James Iry

^ permalink raw reply

* [PATCH] drivers/video/msm/mddi_client_dummy.c: use devm_kzalloc function
From: Damien Cassou @ 2012-08-28  8:39 UTC (permalink / raw)
  To: David Brown
  Cc: kernel-janitors, Daniel Walker, Bryan Huntsman,
	Florian Tobias Schandinat, linux-arm-msm, linux-fbdev,
	linux-kernel

From: Damien Cassou <damien.cassou@lifl.fr>

The various devm_ functions allocate memory that is released when a driver
detaches. This patch replaces the use of kzalloc by devm_kzalloc.

Signed-off-by: Damien Cassou <damien.cassou@lifl.fr>

---
 drivers/video/msm/mddi_client_dummy.c |   13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c
index d2a091c..5faa37f 100644
--- a/drivers/video/msm/mddi_client_dummy.c
+++ b/drivers/video/msm/mddi_client_dummy.c
@@ -51,8 +51,7 @@ static int mddi_dummy_probe(struct platform_device *pdev)
 {
 	struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
 	struct panel_info *panel -		kzalloc(sizeof(struct panel_info), GFP_KERNEL);
-	int ret;
+		devm_kzalloc(&pdev->dev, sizeof(struct panel_info), GFP_KERNEL);
 	if (!panel)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, panel);
@@ -67,18 +66,11 @@ static int mddi_dummy_probe(struct platform_device *pdev)
 				      client_data->fb_resource, 1);
 	panel->panel_data.fb_data = client_data->private_client_data;
 	panel->pdev.dev.platform_data = &panel->panel_data;
-	ret = platform_device_register(&panel->pdev);
-	if (ret) {
-		kfree(panel);
-		return ret;
-	}
-	return 0;
+	return platform_device_register(&panel->pdev);
 }

 static int mddi_dummy_remove(struct platform_device *pdev)
 {
-	struct panel_info *panel = platform_get_drvdata(pdev);
-	kfree(panel);
 	return 0;
 }


^ permalink raw reply related

* Re: [PATCH] pwm-imx: Fix config / enable / disable
From: Sascha Hauer @ 2012-08-28  7:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1305545087.2775440.1345755837651.JavaMail.root@advansee.com>

On Thu, Aug 23, 2012 at 11:03:57PM +0200, Benoît Thébaudeau wrote:
> imx_pwm_config() did not enable the PWM IP clock while accessing the registers.
> Hence, a call to pwm_config() had no effect before pwm_enable() had been called,
> which does not comply to the PWM API.
> 
> Moreover, calling pwm_disable() then pwm_enable() must be a transparent
> operation.
> 
> This fixes the first setting of brightness through sysfs that had no effect with
> leds-pwm.

I don't really like this patch. I'd like to have this one first, it
makes further cleanups easier:

https://lkml.org/lkml/2012/8/28/24

Simililarly, we should probably introduce a imx_pwm_[en|dis]able_v[12]

Then, the pwm core already makes sure that pwm_enable/disable are called
only once, so the if (imx->clk_enabled) in pwm_enable/disable is
unnecessary.

Sascha

> 
> Cc: Thierry Reding <thierry.reding@avionic-design.de>
> Cc: <linux-kernel@vger.kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de>
> Cc: <linux-arm-kernel@lists.infradead.org>
> Cc: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
> Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
> ---
>  .../drivers/pwm/pwm-imx.c                          |   55 +++++++++++++++-----
>  1 file changed, 43 insertions(+), 12 deletions(-)
> 
> diff --git linux-next-c94456b.orig/drivers/pwm/pwm-imx.c linux-next-c94456b/drivers/pwm/pwm-imx.c
> index 2a0b353..0519bf2 100644
> --- linux-next-c94456b.orig/drivers/pwm/pwm-imx.c
> +++ linux-next-c94456b/drivers/pwm/pwm-imx.c
> @@ -55,6 +55,16 @@ static int imx_pwm_config(struct pwm_chip *chip,
>  {
>  	struct imx_chip *imx = to_imx_chip(chip);
>  
> +	/*
> +	 * If the PWM is disabled, make sure to turn on the clock before
> +	 * accessing the registers.
> +	 */
> +	if (!imx->clk_enabled) {
> +		int rc = clk_prepare_enable(imx->clk);
> +		if (rc)
> +			return rc;
> +	}
> +
>  	if (!(cpu_is_mx1() || cpu_is_mx21())) {
>  		unsigned long long c;
>  		unsigned long period_cycles, duty_cycles, prescale;
> @@ -85,8 +95,11 @@ static int imx_pwm_config(struct pwm_chip *chip,
>  		writel(period_cycles, imx->mmio_base + MX3_PWMPR);
>  
>  		cr = MX3_PWMCR_PRESCALER(prescale) |
> -			MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
> -			MX3_PWMCR_DBGEN | MX3_PWMCR_EN;
> +			MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | MX3_PWMCR_DBGEN;
> +
> +		/* If the PWM is enabled, keep it so. */
> +		if (imx->clk_enabled)
> +			cr |= MX3_PWMCR_EN;
>  
>  		if (cpu_is_mx25())
>  			cr |= MX3_PWMCR_CLKSRC_IPG;
> @@ -118,32 +131,50 @@ static int imx_pwm_config(struct pwm_chip *chip,
>  		BUG();
>  	}
>  
> +	/* If the PWM is disabled, turn the clock off again to save power. */
> +	if (!imx->clk_enabled)
> +		clk_disable_unprepare(imx->clk);
> +
>  	return 0;
>  }
>  
>  static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
>  {
>  	struct imx_chip *imx = to_imx_chip(chip);
> -	int rc = 0;
> +	int rc;
>  
> -	if (!imx->clk_enabled) {
> -		rc = clk_prepare_enable(imx->clk);
> -		if (!rc)
> -			imx->clk_enabled = 1;
> +	if (imx->clk_enabled)
> +		return 0;
> +
> +	rc = clk_prepare_enable(imx->clk);
> +	if (rc)
> +		return rc;
> +
> +	if (!(cpu_is_mx1() || cpu_is_mx21())) {
> +		u32 cr = readl(imx->mmio_base + MX3_PWMCR);
> +		cr |= MX3_PWMCR_EN;
> +		writel(cr, imx->mmio_base + MX3_PWMCR);
>  	}
> -	return rc;
> +
> +	imx->clk_enabled = 1;
> +	return 0;
>  }
>  
>  static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
>  {
>  	struct imx_chip *imx = to_imx_chip(chip);
>  
> -	writel(0, imx->mmio_base + MX3_PWMCR);
> +	if (!imx->clk_enabled)
> +		return;
>  
> -	if (imx->clk_enabled) {
> -		clk_disable_unprepare(imx->clk);
> -		imx->clk_enabled = 0;
> +	if (!(cpu_is_mx1() || cpu_is_mx21())) {
> +		u32 cr = readl(imx->mmio_base + MX3_PWMCR);
> +		cr &= ~MX3_PWMCR_EN;
> +		writel(cr, imx->mmio_base + MX3_PWMCR);
>  	}
> +
> +	clk_disable_unprepare(imx->clk);
> +	imx->clk_enabled = 0;
>  }
>  
>  static struct pwm_ops imx_pwm_ops = {
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH] drivrs/video/jz4740_fb.c: Use SIMPLE_DEV_PM_OPS instead of dev_pm_ops
From: Marcos Paulo de Souza @ 2012-08-28  4:38 UTC (permalink / raw)
  To: FlorianSchandinat; +Cc: linux-fbdev, linux-kernel, rjw, Marcos Paulo de Souza

Just a cleanup, not functional changes.

Signed-off-by: Marcos Paulo de Souza <marcos.souza.org@gmail.com>
---

 Just compile test. Please double check.

 drivers/video/jz4740_fb.c |    7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c
index de36693..a53fb7d 100644
--- a/drivers/video/jz4740_fb.c
+++ b/drivers/video/jz4740_fb.c
@@ -807,12 +807,7 @@ static int jzfb_resume(struct device *dev)
 	return 0;
 }
 
-static const struct dev_pm_ops jzfb_pm_ops = {
-	.suspend	= jzfb_suspend,
-	.resume		= jzfb_resume,
-	.poweroff	= jzfb_suspend,
-	.restore	= jzfb_resume,
-};
+static SIMPLE_DEV_PM_OPS(jzfb_pm_ops, jzfb_suspend, jzfb_resume);
 
 #define JZFB_PM_OPS (&jzfb_pm_ops)
 
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH 00/19] SH Mobile LCDC panel cleanup (including board code)
From: Laurent Pinchart @ 2012-08-27 15:35 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1345122054-16013-1-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Simon,

On Monday 27 August 2012 17:54:52 Simon Horman wrote:
> On Thu, Aug 16, 2012 at 03:00:35PM +0200, Laurent Pinchart wrote:
> > Hi everybody,
> > 
> > As part of a general panel API implementation (more on that a bit later),
> > I've cleaned up panel support in the LCDC driver and in the related board
> > code. The result is 19 patches independent of the generic panel API that
> > I would like to get reviewed by the respective board maintainers.
> 
> Hi Paul,
> 
> I'm happy for you to take all of this, including the mach-shmobile
> portions through your tree if that works for you.

I usually push the LCDC patches through the fbdev tree. I'm fine with both 
options though.

> > Laurent Pinchart (19):
> >   fbdev: sh_mobile_lcdc: Get display dimensions from the channel
> >     structure
> >   fbdev: sh_mobile_lcdc: Rename mode argument to modes
> >   fbdev: sh_mobile_lcdc: Remove priv argument from channel and overlay
> >     init
> >   ARM: mach-shmobile: ag5evm: Add LCDC tx_dev field to platform data
> >   fbdev: sh_mipi_dsi: Add channel field to platform data
> >   ARM: mach-shmobile: Initiliaze the new sh_mipi_dsi_info channel field
> >   fbdev: sh_mipi_dsi: Use the sh_mipi_dsi_info channel field
> >   fbdev: sh_mipi_dsi: Use the LCDC entity default mode
> >   fbdev: sh_mipi_dsi: Remove last reference to LCDC platform data
> >   ARM: mach-shmobile: Remove the unused sh_mipi_dsi_info lcd_chan field
> >   fbdev: sh_mipi_dsi: Remove the unused sh_mipi_dsi_info lcd_chan field
> >   fbdev: sh_mobile_lcdc: Store the backlight brightness internally
> >   ARM: mach-shmobile: mackerel: Removed unused get_brightness callback
> >   sh: ap325rxa: Remove unused get_brightness LCDC callback
> >   sh: ecovec24: Remove unused get_brightness LCDC callback
> >   fbdev: sh_mobile_lcdc: Remove unused get_brightness pdata callback
> >   ARM: mach-shmobile: ag5evm: Use the backlight API for brightness
> >     control
> >   sh: kfr2r09: Use the backlight API for brightness control
> >   fbdev: sh_mobile_lcdc: Make sh_mobile_lcdc_sys_bus_ops static
> >  
> >  arch/arm/mach-shmobile/board-ag5evm.c       |  198 +++++++++++-----------
> >  arch/arm/mach-shmobile/board-ap4evb.c       |    4 +-
> >  arch/arm/mach-shmobile/board-mackerel.c     |    6 -
> >  arch/sh/boards/mach-ap325rxa/setup.c        |    6 -
> >  arch/sh/boards/mach-ecovec24/setup.c        |    6 -
> >  arch/sh/boards/mach-kfr2r09/lcd_wqvga.c     |   16 +--
> >  arch/sh/boards/mach-kfr2r09/setup.c         |    7 +-
> >  arch/sh/include/mach-kfr2r09/mach/kfr2r09.h |    6 +-
> >  drivers/video/sh_mipi_dsi.c                 |   69 ++++------
> >  drivers/video/sh_mobile_lcdcfb.c            |   54 ++++----
> >  drivers/video/sh_mobile_lcdcfb.h            |    1 +
> >  include/video/sh_mipi_dsi.h                 |    4 +-
> >  include/video/sh_mobile_lcdc.h              |    1 -
> >  13 files changed, 172 insertions(+), 206 deletions(-)

-- 
Regards,

Laurent Pinchart


^ permalink raw reply

* Re: [PATCH] OMAPDSS: Correct DISPC_IRQ bit definitions for LCD3
From: Tomi Valkeinen @ 2012-08-27  9:26 UTC (permalink / raw)
  To: Chandrabhanu Mahapatra; +Cc: mark.tyler, linux-omap, linux-fbdev
In-Reply-To: <1346057599-5691-1-git-send-email-cmahapatra@ti.com>

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

On Mon, 2012-08-27 at 14:23 +0530, Chandrabhanu Mahapatra wrote:
> The DISPC_IRQ bit definitions pertaining to channel LCD3 as DISPC_IRQ_VSYNC3,
> DISPC_IRQ_SYNC_LOST3, DISPC_IRQ_ACBIAS_COUNT_STAT3 AND DISPC_IRQ_FRAMEDONE3
> which were incorrectly set in previous LCD3 patches have been corrected here.
> 
> Reported-by: Mark Tyler <mark.tyler@ti.com>
> Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
> ---
>  include/video/omapdss.h |    8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/include/video/omapdss.h b/include/video/omapdss.h
> index b868123..9c7cca3 100644
> --- a/include/video/omapdss.h
> +++ b/include/video/omapdss.h
> @@ -48,10 +48,10 @@
>  #define DISPC_IRQ_FRAMEDONEWB		(1 << 23)
>  #define DISPC_IRQ_FRAMEDONETV		(1 << 24)
>  #define DISPC_IRQ_WBBUFFEROVERFLOW	(1 << 25)
> -#define DISPC_IRQ_FRAMEDONE3		(1 << 26)
> -#define DISPC_IRQ_VSYNC3		(1 << 27)
> -#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 28)
> -#define DISPC_IRQ_SYNC_LOST3		(1 << 29)
> +#define DISPC_IRQ_SYNC_LOST3		(1 << 27)
> +#define DISPC_IRQ_VSYNC3		(1 << 28)
> +#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 29)
> +#define DISPC_IRQ_FRAMEDONE3		(1 << 30)
>  
>  struct omap_dss_device;
>  struct omap_overlay_manager;

Thanks, applied.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 0/9] SH Mobile LCDC and MERAM patches
From: Simon Horman @ 2012-08-27  8:59 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1342658362-19491-1-git-send-email-laurent.pinchart@ideasonboard.com>

On Sat, Aug 25, 2012 at 11:54:44AM +0200, Laurent Pinchart wrote:
> Hi Simon,
> 
> On Saturday 25 August 2012 14:31:51 Simon Horman wrote:
> > On Thu, Jul 19, 2012 at 02:39:13AM +0200, Laurent Pinchart wrote:
> > > Hi,
> > > 
> > > Here are 9 patches for the SH Mobile LCDC and MERAM drivers. Patches 1/9
> > > to 4/9 and 9/9 have previously been posted as part of the "SH Mobile LCDC
> > > MERAM-based frame buffer backing store" RFC series. Patch 5/9 has also
> > > been posted as part of the same series, albeit included in patch 9/9.
> > > 
> > > As most of those patches have already been posted for review (patches 6/9
> > > to 8/9 that haven't been posted already are small fixes), I plan to send
> > > a pull request soon, to get the patches in v3.6 if possible.
> > 
> > Hi Laurent,
> > 
> > could you let me know what the status of these patches is with regards to
> > merging.
> 
> They have been merged in v3.6-rc.

Thanks, sorry for not working that out myself.

^ permalink raw reply

* [PATCH] OMAPDSS: Correct DISPC_IRQ bit definitions for LCD3
From: Chandrabhanu Mahapatra @ 2012-08-27  8:55 UTC (permalink / raw)
  To: tomi.valkeinen
  Cc: mark.tyler, linux-omap, linux-fbdev, Chandrabhanu Mahapatra

The DISPC_IRQ bit definitions pertaining to channel LCD3 as DISPC_IRQ_VSYNC3,
DISPC_IRQ_SYNC_LOST3, DISPC_IRQ_ACBIAS_COUNT_STAT3 AND DISPC_IRQ_FRAMEDONE3
which were incorrectly set in previous LCD3 patches have been corrected here.

Reported-by: Mark Tyler <mark.tyler@ti.com>
Signed-off-by: Chandrabhanu Mahapatra <cmahapatra@ti.com>
---
 include/video/omapdss.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index b868123..9c7cca3 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -48,10 +48,10 @@
 #define DISPC_IRQ_FRAMEDONEWB		(1 << 23)
 #define DISPC_IRQ_FRAMEDONETV		(1 << 24)
 #define DISPC_IRQ_WBBUFFEROVERFLOW	(1 << 25)
-#define DISPC_IRQ_FRAMEDONE3		(1 << 26)
-#define DISPC_IRQ_VSYNC3		(1 << 27)
-#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 28)
-#define DISPC_IRQ_SYNC_LOST3		(1 << 29)
+#define DISPC_IRQ_SYNC_LOST3		(1 << 27)
+#define DISPC_IRQ_VSYNC3		(1 << 28)
+#define DISPC_IRQ_ACBIAS_COUNT_STAT3	(1 << 29)
+#define DISPC_IRQ_FRAMEDONE3		(1 << 30)
 
 struct omap_dss_device;
 struct omap_overlay_manager;
-- 
1.7.10


^ permalink raw reply related

* Re: [PATCH 00/19] SH Mobile LCDC panel cleanup (including board code)
From: Simon Horman @ 2012-08-27  8:54 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1345122054-16013-1-git-send-email-laurent.pinchart@ideasonboard.com>

On Thu, Aug 16, 2012 at 03:00:35PM +0200, Laurent Pinchart wrote:
> Hi everybody,
> 
> As part of a general panel API implementation (more on that a bit later), I've
> cleaned up panel support in the LCDC driver and in the related board code. The
> result is 19 patches independent of the generic panel API that I would like to
> get reviewed by the respective board maintainers.

Hi Paul,

I'm happy for you to take all of this, including the mach-shmobile
portions through your tree if that works for you.

> 
> Laurent Pinchart (19):
>   fbdev: sh_mobile_lcdc: Get display dimensions from the channel
>     structure
>   fbdev: sh_mobile_lcdc: Rename mode argument to modes
>   fbdev: sh_mobile_lcdc: Remove priv argument from channel and overlay
>     init
>   ARM: mach-shmobile: ag5evm: Add LCDC tx_dev field to platform data
>   fbdev: sh_mipi_dsi: Add channel field to platform data
>   ARM: mach-shmobile: Initiliaze the new sh_mipi_dsi_info channel field
>   fbdev: sh_mipi_dsi: Use the sh_mipi_dsi_info channel field
>   fbdev: sh_mipi_dsi: Use the LCDC entity default mode
>   fbdev: sh_mipi_dsi: Remove last reference to LCDC platform data
>   ARM: mach-shmobile: Remove the unused sh_mipi_dsi_info lcd_chan field
>   fbdev: sh_mipi_dsi: Remove the unused sh_mipi_dsi_info lcd_chan field
>   fbdev: sh_mobile_lcdc: Store the backlight brightness internally
>   ARM: mach-shmobile: mackerel: Removed unused get_brightness callback
>   sh: ap325rxa: Remove unused get_brightness LCDC callback
>   sh: ecovec24: Remove unused get_brightness LCDC callback
>   fbdev: sh_mobile_lcdc: Remove unused get_brightness pdata callback
>   ARM: mach-shmobile: ag5evm: Use the backlight API for brightness
>     control
>   sh: kfr2r09: Use the backlight API for brightness control
>   fbdev: sh_mobile_lcdc: Make sh_mobile_lcdc_sys_bus_ops static
> 
>  arch/arm/mach-shmobile/board-ag5evm.c       |  198 ++++++++++++++-------------
>  arch/arm/mach-shmobile/board-ap4evb.c       |    4 +-
>  arch/arm/mach-shmobile/board-mackerel.c     |    6 -
>  arch/sh/boards/mach-ap325rxa/setup.c        |    6 -
>  arch/sh/boards/mach-ecovec24/setup.c        |    6 -
>  arch/sh/boards/mach-kfr2r09/lcd_wqvga.c     |   16 +--
>  arch/sh/boards/mach-kfr2r09/setup.c         |    7 +-
>  arch/sh/include/mach-kfr2r09/mach/kfr2r09.h |    6 +-
>  drivers/video/sh_mipi_dsi.c                 |   69 ++++------
>  drivers/video/sh_mobile_lcdcfb.c            |   54 ++++----
>  drivers/video/sh_mobile_lcdcfb.h            |    1 +
>  include/video/sh_mipi_dsi.h                 |    4 +-
>  include/video/sh_mobile_lcdc.h              |    1 -
>  13 files changed, 172 insertions(+), 206 deletions(-)
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> --
> 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 02/23] OMAPDSS: outputs: Create and initialize output instances
From: Tomi Valkeinen @ 2012-08-27  6:44 UTC (permalink / raw)
  To: Archit Taneja; +Cc: linux-omap, linux-fbdev, rob, sumit.semwal
In-Reply-To: <503B115C.7040904@ti.com>

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

On Mon, 2012-08-27 at 11:49 +0530, Archit Taneja wrote:
> On Friday 24 August 2012 06:44 PM, Tomi Valkeinen wrote:
> > On Tue, 2012-08-21 at 11:28 +0530, Archit Taneja wrote:
> >> Create output instances by having an init function in the probes of the platform
> >> device drivers for different interfaces. Create a small function for each
> >> interface to initialize the output entity's fields type and id.
> >>
> >> In the probe of each interface driver, the output entities are created before
> >> the *_probe_pdata() functions intentionally. This is done to ensure that the
> >> output entity is prepared before the panels connected to the output are
> >> registered. We need the output entities to be ready because OMAPDSS will try
> >> to make connections between overlays, managers, outputs and devices during the
> >> panel's probe.
> >
> > You're referring to the recheck_connections stuff? I have a patch that
> > moves that to omapfb side. But of course it doesn't hurt to initialize
> > the output early.
> 
> I've seen that patch. omapfb would need to take care of connecting 
> outputs to displays, and managers to outputs. This is added in 
> recheck_connections done in a patch #9 of the series.
> 
> The question is whether we want some initial connections made between 
> outputs and displays by DSS, or should that be left completely to 
> omapfb/omapdrm?

Good question. I don't know. Perhaps we should set initial connections
there, as the cases where we have multiple displays per output are quite
rare.

> > We should generally do the initialization in output driver's probe more
> > or less so that we first setup everything related to the output driver,
> > and after that we register the dssdevs. But I think that's what is
> > already done.
> >
> > So, no complaints =).
> 
> Another thing that comes up with delaying the recheck_connections stuff 
> is that we can't assume that at the point of panel driver's probe, there 
> is an output connected to the display. That makes it a bit tricky to 
> call an output function in the panel's probe, since it isn't connected 
> to any output at all. An example is when we request for a VC in 
> taal_probe. Since the panel isn't connected to any output yet, we can't 
> really call a dsi function to request for the VC. This particular case 
> can be solved by requesting VCs only when we enable the panel(probably 
> makes more sense this way), but there might be other situations which 
> could get tricky to tackle.

Right. Well, as you said, we can easily move the stuff from taal's probe
to enable. There shouldn't be any problems to that.

However, this problem is part of the bigger problem that I haven't been
able to solve properly: how to manage the probe/enable stuff for panels.
Everything would be simple and easy if we had just one panel per output,
and we could just get and configure everything at probe. But we can have
multiple panels per output, of which only one can be used at a time...

That's why we currently acquire most of the display resources at enable,
instead of probe.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 02/23] OMAPDSS: outputs: Create and initialize output instances
From: Archit Taneja @ 2012-08-27  6:31 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, rob, sumit.semwal
In-Reply-To: <1345814042.9287.72.camel@lappyti>

On Friday 24 August 2012 06:44 PM, Tomi Valkeinen wrote:
> On Tue, 2012-08-21 at 11:28 +0530, Archit Taneja wrote:
>> Create output instances by having an init function in the probes of the platform
>> device drivers for different interfaces. Create a small function for each
>> interface to initialize the output entity's fields type and id.
>>
>> In the probe of each interface driver, the output entities are created before
>> the *_probe_pdata() functions intentionally. This is done to ensure that the
>> output entity is prepared before the panels connected to the output are
>> registered. We need the output entities to be ready because OMAPDSS will try
>> to make connections between overlays, managers, outputs and devices during the
>> panel's probe.
>
> You're referring to the recheck_connections stuff? I have a patch that
> moves that to omapfb side. But of course it doesn't hurt to initialize
> the output early.

I've seen that patch. omapfb would need to take care of connecting 
outputs to displays, and managers to outputs. This is added in 
recheck_connections done in a patch #9 of the series.

The question is whether we want some initial connections made between 
outputs and displays by DSS, or should that be left completely to 
omapfb/omapdrm?

>
> We should generally do the initialization in output driver's probe more
> or less so that we first setup everything related to the output driver,
> and after that we register the dssdevs. But I think that's what is
> already done.
>
> So, no complaints =).

Another thing that comes up with delaying the recheck_connections stuff 
is that we can't assume that at the point of panel driver's probe, there 
is an output connected to the display. That makes it a bit tricky to 
call an output function in the panel's probe, since it isn't connected 
to any output at all. An example is when we request for a VC in 
taal_probe. Since the panel isn't connected to any output yet, we can't 
really call a dsi function to request for the VC. This particular case 
can be solved by requesting VCs only when we enable the panel(probably 
makes more sense this way), but there might be other situations which 
could get tricky to tackle.

>
>> Signed-off-by: Archit Taneja <archit@ti.com>
>> ---
>>   drivers/video/omap2/dss/dpi.c  |   20 ++++++++++++++++++++
>>   drivers/video/omap2/dss/dsi.c  |   26 ++++++++++++++++++++++++--
>>   drivers/video/omap2/dss/hdmi.c |   18 ++++++++++++++++++
>>   drivers/video/omap2/dss/rfbi.c |   19 +++++++++++++++++++
>>   drivers/video/omap2/dss/sdi.c  |   20 ++++++++++++++++++++
>>   drivers/video/omap2/dss/venc.c |   20 ++++++++++++++++++++
>>   6 files changed, 121 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
>> index f260343..4eca2e7 100644
>> --- a/drivers/video/omap2/dss/dpi.c
>> +++ b/drivers/video/omap2/dss/dpi.c
>> @@ -408,10 +408,30 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
>>   	}
>>   }
>>
>> +static int __init dpi_init_output(struct platform_device *pdev)
>> +{
>> +	struct omap_dss_output *out;
>> +
>> +	out = dss_create_output(pdev);
>> +	if (!out)
>> +		return -ENOMEM;
>> +
>> +	out->id = OMAP_DSS_OUTPUT_DPI;
>> +	out->type = OMAP_DISPLAY_TYPE_DPI;
>> +
>> +	return 0;
>> +}
>> +
>>   static int __init omap_dpi_probe(struct platform_device *pdev)
>>   {
>> +	int r;
>> +
>>   	mutex_init(&dpi.lock);
>>
>> +	r = dpi_init_output(pdev);
>> +	if (r)
>> +		return r;
>> +
>>   	dpi_probe_pdata(pdev);
>>
>>   	return 0;
>> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
>> index 659b6cd..22e0873 100644
>> --- a/drivers/video/omap2/dss/dsi.c
>> +++ b/drivers/video/omap2/dss/dsi.c
>> @@ -4903,6 +4903,23 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
>>   	}
>>   }
>>
>> +static int __init dsi_init_output(struct platform_device *dsidev,
>> +		struct dsi_data *dsi)
>> +{
>> +	struct omap_dss_output *out;
>> +
>> +	out = dss_create_output(dsidev);
>> +	if (!out)
>> +		return -ENOMEM;
>> +
>> +	out->id = dsi->module_id = 0 ?
>> +			OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
>> +
>> +	out->type = OMAP_DISPLAY_TYPE_DSI;
>> +
>> +	return 0;
>
> As I mentioned in the last email, I think this could be something like:
>
> struct omap_dss_output *out = &dsi->output;
>
> out->pdev = dsidev;
> out->id = xxx;
> out->type = yyy;
> dss_register_output(out);
>

Right, this is much better, will do it this way.

>
>> +}
>> +
>>   /* DSI1 HW IP initialisation */
>>   static int __init omap_dsihw_probe(struct platform_device *dsidev)
>>   {
>> @@ -4997,10 +5014,14 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
>>   	else
>>   		dsi->num_lanes_supported = 3;
>>
>> -	dsi_probe_pdata(dsidev);
>> -
>>   	dsi_runtime_put(dsidev);
>>
>> +	r = dsi_init_output(dsidev, dsi);
>> +	if (r)
>> +		goto err_init_output;
>> +
>> +	dsi_probe_pdata(dsidev);
>> +
>
> Why do you change the sequence here? Isn't it enough to just add the
> init_output before probe_pdata?

Yes, I think I didn't see the point in keeping the clocks on for 
dsi_init_output() and dsi_probe_pdata(), so tried to incorporate that in 
this patch too :), I'll change this back to the old way, it doesn't make 
sense in moving around pm runtime calls in this series.

Archit


^ permalink raw reply

* Re: [PATCH 0/9] SH Mobile LCDC and MERAM patches
From: Laurent Pinchart @ 2012-08-25  9:54 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1342658362-19491-1-git-send-email-laurent.pinchart@ideasonboard.com>

Hi Simon,

On Saturday 25 August 2012 14:31:51 Simon Horman wrote:
> On Thu, Jul 19, 2012 at 02:39:13AM +0200, Laurent Pinchart wrote:
> > Hi,
> > 
> > Here are 9 patches for the SH Mobile LCDC and MERAM drivers. Patches 1/9
> > to 4/9 and 9/9 have previously been posted as part of the "SH Mobile LCDC
> > MERAM-based frame buffer backing store" RFC series. Patch 5/9 has also
> > been posted as part of the same series, albeit included in patch 9/9.
> > 
> > As most of those patches have already been posted for review (patches 6/9
> > to 8/9 that haven't been posted already are small fixes), I plan to send
> > a pull request soon, to get the patches in v3.6 if possible.
> 
> Hi Laurent,
> 
> could you let me know what the status of these patches is with regards to
> merging.

They have been merged in v3.6-rc.

> > Laurent Pinchart (9):
> >   sh_mobile_meram: Rename operations to cache_[alloc|free|update]
> >   sh_mobile_meram: Use direct function calls for the public API
> >   sh_mobile_meram: Add direct MERAM allocation API
> >   fbdev: sh_mobile_lcdc: Destroy mutex at remove time
> >   fbdev: sh_mobile_lcdc: Fix line pitch computation
> >   fbdev: sh_mobile_lcdc: Use channel configuration to initialize fb
> >     device
> >   fbdev: sh_mobile_lcdc: Support horizontal panning
> >   fbdev: sh_mobile_lcdc: Fix overlay registers update during pan
> >     operation
> >   fbdev: sh_mobile_lcdc: Fix pan offset computation in YUV mode
> >  
> >  drivers/video/sh_mobile_lcdcfb.c |  209 +++++++++++++++++----------------
> >  drivers/video/sh_mobile_lcdcfb.h |    5 +-
> >  drivers/video/sh_mobile_meram.c  |  235 ++++++++++++++++++---------------
> >  include/video/sh_mobile_meram.h  |   71 ++++++++----
> >  4 files changed, 293 insertions(+), 227 deletions(-)

-- 
Regards,

Laurent Pinchart


^ permalink raw reply

* Re: [PATCH 0/9] SH Mobile LCDC and MERAM patches
From: Simon Horman @ 2012-08-25  5:31 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1342658362-19491-1-git-send-email-laurent.pinchart@ideasonboard.com>

On Thu, Jul 19, 2012 at 02:39:13AM +0200, Laurent Pinchart wrote:
> Hi,
> 
> Here are 9 patches for the SH Mobile LCDC and MERAM drivers. Patches 1/9 to
> 4/9 and 9/9 have previously been posted as part of the "SH Mobile LCDC
> MERAM-based frame buffer backing store" RFC series. Patch 5/9 has also been
> posted as part of the same series, albeit included in patch 9/9.
> 
> As most of those patches have already been posted for review (patches 6/9 to
> 8/9 that haven't been posted already are small fixes), I plan to send a pull
> request soon, to get the patches in v3.6 if possible.

Hi Laurent,

could you let me know what the status of these patches is with regards to
merging.

> Laurent Pinchart (9):
>   sh_mobile_meram: Rename operations to cache_[alloc|free|update]
>   sh_mobile_meram: Use direct function calls for the public API
>   sh_mobile_meram: Add direct MERAM allocation API
>   fbdev: sh_mobile_lcdc: Destroy mutex at remove time
>   fbdev: sh_mobile_lcdc: Fix line pitch computation
>   fbdev: sh_mobile_lcdc: Use channel configuration to initialize fb
>     device
>   fbdev: sh_mobile_lcdc: Support horizontal panning
>   fbdev: sh_mobile_lcdc: Fix overlay registers update during pan
>     operation
>   fbdev: sh_mobile_lcdc: Fix pan offset computation in YUV mode
> 
>  drivers/video/sh_mobile_lcdcfb.c |  209 +++++++++++++++++----------------
>  drivers/video/sh_mobile_lcdcfb.h |    5 +-
>  drivers/video/sh_mobile_meram.c  |  235 +++++++++++++++++++++-----------------
>  include/video/sh_mobile_meram.h  |   71 ++++++++----
>  4 files changed, 293 insertions(+), 227 deletions(-)

^ permalink raw reply

* Re: [PATCHv4 0/9] *** ARM: Update arch-vt8500 to Devicetree ***
From: Stephen Warren @ 2012-08-25  3:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1345707346-9035-1-git-send-email-linux@prisktech.co.nz>

On 08/23/2012 01:35 AM, Tony Prisk wrote:
> This patchset updates arch-vt8500 to devicetree and removes all the old-style
> code. Support for WM8650 has also been added.
> 
> Example dts/dtsi files are given for the three currently supported models.
> 
> Major changes:
> 
> GPIO code has been converted to a platform_device and rewritten as WM8505
> support was broken. Add support for WM8650 gpio controller.
> 
> UHCI support was missing. Added this as a generic non-pci uhci controller as
> it doesn't require anything special. Should be usable by any system that doesn't
> have special requirements to get the UHCI controller working.
> 
> Framebuffer code patched to support WM8650. The bindings for this are of concern
> but there doesn't seem to be a formalized binding yet. This patch is based off
> Sascha Hauer's current patch on the dri-devel mailing list and should be easily
> patched out when its finalized.
> 
> Patchset based on Arnd's arm-soc/for-next branch.

I believe all the issues I pointed out are fixed in this series. I'm not
sure I reviewed it in enough detail to ack it, but I'm fine with what I saw.

^ permalink raw reply

* [PATCH] qxl-virtio: introducing virtio-qxl driver.
From: Erlon Cruz @ 2012-08-24 19:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-fbdev, alevy, FlorianSchandinat, Erlon Cruz,
	Fabiano Fidêncio, Rafael F. Santos

The qxl-virtio driver implements a QXL driver using VirtIO as transport, thus
enabling the use of QXL/Spice in non-PCI architectures. In the actual QXL
driver, all communication between Host and Guest is done through PCI shared
memory.

Signed-off-by: Erlon R. Cruz <erlon.cruz@br.flextronics.com>
Signed-off-by: Fabiano Fidêncio <Fabiano.Fidencio@fit-tecnologia.org.br>
Signed-off-by: Rafael F. Santos <fonsecasantos.rafael@gmail.com>
---
 .gitignore                        |    1 +
 drivers/video/Kconfig             |    6 +
 drivers/video/Makefile            |    3 +
 drivers/video/virtio-qxl-bridge.c |  628 +++++++++++++++++++++++++++++++++++++
 include/linux/Kbuild              |    1 +
 include/linux/virtio_bridge.h     |  159 ++++++++++
 6 files changed, 798 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/virtio-qxl-bridge.c
 create mode 100644 include/linux/virtio_bridge.h

diff --git a/.gitignore b/.gitignore
index 57af07c..ebe7e3e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,3 +84,4 @@ GTAGS
 *.orig
 *~
 \#*#
+/nbproject/private/
\ No newline at end of file
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0217f74..466863b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2469,4 +2469,10 @@ config FB_SH_MOBILE_MERAM
 	  Up to 4 memory channels can be configured, allowing 4 RGB or
 	  2 YCbCr framebuffers to be configured.
 
+config VIRTIO_QXL
+	tristate "QXL driver over VirtIO"
+	depends on EXPERIMENTAL && VIRTIO
+	help
+	  This driver provides a QXL video device using virtio transport.
+
 endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ee8dafb..a331743 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -170,3 +170,6 @@ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
 
 #video output switch sysfs driver
 obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+
+# Virtio QLX
+obj-$(CONFIG_VIRTIO_QXL) += virtio-qxl-bridge.o
diff --git a/drivers/video/virtio-qxl-bridge.c b/drivers/video/virtio-qxl-bridge.c
new file mode 100644
index 0000000..c799943
--- /dev/null
+++ b/drivers/video/virtio-qxl-bridge.c
@@ -0,0 +1,628 @@
+/*
+ * Virtio QXL Device
+ *
+ *
+ * Authors:
+ *  Erlon R. Cruz <erlon.cruz@br.flextronics.com>
+ *  Rafael F. Santos <Rafael.Santos@fit-tecnologia.org.br>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_bridge.h>
+#include <linux/mm.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <asm/current.h>
+#include <asm/page.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+
+#define DRIVER_STRING "virtio-qxl-bridge"
+#define SG_ELEMENTS 128
+
+#define DEBUG_ERROR 1
+#define DEBUG_INFO 1
+#define DEBUG_VM 0
+#define DEBUG_SG 0
+#define DEBUG_PUSH_AREA 0
+#define DEBUG_PULL_AREA 0
+#define DEBUG_IOCTL 0
+#define DEBUG_IOPWRITE 0
+#define DEBUG_FOPS 0
+
+ #define dprintk(_level, _fmt, ...)			\
+do {									\
+	if (_level) {						\
+		printk(_fmt, ## __VA_ARGS__);	\
+	}								\
+} while (0)
+
+static inline void printHexa(void *buf, int len)
+{
+	uint8_t *cur, *ubuf;
+	ubuf = (uint8_t *) buf;
+
+	for (cur = ubuf; (cur - ubuf) < len; cur++)
+#ifdef __KERNEL__
+		printk("%02X", *cur);
+#else
+		ErrorF("%02X", *cur);
+#endif
+
+}
+
+dev_t dev;
+int devindex, devno;
+struct semaphore idxsem;
+struct class *virtio_qxl_class;
+
+struct qxl_usrmem_desc {
+	char __user *start;
+	unsigned int len;
+};
+
+struct virtio_qxl_bridge {
+	spinlock_t lock;
+	struct virtio_device *vdev;
+	struct virtqueue *vq;
+	struct scatterlist sg[SG_ELEMENTS];
+	struct scatterlist *vgasg;
+	struct cdev cdev;
+	struct virtioqxl_config config;
+	struct semaphore sem;
+	struct qxl_usrmem_desc mem_desc;
+	struct page **user_pages;
+};
+
+struct vbr_req {
+	struct list_head list;
+	struct vbr_proto_hdr hdr;
+	u8 status;
+};
+
+void put_userpages_vector(struct page **pages, int num_pages, bool dirty)
+{
+	int i;
+
+	for (i = 0; i < num_pages; i++) {
+		if (dirty)
+			set_page_dirty_lock(pages[i]);
+		put_page(pages[i]);
+	}
+}
+
+static int userpages_fill_sg(struct page **upages, struct scatterlist *sg,
+			     u8 __user *virt, int length, int write)
+{
+	struct page *pg;
+	int sg_entries = 0, pagesidx = 0;
+	int tmp_off, rc;
+	uint8_t *ustart, *uend;
+
+	ustart = virt;
+	uend = ustart + length;
+	tmp_off = ((ulong) ustart & ~PAGE_MASK);
+	/* unaligned */
+	if (tmp_off) {
+		int gap = 0, cplen;
+
+		/* Length from offset to the end of the page */
+		gap = PAGE_SIZE - tmp_off;
+		if (gap > length)
+			cplen = length;
+		else
+			cplen = gap;
+
+		down_read(&current->mm->mmap_sem);
+		rc = get_user_pages(current,
+				    current->mm,
+				    (unsigned long)ustart & PAGE_MASK,
+				    1, write, 0, upages + pagesidx++, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		pg = upages[pagesidx - 1];
+		sg_set_page(&sg[sg_entries++], pg, cplen, tmp_off);
+		ustart += cplen;
+		dprintk(DEBUG_SG,
+			"%s: Unaligned buffer: tt len %d, offset %d, gap %d,"
+			" unaligned head %d", __func__, length, tmp_off, gap,
+			cplen);
+	} else {
+		dprintk(DEBUG_SG, "%s: Aligned buffer tt len %d", __func__,
+			length);
+	}
+
+	/* Now start is aligned rigth? hooope so */
+	while (uend - ustart >= PAGE_SIZE) {
+
+		down_read(&current->mm->mmap_sem);
+		rc = get_user_pages(current,
+				    current->mm,
+				    (unsigned long)ustart,
+				    1, write, 0, upages + pagesidx++, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		pg = upages[pagesidx - 1];
+		sg_set_page(&sg[sg_entries++], pg, PAGE_SIZE, 0);
+		ustart += PAGE_SIZE;
+	}
+
+	if (uend - ustart > 0) {
+
+		down_read(&current->mm->mmap_sem);
+		rc = get_user_pages(current,
+				    current->mm,
+				    (unsigned long)ustart,
+				    1, write, 0, upages + pagesidx++, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (rc < 0)
+			goto fail;
+
+		pg = upages[pagesidx - 1];
+		sg_set_page(&sg[sg_entries++], pg, uend - ustart, 0);
+		dprintk(DEBUG_SG, " unaligned tail %d", (int)(uend - ustart));
+		ustart += uend - ustart;
+	}
+
+	if (ustart != uend)
+		panic("Anomalous behavior when filling SG\n");
+
+	dprintk(DEBUG_SG, " %d SG entries\n", sg_entries);
+	return sg_entries;
+
+fail:
+	put_userpages_vector(upages, pagesidx - 1, false);
+	return 0;
+}
+
+static int send_packet(struct virtio_qxl_bridge *devdata,
+		       int what, char __user *buffer, int len, int flags)
+{
+	int in, out, mapped_entries = 0;
+	unsigned int readlen;
+	struct vbr_req *rq;
+	struct scatterlist *sg;
+
+	in = out = 0;
+	rq = kzalloc(sizeof(*rq), GFP_KERNEL);
+
+	rq->hdr.flags |= flags;
+	rq->hdr.function = what;
+	/* The offset of the buffer based on the start of video memory */
+	rq->hdr.param = buffer - devdata->mem_desc.start;
+	rq->hdr.len = len;
+
+	switch (what) {
+	case VIRTIOQXL_GETCFG:
+		sg = devdata->sg;
+		sg_set_buf(&sg[out++], &rq->hdr, sizeof(rq->hdr));
+		sg_set_buf(&sg[out + in++], buffer, len);
+		break;
+
+	case VIRTIOQXL_IOPORT_WRITE:
+		sg = devdata->sg;
+		sg_set_buf(&sg[out++], &rq->hdr, sizeof(rq->hdr));
+		sg_set_buf(&sg[out++], buffer, len);
+		break;
+
+	case VIRTIOQXL_GET_RAM:
+		sg = devdata->vgasg;
+		sg_set_buf(&sg[out++], &rq->hdr, sizeof(rq->hdr));
+		in += mapped_entries +		    userpages_fill_sg(devdata->user_pages, &sg[out], buffer,
+				      len, 1);
+
+		break;
+
+	case VIRTIOQXL_SET_RAM:
+		sg = devdata->vgasg;
+		sg_set_buf(&sg[out++], &rq->hdr, sizeof(rq->hdr));
+		out += mapped_entries +		    userpages_fill_sg(devdata->user_pages, &sg[out], buffer,
+				      len, 0);
+		break;
+	default:
+		panic("%s: virtio QXL request (%d) not supported\n",
+		      DRIVER_STRING, what);
+		break;
+	}
+
+	sg_set_buf(&sg[out + in++], &rq->status, sizeof(rq->status));
+
+	if (virtqueue_add_buf(devdata->vq, sg, out, in, rq, GFP_KERNEL) < 0) {
+		dprintk(DEBUG_ERROR, "%s: error adding buffer\n",
+			DRIVER_STRING);
+		return -1;
+	}
+
+	virtqueue_kick(devdata->vq);
+	while (!virtqueue_get_buf(devdata->vq, &readlen))
+		cpu_relax();
+
+	if (mapped_entries)
+		put_userpages_vector(devdata->user_pages, mapped_entries,
+				     (in > 1));
+
+	kfree(rq);
+	return 0;
+}
+
+static int get_from_host(struct virtio_qxl_bridge *devdata, uint what,
+			 void *bufto, int len)
+{
+	return send_packet(devdata, what, bufto, len, CONFIG_READ);
+}
+
+static int set_on_host(struct virtio_qxl_bridge *devdata, uint what,
+		       void *buffrom, int len)
+{
+	return send_packet(devdata, what, buffrom, len, CONFIG_WRITE);
+}
+
+static int device_open(struct inode *inode, struct file *file)
+{
+	struct virtio_qxl_bridge *virtiodata;
+
+	dprintk(DEBUG_INFO, "%s: entering %s\n", DRIVER_STRING, __func__);
+
+	virtiodata +	    container_of(inode->i_cdev, struct virtio_qxl_bridge, cdev);
+	file->private_data = virtiodata;
+
+	return 0;
+}
+
+static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct virtio_qxl_bridge *brdev = file->private_data;
+
+	switch (cmd) {
+
+	case QXL_IOCTL_QXL_IO_GETCFG:{
+			struct virtioqxl_config *cfg;
+			cfg = &brdev->config;
+			copy_to_user((void __user *)arg, cfg,
+				     sizeof(struct virtioqxl_config));
+			break;
+		}
+
+	case QXL_IOCTL_QXL_IO_SET_RAMSTART:{
+
+			copy_from_user(&brdev->mem_desc.start,
+				       (void __user *)arg,
+				       sizeof(brdev->mem_desc.start));
+			brdev->mem_desc.len +			    brdev->config.vramsize + brdev->config.ramsize +
+			    brdev->config.romsize;
+
+			dprintk(DEBUG_INFO, "%s: user ram start %p\n",
+				DRIVER_STRING, brdev->mem_desc.start);
+			break;
+		}
+
+	case QXL_IOCTL_NOTIFY_CMD:
+	case QXL_IOCTL_NOTIFY_CURSOR:
+	case QXL_IOCTL_UPDATE_AREA:
+	case QXL_IOCTL_UPDATE_IRQ:
+	case QXL_IOCTL_NOTIFY_OOM:
+	case QXL_IOCTL_RESET:
+	case QXL_IOCTL_SET_MODE:
+	case QXL_IOCTL_LOG:
+	case QXL_IOCTL_MEMSLOT_ADD:
+	case QXL_IOCTL_MEMSLOT_DEL:
+	case QXL_IOCTL_DETACH_PRIMARY:
+	case QXL_IOCTL_ATTACH_PRIMARY:
+	case QXL_IOCTL_CREATE_PRIMARY:
+	case QXL_IOCTL_DESTROY_PRIMARY:
+	case QXL_IOCTL_DESTROY_SURFACE_WAIT:
+	case QXL_IOCTL_DESTROY_ALL_SURFACES:
+	case QXL_IOCTL_UPDATE_AREA_ASYNC:
+	case QXL_IOCTL_MEMSLOT_ADD_ASYNC:
+	case QXL_IOCTL_CREATE_PRIMARY_ASYNC:
+	case QXL_IOCTL_DESTROY_PRIMARY_ASYNC:
+	case QXL_IOCTL_DESTROY_SURFACE_ASYNC:
+	case QXL_IOCTL_DESTROY_ALL_SURFACES_ASYNC:
+	case QXL_IOCTL_FLUSH_SURFACES_ASYNC:
+	case QXL_IOCTL_FLUSH_RELEASE:{
+			struct iowrite_cmd *iocmd +			    kmalloc(sizeof(*iocmd), GFP_KERNEL);
+			iocmd->port = _IOC_NR(cmd);
+			iocmd->arg = arg;
+			dprintk(DEBUG_IOPWRITE, " port %d, arg %d\n",
+				iocmd->port, iocmd->arg);
+			set_on_host(brdev, VIRTIOQXL_IOPORT_WRITE, iocmd,
+				    sizeof(*iocmd));
+			kfree(iocmd);
+			break;
+		}
+
+	default:
+		dprintk(DEBUG_INFO, "%s: IOCTL not handled %ui\n", __func__,
+			cmd);
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static ssize_t device_read(struct file *file, char __user *buf, size_t len,
+			   loff_t *f_pos)
+{
+	struct virtio_qxl_bridge *virtiodata = file->private_data;
+
+	if (!virtiodata->mem_desc.start)
+		return -EFAULT;
+
+	if (buf < virtiodata->mem_desc.start ||
+	    (buf + len) >
+	    (virtiodata->mem_desc.start + virtiodata->mem_desc.len))
+		return -EFAULT;
+
+	if (len <= 0)
+		return 0;
+
+	dprintk(DEBUG_FOPS,
+		"%s: virtio_qxl_bridge: %s: reading %d bytes, "
+		"useraddr = %p, videomem offset = %lu\n",
+		DRIVER_STRING, __func__, (int)len, buf,
+		buf - virtiodata->mem_desc.start);
+
+	return get_from_host(virtiodata, VIRTIOQXL_GET_RAM, buf, len);
+}
+
+static ssize_t device_write(struct file *file, const char __user *buf,
+			    size_t len, loff_t *f_pos)
+{
+	struct virtio_qxl_bridge *virtiodata = file->private_data;
+
+	if (!virtiodata->mem_desc.start)
+		return -EFAULT;
+
+	if (buf < virtiodata->mem_desc.start ||
+	    (buf + len) >
+	    (virtiodata->mem_desc.start + virtiodata->mem_desc.len))
+		return -EFAULT;
+
+	if (len <= 0)
+		return 0;
+
+	dprintk(DEBUG_FOPS,
+		"%s: virtio_qxl_bridge: %s: writing %d bytes, "
+		"useraddr = %p, videomem offset = %lu\n",
+		DRIVER_STRING, __func__, (int)len, buf,
+		buf - virtiodata->mem_desc.start);
+
+	return set_on_host(virtiodata, VIRTIOQXL_SET_RAM, (char *)buf, len);
+}
+
+int device_release(struct inode *inode, struct file *file)
+{
+	dprintk(DEBUG_FOPS, "%s: %s\n", DRIVER_STRING, __func__);
+	return 0;
+}
+
+const struct file_operations device_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = device_ioctl,
+	.read = device_read,
+	.write = device_write,
+	.open = device_open,
+	.release = device_release
+};
+
+static int setup_cdev(struct virtio_qxl_bridge *virtiodata)
+{
+	int minor, err = 0;
+	struct device *device;
+
+	down(&idxsem);
+	minor = devindex;
+	devindex++;
+	up(&idxsem);
+
+	devno = MKDEV(MAJOR(dev), minor);
+
+	dprintk(DEBUG_INFO, "%s: %s: adding char device %d/%d\n",
+		DRIVER_STRING, __func__, MAJOR(dev), minor);
+
+	/* Print driver port string */
+	cdev_init(&virtiodata->cdev, &device_fops);
+	virtiodata->cdev.owner = THIS_MODULE;
+	virtiodata->cdev.ops = &device_fops;
+	err = cdev_add(&virtiodata->cdev, devno, 1);
+	if (err) {
+		dprintk(DEBUG_INFO, "%s: error %d adding char device %d",
+			DRIVER_STRING, err, devindex);
+		return err;
+	}
+
+	/* Create a sysfs class entry */
+	device +	    device_create(virtio_qxl_class, NULL, devno, NULL, "virtioqxl%u",
+			  minor);
+	if (IS_ERR(device)) {
+		dprintk(DEBUG_INFO, "%s: error %li creating device %d\n",
+			DRIVER_STRING, PTR_ERR(device), devindex);
+		err = PTR_ERR(device);
+		cdev_del(&virtiodata->cdev);
+	}
+	return err;
+}
+
+static void release_cdev(struct virtio_qxl_bridge *virtiodata)
+{
+	device_destroy(virtio_qxl_class, devno);
+	cdev_del(&virtiodata->cdev);
+}
+
+static int __devinit qxl_bridge_probe(struct virtio_device *vdev)
+{
+	int memlen, sg_elements, err = 0;
+	struct virtio_qxl_bridge *brdev;
+	struct virtioqxl_config *cfg;
+
+	dprintk(DEBUG_INFO, "%s: probing\n", DRIVER_STRING);
+
+	brdev = kmalloc(sizeof(struct virtio_qxl_bridge), GFP_KERNEL);
+	if (!brdev)
+		return -ENOMEM;
+
+	dprintk(DEBUG_INFO, "%s: allocated %lu bytes as virtio_data\n",
+		DRIVER_STRING, sizeof(struct virtio_qxl_bridge));
+
+	brdev->vq = virtio_find_single_vq(vdev, NULL, "requests");
+	if (IS_ERR(brdev->vq)) {
+		err = PTR_ERR(brdev->vq);
+		dprintk(DEBUG_ERROR, "%s: error finding vq\n", DRIVER_STRING);
+		goto out_find;
+	}
+
+	cfg = &brdev->config;
+	brdev->vdev = vdev;
+	brdev->vdev->priv = brdev;
+
+	spin_lock_init(&brdev->lock);
+	sg_init_table(brdev->sg, SG_ELEMENTS);
+	sema_init(&brdev->sem, 1);
+
+	err = setup_cdev(brdev);
+	if (err < 0)
+		goto out_cdev;
+
+	get_from_host(brdev, VIRTIOQXL_GETCFG, cfg, sizeof(*cfg));
+	memlen = cfg->ramsize + cfg->vramsize + cfg->romsize;
+	dprintk(DEBUG_INFO,
+		"%s: got config information from host: ram size %d, "
+		"vram size %d, rom size %d\n", DRIVER_STRING, cfg->ramsize,
+		cfg->vramsize, cfg->romsize);
+
+	/* Memmory + alignment + head/tail */
+	sg_elements = cfg->vramsize / PAGE_SIZE + 1 + 2;
+	brdev->vgasg +	    kmalloc(sizeof(struct scatterlist) * sg_elements, GFP_KERNEL);
+	if (!brdev->vgasg) {
+		dprintk(DEBUG_ERROR, "%s: error allocating SG memory\n",
+			DRIVER_STRING);
+		goto out_driver_mem;
+	}
+	dprintk(DEBUG_INFO, "%s: allocated table for %d SG elements\n",
+		DRIVER_STRING, sg_elements);
+
+	sg_init_table(brdev->vgasg, sg_elements);
+
+	brdev->mem_desc.start = NULL;
+	brdev->user_pages +	    kmalloc((cfg->vramsize / PAGE_SIZE) * sizeof(struct page),
+		    GFP_KERNEL);
+	if (!brdev->user_pages) {
+		dprintk(DEBUG_ERROR, "%s: error allocating page table memory\n",
+			DRIVER_STRING);
+		goto out_driver_mem2;
+	}
+
+	return 0;
+
+out_driver_mem2:
+	kfree(brdev->vgasg);
+out_driver_mem:
+	release_cdev(brdev);
+out_cdev:
+	vdev->config->reset(vdev);
+	vdev->config->del_vqs(vdev);
+out_find:
+	kfree(brdev);
+	return err;
+}
+
+static void __devexit qxl_bridge_remove(struct virtio_device *vdev)
+{
+	struct virtio_qxl_bridge *brdata = vdev->priv;
+
+	kfree(brdata->user_pages);
+	kfree(brdata->vgasg);
+	release_cdev(brdata);
+	vdev->config->reset(vdev);
+	vdev->config->del_vqs(vdev);
+	dprintk(DEBUG_INFO, "%s: removing\n", DRIVER_STRING);
+	kfree(brdata);
+}
+
+static const struct virtio_device_id id_table[] = {
+	{6, VIRTIO_DEV_ANY_ID},
+	{0},
+};
+
+static struct virtio_driver __refdata virtio_qxl = {
+	.driver.name = KBUILD_MODNAME,
+	.driver.owner = THIS_MODULE,
+	.id_table = id_table,
+	.probe = qxl_bridge_probe,
+	.remove = __devexit_p(qxl_bridge_remove),
+};
+
+static int __init init(void)
+{
+	int ret = 0;
+	dev = 0;
+	devindex = 0;
+	devno = 0;
+
+	dprintk(DEBUG_INFO, "%s: init\n", DRIVER_STRING);
+
+	ret = alloc_chrdev_region(&dev, 0, 1, "virtio-qxl-bridge");
+	if (ret < 0) {
+		dprintk(DEBUG_INFO, "%s: can't get major %d\n", DRIVER_STRING,
+			MAJOR(dev));
+		goto out;
+	}
+
+	sema_init(&idxsem, 1);
+
+	virtio_qxl_class = class_create(THIS_MODULE, "virtioqxl");
+	if (IS_ERR(virtio_qxl_class)) {
+		dprintk(DEBUG_INFO, "%s: error creating driver class.\n",
+			DRIVER_STRING);
+		ret = PTR_ERR(virtio_qxl_class);
+		goto class_out;
+	}
+
+	ret = register_virtio_driver(&virtio_qxl);
+	if (!ret)
+		return ret;
+
+	class_destroy(virtio_qxl_class);
+class_out:
+	unregister_chrdev_region(dev, 1);
+out:
+	return ret;
+}
+
+static void __exit finish(void)
+{
+	unregister_virtio_driver(&virtio_qxl);
+	class_destroy(virtio_qxl_class);
+	unregister_chrdev_region(dev, 1);
+	dprintk(DEBUG_INFO, "%s: ...exit.\n", DRIVER_STRING);
+}
+
+module_init(init);
+module_exit(finish);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("VirtIO QXL bridge");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index fa21760..8b814f6 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -397,6 +397,7 @@ header-y += videodev2.h
 header-y += virtio_9p.h
 header-y += virtio_balloon.h
 header-y += virtio_blk.h
+header-y += virtio_bridge.h
 header-y += virtio_config.h
 header-y += virtio_console.h
 header-y += virtio_ids.h
diff --git a/include/linux/virtio_bridge.h b/include/linux/virtio_bridge.h
new file mode 100644
index 0000000..a5f6472
--- /dev/null
+++ b/include/linux/virtio_bridge.h
@@ -0,0 +1,159 @@
+/*
+ * Virtio QXL
+ *
+ *
+ * Authors:
+ *  Erlon R. Cruz <erlon.cruz@br.flextronics.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef VIRTIO_BRIDGE_H
+#define VIRTIO_BRIDGE_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+/* Taken from spice-protocol */
+enum {
+	QXL_IO_NOTIFY_CMD,
+	QXL_IO_NOTIFY_CURSOR,
+	QXL_IO_UPDATE_AREA,
+	QXL_IO_UPDATE_IRQ,
+	QXL_IO_NOTIFY_OOM,
+	QXL_IO_RESET,
+	QXL_IO_SET_MODE,	/* qxl-1 */
+	QXL_IO_LOG,
+	/* appended for qxl-2 */
+	QXL_IO_MEMSLOT_ADD,
+	QXL_IO_MEMSLOT_DEL,
+	QXL_IO_DETACH_PRIMARY,
+	QXL_IO_ATTACH_PRIMARY,
+	QXL_IO_CREATE_PRIMARY,
+	QXL_IO_DESTROY_PRIMARY,
+	QXL_IO_DESTROY_SURFACE_WAIT,
+	QXL_IO_DESTROY_ALL_SURFACES,
+	/* appended for qxl-3 */
+	QXL_IO_UPDATE_AREA_ASYNC,
+	QXL_IO_MEMSLOT_ADD_ASYNC,
+	QXL_IO_CREATE_PRIMARY_ASYNC,
+	QXL_IO_DESTROY_PRIMARY_ASYNC,
+	QXL_IO_DESTROY_SURFACE_ASYNC,
+	QXL_IO_DESTROY_ALL_SURFACES_ASYNC,
+	QXL_IO_FLUSH_SURFACES_ASYNC,
+	QXL_IO_FLUSH_RELEASE,
+	QXL_IO_RANGE_SIZE
+};
+
+/* Transport operations between guest kernel and host */
+enum {
+	VIRTIOQXL_GETCFG,
+	VIRTIOQXL_IOPORT_WRITE,
+	VIRTIOQXL_GET_RAM,
+	VIRTIOQXL_SET_RAM
+};
+
+enum {
+	VIRTIOQXL_STATUS_DONE,
+	VIRTIOQXL_STATUS_ERROR,
+	VIRTIOQXL_STATUS_RANGE
+};
+
+/* TODO: Merge this num with guest_host_cmd? */
+/* Read configs from the host device */
+#define CONFIG_READ 0x00000001
+/* Write configs on the host device */
+#define CONFIG_WRITE 0x00000002
+
+#endif
+
+/* Commands betweend xf86 driver and kernel virtio driver */
+enum {
+	QXL_IO_PUSH_AREA = 100,
+	QXL_IO_PULL_AREA,
+	QXL_IO_GETCFG,
+	QXL_IO_SET_RAMSTART
+};
+
+struct qxl_ram_area {
+	__u32 offset;
+	__u32 len;
+};
+
+struct vbr_proto_hdr {
+	__u32 function;
+	__u32 flags;
+	__u32 param;		/* Parameter related var */
+	__u32 len;
+};
+
+struct iowrite_cmd {
+	__u32 port;
+	__u32 arg;
+};
+
+struct virtioqxl_config {
+	__u32 configsize;
+	__u32 ramsize;
+	__u32 vramsize;
+	__u32 romsize;
+	__u32 virtiomem[0];
+};
+
+#define QXLMAGIC 'v'
+
+#define QXL_IOCTL_NOTIFY_CMD _IOW(QXLMAGIC,\
+					QXL_IO_NOTIFY_CMD, __u32)
+#define QXL_IOCTL_NOTIFY_CURSOR _IOW(QXLMAGIC, \
+					QXL_IO_NOTIFY_CURSOR, __u32)
+#define QXL_IOCTL_UPDATE_AREA _IOW(QXLMAGIC, \
+					QXL_IO_UPDATE_AREA, __u32)
+#define QXL_IOCTL_UPDATE_IRQ _IOW(QXLMAGIC, \
+					QXL_IO_UPDATE_IRQ, __u32)
+#define QXL_IOCTL_NOTIFY_OOM _IOW(QXLMAGIC, \
+					QXL_IO_NOTIFY_OOM, __u32)
+#define QXL_IOCTL_RESET _IOW(QXLMAGIC, \
+					QXL_IO_RESET, __u32)
+#define QXL_IOCTL_SET_MODE _IOW(QXLMAGIC, \
+					QXL_IO_SET_MODE, __u32)
+#define QXL_IOCTL_LOG _IOW(QXLMAGIC, \
+					QXL_IO_LOG, __u32)
+#define QXL_IOCTL_MEMSLOT_ADD _IOW(QXLMAGIC, \
+					QXL_IO_MEMSLOT_ADD, __u32)
+#define QXL_IOCTL_MEMSLOT_DEL _IOW(QXLMAGIC, \
+					QXL_IO_MEMSLOT_DEL, __u32)
+#define QXL_IOCTL_DETACH_PRIMARY _IOW(QXLMAGIC, \
+					QXL_IO_DETACH_PRIMARY, __u32)
+#define QXL_IOCTL_ATTACH_PRIMARY _IOW(QXLMAGIC, \
+					 QXL_IO_ATTACH_PRIMARY, __u32)
+#define QXL_IOCTL_CREATE_PRIMARY _IOW(QXLMAGIC, \
+					QXL_IO_CREATE_PRIMARY, __u32)
+#define QXL_IOCTL_DESTROY_PRIMARY _IOW(QXLMAGIC, \
+					QXL_IO_DESTROY_PRIMARY, __u32)
+#define QXL_IOCTL_DESTROY_SURFACE_WAIT _IOW(QXLMAGIC, \
+					QXL_IO_DESTROY_SURFACE_WAIT, __u32)
+#define QXL_IOCTL_DESTROY_ALL_SURFACES _IOW(QXLMAGIC, \
+					QXL_IO_DESTROY_ALL_SURFACES, __u32)
+#define QXL_IOCTL_UPDATE_AREA_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_UPDATE_AREA_ASYNC, __u32)
+#define QXL_IOCTL_MEMSLOT_ADD_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_MEMSLOT_ADD_ASYNC, __u32)
+#define QXL_IOCTL_CREATE_PRIMARY_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_CREATE_PRIMARY_ASYNC, __u32)
+#define QXL_IOCTL_DESTROY_PRIMARY_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_DESTROY_PRIMARY_ASYNC, __u32)
+#define QXL_IOCTL_DESTROY_SURFACE_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_DESTROY_SURFACE_ASYNC, __u32)
+#define QXL_IOCTL_DESTROY_ALL_SURFACES_ASYNC _IOW(QXLMAGIC, \
+				QXL_IO_DESTROY_ALL_SURFACES_ASYNC, __u32)
+#define QXL_IOCTL_FLUSH_SURFACES_ASYNC _IOW(QXLMAGIC, \
+					QXL_IO_FLUSH_SURFACES_ASYNC, __u32)
+#define QXL_IOCTL_FLUSH_RELEASE _IOW(QXLMAGIC, \
+					QXL_IO_FLUSH_RELEASE, __u32)
+#define QXL_IOCTL_QXL_IO_GETCFG _IOW(QXLMAGIC, \
+					QXL_IO_GETCFG, struct virtioqxl_config)
+#define QXL_IOCTL_QXL_IO_SET_RAMSTART _IOW(QXLMAGIC, \
+					QXL_IO_SET_RAMSTART, __u32)
+#endif /*  VIRTIO_BRIDGE_H */
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH v5] da8xx-fb: allow frame to complete after disabling LCDC
From: Manjunathappa, Prakash @ 2012-08-24 13:25 UTC (permalink / raw)
  To: linux-fbdev

Wait for active frame transfer to complete after disabling LCDC.
At the same this wait is not be required when there are sync and
underflow errors.
Patch applies for revision 2 of LCDC present am335x.
More information on disable and reset sequence can be found in
section 13.4.6 of AM335x TRM @www.ti.com/am335x.

Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
---
Applies on top of fbdev-next of Florian Tobias Schandinat's tree.
Since v4:
Minor nit, removed extra line.
Since v3:
Rely on frame done interrupt instead of polling for it.
Since v2:
Optimized the lcd_disable_raster function.
Since v1:
Changed the commit message, also added link to hardware specification.
 drivers/video/da8xx-fb.c |   52 +++++++++++++++++++++++++++++++++++----------
 1 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 7ae9d53..32f0d06 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -27,6 +27,7 @@
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
+#include <linux/wait.h>
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/console.h>
@@ -48,6 +49,7 @@
 #define LCD_PL_LOAD_DONE		BIT(6)
 #define LCD_FIFO_UNDERFLOW		BIT(5)
 #define LCD_SYNC_LOST			BIT(2)
+#define LCD_FRAME_DONE			BIT(0)
 
 /* LCD DMA Control Register */
 #define LCD_DMA_BURST_SIZE(x)		((x) << 4)
@@ -135,6 +137,8 @@ static resource_size_t da8xx_fb_reg_base;
 static struct resource *lcdc_regs;
 static unsigned int lcd_revision;
 static irq_handler_t lcdc_irq_handler;
+static wait_queue_head_t frame_done_wq;
+static int frame_done_flag;
 
 static inline unsigned int lcdc_read(unsigned int addr)
 {
@@ -288,13 +292,26 @@ static inline void lcd_enable_raster(void)
 }
 
 /* Disable the Raster Engine of the LCD Controller */
-static inline void lcd_disable_raster(void)
+static inline void lcd_disable_raster(bool wait_for_frame_done)
 {
 	u32 reg;
+	int ret;
 
 	reg = lcdc_read(LCD_RASTER_CTRL_REG);
 	if (reg & LCD_RASTER_ENABLE)
 		lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
+	else
+		/* return if already disabled */
+		return;
+
+	if ((wait_for_frame_done = true) && (lcd_revision = LCD_VERSION_2)) {
+		frame_done_flag = 0;
+		ret = wait_event_interruptible_timeout(frame_done_wq,
+				frame_done_flag != 0,
+				msecs_to_jiffies(50));
+		if (ret = 0)
+			pr_err("LCD Controller timed out\n");
+	}
 }
 
 static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
@@ -321,7 +338,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
 		} else {
 			reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
 				LCD_V2_END_OF_FRAME0_INT_ENA |
-				LCD_V2_END_OF_FRAME1_INT_ENA;
+				LCD_V2_END_OF_FRAME1_INT_ENA |
+				LCD_FRAME_DONE;
 			lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
 		}
 		reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
@@ -638,7 +656,7 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
 static void lcd_reset(struct da8xx_fb_par *par)
 {
 	/* Disable the Raster if previously Enabled */
-	lcd_disable_raster();
+	lcd_disable_raster(false);
 
 	/* DMA has to be disabled */
 	lcdc_write(0, LCD_DMA_CTRL_REG);
@@ -734,7 +752,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
 	u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
 
 	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
-		lcd_disable_raster();
+		lcd_disable_raster(false);
 		lcdc_write(stat, LCD_MASKED_STAT_REG);
 		lcd_enable_raster();
 	} else if (stat & LCD_PL_LOAD_DONE) {
@@ -744,7 +762,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
 		 * interrupt via the following write to the status register. If
 		 * this is done after then one gets multiple PL done interrupts.
 		 */
-		lcd_disable_raster();
+		lcd_disable_raster(false);
 
 		lcdc_write(stat, LCD_MASKED_STAT_REG);
 
@@ -775,6 +793,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
 			par->vsync_flag = 1;
 			wake_up_interruptible(&par->vsync_wait);
 		}
+
+		/* Set only when controller is disabled and at the end of
+		 * active frame
+		 */
+		if (stat & BIT(0)) {
+			frame_done_flag = 1;
+			wake_up_interruptible(&frame_done_wq);
+		}
 	}
 
 	lcdc_write(0, LCD_END_OF_INT_IND_REG);
@@ -789,7 +815,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
 	u32 reg_ras;
 
 	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
-		lcd_disable_raster();
+		lcd_disable_raster(false);
 		lcdc_write(stat, LCD_STAT_REG);
 		lcd_enable_raster();
 	} else if (stat & LCD_PL_LOAD_DONE) {
@@ -799,7 +825,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
 		 * interrupt via the following write to the status register. If
 		 * this is done after then one gets multiple PL done interrupts.
 		 */
-		lcd_disable_raster();
+		lcd_disable_raster(false);
 
 		lcdc_write(stat, LCD_STAT_REG);
 
@@ -898,7 +924,7 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
 	if (val = CPUFREQ_POSTCHANGE) {
 		if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) {
 			par->lcd_fck_rate = clk_get_rate(par->lcdc_clk);
-			lcd_disable_raster();
+			lcd_disable_raster(true);
 			lcd_calc_clk_divider(par);
 			lcd_enable_raster();
 		}
@@ -935,7 +961,7 @@ static int __devexit fb_remove(struct platform_device *dev)
 		if (par->panel_power_ctrl)
 			par->panel_power_ctrl(0);
 
-		lcd_disable_raster();
+		lcd_disable_raster(true);
 		lcdc_write(0, LCD_RASTER_CTRL_REG);
 
 		/* disable DMA  */
@@ -1051,7 +1077,7 @@ static int cfb_blank(int blank, struct fb_info *info)
 		if (par->panel_power_ctrl)
 			par->panel_power_ctrl(0);
 
-		lcd_disable_raster();
+		lcd_disable_raster(true);
 		break;
 	default:
 		ret = -EINVAL;
@@ -1356,8 +1382,10 @@ static int __devinit fb_probe(struct platform_device *device)
 
 	if (lcd_revision = LCD_VERSION_1)
 		lcdc_irq_handler = lcdc_irq_handler_rev01;
-	else
+	else {
+		init_waitqueue_head(&frame_done_wq);
 		lcdc_irq_handler = lcdc_irq_handler_rev02;
+	}
 
 	ret = request_irq(par->irq, lcdc_irq_handler, 0,
 			DRIVER_NAME, par);
@@ -1411,7 +1439,7 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state)
 		par->panel_power_ctrl(0);
 
 	fb_set_suspend(info, 1);
-	lcd_disable_raster();
+	lcd_disable_raster(true);
 	clk_disable(par->lcdc_clk);
 	console_unlock();
 
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH 02/23] OMAPDSS: outputs: Create and initialize output instances
From: Tomi Valkeinen @ 2012-08-24 13:14 UTC (permalink / raw)
  To: Archit Taneja; +Cc: linux-omap, linux-fbdev, rob, sumit.semwal
In-Reply-To: <1345528711-27801-3-git-send-email-archit@ti.com>

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

On Tue, 2012-08-21 at 11:28 +0530, Archit Taneja wrote:
> Create output instances by having an init function in the probes of the platform
> device drivers for different interfaces. Create a small function for each
> interface to initialize the output entity's fields type and id.
> 
> In the probe of each interface driver, the output entities are created before
> the *_probe_pdata() functions intentionally. This is done to ensure that the
> output entity is prepared before the panels connected to the output are
> registered. We need the output entities to be ready because OMAPDSS will try
> to make connections between overlays, managers, outputs and devices during the
> panel's probe.

You're referring to the recheck_connections stuff? I have a patch that
moves that to omapfb side. But of course it doesn't hurt to initialize
the output early.

We should generally do the initialization in output driver's probe more
or less so that we first setup everything related to the output driver,
and after that we register the dssdevs. But I think that's what is
already done.

So, no complaints =).

> Signed-off-by: Archit Taneja <archit@ti.com>
> ---
>  drivers/video/omap2/dss/dpi.c  |   20 ++++++++++++++++++++
>  drivers/video/omap2/dss/dsi.c  |   26 ++++++++++++++++++++++++--
>  drivers/video/omap2/dss/hdmi.c |   18 ++++++++++++++++++
>  drivers/video/omap2/dss/rfbi.c |   19 +++++++++++++++++++
>  drivers/video/omap2/dss/sdi.c  |   20 ++++++++++++++++++++
>  drivers/video/omap2/dss/venc.c |   20 ++++++++++++++++++++
>  6 files changed, 121 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
> index f260343..4eca2e7 100644
> --- a/drivers/video/omap2/dss/dpi.c
> +++ b/drivers/video/omap2/dss/dpi.c
> @@ -408,10 +408,30 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
>  	}
>  }
>  
> +static int __init dpi_init_output(struct platform_device *pdev)
> +{
> +	struct omap_dss_output *out;
> +
> +	out = dss_create_output(pdev);
> +	if (!out)
> +		return -ENOMEM;
> +
> +	out->id = OMAP_DSS_OUTPUT_DPI;
> +	out->type = OMAP_DISPLAY_TYPE_DPI;
> +
> +	return 0;
> +}
> +
>  static int __init omap_dpi_probe(struct platform_device *pdev)
>  {
> +	int r;
> +
>  	mutex_init(&dpi.lock);
>  
> +	r = dpi_init_output(pdev);
> +	if (r)
> +		return r;
> +
>  	dpi_probe_pdata(pdev);
>  
>  	return 0;
> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> index 659b6cd..22e0873 100644
> --- a/drivers/video/omap2/dss/dsi.c
> +++ b/drivers/video/omap2/dss/dsi.c
> @@ -4903,6 +4903,23 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
>  	}
>  }
>  
> +static int __init dsi_init_output(struct platform_device *dsidev,
> +		struct dsi_data *dsi)
> +{
> +	struct omap_dss_output *out;
> +
> +	out = dss_create_output(dsidev);
> +	if (!out)
> +		return -ENOMEM;
> +
> +	out->id = dsi->module_id == 0 ?
> +			OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
> +
> +	out->type = OMAP_DISPLAY_TYPE_DSI;
> +
> +	return 0;

As I mentioned in the last email, I think this could be something like:

struct omap_dss_output *out = &dsi->output;

out->pdev = dsidev;
out->id = xxx;
out->type = yyy;
dss_register_output(out);


> +}
> +
>  /* DSI1 HW IP initialisation */
>  static int __init omap_dsihw_probe(struct platform_device *dsidev)
>  {
> @@ -4997,10 +5014,14 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
>  	else
>  		dsi->num_lanes_supported = 3;
>  
> -	dsi_probe_pdata(dsidev);
> -
>  	dsi_runtime_put(dsidev);
>  
> +	r = dsi_init_output(dsidev, dsi);
> +	if (r)
> +		goto err_init_output;
> +
> +	dsi_probe_pdata(dsidev);
> +

Why do you change the sequence here? Isn't it enough to just add the
init_output before probe_pdata?

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 01/23] OMAPDSS: outputs: Create a new entity called outputs
From: Archit Taneja @ 2012-08-24 12:53 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: Archit Taneja, linux-omap, linux-fbdev, rob, sumit.semwal
In-Reply-To: <1345812069.9287.65.camel@lappyti>

On Friday 24 August 2012 06:11 PM, Tomi Valkeinen wrote:
> On Tue, 2012-08-21 at 11:28 +0530, Archit Taneja wrote:
>
>> diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
>> new file mode 100644
>> index 0000000..034ebbe
>> --- /dev/null
>> +++ b/drivers/video/omap2/dss/output.c
>> @@ -0,0 +1,58 @@
>> +/*
>> + * Copyright (C) 2012 Texas Instruments Ltd
>> + * Author: Archit Taneja <archit@ti.com>
>> + *
>> + * 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 published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/slab.h>
>> +
>> +#include <video/omapdss.h>
>> +
>> +#include "dss.h"
>> +
>> +static struct list_head output_list;
>
> You can do:
>
> static LIST_HEAD(output_list);
>
> Then you don't need to initialize it separately.

Oh ok. I'll fix this.

>
>> +
>> +struct omap_dss_output *dss_create_output(struct platform_device *pdev)
>> +{
>> +	struct omap_dss_output *out;
>> +
>> +	out = kzalloc(sizeof(struct omap_dss_output *), GFP_KERNEL);
>> +	if (!out)
>> +		return NULL;
>
> A patch that adds kzalloc but no free is always a bit suspicious =).
>
>> +
>> +	out->pdev = pdev;
>> +
>> +	list_add_tail(&out->list, &output_list);
>> +
>> +	return out;
>> +}
>
> Instead of allocating omap_dss_output here, you could let the caller do
> it, and only initialize it here with default values (if that's even
> needed). Then the caller can use kzalloc, or can just embed the stuct
> into its own data-struct, which may be often a better choice.

So output can be in each interface driver's private data, and we just 
add that to our list of outputs?

>
>> +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
>> +{
>> +	struct omap_dss_output *out;
>> +
>> +	list_for_each_entry(out, &output_list, list) {
>> +		if (out->id = id)
>> +			return out;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +void dss_init_outputs(void)
>> +{
>> +	INIT_LIST_HEAD(&output_list);
>> +}
>> diff --git a/include/video/omapdss.h b/include/video/omapdss.h
>> index b868123..0ba613f 100644
>> --- a/include/video/omapdss.h
>> +++ b/include/video/omapdss.h
>> @@ -207,6 +207,16 @@ enum omap_hdmi_flags {
>>   	OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0,
>>   };
>>
>> +enum omap_dss_output_id {
>> +	OMAP_DSS_OUTPUT_DPI	= 1 << 0,
>> +	OMAP_DSS_OUTPUT_DBI	= 1 << 1,
>> +	OMAP_DSS_OUTPUT_SDI	= 1 << 2,
>> +	OMAP_DSS_OUTPUT_DSI1	= 1 << 3,
>> +	OMAP_DSS_OUTPUT_VENC	= 1 << 4,
>> +	OMAP_DSS_OUTPUT_DSI2	= 1 << 5,
>> +	OMAP_DSS_OUTPUT_HDMI	= 1 << 6,
>> +};
>
> I'm not sure about this. We already have enum omap_display_type. If you
> need the instance number, you could have that as a separate int field.
>
> Where do you need the output_id?

output_id is used to take care of situations where there our multiple 
outputs of the same type, like DSI1 and DSI2. An enum helps when we 
check if an overlay manager supports that output instance or not. For 
ex, on OMAP4, LCD1 connects to DSI1 and not DSI2.

I add a func called dss_feat_get_supported_outputs(channel) later to 
check for this. When setting a new output for a manager, we just do an 
'&' to see if the output in question is in the mask of the manager's set 
of supported outputs.

>
>> +
>>   /* RFBI */
>>
>>   struct rfbi_timings {
>> @@ -492,6 +502,24 @@ struct omap_dsi_pin_config {
>>   	int pins[OMAP_DSS_MAX_DSI_PINS];
>>   };
>>
>> +struct omap_dss_output {
>> +	struct list_head list;
>> +
>> +	/* display type supported by the output */
>> +	enum omap_display_type type;
>> +
>> +	/* output instance */
>> +	enum omap_dss_output_id id;
>
> So instead of omap_dss_output_id, you'd have omap_display_type type and
> int id, which together tell the supported output and also the output
> driver instance.
>
>   Tomi
>


^ permalink raw reply

* Re: [PATCH 01/23] OMAPDSS: outputs: Create a new entity called outputs
From: Tomi Valkeinen @ 2012-08-24 12:41 UTC (permalink / raw)
  To: Archit Taneja; +Cc: linux-omap, linux-fbdev, rob, sumit.semwal
In-Reply-To: <1345528711-27801-2-git-send-email-archit@ti.com>

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

On Tue, 2012-08-21 at 11:28 +0530, Archit Taneja wrote:

> diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
> new file mode 100644
> index 0000000..034ebbe
> --- /dev/null
> +++ b/drivers/video/omap2/dss/output.c
> @@ -0,0 +1,58 @@
> +/*
> + * Copyright (C) 2012 Texas Instruments Ltd
> + * Author: Archit Taneja <archit@ti.com>
> + *
> + * 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 published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include <video/omapdss.h>
> +
> +#include "dss.h"
> +
> +static struct list_head output_list;

You can do:

static LIST_HEAD(output_list);

Then you don't need to initialize it separately.

> +
> +struct omap_dss_output *dss_create_output(struct platform_device *pdev)
> +{
> +	struct omap_dss_output *out;
> +
> +	out = kzalloc(sizeof(struct omap_dss_output *), GFP_KERNEL);
> +	if (!out)
> +		return NULL;

A patch that adds kzalloc but no free is always a bit suspicious =).

> +
> +	out->pdev = pdev;
> +
> +	list_add_tail(&out->list, &output_list);
> +
> +	return out;
> +}

Instead of allocating omap_dss_output here, you could let the caller do
it, and only initialize it here with default values (if that's even
needed). Then the caller can use kzalloc, or can just embed the stuct
into its own data-struct, which may be often a better choice.

> +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
> +{
> +	struct omap_dss_output *out;
> +
> +	list_for_each_entry(out, &output_list, list) {
> +		if (out->id == id)
> +			return out;
> +	}
> +
> +	return NULL;
> +}
> +
> +void dss_init_outputs(void)
> +{
> +	INIT_LIST_HEAD(&output_list);
> +}
> diff --git a/include/video/omapdss.h b/include/video/omapdss.h
> index b868123..0ba613f 100644
> --- a/include/video/omapdss.h
> +++ b/include/video/omapdss.h
> @@ -207,6 +207,16 @@ enum omap_hdmi_flags {
>  	OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0,
>  };
>  
> +enum omap_dss_output_id {
> +	OMAP_DSS_OUTPUT_DPI	= 1 << 0,
> +	OMAP_DSS_OUTPUT_DBI	= 1 << 1,
> +	OMAP_DSS_OUTPUT_SDI	= 1 << 2,
> +	OMAP_DSS_OUTPUT_DSI1	= 1 << 3,
> +	OMAP_DSS_OUTPUT_VENC	= 1 << 4,
> +	OMAP_DSS_OUTPUT_DSI2	= 1 << 5,
> +	OMAP_DSS_OUTPUT_HDMI	= 1 << 6,
> +};

I'm not sure about this. We already have enum omap_display_type. If you
need the instance number, you could have that as a separate int field.

Where do you need the output_id?

> +
>  /* RFBI */
>  
>  struct rfbi_timings {
> @@ -492,6 +502,24 @@ struct omap_dsi_pin_config {
>  	int pins[OMAP_DSS_MAX_DSI_PINS];
>  };
>  
> +struct omap_dss_output {
> +	struct list_head list;
> +
> +	/* display type supported by the output */
> +	enum omap_display_type type;
> +
> +	/* output instance */
> +	enum omap_dss_output_id id;

So instead of omap_dss_output_id, you'd have omap_display_type type and
int id, which together tell the supported output and also the output
driver instance.

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v4 1/3] Runtime Interpreted Power Sequences
From: Tomi Valkeinen @ 2012-08-24 10:34 UTC (permalink / raw)
  To: Alex Courbot
  Cc: Thierry Reding, Stephen Warren, Simon Glass, Grant Likely,
	Rob Herring, Mark Brown, Anton Vorontsov, David Woodhouse,
	Arnd Bergmann, Leela Krishna Amudala, linux-tegra@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, linux-doc@vger.kernel.org
In-Reply-To: <6044581.2jEzZBWCu1@percival>

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

On Fri, 2012-08-24 at 18:24 +0900, Alex Courbot wrote:
> On Tuesday 21 August 2012 17:54:20 Tomi Valkeinen wrote:

> > And as I said, I don't have any problems with some kind of generic power
> > sequences. So the code in the board file could be moved and converted to
> > use the power sequences, if that is better than just plain c code.
> 
> My concern now is, provided that all drivers to their job and handle how their 
> devices are switched on and off, when (if at all) are encoded power sequences 
> better than their equivalent C code? There is the matching database size issue 
> that you mentionned, is it a sufficient concern to justify a new kernel feature?

Good question.

I think obviously the worst solution is to have separate .c driver files
for each panel, where the drivers do 99% the same thing.

So the question is how to represent the 1% difference the panels have.

I think it depends on the panels. If it looks like all the panel have,
say, max 2 regulators and one reset/enable gpio, and they are always
enabled in the same order (regulators first, then the gpio), it should
be easy to handle it in the driver without any power sequence framework.

If the panels require more complex setups, then the code in the panel
driver would probably start to form into a power sequence framework, and
it would make sense to have it as a separate framework.

Then again, if the panel setup is complex, it makes me wonder if it'd be
just easier to handle it with c code in a separate driver.

Also, the database size issue is a bit separate issue. There's the db
size problem with or without the framework, if we do not pass the data
from DT.

So as clarification, I see 4 different options:
- Power sequences in DT (as proposed in this series)
- Custom panel data in DT, that the driver uses to power up properly
- Power sequences in a panel database in kernel
- Custom panel data in a panel db in kernel

> On the other hand some devices like panels are typically not used in many 
> different appliances, so maybe it is not worth to separate them from their 

Yep, this is the reason for my concern with the database size. The DB
could contain 10k panels, of which a board uses one. The rest just waste
memory. But then again, 10k panels is probably not a realistic amount.
It's difficult to guess the amount of memory used by such a database,
though. If it uses, say, 8kB, I'm not sure if it's a reason to panic.

And, as I mentioned, it could be optimized so that the driver throws
away the unneeded panels at __init. Of course here the problem is that
the panel needs to know what panels are needed.

> board definition. As Mark mentionned, having .dtsi files for the DT (and their 
> equivalent .h for kernels that use platform data) might be a good middle 
> ground.

I guess it's the perfectionist in me that leans toward handling it fully
in the kernel, as I think that's architecturally correct thing to do.
The DT data should contain parameters that can be configured per board,
or nodes (like regulators) that are needed by other parts of the DT
data.

If the only reason why to do it via DT is to avoid the possible size
problem with the panel database, perhaps what we should solve is the
optimization of the database. If that seems unsolvable, then DT approach
could be used as a workaround.

And I have to say I'm not too familiar with DT, so if I'm wrong about
what DT should contain, I'm all ears =).

 Tomi


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 6/8] OMAPDSS: DSI: calculate dsi clock
From: Archit Taneja @ 2012-08-24  9:29 UTC (permalink / raw)
  To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev
In-Reply-To: <1345798540.2614.17.camel@deskari>

On Friday 24 August 2012 02:25 PM, Tomi Valkeinen wrote:
> On Fri, 2012-08-24 at 11:46 +0530, Archit Taneja wrote:
>> On Thursday 23 August 2012 07:15 PM, Tomi Valkeinen wrote:
>
>>> +	/* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */
>>
>> This formula looks a bit simplified, we aren't considering the header
>> and footers of long packets that will add to the DDR clock. But I guess
>> not considering these would only give a higher pixel clock than needed,
>> which isn't that bad.
>
> Hmm. The TRM (omap4460) gives this formula in "10.3.4.5.12 How to
> Configure the DSI PLL in Video Mode". The headers/footers etc. are
> handled with adjusting the blanking periods so that DISPC and DSI Tline
> times match.
>
> But obviously they are not used for command mode transfers, so perhaps
> you have a point there. Then again, at least in theory, in command mode
> the DISPC pck should be configurable as high as possible because the
> stall mechanism should stop DISPC when DSI has had enough. And so the
> pck calculation is a bit unneeded for cmd mode, we could just configure
> pck to max.
>
> But if it's correct for video mode, and very close for cmd mode, I guess
> it should be fine?

Yes, it's fine, and we shouldn't try to have an unnecessarily high pixel 
clock in command mode anyway, that would reduce the amount of 
downscaling we could do.

Archit


^ permalink raw reply


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