> -----Original Message----- > From: intel-gfx- > bounces+vijay.a.purushothaman=intel.com at lists.freedesktop.org [mailto:intel- > gfx-bounces+vijay.a.purushothaman=intel.com at lists.freedesktop.org] On > Behalf Of Daniel Vetter > Sent: Wednesday, June 13, 2012 1:37 PM > To: Jesse Barnes > Cc: intel-gfx at lists.freedesktop.org > Subject: Re: [PATCH 1/7] drm/i915: ValleyView mode setting limits > and PLL functions > > On Tue, Jun 12, 2012 at 02:47:29PM -0700, Jesse Barnes wrote: > > Add some VLV limit structures and update the PLL code. > > > > v2: resolve conflicts, Vijay to re-post with PLL valid checks and > > fixed limits > > v3: re-add dpio write function > > > > Signed-off-by: Shobhit Kumar <shobhit.kumar at intel.com> > > Signed-off-by: Vijay Purushothaman <vijay.a.purushothaman at intel.com> > > Your sob-line is missing, and iirc a few people puked over that massively-nested > pll computation loop. I dunno what we've ultimately decided about it, though. > -Daniel > We decided to rework this patch once we have a platform to test. Just today I was able to bring up my system with a test bios version - Thanks to Jesse. I will post a cleaned up version of this patch soon. Thanks, Vijay > > --- > > drivers/gpu/drm/i915/i915_reg.h | 1 + > > drivers/gpu/drm/i915/intel_display.c | 250 > > +++++++++++++++++++++++++++++++++- > > 2 files changed, 249 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/i915_reg.h > > b/drivers/gpu/drm/i915/i915_reg.h index 7dcc04f..281446d 100644 > > --- a/drivers/gpu/drm/i915/i915_reg.h > > +++ b/drivers/gpu/drm/i915/i915_reg.h > > @@ -900,6 +900,7 @@ > > #define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ > > #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ > > #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* > Pineview */ > > +#define DPLL_LOCK_VLV (1<<15) > > #define DPLL_INTEGRATED_CLOCK_VLV (1<<13) > > > > #define SRX_INDEX 0x3c4 > > diff --git a/drivers/gpu/drm/i915/intel_display.c > > b/drivers/gpu/drm/i915/intel_display.c > > index 0161d94..5006928 100644 > > --- a/drivers/gpu/drm/i915/intel_display.c > > +++ b/drivers/gpu/drm/i915/intel_display.c > > @@ -98,6 +98,11 @@ intel_find_pll_ironlake_dp(const intel_limit_t *, struct > drm_crtc *crtc, > > int target, int refclk, intel_clock_t *match_clock, > > intel_clock_t *best_clock); > > > > +static bool > > +intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, > > + int target, int refclk, intel_clock_t *match_clock, > > + intel_clock_t *best_clock); > > + > > static inline u32 /* units of 100MHz */ intel_fdi_link_freq(struct > > drm_device *dev) { @@ -359,6 +364,48 @@ static const intel_limit_t > > intel_limits_ironlake_display_port = { > > .find_pll = intel_find_pll_ironlake_dp, }; > > > > +static const intel_limit_t intel_limits_vlv_dac = { > > + .dot = { .min = 25000, .max = 270000 }, > > + .vco = { .min = 4000000, .max = 6000000 }, > > + .n = { .min = 1, .max = 7 }, > > + .m = { .min = 22, .max = 450 }, /* guess */ > > + .m1 = { .min = 2, .max = 3 }, > > + .m2 = { .min = 11, .max = 156 }, > > + .p = { .min = 10, .max = 30 }, > > + .p1 = { .min = 2, .max = 3 }, > > + .p2 = { .dot_limit = 270000, > > + .p2_slow = 10, .p2_fast = 5 }, > > + .find_pll = intel_vlv_find_best_pll, }; > > + > > +static const intel_limit_t intel_limits_vlv_hdmi = { > > + .dot = { .min = 20000, .max = 165000 }, > > + .vco = { .min = 5994000, .max = 4000000 }, > > + .n = { .min = 1, .max = 7 }, > > + .m = { .min = 60, .max = 300 }, /* guess */ > > + .m1 = { .min = 2, .max = 3 }, > > + .m2 = { .min = 11, .max = 156 }, > > + .p = { .min = 10, .max = 30 }, > > + .p1 = { .min = 2, .max = 3 }, > > + .p2 = { .dot_limit = 270000, > > + .p2_slow = 10, .p2_fast = 5 }, > > + .find_pll = intel_vlv_find_best_pll, }; > > + > > +static const intel_limit_t intel_limits_vlv_dp = { > > + .dot = { .min = 162000, .max = 270000 }, > > + .vco = { .min = 5994000, .max = 4000000 }, > > + .n = { .min = 1, .max = 7 }, > > + .m = { .min = 60, .max = 300 }, /* guess */ > > + .m1 = { .min = 2, .max = 3 }, > > + .m2 = { .min = 11, .max = 156 }, > > + .p = { .min = 10, .max = 30 }, > > + .p1 = { .min = 2, .max = 3 }, > > + .p2 = { .dot_limit = 270000, > > + .p2_slow = 10, .p2_fast = 5 }, > > + .find_pll = intel_vlv_find_best_pll, }; > > + > > u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) { > > unsigned long flags; > > @@ -384,6 +431,28 @@ out_unlock: > > return val; > > } > > > > +static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, > > + u32 val) > > +{ > > + unsigned long flags; > > + > > + spin_lock_irqsave(&dev_priv->dpio_lock, flags); > > + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, > 100)) { > > + DRM_ERROR("DPIO idle wait timed out\n"); > > + goto out_unlock; > > + } > > + > > + I915_WRITE(DPIO_DATA, val); > > + I915_WRITE(DPIO_REG, reg); > > + I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | > > + DPIO_BYTE); > > + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, > 100)) > > + DRM_ERROR("DPIO write wait timed out\n"); > > + > > +out_unlock: > > + spin_unlock_irqrestore(&dev_priv->dpio_lock, flags); } > > + > > static void vlv_init_dpio(struct drm_device *dev) { > > struct drm_i915_private *dev_priv = dev->dev_private; @@ -510,6 > > +579,13 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc, int > refclk) > > limit = &intel_limits_pineview_lvds; > > else > > limit = &intel_limits_pineview_sdvo; > > + } else if (IS_VALLEYVIEW(dev)) { > > + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) > > + limit = &intel_limits_vlv_dac; > > + else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI)) > > + limit = &intel_limits_vlv_hdmi; > > + else > > + limit = &intel_limits_vlv_dp; > > } else if (!IS_GEN2(dev)) { > > if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) > > limit = &intel_limits_i9xx_lvds; > > @@ -783,6 +859,83 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct > drm_crtc *crtc, > > memcpy(best_clock, &clock, sizeof(intel_clock_t)); > > return true; > > } > > +static bool > > +intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc, > > + int target, int refclk, intel_clock_t *match_clock, > > + intel_clock_t *best_clock) > > +{ > > + u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2; > > + u32 m, n, fastclk, minvco, maxvco; > > + u32 updrate, minupdate, fracbits, p; > > + unsigned long bestppm, ppm, absppm; > > + int dotclk; > > + > > + dotclk = target * 1000; > > + > > + bestppm = 1000000; > > + ppm = 0; > > + absppm = 0; > > + > > + fastclk = dotclk / (2*100); > > + minvco = limit->vco.min; > > + maxvco = limit->vco.max; > > + updrate = 0; > > + minupdate = 19200; > > + fracbits = 1; > > + > > + n = p = p1 = p2 = m = m1 = m2 = vco = bestn = 0; > > + bestm1 = bestm2 = bestp1 = bestp2 = 0; > > + > > + for(n = 1; n <= ((refclk) / minupdate); n++) { > > + updrate = refclk / n; > > + for (p1 = 3; p1 > 1; p1--) { > > + for (p2 = 21; p2 > 0; p2--) { > > + if (p2 > 10) > > + p2 = p2 - 1; > > + p = p1 * p2; > > + > > + for( m1=2; m1 <= 3; m1++) { > > + m2 = (((2*(fastclk * p * n / m1 )) + > > + refclk) / (2*refclk)); > > + m = m1 * m2; > > + vco = updrate * m; > > + if(vco >= minvco && vco < maxvco) { > > + ppm = 1000000 *((vco / p) - > > + fastclk) / > > + fastclk; > > + absppm = (ppm > 0)? ppm: (- > ppm); > > + if (absppm < 100 && > > + ((p1 * p2) > > > + (bestp1 * bestp2))) { > > + bestppm = 0; > > + bestn = n; > > + bestm1 = m1; > > + bestm2 = m2; > > + bestp1 = p1; > > + bestp2 = p2; > > + } > > + if (absppm < bestppm - 10) { > > + bestppm = absppm; > > + bestn = n; > > + bestm1 = m1; > > + bestm2 = m2; > > + bestp1 = p1; > > + bestp2 = p2; > > + } > > + } > > + } > > + } /* Next p2 */ > > + } /* Next p1 */ > > + }/* Next n */ > > + > > + best_clock->n = bestn; > > + best_clock->m1 = bestm1; > > + best_clock->m2 = bestm2; > > + best_clock->p1 = bestp1; > > + best_clock->p2 = bestp2; > > + > > + return true; > > +} > > > > static void ironlake_wait_for_vblank(struct drm_device *dev, int > > pipe) { @@ -1287,7 +1440,7 @@ static void intel_enable_pll(struct > > drm_i915_private *dev_priv, enum pipe pipe) > > u32 val; > > > > /* No really, not for ILK+ */ > > - BUG_ON(dev_priv->info->gen >= 5); > > + BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= > 5); > > > > /* PLL is protected by panel, make sure we can write it */ > > if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) @@ -3666,13 > > +3819,37 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, > > return display_bpc != bpc; > > } > > > > +static int vlv_get_refclk(struct drm_crtc *crtc) { > > + struct drm_device *dev = crtc->dev; > > + struct drm_i915_private *dev_priv = dev->dev_private; > > + int refclk = 27000; /* for DP & HDMI */ > > + > > + return 100000; /* only one validated so far */ > > + > > + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) { > > + refclk = 96000; > > + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { > > + if (intel_panel_use_ssc(dev_priv)) > > + refclk = 100000; > > + else > > + refclk = 96000; > > + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { > > + refclk = 100000; > > + } > > + > > + return refclk; > > +} > > + > > static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) > > { > > struct drm_device *dev = crtc->dev; > > struct drm_i915_private *dev_priv = dev->dev_private; > > int refclk; > > > > - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && > > + if (IS_VALLEYVIEW(dev)) { > > + refclk = vlv_get_refclk(crtc); > > + } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && > > intel_panel_use_ssc(dev_priv) && num_connectors < 2) { > > refclk = dev_priv->lvds_ssc_freq * 1000; > > DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", > @@ -3787,6 > > +3964,72 @@ static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t > *clock, > > I915_WRITE(LVDS, temp); > > } > > > > +static void vlv_update_pll(struct drm_crtc *crtc, > > + struct drm_display_mode *mode, > > + struct drm_display_mode *adjusted_mode, > > + intel_clock_t *clock, intel_clock_t *reduced_clock, > > + int refclk, int num_connectors) { > > + struct drm_device *dev = crtc->dev; > > + struct drm_i915_private *dev_priv = dev->dev_private; > > + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > > + int pipe = intel_crtc->pipe; > > + u32 dpll, mdiv, pdiv; > > + u32 bestn, bestm1, bestm2, bestp1, bestp2; > > + bool is_hdmi; > > + > > + is_hdmi = intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); > > + > > + bestn = clock->n; > > + bestm1 = clock->m1; > > + bestm2 = clock->m2; > > + bestp1 = clock->p1; > > + bestp2 = clock->p2; > > + > > + /* Enable DPIO clock input */ > > + dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV > | > > + DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; > > + I915_WRITE(DPLL(pipe), dpll); > > + POSTING_READ(DPLL(pipe)); > > + > > + mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & > DPIO_M2DIV_MASK)); > > + mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT)); > > + mdiv |= ((bestn << DPIO_N_SHIFT)); > > + mdiv |= (1 << DPIO_POST_DIV_SHIFT); > > + mdiv |= (1 << DPIO_K_SHIFT); > > + mdiv |= DPIO_ENABLE_CALIBRATION; > > + intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv); > > + > > + intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000); > > + > > + pdiv = DPIO_REFSEL_OVERRIDE | (5 << DPIO_PLL_MODESEL_SHIFT) | > > + (3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) | > > + (8 << DPIO_DRIVER_CTL_SHIFT) | (5 << > DPIO_CLK_BIAS_CTL_SHIFT); > > + intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv); > > + > > + intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x009f0051); > > + > > + dpll |= DPLL_VCO_ENABLE; > > + I915_WRITE(DPLL(pipe), dpll); > > + POSTING_READ(DPLL(pipe)); > > + if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == > DPLL_LOCK_VLV), 1)) > > + DRM_ERROR("DPLL %d failed to lock\n", pipe); > > + > > + if (is_hdmi) { > > + u32 temp = intel_mode_get_pixel_multiplier(adjusted_mode); > > + > > + if (temp > 1) > > + temp = (temp - 1) << > DPLL_MD_UDI_MULTIPLIER_SHIFT; > > + else > > + temp = 0; > > + > > + I915_WRITE(DPLL_MD(pipe), temp); > > + POSTING_READ(DPLL_MD(pipe)); > > + } > > + > > + intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x641); /* ??? */ } > > + > > static void i9xx_update_pll(struct drm_crtc *crtc, > > struct drm_display_mode *mode, > > struct drm_display_mode *adjusted_mode, @@ - > 4044,6 +4287,9 @@ > > static int i9xx_crtc_mode_set(struct drm_crtc *crtc, > > > > if (IS_GEN2(dev)) > > i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors); > > + else if (IS_VALLEYVIEW(dev)) > > + vlv_update_pll(crtc, mode,adjusted_mode, &clock, NULL, > > + refclk, num_connectors); > > else > > i9xx_update_pll(crtc, mode, adjusted_mode, &clock, > > has_reduced_clock ? &reduced_clock : NULL, > > -- > > 1.7.9.5 > > > > _______________________________________________ > > Intel-gfx mailing list > > Intel-gfx at lists.freedesktop.org > > http://lists.freedesktop.org/mailman/listinfo/intel-gfx > > -- > Daniel Vetter > Mail: daniel at ffwll.ch > Mobile: +41 (0)79 365 57 48 > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx