Merge drm-next into drm-intel-next-queued
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / intel_runtime_pm.c
index 96ab74f3d101c1b3673324704d4fed6b2ef09c2a..53ea564f971ef6acd0ecf01d79254f2993450a78 100644 (file)
@@ -94,6 +94,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
                return "PORT_DDI_D_LANES";
        case POWER_DOMAIN_PORT_DDI_E_LANES:
                return "PORT_DDI_E_LANES";
+       case POWER_DOMAIN_PORT_DDI_F_LANES:
+               return "PORT_DDI_F_LANES";
        case POWER_DOMAIN_PORT_DDI_A_IO:
                return "PORT_DDI_A_IO";
        case POWER_DOMAIN_PORT_DDI_B_IO:
@@ -104,6 +106,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
                return "PORT_DDI_D_IO";
        case POWER_DOMAIN_PORT_DDI_E_IO:
                return "PORT_DDI_E_IO";
+       case POWER_DOMAIN_PORT_DDI_F_IO:
+               return "PORT_DDI_F_IO";
        case POWER_DOMAIN_PORT_DSI:
                return "PORT_DSI";
        case POWER_DOMAIN_PORT_CRT:
@@ -124,6 +128,10 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
                return "AUX_C";
        case POWER_DOMAIN_AUX_D:
                return "AUX_D";
+       case POWER_DOMAIN_AUX_F:
+               return "AUX_F";
+       case POWER_DOMAIN_AUX_IO_A:
+               return "AUX_IO_A";
        case POWER_DOMAIN_GMBUS:
                return "GMBUS";
        case POWER_DOMAIN_INIT:
@@ -390,6 +398,15 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
        I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id));
        hsw_wait_for_power_well_enable(dev_priv, power_well);
 
+       /* Display WA #1178: cnl */
+       if (IS_CANNONLAKE(dev_priv) &&
+           (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C ||
+            id == CNL_DISP_PW_AUX_D || id == CNL_DISP_PW_AUX_F)) {
+               val = I915_READ(CNL_AUX_ANAOVRD1(id));
+               val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS;
+               I915_WRITE(CNL_AUX_ANAOVRD1(id), val);
+       }
+
        if (wait_fuses)
                gen9_wait_for_power_well_fuses(dev_priv, pg);
 
@@ -600,6 +617,11 @@ void gen9_enable_dc5(struct drm_i915_private *dev_priv)
 
        DRM_DEBUG_KMS("Enabling DC5\n");
 
+       /* Wa Display #1183: skl,kbl,cfl */
+       if (IS_GEN9_BC(dev_priv))
+               I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) |
+                          SKL_SELECT_ALTERNATE_DC_EXIT);
+
        gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
 }
 
@@ -627,6 +649,11 @@ void skl_disable_dc6(struct drm_i915_private *dev_priv)
 {
        DRM_DEBUG_KMS("Disabling DC6\n");
 
+       /* Wa Display #1183: skl,kbl,cfl */
+       if (IS_GEN9_BC(dev_priv))
+               I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) |
+                          SKL_SELECT_ALTERNATE_DC_EXIT);
+
        gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
 }
 
@@ -1726,13 +1753,13 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT_ULL(POWER_DOMAIN_AUX_C) |                   \
        BIT_ULL(POWER_DOMAIN_AUDIO) |                   \
        BIT_ULL(POWER_DOMAIN_VGA) |                             \
-       BIT_ULL(POWER_DOMAIN_GMBUS) |                   \
        BIT_ULL(POWER_DOMAIN_INIT))
 #define BXT_DISPLAY_DC_OFF_POWER_DOMAINS (             \
        BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
        BIT_ULL(POWER_DOMAIN_GT_IRQ) |                  \
        BIT_ULL(POWER_DOMAIN_MODESET) |                 \
        BIT_ULL(POWER_DOMAIN_AUX_A) |                   \
+       BIT_ULL(POWER_DOMAIN_GMBUS) |                   \
        BIT_ULL(POWER_DOMAIN_INIT))
 #define BXT_DPIO_CMN_A_POWER_DOMAINS (                 \
        BIT_ULL(POWER_DOMAIN_PORT_DDI_A_LANES) |                \
@@ -1792,6 +1819,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT_ULL(POWER_DOMAIN_GT_IRQ) |                  \
        BIT_ULL(POWER_DOMAIN_MODESET) |                 \
        BIT_ULL(POWER_DOMAIN_AUX_A) |                   \
+       BIT_ULL(POWER_DOMAIN_GMBUS) |                   \
        BIT_ULL(POWER_DOMAIN_INIT))
 
 #define CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS (                \
@@ -1805,9 +1833,11 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT_ULL(POWER_DOMAIN_PORT_DDI_B_LANES) |                \
        BIT_ULL(POWER_DOMAIN_PORT_DDI_C_LANES) |                \
        BIT_ULL(POWER_DOMAIN_PORT_DDI_D_LANES) |                \
+       BIT_ULL(POWER_DOMAIN_PORT_DDI_F_LANES) |                \
        BIT_ULL(POWER_DOMAIN_AUX_B) |                       \
        BIT_ULL(POWER_DOMAIN_AUX_C) |                   \
        BIT_ULL(POWER_DOMAIN_AUX_D) |                   \
+       BIT_ULL(POWER_DOMAIN_AUX_F) |                   \
        BIT_ULL(POWER_DOMAIN_AUDIO) |                   \
        BIT_ULL(POWER_DOMAIN_VGA) |                             \
        BIT_ULL(POWER_DOMAIN_INIT))
@@ -1825,6 +1855,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
        BIT_ULL(POWER_DOMAIN_INIT))
 #define CNL_DISPLAY_AUX_A_POWER_DOMAINS (              \
        BIT_ULL(POWER_DOMAIN_AUX_A) |                   \
+       BIT_ULL(POWER_DOMAIN_AUX_IO_A) |                \
        BIT_ULL(POWER_DOMAIN_INIT))
 #define CNL_DISPLAY_AUX_B_POWER_DOMAINS (              \
        BIT_ULL(POWER_DOMAIN_AUX_B) |                   \
@@ -1835,8 +1866,15 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
 #define CNL_DISPLAY_AUX_D_POWER_DOMAINS (              \
        BIT_ULL(POWER_DOMAIN_AUX_D) |                   \
        BIT_ULL(POWER_DOMAIN_INIT))
+#define CNL_DISPLAY_AUX_F_POWER_DOMAINS (              \
+       BIT_ULL(POWER_DOMAIN_AUX_F) |                   \
+       BIT_ULL(POWER_DOMAIN_INIT))
+#define CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS (           \
+       BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO) |           \
+       BIT_ULL(POWER_DOMAIN_INIT))
 #define CNL_DISPLAY_DC_OFF_POWER_DOMAINS (             \
        CNL_DISPLAY_POWERWELL_2_POWER_DOMAINS |         \
+       BIT_ULL(POWER_DOMAIN_GT_IRQ) |                  \
        BIT_ULL(POWER_DOMAIN_MODESET) |                 \
        BIT_ULL(POWER_DOMAIN_AUX_A) |                   \
        BIT_ULL(POWER_DOMAIN_INIT))
@@ -2384,6 +2422,18 @@ static struct i915_power_well cnl_power_wells[] = {
                .ops = &hsw_power_well_ops,
                .id = SKL_DISP_PW_DDI_D,
        },
+       {
+               .name = "DDI F IO power well",
+               .domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS,
+               .ops = &hsw_power_well_ops,
+               .id = CNL_DISP_PW_DDI_F,
+       },
+       {
+               .name = "AUX F",
+               .domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS,
+               .ops = &hsw_power_well_ops,
+               .id = CNL_DISP_PW_AUX_F,
+       },
 };
 
 static int
@@ -2499,6 +2549,16 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
                set_power_wells(power_domains, skl_power_wells);
        } else if (IS_CANNONLAKE(dev_priv)) {
                set_power_wells(power_domains, cnl_power_wells);
+
+               /*
+                * DDI and Aux IO are getting enabled for all ports
+                * regardless the presence or use. So, in order to avoid
+                * timeouts, lets remove them from the list
+                * for the SKUs without port F.
+                */
+               if (!IS_CNL_WITH_PORT_F(dev_priv))
+                       power_domains->power_well_count -= 2;
+
        } else if (IS_BROXTON(dev_priv)) {
                set_power_wells(power_domains, bxt_power_wells);
        } else if (IS_GEMINILAKE(dev_priv)) {
@@ -2589,6 +2649,48 @@ static void gen9_dbuf_disable(struct drm_i915_private *dev_priv)
                DRM_ERROR("DBuf power disable timeout!\n");
 }
 
+/*
+ * TODO: we shouldn't always enable DBUF_CTL_S2, we should only enable it when
+ * needed and keep it disabled as much as possible.
+ */
+static void icl_dbuf_enable(struct drm_i915_private *dev_priv)
+{
+       I915_WRITE(DBUF_CTL_S1, I915_READ(DBUF_CTL_S1) | DBUF_POWER_REQUEST);
+       I915_WRITE(DBUF_CTL_S2, I915_READ(DBUF_CTL_S2) | DBUF_POWER_REQUEST);
+       POSTING_READ(DBUF_CTL_S2);
+
+       udelay(10);
+
+       if (!(I915_READ(DBUF_CTL_S1) & DBUF_POWER_STATE) ||
+           !(I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE))
+               DRM_ERROR("DBuf power enable timeout\n");
+}
+
+static void icl_dbuf_disable(struct drm_i915_private *dev_priv)
+{
+       I915_WRITE(DBUF_CTL_S1, I915_READ(DBUF_CTL_S1) & ~DBUF_POWER_REQUEST);
+       I915_WRITE(DBUF_CTL_S2, I915_READ(DBUF_CTL_S2) & ~DBUF_POWER_REQUEST);
+       POSTING_READ(DBUF_CTL_S2);
+
+       udelay(10);
+
+       if ((I915_READ(DBUF_CTL_S1) & DBUF_POWER_STATE) ||
+           (I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE))
+               DRM_ERROR("DBuf power disable timeout!\n");
+}
+
+static void icl_mbus_init(struct drm_i915_private *dev_priv)
+{
+       uint32_t val;
+
+       val = MBUS_ABOX_BT_CREDIT_POOL1(16) |
+             MBUS_ABOX_BT_CREDIT_POOL2(16) |
+             MBUS_ABOX_B_CREDIT(1) |
+             MBUS_ABOX_BW_CREDIT(1);
+
+       I915_WRITE(MBUS_ABOX_CTL, val);
+}
+
 static void skl_display_core_init(struct drm_i915_private *dev_priv,
                                   bool resume)
 {
@@ -2737,12 +2839,19 @@ static const struct cnl_procmon {
                { .dw1 = 0x00440000, .dw9 = 0x9A00AB25, .dw10 = 0x8AE38FF1, },
 };
 
-static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv)
+/*
+ * CNL has just one set of registers, while ICL has two sets: one for port A and
+ * the other for port B. The CNL registers are equivalent to the ICL port A
+ * registers, that's why we call the ICL macros even though the function has CNL
+ * on its name.
+ */
+static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv,
+                                      enum port port)
 {
        const struct cnl_procmon *procmon;
        u32 val;
 
-       val = I915_READ(CNL_PORT_COMP_DW3);
+       val = I915_READ(ICL_PORT_COMP_DW3(port));
        switch (val & (PROCESS_INFO_MASK | VOLTAGE_INFO_MASK)) {
        default:
                MISSING_CASE(val);
@@ -2763,13 +2872,13 @@ static void cnl_set_procmon_ref_values(struct drm_i915_private *dev_priv)
                break;
        }
 
-       val = I915_READ(CNL_PORT_COMP_DW1);
+       val = I915_READ(ICL_PORT_COMP_DW1(port));
        val &= ~((0xff << 16) | 0xff);
        val |= procmon->dw1;
-       I915_WRITE(CNL_PORT_COMP_DW1, val);
+       I915_WRITE(ICL_PORT_COMP_DW1(port), val);
 
-       I915_WRITE(CNL_PORT_COMP_DW9, procmon->dw9);
-       I915_WRITE(CNL_PORT_COMP_DW10, procmon->dw10);
+       I915_WRITE(ICL_PORT_COMP_DW9(port), procmon->dw9);
+       I915_WRITE(ICL_PORT_COMP_DW10(port), procmon->dw10);
 }
 
 static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume)
@@ -2790,7 +2899,8 @@ static void cnl_display_core_init(struct drm_i915_private *dev_priv, bool resume
        val &= ~CNL_COMP_PWR_DOWN;
        I915_WRITE(CHICKEN_MISC_2, val);
 
-       cnl_set_procmon_ref_values(dev_priv);
+       /* Dummy PORT_A to get the correct CNL register from the ICL macro */
+       cnl_set_procmon_ref_values(dev_priv, PORT_A);
 
        val = I915_READ(CNL_PORT_COMP_DW0);
        val |= COMP_INIT;
@@ -2854,6 +2964,80 @@ static void cnl_display_core_uninit(struct drm_i915_private *dev_priv)
        I915_WRITE(CHICKEN_MISC_2, val);
 }
 
+static void icl_display_core_init(struct drm_i915_private *dev_priv,
+                                 bool resume)
+{
+       enum port port;
+       u32 val;
+
+       gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+       /* 1. Enable PCH reset handshake. */
+       val = I915_READ(HSW_NDE_RSTWRN_OPT);
+       val |= RESET_PCH_HANDSHAKE_ENABLE;
+       I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
+
+       for (port = PORT_A; port <= PORT_B; port++) {
+               /* 2. Enable DDI combo PHY comp. */
+               val = I915_READ(ICL_PHY_MISC(port));
+               val &= ~ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+               I915_WRITE(ICL_PHY_MISC(port), val);
+
+               cnl_set_procmon_ref_values(dev_priv, port);
+
+               val = I915_READ(ICL_PORT_COMP_DW0(port));
+               val |= COMP_INIT;
+               I915_WRITE(ICL_PORT_COMP_DW0(port), val);
+
+               /* 3. Set power down enable. */
+               val = I915_READ(ICL_PORT_CL_DW5(port));
+               val |= CL_POWER_DOWN_ENABLE;
+               I915_WRITE(ICL_PORT_CL_DW5(port), val);
+       }
+
+       /* 4. Enable power well 1 (PG1) and aux IO power. */
+       /* FIXME: ICL power wells code not here yet. */
+
+       /* 5. Enable CDCLK. */
+       icl_init_cdclk(dev_priv);
+
+       /* 6. Enable DBUF. */
+       icl_dbuf_enable(dev_priv);
+
+       /* 7. Setup MBUS. */
+       icl_mbus_init(dev_priv);
+
+       /* 8. CHICKEN_DCPR_1 */
+       I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) |
+                                       CNL_DDI_CLOCK_REG_ACCESS_ON);
+}
+
+static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
+{
+       enum port port;
+       u32 val;
+
+       gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
+
+       /* 1. Disable all display engine functions -> aready done */
+
+       /* 2. Disable DBUF */
+       icl_dbuf_disable(dev_priv);
+
+       /* 3. Disable CD clock */
+       icl_uninit_cdclk(dev_priv);
+
+       /* 4. Disable Power Well 1 (PG1) and Aux IO Power */
+       /* FIXME: ICL power wells code not here yet. */
+
+       /* 5. Disable Comp */
+       for (port = PORT_A; port <= PORT_B; port++) {
+               val = I915_READ(ICL_PHY_MISC(port));
+               val |= ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN;
+               I915_WRITE(ICL_PHY_MISC(port), val);
+       }
+}
+
 static void chv_phy_control_init(struct drm_i915_private *dev_priv)
 {
        struct i915_power_well *cmn_bc =
@@ -2986,7 +3170,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
 
        power_domains->initializing = true;
 
-       if (IS_CANNONLAKE(dev_priv)) {
+       if (IS_ICELAKE(dev_priv)) {
+               icl_display_core_init(dev_priv, resume);
+       } else if (IS_CANNONLAKE(dev_priv)) {
                cnl_display_core_init(dev_priv, resume);
        } else if (IS_GEN9_BC(dev_priv)) {
                skl_display_core_init(dev_priv, resume);
@@ -3027,7 +3213,9 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
        if (!i915_modparams.disable_power_well)
                intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
 
-       if (IS_CANNONLAKE(dev_priv))
+       if (IS_ICELAKE(dev_priv))
+               icl_display_core_uninit(dev_priv);
+       else if (IS_CANNONLAKE(dev_priv))
                cnl_display_core_uninit(dev_priv);
        else if (IS_GEN9_BC(dev_priv))
                skl_display_core_uninit(dev_priv);
@@ -3143,18 +3331,19 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
  * @dev_priv: i915 device instance
  *
  * This function grabs a device-level runtime pm reference if the device is
- * already in use and ensures that it is powered up.
+ * already in use and ensures that it is powered up. It is illegal to try
+ * and access the HW should intel_runtime_pm_get_if_in_use() report failure.
  *
  * Any runtime pm reference obtained by this function must have a symmetric
  * call to intel_runtime_pm_put() to release the reference again.
+ *
+ * Returns: True if the wakeref was acquired, or False otherwise.
  */
 bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
 {
-       struct pci_dev *pdev = dev_priv->drm.pdev;
-       struct device *kdev = &pdev->dev;
-
        if (IS_ENABLED(CONFIG_PM)) {
-               int ret = pm_runtime_get_if_in_use(kdev);
+               struct pci_dev *pdev = dev_priv->drm.pdev;
+               struct device *kdev = &pdev->dev;
 
                /*
                 * In cases runtime PM is disabled by the RPM core and we get
@@ -3162,9 +3351,7 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
                 * function, since the power state is undefined. This applies
                 * atm to the late/early system suspend/resume handlers.
                 */
-               WARN_ONCE(ret < 0,
-                         "pm_runtime_get_if_in_use() failed: %d\n", ret);
-               if (ret <= 0)
+               if (pm_runtime_get_if_in_use(kdev) <= 0)
                        return false;
        }