Commit e64e739e authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Account for CHV/BXT DPLL clock limitations

CHV/BXT DPLL can't generate frequencies in the 216-240 MHz range.
Account for that when checking whether the HDMI port clock is valid.
This is particularly important for BXT since it can otherwise do
12bpc, and standard 1920x1080p60 CEA modes land right in the middle
of that range when the clock gets multiplied to account for 12bpc.

With the extra checks we will now filter out any mode where both
8bpc and 12bpc clock are within the gap. During modeset we then
pick whichever mode works, favoring 12bpc if both are possible.

12bpc isn't supported on CHV so we simply end up filtering out any
mode where the 8bpc port clock is in the gap.

v2: Fix crtc_clock vs. port_clock fumble in compute_config() (Imre)
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-and-tested-by: default avatarImre Deak <imre.deak@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 6fd765d0
...@@ -1151,7 +1151,7 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder) ...@@ -1151,7 +1151,7 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder)
intel_disable_hdmi(encoder); intel_disable_hdmi(encoder);
} }
static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
{ {
struct drm_device *dev = intel_hdmi_to_dev(hdmi); struct drm_device *dev = intel_hdmi_to_dev(hdmi);
...@@ -1163,25 +1163,49 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) ...@@ -1163,25 +1163,49 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
return 225000; return 225000;
} }
static enum drm_mode_status
hdmi_port_clock_valid(struct intel_hdmi *hdmi,
int clock, bool respect_dvi_limit)
{
struct drm_device *dev = intel_hdmi_to_dev(hdmi);
if (clock < 25000)
return MODE_CLOCK_LOW;
if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit))
return MODE_CLOCK_HIGH;
/* CHV/BXT DPLL can't generate 216-240 MHz */
if ((IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) &&
clock > 216000 && clock < 240000)
return MODE_CLOCK_RANGE;
return MODE_OK;
}
static enum drm_mode_status static enum drm_mode_status
intel_hdmi_mode_valid(struct drm_connector *connector, intel_hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
int clock = mode->clock; struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
struct drm_device *dev = intel_hdmi_to_dev(hdmi);
enum drm_mode_status status;
int clock;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
clock = mode->clock;
if (mode->flags & DRM_MODE_FLAG_DBLCLK) if (mode->flags & DRM_MODE_FLAG_DBLCLK)
clock *= 2; clock *= 2;
if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), /* check if we can do 8bpc */
true)) status = hdmi_port_clock_valid(hdmi, clock, true);
return MODE_CLOCK_HIGH;
if (clock < 25000)
return MODE_CLOCK_LOW;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) /* if we can't do 8bpc we may still be able to do 12bpc */
return MODE_NO_DBLESCAN; if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK)
status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true);
return MODE_OK; return status;
} }
static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
...@@ -1222,8 +1246,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1222,8 +1246,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2; int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); int clock_12bpc = clock_8bpc * 3 / 2;
int desired_bpp; int desired_bpp;
pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink;
...@@ -1242,6 +1266,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1242,6 +1266,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
pipe_config->pixel_multiplier = 2; pipe_config->pixel_multiplier = 2;
clock_8bpc *= 2;
clock_12bpc *= 2; clock_12bpc *= 2;
} }
...@@ -1261,7 +1286,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1261,7 +1286,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
* within limits. * within limits.
*/ */
if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
clock_12bpc <= portclock_limit && hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK &&
hdmi_12bpc_possible(pipe_config) && hdmi_12bpc_possible(pipe_config) &&
0 /* FIXME 12bpc support totally broken */) { 0 /* FIXME 12bpc support totally broken */) {
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
...@@ -1272,6 +1297,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1272,6 +1297,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
} else { } else {
DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
desired_bpp = 8*3; desired_bpp = 8*3;
pipe_config->port_clock = clock_8bpc;
} }
if (!pipe_config->bw_constrained) { if (!pipe_config->bw_constrained) {
...@@ -1279,8 +1306,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, ...@@ -1279,8 +1306,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
pipe_config->pipe_bpp = desired_bpp; pipe_config->pipe_bpp = desired_bpp;
} }
if (adjusted_mode->crtc_clock > portclock_limit) { if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); false) != MODE_OK) {
DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment