linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/2]  enable HDP plugin/unplugged interrupts to hpd_enable/disable
@ 2023-05-10 20:31 Kuogee Hsieh
  2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
                   ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Kuogee Hsieh @ 2023-05-10 20:31 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: Kuogee Hsieh, quic_abhinavk, quic_jesszhan, quic_sbillaka,
	marijn.suijten, freedreno, linux-arm-msm, linux-kernel

There is bug report on exteranl DP display does not work.
This patch add below two patches to fix the problem.
1) enable HDP plugin/unplugged interrupts to hpd_enable/disable
2) add mutex to protect internal_hpd against race condition between different threads
    

Kuogee Hsieh (2):
  drm/msm/dp: enable HDP plugin/unplugged interrupts to
    hpd_enable/disable
  drm/msm/dp: add mutex to protect internal_hpd against race condition
    between different threads

 drivers/gpu/drm/msm/dp/dp_display.c | 37 +++++++++++++++++++++++--------------
 1 file changed, 23 insertions(+), 14 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 20:31 [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Kuogee Hsieh
@ 2023-05-10 20:31 ` Kuogee Hsieh
  2023-05-10 23:55   ` Stephen Boyd
  2023-05-11  4:24   ` Dmitry Baryshkov
  2023-05-10 20:31 ` [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads Kuogee Hsieh
  2023-05-11 16:02 ` [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Dmitry Baryshkov
  2 siblings, 2 replies; 20+ messages in thread
From: Kuogee Hsieh @ 2023-05-10 20:31 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: Kuogee Hsieh, quic_abhinavk, quic_jesszhan, quic_sbillaka,
	marijn.suijten, freedreno, linux-arm-msm, linux-kernel

The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
pinmuxed into DP controller. HPD plug/unplug interrupts cannot be enabled until
internal_hpd flag is set to true.
At both bootup and resume time, the DP driver will enable external DP
plugin interrupts and handle plugin interrupt accordingly. Unfortunately
dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
flag to true later than where DP driver expected during bootup time.

This causes external DP plugin event to not get detected and display stays blank.
Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
simultaneously to avoid timing issue during bootup and resume.

Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 3e13acdf..71aa944 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
 	dp_display_host_init(dp);
 	dp_catalog_ctrl_hpd_config(dp->catalog);
 
-	/* Enable plug and unplug interrupts only if requested */
-	if (dp->dp_display.internal_hpd)
-		dp_catalog_hpd_config_intr(dp->catalog,
-				DP_DP_HPD_PLUG_INT_MASK |
-				DP_DP_HPD_UNPLUG_INT_MASK,
-				true);
-
 	/* Enable interrupt first time
 	 * we are leaving dp clocks on during disconnect
 	 * and never disable interrupt
@@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
 
 	dp_catalog_ctrl_hpd_config(dp->catalog);
 
-	if (dp->dp_display.internal_hpd)
-		dp_catalog_hpd_config_intr(dp->catalog,
-				DP_DP_HPD_PLUG_INT_MASK |
-				DP_DP_HPD_UNPLUG_INT_MASK,
-				true);
-
 	if (dp_catalog_link_is_connected(dp->catalog)) {
 		/*
 		 * set sink to normal operation mode -- D0
@@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
 {
 	struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
 	struct msm_dp *dp_display = dp_bridge->dp_display;
+	struct dp_display_private *dp;
+
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	dp_display->internal_hpd = true;
+	dp_catalog_hpd_config_intr(dp->catalog,
+				DP_DP_HPD_PLUG_INT_MASK |
+				DP_DP_HPD_UNPLUG_INT_MASK,
+				true);
 }
 
 void dp_bridge_hpd_disable(struct drm_bridge *bridge)
 {
 	struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
 	struct msm_dp *dp_display = dp_bridge->dp_display;
+	struct dp_display_private *dp;
+
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+	dp_catalog_hpd_config_intr(dp->catalog,
+				DP_DP_HPD_PLUG_INT_MASK |
+				DP_DP_HPD_UNPLUG_INT_MASK,
+				false);
 	dp_display->internal_hpd = false;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads
  2023-05-10 20:31 [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Kuogee Hsieh
  2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
@ 2023-05-10 20:31 ` Kuogee Hsieh
  2023-05-10 22:46   ` Stephen Boyd
  2023-05-11 16:02 ` [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Dmitry Baryshkov
  2 siblings, 1 reply; 20+ messages in thread
From: Kuogee Hsieh @ 2023-05-10 20:31 UTC (permalink / raw)
  To: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, dmitry.baryshkov, andersson
  Cc: Kuogee Hsieh, quic_abhinavk, quic_jesszhan, quic_sbillaka,
	marijn.suijten, freedreno, linux-arm-msm, linux-kernel

Intrenal_hpd is referenced by event thread but set by drm bridge callback
context. Add mutex to protect internal_hpd to avoid conflicts between
threads.

Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
---
 drivers/gpu/drm/msm/dp/dp_display.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 71aa944..b59ea7a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1792,11 +1792,13 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+	mutex_lock(&dp->event_mutex);
 	dp_display->internal_hpd = true;
 	dp_catalog_hpd_config_intr(dp->catalog,
 				DP_DP_HPD_PLUG_INT_MASK |
 				DP_DP_HPD_UNPLUG_INT_MASK,
 				true);
+	mutex_unlock(&dp->event_mutex);
 }
 
 void dp_bridge_hpd_disable(struct drm_bridge *bridge)
@@ -1807,11 +1809,13 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge)
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+	mutex_lock(&dp->event_mutex);
 	dp_catalog_hpd_config_intr(dp->catalog,
 				DP_DP_HPD_PLUG_INT_MASK |
 				DP_DP_HPD_UNPLUG_INT_MASK,
 				false);
 	dp_display->internal_hpd = false;
+	mutex_unlock(&dp->event_mutex);
 }
 
 void dp_bridge_hpd_notify(struct drm_bridge *bridge,
@@ -1822,8 +1826,12 @@ void dp_bridge_hpd_notify(struct drm_bridge *bridge,
 	struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	/* Without next_bridge interrupts are handled by the DP core directly */
-	if (dp_display->internal_hpd)
+	mutex_lock(&dp->event_mutex);
+	if (dp_display->internal_hpd) {
+		mutex_unlock(&dp->event_mutex);
 		return;
+	}
+	mutex_unlock(&dp->event_mutex);
 
 	if (!dp->core_initialized) {
 		drm_dbg_dp(dp->drm_dev, "not initialized\n");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads
  2023-05-10 20:31 ` [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads Kuogee Hsieh
@ 2023-05-10 22:46   ` Stephen Boyd
  2023-05-10 23:11     ` Abhinav Kumar
  0 siblings, 1 reply; 20+ messages in thread
From: Stephen Boyd @ 2023-05-10 22:46 UTC (permalink / raw)
  To: Kuogee Hsieh, agross, airlied, andersson, daniel, dianders,
	dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_abhinavk, quic_jesszhan, quic_sbillaka, marijn.suijten,
	freedreno, linux-arm-msm, linux-kernel

Quoting Kuogee Hsieh (2023-05-10 13:31:05)
> Intrenal_hpd is referenced by event thread but set by drm bridge callback
> context. Add mutex to protect internal_hpd to avoid conflicts between
> threads.
>
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---

This patch looks completely unnecessary. How can dp_bridge_hpd_enable()
be called at the same time that dp_bridge_hpd_disable() is called or
dp_bridge_hpd_notify() is called? Isn't there locking or ordering at a
higher layer?

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads
  2023-05-10 22:46   ` Stephen Boyd
@ 2023-05-10 23:11     ` Abhinav Kumar
  2023-05-10 23:19       ` Kuogee Hsieh
  0 siblings, 1 reply; 20+ messages in thread
From: Abhinav Kumar @ 2023-05-10 23:11 UTC (permalink / raw)
  To: Stephen Boyd, Kuogee Hsieh, agross, airlied, andersson, daniel,
	dianders, dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel



On 5/10/2023 3:46 PM, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2023-05-10 13:31:05)
>> Intrenal_hpd is referenced by event thread but set by drm bridge callback
>> context. Add mutex to protect internal_hpd to avoid conflicts between
>> threads.
>>
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
> 
> This patch looks completely unnecessary. How can dp_bridge_hpd_enable()
> be called at the same time that dp_bridge_hpd_disable() is called or
> dp_bridge_hpd_notify() is called? Isn't there locking or ordering at a
> higher layer?

Ack. We can drop this patch because we are protected by 
bridge->hpd_mutex in drm_bridge_hpd_enable() / drm_bridge_hpd_disable () 
and drm_bridge_hpd_notify().

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads
  2023-05-10 23:11     ` Abhinav Kumar
@ 2023-05-10 23:19       ` Kuogee Hsieh
  2023-05-10 23:30         ` Abhinav Kumar
  0 siblings, 1 reply; 20+ messages in thread
From: Kuogee Hsieh @ 2023-05-10 23:19 UTC (permalink / raw)
  To: Abhinav Kumar, Stephen Boyd, agross, airlied, andersson, daniel,
	dianders, dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel

internal_hpd is referenced at both plug and unplug handle.

The majority purpose of  mutext is try to serialize internal_hpd between 
dp_bridge_hpd_disable() and either plug or unplug handle.


On 5/10/2023 4:11 PM, Abhinav Kumar wrote:
>
>
> On 5/10/2023 3:46 PM, Stephen Boyd wrote:
>> Quoting Kuogee Hsieh (2023-05-10 13:31:05)
>>> Intrenal_hpd is referenced by event thread but set by drm bridge 
>>> callback
>>> context. Add mutex to protect internal_hpd to avoid conflicts between
>>> threads.
>>>
>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>>> ---
>>
>> This patch looks completely unnecessary. How can dp_bridge_hpd_enable()
>> be called at the same time that dp_bridge_hpd_disable() is called or
>> dp_bridge_hpd_notify() is called? Isn't there locking or ordering at a
>> higher layer?
>
> Ack. We can drop this patch because we are protected by 
> bridge->hpd_mutex in drm_bridge_hpd_enable() / drm_bridge_hpd_disable 
> () and drm_bridge_hpd_notify().

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads
  2023-05-10 23:19       ` Kuogee Hsieh
@ 2023-05-10 23:30         ` Abhinav Kumar
  0 siblings, 0 replies; 20+ messages in thread
From: Abhinav Kumar @ 2023-05-10 23:30 UTC (permalink / raw)
  To: Kuogee Hsieh, Stephen Boyd, agross, airlied, andersson, daniel,
	dianders, dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel

Hi Stephen

On 5/10/2023 4:19 PM, Kuogee Hsieh wrote:
> internal_hpd is referenced at both plug and unplug handle.
> 
> The majority purpose of  mutext is try to serialize internal_hpd between 
> dp_bridge_hpd_disable() and either plug or unplug handle.
> 
> 
> On 5/10/2023 4:11 PM, Abhinav Kumar wrote:
>>
>>
>> On 5/10/2023 3:46 PM, Stephen Boyd wrote:
>>> Quoting Kuogee Hsieh (2023-05-10 13:31:05)
>>>> Intrenal_hpd is referenced by event thread but set by drm bridge 
>>>> callback
>>>> context. Add mutex to protect internal_hpd to avoid conflicts between
>>>> threads.
>>>>
>>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>>>> ---
>>>
>>> This patch looks completely unnecessary. How can dp_bridge_hpd_enable()
>>> be called at the same time that dp_bridge_hpd_disable() is called or
>>> dp_bridge_hpd_notify() is called? Isn't there locking or ordering at a
>>> higher layer?
>>
>> Ack. We can drop this patch because we are protected by 
>> bridge->hpd_mutex in drm_bridge_hpd_enable() / drm_bridge_hpd_disable 
>> () and drm_bridge_hpd_notify().

I understood now, so what kuogee is referring to is that this 
event_mutex protection is to not protect those 3 calls from each other 
(since they are already protected as we saw above) but because 
dp_hpd_plug_handle/dp_hpd_unplug_handle still uses 
dp_display.internal_hpd to re-enable the hot-plug interrupt, this is 
making sure that flow is protected as well.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
@ 2023-05-10 23:55   ` Stephen Boyd
  2023-05-11  0:39     ` Abhinav Kumar
  2023-05-11 15:31     ` Bjorn Andersson
  2023-05-11  4:24   ` Dmitry Baryshkov
  1 sibling, 2 replies; 20+ messages in thread
From: Stephen Boyd @ 2023-05-10 23:55 UTC (permalink / raw)
  To: Kuogee Hsieh, agross, airlied, andersson, daniel, dianders,
	dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_abhinavk, quic_jesszhan, quic_sbillaka, marijn.suijten,
	freedreno, linux-arm-msm, linux-kernel

Quoting Kuogee Hsieh (2023-05-10 13:31:04)
> The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> pinmuxed into DP controller.

Was it? It looks more like it was done to differentiate between eDP and
DP, because internal_hpd is set only if DRM_BRIDGE_OP_HPD is set on the
bridge and we only set the bridge op if the connector type is DP. The
assumption looks like if you have DP connector_type, you have the gpio
pinmuxed for "dp_hot" mode, which isn't exactly true. We don't treat
that gpio as an irq either, because it isn't. Instead the gpio is muxed
to the mdss inside the SoC and then that generates an mdss interrupt
that's combined with non-HPD things like "video ready".

If that all follows, then I don't quite understand why we're setting
internal_hpd to false at all at runtime. It should be set to true at
some point, but ideally that point is during probe.

> HPD plug/unplug interrupts cannot be enabled until
> internal_hpd flag is set to true.
> At both bootup and resume time, the DP driver will enable external DP
> plugin interrupts and handle plugin interrupt accordingly. Unfortunately
> dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
> flag to true later than where DP driver expected during bootup time.
>
> This causes external DP plugin event to not get detected and display stays blank.
> Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
> set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
> simultaneously to avoid timing issue during bootup and resume.
>
> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> ---
>  drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
>  1 file changed, 14 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index 3e13acdf..71aa944 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
>  {
>         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>         struct msm_dp *dp_display = dp_bridge->dp_display;
> +       struct dp_display_private *dp;
> +
> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>
>         dp_display->internal_hpd = true;

Can we set internal_hpd to true during probe when we see that the hpd
pinmux exists? Or do any of these bits toggle in the irq status register
when the gpio isn't muxed to "dp_hot" or the controller is for eDP and
it doesn't have any gpio connection internally? I'm wondering if we can
get by with simply enabling the "dp_hot" pin interrupts
(plug/unplug/replug/irq_hpd) unconditionally and not worrying about them
if eDP is there (because the pin doesn't exist inside the SoC), or if DP
HPD is being signalled out of band through type-c framework.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 23:55   ` Stephen Boyd
@ 2023-05-11  0:39     ` Abhinav Kumar
  2023-05-11 15:44       ` Bjorn Andersson
  2023-05-11 15:31     ` Bjorn Andersson
  1 sibling, 1 reply; 20+ messages in thread
From: Abhinav Kumar @ 2023-05-11  0:39 UTC (permalink / raw)
  To: Stephen Boyd, Kuogee Hsieh, agross, airlied, andersson, daniel,
	dianders, dmitry.baryshkov, dri-devel, robdclark, sean, vkoul
  Cc: quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel



On 5/10/2023 4:55 PM, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2023-05-10 13:31:04)
>> The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
>> pinmuxed into DP controller.
> 
> Was it? It looks more like it was done to differentiate between eDP and
> DP, because internal_hpd is set only if DRM_BRIDGE_OP_HPD is set on the
> bridge and we only set the bridge op if the connector type is DP. The
> assumption looks like if you have DP connector_type, you have the gpio
> pinmuxed for "dp_hot" mode, which isn't exactly true. We don't treat
> that gpio as an irq either, because it isn't. Instead the gpio is muxed
> to the mdss inside the SoC and then that generates an mdss interrupt
> that's combined with non-HPD things like "video ready".
> 
> If that all follows, then I don't quite understand why we're setting
> internal_hpd to false at all at runtime. It should be set to true at
> some point, but ideally that point is during probe.
> 

Kuogee had the same thought originally but were not entirely sure of 
this part of the commit message in Bjorn's original commit which 
introduced these changes.

"This difference is not appropriately represented by the "is_edp"
boolean, but is properly represented by the frameworks invocation of the
hpd_enable() and hpd_disable() callbacks. Switch the current condition
to rely on these callbacks instead"

Does this along with below documentation mean we should generate the hpd 
interrupts only after hpd_enable callback happens?

" * Call &drm_bridge_funcs.hpd_enable if implemented and register the 
given @cb
  * and @data as hot plug notification callback. From now on the @cb will be
  * called with @data when an output status change is detected by the 
bridge,
  * until hot plug notification gets disabled with drm_bridge_hpd_disable().
"

Bjorn, can you please clarify this?

>> HPD plug/unplug interrupts cannot be enabled until
>> internal_hpd flag is set to true.
>> At both bootup and resume time, the DP driver will enable external DP
>> plugin interrupts and handle plugin interrupt accordingly. Unfortunately
>> dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
>> flag to true later than where DP driver expected during bootup time.
>>
>> This causes external DP plugin event to not get detected and display stays blank.
>> Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
>> set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
>> simultaneously to avoid timing issue during bootup and resume.
>>
>> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>> ---
>>   drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
>>   1 file changed, 14 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
>> index 3e13acdf..71aa944 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
>>   {
>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>>          struct msm_dp *dp_display = dp_bridge->dp_display;
>> +       struct dp_display_private *dp;
>> +
>> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>>
>>          dp_display->internal_hpd = true;
> 
> Can we set internal_hpd to true during probe when we see that the hpd
> pinmux exists? Or do any of these bits toggle in the irq status register
> when the gpio isn't muxed to "dp_hot" or the controller is for eDP and
> it doesn't have any gpio connection internally? I'm wondering if we can
> get by with simply enabling the "dp_hot" pin interrupts
> (plug/unplug/replug/irq_hpd) unconditionally and not worrying about them
> if eDP is there (because the pin doesn't exist inside the SoC), or if DP
> HPD is being signalled out of band through type-c framework.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
  2023-05-10 23:55   ` Stephen Boyd
@ 2023-05-11  4:24   ` Dmitry Baryshkov
  2023-05-11 15:53     ` Bjorn Andersson
  1 sibling, 1 reply; 20+ messages in thread
From: Dmitry Baryshkov @ 2023-05-11  4:24 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, andersson, quic_abhinavk, quic_jesszhan,
	quic_sbillaka, marijn.suijten, freedreno, linux-arm-msm,
	linux-kernel

On Wed, 10 May 2023 at 23:31, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
>
> The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> pinmuxed into DP controller. HPD plug/unplug interrupts cannot be enabled until
> internal_hpd flag is set to true.
> At both bootup and resume time, the DP driver will enable external DP
> plugin interrupts and handle plugin interrupt accordingly. Unfortunately
> dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
> flag to true later than where DP driver expected during bootup time.
>
> This causes external DP plugin event to not get detected and display stays blank.
> Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
> set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
> simultaneously to avoid timing issue during bootup and resume.
>
> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>

Thanks for debugging this!

However after looking at the driver I think there is more than this.

We have several other places gated on internal_hpd flag, where we do
not have a strict ordering of events.
I see that dp_hpd_plug_handle() and dp_hpd_unplug_handle() also toggle
DP_DP_IRQ_HPD_INT_MASK and DP_DP_HPD_REPLUG_INT_MASK depending on
internal_hpd. Can we toggle all 4 interrupts from the
hpd_enable/hpd_disable functions? If we can do it, then I think we can
drop the internal_hpd flag completely.

I went on and checked other places where it is used:
- dp_hpd_unplug_handle(), guarding DP_DP_HPD_PLUG_INT_MASK toggling. I
think we can drop these two calls completely. The function is under
the event_mutex protection, so other events can not interfere.
- dp_bridge_hpd_notify(). What is the point of this check? If some
other party informs us of the HPD event, we'd better handle it instead
of dropping it. Correct?  In other words, I'd prefer seeing the
hpd_event_thread removal. Instead of that I think that on
HPD/plug/unplug/etc. IRQ the driver should call into the drm stack,
then the hpd_notify call should process those events.


> ---
>  drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
>  1 file changed, 14 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> index 3e13acdf..71aa944 100644
> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> @@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
>         dp_display_host_init(dp);
>         dp_catalog_ctrl_hpd_config(dp->catalog);
>
> -       /* Enable plug and unplug interrupts only if requested */
> -       if (dp->dp_display.internal_hpd)
> -               dp_catalog_hpd_config_intr(dp->catalog,
> -                               DP_DP_HPD_PLUG_INT_MASK |
> -                               DP_DP_HPD_UNPLUG_INT_MASK,
> -                               true);
> -
>         /* Enable interrupt first time
>          * we are leaving dp clocks on during disconnect
>          * and never disable interrupt
> @@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
>
>         dp_catalog_ctrl_hpd_config(dp->catalog);
>
> -       if (dp->dp_display.internal_hpd)
> -               dp_catalog_hpd_config_intr(dp->catalog,
> -                               DP_DP_HPD_PLUG_INT_MASK |
> -                               DP_DP_HPD_UNPLUG_INT_MASK,
> -                               true);
> -
>         if (dp_catalog_link_is_connected(dp->catalog)) {
>                 /*
>                  * set sink to normal operation mode -- D0
> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
>  {
>         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>         struct msm_dp *dp_display = dp_bridge->dp_display;
> +       struct dp_display_private *dp;
> +
> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>
>         dp_display->internal_hpd = true;
> +       dp_catalog_hpd_config_intr(dp->catalog,
> +                               DP_DP_HPD_PLUG_INT_MASK |
> +                               DP_DP_HPD_UNPLUG_INT_MASK,
> +                               true);
>  }
>
>  void dp_bridge_hpd_disable(struct drm_bridge *bridge)
>  {
>         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>         struct msm_dp *dp_display = dp_bridge->dp_display;
> +       struct dp_display_private *dp;
> +
> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>
> +       dp_catalog_hpd_config_intr(dp->catalog,
> +                               DP_DP_HPD_PLUG_INT_MASK |
> +                               DP_DP_HPD_UNPLUG_INT_MASK,
> +                               false);
>         dp_display->internal_hpd = false;
>  }

--
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 23:55   ` Stephen Boyd
  2023-05-11  0:39     ` Abhinav Kumar
@ 2023-05-11 15:31     ` Bjorn Andersson
  1 sibling, 0 replies; 20+ messages in thread
From: Bjorn Andersson @ 2023-05-11 15:31 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Kuogee Hsieh, agross, airlied, daniel, dianders,
	dmitry.baryshkov, dri-devel, robdclark, sean, vkoul,
	quic_abhinavk, quic_jesszhan, quic_sbillaka, marijn.suijten,
	freedreno, linux-arm-msm, linux-kernel

On Wed, May 10, 2023 at 04:55:04PM -0700, Stephen Boyd wrote:
> Quoting Kuogee Hsieh (2023-05-10 13:31:04)
> > The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> > pinmuxed into DP controller.
> 
> Was it? It looks more like it was done to differentiate between eDP and
> DP, because internal_hpd is set only if DRM_BRIDGE_OP_HPD is set on the
> bridge and we only set the bridge op if the connector type is DP. The
> assumption looks like if you have DP connector_type, you have the gpio
> pinmuxed for "dp_hot" mode, which isn't exactly true. We don't treat
> that gpio as an irq either, because it isn't. Instead the gpio is muxed
> to the mdss inside the SoC and then that generates an mdss interrupt
> that's combined with non-HPD things like "video ready".
> 

The purpose of "internal_hpd" is to indicate track if the internal
HPD-logic should be used or not.

> If that all follows, then I don't quite understand why we're setting
> internal_hpd to false at all at runtime. It should be set to true at
> some point, but ideally that point is during probe.
> 

The DRM framework will invoke hpd_enable on the bridge furthest out that
has OP_HPD. So in the case of HPD signal being pinmuxed into the
HPD-logic, dp_bridge_hpd_enable() will be invoked.

I therefor think the appropriate thing to do is to move the enablement
of the internal HPD-logic to dp_bridge_hpd_enable(), further more I
think the correct thing to do would be to tie the power state of the DP
block to this (and to when the external hpd_notify events signals that
there's something attached).

> > HPD plug/unplug interrupts cannot be enabled until
> > internal_hpd flag is set to true.
> > At both bootup and resume time, the DP driver will enable external DP
> > plugin interrupts and handle plugin interrupt accordingly. Unfortunately
> > dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
> > flag to true later than where DP driver expected during bootup time.
> >
> > This causes external DP plugin event to not get detected and display stays blank.
> > Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
> > set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
> > simultaneously to avoid timing issue during bootup and resume.
> >
> > Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
> > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> > ---
> >  drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
> >  1 file changed, 14 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> > index 3e13acdf..71aa944 100644
> > --- a/drivers/gpu/drm/msm/dp/dp_display.c
> > +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> > @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
> >  {
> >         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> >         struct msm_dp *dp_display = dp_bridge->dp_display;
> > +       struct dp_display_private *dp;
> > +
> > +       dp = container_of(dp_display, struct dp_display_private, dp_display);
> >
> >         dp_display->internal_hpd = true;
> 
> Can we set internal_hpd to true during probe when we see that the hpd
> pinmux exists? Or do any of these bits toggle in the irq status register
> when the gpio isn't muxed to "dp_hot" or the controller is for eDP and
> it doesn't have any gpio connection internally? I'm wondering if we can
> get by with simply enabling the "dp_hot" pin interrupts
> (plug/unplug/replug/irq_hpd) unconditionally and not worrying about them
> if eDP is there (because the pin doesn't exist inside the SoC), or if DP
> HPD is being signalled out of band through type-c framework.

It seems logical to me that the panel driver should handle HPD signaling
(or signal it always-asserted), in which case it also seems reasonable
that hpd_enable() would not be invoked... I didn't go far enough into
that rabbit hole though, but I think it would allow us to drop the
is_edp flag (which isn't at all a property of the controller, but of
what you have connected).

I don't think we should peak into the pinmux settings to determine if
the internal HPD logic should be enabled or not, when the DRM framework
already has this callback to tell us "hey, you're the one doing HPD
detection!".


And as mentioned above, the continuation of this is to tie the power
state to hpd_enable/hpd_disable/hpd_notify and thereby allow the DP
block (and MMCX) to be powered down when nothing is connected (and we
don't need to drive the HPD logic).

Regards,
Bjorn

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-11  0:39     ` Abhinav Kumar
@ 2023-05-11 15:44       ` Bjorn Andersson
  2023-05-11 17:55         ` Stephen Boyd
  0 siblings, 1 reply; 20+ messages in thread
From: Bjorn Andersson @ 2023-05-11 15:44 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: Stephen Boyd, Kuogee Hsieh, agross, airlied, daniel, dianders,
	dmitry.baryshkov, dri-devel, robdclark, sean, vkoul,
	quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel

On Wed, May 10, 2023 at 05:39:07PM -0700, Abhinav Kumar wrote:
> 
> 
> On 5/10/2023 4:55 PM, Stephen Boyd wrote:
> > Quoting Kuogee Hsieh (2023-05-10 13:31:04)
> > > The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> > > pinmuxed into DP controller.
> > 
> > Was it? It looks more like it was done to differentiate between eDP and
> > DP, because internal_hpd is set only if DRM_BRIDGE_OP_HPD is set on the
> > bridge and we only set the bridge op if the connector type is DP. The
> > assumption looks like if you have DP connector_type, you have the gpio
> > pinmuxed for "dp_hot" mode, which isn't exactly true. We don't treat
> > that gpio as an irq either, because it isn't. Instead the gpio is muxed
> > to the mdss inside the SoC and then that generates an mdss interrupt
> > that's combined with non-HPD things like "video ready".
> > 
> > If that all follows, then I don't quite understand why we're setting
> > internal_hpd to false at all at runtime. It should be set to true at
> > some point, but ideally that point is during probe.
> > 
> 
> Kuogee had the same thought originally but were not entirely sure of this
> part of the commit message in Bjorn's original commit which introduced these
> changes.
> 
> "This difference is not appropriately represented by the "is_edp"
> boolean, but is properly represented by the frameworks invocation of the
> hpd_enable() and hpd_disable() callbacks. Switch the current condition
> to rely on these callbacks instead"
> 
> Does this along with below documentation mean we should generate the hpd
> interrupts only after hpd_enable callback happens?
> 
> " * Call &drm_bridge_funcs.hpd_enable if implemented and register the given
> @cb
>  * and @data as hot plug notification callback. From now on the @cb will be
>  * called with @data when an output status change is detected by the bridge,
>  * until hot plug notification gets disabled with drm_bridge_hpd_disable().
> "
> 
> Bjorn, can you please clarify this?
> 

We currently have 3 cases:

1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
and internal HPD-logic is in used (internal_hpd = true). Power needs to
be on at all times etc.

2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
internal HPD-logic should not be used/enabled (internal_hpd = false).
Power doesn't need to be on unless hpd_notify is invoked to tell us that
there's something connected...

3) eDP with or without HPD signal and/or HPD gpio. Downstream
drm_bridge/panel is connected, is_edp = true and internal HPD logic is
short-circuited regardless of the panel providing HPD signal or not.


In #1 dp_bridge_hpd_enable() will be invoked to indicate that the DP
controller is expected to perform HPD handling. In #2
dp_bridge_hpd_enable() will _not_ be invoked, instead some downstream
drm_bridge/panel will get the hpd_enable() callback and will be
responsible to updating the HPD state of the chain, which will cause
hpd_notify to be invoked.


Note that #3 is based entirely on the controller, it has currently no
relation to what is attached. It seems reasonable that this is just
another case of #2 (perhaps just always reporting
connector_status_connected?).

Regards,
Bjorn

> > > HPD plug/unplug interrupts cannot be enabled until
> > > internal_hpd flag is set to true.
> > > At both bootup and resume time, the DP driver will enable external DP
> > > plugin interrupts and handle plugin interrupt accordingly. Unfortunately
> > > dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
> > > flag to true later than where DP driver expected during bootup time.
> > > 
> > > This causes external DP plugin event to not get detected and display stays blank.
> > > Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
> > > set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
> > > simultaneously to avoid timing issue during bootup and resume.
> > > 
> > > Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
> > > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> > > ---
> > >   drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
> > >   1 file changed, 14 insertions(+), 13 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> > > index 3e13acdf..71aa944 100644
> > > --- a/drivers/gpu/drm/msm/dp/dp_display.c
> > > +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> > > @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
> > >   {
> > >          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> > >          struct msm_dp *dp_display = dp_bridge->dp_display;
> > > +       struct dp_display_private *dp;
> > > +
> > > +       dp = container_of(dp_display, struct dp_display_private, dp_display);
> > > 
> > >          dp_display->internal_hpd = true;
> > 
> > Can we set internal_hpd to true during probe when we see that the hpd
> > pinmux exists? Or do any of these bits toggle in the irq status register
> > when the gpio isn't muxed to "dp_hot" or the controller is for eDP and
> > it doesn't have any gpio connection internally? I'm wondering if we can
> > get by with simply enabling the "dp_hot" pin interrupts
> > (plug/unplug/replug/irq_hpd) unconditionally and not worrying about them
> > if eDP is there (because the pin doesn't exist inside the SoC), or if DP
> > HPD is being signalled out of band through type-c framework.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-11  4:24   ` Dmitry Baryshkov
@ 2023-05-11 15:53     ` Bjorn Andersson
  2023-05-11 15:57       ` Dmitry Baryshkov
  0 siblings, 1 reply; 20+ messages in thread
From: Bjorn Andersson @ 2023-05-11 15:53 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, quic_abhinavk, quic_jesszhan,
	quic_sbillaka, marijn.suijten, freedreno, linux-arm-msm,
	linux-kernel

On Thu, May 11, 2023 at 07:24:46AM +0300, Dmitry Baryshkov wrote:
> On Wed, 10 May 2023 at 23:31, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
> >
> > The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> > pinmuxed into DP controller. HPD plug/unplug interrupts cannot be enabled until
> > internal_hpd flag is set to true.
> > At both bootup and resume time, the DP driver will enable external DP
> > plugin interrupts and handle plugin interrupt accordingly. Unfortunately
> > dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
> > flag to true later than where DP driver expected during bootup time.
> >
> > This causes external DP plugin event to not get detected and display stays blank.
> > Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
> > set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
> > simultaneously to avoid timing issue during bootup and resume.
> >
> > Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
> > Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> 
> Thanks for debugging this!
> 
> However after looking at the driver I think there is more than this.
> 
> We have several other places gated on internal_hpd flag, where we do
> not have a strict ordering of events.
> I see that dp_hpd_plug_handle() and dp_hpd_unplug_handle() also toggle
> DP_DP_IRQ_HPD_INT_MASK and DP_DP_HPD_REPLUG_INT_MASK depending on
> internal_hpd. Can we toggle all 4 interrupts from the
> hpd_enable/hpd_disable functions? If we can do it, then I think we can
> drop the internal_hpd flag completely.
> 

Yes, that's what I believe the DRM framework intend us to do.

The problem, and reason why I didn't do tat in my series, was that in
order to update the INT_MASKs you need to clock the IP-block and that's
done elsewhere.

So, for the internal_hpd case, it seems appropriate to pm_runtime_get()
in hpd_enable() and unmask the HPD interrupts, and mask the interrupts
and pm_runtime_put() in hpd_disable().


But for edp and external HPD-signal we also need to make sure power is
on while something is connected...

> I went on and checked other places where it is used:
> - dp_hpd_unplug_handle(), guarding DP_DP_HPD_PLUG_INT_MASK toggling. I
> think we can drop these two calls completely. The function is under
> the event_mutex protection, so other events can not interfere.
> - dp_bridge_hpd_notify(). What is the point of this check? If some
> other party informs us of the HPD event, we'd better handle it instead
> of dropping it. Correct?  In other words, I'd prefer seeing the
> hpd_event_thread removal. Instead of that I think that on
> HPD/plug/unplug/etc. IRQ the driver should call into the drm stack,
> then the hpd_notify call should process those events.
> 

I agree, that seems to be what's expected of us from the DRM framework.

Regards,
Bjorn

> 
> > ---
> >  drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
> >  1 file changed, 14 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
> > index 3e13acdf..71aa944 100644
> > --- a/drivers/gpu/drm/msm/dp/dp_display.c
> > +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> > @@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
> >         dp_display_host_init(dp);
> >         dp_catalog_ctrl_hpd_config(dp->catalog);
> >
> > -       /* Enable plug and unplug interrupts only if requested */
> > -       if (dp->dp_display.internal_hpd)
> > -               dp_catalog_hpd_config_intr(dp->catalog,
> > -                               DP_DP_HPD_PLUG_INT_MASK |
> > -                               DP_DP_HPD_UNPLUG_INT_MASK,
> > -                               true);
> > -
> >         /* Enable interrupt first time
> >          * we are leaving dp clocks on during disconnect
> >          * and never disable interrupt
> > @@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
> >
> >         dp_catalog_ctrl_hpd_config(dp->catalog);
> >
> > -       if (dp->dp_display.internal_hpd)
> > -               dp_catalog_hpd_config_intr(dp->catalog,
> > -                               DP_DP_HPD_PLUG_INT_MASK |
> > -                               DP_DP_HPD_UNPLUG_INT_MASK,
> > -                               true);
> > -
> >         if (dp_catalog_link_is_connected(dp->catalog)) {
> >                 /*
> >                  * set sink to normal operation mode -- D0
> > @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
> >  {
> >         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> >         struct msm_dp *dp_display = dp_bridge->dp_display;
> > +       struct dp_display_private *dp;
> > +
> > +       dp = container_of(dp_display, struct dp_display_private, dp_display);
> >
> >         dp_display->internal_hpd = true;
> > +       dp_catalog_hpd_config_intr(dp->catalog,
> > +                               DP_DP_HPD_PLUG_INT_MASK |
> > +                               DP_DP_HPD_UNPLUG_INT_MASK,
> > +                               true);
> >  }
> >
> >  void dp_bridge_hpd_disable(struct drm_bridge *bridge)
> >  {
> >         struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> >         struct msm_dp *dp_display = dp_bridge->dp_display;
> > +       struct dp_display_private *dp;
> > +
> > +       dp = container_of(dp_display, struct dp_display_private, dp_display);
> >
> > +       dp_catalog_hpd_config_intr(dp->catalog,
> > +                               DP_DP_HPD_PLUG_INT_MASK |
> > +                               DP_DP_HPD_UNPLUG_INT_MASK,
> > +                               false);
> >         dp_display->internal_hpd = false;
> >  }
> 
> --
> With best wishes
> Dmitry

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-11 15:53     ` Bjorn Andersson
@ 2023-05-11 15:57       ` Dmitry Baryshkov
  2023-05-12  0:16         ` Kuogee Hsieh
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Baryshkov @ 2023-05-11 15:57 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, quic_abhinavk, quic_jesszhan,
	quic_sbillaka, marijn.suijten, freedreno, linux-arm-msm,
	linux-kernel

On 11/05/2023 18:53, Bjorn Andersson wrote:
> On Thu, May 11, 2023 at 07:24:46AM +0300, Dmitry Baryshkov wrote:
>> On Wed, 10 May 2023 at 23:31, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
>>>
>>> The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
>>> pinmuxed into DP controller. HPD plug/unplug interrupts cannot be enabled until
>>> internal_hpd flag is set to true.
>>> At both bootup and resume time, the DP driver will enable external DP
>>> plugin interrupts and handle plugin interrupt accordingly. Unfortunately
>>> dp_bridge_hpd_enable() bridge ops function was called to set internal_hpd
>>> flag to true later than where DP driver expected during bootup time.
>>>
>>> This causes external DP plugin event to not get detected and display stays blank.
>>> Move enabling HDP plugin/unplugged interrupts to dp_bridge_hpd_enable()/disable() to
>>> set internal_hpd to true along with enabling HPD plugin/unplugged interrupts
>>> simultaneously to avoid timing issue during bootup and resume.
>>>
>>> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable callbacks")
>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>>
>> Thanks for debugging this!
>>
>> However after looking at the driver I think there is more than this.
>>
>> We have several other places gated on internal_hpd flag, where we do
>> not have a strict ordering of events.
>> I see that dp_hpd_plug_handle() and dp_hpd_unplug_handle() also toggle
>> DP_DP_IRQ_HPD_INT_MASK and DP_DP_HPD_REPLUG_INT_MASK depending on
>> internal_hpd. Can we toggle all 4 interrupts from the
>> hpd_enable/hpd_disable functions? If we can do it, then I think we can
>> drop the internal_hpd flag completely.
>>
> 
> Yes, that's what I believe the DRM framework intend us to do.
> 
> The problem, and reason why I didn't do tat in my series, was that in
> order to update the INT_MASKs you need to clock the IP-block and that's
> done elsewhere.
> 
> So, for the internal_hpd case, it seems appropriate to pm_runtime_get()
> in hpd_enable() and unmask the HPD interrupts, and mask the interrupts
> and pm_runtime_put() in hpd_disable().
> 
> 
> But for edp and external HPD-signal we also need to make sure power is
> on while something is connected...

I think this is already handled by the existing code, see calls to the 
dp_display_host_init().

> 
>> I went on and checked other places where it is used:
>> - dp_hpd_unplug_handle(), guarding DP_DP_HPD_PLUG_INT_MASK toggling. I
>> think we can drop these two calls completely. The function is under
>> the event_mutex protection, so other events can not interfere.
>> - dp_bridge_hpd_notify(). What is the point of this check? If some
>> other party informs us of the HPD event, we'd better handle it instead
>> of dropping it. Correct?  In other words, I'd prefer seeing the
>> hpd_event_thread removal. Instead of that I think that on
>> HPD/plug/unplug/etc. IRQ the driver should call into the drm stack,
>> then the hpd_notify call should process those events.
>>
> 
> I agree, that seems to be what's expected of us from the DRM framework.
> 
> Regards,
> Bjorn
> 
>>
>>> ---
>>>   drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
>>>   1 file changed, 14 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
>>> index 3e13acdf..71aa944 100644
>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>>> @@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
>>>          dp_display_host_init(dp);
>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
>>>
>>> -       /* Enable plug and unplug interrupts only if requested */
>>> -       if (dp->dp_display.internal_hpd)
>>> -               dp_catalog_hpd_config_intr(dp->catalog,
>>> -                               DP_DP_HPD_PLUG_INT_MASK |
>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
>>> -                               true);
>>> -
>>>          /* Enable interrupt first time
>>>           * we are leaving dp clocks on during disconnect
>>>           * and never disable interrupt
>>> @@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
>>>
>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
>>>
>>> -       if (dp->dp_display.internal_hpd)
>>> -               dp_catalog_hpd_config_intr(dp->catalog,
>>> -                               DP_DP_HPD_PLUG_INT_MASK |
>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
>>> -                               true);
>>> -
>>>          if (dp_catalog_link_is_connected(dp->catalog)) {
>>>                  /*
>>>                   * set sink to normal operation mode -- D0
>>> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
>>>   {
>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
>>> +       struct dp_display_private *dp;
>>> +
>>> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>>>
>>>          dp_display->internal_hpd = true;
>>> +       dp_catalog_hpd_config_intr(dp->catalog,
>>> +                               DP_DP_HPD_PLUG_INT_MASK |
>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
>>> +                               true);
>>>   }
>>>
>>>   void dp_bridge_hpd_disable(struct drm_bridge *bridge)
>>>   {
>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
>>> +       struct dp_display_private *dp;
>>> +
>>> +       dp = container_of(dp_display, struct dp_display_private, dp_display);
>>>
>>> +       dp_catalog_hpd_config_intr(dp->catalog,
>>> +                               DP_DP_HPD_PLUG_INT_MASK |
>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
>>> +                               false);
>>>          dp_display->internal_hpd = false;
>>>   }
>>
>> --
>> With best wishes
>> Dmitry

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-10 20:31 [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Kuogee Hsieh
  2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
  2023-05-10 20:31 ` [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads Kuogee Hsieh
@ 2023-05-11 16:02 ` Dmitry Baryshkov
  2 siblings, 0 replies; 20+ messages in thread
From: Dmitry Baryshkov @ 2023-05-11 16:02 UTC (permalink / raw)
  To: Kuogee Hsieh, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, andersson
  Cc: quic_abhinavk, quic_jesszhan, quic_sbillaka, marijn.suijten,
	freedreno, linux-arm-msm, linux-kernel

On 10/05/2023 23:31, Kuogee Hsieh wrote:
> There is bug report on exteranl DP display does not work.
> This patch add below two patches to fix the problem.
> 1) enable HDP plugin/unplugged interrupts to hpd_enable/disable
> 2) add mutex to protect internal_hpd against race condition between different threads
>      
> 
> Kuogee Hsieh (2):
>    drm/msm/dp: enable HDP plugin/unplugged interrupts to
>      hpd_enable/disable
>    drm/msm/dp: add mutex to protect internal_hpd against race condition
>      between different threads
> 
>   drivers/gpu/drm/msm/dp/dp_display.c | 37 +++++++++++++++++++++++--------------
>   1 file changed, 23 insertions(+), 14 deletions(-)
> 

BTW: Kuogee, what happened to the patchset promised at [1] ?

In the reply, [2], I asked you to remove DP_HPD_INIT_SETUP completely, 
and then you went silent.

[1] 
https://lore.kernel.org/dri-devel/4c733721-855a-85fd-82a9-9af0f80fc02e@quicinc.com/ 


[2] 
https://lore.kernel.org/dri-devel/358262c3-e501-3c7f-7502-f0323cdcc634@linaro.org/

-- 
With best wishes
Dmitry


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-11 15:44       ` Bjorn Andersson
@ 2023-05-11 17:55         ` Stephen Boyd
  0 siblings, 0 replies; 20+ messages in thread
From: Stephen Boyd @ 2023-05-11 17:55 UTC (permalink / raw)
  To: Abhinav Kumar, Bjorn Andersson
  Cc: Kuogee Hsieh, agross, airlied, daniel, dianders,
	dmitry.baryshkov, dri-devel, robdclark, sean, vkoul,
	quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel

Quoting Bjorn Andersson (2023-05-11 08:44:16)
> On Wed, May 10, 2023 at 05:39:07PM -0700, Abhinav Kumar wrote:
> >
> >
> > On 5/10/2023 4:55 PM, Stephen Boyd wrote:
> > > Quoting Kuogee Hsieh (2023-05-10 13:31:04)
> > > > The internal_hpd flag was introduced to handle external DP HPD derived from GPIO
> > > > pinmuxed into DP controller.
> > >
> > > Was it? It looks more like it was done to differentiate between eDP and
> > > DP, because internal_hpd is set only if DRM_BRIDGE_OP_HPD is set on the
> > > bridge and we only set the bridge op if the connector type is DP. The
> > > assumption looks like if you have DP connector_type, you have the gpio
> > > pinmuxed for "dp_hot" mode, which isn't exactly true. We don't treat
> > > that gpio as an irq either, because it isn't. Instead the gpio is muxed
> > > to the mdss inside the SoC and then that generates an mdss interrupt
> > > that's combined with non-HPD things like "video ready".
> > >
> > > If that all follows, then I don't quite understand why we're setting
> > > internal_hpd to false at all at runtime. It should be set to true at
> > > some point, but ideally that point is during probe.
> > >
> >
> > Kuogee had the same thought originally but were not entirely sure of this
> > part of the commit message in Bjorn's original commit which introduced these
> > changes.
> >
> > "This difference is not appropriately represented by the "is_edp"
> > boolean, but is properly represented by the frameworks invocation of the
> > hpd_enable() and hpd_disable() callbacks. Switch the current condition
> > to rely on these callbacks instead"
> >
> > Does this along with below documentation mean we should generate the hpd
> > interrupts only after hpd_enable callback happens?
> >
> > " * Call &drm_bridge_funcs.hpd_enable if implemented and register the given
> > @cb
> >  * and @data as hot plug notification callback. From now on the @cb will be
> >  * called with @data when an output status change is detected by the bridge,
> >  * until hot plug notification gets disabled with drm_bridge_hpd_disable().
> > "
> >
> > Bjorn, can you please clarify this?
> >
>
> We currently have 3 cases:
>
> 1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
> and internal HPD-logic is in used (internal_hpd = true). Power needs to
> be on at all times etc.
>
> 2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
> internal HPD-logic should not be used/enabled (internal_hpd = false).
> Power doesn't need to be on unless hpd_notify is invoked to tell us that
> there's something connected...
>
> 3) eDP with or without HPD signal and/or HPD gpio. Downstream
> drm_bridge/panel is connected, is_edp = true and internal HPD logic is
> short-circuited regardless of the panel providing HPD signal or not.

Oh weird. I thought that the "is_edp" controller on sc7280 didn't have
HPD hardware in the PHY (phy@aec2a00), hence all the logic to avoid
using the HPD interrupts and bits there. What is "is_edp" about then?

>
>
> In #1 dp_bridge_hpd_enable() will be invoked to indicate that the DP
> controller is expected to perform HPD handling. In #2
> dp_bridge_hpd_enable() will _not_ be invoked, instead some downstream
> drm_bridge/panel will get the hpd_enable() callback and will be
> responsible to updating the HPD state of the chain, which will cause
> hpd_notify to be invoked.
>
>
> Note that #3 is based entirely on the controller, it has currently no
> relation to what is attached. It seems reasonable that this is just
> another case of #2 (perhaps just always reporting
> connector_status_connected?).
>

Looking at drm_bridge_connector_detect() the default is to consider
DRM_MODE_CONNECTOR_eDP as connector_status_connected. I wonder if
panel_bridge_bridge_funcs can gain a 'detect' function and also set
DRM_BRIDGE_OP_DETECT if the connector_type is DRM_MODE_CONNECTOR_eDP.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-11 15:57       ` Dmitry Baryshkov
@ 2023-05-12  0:16         ` Kuogee Hsieh
  2023-05-12  0:54           ` Dmitry Baryshkov
  0 siblings, 1 reply; 20+ messages in thread
From: Kuogee Hsieh @ 2023-05-12  0:16 UTC (permalink / raw)
  To: Dmitry Baryshkov, Bjorn Andersson
  Cc: dri-devel, robdclark, sean, swboyd, dianders, vkoul, daniel,
	airlied, agross, quic_abhinavk, quic_jesszhan, quic_sbillaka,
	marijn.suijten, freedreno, linux-arm-msm, linux-kernel


On 5/11/2023 8:57 AM, Dmitry Baryshkov wrote:
> On 11/05/2023 18:53, Bjorn Andersson wrote:
>> On Thu, May 11, 2023 at 07:24:46AM +0300, Dmitry Baryshkov wrote:
>>> On Wed, 10 May 2023 at 23:31, Kuogee Hsieh <quic_khsieh@quicinc.com> 
>>> wrote:
>>>>
>>>> The internal_hpd flag was introduced to handle external DP HPD 
>>>> derived from GPIO
>>>> pinmuxed into DP controller. HPD plug/unplug interrupts cannot be 
>>>> enabled until
>>>> internal_hpd flag is set to true.
>>>> At both bootup and resume time, the DP driver will enable external DP
>>>> plugin interrupts and handle plugin interrupt accordingly. 
>>>> Unfortunately
>>>> dp_bridge_hpd_enable() bridge ops function was called to set 
>>>> internal_hpd
>>>> flag to true later than where DP driver expected during bootup time.
>>>>
>>>> This causes external DP plugin event to not get detected and 
>>>> display stays blank.
>>>> Move enabling HDP plugin/unplugged interrupts to 
>>>> dp_bridge_hpd_enable()/disable() to
>>>> set internal_hpd to true along with enabling HPD plugin/unplugged 
>>>> interrupts
>>>> simultaneously to avoid timing issue during bootup and resume.
>>>>
>>>> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable 
>>>> callbacks")
>>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
>>>
>>> Thanks for debugging this!
>>>
>>> However after looking at the driver I think there is more than this.
>>>
>>> We have several other places gated on internal_hpd flag, where we do
>>> not have a strict ordering of events.
>>> I see that dp_hpd_plug_handle() and dp_hpd_unplug_handle() also toggle
>>> DP_DP_IRQ_HPD_INT_MASK and DP_DP_HPD_REPLUG_INT_MASK depending on
>>> internal_hpd. Can we toggle all 4 interrupts from the
>>> hpd_enable/hpd_disable functions? If we can do it, then I think we can
>>> drop the internal_hpd flag completely.
>>>
>>
>> Yes, that's what I believe the DRM framework intend us to do.
>>
>> The problem, and reason why I didn't do tat in my series, was that in
>> order to update the INT_MASKs you need to clock the IP-block and that's
>> done elsewhere.
>>
>> So, for the internal_hpd case, it seems appropriate to pm_runtime_get()
>> in hpd_enable() and unmask the HPD interrupts, and mask the interrupts
>> and pm_runtime_put() in hpd_disable().
>>
>>
>> But for edp and external HPD-signal we also need to make sure power is
>> on while something is connected...
>
> I think this is already handled by the existing code, see calls to the 
> dp_display_host_init().
>
>>
>>> I went on and checked other places where it is used:
>>> - dp_hpd_unplug_handle(), guarding DP_DP_HPD_PLUG_INT_MASK toggling. I
>>> think we can drop these two calls completely. The function is under
>>> the event_mutex protection, so other events can not interfere.
>>> - dp_bridge_hpd_notify(). What is the point of this check? If some
>>> other party informs us of the HPD event, we'd better handle it instead
>>> of dropping it. Correct?  In other words, I'd prefer seeing the
>>> hpd_event_thread removal. Instead of that I think that on
>>> HPD/plug/unplug/etc. IRQ the driver should call into the drm stack,
>>> then the hpd_notify call should process those events.
>>>
1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
and internal HPD-logic is in used (internal_hpd = true). Power needs to
be on at all times etc.

2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
internal HPD-logic should not be used/enabled (internal_hpd = false).
Power doesn't need to be on unless hpd_notify is invoked to tell us that
there's something connected...

- dp_bridge_hpd_notify(). What is the point of this check? <== i have 
below two questions,

1) can you explain when/what this dp_bridge_hpd_notify() will be called?

2) is dp_bridge_hpd_notify() only will be called at above case #2? and 
it will not be used by case #1?



>>
>> I agree, that seems to be what's expected of us from the DRM framework.
>>
>> Regards,
>> Bjorn
>>
>>>
>>>> ---
>>>>   drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
>>>>   1 file changed, 14 insertions(+), 13 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
>>>> b/drivers/gpu/drm/msm/dp/dp_display.c
>>>> index 3e13acdf..71aa944 100644
>>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
>>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
>>>> @@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct 
>>>> dp_display_private *dp)
>>>>          dp_display_host_init(dp);
>>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
>>>>
>>>> -       /* Enable plug and unplug interrupts only if requested */
>>>> -       if (dp->dp_display.internal_hpd)
>>>> -               dp_catalog_hpd_config_intr(dp->catalog,
>>>> -                               DP_DP_HPD_PLUG_INT_MASK |
>>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
>>>> -                               true);
>>>> -
>>>>          /* Enable interrupt first time
>>>>           * we are leaving dp clocks on during disconnect
>>>>           * and never disable interrupt
>>>> @@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
>>>>
>>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
>>>>
>>>> -       if (dp->dp_display.internal_hpd)
>>>> -               dp_catalog_hpd_config_intr(dp->catalog,
>>>> -                               DP_DP_HPD_PLUG_INT_MASK |
>>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
>>>> -                               true);
>>>> -
>>>>          if (dp_catalog_link_is_connected(dp->catalog)) {
>>>>                  /*
>>>>                   * set sink to normal operation mode -- D0
>>>> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge 
>>>> *bridge)
>>>>   {
>>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
>>>> +       struct dp_display_private *dp;
>>>> +
>>>> +       dp = container_of(dp_display, struct dp_display_private, 
>>>> dp_display);
>>>>
>>>>          dp_display->internal_hpd = true;
>>>> +       dp_catalog_hpd_config_intr(dp->catalog,
>>>> +                               DP_DP_HPD_PLUG_INT_MASK |
>>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
>>>> +                               true);
>>>>   }
>>>>
>>>>   void dp_bridge_hpd_disable(struct drm_bridge *bridge)
>>>>   {
>>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
>>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
>>>> +       struct dp_display_private *dp;
>>>> +
>>>> +       dp = container_of(dp_display, struct dp_display_private, 
>>>> dp_display);
>>>>
>>>> +       dp_catalog_hpd_config_intr(dp->catalog,
>>>> +                               DP_DP_HPD_PLUG_INT_MASK |
>>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
>>>> +                               false);
>>>>          dp_display->internal_hpd = false;
>>>>   }
>>>
>>> -- 
>>> With best wishes
>>> Dmitry
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-12  0:16         ` Kuogee Hsieh
@ 2023-05-12  0:54           ` Dmitry Baryshkov
  2023-05-12 18:03             ` Stephen Boyd
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry Baryshkov @ 2023-05-12  0:54 UTC (permalink / raw)
  To: Kuogee Hsieh
  Cc: Bjorn Andersson, dri-devel, robdclark, sean, swboyd, dianders,
	vkoul, daniel, airlied, agross, quic_abhinavk, quic_jesszhan,
	quic_sbillaka, marijn.suijten, freedreno, linux-arm-msm,
	linux-kernel

On Fri, 12 May 2023 at 03:16, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
>
>
> On 5/11/2023 8:57 AM, Dmitry Baryshkov wrote:
> > On 11/05/2023 18:53, Bjorn Andersson wrote:
> >> On Thu, May 11, 2023 at 07:24:46AM +0300, Dmitry Baryshkov wrote:
> >>> On Wed, 10 May 2023 at 23:31, Kuogee Hsieh <quic_khsieh@quicinc.com>
> >>> wrote:
> >>>>
> >>>> The internal_hpd flag was introduced to handle external DP HPD
> >>>> derived from GPIO
> >>>> pinmuxed into DP controller. HPD plug/unplug interrupts cannot be
> >>>> enabled until
> >>>> internal_hpd flag is set to true.
> >>>> At both bootup and resume time, the DP driver will enable external DP
> >>>> plugin interrupts and handle plugin interrupt accordingly.
> >>>> Unfortunately
> >>>> dp_bridge_hpd_enable() bridge ops function was called to set
> >>>> internal_hpd
> >>>> flag to true later than where DP driver expected during bootup time.
> >>>>
> >>>> This causes external DP plugin event to not get detected and
> >>>> display stays blank.
> >>>> Move enabling HDP plugin/unplugged interrupts to
> >>>> dp_bridge_hpd_enable()/disable() to
> >>>> set internal_hpd to true along with enabling HPD plugin/unplugged
> >>>> interrupts
> >>>> simultaneously to avoid timing issue during bootup and resume.
> >>>>
> >>>> Fixes: cd198caddea7 ("drm/msm/dp: Rely on hpd_enable/disable
> >>>> callbacks")
> >>>> Signed-off-by: Kuogee Hsieh <quic_khsieh@quicinc.com>
> >>>
> >>> Thanks for debugging this!
> >>>
> >>> However after looking at the driver I think there is more than this.
> >>>
> >>> We have several other places gated on internal_hpd flag, where we do
> >>> not have a strict ordering of events.
> >>> I see that dp_hpd_plug_handle() and dp_hpd_unplug_handle() also toggle
> >>> DP_DP_IRQ_HPD_INT_MASK and DP_DP_HPD_REPLUG_INT_MASK depending on
> >>> internal_hpd. Can we toggle all 4 interrupts from the
> >>> hpd_enable/hpd_disable functions? If we can do it, then I think we can
> >>> drop the internal_hpd flag completely.
> >>>
> >>
> >> Yes, that's what I believe the DRM framework intend us to do.
> >>
> >> The problem, and reason why I didn't do tat in my series, was that in
> >> order to update the INT_MASKs you need to clock the IP-block and that's
> >> done elsewhere.
> >>
> >> So, for the internal_hpd case, it seems appropriate to pm_runtime_get()
> >> in hpd_enable() and unmask the HPD interrupts, and mask the interrupts
> >> and pm_runtime_put() in hpd_disable().
> >>
> >>
> >> But for edp and external HPD-signal we also need to make sure power is
> >> on while something is connected...
> >
> > I think this is already handled by the existing code, see calls to the
> > dp_display_host_init().
> >
> >>
> >>> I went on and checked other places where it is used:
> >>> - dp_hpd_unplug_handle(), guarding DP_DP_HPD_PLUG_INT_MASK toggling. I
> >>> think we can drop these two calls completely. The function is under
> >>> the event_mutex protection, so other events can not interfere.
> >>> - dp_bridge_hpd_notify(). What is the point of this check? If some
> >>> other party informs us of the HPD event, we'd better handle it instead
> >>> of dropping it. Correct?  In other words, I'd prefer seeing the
> >>> hpd_event_thread removal. Instead of that I think that on
> >>> HPD/plug/unplug/etc. IRQ the driver should call into the drm stack,
> >>> then the hpd_notify call should process those events.
> >>>
> 1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
> and internal HPD-logic is in used (internal_hpd = true). Power needs to
> be on at all times etc.
>
> 2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
> internal HPD-logic should not be used/enabled (internal_hpd = false).
> Power doesn't need to be on unless hpd_notify is invoked to tell us that
> there's something connected...
>
> - dp_bridge_hpd_notify(). What is the point of this check? <== i have
> below two questions,
>
> 1) can you explain when/what this dp_bridge_hpd_notify() will be called?

The call chain is drm_bridge_hpd_notify() ->
drm_bridge_connector_hpd_notify() -> .hpd_notify() for all drm_bridge
in chain

One should add a call to drm_bridge_hpd_notify() when the hotplug
event has been detected.

Also please note the patch https://patchwork.freedesktop.org/patch/484432/

>
> 2) is dp_bridge_hpd_notify() only will be called at above case #2? and
> it will not be used by case #1?

Once the driver calls drm_bridge_hpd_notify() in the hpd path, the
hpd_notify callbacks will be called in case#1 too.

BTW: I don't see drm_bridge_hpd_notify() or
drm_kms_{,connector_}_hotplug_event() HPD notifications in the DP
driver at all. This should be fixed.

>
>
>
> >>
> >> I agree, that seems to be what's expected of us from the DRM framework.
> >>
> >> Regards,
> >> Bjorn
> >>
> >>>
> >>>> ---
> >>>>   drivers/gpu/drm/msm/dp/dp_display.c | 27 ++++++++++++++-------------
> >>>>   1 file changed, 14 insertions(+), 13 deletions(-)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.c
> >>>> b/drivers/gpu/drm/msm/dp/dp_display.c
> >>>> index 3e13acdf..71aa944 100644
> >>>> --- a/drivers/gpu/drm/msm/dp/dp_display.c
> >>>> +++ b/drivers/gpu/drm/msm/dp/dp_display.c
> >>>> @@ -1088,13 +1088,6 @@ static void dp_display_config_hpd(struct
> >>>> dp_display_private *dp)
> >>>>          dp_display_host_init(dp);
> >>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
> >>>>
> >>>> -       /* Enable plug and unplug interrupts only if requested */
> >>>> -       if (dp->dp_display.internal_hpd)
> >>>> -               dp_catalog_hpd_config_intr(dp->catalog,
> >>>> -                               DP_DP_HPD_PLUG_INT_MASK |
> >>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
> >>>> -                               true);
> >>>> -
> >>>>          /* Enable interrupt first time
> >>>>           * we are leaving dp clocks on during disconnect
> >>>>           * and never disable interrupt
> >>>> @@ -1396,12 +1389,6 @@ static int dp_pm_resume(struct device *dev)
> >>>>
> >>>>          dp_catalog_ctrl_hpd_config(dp->catalog);
> >>>>
> >>>> -       if (dp->dp_display.internal_hpd)
> >>>> -               dp_catalog_hpd_config_intr(dp->catalog,
> >>>> -                               DP_DP_HPD_PLUG_INT_MASK |
> >>>> -                               DP_DP_HPD_UNPLUG_INT_MASK,
> >>>> -                               true);
> >>>> -
> >>>>          if (dp_catalog_link_is_connected(dp->catalog)) {
> >>>>                  /*
> >>>>                   * set sink to normal operation mode -- D0
> >>>> @@ -1801,15 +1788,29 @@ void dp_bridge_hpd_enable(struct drm_bridge
> >>>> *bridge)
> >>>>   {
> >>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> >>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
> >>>> +       struct dp_display_private *dp;
> >>>> +
> >>>> +       dp = container_of(dp_display, struct dp_display_private,
> >>>> dp_display);
> >>>>
> >>>>          dp_display->internal_hpd = true;
> >>>> +       dp_catalog_hpd_config_intr(dp->catalog,
> >>>> +                               DP_DP_HPD_PLUG_INT_MASK |
> >>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
> >>>> +                               true);
> >>>>   }
> >>>>
> >>>>   void dp_bridge_hpd_disable(struct drm_bridge *bridge)
> >>>>   {
> >>>>          struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
> >>>>          struct msm_dp *dp_display = dp_bridge->dp_display;
> >>>> +       struct dp_display_private *dp;
> >>>> +
> >>>> +       dp = container_of(dp_display, struct dp_display_private,
> >>>> dp_display);
> >>>>
> >>>> +       dp_catalog_hpd_config_intr(dp->catalog,
> >>>> +                               DP_DP_HPD_PLUG_INT_MASK |
> >>>> +                               DP_DP_HPD_UNPLUG_INT_MASK,
> >>>> +                               false);
> >>>>          dp_display->internal_hpd = false;
> >>>>   }
> >>>
> >>> --
> >>> With best wishes
> >>> Dmitry
> >



-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-12  0:54           ` Dmitry Baryshkov
@ 2023-05-12 18:03             ` Stephen Boyd
  2023-05-12 18:30               ` Dmitry Baryshkov
  0 siblings, 1 reply; 20+ messages in thread
From: Stephen Boyd @ 2023-05-12 18:03 UTC (permalink / raw)
  To: Dmitry Baryshkov, Kuogee Hsieh
  Cc: Bjorn Andersson, dri-devel, robdclark, sean, dianders, vkoul,
	daniel, airlied, agross, quic_abhinavk, quic_jesszhan,
	quic_sbillaka, marijn.suijten, freedreno, linux-arm-msm,
	linux-kernel

Quoting Dmitry Baryshkov (2023-05-11 17:54:19)
> On Fri, 12 May 2023 at 03:16, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
> > 1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
> > and internal HPD-logic is in used (internal_hpd = true). Power needs to
> > be on at all times etc.
> >
> > 2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
> > internal HPD-logic should not be used/enabled (internal_hpd = false).
> > Power doesn't need to be on unless hpd_notify is invoked to tell us that
> > there's something connected...
> >
> > - dp_bridge_hpd_notify(). What is the point of this check? <== i have
> > below two questions,
> >
> > 1) can you explain when/what this dp_bridge_hpd_notify() will be called?
>
> The call chain is drm_bridge_hpd_notify() ->
> drm_bridge_connector_hpd_notify() -> .hpd_notify() for all drm_bridge
> in chain
>
> One should add a call to drm_bridge_hpd_notify() when the hotplug
> event has been detected.
>
> Also please note the patch https://patchwork.freedesktop.org/patch/484432/
>
> >
> > 2) is dp_bridge_hpd_notify() only will be called at above case #2? and
> > it will not be used by case #1?
>
> Once the driver calls drm_bridge_hpd_notify() in the hpd path, the
> hpd_notify callbacks will be called in case#1 too.
>
> BTW: I don't see drm_bridge_hpd_notify() or
> drm_kms_{,connector_}_hotplug_event() HPD notifications in the DP
> driver at all. This should be fixed.
>

Is dp_bridge_hpd_notify() being called by
drm_helper_probe_single_connector_modes() when the connectors are
detected?

I see drm_helper_probe_detect() calls connector->funcs->detect() which I
think calls
drm_bridge_connector_funcs::drm_bridge_connector_hpd_notify() but I
haven't confirmed yet. The 'detect' bridge is the DP bridge in msm
driver

         if (!dp_display->is_edp) {
                bridge->ops =
                        DRM_BRIDGE_OP_DETECT |

so if the bridge_connector is being used then I think when fill_modes()
is called we'll run the detect cycle and call the hpd_notify callbacks
on the bridge chain.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v1 1/2] drm/msm/dp: enable HDP plugin/unplugged interrupts to hpd_enable/disable
  2023-05-12 18:03             ` Stephen Boyd
@ 2023-05-12 18:30               ` Dmitry Baryshkov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry Baryshkov @ 2023-05-12 18:30 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Kuogee Hsieh, Bjorn Andersson, dri-devel, robdclark, sean,
	dianders, vkoul, daniel, airlied, agross, quic_abhinavk,
	quic_jesszhan, quic_sbillaka, marijn.suijten, freedreno,
	linux-arm-msm, linux-kernel

On Fri, 12 May 2023 at 21:03, Stephen Boyd <swboyd@chromium.org> wrote:
>
> Quoting Dmitry Baryshkov (2023-05-11 17:54:19)
> > On Fri, 12 May 2023 at 03:16, Kuogee Hsieh <quic_khsieh@quicinc.com> wrote:
> > > 1) DP with GPIO: No downstream drm_bridge are connected, is_edp = false
> > > and internal HPD-logic is in used (internal_hpd = true). Power needs to
> > > be on at all times etc.
> > >
> > > 2) DP without GPIO: Downstream drm_bridge connected, is_edp = false and
> > > internal HPD-logic should not be used/enabled (internal_hpd = false).
> > > Power doesn't need to be on unless hpd_notify is invoked to tell us that
> > > there's something connected...
> > >
> > > - dp_bridge_hpd_notify(). What is the point of this check? <== i have
> > > below two questions,
> > >
> > > 1) can you explain when/what this dp_bridge_hpd_notify() will be called?
> >
> > The call chain is drm_bridge_hpd_notify() ->
> > drm_bridge_connector_hpd_notify() -> .hpd_notify() for all drm_bridge
> > in chain
> >
> > One should add a call to drm_bridge_hpd_notify() when the hotplug
> > event has been detected.
> >
> > Also please note the patch https://patchwork.freedesktop.org/patch/484432/
> >
> > >
> > > 2) is dp_bridge_hpd_notify() only will be called at above case #2? and
> > > it will not be used by case #1?
> >
> > Once the driver calls drm_bridge_hpd_notify() in the hpd path, the
> > hpd_notify callbacks will be called in case#1 too.
> >
> > BTW: I don't see drm_bridge_hpd_notify() or
> > drm_kms_{,connector_}_hotplug_event() HPD notifications in the DP
> > driver at all. This should be fixed.
> >
>
> Is dp_bridge_hpd_notify() being called by
> drm_helper_probe_single_connector_modes() when the connectors are
> detected?
>
> I see drm_helper_probe_detect() calls connector->funcs->detect() which I
> think calls
> drm_bridge_connector_funcs::drm_bridge_connector_hpd_notify() but I
> haven't confirmed yet. The 'detect' bridge is the DP bridge in msm
> driver
>
>          if (!dp_display->is_edp) {
>                 bridge->ops =
>                         DRM_BRIDGE_OP_DETECT |
>
> so if the bridge_connector is being used then I think when fill_modes()
> is called we'll run the detect cycle and call the hpd_notify callbacks
> on the bridge chain.

Yes. This call chain is correct.
drm_helper_probe_single_connector_modes() ->
drm_bridge_connector_detect() -> drm_bridge_connector_hpd_notify().

However on HPD events the DP driver doesn't call into the drm core
(which I believe should be fixed).

-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2023-05-12 18:31 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-10 20:31 [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Kuogee Hsieh
2023-05-10 20:31 ` [PATCH v1 1/2] drm/msm/dp: " Kuogee Hsieh
2023-05-10 23:55   ` Stephen Boyd
2023-05-11  0:39     ` Abhinav Kumar
2023-05-11 15:44       ` Bjorn Andersson
2023-05-11 17:55         ` Stephen Boyd
2023-05-11 15:31     ` Bjorn Andersson
2023-05-11  4:24   ` Dmitry Baryshkov
2023-05-11 15:53     ` Bjorn Andersson
2023-05-11 15:57       ` Dmitry Baryshkov
2023-05-12  0:16         ` Kuogee Hsieh
2023-05-12  0:54           ` Dmitry Baryshkov
2023-05-12 18:03             ` Stephen Boyd
2023-05-12 18:30               ` Dmitry Baryshkov
2023-05-10 20:31 ` [PATCH v1 2/2] drm/msm/dp: add mutex to protect internal_hpd against race condition between different threads Kuogee Hsieh
2023-05-10 22:46   ` Stephen Boyd
2023-05-10 23:11     ` Abhinav Kumar
2023-05-10 23:19       ` Kuogee Hsieh
2023-05-10 23:30         ` Abhinav Kumar
2023-05-11 16:02 ` [PATCH v1 0/2] enable HDP plugin/unplugged interrupts to hpd_enable/disable Dmitry Baryshkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).