/* Start out suspended */
        dev_priv->mm.suspended = 1;
 
+       if (HAS_POWER_WELL(dev))
+               i915_init_power_well(dev);
+
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev);
                if (ret < 0) {
 
        intel_gpu_ips_teardown();
 
+       if (HAS_POWER_WELL(dev))
+               i915_remove_power_well(dev);
+
        i915_teardown_sysfs(dev);
 
        if (dev_priv->mm.inactive_shrinker.shrink)
 
        struct drm_i915_gem_object *renderctx;
 };
 
+/* Power well structure for haswell */
+struct i915_power_well {
+       struct drm_device *device;
+       spinlock_t lock;
+       /* power well enable/disable usage count */
+       int count;
+       int i915_request;
+};
+
 struct i915_dri1_state {
        unsigned allow_batchbuffer : 1;
        u32 __iomem *gfx_hws_cpu_addr;
         * mchdev_lock in intel_pm.c */
        struct intel_ilk_power_mgmt ips;
 
+       /* Haswell power well */
+       struct i915_power_well power_well;
+
        enum no_fbc_reason no_fbc_reason;
 
        struct drm_mm_node *compressed_fb;
 
 extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
 extern void intel_gpu_ips_teardown(void);
 
+/* Power well */
+extern int i915_init_power_well(struct drm_device *dev);
+extern void i915_remove_power_well(struct drm_device *dev);
+
 extern bool intel_display_power_enabled(struct drm_device *dev,
                                        enum intel_display_power_domain domain);
 extern void intel_init_power_well(struct drm_device *dev);
 
        }
 }
 
-void intel_set_power_well(struct drm_device *dev, bool enable)
+static void __intel_set_power_well(struct drm_device *dev, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        bool is_enabled, enable_requested;
        uint32_t tmp;
 
-       if (!HAS_POWER_WELL(dev))
-               return;
-
-       if (!i915_disable_power_well && !enable)
-               return;
-
        tmp = I915_READ(HSW_PWR_WELL_DRIVER);
        is_enabled = tmp & HSW_PWR_WELL_STATE;
        enable_requested = tmp & HSW_PWR_WELL_ENABLE;
        }
 }
 
+static struct i915_power_well *hsw_pwr;
+
+/* Display audio driver power well request */
+void i915_request_power_well(void)
+{
+       if (WARN_ON(!hsw_pwr))
+               return;
+
+       spin_lock_irq(&hsw_pwr->lock);
+       if (!hsw_pwr->count++ &&
+                       !hsw_pwr->i915_request)
+               __intel_set_power_well(hsw_pwr->device, true);
+       spin_unlock_irq(&hsw_pwr->lock);
+}
+EXPORT_SYMBOL_GPL(i915_request_power_well);
+
+/* Display audio driver power well release */
+void i915_release_power_well(void)
+{
+       if (WARN_ON(!hsw_pwr))
+               return;
+
+       spin_lock_irq(&hsw_pwr->lock);
+       WARN_ON(!hsw_pwr->count);
+       if (!--hsw_pwr->count &&
+                      !hsw_pwr->i915_request)
+               __intel_set_power_well(hsw_pwr->device, false);
+       spin_unlock_irq(&hsw_pwr->lock);
+}
+EXPORT_SYMBOL_GPL(i915_release_power_well);
+
+int i915_init_power_well(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       hsw_pwr = &dev_priv->power_well;
+
+       hsw_pwr->device = dev;
+       spin_lock_init(&hsw_pwr->lock);
+       hsw_pwr->count = 0;
+
+       return 0;
+}
+
+void i915_remove_power_well(struct drm_device *dev)
+{
+       hsw_pwr = NULL;
+}
+
+void intel_set_power_well(struct drm_device *dev, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_power_well *power_well = &dev_priv->power_well;
+
+       if (!HAS_POWER_WELL(dev))
+               return;
+
+       if (!i915_disable_power_well && !enable)
+               return;
+
+       spin_lock_irq(&power_well->lock);
+       power_well->i915_request = enable;
+
+       /* only reject "disable" power well request */
+       if (power_well->count && !enable) {
+               spin_unlock_irq(&power_well->lock);
+               return;
+       }
+
+       __intel_set_power_well(dev, enable);
+       spin_unlock_irq(&power_well->lock);
+}
+
 /*
  * Starting with Haswell, we have a "Power Down Well" that can be turned off
  * when not needed anymore. We have 4 registers that can request the power well
 
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2013 Intel Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+
+#ifndef _I915_POWERWELL_H_
+#define _I915_POWERWELL_H_
+
+/* For use by hda_i915 driver */
+extern void i915_request_power_well(void);
+extern void i915_release_power_well(void);
+
+#endif                         /* _I915_POWERWELL_H_ */