drm/i915: add lpt_init_pch_refclk
authorPaulo Zanoni <paulo.r.zanoni@intel.com>
Sat, 1 Dec 2012 14:04:25 +0000 (12:04 -0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 10 Dec 2012 10:14:29 +0000 (11:14 +0100)
We need this code to init the PCH SSC refclk and the FDI registers.
The BIOS does this too and that's why VGA worked before this patch,
until you tried to suspend the machine...

This patch implements the "Sequence to enable CLKOUT_DP for FDI usage
and configure PCH FDI/IO" from our documentation.

v2:
- Squash Damien Lespiau's reset spelling fix on top.
- Add a comment that we don't need to bother about the ULT special
  case Damien noticed, since ULT won't have VGA.
- Add a comment to rip out the SDV codepaths once haswell ships for
  real.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> (v1)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c

index a12921892446adbe47ac7c043738d036c4979383..530db83ef32018ac3807dcb89fa88bfe1fac665f 100644 (file)
@@ -554,8 +554,7 @@ static int __i915_drm_thaw(struct drm_device *dev)
 
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-                       ironlake_init_pch_refclk(dev);
+               intel_init_pch_refclk(dev);
 
                mutex_lock(&dev->struct_mutex);
                dev_priv->mm.suspended = 0;
index 8513e1cd221c0e07d42c452e40886deecc6ee41b..65213bc2f3c615789d90483e9fdc8d659d098f91 100644 (file)
@@ -1662,7 +1662,7 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev,
 extern bool intel_fbc_enabled(struct drm_device *dev);
 extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
-extern void ironlake_init_pch_refclk(struct drm_device *dev);
+extern void intel_init_pch_refclk(struct drm_device *dev);
 extern void gen6_set_rps(struct drm_device *dev, u8 val);
 extern void intel_detect_pch(struct drm_device *dev);
 extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
index 0760425c892e4805cd1a22b9843f55f5e861bb5f..acf768d0a5d12382df1f549dce9863439b0e2806 100644 (file)
 #define  FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
 #define  FDI_BC_BIFURCATION_SELECT     (1 << 12)
 #define SOUTH_CHICKEN2         0xc2004
-#define  DPLS_EDP_PPS_FIX_DIS  (1<<0)
+#define  FDI_MPHY_IOSFSB_RESET_STATUS  (1<<13)
+#define  FDI_MPHY_IOSFSB_RESET_CTL     (1<<12)
+#define  DPLS_EDP_PPS_FIX_DIS          (1<<0)
 
 #define _FDI_RXA_CHICKEN         0xc200c
 #define _FDI_RXB_CHICKEN         0xc2010
 #define   SBI_SSCDIVINTPHASE_PROPAGATE         (1<<0)
 #define  SBI_SSCCTL                            0x020c
 #define  SBI_SSCCTL6                           0x060C
+#define   SBI_SSCCTL_PATHALT                   (1<<3)
 #define   SBI_SSCCTL_DISABLE                   (1<<0)
 #define  SBI_SSCAUXDIV6                                0x0610
 #define   SBI_SSCAUXDIV_FINALDIV2SEL(x)                ((x)<<4)
 #define  SBI_DBUFF0                            0x2a00
+#define   SBI_DBUFF0_ENABLE                    (1<<0)
 
 /* LPT PIXCLK_GATE */
 #define PIXCLK_GATE                    0xC6020
index 64993ecacf93a31147764d991946420551592033..ce7fc519f61476b18650eda35bda7eda92d57d80 100644 (file)
@@ -4864,10 +4864,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
-/*
- * Initialize reference clocks when the driver loads
- */
-void ironlake_init_pch_refclk(struct drm_device *dev)
+static void ironlake_init_pch_refclk(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
@@ -4981,6 +4978,182 @@ void ironlake_init_pch_refclk(struct drm_device *dev)
        }
 }
 
+/* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
+static void lpt_init_pch_refclk(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       bool has_vga = false;
+       bool is_sdv = false;
+       u32 tmp;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_ANALOG:
+                       has_vga = true;
+                       break;
+               }
+       }
+
+       if (!has_vga)
+               return;
+
+       /* XXX: Rip out SDV support once Haswell ships for real. */
+       if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00)
+               is_sdv = true;
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       tmp &= ~SBI_SSCCTL_DISABLE;
+       tmp |= SBI_SSCCTL_PATHALT;
+       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+
+       udelay(24);
+
+       tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
+       tmp &= ~SBI_SSCCTL_PATHALT;
+       intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
+
+       if (!is_sdv) {
+               tmp = I915_READ(SOUTH_CHICKEN2);
+               tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
+               I915_WRITE(SOUTH_CHICKEN2, tmp);
+
+               if (wait_for_atomic_us(I915_READ(SOUTH_CHICKEN2) &
+                                      FDI_MPHY_IOSFSB_RESET_STATUS, 100))
+                       DRM_ERROR("FDI mPHY reset assert timeout\n");
+
+               tmp = I915_READ(SOUTH_CHICKEN2);
+               tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
+               I915_WRITE(SOUTH_CHICKEN2, tmp);
+
+               if (wait_for_atomic_us((I915_READ(SOUTH_CHICKEN2) &
+                                       FDI_MPHY_IOSFSB_RESET_STATUS) == 0,
+                                      100))
+                       DRM_ERROR("FDI mPHY reset de-assert timeout\n");
+       }
+
+       tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
+       tmp &= ~(0xFF << 24);
+       tmp |= (0x12 << 24);
+       intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
+
+       if (!is_sdv) {
+               tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY);
+               tmp &= ~(0x3 << 6);
+               tmp |= (1 << 6) | (1 << 0);
+               intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY);
+       }
+
+       if (is_sdv) {
+               tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY);
+               tmp |= 0x7FFF;
+               intel_sbi_write(dev_priv, 0x800C, tmp, SBI_MPHY);
+       }
+
+       tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
+       tmp |= (1 << 11);
+       intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
+       tmp |= (1 << 11);
+       intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
+
+       if (is_sdv) {
+               tmp = intel_sbi_read(dev_priv, 0x2038, SBI_MPHY);
+               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
+               intel_sbi_write(dev_priv, 0x2038, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x2138, SBI_MPHY);
+               tmp |= (0x3F << 24) | (0xF << 20) | (0xF << 16);
+               intel_sbi_write(dev_priv, 0x2138, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x203C, SBI_MPHY);
+               tmp |= (0x3F << 8);
+               intel_sbi_write(dev_priv, 0x203C, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x213C, SBI_MPHY);
+               tmp |= (0x3F << 8);
+               intel_sbi_write(dev_priv, 0x213C, tmp, SBI_MPHY);
+       }
+
+       tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
+       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
+       intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
+       tmp |= (1 << 24) | (1 << 21) | (1 << 18);
+       intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
+
+       if (!is_sdv) {
+               tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
+               tmp &= ~(7 << 13);
+               tmp |= (5 << 13);
+               intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
+               tmp &= ~(7 << 13);
+               tmp |= (5 << 13);
+               intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
+       }
+
+       tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
+       tmp &= ~0xFF;
+       tmp |= 0x1C;
+       intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
+       tmp &= ~0xFF;
+       tmp |= 0x1C;
+       intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
+       tmp &= ~(0xFF << 16);
+       tmp |= (0x1C << 16);
+       intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
+
+       tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
+       tmp &= ~(0xFF << 16);
+       tmp |= (0x1C << 16);
+       intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
+
+       if (!is_sdv) {
+               tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
+               tmp |= (1 << 27);
+               intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
+               tmp |= (1 << 27);
+               intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
+               tmp &= ~(0xF << 28);
+               tmp |= (4 << 28);
+               intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
+
+               tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
+               tmp &= ~(0xF << 28);
+               tmp |= (4 << 28);
+               intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
+       }
+
+       /* ULT uses SBI_GEN0, but ULT doesn't have VGA, so we don't care. */
+       tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK);
+       tmp |= SBI_DBUFF0_ENABLE;
+       intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK);
+}
+
+/*
+ * Initialize reference clocks when the driver loads
+ */
+void intel_init_pch_refclk(struct drm_device *dev)
+{
+       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+               ironlake_init_pch_refclk(dev);
+       else if (HAS_PCH_LPT(dev))
+               lpt_init_pch_refclk(dev);
+}
+
 static int ironlake_get_refclk(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -8410,8 +8583,7 @@ static void intel_setup_outputs(struct drm_device *dev)
                        intel_encoder_clones(encoder);
        }
 
-       if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
-               ironlake_init_pch_refclk(dev);
+       intel_init_pch_refclk(dev);
 
        drm_helper_move_panel_connectors_to_head(dev);
 }