2020-11-03 21:52:51

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH 0/3] fix dp link training failed at irq_hpd request

Some dongle require link training be done at irq_hpd request. This serial
patches address the issues so that DP/HDMI display can be lit up properlly.
This serial Patch also fixes clock stuck at "off" state error caused by
previous link training failed.

Kuogee Hsieh (3):
drm/msm/dp: deinitialize mainlink if link training failed
drm/msm/dp: skip checking LINK_STATUS_UPDATED bit
drm/msm/dp: promote irq_hpd handle to handle link training correctly

drivers/gpu/drm/msm/dp/dp_catalog.c | 2 +-
drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
drivers/gpu/drm/msm/dp/dp_ctrl.c | 60 +++++++++++++++++++++--------
drivers/gpu/drm/msm/dp/dp_display.c | 40 ++++++++++++++++---
drivers/gpu/drm/msm/dp/dp_link.c | 29 +++++++-------
drivers/gpu/drm/msm/dp/dp_panel.c | 2 +-
6 files changed, 96 insertions(+), 39 deletions(-)

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


2020-11-03 21:52:54

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH 1/3] drm/msm/dp: deinitialize mainlink if link training failed

DP compo phy have to be enable to start link training. When
link training failed phy need to be disabled so that next
link traning can be proceed smoothly at next plug in. This
patch de-initialize mainlink to disable phy if link training
failed. This prevent system crash due to
disp_cc_mdss_dp_link_intf_clk stuck at "off" state. This patch
also perform checking power_on flag at dp_display_enable() and
dp_display_disable() to avoid crashing when unplug cable while
display is off.

Fixes: fdaf9a5e3c15 (drm/msm/dp: fixes wrong connection state caused by failure of link training)
Signed-off-by: Kuogee Hsieh <[email protected]>
---
drivers/gpu/drm/msm/dp/dp_catalog.c | 2 +-
drivers/gpu/drm/msm/dp/dp_catalog.h | 2 +-
drivers/gpu/drm/msm/dp/dp_ctrl.c | 40 +++++++++++++++++++++++++++--
drivers/gpu/drm/msm/dp/dp_display.c | 15 ++++++++++-
drivers/gpu/drm/msm/dp/dp_panel.c | 2 +-
5 files changed, 55 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 4963bfe6a472..c2fe0009b092 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -572,7 +572,7 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
}

-u32 dp_catalog_hpd_get_state_status(struct dp_catalog *dp_catalog)
+u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
{
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 6d257dbebf29..176a9020a520 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -97,7 +97,7 @@ void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
u32 intr_mask, bool en);
void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog);
-u32 dp_catalog_hpd_get_state_status(struct dp_catalog *dp_catalog);
+u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog);
void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index cee161c8ecc6..c7af040ce252 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1468,6 +1468,30 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl)
return ret;
}

+static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
+{
+ struct dp_io *dp_io;
+ struct phy *phy;
+ int ret;
+
+ dp_io = &ctrl->parser->io;
+ phy = dp_io->phy;
+
+ dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+
+ dp_catalog_ctrl_reset(ctrl->catalog);
+
+ ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
+ if (ret) {
+ DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
+ }
+
+ phy_power_off(phy);
+ phy_exit(phy);
+
+ return 0;
+}
+
static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
{
int ret = 0;
@@ -1648,8 +1672,7 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
if (rc)
return rc;

- while (--link_train_max_retries &&
- !atomic_read(&ctrl->dp_ctrl.aborted)) {
+ while (--link_train_max_retries) {
rc = dp_ctrl_reinitialize_mainlink(ctrl);
if (rc) {
DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n",
@@ -1664,6 +1687,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
break;
} else if (training_step == DP_TRAINING_1) {
/* link train_1 failed */
+ if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+ break;
+ }
+
rc = dp_ctrl_link_rate_down_shift(ctrl);
if (rc < 0) { /* already in RBR = 1.6G */
if (cr.lane_0_1 & DP_LANE0_1_CR_DONE) {
@@ -1683,6 +1710,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
}
} else if (training_step == DP_TRAINING_2) {
/* link train_2 failed, lower lane rate */
+ if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+ break;
+ }
+
rc = dp_ctrl_link_lane_down_shift(ctrl);
if (rc < 0) {
/* end with failure */
@@ -1703,6 +1734,11 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
*/
if (rc == 0) /* link train successfully */
dp_ctrl_push_idle(dp_ctrl);
+ else {
+ /* link training failed */
+ dp_ctrl_deinitialize_mainlink(ctrl);
+ rc = -ECONNRESET;
+ }

return rc;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 3eb0d428abf7..0c0573ad34e6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -529,6 +529,11 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
if (ret) { /* link train failed */
hpd->hpd_high = 0;
dp->hpd_state = ST_DISCONNECTED;
+
+ if (ret == -ECONNRESET) { /* cable unplugged */
+ dp->core_initialized = false;
+ }
+
} else {
/* start sentinel checking in case of missing uevent */
dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout);
@@ -794,6 +799,11 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)

dp_display = g_dp_display;

+ if (dp_display->power_on) {
+ DRM_DEBUG_DP("Link already setup, return\n");
+ return 0;
+ }
+
rc = dp_ctrl_on_stream(dp->ctrl);
if (!rc)
dp_display->power_on = true;
@@ -826,6 +836,9 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)

dp_display = g_dp_display;

+ if (!dp_display->power_on)
+ return 0;
+
/* wait only if audio was enabled */
if (dp_display->audio_enabled) {
if (!wait_for_completion_timeout(&dp->audio_comp,
@@ -1198,7 +1211,7 @@ static int dp_pm_resume(struct device *dev)

dp_catalog_ctrl_hpd_config(dp->catalog);

- status = dp_catalog_hpd_get_state_status(dp->catalog);
+ status = dp_catalog_link_is_connected(dp->catalog);

if (status)
dp->dp_display.is_connected = true;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 1b7a20dc2d8e..97dca3e378b7 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -197,7 +197,7 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
if (!dp_panel->edid) {
DRM_ERROR("panel edid read failed\n");
/* check edid read fail is due to unplug */
- if (!dp_catalog_hpd_get_state_status(panel->catalog)) {
+ if (!dp_catalog_link_is_connected(panel->catalog)) {
rc = -ETIMEDOUT;
goto end;
}
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

2020-11-03 23:29:20

by Kuogee Hsieh

[permalink] [raw]
Subject: [PATCH 3/3] drm/msm/dp: promote irq_hpd handle to handle link training correctly

Some dongles require link training done at irq_hpd request instead
of plugin request. This patch promote irq_hpd handler to handle link
training and setup hpd_state correctly.

Fixes: fdaf9a5e3c15 (drm/msm/dp: fixes wrong connection state caused by failure of link training)
Signed-off-by: Kuogee Hsieh <[email protected]>
---
drivers/gpu/drm/msm/dp/dp_display.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 0c0573ad34e6..27e7e27b8b90 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -449,10 +449,9 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
sink_request = dp->link->sink_request;

if (sink_request & DS_PORT_STATUS_CHANGED) {
- dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
if (dp_display_is_sink_count_zero(dp)) {
DRM_DEBUG_DP("sink count is zero, nothing to do\n");
- return 0;
+ return -ENOTCONN;
}

return dp_display_process_hpd_high(dp);
@@ -469,7 +468,9 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
static int dp_display_usbpd_attention_cb(struct device *dev)
{
int rc = 0;
+ u32 sink_request;
struct dp_display_private *dp;
+ struct dp_usbpd *hpd;

if (!dev) {
DRM_ERROR("invalid dev\n");
@@ -483,10 +484,26 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
return -ENODEV;
}

+ hpd = dp->usbpd;
+
/* check for any test request issued by sink */
rc = dp_link_process_request(dp->link);
- if (!rc)
- dp_display_handle_irq_hpd(dp);
+ if (!rc) {
+ sink_request = dp->link->sink_request;
+ if (sink_request & DS_PORT_STATUS_CHANGED) {
+ /* same as unplugged */
+ hpd->hpd_high = 0;
+ dp->hpd_state = ST_DISCONNECT_PENDING;
+ dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
+ }
+
+ rc = dp_display_handle_irq_hpd(dp);
+
+ if (!rc && (sink_request & DS_PORT_STATUS_CHANGED)) {
+ hpd->hpd_high = 1;
+ dp->hpd_state = ST_CONNECT_PENDING;
+ }
+ }

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

2020-11-05 04:58:17

by Stephen Boyd

[permalink] [raw]
Subject: Re: [PATCH 3/3] drm/msm/dp: promote irq_hpd handle to handle link training correctly

Quoting Kuogee Hsieh (2020-11-03 12:49:02)
> Some dongles require link training done at irq_hpd request instead
> of plugin request. This patch promote irq_hpd handler to handle link
> training and setup hpd_state correctly.
>
> Fixes: fdaf9a5e3c15 (drm/msm/dp: fixes wrong connection state caused by failure of link training)

This fixes tag has a space before it incorrectly. Also, it should have
quotes.

Fixes: fdaf9a5e3c15 ("drm/msm/dp: fixes wrong connection state caused by failure of link training")

> Signed-off-by: Kuogee Hsieh <[email protected]>
> ---