aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Xingchao <xingchao.wang@linux.intel.com>2013-05-30 10:07:11 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-06-06 11:32:16 -0400
commita38911a3fede294e2adfd2deea8104dfbbd760c5 (patch)
tree9262c62e16108554fb626cb04189d17e449bb938
parent99a2008d0b32d72dfc2a54e7be1eb698dd2e3bd6 (diff)
i915/drm: Add private api for power well usage
Haswell Display audio depends on power well in graphic side, it should request power well before use it and release power well after use. I915 will not shutdown power well if it detects audio is using. This patch protects display audio crash for Intel Haswell C3 stepping board. Signed-off-by: Wang Xingchao <xingchao.wang@linux.intel.com> Reviewed-by: Takashi Iwai <tiwai@suse.de> Reviewed-by: Damien Lespiau <damien.lespiau@intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c6
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h12
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h4
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c81
-rw-r--r--include/drm/i915_powerwell.h36
5 files changed, 132 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 22534c3b4fe5..fd8898c8f8e3 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1656,6 +1656,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1656 /* Start out suspended */ 1656 /* Start out suspended */
1657 dev_priv->mm.suspended = 1; 1657 dev_priv->mm.suspended = 1;
1658 1658
1659 if (HAS_POWER_WELL(dev))
1660 i915_init_power_well(dev);
1661
1659 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 1662 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
1660 ret = i915_load_modeset_init(dev); 1663 ret = i915_load_modeset_init(dev);
1661 if (ret < 0) { 1664 if (ret < 0) {
@@ -1712,6 +1715,9 @@ int i915_driver_unload(struct drm_device *dev)
1712 1715
1713 intel_gpu_ips_teardown(); 1716 intel_gpu_ips_teardown();
1714 1717
1718 if (HAS_POWER_WELL(dev))
1719 i915_remove_power_well(dev);
1720
1715 i915_teardown_sysfs(dev); 1721 i915_teardown_sysfs(dev);
1716 1722
1717 if (dev_priv->mm.inactive_shrinker.shrink) 1723 if (dev_priv->mm.inactive_shrinker.shrink)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 215aa63e3f47..87f7f88b1030 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -740,6 +740,15 @@ struct intel_ilk_power_mgmt {
740 struct drm_i915_gem_object *renderctx; 740 struct drm_i915_gem_object *renderctx;
741}; 741};
742 742
743/* Power well structure for haswell */
744struct i915_power_well {
745 struct drm_device *device;
746 spinlock_t lock;
747 /* power well enable/disable usage count */
748 int count;
749 int i915_request;
750};
751
743struct i915_dri1_state { 752struct i915_dri1_state {
744 unsigned allow_batchbuffer : 1; 753 unsigned allow_batchbuffer : 1;
745 u32 __iomem *gfx_hws_cpu_addr; 754 u32 __iomem *gfx_hws_cpu_addr;
@@ -1099,6 +1108,9 @@ typedef struct drm_i915_private {
1099 * mchdev_lock in intel_pm.c */ 1108 * mchdev_lock in intel_pm.c */
1100 struct intel_ilk_power_mgmt ips; 1109 struct intel_ilk_power_mgmt ips;
1101 1110
1111 /* Haswell power well */
1112 struct i915_power_well power_well;
1113
1102 enum no_fbc_reason no_fbc_reason; 1114 enum no_fbc_reason no_fbc_reason;
1103 1115
1104 struct drm_mm_node *compressed_fb; 1116 struct drm_mm_node *compressed_fb;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6bbebf824078..1735cdc86770 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -768,6 +768,10 @@ extern void intel_update_fbc(struct drm_device *dev);
768extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); 768extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
769extern void intel_gpu_ips_teardown(void); 769extern void intel_gpu_ips_teardown(void);
770 770
771/* Power well */
772extern int i915_init_power_well(struct drm_device *dev);
773extern void i915_remove_power_well(struct drm_device *dev);
774
771extern bool intel_display_power_enabled(struct drm_device *dev, 775extern bool intel_display_power_enabled(struct drm_device *dev,
772 enum intel_display_power_domain domain); 776 enum intel_display_power_domain domain);
773extern void intel_init_power_well(struct drm_device *dev); 777extern void intel_init_power_well(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1e1b48ec6c46..a417d7b196c2 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -5024,18 +5024,12 @@ bool intel_display_power_enabled(struct drm_device *dev,
5024 } 5024 }
5025} 5025}
5026 5026
5027void intel_set_power_well(struct drm_device *dev, bool enable) 5027static void __intel_set_power_well(struct drm_device *dev, bool enable)
5028{ 5028{
5029 struct drm_i915_private *dev_priv = dev->dev_private; 5029 struct drm_i915_private *dev_priv = dev->dev_private;
5030 bool is_enabled, enable_requested; 5030 bool is_enabled, enable_requested;
5031 uint32_t tmp; 5031 uint32_t tmp;
5032 5032
5033 if (!HAS_POWER_WELL(dev))
5034 return;
5035
5036 if (!i915_disable_power_well && !enable)
5037 return;
5038
5039 tmp = I915_READ(HSW_PWR_WELL_DRIVER); 5033 tmp = I915_READ(HSW_PWR_WELL_DRIVER);
5040 is_enabled = tmp & HSW_PWR_WELL_STATE; 5034 is_enabled = tmp & HSW_PWR_WELL_STATE;
5041 enable_requested = tmp & HSW_PWR_WELL_ENABLE; 5035 enable_requested = tmp & HSW_PWR_WELL_ENABLE;
@@ -5058,6 +5052,79 @@ void intel_set_power_well(struct drm_device *dev, bool enable)
5058 } 5052 }
5059} 5053}
5060 5054
5055static struct i915_power_well *hsw_pwr;
5056
5057/* Display audio driver power well request */
5058void i915_request_power_well(void)
5059{
5060 if (WARN_ON(!hsw_pwr))
5061 return;
5062
5063 spin_lock_irq(&hsw_pwr->lock);
5064 if (!hsw_pwr->count++ &&
5065 !hsw_pwr->i915_request)
5066 __intel_set_power_well(hsw_pwr->device, true);
5067 spin_unlock_irq(&hsw_pwr->lock);
5068}
5069EXPORT_SYMBOL_GPL(i915_request_power_well);
5070
5071/* Display audio driver power well release */
5072void i915_release_power_well(void)
5073{
5074 if (WARN_ON(!hsw_pwr))
5075 return;
5076
5077 spin_lock_irq(&hsw_pwr->lock);
5078 WARN_ON(!hsw_pwr->count);
5079 if (!--hsw_pwr->count &&
5080 !hsw_pwr->i915_request)
5081 __intel_set_power_well(hsw_pwr->device, false);
5082 spin_unlock_irq(&hsw_pwr->lock);
5083}
5084EXPORT_SYMBOL_GPL(i915_release_power_well);
5085
5086int i915_init_power_well(struct drm_device *dev)
5087{
5088 struct drm_i915_private *dev_priv = dev->dev_private;
5089
5090 hsw_pwr = &dev_priv->power_well;
5091
5092 hsw_pwr->device = dev;
5093 spin_lock_init(&hsw_pwr->lock);
5094 hsw_pwr->count = 0;
5095
5096 return 0;
5097}
5098
5099void i915_remove_power_well(struct drm_device *dev)
5100{
5101 hsw_pwr = NULL;
5102}
5103
5104void intel_set_power_well(struct drm_device *dev, bool enable)
5105{
5106 struct drm_i915_private *dev_priv = dev->dev_private;
5107 struct i915_power_well *power_well = &dev_priv->power_well;
5108
5109 if (!HAS_POWER_WELL(dev))
5110 return;
5111
5112 if (!i915_disable_power_well && !enable)
5113 return;
5114
5115 spin_lock_irq(&power_well->lock);
5116 power_well->i915_request = enable;
5117
5118 /* only reject "disable" power well request */
5119 if (power_well->count && !enable) {
5120 spin_unlock_irq(&power_well->lock);
5121 return;
5122 }
5123
5124 __intel_set_power_well(dev, enable);
5125 spin_unlock_irq(&power_well->lock);
5126}
5127
5061/* 5128/*
5062 * Starting with Haswell, we have a "Power Down Well" that can be turned off 5129 * Starting with Haswell, we have a "Power Down Well" that can be turned off
5063 * when not needed anymore. We have 4 registers that can request the power well 5130 * when not needed anymore. We have 4 registers that can request the power well
diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h
new file mode 100644
index 000000000000..cfdc884405b7
--- /dev/null
+++ b/include/drm/i915_powerwell.h
@@ -0,0 +1,36 @@
1/**************************************************************************
2 *
3 * Copyright 2013 Intel Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 *
27 **************************************************************************/
28
29#ifndef _I915_POWERWELL_H_
30#define _I915_POWERWELL_H_
31
32/* For use by hda_i915 driver */
33extern void i915_request_power_well(void);
34extern void i915_release_power_well(void);
35
36#endif /* _I915_POWERWELL_H_ */