drm/i915: clear up the fdi/dp set_m_n confusion
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 2 Apr 2013 21:38:10 +0000 (23:38 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 3 Apr 2013 09:29:09 +0000 (11:29 +0200)
There's a rather decent confusion going on around transcoder m_n
values. So let's clarify:
- All dp encoders need this, either on the pch transcoder if it's a
  pch port, or on the cpu transcoder/pipe if it's a cpu port.
- fdi links need to have the right m_n values for the fdi link set in
  the cpu transcoder.

To handle the pch vs transcoder stuff a bit better, extract transcoder
set_m_n helpers. To make them simpler, set intel_crtc->cpu_transcoder
als in ironlake_crtc_mode_set, so that gen5+ (where the cpu m_n
registers are all at the same offset) can use it.

Haswell modeset is decently confused about dp vs. edp vs. fdi. dp vs.
edp works exactly the same as dp (since there's no pch dp any more),
so use that as a check. And only set up the fdi m_n values if we
really have a pch encoder present (which means we have a VGA encoder).

On ilk+ we've called ironlake_set_m_n both for cpu_edp and for pch
encoders. Now that dp_set_m_n handles all dp links (thanks to the
pch encoder check), we can ditch the cpu_edp stuff from the
fdi_set_m_n function.

Since the dp_m_n values are not readily available, we need to
carefully coax the edp values out of the encoder. Hence we can't (yet)
kill this superflous complexity.

v2: Rebase on top of the ivb fdi B/C check patch - we need to properly
clear intel_crtc->fdi_lane, otherwise those checks will misfire.

v3: Rebased on top of a s/IS_HASWELL/HAS_DDI/ patch from Paulo Zanoni.

v4: Drop the addition of has_dp_encoder, it's in the wrong patch (Jesse).

Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h

index 181bd0e3228c607de76266ecd42b758444b5eebb..06dacca8257ccce26e9f88f84a9269568c384d27 100644 (file)
@@ -5373,15 +5373,47 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
        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;
@@ -5401,22 +5433,14 @@ static void ironlake_set_m_n(struct drm_crtc *crtc)
                }
        }
 
-       /* 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)
@@ -5426,9 +5450,8 @@ static void ironlake_set_m_n(struct drm_crtc *crtc)
        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;
 
@@ -5437,10 +5460,7 @@ static void ironlake_set_m_n(struct drm_crtc *crtc)
        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,
@@ -5587,6 +5607,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *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) {
@@ -5625,7 +5647,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        } 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)
@@ -5661,7 +5683,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
        /* 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);
 
@@ -5773,15 +5797,15 @@ static int haswell_crtc_mode_set(struct drm_crtc *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);
 
index db592e80f22cc9c5a06b380e8893267e3f2db684..5a209626e9a131152f1534823831db52b8953b70 100644 (file)
@@ -775,12 +775,9 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
        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;
 
        /*
@@ -814,29 +811,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
        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)
index 2f451c2a14f54c12facb1a2aa0a8aea8000509d3..c2a7f84b609d72d099f70fec7bd2ee4fa178c8e9 100644 (file)
@@ -192,6 +192,7 @@ struct intel_crtc_config {
 
        bool dither;
        int pipe_bpp;
+       struct intel_link_m_n dp_m_n;
 
        /* Used by SDVO (and if we ever fix it, HDMI). */
        unsigned pixel_multiplier;
@@ -640,6 +641,10 @@ extern void intel_init_clock_gating(struct drm_device *dev);
 extern void intel_write_eld(struct drm_encoder *encoder,
                            struct drm_display_mode *mode);
 extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
+extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
+                                        struct intel_link_m_n *m_n);
+extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+                                        struct intel_link_m_n *m_n);
 extern void intel_prepare_ddi(struct drm_device *dev);
 extern void hsw_fdi_link_train(struct drm_crtc *crtc);
 extern void intel_ddi_init(struct drm_device *dev, enum port port);