On Wed, Jun 26, 2013 at 01:38:16AM +0300, Jesse Barnes wrote: > We need this for comparing modes between configuration changes. > > v2: try harder to calulate non-simple pixel clocks (Daniel) > call get_clock after getting the encoder config, needed for pixel multiply > (Jesse) > v3: drop get_clock now that the pixel_multiply has been moved into > get_pipe_config > v4: re-add get_clock; we need to get the pixel multiplier in the > encoder, so need to calculate the clock value after the encoder's > get_config is called > v5: drop hsw clock_get, still needs to be written > v6: add fuzzy clock check (Daniel) > v7: wrap fuzzy clock check under !IS_HASWELL > use port_clock field rather than a new CPU eDP clock field in crtc_config > > Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org> You have some random pixel_multiplier = 1 assignments lingering around, those should all go away on top of latest dinq. And with the patch I've just posted we'll even have correct pixel multiplier read-out support on pch-split platforms. Second issue is that the pixel multiplier for the i9xx dotclock reconstruction code looks wrong, it doesn't seem to take it into account at all. -Daniel > --- > drivers/gpu/drm/i915/i915_drv.h | 1 + > drivers/gpu/drm/i915/intel_crt.c | 1 + > drivers/gpu/drm/i915/intel_display.c | 109 +++++++++++++++++++++++++++++++--- > drivers/gpu/drm/i915/intel_dp.c | 8 +++ > drivers/gpu/drm/i915/intel_dvo.c | 1 + > drivers/gpu/drm/i915/intel_hdmi.c | 1 + > drivers/gpu/drm/i915/intel_lvds.c | 1 + > drivers/gpu/drm/i915/intel_sdvo.c | 5 ++ > 8 files changed, 120 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 4bbff22..a9886a5 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -364,6 +364,7 @@ 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/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c > index 3acec8c..765a224 100644 > --- a/drivers/gpu/drm/i915/intel_crt.c > +++ b/drivers/gpu/drm/i915/intel_crt.c > @@ -104,6 +104,7 @@ static void intel_crt_get_config(struct intel_encoder *encoder, > flags |= DRM_MODE_FLAG_NVSYNC; > > pipe_config->adjusted_mode.flags |= flags; > + pipe_config->pixel_multiplier = 1; > } > > /* 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 8f746d9..e75ce2f 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -45,6 +45,11 @@ bool intel_pipe_has_type(struct drm_crtc *crtc, int type); > static void intel_increase_pllclock(struct drm_crtc *crtc); > static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); > > +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, > + struct intel_crtc_config *pipe_config); > +static void ironlake_crtc_clock_get(struct intel_crtc *crtc, > + struct intel_crtc_config *pipe_config); > + > typedef struct { > int min, max; > } intel_range_t; > @@ -6877,11 +6882,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, > } > > /* Returns the clock of the currently programmed mode of the given pipe. */ > -static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) > +static void i9xx_crtc_clock_get(struct intel_crtc *crtc, > + struct intel_crtc_config *pipe_config) > { > + struct drm_device *dev = crtc->base.dev; > struct drm_i915_private *dev_priv = dev->dev_private; > - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > - int pipe = intel_crtc->pipe; > + int pipe = pipe_config->cpu_transcoder; > u32 dpll = I915_READ(DPLL(pipe)); > u32 fp; > intel_clock_t clock; > @@ -6920,7 +6926,8 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) > default: > DRM_DEBUG_KMS("Unknown DPLL mode %08x in programmed " > "mode\n", (int)(dpll & DPLL_MODE_MASK)); > - return 0; > + pipe_config->adjusted_mode.clock = 0; > + return; > } > > if (IS_PINEVIEW(dev)) > @@ -6961,8 +6968,54 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) > * i830PllIsValid() because it relies on the xf86_config connector > * configuration being accurate, which it isn't necessarily. > */ > + pipe_config->adjusted_mode.clock = clock.dot; > +} > + > +static void ironlake_crtc_clock_get(struct intel_crtc *crtc, > + struct intel_crtc_config *pipe_config) > +{ > + struct drm_device *dev = crtc->base.dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + enum transcoder cpu_transcoder = pipe_config->cpu_transcoder; > + int link_freq, repeat; > + u64 clock; > + u32 link_m, link_n; > + > + repeat = pipe_config->pixel_multiplier; > + > + /* > + * The calculation for the data clock is: > + * pixel_clock = ((m/n)*(link_clock * nr_lanes * repeat))/bpp > + * But we want to avoid losing precison if possible, so: > + * pixel_clock = ((m * link_clock * nr_lanes * repeat)/(n*bpp)) > + * > + * and the link clock is simpler: > + * link_clock = (m * link_clock * repeat) / n > + */ > + > + /* > + * We need to get the FDI or DP link clock here to derive > + * the M/N dividers. > + * > + * For FDI, we read it from the BIOS or use a fixed 2.7GHz. > + * For DP, it's either 1.62GHz or 2.7GHz. > + * We do our calculations in 10*MHz since we don't need much precison. > + */ > + if (pipe_config->has_pch_encoder) > + link_freq = intel_fdi_link_freq(dev) * 10000; > + else > + link_freq = pipe_config->port_clock; > + > + link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder)); > + link_n = I915_READ(PIPE_LINK_N1(cpu_transcoder)); > > - return clock.dot; > + if (!link_m || !link_n) > + return; > + > + clock = ((u64)link_m * (u64)link_freq * (u64)repeat); > + do_div(clock, link_n); > + > + pipe_config->adjusted_mode.clock = clock; > } > > /** Returns the currently programmed mode of the given pipe. */ > @@ -6973,6 +7026,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, > struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; > struct drm_display_mode *mode; > + struct intel_crtc_config pipe_config; > int htot = I915_READ(HTOTAL(cpu_transcoder)); > int hsync = I915_READ(HSYNC(cpu_transcoder)); > int vtot = I915_READ(VTOTAL(cpu_transcoder)); > @@ -6982,7 +7036,10 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, > if (!mode) > return NULL; > > - mode->clock = intel_crtc_clock_get(dev, crtc); > + pipe_config.cpu_transcoder = intel_crtc->pipe; > + i9xx_crtc_clock_get(intel_crtc, &pipe_config); > + > + mode->clock = pipe_config.adjusted_mode.clock; > mode->hdisplay = (htot & 0xffff) + 1; > mode->htotal = ((htot & 0xffff0000) >> 16) + 1; > mode->hsync_start = (hsync & 0xffff) + 1; > @@ -8043,6 +8100,28 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) > > } > > +static bool intel_fuzzy_clock_check(struct intel_crtc_config *cur, > + struct intel_crtc_config *new) > +{ > + int clock1, clock2, diff; > + > + clock1 = cur->adjusted_mode.clock; > + clock2 = new->adjusted_mode.clock; > + > + if (clock1 == clock2) > + return true; > + > + if (!clock1 || !clock2) > + return false; > + > + diff = abs(clock1 - clock2); > + > + if (((((diff + clock1 + clock2) * 100)) / (clock1 + clock2)) < 105) > + return true; > + > + return false; > +} > + > #define for_each_intel_crtc_masked(dev, mask, intel_crtc) \ > list_for_each_entry((intel_crtc), \ > &(dev)->mode_config.crtc_list, \ > @@ -8148,6 +8227,15 @@ intel_pipe_config_compare(struct drm_device *dev, > #undef PIPE_CONF_CHECK_FLAGS > #undef PIPE_CONF_QUIRK > > + if (!IS_HASWELL(dev)) { > + if (!intel_fuzzy_clock_check(current_config, pipe_config)) { > + DRM_ERROR("mismatch in clock (expected %d, found %d\n", > + current_config->adjusted_mode.clock, > + pipe_config->adjusted_mode.clock); > + return false; > + } > + } > + > return true; > } > > @@ -9243,6 +9331,7 @@ 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; > @@ -9250,6 +9339,7 @@ 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; > @@ -9257,6 +9347,7 @@ 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; > @@ -9806,8 +9897,12 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) > if (encoder->get_hw_state(encoder, &pipe)) { > crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); > encoder->base.crtc = &crtc->base; > - if (encoder->get_config) > + if (encoder->get_config && > + dev_priv->display.get_clock) { > encoder->get_config(encoder, &crtc->config); > + dev_priv->display.get_clock(crtc, > + &crtc->config); > + } > } else { > encoder->base.crtc = NULL; > } > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > index 8708a0c..ea0655e 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -1340,6 +1340,14 @@ static void intel_dp_get_config(struct intel_encoder *encoder, > flags |= DRM_MODE_FLAG_NVSYNC; > > pipe_config->adjusted_mode.flags |= flags; > + pipe_config->pixel_multiplier = 1; > + > + if (dp_to_dig_port(intel_dp)->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; > + } > } > > static void intel_disable_dp(struct intel_encoder *encoder) > diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c > index eb2020e..21bcffd 100644 > --- a/drivers/gpu/drm/i915/intel_dvo.c > +++ b/drivers/gpu/drm/i915/intel_dvo.c > @@ -154,6 +154,7 @@ static void intel_dvo_get_config(struct intel_encoder *encoder, > flags |= DRM_MODE_FLAG_NVSYNC; > > pipe_config->adjusted_mode.flags |= flags; > + pipe_config->pixel_multiplier = 1; > } > > 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 bc12518..ff69a9e 100644 > --- a/drivers/gpu/drm/i915/intel_hdmi.c > +++ b/drivers/gpu/drm/i915/intel_hdmi.c > @@ -678,6 +678,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, > flags |= DRM_MODE_FLAG_NVSYNC; > > pipe_config->adjusted_mode.flags |= flags; > + pipe_config->pixel_multiplier = 1; > } > > 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 eeff28e..4d7b74e 100644 > --- a/drivers/gpu/drm/i915/intel_lvds.c > +++ b/drivers/gpu/drm/i915/intel_lvds.c > @@ -109,6 +109,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, > flags |= DRM_MODE_FLAG_PVSYNC; > > pipe_config->adjusted_mode.flags |= flags; > + pipe_config->pixel_multiplier = 1; > } > > /* 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 b8e1623..e9dbe74 100644 > --- a/drivers/gpu/drm/i915/intel_sdvo.c > +++ b/drivers/gpu/drm/i915/intel_sdvo.c > @@ -780,6 +780,11 @@ static bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val > return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); > } > > +static bool intel_sdvo_get_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 *val) > +{ > + return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1); > +} > + > static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, > const struct drm_display_mode *mode) > { > -- > 1.7.9.5 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch