aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_hdmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_hdmi.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_hdmi.c104
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.