]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: PCH_ prefix for transcoder timings
[linux-imx.git] / drivers / gpu / drm / i915 / intel_display.c
index 2c3cbec75b4e484efdd55f1215d7390524f5a9fb..9f755fd5cd1cffa6a4dbf2c0f2095854bb2ec0af 100644 (file)
@@ -1206,14 +1206,14 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
        WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
 }
 
-static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
-                                      enum pipe pipe)
+static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+                                          enum pipe pipe)
 {
        int reg;
        u32 val;
        bool enabled;
 
-       reg = TRANSCONF(pipe);
+       reg = PCH_TRANSCONF(pipe);
        val = I915_READ(reg);
        enabled = !!(val & TRANS_ENABLE);
        WARN(enabled,
@@ -1565,7 +1565,7 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
        DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg);
 
        /* Make sure transcoder isn't still depending on us */
-       assert_transcoder_disabled(dev_priv, intel_crtc->pipe);
+       assert_pch_transcoder_disabled(dev_priv, intel_crtc->pipe);
 
        reg = pll->pll_reg;
        val = I915_READ(reg);
@@ -1605,7 +1605,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
                I915_WRITE(reg, val);
        }
 
-       reg = TRANSCONF(pipe);
+       reg = PCH_TRANSCONF(pipe);
        val = I915_READ(reg);
        pipeconf_val = I915_READ(PIPECONF(pipe));
 
@@ -1659,8 +1659,8 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        else
                val |= TRANS_PROGRESSIVE;
 
-       I915_WRITE(TRANSCONF(TRANSCODER_A), val);
-       if (wait_for(I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE, 100))
+       I915_WRITE(LPT_TRANSCONF, val);
+       if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100))
                DRM_ERROR("Failed to enable PCH transcoder\n");
 }
 
@@ -1677,7 +1677,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
        /* Ports must be off as well */
        assert_pch_ports_disabled(dev_priv, pipe);
 
-       reg = TRANSCONF(pipe);
+       reg = PCH_TRANSCONF(pipe);
        val = I915_READ(reg);
        val &= ~TRANS_ENABLE;
        I915_WRITE(reg, val);
@@ -1698,11 +1698,11 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
 {
        u32 val;
 
-       val = I915_READ(_TRANSACONF);
+       val = I915_READ(LPT_TRANSCONF);
        val &= ~TRANS_ENABLE;
-       I915_WRITE(_TRANSACONF, val);
+       I915_WRITE(LPT_TRANSCONF, val);
        /* wait for PCH transcoder off, transcoder state */
-       if (wait_for((I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE) == 0, 50))
+       if (wait_for((I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE) == 0, 50))
                DRM_ERROR("Failed to disable PCH transcoder\n");
 
        /* Workaround: clear timing override bit. */
@@ -2995,6 +2995,30 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
+                                               enum pipe pch_transcoder)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+
+       I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
+                  I915_READ(HTOTAL(cpu_transcoder)));
+       I915_WRITE(PCH_TRANS_HBLANK(pch_transcoder),
+                  I915_READ(HBLANK(cpu_transcoder)));
+       I915_WRITE(PCH_TRANS_HSYNC(pch_transcoder),
+                  I915_READ(HSYNC(cpu_transcoder)));
+
+       I915_WRITE(PCH_TRANS_VTOTAL(pch_transcoder),
+                  I915_READ(VTOTAL(cpu_transcoder)));
+       I915_WRITE(PCH_TRANS_VBLANK(pch_transcoder),
+                  I915_READ(VBLANK(cpu_transcoder)));
+       I915_WRITE(PCH_TRANS_VSYNC(pch_transcoder),
+                  I915_READ(VSYNC(cpu_transcoder)));
+       I915_WRITE(PCH_TRANS_VSYNCSHIFT(pch_transcoder),
+                  I915_READ(VSYNCSHIFT(cpu_transcoder)));
+}
+
 /*
  * Enable PCH resources required for PCH ports:
  *   - PCH PLLs
@@ -3011,7 +3035,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        u32 reg, temp;
 
-       assert_transcoder_disabled(dev_priv, pipe);
+       assert_pch_transcoder_disabled(dev_priv, pipe);
 
        /* Write the TU size bits before fdi link training, so that error
         * detection works. */
@@ -3058,14 +3082,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
 
        /* set transcoder timing, panel must allow it */
        assert_panel_unlocked(dev_priv, pipe);
-       I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
-       I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
-       I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
-
-       I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
-       I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
-       I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
-       I915_WRITE(TRANS_VSYNCSHIFT(pipe),  I915_READ(VSYNCSHIFT(pipe)));
+       ironlake_pch_transcoder_set_timings(intel_crtc, pipe);
 
        intel_fdi_normal_train(crtc);
 
@@ -3115,19 +3132,12 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
 
-       assert_transcoder_disabled(dev_priv, TRANSCODER_A);
+       assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A);
 
        lpt_program_iclkip(crtc);
 
        /* Set transcoder timing. */
-       I915_WRITE(_TRANS_HTOTAL_A, I915_READ(HTOTAL(cpu_transcoder)));
-       I915_WRITE(_TRANS_HBLANK_A, I915_READ(HBLANK(cpu_transcoder)));
-       I915_WRITE(_TRANS_HSYNC_A,  I915_READ(HSYNC(cpu_transcoder)));
-
-       I915_WRITE(_TRANS_VTOTAL_A, I915_READ(VTOTAL(cpu_transcoder)));
-       I915_WRITE(_TRANS_VBLANK_A, I915_READ(VBLANK(cpu_transcoder)));
-       I915_WRITE(_TRANS_VSYNC_A,  I915_READ(VSYNC(cpu_transcoder)));
-       I915_WRITE(_TRANS_VSYNCSHIFT_A, I915_READ(VSYNCSHIFT(cpu_transcoder)));
+       ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A);
 
        lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
@@ -3632,6 +3642,10 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
 
        I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
        I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
+
+       /* Border color in case we don't scale up to the full screen. Black by
+        * default, change to something else for debugging. */
+       I915_WRITE(BCLRPAT(crtc->pipe), 0);
 }
 
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
@@ -4671,12 +4685,17 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe = intel_crtc->pipe;
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
-       uint32_t vsyncshift;
+       uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end;
+
+       /* We need to be careful not to changed the adjusted mode, for otherwise
+        * the hw state checker will get angry at the mismatch. */
+       crtc_vtotal = adjusted_mode->crtc_vtotal;
+       crtc_vblank_end = adjusted_mode->crtc_vblank_end;
 
        if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
                /* the chip adds 2 halflines automatically */
-               adjusted_mode->crtc_vtotal -= 1;
-               adjusted_mode->crtc_vblank_end -= 1;
+               crtc_vtotal -= 1;
+               crtc_vblank_end -= 1;
                vsyncshift = adjusted_mode->crtc_hsync_start
                             - adjusted_mode->crtc_htotal / 2;
        } else {
@@ -4698,10 +4717,10 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
 
        I915_WRITE(VTOTAL(cpu_transcoder),
                   (adjusted_mode->crtc_vdisplay - 1) |
-                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+                  ((crtc_vtotal - 1) << 16));
        I915_WRITE(VBLANK(cpu_transcoder),
                   (adjusted_mode->crtc_vblank_start - 1) |
-                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+                  ((crtc_vblank_end - 1) << 16));
        I915_WRITE(VSYNC(cpu_transcoder),
                   (adjusted_mode->crtc_vsync_start - 1) |
                   ((adjusted_mode->crtc_vsync_end - 1) << 16));
@@ -4721,6 +4740,45 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
                   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 }
 
+static void intel_get_pipe_timings(struct intel_crtc *crtc,
+                                  struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+       uint32_t tmp;
+
+       tmp = I915_READ(HTOTAL(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
+       tmp = I915_READ(HBLANK(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+       tmp = I915_READ(HSYNC(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
+
+       tmp = I915_READ(VTOTAL(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
+       tmp = I915_READ(VBLANK(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+       tmp = I915_READ(VSYNC(cpu_transcoder));
+       pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
+       pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
+
+       if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) {
+               pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+               pipe_config->adjusted_mode.crtc_vtotal += 1;
+               pipe_config->adjusted_mode.crtc_vblank_end += 1;
+       }
+
+       tmp = I915_READ(PIPESRC(crtc->pipe));
+       pipe_config->requested_mode.vdisplay = (tmp & 0xffff) + 1;
+       pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1;
+}
+
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
 {
        struct drm_device *dev = intel_crtc->base.dev;
@@ -4937,6 +4995,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        if (!(tmp & PIPECONF_ENABLE))
                return false;
 
+       intel_get_pipe_timings(crtc, pipe_config);
+
        return true;
 }
 
@@ -5817,6 +5877,22 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
+                                       struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum transcoder transcoder = pipe_config->cpu_transcoder;
+
+       pipe_config->fdi_m_n.link_m = I915_READ(PIPE_LINK_M1(transcoder));
+       pipe_config->fdi_m_n.link_n = I915_READ(PIPE_LINK_N1(transcoder));
+       pipe_config->fdi_m_n.gmch_m = I915_READ(PIPE_DATA_M1(transcoder))
+                                       & ~TU_SIZE_MASK;
+       pipe_config->fdi_m_n.gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
+       pipe_config->fdi_m_n.tu = ((I915_READ(PIPE_DATA_M1(transcoder))
+                                  & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
+}
+
 static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
                                     struct intel_crtc_config *pipe_config)
 {
@@ -5828,20 +5904,23 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
        if (!(tmp & PIPECONF_ENABLE))
                return false;
 
-       if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
+       if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
                pipe_config->has_pch_encoder = true;
 
                tmp = I915_READ(FDI_RX_CTL(crtc->pipe));
                pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
                                          FDI_DP_PORT_WIDTH_SHIFT) + 1;
+
+               ironlake_get_fdi_m_n_config(crtc, pipe_config);
        }
 
+       intel_get_pipe_timings(crtc, pipe_config);
+
        return true;
 }
 
 static void haswell_modeset_global_resources(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        bool enable = false;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
@@ -5853,7 +5932,7 @@ static void haswell_modeset_global_resources(struct drm_device *dev)
                 * sequence that's not yet available. Just in case desktop eDP
                 * on PORT D is possible on haswell, too. */
                /* Even the eDP panel fitter is outside the always-on well. */
-               if (I915_READ(PF_WIN_SZ(crtc->pipe)))
+               if (crtc->config.pch_pfit.size && crtc->base.enabled)
                        enable = true;
        }
 
@@ -5973,14 +6052,18 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
         */
        tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
        if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) &&
-           I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE) {
+           I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) {
                pipe_config->has_pch_encoder = true;
 
                tmp = I915_READ(FDI_RX_CTL(PIPE_A));
                pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
                                          FDI_DP_PORT_WIDTH_SHIFT) + 1;
+
+               ironlake_get_fdi_m_n_config(crtc, pipe_config);
        }
 
+       intel_get_pipe_timings(crtc, pipe_config);
+
        return true;
 }
 
@@ -7958,10 +8041,45 @@ intel_pipe_config_compare(struct intel_crtc_config *current_config,
                return false; \
        }
 
+#define PIPE_CONF_CHECK_FLAGS(name, mask)      \
+       if ((current_config->name ^ pipe_config->name) & (mask)) { \
+               DRM_ERROR("mismatch in " #name " " \
+                         "(expected %i, found %i)\n", \
+                         current_config->name & (mask), \
+                         pipe_config->name & (mask)); \
+               return false; \
+       }
+
        PIPE_CONF_CHECK_I(has_pch_encoder);
        PIPE_CONF_CHECK_I(fdi_lanes);
+       PIPE_CONF_CHECK_I(fdi_m_n.gmch_m);
+       PIPE_CONF_CHECK_I(fdi_m_n.gmch_n);
+       PIPE_CONF_CHECK_I(fdi_m_n.link_m);
+       PIPE_CONF_CHECK_I(fdi_m_n.link_n);
+       PIPE_CONF_CHECK_I(fdi_m_n.tu);
+
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end);
+
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
+       PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
+
+       PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+                             DRM_MODE_FLAG_INTERLACE);
+
+       PIPE_CONF_CHECK_I(requested_mode.hdisplay);
+       PIPE_CONF_CHECK_I(requested_mode.vdisplay);
 
 #undef PIPE_CONF_CHECK_I
+#undef PIPE_CONF_CHECK_FLAGS
 
        return true;
 }