diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1cc31a5..d9efe83 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -4085,6 +4085,8 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
 u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 
+u32 gen9_get_scanline(struct intel_crtc *crtc);
+
 /* intel_dpio_phy.c */
 void bxt_port_to_phy_channel(struct drm_i915_private *dev_priv, enum port port,
 			     enum dpio_phy *phy, enum dpio_channel *ch);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5d391e6..47668dd 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -781,6 +781,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 	struct drm_vblank_crtc *vblank;
 	enum pipe pipe = crtc->pipe;
 	int position, vtotal;
+	struct intel_encoder *encoder;
 
 	if (!crtc->active)
 		return -1;
@@ -792,6 +793,12 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
 		vtotal /= 2;
 
+	if (IS_BROXTON(dev_priv) || IS_GEMINILAKE(dev_priv)) {
+		for_each_encoder_on_crtc(crtc->base.dev, &crtc->base, encoder)
+			if (encoder->type == INTEL_OUTPUT_DSI)
+				return gen9_get_scanline(crtc);
+	}
+
 	if (IS_GEN2(dev_priv))
 		position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
 	else
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 0b03260..85168ee 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -8802,6 +8802,17 @@ enum skl_power_gate {
 #define MIPIO_TXESC_CLK_DIV2			_MMIO(0x160008)
 #define  GLK_TX_ESC_CLK_DIV2_MASK			0x3FF
 
+/* Gen4+ Timestamp and Pipe Frame time stamp registers */
+#define GEN4_TIMESTAMP_CTR	_MMIO(MCHBAR_MIRROR_BASE + 0x2358)
+#define GEN7_TIMESTAMP_CTR	_MMIO(0x44070)
+
+#define _PIPE_FRMTMSTMP_A		0x70048
+#define _PIPE_FRMTMSTMP_B		0x71048
+#define _IVB_PIPE_FRMTMSTMP_C	0x72048
+#define PIPE_FRMTMSTMP(pipe)		\
+			_MMIO_PIPE3((pipe), _PIPE_FRMTMSTMP_A, \
+				_PIPE_FRMTMSTMP_B, _IVB_PIPE_FRMTMSTMP_C)
+
 /* BXT MIPI clock controls */
 #define BXT_MAX_VAR_OUTPUT_KHZ			39500
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0871807..601032f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10352,6 +10352,66 @@ static bool needs_scaling(const struct intel_plane_state *state)
 	return (src_w != dst_w || src_h != dst_h);
 }
 
+/*
+ * For Gen9 DSI, pipe scanline register will not
+ * work to get the scanline since the timings
+ * are driven from the PORT (unlike DDI encoders).
+ * This function will use Framestamp and current
+ * timestamp registers to calculate the scanline.
+ */
+u32 gen9_get_scanline(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	u32 crtc_vblank_start = crtc->base.mode.crtc_vblank_start;
+	u32 crtc_vtotal = crtc->base.mode.crtc_vtotal;
+	u32 crtc_htotal = crtc->base.mode.crtc_htotal;
+	u32 crtc_clock = crtc->base.mode.crtc_clock;
+	u64 scanline = 0, scan_prev_time, scan_curr_time, scan_post_time;
+
+	WARN_ON(!crtc_vtotal);
+	if (!crtc_vtotal)
+		return scanline;
+
+	/* To avoid the race condition where we might cross into the
+	 * next vblank just between the PIPE_FRMTMSTMP and TIMESTAMP_CTR
+	 * reads. We make sure we read PIPE_FRMTMSTMP and TIMESTAMP_CTR
+	 * during the same frame.
+	 */
+	do {
+		/*
+		 * This field provides read back of the display
+		 * pipe frame time stamp. The time stamp value
+		 * is sampled at every start of vertical blank.
+		 */
+		scan_prev_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
+
+		/*
+		 * The TIMESTAMP_CTR register has the current
+		 * time stamp value.
+		 */
+		scan_curr_time = I915_READ_FW(GEN7_TIMESTAMP_CTR);
+
+		scan_post_time = I915_READ_FW(PIPE_FRMTMSTMP(crtc->pipe));
+	} while (scan_post_time != scan_prev_time);
+
+	/*
+	 * Since the register is 32 bit and the values
+	 * can overflow and wrap around, making sure
+	 * current time accounts for the register
+	 * wrap
+	 */
+	if (scan_curr_time < scan_prev_time)
+		scan_curr_time += 0x100000000;
+
+	scanline = div_u64(mul_u64_u32_shr((scan_curr_time - scan_prev_time),
+					crtc_clock, 0), 1000 * crtc_htotal);
+	scanline = min(scanline, (u64)(crtc_vtotal - 1));
+	scanline = (scanline + crtc_vblank_start) % crtc_vtotal;
+
+	return scanline;
+}
+
 int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_state,
 				    struct drm_crtc_state *crtc_state,
 				    const struct intel_plane_state *old_plane_state,
