Skip to content

Commit a6e2af6

Browse files
Kuogee Hsiehrobclark
authored andcommitted
drm/msm/dp: force link training for display resolution change
Display resolution change is implemented through drm modeset. Older modeset (resolution) has to be disabled first before newer modeset (resolution) can be enabled. Display disable will turn off both pixel clock and main link clock so that main link have to be re-trained during display enable to have new video stream flow again. At current implementation, display enable function manually kicks up irq_hpd_handle which will read panel link status and start link training if link status is not in sync state. However, there is rare case that a particular panel links status keep staying in sync for some period of time after main link had been shut down previously at display disabled. In this case, main link retraining will not be executed by irq_hdp_handle(). Hence video stream of newer display resolution will fail to be transmitted to panel due to main link is not in sync between host and panel. This patch will bypass irq_hpd_handle() in favor of directly call dp_ctrl_on_stream() to always perform link training in regardless of main link status. So that no unexpected exception resolution change failure cases will happen. Also this implementation are more efficient than manual kicking off irq_hpd_handle function. Changes in v2: -- set force_link_train flag on DP only (is_edp == false) Changes in v3: -- revise commit text -- add Fixes tag Changes in v4: -- revise commit text Changes in v5: -- fix spelling at commit text Changes in v6: -- split dp_ctrl_on_stream() for phy test case -- revise commit text for modeset Changes in v7: -- drop 0 assignment at local variable (ret = 0) Changes in v8: -- add patch to remove pixel_rate from dp_ctrl Changes in v9: -- forward declare dp_ctrl_on_stream_phy_test_report() Fixes: 62671d2 ("drm/msm/dp: fixes wrong connection state caused by failure of link train") Signed-off-by: Kuogee Hsieh <[email protected]> Reviewed-by: Stephen Boyd <[email protected]> Patchwork: https://patchwork.freedesktop.org/patch/489895/ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Clark <[email protected]>
1 parent 2211e34 commit a6e2af6

File tree

3 files changed

+32
-16
lines changed

3 files changed

+32
-16
lines changed

drivers/gpu/drm/msm/dp/dp_ctrl.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,8 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
15331533
return ret;
15341534
}
15351535

1536+
static int dp_ctrl_on_stream_phy_test_report(struct dp_ctrl *dp_ctrl);
1537+
15361538
static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
15371539
{
15381540
int ret = 0;
@@ -1556,7 +1558,7 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
15561558

15571559
ret = dp_ctrl_on_link(&ctrl->dp_ctrl);
15581560
if (!ret)
1559-
ret = dp_ctrl_on_stream(&ctrl->dp_ctrl);
1561+
ret = dp_ctrl_on_stream_phy_test_report(&ctrl->dp_ctrl);
15601562
else
15611563
DRM_ERROR("failed to enable DP link controller\n");
15621564

@@ -1812,7 +1814,27 @@ static int dp_ctrl_link_retrain(struct dp_ctrl_private *ctrl)
18121814
return dp_ctrl_setup_main_link(ctrl, &training_step);
18131815
}
18141816

1815-
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
1817+
static int dp_ctrl_on_stream_phy_test_report(struct dp_ctrl *dp_ctrl)
1818+
{
1819+
int ret;
1820+
struct dp_ctrl_private *ctrl;
1821+
1822+
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1823+
1824+
ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
1825+
1826+
ret = dp_ctrl_enable_stream_clocks(ctrl);
1827+
if (ret) {
1828+
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
1829+
return ret;
1830+
}
1831+
1832+
dp_ctrl_send_phy_test_pattern(ctrl);
1833+
1834+
return 0;
1835+
}
1836+
1837+
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
18161838
{
18171839
int ret = 0;
18181840
bool mainlink_ready = false;
@@ -1848,12 +1870,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
18481870
goto end;
18491871
}
18501872

1851-
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
1852-
dp_ctrl_send_phy_test_pattern(ctrl);
1853-
return 0;
1854-
}
1855-
1856-
if (!dp_ctrl_channel_eq_ok(ctrl))
1873+
if (force_link_train || !dp_ctrl_channel_eq_ok(ctrl))
18571874
dp_ctrl_link_retrain(ctrl);
18581875

18591876
/* stop txing train pattern to end link training */

drivers/gpu/drm/msm/dp/dp_ctrl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct dp_ctrl {
2121
};
2222

2323
int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
24-
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
24+
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train);
2525
int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
2626
int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl);
2727
int dp_ctrl_off(struct dp_ctrl *dp_ctrl);

drivers/gpu/drm/msm/dp/dp_display.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)
873873
return 0;
874874
}
875875

876-
rc = dp_ctrl_on_stream(dp->ctrl);
876+
rc = dp_ctrl_on_stream(dp->ctrl, data);
877877
if (!rc)
878878
dp_display->power_on = true;
879879

@@ -1660,6 +1660,7 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
16601660
int rc = 0;
16611661
struct dp_display_private *dp_display;
16621662
u32 state;
1663+
bool force_link_train = false;
16631664

16641665
dp_display = container_of(dp, struct dp_display_private, dp_display);
16651666
if (!dp_display->dp_mode.drm_mode.clock) {
@@ -1694,10 +1695,12 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
16941695

16951696
state = dp_display->hpd_state;
16961697

1697-
if (state == ST_DISPLAY_OFF)
1698+
if (state == ST_DISPLAY_OFF) {
16981699
dp_display_host_phy_init(dp_display);
1700+
force_link_train = true;
1701+
}
16991702

1700-
dp_display_enable(dp_display, 0);
1703+
dp_display_enable(dp_display, force_link_train);
17011704

17021705
rc = dp_display_post_enable(dp);
17031706
if (rc) {
@@ -1706,10 +1709,6 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
17061709
dp_display_unprepare(dp);
17071710
}
17081711

1709-
/* manual kick off plug event to train link */
1710-
if (state == ST_DISPLAY_OFF)
1711-
dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0);
1712-
17131712
/* completed connection */
17141713
dp_display->hpd_state = ST_CONNECTED;
17151714

0 commit comments

Comments
 (0)