]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/gpu/drm/i915/intel_audio.c
drm/i915: Force 2*96 MHz cdclk on glk/cnl when audio power is enabled
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / i915 / intel_audio.c
index d1a8c0fa2d38359d51f40b398ffee7a4e0fd410a..0d9c65f40116f2d00bb36e3046b2bdf38adcecb2 100644 (file)
@@ -688,13 +688,70 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv)
        }
 }
 
+static void glk_force_audio_cdclk(struct drm_i915_private *dev_priv,
+                                 bool enable)
+{
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_atomic_state *state;
+       int ret;
+
+       drm_modeset_acquire_init(&ctx, 0);
+       state = drm_atomic_state_alloc(&dev_priv->drm);
+       if (WARN_ON(!state))
+               return;
+
+       state->acquire_ctx = &ctx;
+
+ retry:
+       to_intel_atomic_state(state)->cdclk.force_min_cdclk_changed = true;
+       to_intel_atomic_state(state)->cdclk.force_min_cdclk =
+               enable ? 2 * 96000 : 0;
+
+       /*
+        * Protects dev_priv->cdclk.force_min_cdclk
+        * Need to lock this here in case we have no active pipes
+        * and thus wouldn't lock it during the commit otherwise.
+        */
+       ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
+                              &ctx);
+       if (!ret)
+               ret = drm_atomic_commit(state);
+
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(&ctx);
+               goto retry;
+       }
+
+       WARN_ON(ret);
+
+       drm_atomic_state_put(state);
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+}
+
 static void i915_audio_component_get_power(struct device *kdev)
 {
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
        intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
+
+       /* Force CDCLK to 2*BCLK as long as we need audio to be powered. */
+       if (dev_priv->audio_power_refcount++ == 0)
+               if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+                       glk_force_audio_cdclk(dev_priv, true);
+
 }
 
 static void i915_audio_component_put_power(struct device *kdev)
 {
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+
+       /* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */
+       if (--dev_priv->audio_power_refcount == 0)
+               if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv))
+                       glk_force_audio_cdclk(dev_priv, false);
+
        intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
 }