diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_hdmi.c | 104 |
1 files changed, 58 insertions, 46 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 4a1b2d863b0c..7e51c98c475e 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -1865,28 +1865,69 @@ static int intel_hdmi_port_clock(int clock, int bpc) return clock * bpc / 8; } +static bool intel_hdmi_bpc_possible(struct drm_connector *connector, + int bpc, bool has_hdmi_sink, bool ycbcr420_output) +{ + struct drm_i915_private *i915 = to_i915(connector->dev); + const struct drm_display_info *info = &connector->display_info; + const struct drm_hdmi_info *hdmi = &info->hdmi; + + switch (bpc) { + case 12: + if (HAS_GMCH(i915)) + return false; + + if (!has_hdmi_sink) + return false; + + if (ycbcr420_output) + return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; + else + return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36; + case 10: + if (DISPLAY_VER(i915) < 11) + return false; + + if (!has_hdmi_sink) + return false; + + if (ycbcr420_output) + return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; + else + return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30; + case 8: + return true; + default: + MISSING_CASE(bpc); + return false; + } +} + static enum drm_mode_status -intel_hdmi_mode_clock_valid(struct intel_hdmi *hdmi, int clock, bool has_hdmi_sink) +intel_hdmi_mode_clock_valid(struct drm_connector *connector, int clock, + bool has_hdmi_sink, bool ycbcr420_output) { - struct drm_device *dev = intel_hdmi_to_dev(hdmi); - struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_hdmi *hdmi = intel_attached_hdmi(to_intel_connector(connector)); enum drm_mode_status status; + if (ycbcr420_output) + clock /= 2; + /* check if we can do 8bpc */ status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 8), true, has_hdmi_sink); - if (has_hdmi_sink) { - /* if we can't do 8bpc we may still be able to do 12bpc */ - if (status != MODE_OK && !HAS_GMCH(dev_priv)) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 12), - true, has_hdmi_sink); + /* if we can't do 8bpc we may still be able to do 12bpc */ + if (status != MODE_OK && + intel_hdmi_bpc_possible(connector, 12, has_hdmi_sink, ycbcr420_output)) + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 12), + true, has_hdmi_sink); - /* if we can't do 8,12bpc we may still be able to do 10bpc */ - if (status != MODE_OK && DISPLAY_VER(dev_priv) >= 11) - status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 10), - true, has_hdmi_sink); - } + /* if we can't do 8,12bpc we may still be able to do 10bpc */ + if (status != MODE_OK && + intel_hdmi_bpc_possible(connector, 10, has_hdmi_sink, ycbcr420_output)) + status = hdmi_port_clock_valid(hdmi, intel_hdmi_port_clock(clock, 10), + true, has_hdmi_sink); return status; } @@ -1920,18 +1961,15 @@ intel_hdmi_mode_valid(struct drm_connector *connector, } ycbcr_420_only = drm_mode_is_420_only(&connector->display_info, mode); - if (ycbcr_420_only) - clock /= 2; - status = intel_hdmi_mode_clock_valid(hdmi, clock, has_hdmi_sink); + status = intel_hdmi_mode_clock_valid(connector, clock, has_hdmi_sink, ycbcr_420_only); if (status != MODE_OK) { if (ycbcr_420_only || !connector->ycbcr_420_allowed || !drm_mode_is_420_also(&connector->display_info, mode)) return status; - clock /= 2; - status = intel_hdmi_mode_clock_valid(hdmi, clock, has_hdmi_sink); + status = intel_hdmi_mode_clock_valid(connector, clock, has_hdmi_sink, true); if (status != MODE_OK) return status; } @@ -1950,32 +1988,12 @@ bool intel_hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, if (crtc_state->pipe_bpp < bpc * 3) return false; - if (!has_hdmi_sink) - return false; - for_each_new_connector_in_state(state, connector, connector_state, i) { - const struct drm_display_info *info = &connector->display_info; - if (connector_state->crtc != crtc_state->uapi.crtc) continue; - if (ycbcr420_output) { - const struct drm_hdmi_info *hdmi = &info->hdmi; - - if (bpc == 12 && !(hdmi->y420_dc_modes & - DRM_EDID_YCBCR420_DC_36)) - return false; - else if (bpc == 10 && !(hdmi->y420_dc_modes & - DRM_EDID_YCBCR420_DC_30)) - return false; - } else { - if (bpc == 12 && !(info->edid_hdmi_dc_modes & - DRM_EDID_HDMI_DC_36)) - return false; - else if (bpc == 10 && !(info->edid_hdmi_dc_modes & - DRM_EDID_HDMI_DC_30)) - return false; - } + if (!intel_hdmi_bpc_possible(connector, bpc, has_hdmi_sink, ycbcr420_output)) + return false; } return true; @@ -1989,12 +2007,6 @@ static bool hdmi_deep_color_possible(const struct intel_crtc_state *crtc_state, const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; - if (HAS_GMCH(dev_priv)) - return false; - - if (bpc == 10 && DISPLAY_VER(dev_priv) < 11) - return false; - /* * HDMI deep color affects the clocks, so it's only possible * when not cloning with other encoder types. |