From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> Now that adjusted_mode.clock no longer contains the pixel_multiplier, we can kill the get_clock() callback and instead do the clock readout in get_pipe_config(). Also i9xx_crtc_clock_get() can now extract the frequency of the PCH DPLL, so use it to populate port_clock accurately for PCH encoders. For DP in port A the encoder is still responsible for filling in port_clock. The FDI adjusted_mode.clock extraction is kept in place for some extra sanity checking, but we no longer need to pretend it's also the port_clock. In the encoder get_config() functions fill out adjusted_mode.clock based on port_clock and other details such as the DP M/N values, HDMI 12bpc and SDVO pixel_multiplier. For PCH encoders we will then do an extra sanity check to make sure the dotclock we derived from the FDI configuratiuon matches the one we derive from port_clock. DVO doesn't exist on PCH platforms, so it doesn't need to anything but assign adjusted_mode.clock=port_clock. And DDI is HSW only, so none of the changes apply there. v2: Use hdmi_reg color format to detect 12bpc HDMI case v3: Set adjusted_mode.clock for LVDS too Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_crt.c | 8 ++++++ drivers/gpu/drm/i915/intel_display.c | 47 ++++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_dp.c | 11 ++++++++- drivers/gpu/drm/i915/intel_drv.h | 2 ++ drivers/gpu/drm/i915/intel_dvo.c | 2 ++ drivers/gpu/drm/i915/intel_hdmi.c | 11 +++++++++ drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++ drivers/gpu/drm/i915/intel_sdvo.c | 8 ++++++ 10 files changed, 81 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 769c138..09fc308 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -369,7 +369,6 @@ struct drm_i915_display_funcs { * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, struct intel_crtc_config *); - void (*get_clock)(struct intel_crtc *, struct intel_crtc_config *); int (*crtc_mode_set)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c7f2da3..ace9443 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2071,6 +2071,7 @@ /* Gen 4 SDVO/HDMI bits: */ #define SDVO_COLOR_FORMAT_8bpc (0 << 26) +#define SDVO_COLOR_FORMAT_MASK (7 << 26) #define SDVO_ENCODING_SDVO (0 << 10) #define SDVO_ENCODING_HDMI (2 << 10) #define HDMI_MODE_SELECT_HDMI (1 << 9) /* HDMI only */ diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index ea9022e..be99cf2 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -89,6 +89,7 @@ static void intel_crt_get_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder); u32 tmp, flags = 0; + int dotclock; tmp = I915_READ(crt->adpa_reg); @@ -103,6 +104,13 @@ static void intel_crt_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; + + dotclock = pipe_config->port_clock; + + if (HAS_PCH_SPLIT(dev_priv->dev)) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.clock = dotclock; } /* Note: The caller is required to filter out dpms modes not supported by the diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4f07292..31478b7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5047,6 +5047,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, DPLL_PORTB_READY_MASK); } + i9xx_crtc_clock_get(crtc, pipe_config); + return true; } @@ -6007,6 +6009,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, pipe_config->pixel_multiplier = ((tmp & PLL_REF_SDVO_HDMI_MULTIPLIER_MASK) >> PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT) + 1; + + ironlake_crtc_clock_get(crtc, pipe_config); } else { pipe_config->pixel_multiplier = 1; } @@ -7416,7 +7420,12 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, i9xx_clock(refclk, &clock); } - pipe_config->adjusted_mode.clock = clock.dot; + /* + * This value includes pixel_multiplier. We will use + * port_clock to compute adjusted_mode.clock in the + * encoder's get_config() function. + */ + pipe_config->port_clock = clock.dot; } int intel_dotclock_calculate(int link_freq, @@ -7444,6 +7453,9 @@ static void ironlake_crtc_clock_get(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; int link_freq; + /* read out port_clock from the DPLL */ + i9xx_crtc_clock_get(crtc, pipe_config); + /* * We need to get the FDI or DP link clock here to derive * the M/N dividers. @@ -7454,6 +7466,12 @@ static void ironlake_crtc_clock_get(struct intel_crtc *crtc, */ link_freq = intel_fdi_link_freq(dev) * 10000; + /* + * This value does not include pixel_multiplier. + * We will check that port_clock and adjusted_mode.clock + * agree once we know their relationship in the encoder's + * get_config() function. + */ pipe_config->adjusted_mode.clock = intel_dotclock_calculate(link_freq, &pipe_config->fdi_m_n); } @@ -8867,9 +8885,6 @@ check_crtc_state(struct drm_device *dev) encoder->get_config(encoder, &pipe_config); } - if (dev_priv->display.get_clock) - dev_priv->display.get_clock(crtc, &pipe_config); - WARN(crtc->active != active, "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); @@ -8944,6 +8959,18 @@ intel_modeset_check_state(struct drm_device *dev) check_shared_dpll_state(dev); } +void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, + int dotclock) +{ + /* + * FDI already provided one idea for the dotclock. + * Yell if the encoder disagrees. + */ + WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.clock, dotclock), + "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", + pipe_config->adjusted_mode.clock, dotclock); +} + static int __intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb) @@ -9895,7 +9922,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (HAS_PCH_SPLIT(dev)) { dev_priv->display.get_pipe_config = ironlake_get_pipe_config; - dev_priv->display.get_clock = ironlake_crtc_clock_get; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; @@ -9903,7 +9929,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = ironlake_update_plane; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; - dev_priv->display.get_clock = i9xx_crtc_clock_get; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -9911,7 +9936,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = i9xx_update_plane; } else { dev_priv->display.get_pipe_config = i9xx_get_pipe_config; - dev_priv->display.get_clock = i9xx_crtc_clock_get; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; @@ -10525,15 +10549,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) pipe); } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, - base.head) { - if (!crtc->active) - continue; - if (dev_priv->display.get_clock) - dev_priv->display.get_clock(crtc, - &crtc->config); - } - list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) { if (connector->get_hw_state(connector)) { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index be0449b..509a9e4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1372,6 +1372,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; enum port port = dp_to_dig_port(intel_dp)->port; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + int dotclock; if ((port == PORT_A) || !HAS_PCH_CPT(dev)) { tmp = I915_READ(intel_dp->output_reg); @@ -1403,12 +1404,20 @@ static void intel_dp_get_config(struct intel_encoder *encoder, intel_dp_get_m_n(crtc, pipe_config); - if (dp_to_dig_port(intel_dp)->port == PORT_A) { + if (port == PORT_A) { if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ) pipe_config->port_clock = 162000; else pipe_config->port_clock = 270000; } + + dotclock = intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + + if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.clock = dotclock; } static bool is_edp_psr(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4cf8898..6e1204f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -805,5 +805,7 @@ extern void intel_dp_get_m_n(struct intel_crtc *crtc, struct intel_crtc_config *pipe_config); extern int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); +extern void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, + int dotclock); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 406303b..92487ce 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -153,6 +153,8 @@ static void intel_dvo_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; + + pipe_config->adjusted_mode.clock = pipe_config->port_clock; } static void intel_disable_dvo(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 4148cc8..16daa72 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -713,6 +713,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; u32 tmp, flags = 0; + int dotclock; tmp = I915_READ(intel_hdmi->hdmi_reg); @@ -727,6 +728,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; + + if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc) + dotclock = pipe_config->port_clock * 2 / 3; + else + dotclock = pipe_config->port_clock; + + if (HAS_PCH_SPLIT(dev_priv->dev)) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.clock = dotclock; } static void intel_enable_hdmi(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 831a5c0..05e5485 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -92,6 +92,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 lvds_reg, tmp, flags = 0; + int dotclock; if (HAS_PCH_SPLIT(dev)) lvds_reg = PCH_LVDS; @@ -116,6 +117,13 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE; } + + dotclock = pipe_config->port_clock; + + if (HAS_PCH_SPLIT(dev_priv->dev)) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.clock = dotclock; } /* The LVDS pin pair needs to be on before the DPLLs are enabled. diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 74042c6..7148fdd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1319,6 +1319,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo_dtd dtd; int encoder_pixel_multiplier = 0; + int dotclock; u32 flags = 0, sdvox; u8 val; bool ret; @@ -1357,6 +1358,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, >> SDVO_PORT_MULTIPLY_SHIFT) + 1; } + dotclock = pipe_config->port_clock / pipe_config->pixel_multiplier; + + if (HAS_PCH_SPLIT(dev)) + ironlake_check_encoder_dotclock(pipe_config, dotclock); + + pipe_config->adjusted_mode.clock = dotclock; + /* Cross check the port pixel multiplier with the sdvo encoder state. */ if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1)) { -- 1.8.1.5 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx