{297000,        2,      22,     20},
        {298000,        2,      21,     19},
 };
+
+void intel_ddi_mode_set(struct drm_encoder *encoder,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       int port = intel_hdmi->ddi_port;
+       int pipe = intel_crtc->pipe;
+       int p, n2, r2, valid=0;
+       u32 temp, i;
+
+       /* On Haswell, we need to enable the clocks and prepare DDI function to
+        * work in HDMI mode for this pipe.
+        */
+       DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
+
+       for (i=0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) {
+               if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) {
+                       p = wrpll_tmds_clock_table[i].p;
+                       n2 = wrpll_tmds_clock_table[i].n2;
+                       r2 = wrpll_tmds_clock_table[i].r2;
+
+                       DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n",
+                                       crtc->mode.clock,
+                                       p, n2, r2);
+
+                       valid = 1;
+                       break;
+               }
+       }
+
+       if (!valid) {
+               DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n",
+                               crtc->mode.clock);
+               return;
+       }
+
+       /* Enable LCPLL if disabled */
+       temp = I915_READ(LCPLL_CTL);
+       if (temp & LCPLL_PLL_DISABLE)
+               I915_WRITE(LCPLL_CTL,
+                               temp & ~LCPLL_PLL_DISABLE);
+
+       /* Configure WR PLL 1, program the correct divider values for
+        * the desired frequency and wait for warmup */
+       I915_WRITE(WRPLL_CTL1,
+                       WRPLL_PLL_ENABLE |
+                       WRPLL_PLL_SELECT_LCPLL_2700 |
+                       WRPLL_DIVIDER_REFERENCE(r2) |
+                       WRPLL_DIVIDER_FEEDBACK(n2) |
+                       WRPLL_DIVIDER_POST(p));
+
+       udelay(20);
+
+       /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use
+        * this port for connection.
+        */
+       I915_WRITE(PORT_CLK_SEL(port),
+                       PORT_CLK_SEL_WRPLL1);
+       I915_WRITE(PIPE_CLK_SEL(pipe),
+                       PIPE_CLK_SEL_PORT(port));
+
+       udelay(20);
+
+       if (intel_hdmi->has_audio) {
+               /* Proper support for digital audio needs a new logic and a new set
+                * of registers, so we leave it for future patch bombing.
+                */
+               DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n",
+                                pipe_name(intel_crtc->pipe));
+       }
+
+       /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
+       temp = I915_READ(DDI_FUNC_CTL(pipe));
+       temp &= ~PIPE_DDI_PORT_MASK;
+       temp &= ~PIPE_DDI_BPC_12;
+       temp |= PIPE_DDI_SELECT_PORT(port) |
+                       PIPE_DDI_MODE_SELECT_HDMI |
+                       ((intel_crtc->bpp > 24) ?
+                               PIPE_DDI_BPC_12 :
+                               PIPE_DDI_BPC_8) |
+                       PIPE_DDI_FUNC_ENABLE;
+
+       I915_WRITE(DDI_FUNC_CTL(pipe), temp);
+
+       intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+       intel_hdmi_set_spd_infoframe(encoder);
+}
+
+void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       int port = intel_hdmi->ddi_port;
+       u32 temp;
+
+       temp = I915_READ(DDI_BUF_CTL(port));
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               temp &= ~DDI_BUF_CTL_ENABLE;
+       } else {
+               temp |= DDI_BUF_CTL_ENABLE;
+       }
+
+       /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
+        * and swing/emphasis values are ignored so nothing special needs
+        * to be done besides enabling the port.
+        */
+       I915_WRITE(DDI_BUF_CTL(port),
+                       temp);
+}
 
        kfree(connector);
 }
 
+static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
+       .dpms = intel_ddi_dpms,
+       .mode_fixup = intel_hdmi_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_ddi_mode_set,
+       .commit = intel_encoder_commit,
+};
+
 static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
        .dpms = intel_hdmi_dpms,
        .mode_fixup = intel_hdmi_mode_fixup,
                        I915_WRITE(TVIDEO_DIP_CTL(i), 0);
        }
 
-       drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+       if (IS_HASWELL(dev))
+               drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
+       else
+               drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
        intel_hdmi_add_properties(intel_hdmi, connector);