All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yakir Yang <ykk@rock-chips.com>
To: Inki Dae <inki.dae@samsung.com>,
	Mark Yao <mark.yao@rock-chips.com>,
	Jingoo Han <jingoohan1@gmail.com>,
	Heiko Stuebner <heiko@sntech.de>
Cc: Thierry Reding <treding@nvidia.com>,
	Krzysztof Kozlowski <k.kozlowski@samsung.com>,
	Rob Herring <robh+dt@kernel.org>,
	Russell King <linux@arm.linux.org.uk>,
	emil.l.velikov@gmail.com,
	Gustavo Padovan <gustavo.padovan@collabora.co.uk>,
	Kishon Vijay Abraham I <kishon@ti.com>,
	javier@osg.samsung.com, Andy Yan <andy.yan@rock-chips.com>,
	Yakir Yang <ykk@rock-chips.com>,
	dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org,
	linux-rockchip@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH v12 18/18] drm: bridge: analogix/dp: Fix the possible dead lock in bridge disable time
Date: Wed, 23 Dec 2015 20:55:22 +0800	[thread overview]
Message-ID: <1450875322-19728-1-git-send-email-ykk@rock-chips.com> (raw)
In-Reply-To: <1450873538-18304-1-git-send-email-ykk@rock-chips.com>

It may caused a dead lock if we flush the hpd work in bridge disable time.

The normal flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
        3. HPD work already in idle, no need to run the work function.
  OUT <-- analogix_dp_bridge
  OUT <-- DRM IOCTL

The dead lock flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
  IN --> analogix_dp_hotplug
  IN --> drm_helper_hpd_irq_event
        3. Acquire mode_config lock (This lock already have been acquired in previous step 1)
** Dead Lock Now **

It's wrong to flush the hpd work in bridge->disable time, I guess the
original code just want to ensure the delay work must be finish before
encoder disabled.

The flush work in bridge disable time is try to ensure the HPD event
won't be missed before display card disabled, actually we can take a
fast respond way(interrupt thread) to update DRM HPD event to fix the
delay update and possible dead lock.

Signed-off-by: Yakir Yang <ykk@rock-chips.com>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 62 ++++++++++------------
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 +++++++++
 3 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1e98489..04efed2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -851,47 +851,40 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
 	}
 }
 
-static irqreturn_t analogix_dp_irq_handler(int irq, void *arg)
+static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
 {
 	struct analogix_dp_device *dp = arg;
-
+	irqreturn_t ret = IRQ_NONE;
 	enum dp_irq_type irq_type;
 
 	irq_type = analogix_dp_get_irq_type(dp);
-	switch (irq_type) {
-	case DP_IRQ_TYPE_HP_CABLE_IN:
-		dev_dbg(dp->dev, "Received irq - cable in\n");
-		schedule_work(&dp->hotplug_work);
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CABLE_OUT:
-		dev_dbg(dp->dev, "Received irq - cable out\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CHANGE:
-		/*
-		 * We get these change notifications once in a while, but there
-		 * is nothing we can do with them. Just ignore it for now and
-		 * only handle cable changes.
-		 */
-		dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	default:
-		dev_err(dp->dev, "Received irq - unknown type!\n");
-		break;
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_mute_hpd_interrupt(dp);
+		ret = IRQ_WAKE_THREAD;
 	}
-	return IRQ_HANDLED;
+
+	return ret;
 }
 
-static void analogix_dp_hotplug(struct work_struct *work)
+static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
 {
-	struct analogix_dp_device *dp;
+	struct analogix_dp_device *dp = arg;
+	enum dp_irq_type irq_type;
+
+	irq_type = analogix_dp_get_irq_type(dp);
+	if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN ||
+	    irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) {
+		dev_dbg(dp->dev, "Detected cable status changed!\n");
+		if (dp->drm_dev)
+			drm_helper_hpd_irq_event(dp->drm_dev);
+	}
 
-	dp = container_of(work, struct analogix_dp_device, hotplug_work);
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_clear_hotplug_interrupts(dp);
+		analogix_dp_unmute_hpd_interrupt(dp);
+	}
 
-	if (dp->drm_dev)
-		drm_helper_hpd_irq_event(dp->drm_dev);
+	return IRQ_HANDLED;
 }
 
 static void analogix_dp_commit(struct analogix_dp_device *dp)
@@ -1077,7 +1070,6 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 	}
 
 	disable_irq(dp->irq);
-	flush_work(&dp->hotplug_work);
 	phy_power_off(dp->phy);
 
 	if (dp->plat_data->power_off)
@@ -1336,8 +1328,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 		return -ENODEV;
 	}
 
-	INIT_WORK(&dp->hotplug_work, analogix_dp_hotplug);
-
 	pm_runtime_enable(dev);
 
 	phy_power_on(dp->phy);
@@ -1351,8 +1341,10 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	analogix_dp_init_dp(dp);
 
-	ret = devm_request_irq(&pdev->dev, dp->irq, analogix_dp_irq_handler,
-			       irq_flags, "analogix-dp", dp);
+	ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
+					analogix_dp_hardirq,
+					analogix_dp_irq_thread,
+					irq_flags, "analogix-dp", dp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
 		goto err_disable_pm_runtime;
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 40a0759..a4e1330 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -172,7 +172,6 @@ struct analogix_dp_device {
 
 	struct video_info	video_info;
 	struct link_train	link_train;
-	struct work_struct	hotplug_work;
 	struct phy		*phy;
 	int			dpms_mode;
 	int			hpd_gpio;
@@ -191,6 +190,8 @@ void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
 void analogix_dp_reset(struct analogix_dp_device *dp);
 void analogix_dp_swreset(struct analogix_dp_device *dp);
 void analogix_dp_config_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp);
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp);
 void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable);
 void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 8687eea..928103e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -185,6 +185,32 @@ void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
 }
 
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+	reg &= ~COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+	reg &= ~INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
 {
 	u32 reg;
-- 
1.9.1



WARNING: multiple messages have this Message-ID (diff)
From: Yakir Yang <ykk@rock-chips.com>
To: Inki Dae <inki.dae@samsung.com>,
	Mark Yao <mark.yao@rock-chips.com>,
	Jingoo Han <jingoohan1@gmail.com>,
	Heiko Stuebner <heiko@sntech.de>
Cc: devicetree@vger.kernel.org,
	Krzysztof Kozlowski <k.kozlowski@samsung.com>,
	linux-samsung-soc@vger.kernel.org,
	Russell King <linux@arm.linux.org.uk>,
	linux-rockchip@lists.infradead.org, emil.l.velikov@gmail.com,
	linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
	Kishon Vijay Abraham I <kishon@ti.com>,
	javier@osg.samsung.com, Rob Herring <robh+dt@kernel.org>,
	Andy Yan <andy.yan@rock-chips.com>,
	Thierry Reding <treding@nvidia.com>,
	Gustavo Padovan <gustavo.padovan@collabora.co.uk>,
	linux-arm-kernel@lists.infradead.org
Subject: [PATCH v12 18/18] drm: bridge: analogix/dp: Fix the possible dead lock in bridge disable time
Date: Wed, 23 Dec 2015 20:55:22 +0800	[thread overview]
Message-ID: <1450875322-19728-1-git-send-email-ykk@rock-chips.com> (raw)
In-Reply-To: <1450873538-18304-1-git-send-email-ykk@rock-chips.com>

It may caused a dead lock if we flush the hpd work in bridge disable time.

The normal flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
        3. HPD work already in idle, no need to run the work function.
  OUT <-- analogix_dp_bridge
  OUT <-- DRM IOCTL

The dead lock flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
  IN --> analogix_dp_hotplug
  IN --> drm_helper_hpd_irq_event
        3. Acquire mode_config lock (This lock already have been acquired in previous step 1)
** Dead Lock Now **

It's wrong to flush the hpd work in bridge->disable time, I guess the
original code just want to ensure the delay work must be finish before
encoder disabled.

The flush work in bridge disable time is try to ensure the HPD event
won't be missed before display card disabled, actually we can take a
fast respond way(interrupt thread) to update DRM HPD event to fix the
delay update and possible dead lock.

Signed-off-by: Yakir Yang <ykk@rock-chips.com>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 62 ++++++++++------------
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 +++++++++
 3 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1e98489..04efed2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -851,47 +851,40 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
 	}
 }
 
-static irqreturn_t analogix_dp_irq_handler(int irq, void *arg)
+static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
 {
 	struct analogix_dp_device *dp = arg;
-
+	irqreturn_t ret = IRQ_NONE;
 	enum dp_irq_type irq_type;
 
 	irq_type = analogix_dp_get_irq_type(dp);
-	switch (irq_type) {
-	case DP_IRQ_TYPE_HP_CABLE_IN:
-		dev_dbg(dp->dev, "Received irq - cable in\n");
-		schedule_work(&dp->hotplug_work);
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CABLE_OUT:
-		dev_dbg(dp->dev, "Received irq - cable out\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CHANGE:
-		/*
-		 * We get these change notifications once in a while, but there
-		 * is nothing we can do with them. Just ignore it for now and
-		 * only handle cable changes.
-		 */
-		dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	default:
-		dev_err(dp->dev, "Received irq - unknown type!\n");
-		break;
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_mute_hpd_interrupt(dp);
+		ret = IRQ_WAKE_THREAD;
 	}
-	return IRQ_HANDLED;
+
+	return ret;
 }
 
-static void analogix_dp_hotplug(struct work_struct *work)
+static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
 {
-	struct analogix_dp_device *dp;
+	struct analogix_dp_device *dp = arg;
+	enum dp_irq_type irq_type;
+
+	irq_type = analogix_dp_get_irq_type(dp);
+	if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN ||
+	    irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) {
+		dev_dbg(dp->dev, "Detected cable status changed!\n");
+		if (dp->drm_dev)
+			drm_helper_hpd_irq_event(dp->drm_dev);
+	}
 
-	dp = container_of(work, struct analogix_dp_device, hotplug_work);
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_clear_hotplug_interrupts(dp);
+		analogix_dp_unmute_hpd_interrupt(dp);
+	}
 
-	if (dp->drm_dev)
-		drm_helper_hpd_irq_event(dp->drm_dev);
+	return IRQ_HANDLED;
 }
 
 static void analogix_dp_commit(struct analogix_dp_device *dp)
@@ -1077,7 +1070,6 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 	}
 
 	disable_irq(dp->irq);
-	flush_work(&dp->hotplug_work);
 	phy_power_off(dp->phy);
 
 	if (dp->plat_data->power_off)
@@ -1336,8 +1328,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 		return -ENODEV;
 	}
 
-	INIT_WORK(&dp->hotplug_work, analogix_dp_hotplug);
-
 	pm_runtime_enable(dev);
 
 	phy_power_on(dp->phy);
@@ -1351,8 +1341,10 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	analogix_dp_init_dp(dp);
 
-	ret = devm_request_irq(&pdev->dev, dp->irq, analogix_dp_irq_handler,
-			       irq_flags, "analogix-dp", dp);
+	ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
+					analogix_dp_hardirq,
+					analogix_dp_irq_thread,
+					irq_flags, "analogix-dp", dp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
 		goto err_disable_pm_runtime;
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 40a0759..a4e1330 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -172,7 +172,6 @@ struct analogix_dp_device {
 
 	struct video_info	video_info;
 	struct link_train	link_train;
-	struct work_struct	hotplug_work;
 	struct phy		*phy;
 	int			dpms_mode;
 	int			hpd_gpio;
@@ -191,6 +190,8 @@ void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
 void analogix_dp_reset(struct analogix_dp_device *dp);
 void analogix_dp_swreset(struct analogix_dp_device *dp);
 void analogix_dp_config_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp);
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp);
 void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable);
 void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 8687eea..928103e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -185,6 +185,32 @@ void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
 }
 
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+	reg &= ~COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+	reg &= ~INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
 {
 	u32 reg;
-- 
1.9.1


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

WARNING: multiple messages have this Message-ID (diff)
From: ykk@rock-chips.com (Yakir Yang)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v12 18/18] drm: bridge: analogix/dp: Fix the possible dead lock in bridge disable time
Date: Wed, 23 Dec 2015 20:55:22 +0800	[thread overview]
Message-ID: <1450875322-19728-1-git-send-email-ykk@rock-chips.com> (raw)
In-Reply-To: <1450873538-18304-1-git-send-email-ykk@rock-chips.com>

It may caused a dead lock if we flush the hpd work in bridge disable time.

The normal flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
        3. HPD work already in idle, no need to run the work function.
  OUT <-- analogix_dp_bridge
  OUT <-- DRM IOCTL

The dead lock flow would like:
  IN --> DRM IOCTL
        1. Acquire crtc_ww_class_mutex (DRM IOCTL)
  IN --> analogix_dp_bridge
        2. Acquire hpd work lock (Flush hpd work)
  IN --> analogix_dp_hotplug
  IN --> drm_helper_hpd_irq_event
        3. Acquire mode_config lock (This lock already have been acquired in previous step 1)
** Dead Lock Now **

It's wrong to flush the hpd work in bridge->disable time, I guess the
original code just want to ensure the delay work must be finish before
encoder disabled.

The flush work in bridge disable time is try to ensure the HPD event
won't be missed before display card disabled, actually we can take a
fast respond way(interrupt thread) to update DRM HPD event to fix the
delay update and possible dead lock.

Signed-off-by: Yakir Yang <ykk@rock-chips.com>
---
Changes in v12: None
Changes in v11: None
Changes in v10: None
Changes in v9: None
Changes in v8: None
Changes in v7: None
Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 62 ++++++++++------------
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  3 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 26 +++++++++
 3 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 1e98489..04efed2 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -851,47 +851,40 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp,
 	}
 }
 
-static irqreturn_t analogix_dp_irq_handler(int irq, void *arg)
+static irqreturn_t analogix_dp_hardirq(int irq, void *arg)
 {
 	struct analogix_dp_device *dp = arg;
-
+	irqreturn_t ret = IRQ_NONE;
 	enum dp_irq_type irq_type;
 
 	irq_type = analogix_dp_get_irq_type(dp);
-	switch (irq_type) {
-	case DP_IRQ_TYPE_HP_CABLE_IN:
-		dev_dbg(dp->dev, "Received irq - cable in\n");
-		schedule_work(&dp->hotplug_work);
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CABLE_OUT:
-		dev_dbg(dp->dev, "Received irq - cable out\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CHANGE:
-		/*
-		 * We get these change notifications once in a while, but there
-		 * is nothing we can do with them. Just ignore it for now and
-		 * only handle cable changes.
-		 */
-		dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
-		analogix_dp_clear_hotplug_interrupts(dp);
-		break;
-	default:
-		dev_err(dp->dev, "Received irq - unknown type!\n");
-		break;
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_mute_hpd_interrupt(dp);
+		ret = IRQ_WAKE_THREAD;
 	}
-	return IRQ_HANDLED;
+
+	return ret;
 }
 
-static void analogix_dp_hotplug(struct work_struct *work)
+static irqreturn_t analogix_dp_irq_thread(int irq, void *arg)
 {
-	struct analogix_dp_device *dp;
+	struct analogix_dp_device *dp = arg;
+	enum dp_irq_type irq_type;
+
+	irq_type = analogix_dp_get_irq_type(dp);
+	if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN ||
+	    irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) {
+		dev_dbg(dp->dev, "Detected cable status changed!\n");
+		if (dp->drm_dev)
+			drm_helper_hpd_irq_event(dp->drm_dev);
+	}
 
-	dp = container_of(work, struct analogix_dp_device, hotplug_work);
+	if (irq_type != DP_IRQ_TYPE_UNKNOWN) {
+		analogix_dp_clear_hotplug_interrupts(dp);
+		analogix_dp_unmute_hpd_interrupt(dp);
+	}
 
-	if (dp->drm_dev)
-		drm_helper_hpd_irq_event(dp->drm_dev);
+	return IRQ_HANDLED;
 }
 
 static void analogix_dp_commit(struct analogix_dp_device *dp)
@@ -1077,7 +1070,6 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 	}
 
 	disable_irq(dp->irq);
-	flush_work(&dp->hotplug_work);
 	phy_power_off(dp->phy);
 
 	if (dp->plat_data->power_off)
@@ -1336,8 +1328,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 		return -ENODEV;
 	}
 
-	INIT_WORK(&dp->hotplug_work, analogix_dp_hotplug);
-
 	pm_runtime_enable(dev);
 
 	phy_power_on(dp->phy);
@@ -1351,8 +1341,10 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev,
 
 	analogix_dp_init_dp(dp);
 
-	ret = devm_request_irq(&pdev->dev, dp->irq, analogix_dp_irq_handler,
-			       irq_flags, "analogix-dp", dp);
+	ret = devm_request_threaded_irq(&pdev->dev, dp->irq,
+					analogix_dp_hardirq,
+					analogix_dp_irq_thread,
+					irq_flags, "analogix-dp", dp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
 		goto err_disable_pm_runtime;
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 40a0759..a4e1330 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -172,7 +172,6 @@ struct analogix_dp_device {
 
 	struct video_info	video_info;
 	struct link_train	link_train;
-	struct work_struct	hotplug_work;
 	struct phy		*phy;
 	int			dpms_mode;
 	int			hpd_gpio;
@@ -191,6 +190,8 @@ void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
 void analogix_dp_reset(struct analogix_dp_device *dp);
 void analogix_dp_swreset(struct analogix_dp_device *dp);
 void analogix_dp_config_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp);
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp);
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp);
 void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable);
 void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 8687eea..928103e 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -185,6 +185,32 @@ void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
 }
 
+void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = readl(dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+	reg &= ~COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+	reg &= ~INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
+void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4);
+
+	reg = INT_STA_MASK;
+	writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
+}
+
 enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
 {
 	u32 reg;
-- 
1.9.1

  parent reply	other threads:[~2015-12-23 12:57 UTC|newest]

Thread overview: 85+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-23 12:25 [PATCH v12 0/18] Add Analogix Core Display Port Driver Yakir Yang
2015-12-23 12:25 ` Yakir Yang
2015-12-23 12:25 ` Yakir Yang
2015-12-23 12:29 ` [PATCH v12 01/18] drm: bridge: analogix/dp: split exynos dp driver to bridge directory Yakir Yang
2015-12-23 12:29   ` Yakir Yang
2015-12-23 12:31 ` [PATCH v12 02/18] drm: bridge: analogix/dp: fix some obvious code style Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:31 ` [PATCH v12 03/18] drm: bridge: analogix/dp: remove duplicate configuration of link rate and link count Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:31 ` [PATCH v12 04/18] drm: bridge: analogix/dp: dynamic parse sync_pol & interlace & dynamic_range Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:31   ` Yakir Yang
2015-12-23 12:32 ` [PATCH v12 05/18] dt-bindings: add document for analogix display port driver Yakir Yang
2015-12-23 12:32   ` Yakir Yang
2015-12-23 12:32   ` Yakir Yang
2015-12-23 12:32 ` [PATCH v12 06/18] ARM: dts: exynos/dp: remove some properties that deprecated by analogix_dp driver Yakir Yang
2015-12-23 12:32   ` Yakir Yang
2015-12-23 12:32   ` Yakir Yang
2015-12-23 12:32 ` [PATCH v12 07/18] drm: rockchip: dp: add rockchip platform dp driver Yakir Yang
2015-12-23 12:32   ` Yakir Yang
2015-12-23 12:34 ` [PATCH v12 08/18] dt-bindings: add document for rockchip variant of analogix_dp Yakir Yang
2015-12-23 12:34   ` Yakir Yang
2015-12-23 12:36 ` [PATCH v12 09/18] phy: Add driver for rockchip Display Port PHY Yakir Yang
2015-12-23 12:36   ` Yakir Yang
2015-12-23 12:38 ` [PATCH v12 10/18] dt-bindings: add document for rockchip dp phy Yakir Yang
2015-12-23 12:38   ` Yakir Yang
2015-12-23 12:40 ` [PATCH v12 11/18] drm: bridge: analogix/dp: add some rk3288 special registers setting Yakir Yang
2015-12-23 12:40   ` Yakir Yang
2015-12-23 12:42 ` [PATCH v12 12/18] drm: bridge: analogix/dp: add max link rate and lane count limit for RK3288 Yakir Yang
2015-12-23 12:42   ` Yakir Yang
2015-12-23 12:42   ` Yakir Yang
2015-12-23 12:44 ` [PATCH v12 13/18] drm: bridge: analogix/dp: try force hpd after plug in lookup failed Yakir Yang
2015-12-23 12:44   ` Yakir Yang
2015-12-23 12:46 ` [PATCH v12 14/18] drm: bridge: analogix/dp: move hpd detect to connector detect function Yakir Yang
2015-12-23 12:46   ` Yakir Yang
2015-12-23 12:46   ` Yakir Yang
2015-12-23 12:49 ` [PATCH v12 15/18] drm: bridge: analogix/dp: add edid modes parse in get_modes method Yakir Yang
2015-12-23 12:49   ` Yakir Yang
2015-12-23 12:49   ` Yakir Yang
2015-12-23 12:51 ` [PATCH v12 16/18] drm: bridge: analogix/dp: expand the wait time for looking AUX CH reply flag Yakir Yang
2015-12-23 12:51   ` Yakir Yang
2015-12-23 15:10   ` Jingoo Han
2015-12-23 15:10     ` Jingoo Han
2015-12-23 15:10     ` Jingoo Han
2015-12-24  1:23     ` Yakir Yang
2015-12-24  1:23       ` Yakir Yang
2015-12-24  1:23       ` Yakir Yang
2015-12-25 13:01       ` Jingoo Han
2015-12-25 13:01         ` Jingoo Han
2015-12-25 13:01         ` Jingoo Han
2015-12-23 12:53 ` [PATCH v12 17/18] drm: bridge: analogix/dp: add panel prepare/unprepare in suspend/resume time Yakir Yang
2015-12-23 12:53   ` Yakir Yang
2015-12-23 12:55 ` Yakir Yang [this message]
2015-12-23 12:55   ` [PATCH v12 18/18] drm: bridge: analogix/dp: Fix the possible dead lock in bridge disable time Yakir Yang
2015-12-23 12:55   ` Yakir Yang
2016-01-13 14:59 ` [PATCH v12 0/18] Add Analogix Core Display Port Driver Heiko Stuebner
2016-01-13 14:59   ` Heiko Stuebner
2016-01-13 14:59   ` Heiko Stuebner
2016-01-17 14:25   ` Heiko Stuebner
2016-01-17 14:25     ` Heiko Stuebner
2016-01-17 14:25     ` Heiko Stuebner
2016-01-17 14:25     ` Heiko Stuebner
2016-01-18 10:48     ` Yakir Yang
2016-01-18 10:48       ` Yakir Yang
2016-01-18 10:48       ` Yakir Yang
2016-01-19  9:58 ` [PATCH v12.1 01/17] drm: bridge: analogix/dp: split exynos dp driver to bridge directory Yakir Yang
2016-01-19  9:58   ` Yakir Yang
2016-01-19 10:00 ` [PATCH v12.1 05/17] dt-bindings: add document for analogix display port driver Yakir Yang
2016-01-19 10:00   ` Yakir Yang
2016-01-19 10:00   ` Yakir Yang
2016-01-19 10:02 ` [PATCH v12.1 06/17] ARM: dts: exynos/dp: remove some properties that deprecated by analogix_dp driver Yakir Yang
2016-01-19 10:02   ` Yakir Yang
2016-01-19 10:02   ` Yakir Yang
2016-01-19 10:04 ` [PATCH v12.1 07/17] drm: rockchip: dp: add rockchip platform dp driver Yakir Yang
2016-01-19 10:04   ` Yakir Yang
2016-01-21 19:11   ` Heiko Stuebner
2016-01-21 19:11     ` Heiko Stuebner
2016-01-22  1:37     ` Yakir Yang
2016-01-22  1:37       ` Yakir Yang
2016-01-22  1:37       ` Yakir Yang
2016-01-19 10:06 ` [PATCH v12.1 13/17] drm: bridge: analogix/dp: try force hpd after plug in lookup failed Yakir Yang
2016-01-19 10:06   ` Yakir Yang
2016-01-19 10:06   ` Yakir Yang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1450875322-19728-1-git-send-email-ykk@rock-chips.com \
    --to=ykk@rock-chips.com \
    --cc=andy.yan@rock-chips.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=emil.l.velikov@gmail.com \
    --cc=gustavo.padovan@collabora.co.uk \
    --cc=heiko@sntech.de \
    --cc=inki.dae@samsung.com \
    --cc=javier@osg.samsung.com \
    --cc=jingoohan1@gmail.com \
    --cc=k.kozlowski@samsung.com \
    --cc=kishon@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=mark.yao@rock-chips.com \
    --cc=robh+dt@kernel.org \
    --cc=treding@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.