diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c index 2d65fc924f07..120a6defc868 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c @@ -125,6 +125,55 @@ static void sde_hdmi_clear_hdr_info(struct drm_bridge *bridge) connector->hdr_supported = false; } +static void sde_hdmi_clear_vsdb_info(struct drm_bridge *bridge) +{ + struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct drm_connector *connector = hdmi->connector; + + connector->max_tmds_clock = 0; + connector->latency_present[0] = false; + connector->latency_present[1] = false; + connector->video_latency[0] = false; + connector->video_latency[1] = false; + connector->audio_latency[0] = false; + connector->audio_latency[1] = false; +} + +static void sde_hdmi_clear_hf_vsdb_info(struct drm_bridge *bridge) +{ + struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct drm_connector *connector = hdmi->connector; + + connector->max_tmds_char = 0; + connector->scdc_present = false; + connector->rr_capable = false; + connector->supports_scramble = false; + connector->flags_3d = 0; +} + +static void sde_hdmi_clear_vcdb_info(struct drm_bridge *bridge) +{ + struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + struct drm_connector *connector = hdmi->connector; + + connector->pt_scan_info = 0; + connector->it_scan_info = 0; + connector->ce_scan_info = 0; + connector->rgb_qs = false; + connector->yuv_qs = false; +} + +static void sde_hdmi_clear_vsdbs(struct drm_bridge *bridge) +{ + /* Clear fields of HDMI VSDB */ + sde_hdmi_clear_vsdb_info(bridge); + /* Clear fields of HDMI forum VSDB */ + sde_hdmi_clear_hf_vsdb_info(bridge); +} + static int _sde_hdmi_bridge_power_on(struct drm_bridge *bridge) { struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); @@ -606,6 +655,12 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) mutex_lock(&display->display_lock); + if (!bridge) { + SDE_ERROR("Invalid params\n"); + mutex_unlock(&display->display_lock); + return; + } + display->pll_update_enable = false; display->sink_hdcp_ver = SDE_HDMI_HDCP_NONE; display->sink_hdcp22_support = false; @@ -614,6 +669,11 @@ static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge) sde_hdmi_hdcp_off(display); sde_hdmi_clear_hdr_info(bridge); + /* Clear HDMI VSDB blocks info */ + sde_hdmi_clear_vsdbs(bridge); + /* Clear HDMI VCDB block info */ + sde_hdmi_clear_vcdb_info(bridge); + mutex_unlock(&display->display_lock); } @@ -940,6 +1000,9 @@ static bool _sde_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge); struct hdmi *hdmi = sde_hdmi_bridge->hdmi; + /* Clear the private flags before assigning new one */ + adjusted_mode->private_flags = 0; + adjusted_mode->private_flags |= _sde_hdmi_choose_best_format(hdmi, adjusted_mode); SDE_DEBUG("Adjusted mode private flags: 0x%x\n", diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c index 50667c5921a0..043e439835f1 100644 --- a/drivers/gpu/drm/msm/sde_edid_parser.c +++ b/drivers/gpu/drm/msm/sde_edid_parser.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -252,12 +252,13 @@ static void sde_edid_parse_Y420CMDB( struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl, const u8 *db) { - u32 offset = 0; u8 cmdb_len = 0; u8 svd_len = 0; const u8 *svd = NULL; - u32 i = 0, j = 0; + u32 i = 0; u32 video_format = 0; + u32 num_cmdb_svd = 0; + const u32 mult = 8; if (!edid_ctrl) { DEV_ERR("%s: edid_ctrl is NULL\n", __func__); @@ -271,8 +272,8 @@ const u8 *db) SDE_EDID_DEBUG("%s +\n", __func__); cmdb_len = db[0] & 0x1f; - /* Byte 3 to L+1 contain SVDs */ - offset += 2; + if (cmdb_len < 1) + return; svd = sde_edid_find_block(edid_ctrl->edid, VIDEO_DATA_BLOCK); @@ -282,21 +283,26 @@ const u8 *db) ++svd; } - for (i = 0; i < svd_len; i++, j++) { - video_format = *(svd + i) & 0x7F; - if (cmdb_len == 1) { - /* If cmdb_len is 1, it means all SVDs support YUV */ - sde_edid_set_y420_support(connector, video_format); - } else if (db[offset] & (1 << j)) { - sde_edid_set_y420_support(connector, video_format); + if (cmdb_len == 1) + num_cmdb_svd = svd_len; + else { + num_cmdb_svd = (cmdb_len - 1) * mult; + if (num_cmdb_svd > svd_len) + num_cmdb_svd = svd_len; + } - if (j & 0x80) { - j = j/8; - offset++; - if (offset >= cmdb_len) - break; - } - } + for (i = 0; i < num_cmdb_svd; i++) { + video_format = *(svd + i) & 0x7F; + /* + * If cmdb_len is 1, it means all SVDs support YUV + * Else, we check each byte of the cmdb bitmap bitwise + * and match those bits with the formats populated + * during the parsing of the Video Data Blocks. + * Refer to CTA 861-F section 7.5.11 YCBCR 4:2:0 Capability + * Map Data Block for more details on this. + */ + if (cmdb_len == 1 || (db[2 + i / mult] & (1 << (i % mult)))) + sde_edid_set_y420_support(connector, video_format); } SDE_EDID_DEBUG("%s -\n", __func__);