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 <fhossain@codeaurora.org>
This commit is contained in:
Fuad Hossain
2019-09-11 18:30:40 -04:00
parent 8babba1d11
commit c348cb858a
4 changed files with 68 additions and 44 deletions

View File

@@ -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;