Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] include: fb: Add definiton for window positioning
From: Baruch Siach @ 2011-09-20 11:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316532641-2657-2-git-send-email-ajaykumar.rs@samsung.com>

Hi Ajay,

On Tue, Sep 20, 2011 at 11:30:39AM -0400, Ajay Kumar wrote:
> This patch adds a data structure definiton to hold framebuffer windows/planes.
> An ioctl number is also added to provide user access
> to change window position dynamically.

[snip]

> +/* Window overlaying */
> +struct fb_overlay_win_pos {
> +	__u32 win_pos_x;	/* x-offset from LCD(0,0) where window starts */
> +	__u32 win_pos_y;	/* y-offset from LCD(0,0) where window starts */
> +};

Why not allow negative offsets where the left or upper part of the framebuffer 
is hidden?

baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{   - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

^ permalink raw reply

* Re: [PATCH 1/3] include: fb: Add definiton for window positioning
From: Tomi Valkeinen @ 2011-09-20 11:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316532641-2657-2-git-send-email-ajaykumar.rs@samsung.com>

On Tue, 2011-09-20 at 11:30 -0400, Ajay Kumar wrote:
> This patch adds a data structure definiton to hold framebuffer windows/planes.
> An ioctl number is also added to provide user access
> to change window position dynamically.
> 
> Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
> Signed-off-by: Banajit Goswami <banajit.g@samsung.com>
> Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
>  include/linux/fb.h |    7 +++++++
>  1 files changed, 7 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index 1d6836c..2141941 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -39,6 +39,7 @@
>  #define FBIOPUT_MODEINFO        0x4617
>  #define FBIOGET_DISPINFO        0x4618
>  #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
> +#define FBIOPOS_OVERLAY_WIN	_IOW('F', 0x21, struct fb_overlay_win_pos)
>  
>  #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
>  #define FB_TYPE_PLANES			1	/* Non interleaved planes */
> @@ -366,6 +367,12 @@ struct fb_image {
>  	struct fb_cmap cmap;	/* color map info */
>  };
>  
> +/* Window overlaying */
> +struct fb_overlay_win_pos {
> +	__u32 win_pos_x;	/* x-offset from LCD(0,0) where window starts */
> +	__u32 win_pos_y;	/* y-offset from LCD(0,0) where window starts */
> +};

Shouldn't this also include the window size (in case scaling is
supported)?

This also won't work for setups where the same framebuffer is used by
multiple overlays. For example, this is the case on OMAP when the same
content is cloned to, say, LCD and TV, each of which is showing an
overlay.

 Tomi



^ permalink raw reply

* [PATCH 2/3] ARM: SAMSUNG: Embed window positioning data structure in
From: Ajay Kumar @ 2011-09-20  9:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316532641-2657-1-git-send-email-ajaykumar.rs@samsung.com>

This patch adds a new field in s3c_fb_pd_win structure,
thereby allowing the user to place window at the desired position.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Banajit Goswami <banajit.g@samsung.com>
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 arch/arm/plat-samsung/include/plat/fb.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index 0fedf47..920decd 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -27,6 +27,7 @@
  * @win_mode: The display parameters to initialise (not for window 0)
  * @virtual_x: The virtual X size.
  * @virtual_y: The virtual Y size.
+ * @winpos: Position of overlayed window w.r.t the LCD screen.
  */
 struct s3c_fb_pd_win {
 	struct fb_videomode	win_mode;
@@ -35,6 +36,8 @@ struct s3c_fb_pd_win {
 	unsigned short		max_bpp;
 	unsigned short		virtual_x;
 	unsigned short		virtual_y;
+
+	struct fb_overlay_win_pos	winpos;
 };
 
 /**
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 3/3] video: s3c-fb: Modify s3c-fb driver to support window
From: Ajay Kumar @ 2011-09-20  9:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316532641-2657-1-git-send-email-ajaykumar.rs@samsung.com>

Positions the framebuffer window during driver initialization,
using the platform data.It also adds an ioctl definition
to change window position dynamically.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Banajit Goswami <banajit.g@samsung.com>
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 drivers/video/s3c-fb.c |   37 ++++++++++++++++++++++++++++++++-----
 1 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 0fda252..b087a12 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -441,6 +441,7 @@ static int s3c_fb_set_par(struct fb_info *info)
 {
 	struct fb_var_screeninfo *var = &info->var;
 	struct s3c_fb_win *win = info->par;
+	struct fb_overlay_win_pos *winpos = &win->windata->winpos;
 	struct s3c_fb *sfb = win->parent;
 	void __iomem *regs = sfb->regs;
 	void __iomem *buf = regs;
@@ -539,12 +540,13 @@ static int s3c_fb_set_par(struct fb_info *info)
 
 	/* write 'OSD' registers to control position of framebuffer */
 
-	data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
+	data = VIDOSDxA_TOPLEFT_X(winpos->win_pos_x) |
+	       VIDOSDxA_TOPLEFT_Y(winpos->win_pos_y);
 	writel(data, regs + VIDOSD_A(win_no, sfb->variant));
 
-	data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
-						     var->xres - 1)) |
-	       VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
+	data = VIDOSDxB_BOTRIGHT_X((s3c_fb_align_word(var->bits_per_pixel,
+	       (winpos->win_pos_x + var->xres - 1)))) |
+	       VIDOSDxB_BOTRIGHT_Y((winpos->win_pos_y + var->yres - 1));
 
 	writel(data, regs + VIDOSD_B(win_no, sfb->variant));
 
@@ -998,9 +1000,11 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
 	struct s3c_fb_win *win = info->par;
+	struct fb_overlay_win_pos *winpos = &win->windata->winpos;
 	struct s3c_fb *sfb = win->parent;
-	int ret;
+	int ret = 0;
 	u32 crtc;
+	u32 data;
 
 	switch (cmd) {
 	case FBIO_WAITFORVSYNC:
@@ -1011,6 +1015,29 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
 
 		ret = s3c_fb_wait_for_vsync(sfb, crtc);
 		break;
+	case FBIOPOS_OVERLAY_WIN:
+		if (copy_from_user(winpos, (u32 __user *)arg,
+					sizeof(struct fb_overlay_win_pos))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		shadow_protect_win(win, 1);
+
+		/* write 'OSD' registers to set position of the window */
+		data = VIDOSDxA_TOPLEFT_X(winpos->win_pos_x) |
+		       VIDOSDxA_TOPLEFT_Y(winpos->win_pos_y);
+		writel(data, sfb->regs + VIDOSD_A(win->index, sfb->variant));
+
+		data = VIDOSDxB_BOTRIGHT_X(
+				s3c_fb_align_word(info->var.bits_per_pixel,
+				(winpos->win_pos_x + info->var.xres - 1)));
+		data |=	VIDOSDxB_BOTRIGHT_Y(winpos->win_pos_y +
+				info->var.yres - 1);
+		writel(data, sfb->regs + VIDOSD_B(win->index, sfb->variant));
+
+		shadow_protect_win(win, 0);
+		break;
 	default:
 		ret = -ENOTTY;
 	}
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/3] include: fb: Add definiton for window positioning structure
From: Ajay Kumar @ 2011-09-20  9:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316532641-2657-1-git-send-email-ajaykumar.rs@samsung.com>

This patch adds a data structure definiton to hold framebuffer windows/planes.
An ioctl number is also added to provide user access
to change window position dynamically.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Banajit Goswami <banajit.g@samsung.com>
Suggested-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 include/linux/fb.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/fb.h b/include/linux/fb.h
index 1d6836c..2141941 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -39,6 +39,7 @@
 #define FBIOPUT_MODEINFO        0x4617
 #define FBIOGET_DISPINFO        0x4618
 #define FBIO_WAITFORVSYNC	_IOW('F', 0x20, __u32)
+#define FBIOPOS_OVERLAY_WIN	_IOW('F', 0x21, struct fb_overlay_win_pos)
 
 #define FB_TYPE_PACKED_PIXELS		0	/* Packed Pixels	*/
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
@@ -366,6 +367,12 @@ struct fb_image {
 	struct fb_cmap cmap;	/* color map info */
 };
 
+/* Window overlaying */
+struct fb_overlay_win_pos {
+	__u32 win_pos_x;	/* x-offset from LCD(0,0) where window starts */
+	__u32 win_pos_y;	/* y-offset from LCD(0,0) where window starts */
+};
+
 /*
  * hardware cursor control
  */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 0/3] FB: Add window positioning support
From: Ajay Kumar @ 2011-09-20  9:28 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset adds support for positioning the overlay windows on the LCD.

These patches are based on the discussion about adding features to fbdev at:
http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg06292.html

To Florian:
  	include: fb: Add definiton for window positioning structure
  	video: s3c-fb: Modify s3c-fb driver to support window positioning

To Kukjin,
  	ARM: SAMSUNG: Embed window positioning data structure in s3c-fb plat
  		      data

 arch/arm/plat-samsung/include/plat/fb.h |    3 ++
 drivers/video/s3c-fb.c                  |   37 ++++++++++++++++++++++++++----
 include/linux/fb.h                      |    7 ++++++
 3 files changed, 42 insertions(+), 5 deletions(-)


^ permalink raw reply

* Re: Proposal for a low-level Linux display framework
From: Patrik Jakobsson @ 2011-09-20  8:29 UTC (permalink / raw)
  To: Tomi Valkeinen
  Cc: linaro-dev, linux-fbdev, dri-devel, linux-kernel, Archit Taneja,
	Clark, Rob
In-Reply-To: <1316417361.1978.48.camel@deskari>

On Mon, Sep 19, 2011 at 9:29 AM, Tomi Valkeinen wrote:
>> So DSI is more like i2c than the DisplayPort aux channel or DDC. That
>
> Well, not quite. DSI is like DisplayPort and DisplayPort aux combined;
> there's only one bus, DSI, which is used to transfer video data and
> commands.
>
> For DSI video mode, the transfer is somewhat like traditional displays,
> and video data is send according to a pixel clock as a constant stream.
> However, before the video stream is enabled the bus can be used in
> bi-directional communication. And even when the video stream is enabled,
> there can be other communication in the blanking periods.

This sounds a lot like SDVO. You communicate with the SDVO chip through
i2c and then do a bus switch to get to the DDC. You also have the GMBus
with interrupt support that can help you do the i2c transfers.

SDVO supports many connectors and can have multiple in and out channels
so some setups are a bit complicated.

It would be nice to have a model that fits both DSI and SDVO, and the option
to configure some of it from userspace.

I thought the purpose of drm_encoder was to abstract hardware like this?

-Patrik

^ permalink raw reply

* Re: Proposal for a low-level Linux display framework
From: Tomi Valkeinen @ 2011-09-19  7:29 UTC (permalink / raw)
  To: Keith Packard
  Cc: Alan Cox, linux-fbdev, linux-kernel, dri-devel, linaro-dev,
	Clark, Rob, Archit Taneja
In-Reply-To: <yunfwjtauqg.fsf@aiko.keithp.com>

On Sun, 2011-09-18 at 23:53 -0700, Keith Packard wrote:
> On Mon, 19 Sep 2011 09:33:34 +0300, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> 
> > I think it's a bit more complex than that. True, there are MIPI
> > standards, for the video there are DPI, DBI, DSI, and for the commands
> > there is DCS. And, as you mentioned, many panels need custom
> > initialization, or support only parts of the DCS, or have other
> > quirks.
> 
> So DSI is more like i2c than the DisplayPort aux channel or DDC. That

Well, not quite. DSI is like DisplayPort and DisplayPort aux combined;
there's only one bus, DSI, which is used to transfer video data and
commands.

For DSI video mode, the transfer is somewhat like traditional displays,
and video data is send according to a pixel clock as a constant stream.
However, before the video stream is enabled the bus can be used in
bi-directional communication. And even when the video stream is enabled,
there can be other communication in the blanking periods.

For DSI command mode the transfer is a bit like high speed i2c; messages
are sent when needed (when the userspace gives the command to update),
without any strict timings. In practice this means that the peripheral
needs to have a framebuffer memory of its own, which it uses to refresh
the actual panel (or send the pixels forward to another peripheral).

As the use patterns of these two types of displays are quite different,
we have the terms auto-update and manual-update displays for them.

> seems fine; you can create a DSI infrastructure like the i2c
> infrastructure and then just have your display drivers use it to talk to
> the panel. We might eventually end up with some shared DRM code to deal
> with common DSI functions for display devices, like the EDID code
> today, but that doesn't need to happen before you can write your first
> DSI-using display driver.

One difference with i2c and DSI is that i2c is independent of the video
path, so it's easy to keep that separate from DRM. But for DSI the data
is produced by the video hardware using the overlays, encoders etc. I
don't quite see how we could have an i2c-like separate DSI API, which
wasn't part of DRM.

And even in simpler case MIPI DPI, which is a traditional parallel RGB
interface, a panel may need custom configuration via, say, i2c or spi.
We can, of course, create a i2c device driver for the panel, but how is
that then connected to DRM? The i2c driver may need to know things like
when the display is enabled/disabled, about backlight changes, or any
other display related event.

Is there a way for the i2c driver to get these events, and add new
properties to the DRM (say, if the panel has a feature configured via
i2c, but we'd like it to be visible to the userspace via the DRM
driver)?

 Tomi



^ permalink raw reply

* Re: Proposal for a low-level Linux display framework
From: Keith Packard @ 2011-09-19  6:53 UTC (permalink / raw)
  To: Tomi Valkeinen, Alan Cox
  Cc: linux-fbdev, linaro-dev, linux-kernel, dri-devel, Archit Taneja,
	Clark, Rob
In-Reply-To: <1316414014.1978.12.camel@deskari>

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

On Mon, 19 Sep 2011 09:33:34 +0300, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:

> I think it's a bit more complex than that. True, there are MIPI
> standards, for the video there are DPI, DBI, DSI, and for the commands
> there is DCS. And, as you mentioned, many panels need custom
> initialization, or support only parts of the DCS, or have other
> quirks.

So DSI is more like i2c than the DisplayPort aux channel or DDC. That
seems fine; you can create a DSI infrastructure like the i2c
infrastructure and then just have your display drivers use it to talk to
the panel. We might eventually end up with some shared DRM code to deal
with common DSI functions for display devices, like the EDID code
today, but that doesn't need to happen before you can write your first
DSI-using display driver.

-- 
keith.packard@intel.com

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCHv2 09/15] OMAP: DSS2: HDMI: implement detect()
From: Tomi Valkeinen @ 2011-09-19  6:50 UTC (permalink / raw)
  To: K, Mythri P; +Cc: Rob Clark, linux-omap, linux-fbdev, archit
In-Reply-To: <CAP5A+B9upB3VUaRme84Fm6ewx9KkyOu4hCavMetkEeKcSHORXw@mail.gmail.com>

On Fri, 2011-09-16 at 18:11 +0530, K, Mythri P wrote:
> Hi,

> >> Sequence with HPD:
> >> 1.Register for HPD connect.
> >> 2.Enable display
> >> 3.Notify DRM/Audio/Kernel component that wants to listen to this event.
> >
> > Why would you enable the display even if there's no monitor connected?
> >
> > And when the DRM starts, how does DRM know if the display was already
> > connected? Would you send a HPD event when DRM registers to the event
> > even if there's no actual plug-in event done (i.e. user actually
> > connecting the cable)?
> >
> HPD event would be triggered only when the cable is connected , and
> the EDID is ready to be read by the monitor. So the question enabling
> display doesnt exist. When HDMI is enabled in the HPD mode it will be
> in minimal power mode.

I don't think that will work correctly. "enable" in the current driver
means that the DISPC output will be enabled, and the display is showing
an image.

How would you implement the case with your model where the user wants to
get the EDID information, but doesn't want to enable the display yet
(send an output signal)?

I think we need a new power state for the displays. DSI panels could use
it also, as there's a need to turn them on for configuration before
actually turning on the actual display.

 Tomi



^ permalink raw reply

* Re: Proposal for a low-level Linux display framework
From: Tomi Valkeinen @ 2011-09-19  6:33 UTC (permalink / raw)
  To: Alan Cox
  Cc: Keith Packard, linux-fbdev, linux-kernel, dri-devel, linaro-dev,
	Clark, Rob, Archit Taneja
In-Reply-To: <20110916175326.54567b14@lxorguk.ukuu.org.uk>

On Fri, 2011-09-16 at 17:53 +0100, Alan Cox wrote:
> > I'm not sure a common interface to all of these different
> > channels makes sense, but surely a DSI library and an aux channel
> > library would fit nicely alongside the existing DDC library.
> 
> DSI and the various other MIPI bits tend to be horribly panel and device
> specific. In one sense yes its a standard with standard commands,
> processes, queries etc, on the other a lot of stuff is oriented around
> the 'its a fixed configuration unit we don't need to have queries' view.

I think it's a bit more complex than that. True, there are MIPI
standards, for the video there are DPI, DBI, DSI, and for the commands
there is DCS. And, as you mentioned, many panels need custom
initialization, or support only parts of the DCS, or have other quirks.

However, I think the biggest thing to realize here is that DSI
peripherals can be anything. It's not always so that you have a DSI bus
and a single panel connected to it. You can have hubs, buffer chips,
etc.

We need DSI peripheral device drivers for those, a single "DSI output"
driver cannot work. And this is also the most important thing in my
original proposition.

> There also tends to be a lot of vendor magic initialisation logic both
> chipset and device dependant, and often 'plumbing dependant' on SoC

While I have DSI experience with only one SoC, I do believe it'd be
possible to create a DSI API that would allow us to have platform
independent DSI peripheral drivers.

Can you share any SoC side DSI peculiarities on Intel's SoCs?

 Tomi



^ permalink raw reply

* linux-next: manual merge of the fbdev tree with the mips tree
From: Stephen Rothwell @ 2011-09-19  6:22 UTC (permalink / raw)
  To: Florian Tobias Schandinat, linux-fbdev
  Cc: linux-next, linux-kernel, Manuel Lauss, Ralf Baechle, Paul Mundt

Hi all,

Today's linux-next merge of the fbdev tree got a conflict in
drivers/video/Kconfig between commit 9d7dec27ace1 ("MIPS: Alchemy: remove
all CONFIG_SOC_AU1??? defines") from the mips tree and commit
4ee584615102 ("au1200fb: switch to FB_SYS helpers") from the fbdev tree.

Just context changes. I fixed it up (see below) and can carry the fix as
necessary.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc drivers/video/Kconfig
index 55a7df4,8165c55..0000000
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@@ -1755,10 -1764,11 +1764,11 @@@ config FB_AU110
  
  config FB_AU1200
  	bool "Au1200 LCD Driver"
 -	depends on (FB = y) && MIPS && SOC_AU1200
 +	depends on (FB = y) && MIPS_ALCHEMY
- 	select FB_CFB_FILLRECT
- 	select FB_CFB_COPYAREA
- 	select FB_CFB_IMAGEBLIT
+ 	select FB_SYS_FILLRECT
+ 	select FB_SYS_COPYAREA
+ 	select FB_SYS_IMAGEBLIT
+ 	select FB_SYS_FOPS
  	help
  	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
  	  various panels and CRTs by passing in kernel cmd line option

^ permalink raw reply

* [WIP/RFC 31/31] fbdev: sh_mobile_lcdc: Add media controller support
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/Kconfig            |    1 +
 drivers/video/sh_mobile_lcdcfb.c |  116 ++++++++++++++++++++++++++++++++++++--
 drivers/video/sh_mobile_lcdcfb.h |    8 +++
 3 files changed, 120 insertions(+), 5 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 549b960..c18e1b8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1977,6 +1977,7 @@ config FB_SH_MOBILE_LCDC
 	select FB_SYS_FOPS
 	select FB_DEFERRED_IO
 	select FB_BACKLIGHT
+	select MEDIA_CONTROLLER
 	select SH_MIPI_DSI if SH_LCD_MIPI_DSI
 	---help---
 	  Frame buffer driver for the on-chip SH-Mobile LCD controller.
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 19ac3c5..ac8b82d 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -26,6 +26,9 @@
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 
+#include <media/media-device.h>
+#include <media/media-entity.h>
+
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mobile_meram.h>
 
@@ -38,17 +41,22 @@
 #define MAX_YRES 1080
 
 struct sh_mobile_lcdc_priv {
+	struct media_device mdev;
+	struct device *dev;
+	struct sh_mobile_meram_info *meram_dev;
+
 	void __iomem *base;
 	int irq;
-	atomic_t hw_usecnt;
-	struct device *dev;
 	struct clk *dot_clk;
+
+	atomic_t hw_usecnt;
 	unsigned long lddckr;
+
 	struct sh_mobile_lcdc_chan ch[2];
 	struct notifier_block notifier;
+
 	int started;
 	int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
-	struct sh_mobile_meram_info *meram_dev;
 };
 
 /* -----------------------------------------------------------------------------
@@ -1532,6 +1540,84 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
 }
 
 /* -----------------------------------------------------------------------------
+ * Media controller init/cleanup
+ */
+
+static int __devinit sh_mobile_lcdc_media_init(struct sh_mobile_lcdc_chan *ch)
+{
+	int ret;
+
+	/* Initialize the panel media entity. */
+	ch->panel.pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&ch->panel.entity, 1, &ch->panel.pad, 0);
+	if (ret < 0)
+		return ret;
+
+	ch->panel.entity.name = "Panel";
+
+	/* Create links. */
+	if (ch->tx_dev) {
+		ret = media_entity_create_link(&ch->info->entity, 0,
+					       &ch->tx_dev->entity, 0,
+					       MEDIA_LNK_FL_IMMUTABLE |
+					       MEDIA_LNK_FL_ENABLED);
+		if (ret < 0)
+			return ret;
+
+		ret = media_entity_create_link(&ch->tx_dev->entity, 1,
+					       &ch->panel.entity, 0,
+					       MEDIA_LNK_FL_IMMUTABLE |
+					       MEDIA_LNK_FL_ENABLED);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = media_entity_create_link(&ch->info->entity, 0,
+					       &ch->panel.entity, 0,
+					       MEDIA_LNK_FL_IMMUTABLE |
+					       MEDIA_LNK_FL_ENABLED);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit
+sh_mobile_lcdc_media_register(struct sh_mobile_lcdc_priv *priv)
+{
+	unsigned int i;
+	int ret;
+
+	priv->mdev.dev = priv->dev;
+	strlcpy(priv->mdev.model, "SH Mobile LCDC", sizeof(priv->mdev.model));
+
+	ret = media_device_register(&priv->mdev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
+		struct sh_mobile_lcdc_chan *ch = &priv->ch[i];
+
+		if (ch->info = NULL)
+			continue;
+
+		if (ch->tx_dev) {
+			ret = media_device_register_entity(&priv->mdev,
+							   &ch->tx_dev->entity);
+			if (ret < 0)
+				return ret;
+		}
+
+		ret = media_device_register_entity(&priv->mdev,
+						   &ch->panel.entity);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* -----------------------------------------------------------------------------
  * Probe/remove and driver init/exit
  */
 
@@ -1587,6 +1673,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 					  info->screen_base, ch->dma_handle);
 		fb_dealloc_cmap(&info->cmap);
 		framebuffer_release(info);
+
+		media_device_unregister_entity(&ch->panel.entity);
+		media_entity_cleanup(&ch->panel.entity);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
@@ -1651,8 +1740,9 @@ sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 
 static int __devinit
 sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
-			    struct sh_mobile_lcdc_chan *ch)
+			    struct sh_mobile_lcdc_chan *ch, unsigned int index)
 {
+	struct platform_device *pdev = to_platform_device(priv->dev);
 	struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
 	const struct fb_videomode *max_mode;
 	const struct fb_videomode *mode;
@@ -1679,6 +1769,8 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	info->par = ch;
 	info->pseudo_palette = &ch->pseudo_palette;
 	info->flags = FBINFO_FLAG_DEFAULT;
+	snprintf(info->name, sizeof(info->name), "LCDC %u channel %u", pdev->id,
+		 index);
 
 	if (cfg->tx_dev) {
 		if (!cfg->tx_dev->dev.driver ||
@@ -1691,6 +1783,12 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 		ch->tx_dev->lcdc = ch;
 	}
 
+	ret = sh_mobile_lcdc_media_init(ch);
+	if (ret < 0) {
+		dev_err(priv->dev, "unable to initialize media entities\n");
+		return ret;
+	}
+
 	/* Iterate through the modes to validate them and find the highest
 	 * resolution.
 	 */
@@ -1907,11 +2005,18 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 	for (i = 0; i < num_channels; i++) {
 		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
 
-		error = sh_mobile_lcdc_channel_init(priv, ch);
+		error = sh_mobile_lcdc_channel_init(priv, ch, i);
 		if (error)
 			goto err1;
 	}
 
+	error = sh_mobile_lcdc_media_register(priv);
+	if (error) {
+		dev_err(&pdev->dev, "media device registration failed (%d)\n",
+			error);
+		goto err1;
+	}
+
 	error = sh_mobile_lcdc_start(priv);
 	if (error) {
 		dev_err(&pdev->dev, "unable to start hardware\n");
@@ -1931,6 +2036,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
 			}
 		}
 
+		info->mdev = &priv->mdev;
 		info->bl_dev = ch->bl;
 
 		error = register_framebuffer(info);
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index fa60d00..98ed5f4 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -79,6 +79,14 @@ struct sh_mobile_lcdc_chan {
 	int (*notify)(struct sh_mobile_lcdc_chan *ch,
 		      enum sh_mobile_lcdc_entity_event event,
 		      struct fb_var_screeninfo *var);
+
+	struct media_pad pad;
+	struct media_entity entity;
+
+	struct {
+		struct media_pad pad;
+		struct media_entity entity;
+	} panel;
 };
 
 #endif
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 30/31] fbdev: sh_mobile_hdmi: Add media controller support
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Initialize the entity associated with the HDMI transmitter.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_hdmi.c |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index c17e3ad..c30c6a0 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -209,6 +209,7 @@ enum hotplug_state {
 
 struct sh_hdmi {
 	struct sh_mobile_lcdc_entity entity;
+	struct media_pad pads[2];
 
 	void __iomem *base;
 	enum hotplug_state hp_state;	/* hot-plug status */
@@ -1129,9 +1130,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	int irq = platform_get_irq(pdev, 0), ret;
+	int irq = platform_get_irq(pdev, 0);
 	struct sh_hdmi *hdmi;
 	long rate;
+	int ret;
 
 	if (!res || !pdata || irq < 0)
 		return -ENODEV;
@@ -1146,6 +1148,17 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 	hdmi->entity.owner = THIS_MODULE;
 	hdmi->entity.ops = &sh_hdmi_ops;
 
+	/* Initialize the panel media entity. */
+	hdmi->pads[0].flags = MEDIA_PAD_FL_SINK;
+	hdmi->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&hdmi->entity.entity, 2, hdmi->pads, 0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to initialize HDMI entity\n");
+		goto egetclk;
+	}
+
+	hdmi->entity.entity.name = "HDMI transmitter";
+
 	hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
 	if (IS_ERR(hdmi->hdmi_clk)) {
 		ret = PTR_ERR(hdmi->hdmi_clk);
@@ -1224,6 +1237,7 @@ ereqreg:
 erate:
 	clk_put(hdmi->hdmi_clk);
 egetclk:
+	media_entity_cleanup(&hdmi->entity.entity);
 	kfree(hdmi);
 
 	return ret;
@@ -1247,6 +1261,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 	clk_put(hdmi->hdmi_clk);
 	iounmap(hdmi->base);
 	release_mem_region(res->start, resource_size(res));
+	media_entity_cleanup(&hdmi->entity.entity);
 	kfree(hdmi);
 
 	return 0;
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 29/31] fbdev: sh_mipi_dsi: Add media controller support
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Initialize the entity associated with the MIPI/DSI transmitter.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mipi_dsi.c |   17 ++++++++++++++++-
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 3ead395..93ee3ee 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -50,6 +50,7 @@
 
 struct sh_mipi {
 	struct sh_mobile_lcdc_entity entity;
+	struct media_pad pads[2];
 
 	void __iomem	*base;
 	void __iomem	*linkbase;
@@ -364,8 +365,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	unsigned long rate, f_current;
-	int idx = pdev->id, ret;
+	int idx = pdev->id;
 	char dsip_clk[] = "dsi.p_clk";
+	int ret;
 
 	if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
 		return -ENODEV;
@@ -389,6 +391,17 @@ static int __init sh_mipi_probe(struct platform_device *pdev)
 	mipi->entity.owner = THIS_MODULE;
 	mipi->entity.ops = &mipi_ops;
 
+	/* Initialize the panel media entity. */
+	mipi->pads[0].flags = MEDIA_PAD_FL_SINK;
+	mipi->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&mipi->entity.entity, 2, mipi->pads, 0);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to initialize MIPI entity\n");
+		goto ereqreg;
+	}
+
+	mipi->entity.entity.name = "MIPI/DSI transmitter";
+
 	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
 		dev_err(&pdev->dev, "MIPI register region already claimed\n");
 		ret = -EBUSY;
@@ -497,6 +510,7 @@ ereqreg2:
 emap:
 	release_mem_region(res->start, resource_size(res));
 ereqreg:
+	media_entity_cleanup(&mipi->entity.entity);
 	kfree(mipi);
 ealloc:
 efindslot:
@@ -541,6 +555,7 @@ static int __exit sh_mipi_remove(struct platform_device *pdev)
 	if (res)
 		release_mem_region(res->start, resource_size(res));
 	platform_set_drvdata(pdev, NULL);
+	media_entity_cleanup(&mipi->entity.entity);
 	kfree(mipi);
 
 	return 0;
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 28/31] fbdev: sh_mobile_lcdc: Make LCDC entity inherit from media_entity
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index ec57533..fa60d00 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -5,6 +5,7 @@
 #include <linux/fb.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
+#include <media/media-entity.h>
 
 /* per-channel registers */
 enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
@@ -34,6 +35,7 @@ enum sh_mobile_lcdc_entity_event {
 };
 
 struct sh_mobile_lcdc_entity {
+	struct media_entity entity;
 	struct module *owner;
 	const struct sh_mobile_lcdc_entity_ops *ops;
 	struct sh_mobile_lcdc_chan *lcdc;
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 27/31] fbdev: Add media controller support
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Initialize and register a single-pad media entity when media controller
support is available.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/fbmem.c   |   21 +++++++++++++++++++++
 drivers/video/fbsysfs.c |   11 +++++++++++
 include/linux/fb.h      |    8 ++++++++
 3 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 5aac00e..26154fb 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -35,6 +35,7 @@
 
 #include <asm/fb.h>
 
+#include <media/media-device.h>
 
     /*
      *  Frame buffer device initialization and setup routines
@@ -1572,6 +1573,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
 	int i;
 	struct fb_event event;
 	struct fb_videomode mode;
+	int ret;
 
 	if (fb_check_foreignness(fb_info))
 		return -ENOSYS;
@@ -1625,6 +1627,21 @@ static int do_register_framebuffer(struct fb_info *fb_info)
 	fb_add_videomode(&mode, &fb_info->modelist);
 	registered_fb[i] = fb_info;
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	if (fb_info->mdev) {
+		fb_info->entity.type = MEDIA_ENT_T_DEVNODE_FB;
+		fb_info->entity.name = fb_info->name;
+		fb_info->entity.fb.major = FB_MAJOR;
+		fb_info->entity.fb.minor = i;
+		ret = media_device_register_entity(fb_info->mdev,
+						   &fb_info->entity);
+		if (ret < 0)
+			printk(KERN_WARNING
+			       "%s: media_device_register_entity failed\n",
+			       __func__);
+	}
+#endif
+
 	event.info = fb_info;
 	if (!lock_fb_info(fb_info))
 		return -ENODEV;
@@ -1651,6 +1668,10 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
 	if (ret)
 		return -EINVAL;
 
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	if (fb_info->mdev)
+		media_device_unregister_entity(&fb_info->entity);
+#endif
 	if (fb_info->pixmap.addr &&
 	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
 		kfree(fb_info->pixmap.addr);
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 04251ce..5d1ce86 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -63,6 +63,14 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
 	mutex_init(&info->bl_curve_mutex);
 #endif
 
+#ifdef CONFIG_MEDIA_CONTROLLER
+	info->pad.flags = MEDIA_PAD_FL_SOURCE;
+	if (media_entity_init(&info->entity, 1, &info->pad, 0) < 0) {
+		kfree(info);
+		return NULL;
+	}
+#endif
+
 	return info;
 #undef PADDING
 #undef BYTES_PER_LONG
@@ -80,6 +88,9 @@ EXPORT_SYMBOL(framebuffer_alloc);
  */
 void framebuffer_release(struct fb_info *info)
 {
+#ifdef CONFIG_MEDIA_CONTROLLER
+	media_entity_cleanup(&info->entity);
+#endif
 	kfree(info->apertures);
 	kfree(info);
 }
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 98b23e3..24b7368 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -423,9 +423,11 @@ struct fb_cursor {
 #include <linux/list.h>
 #include <linux/backlight.h>
 #include <linux/slab.h>
+#include <media/media-entity.h>
 #include <asm/io.h>
 
 struct vm_area_struct;
+struct media_device;
 struct fb_info;
 struct device;
 struct file;
@@ -879,6 +881,12 @@ struct fb_info {
 #endif
 
 	struct fb_ops *fbops;
+#ifdef CONFIG_MEDIA_CONTROLLER
+	char name[32];			/* Device name */
+	struct media_pad pad;		/* Output pad */
+	struct media_device *mdev;	/* Optional media device */
+	struct media_entity entity;	/* Media entity */
+#endif
 	struct device *device;		/* This is the parent */
 	struct device *dev;		/* This is this fb device */
 	int class_flag;                    /* private sysfs flags */
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 26/31] media: Initialize media controller core with subsys_initcall
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

The media controller core needs to be initialized before the frame
buffer devices. Use subsys_initcall() instead of module_init().

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/media-devnode.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 7b42ace..06a06b1 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -312,8 +312,8 @@ static void __exit media_devnode_exit(void)
 	unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
 }
 
-module_init(media_devnode_init)
-module_exit(media_devnode_exit)
+subsys_initcall(media_devnode_init);
+module_exit(media_devnode_exit);
 
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 MODULE_DESCRIPTION("Device node registration for media drivers");
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 25/31] sh_mobile_hdmi: Use LCDC notification callback
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Instead of accessing the LCDC channel and fb_info structures directly,
use the LCDC notification callback to inform the LCDC driver about
display-related events.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_hdmi.c |   88 +++++++---------------------------------
 1 files changed, 15 insertions(+), 73 deletions(-)

diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 4b87c6e..c17e3ad 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -733,12 +733,11 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
 static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 			     unsigned long *parent_rate)
 {
-	struct fb_info *info = hdmi->entity.lcdc
-			     ? hdmi->entity.lcdc->info : NULL;
-	struct fb_var_screeninfo tmpvar;
-	struct fb_var_screeninfo *var = &tmpvar;
+	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
+	struct fb_info *info = ch ? ch->info : NULL;
+	struct fb_var_screeninfo var;
 	const struct fb_videomode *mode, *found = NULL;
-	struct fb_modelist *modelist = NULL;
+	const struct fb_modelist *modelist = NULL;
 	unsigned int f_width = 0, f_height = 0, f_refresh = 0;
 	unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
 	bool scanning = false, preferred_bad = false;
@@ -856,12 +855,10 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 		}
 
 		/* Check if supported: sufficient fb memory, supported clock-rate */
-		fb_videomode_to_var(var, mode);
+		fb_videomode_to_var(&var, mode);
 
-		var->bits_per_pixel = info->var.bits_per_pixel;
-
-		if (info && info->fbops->fb_check_var &&
-		    info->fbops->fb_check_var(var, info)) {
+		if (ch && ch->notify &&
+		    ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_MODE, &var)) {
 			scanning = true;
 			preferred_bad = true;
 			continue;
@@ -1042,32 +1039,6 @@ static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
 	.display_off = sh_hdmi_display_off,
 };
 
-static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
-{
-	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
-	struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var;
-	struct fb_videomode mode1, mode2;
-
-	fb_var_to_videomode(&mode1, old_var);
-	fb_var_to_videomode(&mode2, new_var);
-
-	dev_dbg(hdmi->dev, "Old %ux%u, new %ux%u\n",
-		mode1.xres, mode1.yres, mode2.xres, mode2.yres);
-
-	if (fb_mode_is_equal(&mode1, &mode2)) {
-		/* It can be a different monitor with an equal video-mode */
-		old_var->width = new_var->width;
-		old_var->height = new_var->height;
-		return false;
-	}
-
-	dev_dbg(hdmi->dev, "Switching %u -> %u lines\n",
-		mode1.yres, mode2.yres);
-	*old_var = *new_var;
-
-	return true;
-}
-
 /**
  * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock
  * @hdmi:		driver context
@@ -1107,15 +1078,14 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
 static void sh_hdmi_edid_work_fn(struct work_struct *work)
 {
 	struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
+	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 	int ret;
 
 	dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
 		hdmi->hp_state);
 
 	if (hdmi->hp_state = HDMI_HOTPLUG_CONNECTED) {
-		struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 		unsigned long parent_rate = 0, hdmi_rate;
-		struct fb_info *info;
 
 		ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
 		if (ret < 0)
@@ -1133,47 +1103,19 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 		/* Switched to another (d) power-save mode */
 		msleep(10);
 
-		if (ch = NULL)
-			goto out;
-
-		info = ch->info;
-
-		console_lock();
-
-		/* HDMI plug in */
-		if (!sh_hdmi_must_reconfigure(hdmi) &&
-		    info->state = FBINFO_STATE_RUNNING) {
-			/*
-			 * First activation with the default monitor - just turn
-			 * on, if we run a resume here, the logo disappears
-			 */
-			if (lock_fb_info(info)) {
-				info->var.width = hdmi->var.width;
-				info->var.height = hdmi->var.height;
-				sh_hdmi_display_on(&hdmi->entity);
-				unlock_fb_info(info);
-			}
-		} else {
-			/* New monitor or have to wake up */
-			fb_set_suspend(info, 0);
-		}
-
-		console_unlock();
+		if (ch && ch->notify)
+			ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
+				   &hdmi->var);
 	} else {
-		ret = 0;
-		if (hdmi->entity.lcdc = NULL)
-			goto out;
-
 		hdmi->monspec.modedb_len = 0;
 		fb_destroy_modedb(hdmi->monspec.modedb);
 		hdmi->monspec.modedb = NULL;
 
-		console_lock();
-
-		/* HDMI disconnect */
-		fb_set_suspend(hdmi->entity.lcdc->info, 1);
+		if (ch && ch->notify)
+			ch->notify(ch, SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
+				   NULL);
 
-		console_unlock();
+		ret = 0;
 	}
 
 out:
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 24/31] sh_mobile_lcdc: Add display notify callback to sh_mobile_lcdc_chan
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

The callback implements 3 notification events:

- SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT notifies the LCDC that the
  display has been connected
- SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT notifies the LCDC that the
  display has been disconnected
- SH_MOBILE_LCDC_EVENT_DISPLAY_MODE notifies that LCDC that a display
  mode has been detected

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |   77 ++++++++++++++++++++++++++++++++++++++
 drivers/video/sh_mobile_lcdcfb.h |   10 +++++
 2 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index d6c117b..19ac3c5 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -359,6 +359,82 @@ static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
 		ch->tx_dev->ops->display_off(ch->tx_dev);
 }
 
+static bool
+sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
+				const struct fb_var_screeninfo *new_var)
+{
+	struct fb_var_screeninfo *old_var = &ch->display_var;
+	struct fb_videomode old_mode;
+	struct fb_videomode new_mode;
+
+	fb_var_to_videomode(&old_mode, old_var);
+	fb_var_to_videomode(&new_mode, new_var);
+
+	dev_dbg(ch->info->dev, "Old %ux%u, new %ux%u\n",
+		old_mode.xres, old_mode.yres, new_mode.xres, new_mode.yres);
+
+	if (fb_mode_is_equal(&old_mode, &new_mode)) {
+		/* It can be a different monitor with an equal video-mode */
+		old_var->width = new_var->width;
+		old_var->height = new_var->height;
+		return false;
+	}
+
+	dev_dbg(ch->info->dev, "Switching %u -> %u lines\n",
+		old_mode.yres, new_mode.yres);
+	*old_var = *new_var;
+
+	return true;
+}
+
+static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
+					 enum sh_mobile_lcdc_entity_event event,
+					 struct fb_var_screeninfo *var)
+{
+	struct fb_info *info = ch->info;
+	int ret = 0;
+
+	switch (event) {
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
+		/* HDMI plug in */
+		console_lock();
+
+		if (!sh_mobile_lcdc_must_reconfigure(ch, var) &&
+		    info->state = FBINFO_STATE_RUNNING) {
+			/* First activation with the default monitor - just turn
+			 * on, if we run a resume here, the logo disappears.
+			 */
+			if (lock_fb_info(info)) {
+				info->var.width = var->width;
+				info->var.height = var->height;
+				sh_mobile_lcdc_display_on(ch);
+				unlock_fb_info(info);
+			}
+		} else {
+			/* New monitor or have to wake up */
+			fb_set_suspend(info, 0);
+		}
+
+		console_unlock();
+		break;
+
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
+		/* HDMI disconnect */
+		console_lock();
+		fb_set_suspend(info, 1);
+		console_unlock();
+		break;
+
+	case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
+		/* Validate a proposed new mode */
+		var->bits_per_pixel = info->var.bits_per_pixel;
+		ret = info->fbops->fb_check_var(var, info);
+		break;
+	}
+
+	return ret;
+}
+
 /* -----------------------------------------------------------------------------
  * Format helpers
  */
@@ -1589,6 +1665,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	int i;
 
 	mutex_init(&ch->open_lock);
+	ch->notify = sh_mobile_lcdc_display_notify;
 
 	/* Allocate the frame buffer device. */
 	ch->info = framebuffer_alloc(0, priv->dev);
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 8f1e007..ec57533 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -27,6 +27,12 @@ struct sh_mobile_lcdc_entity_ops {
 	void (*display_off)(struct sh_mobile_lcdc_entity *entity);
 };
 
+enum sh_mobile_lcdc_entity_event {
+	SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT,
+	SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT,
+	SH_MOBILE_LCDC_EVENT_DISPLAY_MODE,
+};
+
 struct sh_mobile_lcdc_entity {
 	struct module *owner;
 	const struct sh_mobile_lcdc_entity_ops *ops;
@@ -67,6 +73,10 @@ struct sh_mobile_lcdc_chan {
 	unsigned long base_addr_y;
 	unsigned long base_addr_c;
 	unsigned int pitch;
+
+	int (*notify)(struct sh_mobile_lcdc_chan *ch,
+		      enum sh_mobile_lcdc_entity_event event,
+		      struct fb_var_screeninfo *var);
 };
 
 #endif
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 23/31] fbdev: sh_mobile_lcdc: Return display connection state in display_on
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

Return true if the display is connected and false otherwise. Set the fb
info state to FBINFO_STATE_SUSPENDED in the sh_mobile_lcdc driver when
the display is not connected.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mipi_dsi.c      |    4 +++-
 drivers/video/sh_mobile_hdmi.c   |    9 +++++----
 drivers/video/sh_mobile_lcdcfb.c |    8 ++++++--
 drivers/video/sh_mobile_lcdcfb.h |    2 +-
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index f5d380c..3ead395 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -125,12 +125,14 @@ static void sh_mipi_shutdown(struct platform_device *pdev)
 	sh_mipi_dsi_enable(mipi, false);
 }
 
-static void mipi_display_on(struct sh_mobile_lcdc_entity *entity)
+static bool mipi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
 	struct sh_mipi *mipi = to_sh_mipi(entity);
 
 	pm_runtime_get_sync(mipi->dev);
 	sh_mipi_dsi_enable(mipi, true);
+
+	return true;
 }
 
 static void mipi_display_off(struct sh_mobile_lcdc_entity *entity)
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 88de4e0..4b87c6e 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1000,13 +1000,13 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
+static bool sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
 	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
 	struct sh_mobile_lcdc_chan *ch = entity->lcdc;
-	struct fb_info *info = ch->info;
 
-	dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state);
+	dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi,
+		hdmi->hp_state);
 
 	/*
 	 * hp_state can be set to
@@ -1021,10 +1021,11 @@ static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
 		dev_dbg(hdmi->dev, "HDMI running\n");
 		break;
 	case HDMI_HOTPLUG_DISCONNECTED:
-		info->state = FBINFO_STATE_SUSPENDED;
 	default:
 		hdmi->var = ch->display_var;
 	}
+
+	return hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED;
 }
 
 static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index afd00cc..d6c117b 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -335,9 +335,13 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
 static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
 {
 	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
+	bool connected;
 
-	if (ch->tx_dev)
-		ch->tx_dev->ops->display_on(ch->tx_dev);
+	if (ch->tx_dev) {
+		connected = ch->tx_dev->ops->display_on(ch->tx_dev);
+		if (!connected)
+			ch->info->state = FBINFO_STATE_SUSPENDED;
+	}
 
 	/* HDMI must be enabled before LCDC configuration */
 	if (panel->display_on)
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index 50c2d1f..8f1e007 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -23,7 +23,7 @@ struct sh_mobile_lcdc_chan;
 
 struct sh_mobile_lcdc_entity_ops {
 	/* Display */
-	void (*display_on)(struct sh_mobile_lcdc_entity *entity);
+	bool (*display_on)(struct sh_mobile_lcdc_entity *entity);
 	void (*display_off)(struct sh_mobile_lcdc_entity *entity);
 };
 
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 22/31] fbdev: sh_mobile_lcdc: Remove fb_info parameter to display_on operation
From: Laurent Pinchart @ 2011-09-19  0:28 UTC (permalink / raw)
  To: linux-fbdev

The parameter is unused, remove it.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mipi_dsi.c      |    3 +--
 drivers/video/sh_mobile_hdmi.c   |   10 ++--------
 drivers/video/sh_mobile_lcdcfb.c |    2 +-
 drivers/video/sh_mobile_lcdcfb.h |    3 +--
 4 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index e198067..f5d380c 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -125,8 +125,7 @@ static void sh_mipi_shutdown(struct platform_device *pdev)
 	sh_mipi_dsi_enable(mipi, false);
 }
 
-static void mipi_display_on(struct sh_mobile_lcdc_entity *entity,
-			    struct fb_info *info)
+static void mipi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
 	struct sh_mipi *mipi = to_sh_mipi(entity);
 
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index deca755..88de4e0 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1000,14 +1000,8 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-/* locking:	called with info->lock held, or before register_framebuffer() */
-static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity,
-			       struct fb_info *info)
+static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity)
 {
-	/*
-	 * info is guaranteed to be valid, when we are called, because our
-	 * FB_EVENT_FB_UNBIND notify is also called with info->lock held
-	 */
 	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
 	struct sh_mobile_lcdc_chan *ch = entity->lcdc;
 	struct fb_info *info = ch->info;
@@ -1155,7 +1149,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 			if (lock_fb_info(info)) {
 				info->var.width = hdmi->var.width;
 				info->var.height = hdmi->var.height;
-				sh_hdmi_display_on(&hdmi->entity, info);
+				sh_hdmi_display_on(&hdmi->entity);
 				unlock_fb_info(info);
 			}
 		} else {
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f8bdbe9..afd00cc 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -337,7 +337,7 @@ static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
 	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
 
 	if (ch->tx_dev)
-		ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
+		ch->tx_dev->ops->display_on(ch->tx_dev);
 
 	/* HDMI must be enabled before LCDC configuration */
 	if (panel->display_on)
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index b57a847..50c2d1f 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -23,8 +23,7 @@ struct sh_mobile_lcdc_chan;
 
 struct sh_mobile_lcdc_entity_ops {
 	/* Display */
-	void (*display_on)(struct sh_mobile_lcdc_entity *entity,
-			   struct fb_info *info);
+	void (*display_on)(struct sh_mobile_lcdc_entity *entity);
 	void (*display_off)(struct sh_mobile_lcdc_entity *entity);
 };
 
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 21/31] sh_mobile_hdmi: Use sh_mobile_lcdc_entity::channel to access fb_info
From: Laurent Pinchart @ 2011-09-19  0:27 UTC (permalink / raw)
  To: linux-fbdev

The fb_info parameter passed to the display_on operation will be
removed, don't use it.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_hdmi.c |   81 ++++++---------------------------------
 1 files changed, 13 insertions(+), 68 deletions(-)

diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index d89645e..deca755 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -219,16 +219,12 @@ struct sh_hdmi {
 	u8 edid_blocks;
 	struct clk *hdmi_clk;
 	struct device *dev;
-	struct fb_info *info;
-	struct mutex mutex;		/* Protect the info pointer */
 	struct delayed_work edid_work;
 	struct fb_var_screeninfo var;
 	struct fb_monspecs monspec;
-	struct notifier_block notifier;
 };
 
 #define entity_to_sh_hdmi(e)	container_of(e, struct sh_hdmi, entity)
-#define notifier_to_sh_hdmi(n)	container_of(n, struct sh_hdmi, notifier)
 
 static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg)
 {
@@ -737,10 +733,11 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi,
 static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate,
 			     unsigned long *parent_rate)
 {
+	struct fb_info *info = hdmi->entity.lcdc
+			     ? hdmi->entity.lcdc->info : NULL;
 	struct fb_var_screeninfo tmpvar;
 	struct fb_var_screeninfo *var = &tmpvar;
 	const struct fb_videomode *mode, *found = NULL;
-	struct fb_info *info = hdmi->info;
 	struct fb_modelist *modelist = NULL;
 	unsigned int f_width = 0, f_height = 0, f_refresh = 0;
 	unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
@@ -1012,13 +1009,11 @@ static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity,
 	 * FB_EVENT_FB_UNBIND notify is also called with info->lock held
 	 */
 	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
-	struct sh_mobile_lcdc_chan *ch = info->par;
+	struct sh_mobile_lcdc_chan *ch = entity->lcdc;
+	struct fb_info *info = ch->info;
 
 	dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, hdmi, info->state);
 
-	/* No need to lock */
-	hdmi->info = info;
-
 	/*
 	 * hp_state can be set to
 	 * HDMI_HOTPLUG_DISCONNECTED:	on monitor unplug
@@ -1038,7 +1033,6 @@ static void sh_hdmi_display_on(struct sh_mobile_lcdc_entity *entity,
 	}
 }
 
-/* locking: called with info->lock held */
 static void sh_hdmi_display_off(struct sh_mobile_lcdc_entity *entity)
 {
 	struct sh_hdmi *hdmi = entity_to_sh_hdmi(entity);
@@ -1055,15 +1049,14 @@ static const struct sh_mobile_lcdc_entity_ops sh_hdmi_ops = {
 
 static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
 {
-	struct fb_info *info = hdmi->info;
-	struct sh_mobile_lcdc_chan *ch = info->par;
+	struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 	struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var;
 	struct fb_videomode mode1, mode2;
 
 	fb_var_to_videomode(&mode1, old_var);
 	fb_var_to_videomode(&mode2, new_var);
 
-	dev_dbg(info->dev, "Old %ux%u, new %ux%u\n",
+	dev_dbg(hdmi->dev, "Old %ux%u, new %ux%u\n",
 		mode1.xres, mode1.yres, mode2.xres, mode2.yres);
 
 	if (fb_mode_is_equal(&mode1, &mode2)) {
@@ -1073,7 +1066,7 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi)
 		return false;
 	}
 
-	dev_dbg(info->dev, "Switching %u -> %u lines\n",
+	dev_dbg(hdmi->dev, "Switching %u -> %u lines\n",
 		mode1.yres, mode2.yres);
 	*old_var = *new_var;
 
@@ -1119,17 +1112,15 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
 static void sh_hdmi_edid_work_fn(struct work_struct *work)
 {
 	struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
-	struct sh_mobile_lcdc_chan *ch;
 	int ret;
 
 	dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, hdmi,
 		hdmi->hp_state);
 
-	mutex_lock(&hdmi->mutex);
-
 	if (hdmi->hp_state = HDMI_HOTPLUG_CONNECTED) {
-		struct fb_info *info = hdmi->info;
+		struct sh_mobile_lcdc_chan *ch = hdmi->entity.lcdc;
 		unsigned long parent_rate = 0, hdmi_rate;
+		struct fb_info *info;
 
 		ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
 		if (ret < 0)
@@ -1147,10 +1138,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 		/* Switched to another (d) power-save mode */
 		msleep(10);
 
-		if (!info)
+		if (ch = NULL)
 			goto out;
 
-		ch = info->par;
+		info = ch->info;
 
 		console_lock();
 
@@ -1175,7 +1166,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 		console_unlock();
 	} else {
 		ret = 0;
-		if (!hdmi->info)
+		if (hdmi->entity.lcdc = NULL)
 			goto out;
 
 		hdmi->monspec.modedb_len = 0;
@@ -1185,7 +1176,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 		console_lock();
 
 		/* HDMI disconnect */
-		fb_set_suspend(hdmi->info, 1);
+		fb_set_suspend(hdmi->entity.lcdc->info, 1);
 
 		console_unlock();
 	}
@@ -1193,47 +1184,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
 out:
 	if (ret < 0 && ret != -EAGAIN)
 		hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED;
-	mutex_unlock(&hdmi->mutex);
 
 	dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, hdmi);
 }
 
-static int sh_hdmi_notify(struct notifier_block *nb,
-			  unsigned long action, void *data)
-{
-	struct fb_event *event = data;
-	struct fb_info *info = event->info;
-	struct sh_hdmi *hdmi = notifier_to_sh_hdmi(nb);
-
-	if (!hdmi || nb != &hdmi->notifier || hdmi->info != info)
-		return NOTIFY_DONE;
-
-	switch(action) {
-	case FB_EVENT_FB_REGISTERED:
-		/* Unneeded, activation taken care by sh_hdmi_display_on() */
-		break;
-	case FB_EVENT_FB_UNREGISTERED:
-		/*
-		 * We are called from unregister_framebuffer() with the
-		 * info->lock held. This is bad for us, because we can race with
-		 * the scheduled work, which has to call fb_set_suspend(), which
-		 * takes info->lock internally, so, sh_hdmi_edid_work_fn()
-		 * cannot take and hold info->lock for the whole function
-		 * duration. Using an additional lock creates a classical AB-BA
-		 * lock up. Therefore, we have to release the info->lock
-		 * temporarily, synchronise with the work queue and re-acquire
-		 * the info->lock.
-		 */
-		unlock_fb_info(info);
-		mutex_lock(&hdmi->mutex);
-		hdmi->info = NULL;
-		mutex_unlock(&hdmi->mutex);
-		lock_fb_info(info);
-		return NOTIFY_OK;
-	}
-	return NOTIFY_DONE;
-}
-
 static int __init sh_hdmi_probe(struct platform_device *pdev)
 {
 	struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data;
@@ -1251,8 +1205,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	mutex_init(&hdmi->mutex);
-
 	hdmi->dev = &pdev->dev;
 	hdmi->entity.owner = THIS_MODULE;
 	hdmi->entity.ops = &sh_hdmi_ops;
@@ -1320,9 +1272,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 		goto ecodec;
 	}
 
-	hdmi->notifier.notifier_call = sh_hdmi_notify;
-	fb_register_client(&hdmi->notifier);
-
 	return 0;
 
 ecodec:
@@ -1338,7 +1287,6 @@ ereqreg:
 erate:
 	clk_put(hdmi->hdmi_clk);
 egetclk:
-	mutex_destroy(&hdmi->mutex);
 	kfree(hdmi);
 
 	return ret;
@@ -1352,8 +1300,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 
 	snd_soc_unregister_codec(&pdev->dev);
 
-	fb_unregister_client(&hdmi->notifier);
-
 	/* No new work will be scheduled, wait for running ISR */
 	free_irq(irq, hdmi);
 	/* Wait for already scheduled work */
@@ -1364,7 +1310,6 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 	clk_put(hdmi->hdmi_clk);
 	iounmap(hdmi->base);
 	release_mem_region(res->start, resource_size(res));
-	mutex_destroy(&hdmi->mutex);
 	kfree(hdmi);
 
 	return 0;
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 20/31] sh_mobile_lcdc: Add an lcdc channel pointer to sh_mobile_lcdc_entity
From: Laurent Pinchart @ 2011-09-19  0:27 UTC (permalink / raw)
  To: linux-fbdev

The field will be used by the transmitter drivers to access
sh_mobile_lcdc_chan fields such as fb_info.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/video/sh_mobile_lcdcfb.c |    5 ++++-
 drivers/video/sh_mobile_lcdcfb.h |    2 ++
 2 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index eff475d..f8bdbe9 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -1494,8 +1494,10 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
 		if (!info || !info->device)
 			continue;
 
-		if (ch->tx_dev)
+		if (ch->tx_dev) {
+			ch->tx_dev->lcdc = NULL;
 			module_put(ch->cfg.tx_dev->dev.driver->owner);
+		}
 
 		if (ch->sglist)
 			vfree(ch->sglist);
@@ -1605,6 +1607,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 			return -EINVAL;
 		}
 		ch->tx_dev = platform_get_drvdata(cfg->tx_dev);
+		ch->tx_dev->lcdc = ch;
 	}
 
 	/* Iterate through the modes to validate them and find the highest
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h
index c992a98..b57a847 100644
--- a/drivers/video/sh_mobile_lcdcfb.h
+++ b/drivers/video/sh_mobile_lcdcfb.h
@@ -19,6 +19,7 @@ struct fb_info;
 struct module;
 struct sh_mobile_lcdc_entity;
 struct sh_mobile_lcdc_priv;
+struct sh_mobile_lcdc_chan;
 
 struct sh_mobile_lcdc_entity_ops {
 	/* Display */
@@ -30,6 +31,7 @@ struct sh_mobile_lcdc_entity_ops {
 struct sh_mobile_lcdc_entity {
 	struct module *owner;
 	const struct sh_mobile_lcdc_entity_ops *ops;
+	struct sh_mobile_lcdc_chan *lcdc;
 };
 
 /*
-- 
1.7.3.4


^ permalink raw reply related

* [WIP/RFC 19/31] fbdev: sh_mobile_lcdc: Merge board_cfg and lcd_size_cfg into panel_cfg
From: Laurent Pinchart @ 2011-09-19  0:27 UTC (permalink / raw)
  To: linux-fbdev

Update board code accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-shmobile/board-ag5evm.c   |    6 ++--
 arch/arm/mach-shmobile/board-ap4evb.c   |    8 +++---
 arch/arm/mach-shmobile/board-mackerel.c |    6 +++-
 arch/sh/boards/mach-ap325rxa/setup.c    |    6 +---
 arch/sh/boards/mach-ecovec24/setup.c    |    2 +-
 arch/sh/boards/mach-kfr2r09/setup.c     |    4 +--
 arch/sh/boards/mach-migor/setup.c       |    8 ++----
 arch/sh/boards/mach-se/7724/setup.c     |    2 +-
 drivers/video/sh_mobile_lcdcfb.c        |   35 +++++++++++++++----------------
 include/video/sh_mobile_lcdc.h          |   12 +++-------
 10 files changed, 40 insertions(+), 49 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 139fbd1..c8b57a7 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -258,12 +258,12 @@ static struct sh_mobile_lcdc_info lcdc0_info = {
 		.interface_type = RGB24,
 		.clock_divider = 1,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_size_cfg.width = 44,
-		.lcd_size_cfg.height = 79,
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.lcd_cfg = lcdc0_modes,
 		.num_cfg = ARRAY_SIZE(lcdc0_modes),
-		.board_cfg = {
+		.panel_cfg = {
+			.width = 44,
+			.height = 79,
 			.display_on = lcd_backlight_on,
 			.display_off = lcd_backlight_reset,
 		},
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 851e1ac..f8d0b4d 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1326,8 +1326,8 @@ static void __init ap4evb_init(void)
 	lcdc_info.ch[0].interface_type		= RGB24;
 	lcdc_info.ch[0].clock_divider		= 1;
 	lcdc_info.ch[0].flags			= LCDC_FLAGS_DWPOL;
-	lcdc_info.ch[0].lcd_size_cfg.width	= 44;
-	lcdc_info.ch[0].lcd_size_cfg.height	= 79;
+	lcdc_info.ch[0].panel_cfg.width		= 44;
+	lcdc_info.ch[0].panel_cfg.height	= 79;
 
 	platform_add_devices(qhd_devices, ARRAY_SIZE(qhd_devices));
 
@@ -1368,8 +1368,8 @@ static void __init ap4evb_init(void)
 	lcdc_info.ch[0].interface_type		= RGB18;
 	lcdc_info.ch[0].clock_divider		= 3;
 	lcdc_info.ch[0].flags			= 0;
-	lcdc_info.ch[0].lcd_size_cfg.width	= 152;
-	lcdc_info.ch[0].lcd_size_cfg.height	= 91;
+	lcdc_info.ch[0].panel_cfg.width		= 152;
+	lcdc_info.ch[0].panel_cfg.height	= 91;
 
 	/* enable TouchScreen */
 	irq_set_irq_type(IRQ7, IRQ_TYPE_LEVEL_LOW);
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index ecd1982..1bdcf61 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -393,8 +393,10 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 		.interface_type		= RGB24,
 		.clock_divider		= 3,
 		.flags			= 0,
-		.lcd_size_cfg.width	= 152,
-		.lcd_size_cfg.height	= 91,
+		.panel_cfg = {
+			.width		= 152,
+			.height		= 91,
+		},
 		.bl_info = {
 			.name = "sh_mobile_lcdc_bl",
 			.max_brightness = 1,
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 315d79a..4d1df51 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -212,11 +212,9 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 		.clock_divider = 1,
 		.lcd_cfg = ap325rxa_lcdc_modes,
 		.num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes),
-		.lcd_size_cfg = { /* 7.0 inch */
-			.width = 152,
+		.panel_cfg = {
+			.width = 152,	/* 7.0 inch */
 			.height = 91,
-		},
-		.board_cfg = {
 			.display_on = ap320_wvga_power_on,
 			.display_off = ap320_wvga_power_off,
 		},
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index b957b54..3f3f2ec 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -327,7 +327,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 		.interface_type = RGB18,
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
-		.lcd_size_cfg = { /* 7.0 inch */
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 208c9b0..615cb4b 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -152,11 +152,9 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
 		.flags = LCDC_FLAGS_DWPOL,
 		.lcd_cfg = kfr2r09_lcdc_modes,
 		.num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes),
-		.lcd_size_cfg = {
+		.panel_cfg = {
 			.width = 35,
 			.height = 58,
-		},
-		.board_cfg = {
 			.setup_sys = kfr2r09_lcd_setup,
 			.start_transfer = kfr2r09_lcd_start,
 			.display_on = kfr2r09_lcd_on,
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 69f8d7d..b052946 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -249,7 +249,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
 		.clock_divider = 2,
 		.lcd_cfg = migor_lcd_modes,
 		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
-		.lcd_size_cfg = { /* 7.0 inch */
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
@@ -263,11 +263,9 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
 		.clock_divider = 10,
 		.lcd_cfg = migor_lcd_modes,
 		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
-		.lcd_size_cfg = { /* 2.4 inch */
-			.width = 49,
+		.panel_cfg = {
+			.width = 49,	/* 2.4 inch */
 			.height = 37,
-		},
-		.board_cfg = {
 			.setup_sys = migor_lcd_qvga_setup,
 		},
 		.sys_bus_cfg = {
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 334b463..56e7361 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -181,7 +181,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.fourcc = V4L2_PIX_FMT_RGB565,
 		.clock_divider = 1,
-		.lcd_size_cfg = { /* 7.0 inch */
+		.panel_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index a490c7a..eff475d 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -288,7 +288,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
 				       struct list_head *pagelist)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
-	struct sh_mobile_lcdc_board_cfg	*bcfg = &ch->cfg.board_cfg;
+	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
 
 	/* enable clocks before accessing hardware */
 	sh_mobile_lcdc_clk_on(ch->lcdc);
@@ -313,13 +313,13 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
 
 		/* trigger panel update */
 		dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
-		if (bcfg->start_transfer)
-			bcfg->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
+		if (panel->start_transfer)
+			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
 		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
 		dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
 	} else {
-		if (bcfg->start_transfer)
-			bcfg->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
+		if (panel->start_transfer)
+			panel->start_transfer(ch, &sh_mobile_lcdc_sys_bus_ops);
 		lcdc_write_chan(ch, LDSM2R, LDSM2R_OSTRG);
 	}
 }
@@ -334,22 +334,22 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
 
 static void sh_mobile_lcdc_display_on(struct sh_mobile_lcdc_chan *ch)
 {
-	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
+	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
 
 	if (ch->tx_dev)
 		ch->tx_dev->ops->display_on(ch->tx_dev, ch->info);
 
 	/* HDMI must be enabled before LCDC configuration */
-	if (board_cfg->display_on)
-		board_cfg->display_on();
+	if (panel->display_on)
+		panel->display_on();
 }
 
 static void sh_mobile_lcdc_display_off(struct sh_mobile_lcdc_chan *ch)
 {
-	struct sh_mobile_lcdc_board_cfg	*board_cfg = &ch->cfg.board_cfg;
+	struct sh_mobile_lcdc_panel_cfg *panel = &ch->cfg.panel_cfg;
 
-	if (board_cfg->display_off)
-		board_cfg->display_off();
+	if (panel->display_off)
+		panel->display_off();
 
 	if (ch->tx_dev)
 		ch->tx_dev->ops->display_off(ch->tx_dev);
@@ -679,16 +679,15 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
 	lcdc_wait_bit(priv, _LDCNT2R, LDCNT2R_BR, 0);
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
-		struct sh_mobile_lcdc_board_cfg	*board_cfg;
+		struct sh_mobile_lcdc_panel_cfg *panel;
 
 		ch = &priv->ch[k];
 		if (!ch->enabled)
 			continue;
 
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->setup_sys) {
-			ret = board_cfg->setup_sys(ch,
-						   &sh_mobile_lcdc_sys_bus_ops);
+		panel = &ch->cfg.panel_cfg;
+		if (panel->setup_sys) {
+			ret = panel->setup_sys(ch, &sh_mobile_lcdc_sys_bus_ops);
 			if (ret)
 				return ret;
 		}
@@ -1654,8 +1653,8 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv,
 	 */
 	var = &info->var;
 	fb_videomode_to_var(var, mode);
-	var->width = cfg->lcd_size_cfg.width;
-	var->height = cfg->lcd_size_cfg.height;
+	var->width = cfg->panel_cfg.width;
+	var->height = cfg->panel_cfg.height;
 	var->yres_virtual = var->yres * 2;
 	var->activate = FB_ACTIVATE_NOW;
 
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 541b2b3..84163e4 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -147,7 +147,9 @@ struct sh_mobile_lcdc_sys_bus_ops {
 	unsigned long (*read_data)(void *handle);
 };
 
-struct sh_mobile_lcdc_board_cfg {
+struct sh_mobile_lcdc_panel_cfg {
+	unsigned long width;		/* Panel width in mm */
+	unsigned long height;		/* Panel height in mm */
 	int (*setup_sys)(void *sys_ops_handle,
 			 struct sh_mobile_lcdc_sys_bus_ops *sys_ops);
 	void (*start_transfer)(void *sys_ops_handle,
@@ -156,11 +158,6 @@ struct sh_mobile_lcdc_board_cfg {
 	void (*display_off)(void);
 };
 
-struct sh_mobile_lcdc_lcd_size_cfg { /* width and height of panel in mm */
-	unsigned long width;
-	unsigned long height;
-};
-
 /* backlight info */
 struct sh_mobile_lcdc_bl_info {
 	const char *name;
@@ -178,8 +175,7 @@ struct sh_mobile_lcdc_chan_cfg {
 	unsigned long flags; /* LCDC_FLAGS_... */
 	const struct fb_videomode *lcd_cfg;
 	int num_cfg;
-	struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg;
-	struct sh_mobile_lcdc_board_cfg board_cfg;
+	struct sh_mobile_lcdc_panel_cfg panel_cfg;
 	struct sh_mobile_lcdc_bl_info bl_info;
 	struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
 	struct sh_mobile_meram_cfg *meram_cfg;
-- 
1.7.3.4


^ permalink raw reply related


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