struct intel_cdclk_state actual;
                /* The current hardware cdclk state */
                struct intel_cdclk_state hw;
+
+               int force_min_cdclk;
        } cdclk;
 
        /**
         *
         */
        struct mutex av_mutex;
+       int audio_power_refcount;
 
        struct {
                struct mutex mutex;
 
        }
 }
 
+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 unsigned long i915_audio_component_get_power(struct device *kdev)
 {
+       struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
+       intel_wakeref_t ret;
+
        /* Catch potential impedance mismatches before they occur! */
        BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long));
 
-       return intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
+       ret = intel_display_power_get(dev_priv, 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);
+
+       return ret;
 }
 
 static void i915_audio_component_put_power(struct device *kdev,
                                           unsigned long cookie)
 {
-       intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO, cookie);
+       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(dev_priv, POWER_DOMAIN_AUDIO, cookie);
 }
 
 static void i915_audio_component_codec_wake_override(struct device *kdev,
 
        /*
         * According to BSpec, "The CD clock frequency must be at least twice
         * the frequency of the Azalia BCLK." and BCLK is 96 MHz by default.
-        *
-        * FIXME: Check the actual, not default, BCLK being used.
-        *
-        * FIXME: This does not depend on ->has_audio because the higher CDCLK
-        * is required for audio probe, also when there are no audio capable
-        * displays connected at probe time. This leads to unnecessarily high
-        * CDCLK when audio is not required.
-        *
-        * FIXME: This limit is only applied when there are displays connected
-        * at probe time. If we probe without displays, we'll still end up using
-        * the platform minimum CDCLK, failing audio probe.
         */
-       if (INTEL_GEN(dev_priv) >= 9)
+       if (crtc_state->has_audio && INTEL_GEN(dev_priv) >= 9)
                min_cdclk = max(2 * 96000, min_cdclk);
 
        /*
                intel_state->min_cdclk[i] = min_cdclk;
        }
 
-       min_cdclk = 0;
+       min_cdclk = intel_state->cdclk.force_min_cdclk;
        for_each_pipe(dev_priv, pipe)
                min_cdclk = max(intel_state->min_cdclk[pipe], min_cdclk);
 
                vlv_calc_voltage_level(dev_priv, cdclk);
 
        if (!intel_state->active_crtcs) {
-               cdclk = vlv_calc_cdclk(dev_priv, 0);
+               cdclk = vlv_calc_cdclk(dev_priv,
+                                      intel_state->cdclk.force_min_cdclk);
 
                intel_state->cdclk.actual.cdclk = cdclk;
                intel_state->cdclk.actual.voltage_level =
                bdw_calc_voltage_level(cdclk);
 
        if (!intel_state->active_crtcs) {
-               cdclk = bdw_calc_cdclk(0);
+               cdclk = bdw_calc_cdclk(intel_state->cdclk.force_min_cdclk);
 
                intel_state->cdclk.actual.cdclk = cdclk;
                intel_state->cdclk.actual.voltage_level =
                skl_calc_voltage_level(cdclk);
 
        if (!intel_state->active_crtcs) {
-               cdclk = skl_calc_cdclk(0, vco);
+               cdclk = skl_calc_cdclk(intel_state->cdclk.force_min_cdclk, vco);
 
                intel_state->cdclk.actual.vco = vco;
                intel_state->cdclk.actual.cdclk = cdclk;
 
        if (!intel_state->active_crtcs) {
                if (IS_GEMINILAKE(dev_priv)) {
-                       cdclk = glk_calc_cdclk(0);
+                       cdclk = glk_calc_cdclk(intel_state->cdclk.force_min_cdclk);
                        vco = glk_de_pll_vco(dev_priv, cdclk);
                } else {
-                       cdclk = bxt_calc_cdclk(0);
+                       cdclk = bxt_calc_cdclk(intel_state->cdclk.force_min_cdclk);
                        vco = bxt_de_pll_vco(dev_priv, cdclk);
                }
 
                    cnl_compute_min_voltage_level(intel_state));
 
        if (!intel_state->active_crtcs) {
-               cdclk = cnl_calc_cdclk(0);
+               cdclk = cnl_calc_cdclk(intel_state->cdclk.force_min_cdclk);
                vco = cnl_cdclk_pll_vco(dev_priv, cdclk);
 
                intel_state->cdclk.actual.vco = vco;
                    cnl_compute_min_voltage_level(intel_state));
 
        if (!intel_state->active_crtcs) {
-               cdclk = icl_calc_cdclk(0, ref);
+               cdclk = icl_calc_cdclk(intel_state->cdclk.force_min_cdclk, ref);
                vco = icl_calc_cdclk_pll_vco(dev_priv, cdclk);
 
                intel_state->cdclk.actual.vco = vco;
 
                return -EINVAL;
        }
 
+       /* keep the current setting */
+       if (!intel_state->cdclk.force_min_cdclk_changed)
+               intel_state->cdclk.force_min_cdclk =
+                       dev_priv->cdclk.force_min_cdclk;
+
        intel_state->modeset = true;
        intel_state->active_crtcs = dev_priv->active_crtcs;
        intel_state->cdclk.logical = dev_priv->cdclk.logical;
        struct drm_crtc *crtc;
        struct drm_crtc_state *old_crtc_state, *crtc_state;
        int ret, i;
-       bool any_ms = false;
+       bool any_ms = intel_state->cdclk.force_min_cdclk_changed;
 
        /* Catch I915_MODE_FLAG_INHERITED */
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
                dev_priv->active_crtcs = intel_state->active_crtcs;
                dev_priv->cdclk.logical = intel_state->cdclk.logical;
                dev_priv->cdclk.actual = intel_state->cdclk.actual;
+               dev_priv->cdclk.force_min_cdclk =
+                       intel_state->cdclk.force_min_cdclk;
        }
 
        drm_atomic_state_get(state);
 
                 * state only when all crtc's are DPMS off.
                 */
                struct intel_cdclk_state actual;
+
+               int force_min_cdclk;
+               bool force_min_cdclk_changed;
        } cdclk;
 
        bool dpll_set, modeset;