| From 9466381b07a964c686d678d34ebc6079d3f5025c Mon Sep 17 00:00:00 2001 |
| From: Wang Xingchao <xingchao.wang@linux.intel.com> |
| Date: Thu, 30 May 2013 22:07:11 +0800 |
| Subject: 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> |
| (cherry picked from commit a38911a3fede294e2adfd2deea8104dfbbd760c5) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_dma.c | 6 ++ |
| drivers/gpu/drm/i915/i915_drv.h | 12 +++++ |
| drivers/gpu/drm/i915/intel_drv.h | 4 + |
| drivers/gpu/drm/i915/intel_pm.c | 81 +++++++++++++++++++++++++++++++++++---- |
| include/drm/i915_powerwell.h | 36 +++++++++++++++++ |
| 5 files changed, 132 insertions(+), 7 deletions(-) |
| create mode 100644 include/drm/i915_powerwell.h |
| |
| --- a/drivers/gpu/drm/i915/i915_dma.c |
| +++ b/drivers/gpu/drm/i915/i915_dma.c |
| @@ -1642,6 +1642,9 @@ int i915_driver_load(struct drm_device * |
| /* 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) { |
| @@ -1694,6 +1697,9 @@ int i915_driver_unload(struct drm_device |
| |
| 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) |
| --- a/drivers/gpu/drm/i915/i915_drv.h |
| +++ b/drivers/gpu/drm/i915/i915_drv.h |
| @@ -741,6 +741,15 @@ struct intel_ilk_power_mgmt { |
| 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; |
| @@ -1100,6 +1109,9 @@ typedef struct drm_i915_private { |
| * 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; |
| --- 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_ |
| 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); |
| --- 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 |
| } |
| } |
| |
| -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; |
| @@ -5058,6 +5052,79 @@ void intel_set_power_well(struct drm_dev |
| } |
| } |
| |
| +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 |
| +++ b/include/drm/i915_powerwell.h |
| @@ -0,0 +1,36 @@ |
| +/************************************************************************** |
| + * |
| + * 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_ */ |