drm/i915/chv: Add update and enable pll for Cherryview
authorChon Ming Lee <chon.ming.lee@intel.com>
Fri, 2 May 2014 11:27:47 +0000 (14:27 +0300)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 12 May 2014 17:50:14 +0000 (19:50 +0200)
Added programming PLL for CHV based on "Application note for 1273 CHV
Display phy".

v2:  -Break the common lane reset into another patch.
     -Break the clock calculation into another patch.

    -The changes are based on Ville review.
    -Rework based on DPIO register define naming convention change.
    -Break the dpio write into few lines to improve readability.
    -Correct the udelay during chv_enable_pll.
    -clean up some magic numbers with some new define.
    -program the afc recal bit which was missed.

v3: Based on Ville review
-  minor correction of the bit defination
    - add deassert/propagate data lane reset

v4: Corrected the udelay between dclkp enable and pll enable.
Minor comment and better way to clear the TX lane reset.

v5: Squash in fixup from Rafael Barbalho.

[vsyrjala: v6: Polish the defines (Imre)]

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c

index 921b48fbf5716eb5387096f7266c240d1baa8015..816470ea57367e6bede50cfda4201a95cb73a178 100644 (file)
@@ -681,6 +681,12 @@ enum punit_power_well {
 #define _VLV_PCS_DW9_CH1               0x8424
 #define        VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1)
 
+#define _CHV_PCS_DW10_CH0              0x8228
+#define _CHV_PCS_DW10_CH1              0x8428
+#define   DPIO_PCS_SWING_CALC_TX0_TX2  (1<<30)
+#define   DPIO_PCS_SWING_CALC_TX1_TX3  (1<<31)
+#define CHV_PCS_DW10(ch) _PORT(ch, _CHV_PCS_DW10_CH0, _CHV_PCS_DW10_CH1)
+
 #define _VLV_PCS_DW11_CH0              0x822c
 #define _VLV_PCS_DW11_CH1              0x842c
 #define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1)
@@ -699,14 +705,21 @@ enum punit_power_well {
 
 #define _VLV_TX_DW2_CH0                        0x8288
 #define _VLV_TX_DW2_CH1                        0x8488
+#define   DPIO_SWING_MARGIN_SHIFT      16
+#define   DPIO_SWING_MARGIN_MASK       (0xff << DPIO_SWING_MARGIN_SHIFT)
+#define   DPIO_UNIQ_TRANS_SCALE_SHIFT  8
 #define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1)
 
 #define _VLV_TX_DW3_CH0                        0x828c
 #define _VLV_TX_DW3_CH1                        0x848c
+/* The following bit for CHV phy */
+#define   DPIO_TX_UNIQ_TRANS_SCALE_EN  (1<<27)
 #define VLV_TX_DW3(ch) _PORT(ch, _VLV_TX_DW3_CH0, _VLV_TX_DW3_CH1)
 
 #define _VLV_TX_DW4_CH0                        0x8290
 #define _VLV_TX_DW4_CH1                        0x8490
+#define   DPIO_SWING_DEEMPH9P5_SHIFT   24
+#define   DPIO_SWING_DEEMPH9P5_MASK    (0xff << DPIO_SWING_DEEMPH9P5_SHIFT)
 #define VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1)
 
 #define _VLV_TX3_DW4_CH0               0x690
@@ -726,6 +739,62 @@ enum punit_power_well {
 #define _VLV_TX_DW14_CH1               0x84b8
 #define VLV_TX_DW14(ch) _PORT(ch, _VLV_TX_DW14_CH0, _VLV_TX_DW14_CH1)
 
+/* CHV dpPhy registers */
+#define _CHV_PLL_DW0_CH0               0x8000
+#define _CHV_PLL_DW0_CH1               0x8180
+#define CHV_PLL_DW0(ch) _PIPE(ch, _CHV_PLL_DW0_CH0, _CHV_PLL_DW0_CH1)
+
+#define _CHV_PLL_DW1_CH0               0x8004
+#define _CHV_PLL_DW1_CH1               0x8184
+#define   DPIO_CHV_N_DIV_SHIFT         8
+#define   DPIO_CHV_M1_DIV_BY_2         (0 << 0)
+#define CHV_PLL_DW1(ch) _PIPE(ch, _CHV_PLL_DW1_CH0, _CHV_PLL_DW1_CH1)
+
+#define _CHV_PLL_DW2_CH0               0x8008
+#define _CHV_PLL_DW2_CH1               0x8188
+#define CHV_PLL_DW2(ch) _PIPE(ch, _CHV_PLL_DW2_CH0, _CHV_PLL_DW2_CH1)
+
+#define _CHV_PLL_DW3_CH0               0x800c
+#define _CHV_PLL_DW3_CH1               0x818c
+#define  DPIO_CHV_FRAC_DIV_EN          (1 << 16)
+#define  DPIO_CHV_FIRST_MOD            (0 << 8)
+#define  DPIO_CHV_SECOND_MOD           (1 << 8)
+#define  DPIO_CHV_FEEDFWD_GAIN_SHIFT   0
+#define CHV_PLL_DW3(ch) _PIPE(ch, _CHV_PLL_DW3_CH0, _CHV_PLL_DW3_CH1)
+
+#define _CHV_PLL_DW6_CH0               0x8018
+#define _CHV_PLL_DW6_CH1               0x8198
+#define   DPIO_CHV_GAIN_CTRL_SHIFT     16
+#define          DPIO_CHV_INT_COEFF_SHIFT      8
+#define   DPIO_CHV_PROP_COEFF_SHIFT    0
+#define CHV_PLL_DW6(ch) _PIPE(ch, _CHV_PLL_DW6_CH0, _CHV_PLL_DW6_CH1)
+
+#define _CHV_CMN_DW13_CH0              0x8134
+#define _CHV_CMN_DW0_CH1               0x8080
+#define   DPIO_CHV_S1_DIV_SHIFT                21
+#define   DPIO_CHV_P1_DIV_SHIFT                13 /* 3 bits */
+#define   DPIO_CHV_P2_DIV_SHIFT                8  /* 5 bits */
+#define   DPIO_CHV_K_DIV_SHIFT         4
+#define   DPIO_PLL_FREQLOCK            (1 << 1)
+#define   DPIO_PLL_LOCK                        (1 << 0)
+#define CHV_CMN_DW13(ch) _PIPE(ch, _CHV_CMN_DW13_CH0, _CHV_CMN_DW0_CH1)
+
+#define _CHV_CMN_DW14_CH0              0x8138
+#define _CHV_CMN_DW1_CH1               0x8084
+#define   DPIO_AFC_RECAL               (1 << 14)
+#define   DPIO_DCLKP_EN                        (1 << 13)
+#define CHV_CMN_DW14(ch) _PIPE(ch, _CHV_CMN_DW14_CH0, _CHV_CMN_DW1_CH1)
+
+#define CHV_CMN_DW30                   0x8178
+#define   DPIO_LRC_BYPASS              (1 << 3)
+
+#define _TXLANE(ch, lane, offset) ((ch ? 0x2400 : 0) + \
+                                       (lane) * 0x200 + (offset))
+
+#define CHV_TX_DW11(ch, lane) _TXLANE(ch, lane, 0xac)
+#define   DPIO_FRC_LATENCY_SHFIT       8
+#define CHV_TX_DW14(ch, lane) _TXLANE(ch, lane, 0xb8)
+#define   DPIO_UPAR_SHIFT              30
 /*
  * Fence registers
  */
@@ -1415,6 +1484,7 @@ enum punit_power_well {
 #define   DPLL_LOCK_VLV                        (1<<15)
 #define   DPLL_INTEGRATED_CRI_CLK_VLV  (1<<14)
 #define   DPLL_INTEGRATED_CLOCK_VLV    (1<<13)
+#define   DPLL_SSC_REF_CLOCK_CHV       (1<<13)
 #define   DPLL_PORTC_READY_MASK                (0xf << 4)
 #define   DPLL_PORTB_READY_MASK                (0xf)
 
index 13330fd7b21ccab7d86f75cf86d2f0e9ad97004a..9bfc271c751f4c415d70f93ea59b64536869c28f 100644 (file)
@@ -1555,6 +1555,49 @@ static void vlv_enable_pll(struct intel_crtc *crtc)
        udelay(150); /* wait for warmup */
 }
 
+static void chv_enable_pll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+       enum dpio_channel port = vlv_pipe_to_channel(pipe);
+       int dpll = DPLL(crtc->pipe);
+       u32 tmp;
+
+       assert_pipe_disabled(dev_priv, crtc->pipe);
+
+       BUG_ON(!IS_CHERRYVIEW(dev_priv->dev));
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       /* Enable back the 10bit clock to display controller */
+       tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
+       tmp |= DPIO_DCLKP_EN;
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
+
+       /*
+        * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
+        */
+       udelay(1);
+
+       /* Enable PLL */
+       tmp = I915_READ(dpll);
+       tmp |= DPLL_VCO_ENABLE;
+       I915_WRITE(dpll, tmp);
+
+       /* Check PLL is locked */
+       if (wait_for(((I915_READ(dpll) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
+               DRM_ERROR("PLL %d failed to lock\n", pipe);
+
+       /* Deassert soft data lane reset*/
+       tmp = vlv_dpio_read(dev_priv, pipe, VLV_PCS_DW0(port));
+       tmp |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), tmp);
+
+
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
 static void i9xx_enable_pll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
@@ -4470,8 +4513,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
        is_dsi = intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI);
 
-       if (!is_dsi)
-               vlv_enable_pll(intel_crtc);
+       if (!is_dsi) {
+               if (IS_CHERRYVIEW(dev))
+                       chv_enable_pll(intel_crtc);
+               else
+                       vlv_enable_pll(intel_crtc);
+       }
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
@@ -5326,6 +5373,87 @@ static void vlv_update_pll(struct intel_crtc *crtc)
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void chv_update_pll(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+       int dpll_reg = DPLL(crtc->pipe);
+       enum dpio_channel port = vlv_pipe_to_channel(pipe);
+       u32 val, loopfilter, intcoeff;
+       u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
+       int refclk;
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       bestn = crtc->config.dpll.n;
+       bestm2_frac = crtc->config.dpll.m2 & 0x3fffff;
+       bestm1 = crtc->config.dpll.m1;
+       bestm2 = crtc->config.dpll.m2 >> 22;
+       bestp1 = crtc->config.dpll.p1;
+       bestp2 = crtc->config.dpll.p2;
+
+       /*
+        * Enable Refclk and SSC
+        */
+       val = I915_READ(dpll_reg);
+       val |= (DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV);
+       I915_WRITE(dpll_reg, val);
+
+       /* Propagate soft reset to data lane reset */
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS_DW0(port));
+       val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), val);
+
+       /* Disable 10bit clock to display controller */
+       val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
+       val &= ~DPIO_DCLKP_EN;
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
+
+       /* p1 and p2 divider */
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port),
+                       5 << DPIO_CHV_S1_DIV_SHIFT |
+                       bestp1 << DPIO_CHV_P1_DIV_SHIFT |
+                       bestp2 << DPIO_CHV_P2_DIV_SHIFT |
+                       1 << DPIO_CHV_K_DIV_SHIFT);
+
+       /* Feedback post-divider - m2 */
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2);
+
+       /* Feedback refclk divider - n and m1 */
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port),
+                       DPIO_CHV_M1_DIV_BY_2 |
+                       1 << DPIO_CHV_N_DIV_SHIFT);
+
+       /* M2 fraction division */
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
+
+       /* M2 fraction division enable */
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port),
+                      DPIO_CHV_FRAC_DIV_EN |
+                      (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT));
+
+       /* Loop filter */
+       refclk = i9xx_get_refclk(&crtc->base, 0);
+       loopfilter = 5 << DPIO_CHV_PROP_COEFF_SHIFT |
+               2 << DPIO_CHV_GAIN_CTRL_SHIFT;
+       if (refclk == 100000)
+               intcoeff = 11;
+       else if (refclk == 38400)
+               intcoeff = 10;
+       else
+               intcoeff = 9;
+       loopfilter |= intcoeff << DPIO_CHV_INT_COEFF_SHIFT;
+       vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter);
+
+       /* AFC Recal */
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port),
+                       vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) |
+                       DPIO_AFC_RECAL);
+
+       mutex_unlock(&dev_priv->dpio_lock);
+}
+
 static void i9xx_update_pll(struct intel_crtc *crtc,
                            intel_clock_t *reduced_clock,
                            int num_connectors)
@@ -5709,6 +5837,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                i8xx_update_pll(intel_crtc,
                                has_reduced_clock ? &reduced_clock : NULL,
                                num_connectors);
+       } else if (IS_CHERRYVIEW(dev)) {
+               chv_update_pll(intel_crtc);
        } else if (IS_VALLEYVIEW(dev)) {
                vlv_update_pll(intel_crtc);
        } else {