[Intel-gfx] [PATCH 2/5] drm/i915: get mode clock when reading the pipe config v7
Daniel Vetter
daniel at ffwll.ch
Wed Jun 26 13:37:18 CEST 2013
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
More information about the Intel-gfx
mailing list