return bps / (link_bw * 8) + 1;
 }
 
-static void ironlake_set_m_n(struct drm_crtc *crtc)
+void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+                                 struct intel_link_m_n *m_n)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+
+       I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+       I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n);
+       I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m);
+       I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n);
+}
+
+void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
+                                 struct intel_link_m_n *m_n)
+{
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe = crtc->pipe;
+       enum transcoder transcoder = crtc->cpu_transcoder;
+
+       if (INTEL_INFO(dev)->gen >= 5) {
+               I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
+               I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
+               I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
+               I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
+       } else {
+               I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+               I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n);
+               I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m);
+               I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n);
+       }
+}
+
+static void ironlake_fdi_set_m_n(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_display_mode *adjusted_mode =
                &intel_crtc->config.adjusted_mode;
        struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
        struct intel_encoder *intel_encoder, *edp_encoder = NULL;
        struct intel_link_m_n m_n = {0};
        int target_clock, lane, link_bw;
                }
        }
 
-       /* FDI link */
-       lane = 0;
-       /* CPU eDP doesn't require FDI link, so just set DP M/N
-          according to current link config */
-       if (is_cpu_edp) {
-               intel_edp_link_config(edp_encoder, &lane, &link_bw);
-       } else {
-               /* FDI is a binary signal running at ~2.7GHz, encoding
-                * each output octet as 10 bits. The actual frequency
-                * is stored as a divider into a 100MHz clock, and the
-                * mode pixel clock is stored in units of 1KHz.
-                * Hence the bw of each lane in terms of the mode signal
-                * is:
-                */
-               link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
-       }
+       /* FDI is a binary signal running at ~2.7GHz, encoding
+        * each output octet as 10 bits. The actual frequency
+        * is stored as a divider into a 100MHz clock, and the
+        * mode pixel clock is stored in units of 1KHz.
+        * Hence the bw of each lane in terms of the mode signal
+        * is:
+        */
+       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
 
        /* [e]DP over FDI requires target mode clock instead of link clock. */
        if (edp_encoder)
        else
                target_clock = adjusted_mode->clock;
 
-       if (!lane)
-               lane = ironlake_get_lanes_required(target_clock, link_bw,
-                                                  intel_crtc->config.pipe_bpp);
+       lane = ironlake_get_lanes_required(target_clock, link_bw,
+                                          intel_crtc->config.pipe_bpp);
 
        intel_crtc->fdi_lanes = lane;
 
        intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock,
                               link_bw, &m_n);
 
-       I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m);
-       I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n);
-       I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m);
-       I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n);
+       intel_cpu_transcoder_set_m_n(intel_crtc, &m_n);
 }
 
 static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
             "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
 
+       intel_crtc->cpu_transcoder = pipe;
+
        ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
                                     &has_reduced_clock, &reduced_clock);
        if (!ok) {
        } else
                intel_put_pch_pll(intel_crtc);
 
-       if (is_dp && !is_cpu_edp)
+       if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
 
        /* Note, this also computes intel_crtc->fdi_lanes which is used below in
         * ironlake_check_fdi_lanes. */
-       ironlake_set_m_n(crtc);
+       intel_crtc->fdi_lanes = 0;
+       if (intel_crtc->config.has_pch_encoder)
+               ironlake_fdi_set_m_n(crtc);
 
        fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc);
 
        DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
        drm_mode_debug_printmodeline(mode);
 
-       if (is_dp && !is_cpu_edp)
+       if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
        intel_crtc->lowfreq_avail = false;
 
        intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
 
-       if (!is_dp || is_cpu_edp)
-               ironlake_set_m_n(crtc);
+       if (intel_crtc->config.has_pch_encoder)
+               ironlake_fdi_set_m_n(crtc);
 
        haswell_set_pipeconf(crtc, adjusted_mode, dither);
 
 
        struct drm_device *dev = crtc->dev;
        struct intel_encoder *intel_encoder;
        struct intel_dp *intel_dp;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int lane_count = 4;
        struct intel_link_m_n m_n;
-       int pipe = intel_crtc->pipe;
-       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
        int target_clock;
 
        /*
        intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane_count,
                               target_clock, adjusted_mode->clock, &m_n);
 
-       if (HAS_DDI(dev)) {
-               I915_WRITE(PIPE_DATA_M1(cpu_transcoder),
-                          TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n);
-               I915_WRITE(PIPE_LINK_M1(cpu_transcoder), m_n.link_m);
-               I915_WRITE(PIPE_LINK_N1(cpu_transcoder), m_n.link_n);
-       } else if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n);
-               I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m);
-               I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n);
-       } else if (IS_VALLEYVIEW(dev)) {
-               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
-               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
-               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
-       } else {
-               I915_WRITE(PIPE_GMCH_DATA_M(pipe),
-                          TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n);
-               I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m);
-               I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n);
-       }
+       if (intel_crtc->config.has_pch_encoder)
+               intel_pch_transcoder_set_m_n(intel_crtc, &m_n);
+       else
+               intel_cpu_transcoder_set_m_n(intel_crtc, &m_n);
 }
 
 void intel_dp_init_link_config(struct intel_dp *intel_dp)