drm/i915: fix issue in display pipe setup on IGDNG
authorZhenyu Wang <zhenyuw@linux.intel.com>
Thu, 23 Jul 2009 17:00:29 +0000 (01:00 +0800)
committerEric Anholt <eric@anholt.net>
Wed, 29 Jul 2009 22:16:01 +0000 (15:16 -0700)
During pipe DPMS off, instead of busy waiting pipe off, insert
delays during wait and don't loop after enough tries which matches
spec requirement. Also try to match DPMS on path by disable FDI TX
PLL in DPMS off. Disable PF by writing PF_WIN_SZ which really trigger
the update.

Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c

index 897a116cad14852bc464e80b6af8d0b0c74a18c1..7c77c4c53c526493377f17feed30b0e6a3297093 100644 (file)
 #define PFA_CTL_1               0x68080
 #define PFB_CTL_1               0x68880
 #define  PF_ENABLE              (1<<31)
+#define PFA_WIN_SZ             0x68074
+#define PFB_WIN_SZ             0x68874
 
 /* legacy palette */
 #define LGC_PALETTE_A           0x4a000
index b06364ed25912c35e412c8994aeec997e5916d9a..15a8c3908acb3c13a862e6f26d7b7e27e638f2d7 100644 (file)
@@ -1038,6 +1038,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
        int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
        int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
        int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
+       int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
        int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
        int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
        int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
@@ -1051,7 +1052,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
        int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
        int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
        u32 temp;
-       int tries = 5, j;
+       int tries = 5, j, n;
 
        /* XXX: When our outputs are all unaware of DPMS modes other than off
         * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -1239,19 +1240,21 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                if ((temp & PIPEACONF_ENABLE) != 0) {
                        I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
                        I915_READ(pipeconf_reg);
+                       n = 0;
                        /* wait for cpu pipe off, pipe state */
-                       while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
-                               ;
+                       while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
+                               n++;
+                               if (n < 60) {
+                                       udelay(500);
+                                       continue;
+                               } else {
+                                       DRM_DEBUG("pipe %d off delay\n", pipe);
+                                       break;
+                               }
+                       }
                } else
                        DRM_DEBUG("crtc %d is disabled\n", pipe);
 
-               /* IGDNG-A : disable cpu panel fitter ? */
-               temp = I915_READ(pf_ctl_reg);
-               if ((temp & PF_ENABLE) != 0) {
-                       I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
-                       I915_READ(pf_ctl_reg);
-               }
-
                /* disable CPU FDI tx and PCH FDI rx */
                temp = I915_READ(fdi_tx_reg);
                I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
@@ -1261,6 +1264,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
                I915_READ(fdi_rx_reg);
 
+               udelay(100);
+
                /* still set train pattern 1 */
                temp = I915_READ(fdi_tx_reg);
                temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1272,14 +1277,25 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                temp |= FDI_LINK_TRAIN_PATTERN_1;
                I915_WRITE(fdi_rx_reg, temp);
 
+               udelay(100);
+
                /* disable PCH transcoder */
                temp = I915_READ(transconf_reg);
                if ((temp & TRANS_ENABLE) != 0) {
                        I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
                        I915_READ(transconf_reg);
+                       n = 0;
                        /* wait for PCH transcoder off, transcoder state */
-                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
-                               ;
+                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
+                               n++;
+                               if (n < 60) {
+                                       udelay(500);
+                                       continue;
+                               } else {
+                                       DRM_DEBUG("transcoder %d off delay\n", pipe);
+                                       break;
+                               }
+                       }
                }
 
                /* disable PCH DPLL */
@@ -1297,6 +1313,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_READ(fdi_rx_reg);
                }
 
+               /* Disable CPU FDI TX PLL */
+               temp = I915_READ(fdi_tx_reg);
+               if ((temp & FDI_TX_PLL_ENABLE) != 0) {
+                       I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
+                       I915_READ(fdi_tx_reg);
+                       udelay(100);
+               }
+
+               /* Disable PF */
+               temp = I915_READ(pf_ctl_reg);
+               if ((temp & PF_ENABLE) != 0) {
+                       I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
+                       I915_READ(pf_ctl_reg);
+               }
+               I915_WRITE(pf_win_size, 0);
+
                /* Wait for the clocks to turn off. */
                udelay(150);
                break;