@@ -1941,40 +1941,61 @@ static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl)
return msm_dp_ctrl_setup_main_link(ctrl, &training_step);
}
-int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train)
+int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train)
{
int ret = 0;
- bool mainlink_ready = false;
struct msm_dp_ctrl_private *ctrl;
- unsigned long pixel_rate;
- unsigned long pixel_rate_orig;
if (!msm_dp_ctrl)
return -EINVAL;
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
- pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock;
-
- if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
- pixel_rate >>= 1;
-
- drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
- ctrl->link->link_params.rate,
- ctrl->link->link_params.num_lanes, pixel_rate);
+ drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d\n",
+ ctrl->link->link_params.rate,
+ ctrl->link->link_params.num_lanes);
drm_dbg_dp(ctrl->drm_dev,
- "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
- ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
+ "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
+ ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on);
if (!ctrl->link_clks_on) { /* link clk is off */
ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl);
if (ret) {
DRM_ERROR("Failed to start link clocks. ret=%d\n", ret);
- goto end;
+ return ret;
}
}
+ if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
+ msm_dp_ctrl_link_retrain(ctrl);
+
+ /* stop txing train pattern to end link training */
+ msm_dp_ctrl_clear_training_pattern(ctrl);
+
+ return ret;
+}
+
+int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl)
+{
+ int ret = 0;
+ bool mainlink_ready = false;
+ struct msm_dp_ctrl_private *ctrl;
+ unsigned long pixel_rate;
+ unsigned long pixel_rate_orig;
+
+ if (!msm_dp_ctrl)
+ return -EINVAL;
+
+ ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
+
+ pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock;
+
+ if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420)
+ pixel_rate >>= 1;
+
+ drm_dbg_dp(ctrl->drm_dev, "pixel_rate=%lu\n", pixel_rate);
+
ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000);
if (ret) {
DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret);
@@ -1992,12 +2013,6 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
ctrl->stream_clks_on = true;
}
- if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl))
- msm_dp_ctrl_link_retrain(ctrl);
-
- /* stop txing train pattern to end link training */
- msm_dp_ctrl_clear_training_pattern(ctrl);
-
/*
* Set up transfer unit values and set controller state to send
* video.
@@ -18,7 +18,8 @@ struct msm_dp_ctrl {
struct phy;
int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl);
-int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train);
+int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl);
+int msm_dp_ctrl_prepare_stream_on(struct msm_dp_ctrl *dp_ctrl, bool force_link_train);
void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl);
@@ -811,7 +811,37 @@ static int msm_dp_display_set_mode(struct msm_dp *msm_dp_display,
return 0;
}
-static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_link_train)
+static int msm_dp_display_prepare(struct msm_dp_display_private *dp)
+{
+ int rc = 0;
+ struct msm_dp *msm_dp_display = &dp->msm_dp_display;
+ bool force_link_train = false;
+
+ drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count);
+ if (msm_dp_display->prepared) {
+ drm_dbg_dp(dp->drm_dev, "Link already setup, return\n");
+ return 0;
+ }
+
+ rc = pm_runtime_resume_and_get(&msm_dp_display->pdev->dev);
+ if (rc) {
+ DRM_ERROR("failed to pm_runtime_resume\n");
+ return rc;
+ }
+
+ if (dp->hpd_state == ST_CONNECTED && !msm_dp_display->power_on) {
+ msm_dp_display_host_phy_init(dp);
+ force_link_train = true;
+ }
+
+ rc = msm_dp_ctrl_prepare_stream_on(dp->ctrl, force_link_train);
+ if (!rc)
+ msm_dp_display->prepared = true;
+
+ return rc;
+}
+
+static int msm_dp_display_enable(struct msm_dp_display_private *dp)
{
int rc = 0;
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
@@ -822,7 +852,7 @@ static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_l
return 0;
}
- rc = msm_dp_ctrl_on_stream(dp->ctrl, force_link_train);
+ rc = msm_dp_ctrl_on_stream(dp->ctrl);
if (!rc)
msm_dp_display->power_on = true;
@@ -852,13 +882,10 @@ static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display)
return 0;
}
-static int msm_dp_display_disable(struct msm_dp_display_private *dp)
+static void msm_dp_display_audio_notify_disable(struct msm_dp_display_private *dp)
{
struct msm_dp *msm_dp_display = &dp->msm_dp_display;
- if (!msm_dp_display->power_on)
- return 0;
-
/* wait only if audio was enabled */
if (msm_dp_display->audio_enabled) {
/* signal the disconnect event */
@@ -869,6 +896,14 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
}
msm_dp_display->audio_enabled = false;
+}
+
+static int msm_dp_display_disable(struct msm_dp_display_private *dp)
+{
+ struct msm_dp *msm_dp_display = &dp->msm_dp_display;
+
+ if (!msm_dp_display->power_on)
+ return 0;
if (dp->link->sink_count == 0) {
/*
@@ -1498,9 +1533,8 @@ void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int rc = 0;
+
struct msm_dp_display_private *msm_dp_display;
- u32 state;
- bool force_link_train = false;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
@@ -1508,25 +1542,23 @@ void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
msm_dp_hpd_plug_handle(msm_dp_display, 0);
mutex_lock(&msm_dp_display->event_mutex);
- if (pm_runtime_resume_and_get(&dp->pdev->dev)) {
- DRM_ERROR("failed to pm_runtime_resume\n");
+
+ rc = msm_dp_display_prepare(msm_dp_display);
+ if (rc) {
+ DRM_ERROR("DP display prepare failed, rc=%d\n", rc);
mutex_unlock(&msm_dp_display->event_mutex);
return;
}
- state = msm_dp_display->hpd_state;
-
- if (state == ST_CONNECTED && !dp->power_on) {
- msm_dp_display_host_phy_init(msm_dp_display);
- force_link_train = true;
- }
-
- msm_dp_display_enable(msm_dp_display, force_link_train);
-
- rc = msm_dp_display_post_enable(dp);
- if (rc) {
- DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
- msm_dp_display_disable(msm_dp_display);
+ if (dp->prepared) {
+ rc = msm_dp_display_enable(msm_dp_display);
+ if (rc)
+ DRM_ERROR("DP display enable failed, rc=%d\n", rc);
+ rc = msm_dp_display_post_enable(dp);
+ if (rc) {
+ DRM_ERROR("DP display post enable failed, rc=%d\n", rc);
+ msm_dp_display_disable(msm_dp_display);
+ }
}
/* completed connection */
@@ -1548,6 +1580,20 @@ void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
msm_dp_ctrl_push_idle(msm_dp_display->ctrl);
}
+static void msm_dp_display_unprepare(struct msm_dp_display_private *dp)
+{
+ struct msm_dp *msm_dp_display = &dp->msm_dp_display;
+
+ if (!msm_dp_display->prepared) {
+ drm_dbg_dp(dp->drm_dev, "Link already setup, return\n");
+ return;
+ }
+
+ pm_runtime_put_sync(&msm_dp_display->pdev->dev);
+
+ msm_dp_display->prepared = false;
+}
+
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
struct drm_bridge_state *old_bridge_state)
{
@@ -1568,6 +1614,8 @@ void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n",
dp->connector_type, state);
+ msm_dp_display_audio_notify_disable(msm_dp_display);
+
msm_dp_display_disable(msm_dp_display);
state = msm_dp_display->hpd_state;
@@ -1576,9 +1624,10 @@ void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
msm_dp_display->hpd_state = ST_DISCONNECTED;
}
+ msm_dp_display_unprepare(msm_dp_display);
+
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
- pm_runtime_put_sync(&dp->pdev->dev);
mutex_unlock(&msm_dp_display->event_mutex);
}
@@ -21,6 +21,7 @@ struct msm_dp {
bool link_ready;
bool audio_enabled;
bool power_on;
+ bool prepared;
unsigned int connector_type;
bool is_edp;
bool internal_hpd;
dp_display_enable() currently re-trains the link if needed and then enables the pixel clock, programs the controller to start sending the pixel stream. Break up these two parts into separate APIs to distinguish these two parts better. Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com> --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 57 ++++++++++++++-------- drivers/gpu/drm/msm/dp/dp_ctrl.h | 3 +- drivers/gpu/drm/msm/dp/dp_display.c | 97 ++++++++++++++++++++++++++++--------- drivers/gpu/drm/msm/dp/dp_display.h | 1 + 4 files changed, 112 insertions(+), 46 deletions(-)