Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v2] matroxfb: remove incorrect Matrox G200eV support
From: Darrick J. Wong @ 2011-03-04 20:29 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Gary Hade, linux-fbdev, linux-kernel, Krzysztof Helt,
	Petr Vandrovec, Andrew Morton
In-Reply-To: <AANLkTikwSXN8VgDaoUqfHcxoTNxW9uA4D2fUtRLuLbHo@mail.gmail.com>

On Tue, Mar 01, 2011 at 10:29:23AM -0800, Linus Torvalds wrote:
> On Tue, Mar 1, 2011 at 9:50 AM, Gary Hade <garyhade@us.ibm.com> wrote:
> >
> > Remove incorrect Matrox G200eV support that was previously added
> > by commit e3a1938805d2e81b27d3d348788644f3bad004f2
> 
> That commit goes back to 2.6.28 (and is dated Oct 2008).
> 
> That means that you really need to describe the problem more:
> 
> > One serious issue with the G200eV support that I have reproduced
> > on a Matrox G200eV equipped IBM x3650 M2 is the lack of text (login
> > banner, login prompt, etc) on the console when X not running and
> > lack of text on all of the virtual consoles after X is started.

On an IBM x3650m2, loading the matroxfb-base fb driver for the builtin Matrox
G200eV VGA chip results in no usable analog signal coming out of the VGA port.
I noticed the "outputs=" parameter to that driver, and forced all outputs on;
when I did that, the display showed a crazed jumble of static and powered off.
The display would not power on again until I removed and reinserted the power
plug.  Other displays reacted less violently but not functionally, either.

> .. but without the commit, you get no fb at all, right? So even with
> the commit, at worst you'd just be able to not use the matroxfb
> driver, right?

Yep.  We contacted Matrox to see if they would help us sort out the output
misprogramming issue, and they declined.  Evidently they're no longer
interested in matroxfb support.

> What I'm trying to say is that I suspect there are G200eV users that
> likely prefer having the support in - even though it's not perfect.
> And the fact that the commit has been there for 2.5 years without
> comments makes me very loath to just revert it.

This is all quite strange -- 2.5 years ago when I wrote the patch it seemed to
work ok.  On newer revisions of the x3650M2 it seems broken.  The original
machine I wrote it for was cut up ages ago.

I suppose we could simply blacklist any G200eV with a subsystem vendor ID of
0x1014 (IBM) until we figure out how to correct the driver.  Our customers will
be deprived, but as it seems to be broken across most of our product lines I
doubt any of them are making serious use of it anyway. :)

Something like this?
--
matroxfb: Blacklist IBM G200eV chips

On an IBM x3650m2, loading the matroxfb-base fb driver for the builtin Matrox
G200eV VGA chip results in no usable analog signal coming out of the VGA port.
I noticed the "outputs=" parameter to that driver, and forced all outputs on;
when I did that, the display showed a crazed jumble of static and powered off.
The display would not power on again until I removed and reinserted the power
plug.  Other displays reacted less violently but not functionally, either.

For now, don't talk to the G200eV if it has an IBM subvendor ID.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---

 drivers/video/matrox/matroxfb_base.c |   25 ++++++++++++++++++++++++-
 1 files changed, 24 insertions(+), 1 deletions(-)

diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index a082deb..a86e401 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -1385,6 +1385,17 @@ static struct video_board vbG400		= {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
 #define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
 #define DEVF_G550	(DEVF_G450)
 
+static struct blacklisted_board {
+	unsigned short vendor, device, svid, sid;
+		} black_list[] = {
+#ifdef CONFIG_FB_MATROX_G
+	/* Onboard G200eV in IBM servers cause display failures */
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200EV_PCI,
+	 PCI_VENDOR_ID_IBM, 0},
+#endif
+	{0, 0, 0, 0},
+};
+
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
 	unsigned int flags;
@@ -2012,10 +2023,11 @@ static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
 
 static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
 	struct board* b;
+	struct blacklisted_board *d;
 	u_int16_t svid;
 	u_int16_t sid;
 	struct matrox_fb_info* minfo;
-	int err;
+	int err, ignore;
 	u_int32_t cmd;
 	DBG(__func__)
 
@@ -2025,6 +2037,17 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
 		if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue;
 		if (b->svid)
 			if ((b->svid != svid) || (b->sid != sid)) continue;
+		ignore = 0;
+		for (d = black_list; d->vendor; d++)
+			if (d->vendor = pdev->vendor &&
+			    d->device = pdev->device &&
+			    d->svid = svid &&
+			    (!d->sid || d->sid = sid)) {
+				ignore = 1;
+				break;
+			}
+		if (ignore)
+			continue;
 		break;
 	}
 	/* not match... */

^ permalink raw reply related

* Re: [PATCH 3/4] [ARM] msm_fb: Fix framebuffer console
From: Arve Hjønnevåg @ 2011-03-04 23:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <9d6dd47e36dafad4e2f876d994f607e2.squirrel@www.codeaurora.org>

On Wed, Mar 2, 2011 at 1:26 PM, Carl Vanderlip <carlv@codeaurora.org> wrote:
> On Wed, 2011-03-02 at 13:17 -0800, Carl Vanderlip wrote:
>> From: Arve Hjønnevåg <arve@android.com>
>>
>> Don't allow non panning updates to bypass the wait for the panel to turn
> on.
>>
>> Signed-off-by: Carl Vanderlip <carlv@codeaurora.org>
>
> Arve,
>
>        This patch did not have a SOB from you. Would you sign off on this patch?
>

Yes, you can add a sign-off and/or ack by me.

-- 
Arve Hjønnevåg

^ permalink raw reply

* [PATCH] video: pwm_backlight: Add check_fb hook
From: Robert Morell @ 2011-03-05  1:08 UTC (permalink / raw)
  To: Richard Purdie, Arun Murthy, Andrew Morton, Linus Walleij
  Cc: linux-fbdev, linux-kernel, Robert Morell

In systems with multiple framebuffer devices, one of the devices might
be blanked while another is unblanked.  In order for the backlight
blanking logic to know whether to turn off the backlight for a
particular framebuffer's blanking notification, it needs to be able to
check if a given framebuffer device corresponds to the backlight.

This plumbs the check_fb hook from core backlight through the
pwm_backlight helper to allow platform code to plug in a check_fb hook.

Signed-off-by: Robert Morell <rmorell@nvidia.com>
---
 drivers/video/backlight/pwm_bl.c |   11 +++++++++++
 include/linux/pwm_backlight.h    |    3 +++
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 21866ec..0f2c131 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -28,6 +28,7 @@ struct pwm_bl_data {
 	unsigned int		lth_brightness;
 	int			(*notify)(struct device *,
 					  int brightness);
+	int			(*check_fb)(struct device *, struct fb_info *);
 };
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -62,9 +63,18 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
 	return bl->props.brightness;
 }
 
+static int pwm_backlight_check_fb(struct backlight_device *bl,
+				  struct fb_info *info)
+{
+	struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+
+	return !pb->check_fb || pb->check_fb(pb->dev, info);
+}
+
 static const struct backlight_ops pwm_backlight_ops = {
 	.update_status	= pwm_backlight_update_status,
 	.get_brightness	= pwm_backlight_get_brightness,
+	.check_fb	= pwm_backlight_check_fb,
 };
 
 static int pwm_backlight_probe(struct platform_device *pdev)
@@ -95,6 +105,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
 	pb->period = data->pwm_period_ns;
 	pb->notify = data->notify;
+	pb->check_fb = data->check_fb;
 	pb->lth_brightness = data->lth_brightness *
 		(data->pwm_period_ns / data->max_brightness);
 	pb->dev = &pdev->dev;
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index e031e1a..5e3e25a 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -4,6 +4,8 @@
 #ifndef __LINUX_PWM_BACKLIGHT_H
 #define __LINUX_PWM_BACKLIGHT_H
 
+#include <linux/backlight.h>
+
 struct platform_pwm_backlight_data {
 	int pwm_id;
 	unsigned int max_brightness;
@@ -13,6 +15,7 @@ struct platform_pwm_backlight_data {
 	int (*init)(struct device *dev);
 	int (*notify)(struct device *dev, int brightness);
 	void (*exit)(struct device *dev);
+	int (*check_fb)(struct device *dev, struct fb_info *info);
 };
 
 #endif
-- 
1.7.3.4


^ permalink raw reply related

* Re: [PATCH v2 1/3] ARM: PXA: PXAFB: Fix double-free issue
From: Vasily Khoruzhick @ 2011-03-05 22:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298214147-11578-1-git-send-email-anarsoul@gmail.com>

Please discard this series.

PXA270/3xx overlay memory management is still broken - it was not good 
decision to allocate memory on open/close - after some time OS just does not 
have 115kb of contiguous memory, so it fails to allocate overlay fb memory 
after ~1h of uptime.

I'll rework it and resend soon.

Regards
Vasily

^ permalink raw reply

* [PATCH] video: add MODULE_DEVICE_TABLE
From: Axel Lin @ 2011-03-07  8:26 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ghozlane Toumi, David S. Miller, Alan Hourihane, Paul Mundt,
	linux-fbdev

The device table is required to load modules based on modaliases.

Signed-off-by: Axel Lin <axel.lin@gmail.com>
Cc: Ghozlane Toumi <gtoumi@laposte.net>
Cc: David S. Miller <davem@davemloft.net>
Cc: Alan Hourihane <alanh@tungstengraphics.com>
---
 drivers/video/sstfb.c               |    1 +
 drivers/video/sunxvr2500.c          |    1 +
 drivers/video/sunxvr500.c           |    1 +
 drivers/video/vermilion/vermilion.c |    1 +
 4 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 2ab7041..597e80b 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1485,6 +1485,7 @@ static const struct pci_device_id sstfb_id_tbl[] = {
 		.driver_data = ID_VOODOO2, },
 	{ 0 },
 };
+MODULE_DEVICE_TABLE(pci, sstfb_id_tbl);
 
 static struct pci_driver sstfb_driver = {
 	.name		= "sstfb",
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
index 5848436..a83bc42 100644
--- a/drivers/video/sunxvr2500.c
+++ b/drivers/video/sunxvr2500.c
@@ -244,6 +244,7 @@ static struct pci_device_id s3d_pci_table[] = {
 	{	PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0033),	},
 	{ 0, }
 };
+MODULE_DEVICE_TABLE(pci, s3d_pci_table);
 
 static struct pci_driver s3d_driver = {
 	.name		= "s3d",
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
index b9c2b94..19e0395 100644
--- a/drivers/video/sunxvr500.c
+++ b/drivers/video/sunxvr500.c
@@ -428,6 +428,7 @@ static struct pci_device_id e3d_pci_table[] = {
 	},
 	{ 0, }
 };
+MODULE_DEVICE_TABLE(pci, e3d_pci_table);
 
 static struct pci_driver e3d_driver = {
 	.name		= "e3d",
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 931a567..30bd156 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -1057,6 +1057,7 @@ static struct pci_device_id vml_ids[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)},
 	{0}
 };
+MODULE_DEVICE_TABLE(pci, vml_ids);
 
 static struct pci_driver vmlfb_pci_driver = {
 	.name = "vmlfb",
-- 
1.7.2




^ permalink raw reply related

* Re: [PATCH v2] matroxfb: remove incorrect Matrox G200eV support
From: Benjamin Herrenschmidt @ 2011-03-07  8:59 UTC (permalink / raw)
  To: djwong
  Cc: Linus Torvalds, Gary Hade, linux-fbdev, linux-kernel,
	Krzysztof Helt, Petr Vandrovec, Andrew Morton
In-Reply-To: <20110304202905.GB27190@tux1.beaverton.ibm.com>

On Fri, 2011-03-04 at 12:29 -0800, Darrick J. Wong wrote:
> This is all quite strange -- 2.5 years ago when I wrote the patch it
> seemed to
> work ok.  On newer revisions of the x3650M2 it seems broken.  The
> original
> machine I wrote it for was cut up ages ago.
> 
> I suppose we could simply blacklist any G200eV with a subsystem vendor
> ID of
> 0x1014 (IBM) until we figure out how to correct the driver.  Our
> customers will
> be deprived, but as it seems to be broken across most of our product
> lines I
> doubt any of them are making serious use of it anyway. :)
> 
> Something like this? 

Does X work with the open source drivers ? In that case a better
approach would be to try to figure out what's different between the way
the 2 drivers setup the card registers and fix matroxfb..

Cheers,
Ben.



^ permalink raw reply

* Re: [PATCH] video: add MODULE_DEVICE_TABLE
From: Alan Cox @ 2011-03-07 10:31 UTC (permalink / raw)
  To: Axel Lin
  Cc: linux-kernel, Ghozlane Toumi, David S. Miller, Alan Hourihane,
	Paul Mundt, linux-fbdev
In-Reply-To: <1299486373.20702.1.camel@mola>

On Mon, 07 Mar 2011 16:26:13 +0800
Axel Lin <axel.lin@gmail.com> wrote:

> The device table is required to load modules based on modaliases.

Doing this then triggers autoloading which for some of these drivers is
the wrong thing.

> diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
> index 2ab7041..597e80b 100644
> --- a/drivers/video/sstfb.c
> +++ b/drivers/video/sstfb.c
> @@ -1485,6 +1485,7 @@ static const struct pci_device_id sstfb_id_tbl[] = {
>  		.driver_data = ID_VOODOO2, },
>  	{ 0 },
>  };
> +MODULE_DEVICE_TABLE(pci, sstfb_id_tbl);

NAK - as things stand in the frame buffer world you don't want sstfb
autoloading and stealing your main framebuffer away.


^ permalink raw reply

* Re: [Drbd-dev] [PATCH 2/2 v2] netlink: kill eff_cap from struct netlink_skb_parms
From: Patrick McHardy @ 2011-03-08 14:50 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Chris Wright, David Miller, linux-fbdev, netdev,
	linux-security-module, dm-devel, drbd-dev
In-Reply-To: <20110304012956.GA13573@ioremap.net>

Am 04.03.2011 02:29, schrieb Evgeniy Polyakov:
> Hi.
> 
> On Thu, Mar 03, 2011 at 11:37:46PM +0100, Lars Ellenberg (lars.ellenberg@linbit.com) wrote:
>> If so, then this change introduces the possibility for normal users to
>> send privileged commands to connector based subsystems, even if they
>> may not be able to bind() to suitable sockets to receive any replies.
>>
>> Am I missing something?
> 
> Yup, connector is very async at that place, but I wonder why the hell I
> ever made that decision. I believe we can replace it with pure sync call
> of the registered connector callback, since netlink is synchronous and
> no one has any problem with it.
> 

Are you going to do this or do you want me to take care of it?

^ permalink raw reply

* Re: [Drbd-dev] [PATCH 2/2 v2] netlink: kill eff_cap from struct
From: Evgeniy Polyakov @ 2011-03-08 18:32 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Chris Wright, David Miller, linux-fbdev, netdev,
	linux-security-module, dm-devel, drbd-dev
In-Reply-To: <4D764247.9080509@trash.net>

Hi Patrick.

On Tue, Mar 08, 2011 at 03:50:47PM +0100, Patrick McHardy (kaber@trash.net) wrote:
> > Yup, connector is very async at that place, but I wonder why the hell I
> > ever made that decision. I believe we can replace it with pure sync call
> > of the registered connector callback, since netlink is synchronous and
> > no one has any problem with it.
> 
> Are you going to do this or do you want me to take care of it?

I will return back at the end of the week and will take care of this
problem. I will not mind if you complete it first though :)

-- 
	Evgeniy Polyakov

^ permalink raw reply

* Re: [Drbd-dev] [PATCH 2/2 v2] netlink: kill eff_cap from struct netlink_skb_parms
From: Patrick McHardy @ 2011-03-08 18:54 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Chris Wright, David Miller, linux-fbdev, netdev,
	linux-security-module, dm-devel, drbd-dev
In-Reply-To: <20110308183246.GA17412@ioremap.net>

Am 08.03.2011 19:32, schrieb Evgeniy Polyakov:
> Hi Patrick.
> 
> On Tue, Mar 08, 2011 at 03:50:47PM +0100, Patrick McHardy (kaber@trash.net) wrote:
>>> Yup, connector is very async at that place, but I wonder why the hell I
>>> ever made that decision. I believe we can replace it with pure sync call
>>> of the registered connector callback, since netlink is synchronous and
>>> no one has any problem with it.
>>
>> Are you going to do this or do you want me to take care of it?
> 
> I will return back at the end of the week and will take care of this
> problem. I will not mind if you complete it first though :)

Thanks Evgeniy, I'll give it a shot.

^ permalink raw reply

* [PATCH 0/6] OMAP: DSS2: DSI: IRQ restructuring
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen

Hi,

In the future we will have more features using the DSI interrupts, like ULPS
handling, and making use-case specific hooks into the main IRQ handler would
become burdensome.

This patch set cleans up the DSI IRQ handling a bit by implementing a generic
way to register/unregister interrupt service routines. This allows us to remove
the use-case specific callbacks from the main IRQ handler.

 Tomi

Tomi Valkeinen (6):
  OMAP: DSS2: DSI: Restructure IRQ handler
  OMAP: DSS2: DSI: Add ISR support
  OMAP: DSS2: DSI: use ISR in send_bta_sync
  OMAP: DSS2: DSI: use ISR for BTA in framedone
  OMAP: DSS2: DSI: catch DSI errors in send_bta_sync
  OMAP: DSS2: DSI: fix IRQ debug prints

 drivers/video/omap2/dss/dsi.c |  523 ++++++++++++++++++++++++++++++++---------
 1 files changed, 408 insertions(+), 115 deletions(-)


^ permalink raw reply

* [PATCH 1/6] OMAP: DSS2: DSI: Restructure IRQ handler
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

Clean up the IRQ handler a bit by separating collection of IRQ stats and
handling of IRQ errors to separate functions.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |  123 ++++++++++++++++++++++++-----------------
 1 files changed, 73 insertions(+), 50 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index be7694f..a0881da 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -480,26 +480,33 @@ static void print_irq_status_cio(u32 status)
 	printk("\n");
 }
 
-static int debug_irq;
-
-/* called from dss */
-static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
+static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
 {
-	u32 irqstatus, vcstatus, ciostatus;
 	int i;
 
-	irqstatus = dsi_read_reg(DSI_IRQSTATUS);
-
-	/* IRQ is not for us */
-	if (!irqstatus)
-		return IRQ_NONE;
-
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
 	spin_lock(&dsi.irq_stats_lock);
+
 	dsi.irq_stats.irq_count++;
 	dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+
+	for (i = 0; i < 4; ++i)
+		dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+
+	dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+
+	spin_unlock(&dsi.irq_stats_lock);
+}
+#else
+#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
 #endif
 
+static int debug_irq;
+
+static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+	int i;
+
 	if (irqstatus & DSI_IRQ_ERROR_MASK) {
 		DSSERR("DSI error, irqstatus %x\n", irqstatus);
 		print_irq_status(irqstatus);
@@ -510,37 +517,48 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 		print_irq_status(irqstatus);
 	}
 
-#ifdef DSI_CATCH_MISSING_TE
-	if (irqstatus & DSI_IRQ_TE_TRIGGER)
-		del_timer(&dsi.te_timer);
-#endif
-
 	for (i = 0; i < 4; ++i) {
-		if ((irqstatus & (1<<i)) = 0)
-			continue;
+		if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
+			DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
+				       i, vcstatus[i]);
+			print_irq_status_vc(i, vcstatus[i]);
+		} else if (debug_irq) {
+			print_irq_status_vc(i, vcstatus[i]);
+		}
+	}
 
-		vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+	if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
+		DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
+		print_irq_status_cio(ciostatus);
+	} else if (debug_irq) {
+		print_irq_status_cio(ciostatus);
+	}
+}
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-		dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
-#endif
+static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
+{
+	u32 irqstatus, vcstatus[4], ciostatus;
+	int i;
 
-		if (vcstatus & DSI_VC_IRQ_BTA) {
-			complete(&dsi.bta_completion);
+	irqstatus = dsi_read_reg(DSI_IRQSTATUS);
 
-			if (dsi.bta_callback)
-				dsi.bta_callback();
-		}
+	/* IRQ is not for us */
+	if (!irqstatus)
+		return IRQ_NONE;
 
-		if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
-			DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
-				       i, vcstatus);
-			print_irq_status_vc(i, vcstatus);
-		} else if (debug_irq) {
-			print_irq_status_vc(i, vcstatus);
+	dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+	/* flush posted write */
+	dsi_read_reg(DSI_IRQSTATUS);
+
+	for (i = 0; i < 4; ++i) {
+		if ((irqstatus & (1 << i)) = 0) {
+			vcstatus[i] = 0;
+			continue;
 		}
 
-		dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
+		vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+
+		dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
 		/* flush posted write */
 		dsi_read_reg(DSI_VC_IRQSTATUS(i));
 	}
@@ -548,29 +566,34 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 	if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
 		ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-		dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
-#endif
-
 		dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
 		/* flush posted write */
 		dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+	} else {
+		ciostatus = 0;
+	}
 
-		if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
-			DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
-			print_irq_status_cio(ciostatus);
-		} else if (debug_irq) {
-			print_irq_status_cio(ciostatus);
+#ifdef DSI_CATCH_MISSING_TE
+	if (irqstatus & DSI_IRQ_TE_TRIGGER)
+		del_timer(&dsi.te_timer);
+#endif
+
+	for (i = 0; i < 4; ++i) {
+		if (vcstatus[i] = 0)
+			continue;
+
+		if (vcstatus[i] & DSI_VC_IRQ_BTA) {
+			complete(&dsi.bta_completion);
+
+			if (dsi.bta_callback)
+				dsi.bta_callback();
 		}
 	}
 
-	dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
-	/* flush posted write */
-	dsi_read_reg(DSI_IRQSTATUS);
+	dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+
+	dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
 
-#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-	spin_unlock(&dsi.irq_stats_lock);
-#endif
 	return IRQ_HANDLED;
 }
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH 2/6] OMAP: DSS2: DSI: Add ISR support
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

Add generic ISR support for DSI interrupts. ISRs can be used instead of
custom hooks in the interrupt handler.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |  325 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 301 insertions(+), 24 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index a0881da..9aea9a7 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -193,6 +193,16 @@ struct dsi_reg { u16 idx; };
 #define REGM_DSI_MAX (1 << 4)
 #define LP_DIV_MAX ((1 << 13) - 1)
 
+typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+
+#define DSI_MAX_NR_ISRS                2
+
+struct dsi_isr_data {
+	omap_dsi_isr_t	isr;
+	void		*arg;
+	u32		mask;
+};
+
 enum fifo_size {
 	DSI_FIFO_SIZE_0		= 0,
 	DSI_FIFO_SIZE_32	= 1,
@@ -219,6 +229,12 @@ struct dsi_irq_stats {
 	unsigned cio_irqs[32];
 };
 
+struct dsi_isr_tables {
+	struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
+	struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
+	struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
+};
+
 static struct
 {
 	struct platform_device *pdev;
@@ -244,6 +260,11 @@ static struct
 	struct completion bta_completion;
 	void (*bta_callback)(void);
 
+	spinlock_t irq_lock;
+	struct dsi_isr_tables isr_tables;
+	/* space for a copy used by the interrupt handler */
+	struct dsi_isr_tables isr_tables_copy;
+
 	int update_channel;
 	struct dsi_update_region update_region;
 
@@ -535,11 +556,49 @@ static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
 	}
 }
 
+static void dsi_call_isrs(struct dsi_isr_data *isr_array,
+		unsigned isr_array_size, u32 irqstatus)
+{
+	struct dsi_isr_data *isr_data;
+	int i;
+
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+		if (isr_data->isr && isr_data->mask & irqstatus)
+			isr_data->isr(isr_data->arg, irqstatus);
+	}
+}
+
+static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
+		u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+{
+	int i;
+
+	dsi_call_isrs(isr_tables->isr_table,
+			ARRAY_SIZE(isr_tables->isr_table),
+			irqstatus);
+
+	for (i = 0; i < 4; ++i) {
+		if (vcstatus[i] = 0)
+			continue;
+		dsi_call_isrs(isr_tables->isr_table_vc[i],
+				ARRAY_SIZE(isr_tables->isr_table_vc[i]),
+				vcstatus[i]);
+	}
+
+	if (ciostatus != 0)
+		dsi_call_isrs(isr_tables->isr_table_cio,
+				ARRAY_SIZE(isr_tables->isr_table_cio),
+				ciostatus);
+}
+
 static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 {
 	u32 irqstatus, vcstatus[4], ciostatus;
 	int i;
 
+	spin_lock(&dsi.irq_lock);
+
 	irqstatus = dsi_read_reg(DSI_IRQSTATUS);
 
 	/* IRQ is not for us */
@@ -590,6 +649,14 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 		}
 	}
 
+	/* make a copy and unlock, so that isrs can unregister
+	 * themselves */
+	memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+
+	spin_unlock(&dsi.irq_lock);
+
+	dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+
 	dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
 
 	dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
@@ -597,42 +664,251 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 	return IRQ_HANDLED;
 }
 
-static void _dsi_initialize_irq(void)
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+		unsigned isr_array_size, u32 default_mask,
+		const struct dsi_reg enable_reg,
+		const struct dsi_reg status_reg)
 {
-	u32 l;
+	struct dsi_isr_data *isr_data;
+	u32 mask;
+	u32 old_mask;
 	int i;
 
-	/* disable all interrupts */
-	dsi_write_reg(DSI_IRQENABLE, 0);
-	for (i = 0; i < 4; ++i)
-		dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
+	mask = default_mask;
 
-	/* clear interrupt status */
-	l = dsi_read_reg(DSI_IRQSTATUS);
-	dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
 
-	for (i = 0; i < 4; ++i) {
-		l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
-		dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
+		if (isr_data->isr = NULL)
+			continue;
+
+		mask |= isr_data->mask;
 	}
 
-	l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
+	old_mask = dsi_read_reg(enable_reg);
+	/* clear the irqstatus for newly enabled irqs */
+	dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
+	dsi_write_reg(enable_reg, mask);
+
+	/* flush posted writes */
+	dsi_read_reg(enable_reg);
+	dsi_read_reg(status_reg);
+}
 
-	/* enable error irqs */
-	l = DSI_IRQ_ERROR_MASK;
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(void)
+{
+	u32 mask = DSI_IRQ_ERROR_MASK;
 #ifdef DSI_CATCH_MISSING_TE
-	l |= DSI_IRQ_TE_TRIGGER;
+	mask |= DSI_IRQ_TE_TRIGGER;
 #endif
-	dsi_write_reg(DSI_IRQENABLE, l);
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+			DSI_IRQENABLE, DSI_IRQSTATUS);
+}
 
-	l = DSI_VC_IRQ_ERROR_MASK;
-	for (i = 0; i < 4; ++i)
-		dsi_write_reg(DSI_VC_IRQENABLE(i), l);
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(int vc)
+{
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+			DSI_VC_IRQ_ERROR_MASK,
+			DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
+}
+
+/* dsi.irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(void)
+{
+	_omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+			DSI_CIO_IRQ_ERROR_MASK,
+			DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
+}
+
+static void _dsi_initialize_irq(void)
+{
+	unsigned long flags;
+	int vc;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+
+	_omap_dsi_set_irqs();
+	for (vc = 0; vc < 4; ++vc)
+		_omap_dsi_set_irqs_vc(vc);
+	_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+}
+
+static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+		struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+	struct dsi_isr_data *isr_data;
+	int free_idx;
+	int i;
+
+	BUG_ON(isr = NULL);
+
+	/* check for duplicate entry and find a free slot */
+	free_idx = -1;
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+
+		if (isr_data->isr = isr && isr_data->arg = arg &&
+				isr_data->mask = mask) {
+			return -EINVAL;
+		}
+
+		if (isr_data->isr = NULL && free_idx = -1)
+			free_idx = i;
+	}
+
+	if (free_idx = -1)
+		return -EBUSY;
+
+	isr_data = &isr_array[free_idx];
+	isr_data->isr = isr;
+	isr_data->arg = arg;
+	isr_data->mask = mask;
+
+	return 0;
+}
+
+static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
+		struct dsi_isr_data *isr_array, unsigned isr_array_size)
+{
+	struct dsi_isr_data *isr_data;
+	int i;
+
+	for (i = 0; i < isr_array_size; i++) {
+		isr_data = &isr_array[i];
+		if (isr_data->isr != isr || isr_data->arg != arg ||
+				isr_data->mask != mask)
+			continue;
+
+		isr_data->isr = NULL;
+		isr_data->arg = NULL;
+		isr_data->mask = 0;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+	if (r = 0)
+		_omap_dsi_set_irqs();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
+			ARRAY_SIZE(dsi.isr_tables.isr_table));
+
+	if (r = 0)
+		_omap_dsi_set_irqs();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+		u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask,
+			dsi.isr_tables.isr_table_vc[channel],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+	if (r = 0)
+		_omap_dsi_set_irqs_vc(channel);
 
-	l = DSI_CIO_IRQ_ERROR_MASK;
-	dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
+		u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask,
+			dsi.isr_tables.isr_table_vc[channel],
+			ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+
+	if (r = 0)
+		_omap_dsi_set_irqs_vc(channel);
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+	if (r = 0)
+		_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
+}
+
+static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+{
+	unsigned long flags;
+	int r;
+
+	spin_lock_irqsave(&dsi.irq_lock, flags);
+
+	r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
+			ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+
+	if (r = 0)
+		_omap_dsi_set_irqs_cio();
+
+	spin_unlock_irqrestore(&dsi.irq_lock, flags);
+
+	return r;
 }
 
 static u32 dsi_get_errors(void)
@@ -3362,6 +3638,7 @@ static int dsi_init(struct platform_device *pdev)
 	int r, i;
 	struct resource *dsi_mem;
 
+	spin_lock_init(&dsi.irq_lock);
 	spin_lock_init(&dsi.errors_lock);
 	dsi.errors = 0;
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH 3/6] OMAP: DSS2: DSI: use ISR in send_bta_sync
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

Remove bta_completion handling from the interrupt handler, and use ISR
support instead.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |   32 ++++++++++++++++++--------------
 1 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 9aea9a7..a4d47dd 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -257,7 +257,6 @@ static struct
 
 	unsigned pll_locked;
 
-	struct completion bta_completion;
 	void (*bta_callback)(void);
 
 	spinlock_t irq_lock;
@@ -341,6 +340,11 @@ static bool dsi_bus_is_locked(void)
 	return dsi.bus_lock.count = 0;
 }
 
+static void dsi_completion_handler(void *data, u32 mask)
+{
+	complete((struct completion *)data);
+}
+
 static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
 		int value)
 {
@@ -642,8 +646,6 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 			continue;
 
 		if (vcstatus[i] & DSI_VC_IRQ_BTA) {
-			complete(&dsi.bta_completion);
-
 			if (dsi.bta_callback)
 				dsi.bta_callback();
 		}
@@ -2251,33 +2253,37 @@ static int dsi_vc_send_bta(int channel)
 
 int dsi_vc_send_bta_sync(int channel)
 {
+	DECLARE_COMPLETION_ONSTACK(completion);
 	int r = 0;
 	u32 err;
 
-	INIT_COMPLETION(dsi.bta_completion);
-
-	dsi_vc_enable_bta_irq(channel);
+	r = dsi_register_isr_vc(channel, dsi_completion_handler,
+			&completion, DSI_VC_IRQ_BTA);
+	if (r)
+		goto err0;
 
 	r = dsi_vc_send_bta(channel);
 	if (r)
-		goto err;
+		goto err1;
 
-	if (wait_for_completion_timeout(&dsi.bta_completion,
+	if (wait_for_completion_timeout(&completion,
 				msecs_to_jiffies(500)) = 0) {
 		DSSERR("Failed to receive BTA\n");
 		r = -EIO;
-		goto err;
+		goto err1;
 	}
 
 	err = dsi_get_errors();
 	if (err) {
 		DSSERR("Error while sending BTA: %x\n", err);
 		r = -EIO;
-		goto err;
+		goto err1;
 	}
-err:
-	dsi_vc_disable_bta_irq(channel);
 
+err1:
+	dsi_unregister_isr_vc(channel, dsi_completion_handler,
+			&completion, DSI_VC_IRQ_BTA);
+err0:
 	return r;
 }
 EXPORT_SYMBOL(dsi_vc_send_bta_sync);
@@ -3647,8 +3653,6 @@ static int dsi_init(struct platform_device *pdev)
 	dsi.irq_stats.last_reset = jiffies;
 #endif
 
-	init_completion(&dsi.bta_completion);
-
 	mutex_init(&dsi.lock);
 	sema_init(&dsi.bus_lock, 1);
 
-- 
1.7.1


^ permalink raw reply related

* [PATCH 4/6] OMAP: DSS2: DSI: use ISR for BTA in framedone
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

Remove bta_callback from the interrupt handler, and use ISR support
instead.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |   57 +++++++++++------------------------------
 1 files changed, 15 insertions(+), 42 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index a4d47dd..5672e40 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -257,8 +257,6 @@ static struct
 
 	unsigned pll_locked;
 
-	void (*bta_callback)(void);
-
 	spinlock_t irq_lock;
 	struct dsi_isr_tables isr_tables;
 	/* space for a copy used by the interrupt handler */
@@ -641,16 +639,6 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 		del_timer(&dsi.te_timer);
 #endif
 
-	for (i = 0; i < 4; ++i) {
-		if (vcstatus[i] = 0)
-			continue;
-
-		if (vcstatus[i] & DSI_VC_IRQ_BTA) {
-			if (dsi.bta_callback)
-				dsi.bta_callback();
-		}
-	}
-
 	/* make a copy and unlock, so that isrs can unregister
 	 * themselves */
 	memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
@@ -924,26 +912,6 @@ static u32 dsi_get_errors(void)
 	return e;
 }
 
-static void dsi_vc_enable_bta_irq(int channel)
-{
-	u32 l;
-
-	dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
-
-	l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-	l |= DSI_VC_IRQ_BTA;
-	dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
-}
-
-static void dsi_vc_disable_bta_irq(int channel)
-{
-	u32 l;
-
-	l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
-	l &= ~DSI_VC_IRQ_BTA;
-	dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
-}
-
 /* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
 static inline void enable_clocks(bool enable)
 {
@@ -3097,19 +3065,20 @@ static void dsi_te_timeout(unsigned long arg)
 }
 #endif
 
+static void dsi_framedone_bta_callback(void *data, u32 mask);
+
 static void dsi_handle_framedone(int error)
 {
 	const int channel = dsi.update_channel;
 
-	cancel_delayed_work(&dsi.framedone_timeout_work);
+	dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+			NULL, DSI_VC_IRQ_BTA);
 
-	dsi_vc_disable_bta_irq(channel);
+	cancel_delayed_work(&dsi.framedone_timeout_work);
 
 	/* SIDLEMODE back to smart-idle */
 	dispc_enable_sidle();
 
-	dsi.bta_callback = NULL;
-
 	if (dsi.te_enabled) {
 		/* enable LP_RX_TO again after the TE */
 		REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
@@ -3143,7 +3112,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 	dsi_handle_framedone(-ETIMEDOUT);
 }
 
-static void dsi_framedone_bta_callback(void)
+static void dsi_framedone_bta_callback(void *data, u32 mask)
 {
 	dsi_handle_framedone(0);
 
@@ -3183,15 +3152,19 @@ static void dsi_framedone_irq_callback(void *data, u32 mask)
 	 * asynchronously.
 	 * */
 
-	dsi.bta_callback = dsi_framedone_bta_callback;
-
-	barrier();
-
-	dsi_vc_enable_bta_irq(channel);
+	r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
+			NULL, DSI_VC_IRQ_BTA);
+	if (r) {
+		DSSERR("Failed to register BTA ISR\n");
+		dsi_handle_framedone(-EIO);
+		return;
+	}
 
 	r = dsi_vc_send_bta(channel);
 	if (r) {
 		DSSERR("BTA after framedone failed\n");
+		dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
+				NULL, DSI_VC_IRQ_BTA);
 		dsi_handle_framedone(-EIO);
 	}
 }
-- 
1.7.1


^ permalink raw reply related

* [PATCH 5/6] OMAP: DSS2: DSI: catch DSI errors in send_bta_sync
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

dsi_vc_send_bta_sync() waits for BTA interrupt with a 500ms timeout. If
a DSI error happens, no BTA is received and the timeout triggers. This
could be handled much faster by listening to DSI errors also.

This patch uses the ISR support to notice DSI errors while waiting for
the BTA, thus speeding up the fail-path considerably.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |   15 +++++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 5672e40..ec5b879 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2230,24 +2230,31 @@ int dsi_vc_send_bta_sync(int channel)
 	if (r)
 		goto err0;
 
-	r = dsi_vc_send_bta(channel);
+	r = dsi_register_isr(dsi_completion_handler, &completion,
+			DSI_IRQ_ERROR_MASK);
 	if (r)
 		goto err1;
 
+	r = dsi_vc_send_bta(channel);
+	if (r)
+		goto err2;
+
 	if (wait_for_completion_timeout(&completion,
 				msecs_to_jiffies(500)) = 0) {
 		DSSERR("Failed to receive BTA\n");
 		r = -EIO;
-		goto err1;
+		goto err2;
 	}
 
 	err = dsi_get_errors();
 	if (err) {
 		DSSERR("Error while sending BTA: %x\n", err);
 		r = -EIO;
-		goto err1;
+		goto err2;
 	}
-
+err2:
+	dsi_unregister_isr(dsi_completion_handler, &completion,
+			DSI_IRQ_ERROR_MASK);
 err1:
 	dsi_unregister_isr_vc(channel, dsi_completion_handler,
 			&completion, DSI_VC_IRQ_BTA);
-- 
1.7.1


^ permalink raw reply related

* [PATCH 6/6] OMAP: DSS2: DSI: fix IRQ debug prints
From: Tomi Valkeinen @ 2011-03-09  7:21 UTC (permalink / raw)
  To: linux-omap, linux-fbdev; +Cc: Tomi Valkeinen
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

print_irq_status functions can be called with empty irq status when full
irq debugging is enabled. This patch makes print_irq_status functions
return immediately when given an empty irq status to lessen the debug
spam slightly.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
 drivers/video/omap2/dss/dsi.c |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index ec5b879..f6733b5 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -412,6 +412,9 @@ static void dsi_perf_show(const char *name)
 
 static void print_irq_status(u32 status)
 {
+	if (status = 0)
+		return;
+
 #ifndef VERBOSE_IRQ
 	if ((status & ~DSI_IRQ_CHANNEL_MASK) = 0)
 		return;
@@ -447,6 +450,9 @@ static void print_irq_status(u32 status)
 
 static void print_irq_status_vc(int channel, u32 status)
 {
+	if (status = 0)
+		return;
+
 #ifndef VERBOSE_IRQ
 	if ((status & ~DSI_VC_IRQ_PACKET_SENT) = 0)
 		return;
@@ -473,6 +479,9 @@ static void print_irq_status_vc(int channel, u32 status)
 
 static void print_irq_status_cio(u32 status)
 {
+	if (status = 0)
+		return;
+
 	printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
 
 #define PIS(x) \
-- 
1.7.1


^ permalink raw reply related

* Re: [PATCH 0/6] OMAP: DSS2: DSI: IRQ restructuring
From: archit taneja @ 2011-03-09 13:50 UTC (permalink / raw)
  To: Valkeinen, Tomi; +Cc: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <1299655288-7121-1-git-send-email-tomi.valkeinen@ti.com>

On Wednesday 09 March 2011 12:51 PM, Valkeinen, Tomi wrote:
> Hi,
>
> In the future we will have more features using the DSI interrupts, like ULPS
> handling, and making use-case specific hooks into the main IRQ handler would
> become burdensome.
>
> This patch set cleans up the DSI IRQ handling a bit by implementing a generic
> way to register/unregister interrupt service routines. This allows us to remove
> the use-case specific callbacks from the main IRQ handler.
>

Would this make it more easy/difficult to migrate to irq_chip(if needed) 
later on? I guess it will atleast bring dispc and dsi irq 
requesting/handling in a similar state, hence the changes needed to move 
to irq_chip would be the same for both.

Archit

>   Tomi
>
> Tomi Valkeinen (6):
>    OMAP: DSS2: DSI: Restructure IRQ handler
>    OMAP: DSS2: DSI: Add ISR support
>    OMAP: DSS2: DSI: use ISR in send_bta_sync
>    OMAP: DSS2: DSI: use ISR for BTA in framedone
>    OMAP: DSS2: DSI: catch DSI errors in send_bta_sync
>    OMAP: DSS2: DSI: fix IRQ debug prints
>
>   drivers/video/omap2/dss/dsi.c |  523 ++++++++++++++++++++++++++++++++---------
>   1 files changed, 408 insertions(+), 115 deletions(-)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" 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 0/6] OMAP: DSS2: DSI: IRQ restructuring
From: Tomi Valkeinen @ 2011-03-09 14:45 UTC (permalink / raw)
  To: Taneja, Archit; +Cc: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
In-Reply-To: <4D77868A.7020700@ti.com>

On Wed, 2011-03-09 at 07:54 -0600, Taneja, Archit wrote:
> On Wednesday 09 March 2011 12:51 PM, Valkeinen, Tomi wrote:
> > Hi,
> >
> > In the future we will have more features using the DSI interrupts, like ULPS
> > handling, and making use-case specific hooks into the main IRQ handler would
> > become burdensome.
> >
> > This patch set cleans up the DSI IRQ handling a bit by implementing a generic
> > way to register/unregister interrupt service routines. This allows us to remove
> > the use-case specific callbacks from the main IRQ handler.
> >
> 
> Would this make it more easy/difficult to migrate to irq_chip(if needed) 
> later on? I guess it will atleast bring dispc and dsi irq 
> requesting/handling in a similar state, hence the changes needed to move 
> to irq_chip would be the same for both.

Well, I'm not really familiar with irq_chip, but I don't see how this
could make it more difficult. It divides the code in cleaner way,
removing irq specific callbacks in the irq handler, so it should make
migrating easier, if anything.

 Tomi



^ permalink raw reply

* Re: [PATCH v2] fbdev: sh_mobile_lcdc: Add YUV input support
From: Paul Mundt @ 2011-03-11  4:54 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <1298526433-6621-1-git-send-email-dhobsong@igel.co.jp>

On Wed, Mar 02, 2011 at 03:42:13PM +0900, Damian wrote:
> Supports YCbCr420sp, YCbCr422sp, and YCbCr44sp, formats
> (bpp = 12, 16, and 24) respectively.
> 
> When double-buffering both Y planes appear before the C planes (Y-Y-C-C),
> as opposed to  Y-C-Y-C.
> Set .nonstd in struct sh_mobile_lcdc_chan_cfg to enable YUV mode, and use
> .bpp to distiguish between the 3 modes.
> The value of .nonstd is copied to bits 16-31 of LDDFR in the LCDC and
> should be set accordingly.
> .nonstd must be set to 0 for RGB mode.
> 
> Due to the encoding of YUV data, the framebuffer will clear to green
> instead of black.
> 
> In YUV 420 mode, panning is only possible in 2 line increments.
> Additionally in YUV 420 mode the vertical resolution of the framebuffer
> must be an even number.
> 
> Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>

This version of the patch was horribly line-wrapped, but the previous one
'fbdev: sh_mobile_lcdc: Add YUV framebuffer support' which seemed to have
an identical description and versioning looked fine, so I've taken that
one in to the fbdev tree.

You may wish to double check to make sure that what has been merged is in
sync with your latest changes.

^ permalink raw reply

* [PATCH 1/4] ARM: PXA: PXAFB: rework pxafb overlay memory management
From: Vasily Khoruzhick @ 2011-03-11  9:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201103060030.59584.anarsoul@gmail.com>

PXAFB overlay memory management is something messy:
- it allocates memory dynamically on open/release, and it results
  in memory allocation failure after ~1h of uptime (system does not have
  115k of physically contiguous memory)
- in release callback it tries to free memory even if it was not
  allocated.

Also driver touches FDADR1 on main plane reconfiguration, and it can cause
problems if overlay1 is enabled.

This patch attempts to fix those issues.

Patch is based on Russell King's work.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/video/pxafb.c |  121 ++++++++++++++++++++++++++++++++-----------------
 drivers/video/pxafb.h |    3 +-
 2 files changed, 81 insertions(+), 43 deletions(-)

diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 825b665..0764759 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -627,7 +627,12 @@ static void overlay1fb_enable(struct pxafb_layer *ofb)
 
 static void overlay1fb_disable(struct pxafb_layer *ofb)
 {
-	uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
+	uint32_t lccr5;
+
+	if (!(lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN))
+		return;
+
+	lccr5 = lcd_readl(ofb->fbi, LCCR5);
 
 	lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
 
@@ -685,7 +690,12 @@ static void overlay2fb_enable(struct pxafb_layer *ofb)
 
 static void overlay2fb_disable(struct pxafb_layer *ofb)
 {
-	uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
+	uint32_t lccr5;
+
+	if (!(lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN))
+		return;
+
+	lccr5 = lcd_readl(ofb->fbi, LCCR5);
 
 	lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
 
@@ -720,12 +730,10 @@ static int overlayfb_open(struct fb_info *info, int user)
 	if (user = 0)
 		return -ENODEV;
 
-	/* allow only one user at a time */
-	if (atomic_inc_and_test(&ofb->usage))
-		return -EBUSY;
+	if (ofb->usage++ = 0)
+		/* unblank the base framebuffer */
+		fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
 
-	/* unblank the base framebuffer */
-	fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
 	return 0;
 }
 
@@ -733,12 +741,15 @@ static int overlayfb_release(struct fb_info *info, int user)
 {
 	struct pxafb_layer *ofb = (struct pxafb_layer*) info;
 
-	atomic_dec(&ofb->usage);
-	ofb->ops->disable(ofb);
+	if (ofb->usage = 1) {
+		ofb->ops->disable(ofb);
+		ofb->fb.var.height	= -1;
+		ofb->fb.var.width	= -1;
+		ofb->fb.var.xres = ofb->fb.var.xres_virtual = 0;
+		ofb->fb.var.yres = ofb->fb.var.yres_virtual = 0;
 
-	free_pages_exact(ofb->video_mem, ofb->video_mem_size);
-	ofb->video_mem = NULL;
-	ofb->video_mem_size = 0;
+		ofb->usage--;
+	}
 	return 0;
 }
 
@@ -794,7 +805,7 @@ static int overlayfb_check_var(struct fb_var_screeninfo *var,
 	return 0;
 }
 
-static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
+static int overlayfb_check_video_memory(struct pxafb_layer *ofb)
 {
 	struct fb_var_screeninfo *var = &ofb->fb.var;
 	int pfor = NONSTD_TO_PFOR(var->nonstd);
@@ -812,27 +823,11 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
 
 	size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual);
 
-	/* don't re-allocate if the original video memory is enough */
 	if (ofb->video_mem) {
 		if (ofb->video_mem_size >= size)
 			return 0;
-
-		free_pages_exact(ofb->video_mem, ofb->video_mem_size);
 	}
-
-	ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
-	if (ofb->video_mem = NULL)
-		return -ENOMEM;
-
-	ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
-	ofb->video_mem_size = size;
-
-	mutex_lock(&ofb->fb.mm_lock);
-	ofb->fb.fix.smem_start	= ofb->video_mem_phys;
-	ofb->fb.fix.smem_len	= ofb->fb.fix.line_length * var->yres_virtual;
-	mutex_unlock(&ofb->fb.mm_lock);
-	ofb->fb.screen_base	= ofb->video_mem;
-	return 0;
+	return -EINVAL;
 }
 
 static int overlayfb_set_par(struct fb_info *info)
@@ -841,7 +836,7 @@ static int overlayfb_set_par(struct fb_info *info)
 	struct fb_var_screeninfo *var = &info->var;
 	int xpos, ypos, pfor, bpp, ret;
 
-	ret = overlayfb_map_video_memory(ofb);
+	ret = overlayfb_check_video_memory(ofb);
 	if (ret)
 		return ret;
 
@@ -891,7 +886,7 @@ static void __devinit init_pxafb_overlay(struct pxafb_info *fbi,
 
 	ofb->id = id;
 	ofb->ops = &ofb_ops[id];
-	atomic_set(&ofb->usage, 0);
+	ofb->usage = 0;
 	ofb->fbi = fbi;
 	init_completion(&ofb->branch_done);
 }
@@ -904,20 +899,54 @@ static inline int pxafb_overlay_supported(void)
 	return 0;
 }
 
-static int __devinit pxafb_overlay_init(struct pxafb_info *fbi)
+static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info *pxafb,
+	struct pxafb_layer *ofb)
+{
+	/* We assume that user will use at most video_mem_size for overlay fb,
+	 * anyway, it's useless to use 16bpp main plane and 24bpp overlay
+	 */
+	ofb->video_mem = alloc_pages_exact(PAGE_ALIGN(pxafb->video_mem_size),
+		GFP_KERNEL | __GFP_ZERO);
+	if (ofb->video_mem = NULL)
+		return -ENOMEM;
+
+	ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
+	ofb->video_mem_size = PAGE_ALIGN(pxafb->video_mem_size);
+
+	mutex_lock(&ofb->fb.mm_lock);
+	ofb->fb.fix.smem_start	= ofb->video_mem_phys;
+	ofb->fb.fix.smem_len	= pxafb->video_mem_size;
+	mutex_unlock(&ofb->fb.mm_lock);
+
+	ofb->fb.screen_base	= ofb->video_mem;
+
+	return 0;
+}
+
+static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
 {
 	int i, ret;
 
 	if (!pxafb_overlay_supported())
-		return 0;
+		return;
 
 	for (i = 0; i < 2; i++) {
-		init_pxafb_overlay(fbi, &fbi->overlay[i], i);
-		ret = register_framebuffer(&fbi->overlay[i].fb);
+		struct pxafb_layer *ofb = &fbi->overlay[i];
+		init_pxafb_overlay(fbi, ofb, i);
+		ret = register_framebuffer(&ofb->fb);
 		if (ret) {
 			dev_err(fbi->dev, "failed to register overlay %d\n", i);
-			return ret;
+			continue;
+		}
+		ret = pxafb_overlay_map_video_memory(fbi, ofb);
+		if (ret) {
+			dev_err(fbi->dev,
+				"failed to map video memory for overlay %d\n",
+				i);
+			unregister_framebuffer(&ofb->fb);
+			continue;
 		}
+		ofb->registered = 1;
 	}
 
 	/* mask all IU/BS/EOF/SOF interrupts */
@@ -926,7 +955,6 @@ static int __devinit pxafb_overlay_init(struct pxafb_info *fbi)
 	/* place overlay(s) on top of base */
 	fbi->lccr0 |= LCCR0_OUC;
 	pr_info("PXA Overlay driver loaded successfully!\n");
-	return 0;
 }
 
 static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
@@ -936,8 +964,15 @@ static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
 	if (!pxafb_overlay_supported())
 		return;
 
-	for (i = 0; i < 2; i++)
-		unregister_framebuffer(&fbi->overlay[i].fb);
+	for (i = 0; i < 2; i++) {
+		struct pxafb_layer *ofb = &fbi->overlay[i];
+		if (ofb->registered) {
+			if (ofb->video_mem)
+				free_pages_exact(ofb->video_mem,
+					ofb->video_mem_size);
+			unregister_framebuffer(&ofb->fb);
+		}
+	}
 }
 #else
 static inline void pxafb_overlay_init(struct pxafb_info *fbi) {}
@@ -1368,7 +1403,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 	    (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
 	    (lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) ||
 	    (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
-	    (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
+	    ((fbi->lccr0 & LCCR0_SDS) &&
+	    (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])))
 		pxafb_schedule_work(fbi, C_REENABLE);
 
 	return 0;
@@ -1420,7 +1456,8 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
 	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
 
 	lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
-	lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
+	if (fbi->lccr0 & LCCR0_SDS)
+		lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
 	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
 }
 
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 2353521..26ba9fa 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -92,7 +92,8 @@ struct pxafb_layer_ops {
 struct pxafb_layer {
 	struct fb_info		fb;
 	int			id;
-	atomic_t		usage;
+	int			registered;
+	uint32_t		usage;
 	uint32_t		control[2];
 
 	struct pxafb_layer_ops	*ops;
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 2/4] ARM: PXA: PXAFB: Fix plane Z-ordering problem
From: Vasily Khoruzhick @ 2011-03-11  9:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1299835250-11095-1-git-send-email-anarsoul@gmail.com>

pxafb_overlay_init is not right place to change Z-ordering,
move it to main plane initialization.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/video/pxafb.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 0764759..e2f643e 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -952,8 +952,6 @@ static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
 	/* mask all IU/BS/EOF/SOF interrupts */
 	lcd_writel(fbi, LCCR5, ~0);
 
-	/* place overlay(s) on top of base */
-	fbi->lccr0 |= LCCR0_OUC;
 	pr_info("PXA Overlay driver loaded successfully!\n");
 }
 
@@ -1843,6 +1841,12 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
 
 	pxafb_decode_mach_info(fbi, inf);
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+	/* place overlay(s) on top of base */
+	if (pxafb_overlay_supported())
+		fbi->lccr0 |= LCCR0_OUC;
+#endif
+
 	init_waitqueue_head(&fbi->ctrlr_wait);
 	INIT_WORK(&fbi->task, pxafb_task);
 	mutex_init(&fbi->ctrlr_lock);
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 3/4] ARM: PXA: PXAFB: Fix typo in ypos assignment
From: Vasily Khoruzhick @ 2011-03-11  9:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1299835250-11095-1-git-send-email-anarsoul@gmail.com>

Sascha Hauer <s.hauer@pengutronix.de> pointed that
ypos takes value of xpos due to typo.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/video/pxafb.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index e2f643e..a3bdcc1 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -761,7 +761,7 @@ static int overlayfb_check_var(struct fb_var_screeninfo *var,
 	int xpos, ypos, pfor, bpp;
 
 	xpos = NONSTD_TO_XPOS(var->nonstd);
-	ypos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
 	pfor = NONSTD_TO_PFOR(var->nonstd);
 
 	bpp = pxafb_var_to_bpp(var);
@@ -842,7 +842,7 @@ static int overlayfb_set_par(struct fb_info *info)
 
 	bpp  = pxafb_var_to_bpp(var);
 	xpos = NONSTD_TO_XPOS(var->nonstd);
-	ypos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
 	pfor = NONSTD_TO_PFOR(var->nonstd);
 
 	ofb->control[0] = OVLxC1_PPL(var->xres) | OVLxC1_LPO(var->yres) |
-- 
1.7.4.1


^ permalink raw reply related

* [PATCH 4/4] ARM: PXA: PXAFB: don't disable controller on cpufreq transition if overlay is in use
From: Vasily Khoruzhick @ 2011-03-11  9:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1299835250-11095-1-git-send-email-anarsoul@gmail.com>

It's not safe to disable controller if overlay(s) is enabled (results in
system hang). So we avoid to disable controller in this case. Userspace
should choose proper governor to avoid freq changing when overlay is in
use, otherwise LCD may blink.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/video/pxafb.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index a3bdcc1..a2e5b51 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1648,7 +1648,8 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
 
 	switch (val) {
 	case CPUFREQ_PRECHANGE:
-		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+		if (!fbi->overlay[0].usage && !fbi->overlay[1].usage)
+			set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-- 
1.7.4.1


^ permalink raw reply related

* Re: [PATCH 1/4] ARM: PXA: PXAFB: rework pxafb overlay memory management
From: Marek Vasut @ 2011-03-11 21:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1299835250-11095-1-git-send-email-anarsoul@gmail.com>

On Friday 11 March 2011 10:20:47 Vasily Khoruzhick wrote:
> PXAFB overlay memory management is something messy:
> - it allocates memory dynamically on open/release, and it results
>   in memory allocation failure after ~1h of uptime (system does not have
>   115k of physically contiguous memory)
> - in release callback it tries to free memory even if it was not
>   allocated.
> 
> Also driver touches FDADR1 on main plane reconfiguration, and it can cause
> problems if overlay1 is enabled.
> 
> This patch attempts to fix those issues.
> 
> Patch is based on Russell King's work.
> 
> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> ---
>  drivers/video/pxafb.c |  121
> ++++++++++++++++++++++++++++++++----------------- drivers/video/pxafb.h | 
>   3 +-
>  2 files changed, 81 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
> index 825b665..0764759 100644
> --- a/drivers/video/pxafb.c
> +++ b/drivers/video/pxafb.c
> @@ -627,7 +627,12 @@ static void overlay1fb_enable(struct pxafb_layer *ofb)
> 
>  static void overlay1fb_disable(struct pxafb_layer *ofb)
>  {
> -	uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
> +	uint32_t lccr5;
> +
> +	if (!(lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN))
> +		return;
> +
> +	lccr5 = lcd_readl(ofb->fbi, LCCR5);
> 
>  	lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
> 
> @@ -685,7 +690,12 @@ static void overlay2fb_enable(struct pxafb_layer *ofb)
> 
>  static void overlay2fb_disable(struct pxafb_layer *ofb)
>  {
> -	uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
> +	uint32_t lccr5;
> +
> +	if (!(lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN))
> +		return;
> +
> +	lccr5 = lcd_readl(ofb->fbi, LCCR5);
> 
>  	lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
> 
> @@ -720,12 +730,10 @@ static int overlayfb_open(struct fb_info *info, int
> user) if (user = 0)
>  		return -ENODEV;
> 
> -	/* allow only one user at a time */
> -	if (atomic_inc_and_test(&ofb->usage))
> -		return -EBUSY;
> +	if (ofb->usage++ = 0)

TBH I don't like this notation, it feels hard to read. Can you split that ofb-
>usage++ into two parts ?

Cheers

> +		/* unblank the base framebuffer */
> +		fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
> 
> -	/* unblank the base framebuffer */
> -	fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
>  	return 0;
>  }
> 
> @@ -733,12 +741,15 @@ static int overlayfb_release(struct fb_info *info,
> int user) {
>  	struct pxafb_layer *ofb = (struct pxafb_layer*) info;
> 
> -	atomic_dec(&ofb->usage);
> -	ofb->ops->disable(ofb);
> +	if (ofb->usage = 1) {
> +		ofb->ops->disable(ofb);
> +		ofb->fb.var.height	= -1;
> +		ofb->fb.var.width	= -1;
> +		ofb->fb.var.xres = ofb->fb.var.xres_virtual = 0;
> +		ofb->fb.var.yres = ofb->fb.var.yres_virtual = 0;
> 
> -	free_pages_exact(ofb->video_mem, ofb->video_mem_size);
> -	ofb->video_mem = NULL;
> -	ofb->video_mem_size = 0;
> +		ofb->usage--;
> +	}
>  	return 0;
>  }
> 
> @@ -794,7 +805,7 @@ static int overlayfb_check_var(struct fb_var_screeninfo
> *var, return 0;
>  }
> 
> -static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
> +static int overlayfb_check_video_memory(struct pxafb_layer *ofb)
>  {
>  	struct fb_var_screeninfo *var = &ofb->fb.var;
>  	int pfor = NONSTD_TO_PFOR(var->nonstd);
> @@ -812,27 +823,11 @@ static int overlayfb_map_video_memory(struct
> pxafb_layer *ofb)
> 
>  	size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual);
> 
> -	/* don't re-allocate if the original video memory is enough */
>  	if (ofb->video_mem) {
>  		if (ofb->video_mem_size >= size)
>  			return 0;
> -
> -		free_pages_exact(ofb->video_mem, ofb->video_mem_size);
>  	}
> -
> -	ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
> -	if (ofb->video_mem = NULL)
> -		return -ENOMEM;
> -
> -	ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
> -	ofb->video_mem_size = size;
> -
> -	mutex_lock(&ofb->fb.mm_lock);
> -	ofb->fb.fix.smem_start	= ofb->video_mem_phys;
> -	ofb->fb.fix.smem_len	= ofb->fb.fix.line_length * var->yres_virtual;
> -	mutex_unlock(&ofb->fb.mm_lock);
> -	ofb->fb.screen_base	= ofb->video_mem;
> -	return 0;
> +	return -EINVAL;
>  }
> 
>  static int overlayfb_set_par(struct fb_info *info)
> @@ -841,7 +836,7 @@ static int overlayfb_set_par(struct fb_info *info)
>  	struct fb_var_screeninfo *var = &info->var;
>  	int xpos, ypos, pfor, bpp, ret;
> 
> -	ret = overlayfb_map_video_memory(ofb);
> +	ret = overlayfb_check_video_memory(ofb);
>  	if (ret)
>  		return ret;
> 
> @@ -891,7 +886,7 @@ static void __devinit init_pxafb_overlay(struct
> pxafb_info *fbi,
> 
>  	ofb->id = id;
>  	ofb->ops = &ofb_ops[id];
> -	atomic_set(&ofb->usage, 0);
> +	ofb->usage = 0;
>  	ofb->fbi = fbi;
>  	init_completion(&ofb->branch_done);
>  }
> @@ -904,20 +899,54 @@ static inline int pxafb_overlay_supported(void)
>  	return 0;
>  }
> 
> -static int __devinit pxafb_overlay_init(struct pxafb_info *fbi)
> +static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info
> *pxafb, +	struct pxafb_layer *ofb)
> +{
> +	/* We assume that user will use at most video_mem_size for overlay fb,
> +	 * anyway, it's useless to use 16bpp main plane and 24bpp overlay
> +	 */
> +	ofb->video_mem = alloc_pages_exact(PAGE_ALIGN(pxafb->video_mem_size),
> +		GFP_KERNEL | __GFP_ZERO);
> +	if (ofb->video_mem = NULL)
> +		return -ENOMEM;
> +
> +	ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
> +	ofb->video_mem_size = PAGE_ALIGN(pxafb->video_mem_size);
> +
> +	mutex_lock(&ofb->fb.mm_lock);
> +	ofb->fb.fix.smem_start	= ofb->video_mem_phys;
> +	ofb->fb.fix.smem_len	= pxafb->video_mem_size;
> +	mutex_unlock(&ofb->fb.mm_lock);
> +
> +	ofb->fb.screen_base	= ofb->video_mem;
> +
> +	return 0;
> +}
> +
> +static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
>  {
>  	int i, ret;
> 
>  	if (!pxafb_overlay_supported())
> -		return 0;
> +		return;
> 
>  	for (i = 0; i < 2; i++) {
> -		init_pxafb_overlay(fbi, &fbi->overlay[i], i);
> -		ret = register_framebuffer(&fbi->overlay[i].fb);
> +		struct pxafb_layer *ofb = &fbi->overlay[i];
> +		init_pxafb_overlay(fbi, ofb, i);
> +		ret = register_framebuffer(&ofb->fb);
>  		if (ret) {
>  			dev_err(fbi->dev, "failed to register overlay %d\n", i);
> -			return ret;
> +			continue;
> +		}
> +		ret = pxafb_overlay_map_video_memory(fbi, ofb);
> +		if (ret) {
> +			dev_err(fbi->dev,
> +				"failed to map video memory for overlay %d\n",
> +				i);
> +			unregister_framebuffer(&ofb->fb);
> +			continue;
>  		}
> +		ofb->registered = 1;
>  	}
> 
>  	/* mask all IU/BS/EOF/SOF interrupts */
> @@ -926,7 +955,6 @@ static int __devinit pxafb_overlay_init(struct
> pxafb_info *fbi) /* place overlay(s) on top of base */
>  	fbi->lccr0 |= LCCR0_OUC;
>  	pr_info("PXA Overlay driver loaded successfully!\n");
> -	return 0;
>  }
> 
>  static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
> @@ -936,8 +964,15 @@ static void __devexit pxafb_overlay_exit(struct
> pxafb_info *fbi) if (!pxafb_overlay_supported())
>  		return;
> 
> -	for (i = 0; i < 2; i++)
> -		unregister_framebuffer(&fbi->overlay[i].fb);
> +	for (i = 0; i < 2; i++) {
> +		struct pxafb_layer *ofb = &fbi->overlay[i];
> +		if (ofb->registered) {
> +			if (ofb->video_mem)
> +				free_pages_exact(ofb->video_mem,
> +					ofb->video_mem_size);
> +			unregister_framebuffer(&ofb->fb);
> +		}
> +	}
>  }
>  #else
>  static inline void pxafb_overlay_init(struct pxafb_info *fbi) {}
> @@ -1368,7 +1403,8 @@ static int pxafb_activate_var(struct
> fb_var_screeninfo *var, (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
>  	    (lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) ||
>  	    (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
> -	    (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
> +	    ((fbi->lccr0 & LCCR0_SDS) &&
> +	    (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])))
>  		pxafb_schedule_work(fbi, C_REENABLE);
> 
>  	return 0;
> @@ -1420,7 +1456,8 @@ static void pxafb_enable_controller(struct pxafb_info
> *fbi) lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
> 
>  	lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
> -	lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
> +	if (fbi->lccr0 & LCCR0_SDS)
> +		lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
>  	lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
>  }
> 
> diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
> index 2353521..26ba9fa 100644
> --- a/drivers/video/pxafb.h
> +++ b/drivers/video/pxafb.h
> @@ -92,7 +92,8 @@ struct pxafb_layer_ops {
>  struct pxafb_layer {
>  	struct fb_info		fb;
>  	int			id;
> -	atomic_t		usage;
> +	int			registered;
> +	uint32_t		usage;
>  	uint32_t		control[2];
> 
>  	struct pxafb_layer_ops	*ops;

^ 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