From c348cb858aa5df45490c992ec89f6fbbaac6ec9d Mon Sep 17 00:00:00 2001 From: Fuad Hossain Date: Wed, 11 Sep 2019 18:30:40 -0400 Subject: [PATCH] drm: msm: dp: Fix DSC and FEC handling Ensure that the driver is handling DSC and FEC enablement properly. FEC can now be independently enabled without DSC. FEC configuration is also now performed after link training in order to avoid link training failures as per the DP spec. Consequently, DSC can now be left on during compliance testing. For DSC use-cases, ensure that the minimum supported bpp is set to 24, as required by the DSC spec. CRs-Fixed: 2517994 Change-Id: I40339585da5b4e51251a3be7119b6959954954d7 Signed-off-by: Fuad Hossain --- msm/dp/dp_ctrl.c | 29 ++++++++++------- msm/dp/dp_ctrl.h | 2 +- msm/dp/dp_display.c | 5 +-- msm/dp/dp_panel.c | 76 +++++++++++++++++++++++++++------------------ 4 files changed, 68 insertions(+), 44 deletions(-) diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index e0a8d1e3fe..d12ba53681 100644 --- a/msm/dp/dp_ctrl.c +++ b/msm/dp/dp_ctrl.c @@ -69,6 +69,7 @@ struct dp_ctrl_private { bool power_on; bool mst_mode; bool fec_mode; + bool dsc_mode; atomic_t aborted; @@ -575,7 +576,6 @@ end: static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl) { int ret = 0; - const unsigned int fec_cfg_dpcd = 0x120; if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) goto end; @@ -588,7 +588,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl) ctrl->catalog->reset(ctrl->catalog); if (ctrl->fec_mode) - drm_dp_dpcd_writeb(ctrl->aux->drm_aux, fec_cfg_dpcd, 0x01); + drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_FEC_CONFIGURATION, + 0x01); ret = dp_ctrl_link_train(ctrl); @@ -926,7 +927,7 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg); ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode, - ctrl->fec_mode, false); + ctrl->fec_mode, ctrl->dsc_mode, false); if (ret) DP_ERR("failed to enable DP controller\n"); @@ -1138,19 +1139,18 @@ static void dp_ctrl_fec_dsc_setup(struct dp_ctrl_private *ctrl) u8 fec_sts = 0; int rlen; u32 dsc_enable; - const unsigned int fec_sts_dpcd = 0x280; - if (ctrl->stream_count || !ctrl->fec_mode) + if (!ctrl->fec_mode) return; ctrl->catalog->fec_config(ctrl->catalog, ctrl->fec_mode); /* wait for controller to start fec sequence */ usleep_range(900, 1000); - drm_dp_dpcd_readb(ctrl->aux->drm_aux, fec_sts_dpcd, &fec_sts); + drm_dp_dpcd_readb(ctrl->aux->drm_aux, DP_FEC_STATUS, &fec_sts); DP_DEBUG("sink fec status:%d\n", fec_sts); - dsc_enable = ctrl->fec_mode ? 1 : 0; + dsc_enable = ctrl->dsc_mode ? 1 : 0; rlen = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_DSC_ENABLE, dsc_enable); if (rlen < 1) @@ -1191,13 +1191,14 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) dp_ctrl_wait4video_ready(ctrl); - dp_ctrl_fec_dsc_setup(ctrl); - ctrl->stream_count++; link_ready = ctrl->catalog->mainlink_ready(ctrl->catalog); DP_DEBUG("mainlink %s\n", link_ready ? "READY" : "NOT READY"); + /* wait for link training completion before fec config as per spec */ + dp_ctrl_fec_dsc_setup(ctrl); + return rc; } @@ -1266,7 +1267,7 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) } static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, - bool fec_mode, bool shallow) + bool fec_mode, bool dsc_mode, bool shallow) { int rc = 0; struct dp_ctrl_private *ctrl; @@ -1285,7 +1286,11 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, goto end; ctrl->mst_mode = mst_mode; - ctrl->fec_mode = fec_mode; + if (fec_mode) { + ctrl->fec_mode = fec_mode; + ctrl->dsc_mode = dsc_mode; + } + rate = ctrl->panel->link_info.rate; if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { @@ -1323,6 +1328,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) if (!ctrl->power_on) return; + ctrl->catalog->fec_config(ctrl->catalog, false); dp_ctrl_configure_source_link_params(ctrl, false); ctrl->catalog->reset(ctrl->catalog); @@ -1333,6 +1339,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) ctrl->mst_mode = false; ctrl->fec_mode = false; + ctrl->dsc_mode = false; ctrl->power_on = false; memset(&ctrl->mst_ch_info, 0, sizeof(ctrl->mst_ch_info)); DP_DEBUG("DP off done\n"); diff --git a/msm/dp/dp_ctrl.h b/msm/dp/dp_ctrl.h index 0f855efb89..ac6af632a3 100644 --- a/msm/dp/dp_ctrl.h +++ b/msm/dp/dp_ctrl.h @@ -17,7 +17,7 @@ struct dp_ctrl { int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset); void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en, - bool shallow); + bool dsc_en, bool shallow); void (*off)(struct dp_ctrl *dp_ctrl); void (*abort)(struct dp_ctrl *dp_ctrl); void (*isr)(struct dp_ctrl *dp_ctrl); diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index fc35275076..f24341f113 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -884,7 +884,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp_display_process_mst_hpd_high(dp, false); rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, - dp->panel->fec_en, false); + dp->panel->fec_en, dp->panel->dsc_en, false); if (rc) { dp_display_state_remove(DP_STATE_CONNECTED); goto end; @@ -1665,7 +1665,8 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) * So, we execute in shallow mode here to do only minimal * and required things. */ - rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, true); + rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, + dp_panel->dsc_en, true); if (rc) goto end; diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 2f6d8d9468..a4a2a735ce 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -2019,14 +2019,7 @@ end: static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel) { - s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1); - - if (!dp_panel->dsc_feature_enable || !dp_panel->fec_feature_enable) { - DP_DEBUG("source dsc is not supported\n"); - return; - } - - if (dp_panel->dsc_dpcd[0] && dp_panel->fec_dpcd) { + if (dp_panel->dsc_dpcd[0]) { dp_panel->sink_dsc_caps.dsc_capable = true; dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1]; dp_panel->sink_dsc_caps.block_pred_en = @@ -2039,21 +2032,13 @@ static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel) dp_panel->dsc_en = false; } - dp_panel->fec_en = dp_panel->dsc_en; dp_panel->widebus_en = dp_panel->dsc_en; - - /* fec_overhead = 1.00 / 0.97582 */ - if (dp_panel->fec_en) - fec_overhead_fp = drm_fixp_from_fraction(100000, 97582); - - dp_panel->fec_overhead_fp = fec_overhead_fp; } static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) { int rlen; struct dp_panel_private *panel; - const int fec_cap = 0x90; int dpcd_rev; if (!dp_panel) { @@ -2061,14 +2046,9 @@ static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) return; } - dp_panel->dsc_en = false; - dp_panel->fec_en = false; - dpcd_rev = dp_panel->dpcd[DP_DPCD_REV]; panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - dp_panel->fec_overhead_fp = 0; if (panel->parser->dsc_feature_enable && dpcd_rev >= 0x14) { rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DSC_SUPPORT, dp_panel->dsc_dpcd, (DP_RECEIVER_DSC_CAP_SIZE + 1)); @@ -2081,17 +2061,38 @@ static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, false); - rlen = drm_dp_dpcd_read(panel->aux->drm_aux, fec_cap, - &dp_panel->fec_dpcd, 1); - if (rlen < 1) { - DP_ERR("fec dpcd read failed, rlen=%d\n", rlen); - return; - } - dp_panel_decode_dsc_dpcd(dp_panel); } } +static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1); + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + rlen = drm_dp_dpcd_readb(panel->aux->drm_aux, DP_FEC_CAPABILITY, + &dp_panel->fec_dpcd); + if (rlen < 1) { + DP_ERR("fec capability read failed, rlen=%d\n", rlen); + return; + } + + dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE; + if (dp_panel->fec_en) + fec_overhead_fp = drm_fixp_from_fraction(100000, 97582); + + dp_panel->fec_overhead_fp = fec_overhead_fp; + + return; +} + static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, struct drm_connector *connector, bool multi_func) { @@ -2148,7 +2149,18 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable; dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; - dp_panel_read_sink_dsc_caps(dp_panel); + dp_panel->fec_en = false; + dp_panel->dsc_en = false; + + if (dp_panel->fec_feature_enable) { + dp_panel_read_sink_fec_caps(dp_panel); + + if (dp_panel->dsc_feature_enable && dp_panel->fec_en) + dp_panel_read_sink_dsc_caps(dp_panel); + } + + DP_INFO("fec_en=%d, dsc_en=%d, widebus_en=%d\n", dp_panel->fec_en, + dp_panel->dsc_en, dp_panel->widebus_en); end: return rc; } @@ -2157,9 +2169,13 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, u32 mode_edid_bpp, u32 mode_pclk_khz) { struct drm_dp_link *link_info; - const u32 max_supported_bpp = 30, min_supported_bpp = 18; + const u32 max_supported_bpp = 30; + u32 min_supported_bpp = 18; u32 bpp = 0, data_rate_khz = 0; + if (dp_panel->dsc_en) + min_supported_bpp = 24; + bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); link_info = &dp_panel->link_info;