diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2364ece..794d0ba 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6367,6 +6367,7 @@ enum punit_power_well {
 #define  DPLL_CRTL1_LINK_RATE_1620		3
 #define  DPLL_CRTL1_LINK_RATE_1080		4
 #define  DPLL_CRTL1_LINK_RATE_2160		5
+#define  DPLL_CRTL1_LINK_RATE_SHIFT(id)		((id)*6+1)
 
 /* DPLL control2 */
 #define DPLL_CTRL2				0x6C05C
@@ -6374,6 +6375,7 @@ enum punit_power_well {
 #define  DPLL_CTRL2_DDI_CLK_SEL_MASK(port)	(3<<((port)*3+1))
 #define  DPLL_CTRL2_DDI_CLK_SEL(clk, port)	(clk<<((port)*3+1))
 #define  DPLL_CTRL2_DDI_SEL_OVERRIDE(port)	(1<<(port*3))
+#define  DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port)	(port*3+1)
 
 /* DPLL Status */
 #define DPLL_STATUS	0x6C060
@@ -6400,6 +6402,9 @@ enum punit_power_well {
 #define  DPLL_CFGCR2_PDIV(x)		(x<<2)
 #define  DPLL_CFGCR2_CENTRAL_FREQ_MASK	(3)
 
+#define GET_CFG_CR1_REG(id) (DPLL1_CFGCR1 + (id - 1) * 8)
+#define GET_CFG_CR2_REG(id) (DPLL1_CFGCR2 + (id - 1) * 8)
+
 enum central_freq {
 	freq_9600 = 0,
 	freq_9000 = 1,
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e7a5428..b5cfb07 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -649,6 +649,114 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
 	return (refclk * n * 100) / (p * r);
 }
 
+static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
+			       enum intel_dpll_id dpll)
+{
+	uint32_t cfgcr1_reg, cfgcr2_reg;
+	uint32_t cfgcr1, cfgcr2;
+	uint32_t p0, p1, p2, dco_freq;
+
+	cfgcr1_reg = GET_CFG_CR1_REG(dpll);
+	cfgcr2_reg = GET_CFG_CR2_REG(dpll);
+
+	cfgcr1 = I915_READ(cfgcr1_reg);
+	cfgcr2 = I915_READ(cfgcr2_reg);
+
+	p0 = (cfgcr2 & DPLL_CFGCR2_PDIV_MASK) >> 2;
+	p2 = (cfgcr2 & DPLL_CFGCR2_KDIV_MASK) >> 5;
+
+	if (cfgcr2 &  DPLL_CFGCR2_QDIV_MODE(1))
+		p1 = (cfgcr2 & DPLL_CFGCR2_QDIV_RATIO_MASK) >> 8;
+	else
+		p1 = 1;
+
+
+	switch (p0) {
+	case pdiv_1:
+		p0 = 1;
+		break;
+	case pdiv_2:
+		p0 = 2;
+		break;
+	case pdiv_3:
+		p0 = 3;
+		break;
+	case pdiv_7:
+		p0 = 7;
+		break;
+	}
+
+	switch (p2) {
+	case kdiv_5:
+		p2 = 5;
+		break;
+	case kdiv_2:
+		p2 = 2;
+		break;
+	case kdiv_3:
+		p2 = 3;
+		break;
+	case kdiv_1:
+		p2 = 1;
+		break;
+	}
+
+	dco_freq = (cfgcr1 & DPLL_CFGCR1_DCO_INTEGER_MASK) * 24 * 1000;
+
+	dco_freq += (((cfgcr1 & DPLL_CFGCR1_DCO_FRACTION_MASK) >> 9) * 24 *
+		1000) / 0x8000;
+
+	return dco_freq / (p0 * p1 * p2 * 5);
+}
+
+
+static void skl_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;
+	uint32_t dpll_ctl1, dpll;
+
+	/* FIXME: This should be tracked in the pipe config. */
+	dpll = I915_READ(DPLL_CTRL2);
+	dpll &= DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
+	dpll >>= DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port);
+
+	dpll_ctl1 = I915_READ(DPLL_CTRL1);
+
+	if (dpll_ctl1 & DPLL_CTRL1_HDMI_MODE(dpll)) {
+		link_clock = skl_calc_wrpll_link(dev_priv, dpll);
+	} else {
+		link_clock = dpll_ctl1 & DPLL_CRTL1_LINK_RATE_MASK(dpll);
+		link_clock >>= DPLL_CRTL1_LINK_RATE_SHIFT(dpll);
+
+		switch (link_clock) {
+		case DPLL_CRTL1_LINK_RATE_810:
+			link_clock = 81000;
+			break;
+		case DPLL_CRTL1_LINK_RATE_1350:
+			link_clock = 135000;
+			break;
+		case DPLL_CRTL1_LINK_RATE_2700:
+			link_clock = 270000;
+			break;
+		default:
+			break;
+		}
+		link_clock *= 2;
+	}
+
+	pipe_config->port_clock = link_clock;
+
+	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 hsw_ddi_clock_get(struct intel_encoder *encoder,
 			      struct intel_crtc_config *pipe_config)
 {
@@ -1535,6 +1643,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 	u32 temp, flags = 0;
+	struct drm_device *dev = dev_priv->dev;
 
 	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
 	if (temp & TRANS_DDI_PHSYNC)
@@ -1606,7 +1715,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 		dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
 	}
 
-	hsw_ddi_clock_get(encoder, pipe_config);
+	if (INTEL_INFO(dev)->gen < 9)
+		hsw_ddi_clock_get(encoder, pipe_config);
+	else
+		skl_ddi_clock_get(encoder, pipe_config);
 }
 
 static void intel_ddi_destroy(struct drm_encoder *encoder)
