aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_pm.c
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2013-11-25 10:15:29 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-11-26 14:04:59 -0500
commitc1ca727f89450cbc560af93045d57a186b83b0dc (patch)
treeb06bab5a952b0d16fed0f280898ed141edcb08e2 /drivers/gpu/drm/i915/intel_pm.c
parentfbeeaa2306fcff7614c8b41b420a400503b6d28e (diff)
drm/i915: support for multiple power wells
HW generations so far had only one always-on power well and optionally one dynamic power well. Upcoming HW gens may have multiple dynamic power wells, so add some infrastructure to support them. The idea is to keep the existing power domain API used by the rest of the driver and create a mapping between these power domains and the underlying power wells. This mapping can differ from one HW to another but high level driver code doesn't need to know about this. Through the existing get/put API it would just ask for a given power domain and the power domain framework would make sure the relevant power wells get enabled in the right order. Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Paulo Zanoni <paulo.zanoni@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c116
1 files changed, 99 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 8f472daa2793..2b3173415212 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -5627,15 +5627,41 @@ static bool is_always_on_power_domain(struct drm_device *dev,
5627 return BIT(domain) & always_on_domains; 5627 return BIT(domain) & always_on_domains;
5628} 5628}
5629 5629
5630#define for_each_power_well(i, power_well, domain_mask, power_domains) \
5631 for (i = 0; \
5632 i < (power_domains)->power_well_count && \
5633 ((power_well) = &(power_domains)->power_wells[i]); \
5634 i++) \
5635 if ((power_well)->domains & (domain_mask))
5636
5637#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
5638 for (i = (power_domains)->power_well_count - 1; \
5639 i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
5640 i--) \
5641 if ((power_well)->domains & (domain_mask))
5642
5630/** 5643/**
5631 * We should only use the power well if we explicitly asked the hardware to 5644 * We should only use the power well if we explicitly asked the hardware to
5632 * enable it, so check if it's enabled and also check if we've requested it to 5645 * enable it, so check if it's enabled and also check if we've requested it to
5633 * be enabled. 5646 * be enabled.
5634 */ 5647 */
5648static bool hsw_power_well_enabled(struct drm_device *dev,
5649 struct i915_power_well *power_well)
5650{
5651 struct drm_i915_private *dev_priv = dev->dev_private;
5652
5653 return I915_READ(HSW_PWR_WELL_DRIVER) ==
5654 (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
5655}
5656
5635bool intel_display_power_enabled(struct drm_device *dev, 5657bool intel_display_power_enabled(struct drm_device *dev,
5636 enum intel_display_power_domain domain) 5658 enum intel_display_power_domain domain)
5637{ 5659{
5638 struct drm_i915_private *dev_priv = dev->dev_private; 5660 struct drm_i915_private *dev_priv = dev->dev_private;
5661 struct i915_power_domains *power_domains;
5662 struct i915_power_well *power_well;
5663 bool is_enabled;
5664 int i;
5639 5665
5640 if (!HAS_POWER_WELL(dev)) 5666 if (!HAS_POWER_WELL(dev))
5641 return true; 5667 return true;
@@ -5643,11 +5669,24 @@ bool intel_display_power_enabled(struct drm_device *dev,
5643 if (is_always_on_power_domain(dev, domain)) 5669 if (is_always_on_power_domain(dev, domain))
5644 return true; 5670 return true;
5645 5671
5646 return I915_READ(HSW_PWR_WELL_DRIVER) == 5672 power_domains = &dev_priv->power_domains;
5647 (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); 5673
5674 is_enabled = true;
5675
5676 mutex_lock(&power_domains->lock);
5677 for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
5678 if (!power_well->is_enabled(dev, power_well)) {
5679 is_enabled = false;
5680 break;
5681 }
5682 }
5683 mutex_unlock(&power_domains->lock);
5684
5685 return is_enabled;
5648} 5686}
5649 5687
5650static void __intel_set_power_well(struct drm_device *dev, bool enable) 5688static void hsw_set_power_well(struct drm_device *dev,
5689 struct i915_power_well *power_well, bool enable)
5651{ 5690{
5652 struct drm_i915_private *dev_priv = dev->dev_private; 5691 struct drm_i915_private *dev_priv = dev->dev_private;
5653 bool is_enabled, enable_requested; 5692 bool is_enabled, enable_requested;
@@ -5713,16 +5752,17 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
5713static void __intel_power_well_get(struct drm_device *dev, 5752static void __intel_power_well_get(struct drm_device *dev,
5714 struct i915_power_well *power_well) 5753 struct i915_power_well *power_well)
5715{ 5754{
5716 if (!power_well->count++) 5755 if (!power_well->count++ && power_well->set)
5717 __intel_set_power_well(dev, true); 5756 power_well->set(dev, power_well, true);
5718} 5757}
5719 5758
5720static void __intel_power_well_put(struct drm_device *dev, 5759static void __intel_power_well_put(struct drm_device *dev,
5721 struct i915_power_well *power_well) 5760 struct i915_power_well *power_well)
5722{ 5761{
5723 WARN_ON(!power_well->count); 5762 WARN_ON(!power_well->count);
5724 if (!--power_well->count && i915_disable_power_well) 5763
5725 __intel_set_power_well(dev, false); 5764 if (!--power_well->count && power_well->set && i915_disable_power_well)
5765 power_well->set(dev, power_well, false);
5726} 5766}
5727 5767
5728void intel_display_power_get(struct drm_device *dev, 5768void intel_display_power_get(struct drm_device *dev,
@@ -5730,6 +5770,8 @@ void intel_display_power_get(struct drm_device *dev,
5730{ 5770{
5731 struct drm_i915_private *dev_priv = dev->dev_private; 5771 struct drm_i915_private *dev_priv = dev->dev_private;
5732 struct i915_power_domains *power_domains; 5772 struct i915_power_domains *power_domains;
5773 struct i915_power_well *power_well;
5774 int i;
5733 5775
5734 if (!HAS_POWER_WELL(dev)) 5776 if (!HAS_POWER_WELL(dev))
5735 return; 5777 return;
@@ -5740,7 +5782,8 @@ void intel_display_power_get(struct drm_device *dev,
5740 power_domains = &dev_priv->power_domains; 5782 power_domains = &dev_priv->power_domains;
5741 5783
5742 mutex_lock(&power_domains->lock); 5784 mutex_lock(&power_domains->lock);
5743 __intel_power_well_get(dev, &power_domains->power_wells[0]); 5785 for_each_power_well(i, power_well, BIT(domain), power_domains)
5786 __intel_power_well_get(dev, power_well);
5744 mutex_unlock(&power_domains->lock); 5787 mutex_unlock(&power_domains->lock);
5745} 5788}
5746 5789
@@ -5749,6 +5792,8 @@ void intel_display_power_put(struct drm_device *dev,
5749{ 5792{
5750 struct drm_i915_private *dev_priv = dev->dev_private; 5793 struct drm_i915_private *dev_priv = dev->dev_private;
5751 struct i915_power_domains *power_domains; 5794 struct i915_power_domains *power_domains;
5795 struct i915_power_well *power_well;
5796 int i;
5752 5797
5753 if (!HAS_POWER_WELL(dev)) 5798 if (!HAS_POWER_WELL(dev))
5754 return; 5799 return;
@@ -5759,7 +5804,8 @@ void intel_display_power_put(struct drm_device *dev,
5759 power_domains = &dev_priv->power_domains; 5804 power_domains = &dev_priv->power_domains;
5760 5805
5761 mutex_lock(&power_domains->lock); 5806 mutex_lock(&power_domains->lock);
5762 __intel_power_well_put(dev, &power_domains->power_wells[0]); 5807 for_each_power_well_rev(i, power_well, BIT(domain), power_domains)
5808 __intel_power_well_put(dev, power_well);
5763 mutex_unlock(&power_domains->lock); 5809 mutex_unlock(&power_domains->lock);
5764} 5810}
5765 5811
@@ -5793,17 +5839,52 @@ void i915_release_power_well(void)
5793} 5839}
5794EXPORT_SYMBOL_GPL(i915_release_power_well); 5840EXPORT_SYMBOL_GPL(i915_release_power_well);
5795 5841
5842static struct i915_power_well hsw_power_wells[] = {
5843 {
5844 .name = "display",
5845 .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS,
5846 .is_enabled = hsw_power_well_enabled,
5847 .set = hsw_set_power_well,
5848 },
5849};
5850
5851static struct i915_power_well bdw_power_wells[] = {
5852 {
5853 .name = "display",
5854 .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS,
5855 .is_enabled = hsw_power_well_enabled,
5856 .set = hsw_set_power_well,
5857 },
5858};
5859
5860#define set_power_wells(power_domains, __power_wells) ({ \
5861 (power_domains)->power_wells = (__power_wells); \
5862 (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
5863})
5864
5796int intel_power_domains_init(struct drm_device *dev) 5865int intel_power_domains_init(struct drm_device *dev)
5797{ 5866{
5798 struct drm_i915_private *dev_priv = dev->dev_private; 5867 struct drm_i915_private *dev_priv = dev->dev_private;
5799 struct i915_power_domains *power_domains = &dev_priv->power_domains; 5868 struct i915_power_domains *power_domains = &dev_priv->power_domains;
5800 struct i915_power_well *power_well; 5869
5870 if (!HAS_POWER_WELL(dev))
5871 return 0;
5801 5872
5802 mutex_init(&power_domains->lock); 5873 mutex_init(&power_domains->lock);
5803 hsw_pwr = power_domains;
5804 5874
5805 power_well = &power_domains->power_wells[0]; 5875 /*
5806 power_well->count = 0; 5876 * The enabling order will be from lower to higher indexed wells,
5877 * the disabling order is reversed.
5878 */
5879 if (IS_HASWELL(dev)) {
5880 set_power_wells(power_domains, hsw_power_wells);
5881 hsw_pwr = power_domains;
5882 } else if (IS_BROADWELL(dev)) {
5883 set_power_wells(power_domains, bdw_power_wells);
5884 hsw_pwr = power_domains;
5885 } else {
5886 WARN_ON(1);
5887 }
5807 5888
5808 return 0; 5889 return 0;
5809} 5890}
@@ -5818,15 +5899,16 @@ static void intel_power_domains_resume(struct drm_device *dev)
5818 struct drm_i915_private *dev_priv = dev->dev_private; 5899 struct drm_i915_private *dev_priv = dev->dev_private;
5819 struct i915_power_domains *power_domains = &dev_priv->power_domains; 5900 struct i915_power_domains *power_domains = &dev_priv->power_domains;
5820 struct i915_power_well *power_well; 5901 struct i915_power_well *power_well;
5902 int i;
5821 5903
5822 if (!HAS_POWER_WELL(dev)) 5904 if (!HAS_POWER_WELL(dev))
5823 return; 5905 return;
5824 5906
5825 mutex_lock(&power_domains->lock); 5907 mutex_lock(&power_domains->lock);
5826 5908 for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
5827 power_well = &power_domains->power_wells[0]; 5909 if (power_well->set)
5828 __intel_set_power_well(dev, power_well->count > 0); 5910 power_well->set(dev, power_well, power_well->count > 0);
5829 5911 }
5830 mutex_unlock(&power_domains->lock); 5912 mutex_unlock(&power_domains->lock);
5831} 5913}
5832 5914