@@ -1078,6 +1078,27 @@ void msm_dp_catalog_panel_disable_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog)
msm_dp_catalog_panel_update_sdp(msm_dp_catalog);
}
+void msm_dp_catalog_trigger_act(struct msm_dp_catalog *msm_dp_catalog)
+{
+ struct msm_dp_catalog_private *catalog;
+
+ catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog);
+
+ msm_dp_write_link(catalog, REG_DP_MST_ACT, 0x1);
+
+ /* make sure ACT signal is performed */
+ wmb();
+}
+
+bool msm_dp_catalog_read_act_complete_sts(struct msm_dp_catalog *msm_dp_catalog)
+{
+ struct msm_dp_catalog_private *catalog;
+
+ catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog);
+
+ return msm_dp_read_link(catalog, REG_DP_MST_ACT);
+}
+
void msm_dp_catalog_panel_tpg_enable(struct msm_dp_catalog *msm_dp_catalog,
struct drm_display_mode *drm_mode)
{
@@ -135,4 +135,8 @@ void msm_dp_catalog_audio_config_sdp(struct msm_dp_catalog *catalog);
void msm_dp_catalog_audio_init(struct msm_dp_catalog *catalog);
void msm_dp_catalog_audio_sfe_level(struct msm_dp_catalog *catalog, u32 safe_to_exit_level);
+/* DP MST APIs */
+void msm_dp_catalog_trigger_act(struct msm_dp_catalog *dp_catalog);
+bool msm_dp_catalog_read_act_complete_sts(struct msm_dp_catalog *dp_catalog);
+
#endif /* _DP_CATALOG_H_ */
@@ -97,6 +97,8 @@ struct msm_dp_ctrl_private {
bool core_clks_on;
bool link_clks_on;
+
+ bool mst_active;
bool stream_clks_on[DP_STREAM_MAX];
};
@@ -1625,6 +1627,26 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
return 0;
}
+int msm_dp_ctrl_mst_send_act(struct msm_dp_ctrl *msm_dp_ctrl)
+{
+ struct msm_dp_ctrl_private *ctrl;
+ bool act_complete;
+
+ ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
+
+ msm_dp_catalog_trigger_act(ctrl->catalog);
+ msleep(20); /* needs 1 frame time */
+
+ act_complete = msm_dp_catalog_read_act_complete_sts(ctrl->catalog);
+
+ if (!act_complete)
+ DRM_ERROR("mst ACT trigger complete SUCCESS\n");
+ else
+ drm_dbg_dp(ctrl->drm_dev, "mst ACT trigger complete failed\n");
+
+ return 0;
+}
+
static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
{
int ret = 0;
@@ -1643,6 +1665,9 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
+ if (ctrl->mst_active)
+ msm_dp_ctrl_mst_send_act(&ctrl->msm_dp_ctrl);
+
ret = msm_dp_ctrl_wait4video_ready(ctrl);
end:
return ret;
@@ -1745,7 +1770,7 @@ static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl
msm_dp_ctrl_stream_clk_off(&ctrl->msm_dp_ctrl, msm_dp_panel);
msm_dp_ctrl_off_link(&ctrl->msm_dp_ctrl);
- ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl);
+ ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl, ctrl->mst_active);
if (ret) {
DRM_ERROR("failed to enable DP link controller\n");
return ret;
@@ -1825,7 +1850,7 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
return drm_dp_channel_eq_ok(link_status, num_lanes);
}
-int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
+int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl, bool mst_active)
{
int rc = 0;
struct msm_dp_ctrl_private *ctrl;
@@ -1844,6 +1869,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
rate = ctrl->panel->link_info.rate;
pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock;
+ ctrl->mst_active = mst_active;
msm_dp_ctrl_core_clk_enable(&ctrl->msm_dp_ctrl);
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
@@ -2035,6 +2061,9 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
+ if (ctrl->mst_active)
+ msm_dp_ctrl_mst_send_act(msm_dp_ctrl);
+
ret = msm_dp_ctrl_wait4video_ready(ctrl);
if (ret)
return ret;
@@ -2104,6 +2133,8 @@ void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl)
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+ ctrl->mst_active = false;
+
dev_pm_opp_set_rate(ctrl->dev, 0);
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
@@ -2264,6 +2295,7 @@ struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link
ctrl->catalog = catalog;
ctrl->dev = dev;
ctrl->phy = phy;
+ ctrl->mst_active = false;
ret = msm_dp_ctrl_clk_init(&ctrl->msm_dp_ctrl);
if (ret) {
@@ -17,7 +17,7 @@ struct msm_dp_ctrl {
struct phy;
-int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl);
+int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl, bool mst_active);
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, struct msm_dp_panel *msm_dp_panel);
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);
@@ -46,5 +46,6 @@ void msm_dp_ctrl_clear_vsc_sdp_pkt(struct msm_dp_ctrl *msm_dp_ctrl,
struct msm_dp_panel *msm_dp_panel);
void msm_dp_ctrl_psm_config(struct msm_dp_ctrl *msm_dp_ctrl);
void msm_dp_ctrl_reinit_phy(struct msm_dp_ctrl *msm_dp_ctrl);
+int msm_dp_ctrl_mst_send_act(struct msm_dp_ctrl *ctrl);
#endif /* _DP_CTRL_H_ */
@@ -370,6 +370,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
struct drm_connector *connector = dp->msm_dp_display.connector;
const struct drm_display_info *info = &connector->display_info;
int rc = 0;
+ struct msm_dp *dp_display = &dp->msm_dp_display;
rc = msm_dp_panel_read_link_caps(dp->panel, connector);
if (rc)
@@ -399,7 +400,7 @@ static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
msm_dp_link_psm_config(dp->link, &dp->panel->link_info, false);
msm_dp_link_reset_phy_params_vx_px(dp->link);
- rc = msm_dp_ctrl_on_link(dp->ctrl);
+ rc = msm_dp_ctrl_on_link(dp->ctrl, dp_display->mst_active);
if (rc) {
DRM_ERROR("failed to complete DP link training\n");
goto end;
@@ -1628,6 +1629,9 @@ void msm_dp_display_atomic_disable(struct msm_dp *dp)
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
msm_dp_ctrl_push_idle(msm_dp_display->ctrl);
+
+ if (dp->mst_active)
+ msm_dp_ctrl_mst_send_act(msm_dp_display->ctrl);
}
static void msm_dp_display_unprepare(struct msm_dp_display_private *dp)
@@ -22,6 +22,7 @@ struct msm_dp {
bool audio_enabled;
bool power_on;
bool prepared;
+ bool mst_active;
unsigned int connector_type;
bool is_edp;
bool internal_hpd;
@@ -330,6 +330,9 @@
#define REG_DP_PHY_AUX_BIST_CFG (0x00000050)
#define REG_DP_PHY_AUX_INTERRUPT_STATUS (0x000000BC)
+/* DP MST related registers */
+#define REG_DP_MST_ACT (0x00000500)
+
/* DP HDCP 1.3 registers */
#define DP_HDCP_CTRL (0x0A0)
#define DP_HDCP_STATUS (0x0A4)
Whenever virtual channel slot allocation changes, the DP source must send the action control trigger sequence to notify the sink about the same. This would be applicable during the start and stop of the pixel stream. Add the infrastructure to be able to send ACT packets for the DP controller when operating in MST mode. Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com> --- drivers/gpu/drm/msm/dp/dp_catalog.c | 21 +++++++++++++++++++++ drivers/gpu/drm/msm/dp/dp_catalog.h | 4 ++++ drivers/gpu/drm/msm/dp/dp_ctrl.c | 36 ++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/msm/dp/dp_ctrl.h | 3 ++- drivers/gpu/drm/msm/dp/dp_display.c | 6 +++++- drivers/gpu/drm/msm/dp/dp_display.h | 1 + drivers/gpu/drm/msm/dp/dp_reg.h | 3 +++ 7 files changed, 70 insertions(+), 4 deletions(-)