diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_runtime_pm.c | 164 |
1 files changed, 147 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 70e659772a7a..53ea564f971e 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -130,6 +130,8 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) 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: @@ -1853,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) | \ @@ -2646,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) { @@ -2794,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); @@ -2820,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) @@ -2847,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; @@ -2911,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 = @@ -3043,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); @@ -3084,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); @@ -3200,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 @@ -3219,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; } |