#define  SPLL_PLL_ENABLE               (1<<31)
 #define  SPLL_PLL_SSC                  (1<<28)
 #define  SPLL_PLL_NON_SSC              (2<<28)
+#define  SPLL_PLL_LCPLL                        (3<<28)
+#define  SPLL_PLL_REF_MASK             (3<<28)
 #define  SPLL_PLL_FREQ_810MHz          (0<<26)
 #define  SPLL_PLL_FREQ_1350MHz         (1<<26)
+#define  SPLL_PLL_FREQ_2700MHz         (2<<26)
+#define  SPLL_PLL_FREQ_MASK            (3<<26)
 
 /* WRPLL */
 #define WRPLL_CTL1                     0x46040
 #define  WRPLL_PLL_SELECT_LCPLL_2700   (0x03<<28)
 /* WRPLL divider programming */
 #define  WRPLL_DIVIDER_REFERENCE(x)    ((x)<<0)
+#define  WRPLL_DIVIDER_REF_MASK                (0xff)
 #define  WRPLL_DIVIDER_POST(x)         ((x)<<8)
+#define  WRPLL_DIVIDER_POST_MASK       (0x3f<<8)
+#define  WRPLL_DIVIDER_POST_SHIFT      8
 #define  WRPLL_DIVIDER_FEEDBACK(x)     ((x)<<16)
+#define  WRPLL_DIVIDER_FB_SHIFT                16
+#define  WRPLL_DIVIDER_FB_MASK         (0xff<<16)
 
 /* Port clock selection */
 #define PORT_CLK_SEL_A                 0x46100
 #define  PORT_CLK_SEL_WRPLL1           (4<<29)
 #define  PORT_CLK_SEL_WRPLL2           (5<<29)
 #define  PORT_CLK_SEL_NONE             (7<<29)
+#define  PORT_CLK_SEL_MASK             (7<<29)
 
 /* Transcoder clock selection */
 #define TRANS_CLK_SEL_A                        0x46140
 
        /* Otherwise a < c && b >= d, do nothing */
 }
 
+static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                                    int reg)
+{
+       int refclk = LC_FREQ;
+       int n, p, r;
+       u32 wrpll;
+
+       wrpll = I915_READ(reg);
+       switch (wrpll & SPLL_PLL_REF_MASK) {
+       case SPLL_PLL_SSC:
+       case SPLL_PLL_NON_SSC:
+               /*
+                * We could calculate spread here, but our checking
+                * code only cares about 5% accuracy, and spread is a max of
+                * 0.5% downspread.
+                */
+               refclk = 135;
+               break;
+       case SPLL_PLL_LCPLL:
+               refclk = LC_FREQ;
+               break;
+       default:
+               WARN(1, "bad wrpll refclk\n");
+               return 0;
+       }
+
+       r = wrpll & WRPLL_DIVIDER_REF_MASK;
+       p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
+       n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
+
+       return (LC_FREQ * n) / (p * r);
+}
+
+static void intel_ddi_clock_get(struct intel_encoder *encoder,
+                               struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       enum port port = intel_ddi_get_encoder_port(encoder);
+       int link_clock = 0;
+       u32 val, pll;
+
+       val = I915_READ(PORT_CLK_SEL(port));
+       switch (val & PORT_CLK_SEL_MASK) {
+       case PORT_CLK_SEL_LCPLL_810:
+               link_clock = 81000;
+               break;
+       case PORT_CLK_SEL_LCPLL_1350:
+               link_clock = 135000;
+               break;
+       case PORT_CLK_SEL_LCPLL_2700:
+               link_clock = 270000;
+               break;
+       case PORT_CLK_SEL_WRPLL1:
+               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
+               break;
+       case PORT_CLK_SEL_WRPLL2:
+               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
+               break;
+       case PORT_CLK_SEL_SPLL:
+               pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
+               if (pll == SPLL_PLL_FREQ_810MHz)
+                       link_clock = 81000;
+               else if (pll == SPLL_PLL_FREQ_1350MHz)
+                       link_clock = 135000;
+               else if (pll == SPLL_PLL_FREQ_2700MHz)
+                       link_clock = 270000;
+               else {
+                       WARN(1, "bad spll freq\n");
+                       return;
+               }
+               break;
+       default:
+               WARN(1, "bad port clock sel\n");
+               return;
+       }
+
+       pipe_config->port_clock = link_clock * 2;
+
+       if (pipe_config->has_pch_encoder)
+               pipe_config->adjusted_mode.crtc_clock =
+                       intel_dotclock_calculate(pipe_config->port_clock,
+                                                &pipe_config->fdi_m_n);
+       else if (pipe_config->has_dp_encoder)
+               pipe_config->adjusted_mode.crtc_clock =
+                       intel_dotclock_calculate(pipe_config->port_clock,
+                                                &pipe_config->dp_m_n);
+       else
+               pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+}
+
 static void
 intel_ddi_calculate_wrpll(int clock /* in Hz */,
                          unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
                              pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp);
                dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
        }
+
+       intel_ddi_clock_get(encoder, pipe_config);
 }
 
 static void intel_ddi_destroy(struct drm_encoder *encoder)