@@ -1356,6 +1356,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
{
int cdclk = cdclk_state->cdclk;
int vco = cdclk_state->vco;
+ bool enable_pw2 = false;
u32 val, divider;
int ret;
@@ -1381,6 +1382,14 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
}
/*
+ * On GLK HDA apparently gets confused if
+ * cdclk is changed while PW2 is on
+ */
+ if (IS_GEMINILAKE(dev_priv))
+ enable_pw2 = intel_display_power_toggle_start(dev_priv,
+ SKL_DISP_PW_2);
+
+ /*
* Inform power controller of upcoming frequency change. BSpec
* requires us to wait up to 150usec, but that leads to timeouts;
* the 2ms used here is based on experiment.
@@ -1437,6 +1446,11 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
}
intel_update_cdclk(dev_priv);
+
+ if (IS_GEMINILAKE(dev_priv))
+ intel_display_power_toggle_end(dev_priv,
+ SKL_DISP_PW_2,
+ enable_pw2);
}
static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
@@ -1964,6 +1964,11 @@ bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
void intel_display_power_put(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
+bool intel_display_power_toggle_start(struct drm_i915_private *dev_priv,
+ enum i915_power_well_id power_well_id);
+void intel_display_power_toggle_end(struct drm_i915_private *dev_priv,
+ enum i915_power_well_id power_well_id,
+ bool enable);
void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
u8 req_slices);
@@ -2809,6 +2809,40 @@ static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
usleep_range(10, 30); /* 10 us delay per Bspec */
}
+bool intel_display_power_toggle_start(struct drm_i915_private *dev_priv,
+ enum i915_power_well_id power_well_id)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ struct i915_power_well *well = lookup_power_well(dev_priv, power_well_id);
+ bool was_enabled;
+
+ mutex_lock(&power_domains->lock);
+
+ was_enabled = well->hw_enabled;
+
+ if (was_enabled)
+ intel_power_well_disable(dev_priv, well);
+
+ return was_enabled;
+}
+
+void intel_display_power_toggle_end(struct drm_i915_private *dev_priv,
+ enum i915_power_well_id power_well_id,
+ bool enable)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ struct i915_power_well *well = lookup_power_well(dev_priv, power_well_id);
+
+ lockdep_assert_held(&power_domains->lock);
+
+ if (enable) {
+ WARN_ON(well->hw_enabled);
+ intel_power_well_enable(dev_priv, well);
+ }
+
+ mutex_unlock(&power_domains->lock);
+}
+
void bxt_display_core_init(struct drm_i915_private *dev_priv,
bool resume)
{