[Intel-gfx] [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c
Imre Deak
imre.deak at intel.com
Tue Sep 30 14:22:09 CEST 2014
On Tue, 2014-09-30 at 10:56 +0200, Daniel Vetter wrote:
> Geez is the audio hack ugly.
>
> Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
Looks ok, but needs to be rebased on
commit 08524a9ffa396c56ff3fbec9cfd80edd3fa6a058
Author: Satheeshakrishna M <satheeshakrishna.m at intel.com>
Date: Tue Apr 8 15:46:56 2014 +0530
drm/i915/skl: Restore pipe B/C interrupts
> ---
> drivers/gpu/drm/i915/Makefile | 4 +-
> drivers/gpu/drm/i915/intel_drv.h | 39 +-
> drivers/gpu/drm/i915/intel_pm.c | 1158 ------------------------------
> drivers/gpu/drm/i915/intel_runtime_pm.c | 1190 +++++++++++++++++++++++++++++++
> 4 files changed, 1214 insertions(+), 1177 deletions(-)
> create mode 100644 drivers/gpu/drm/i915/intel_runtime_pm.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 2d8317d36e09..3a6bce047f6f 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -11,7 +11,9 @@ i915-y := i915_drv.o \
> i915_params.o \
> i915_suspend.o \
> i915_sysfs.o \
> - intel_pm.o
> + intel_pm.o \
> + intel_runtime_pm.o
> +
> i915-$(CONFIG_COMPAT) += i915_ioc32.o
> i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 617126786819..a963dd870994 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1073,6 +1073,27 @@ extern struct drm_display_mode *intel_find_panel_downclock(
> struct drm_display_mode *fixed_mode,
> struct drm_connector *connector);
>
> +/* intel_runtime_pm.c */
> +int intel_power_domains_init(struct drm_i915_private *);
> +void intel_power_domains_remove(struct drm_i915_private *);
> +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
> +void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
> +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
> +
> +bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain);
> +bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain);
> +void intel_display_power_get(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain);
> +void intel_display_power_put(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain);
> +void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
> +void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
> +void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
> +void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
> +void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
> +
> /* intel_pm.c */
> void intel_init_clock_gating(struct drm_device *dev);
> void intel_suspend_hw(struct drm_device *dev);
> @@ -1090,17 +1111,6 @@ bool intel_fbc_enabled(struct drm_device *dev);
> void intel_update_fbc(struct drm_device *dev);
> void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
> void intel_gpu_ips_teardown(void);
> -int intel_power_domains_init(struct drm_i915_private *);
> -void intel_power_domains_remove(struct drm_i915_private *);
> -bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain);
> -bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain);
> -void intel_display_power_get(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain);
> -void intel_display_power_put(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain);
> -void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
> void intel_init_gt_powersave(struct drm_device *dev);
> void intel_cleanup_gt_powersave(struct drm_device *dev);
> void intel_enable_gt_powersave(struct drm_device *dev);
> @@ -1111,13 +1121,6 @@ void ironlake_teardown_rc6(struct drm_device *dev);
> void gen6_update_ring_freq(struct drm_device *dev);
> void gen6_rps_idle(struct drm_i915_private *dev_priv);
> void gen6_rps_boost(struct drm_i915_private *dev_priv);
> -void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
> -void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
> -void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
> -void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
> -void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
> -void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
> -void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
> void ilk_wm_get_hw_state(struct drm_device *dev);
>
>
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 6b416201240f..06c1ea0a7bfd 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -30,9 +30,6 @@
> #include "intel_drv.h"
> #include "../../../platform/x86/intel_ips.h"
> #include <linux/module.h>
> -#include <linux/vgaarb.h>
> -#include <drm/i915_powerwell.h>
> -#include <linux/pm_runtime.h>
>
> /**
> * RC6 is a special power stage which allows the GPU to enter an very
> @@ -6206,1162 +6203,7 @@ void intel_suspend_hw(struct drm_device *dev)
> lpt_suspend_hw(dev);
> }
>
> -#define for_each_power_well(i, power_well, domain_mask, power_domains) \
> - for (i = 0; \
> - i < (power_domains)->power_well_count && \
> - ((power_well) = &(power_domains)->power_wells[i]); \
> - i++) \
> - if ((power_well)->domains & (domain_mask))
>
> -#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
> - for (i = (power_domains)->power_well_count - 1; \
> - i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
> - i--) \
> - if ((power_well)->domains & (domain_mask))
> -
> -/**
> - * We should only use the power well if we explicitly asked the hardware to
> - * enable it, so check if it's enabled and also check if we've requested it to
> - * be enabled.
> - */
> -static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - return I915_READ(HSW_PWR_WELL_DRIVER) ==
> - (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
> -}
> -
> -bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain)
> -{
> - struct i915_power_domains *power_domains;
> - struct i915_power_well *power_well;
> - bool is_enabled;
> - int i;
> -
> - if (dev_priv->pm.suspended)
> - return false;
> -
> - power_domains = &dev_priv->power_domains;
> -
> - is_enabled = true;
> -
> - for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
> - if (power_well->always_on)
> - continue;
> -
> - if (!power_well->hw_enabled) {
> - is_enabled = false;
> - break;
> - }
> - }
> -
> - return is_enabled;
> -}
> -
> -bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain)
> -{
> - struct i915_power_domains *power_domains;
> - bool ret;
> -
> - power_domains = &dev_priv->power_domains;
> -
> - mutex_lock(&power_domains->lock);
> - ret = intel_display_power_enabled_unlocked(dev_priv, domain);
> - mutex_unlock(&power_domains->lock);
> -
> - return ret;
> -}
> -
> -/*
> - * 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
> - * to be enabled, and it will only be disabled if none of the registers is
> - * requesting it to be enabled.
> - */
> -static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> -
> - /*
> - * After we re-enable the power well, if we touch VGA register 0x3d5
> - * we'll get unclaimed register interrupts. This stops after we write
> - * anything to the VGA MSR register. The vgacon module uses this
> - * register all the time, so if we unbind our driver and, as a
> - * consequence, bind vgacon, we'll get stuck in an infinite loop at
> - * console_unlock(). So make here we touch the VGA MSR register, making
> - * sure vgacon can keep working normally without triggering interrupts
> - * and error messages.
> - */
> - vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
> - outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
> - vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
> -
> - if (IS_BROADWELL(dev))
> - gen8_irq_power_well_post_enable(dev_priv);
> -}
> -
> -static void hsw_set_power_well(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well, bool enable)
> -{
> - bool is_enabled, enable_requested;
> - uint32_t tmp;
> -
> - tmp = I915_READ(HSW_PWR_WELL_DRIVER);
> - is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
> - enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
> -
> - if (enable) {
> - if (!enable_requested)
> - I915_WRITE(HSW_PWR_WELL_DRIVER,
> - HSW_PWR_WELL_ENABLE_REQUEST);
> -
> - if (!is_enabled) {
> - DRM_DEBUG_KMS("Enabling power well\n");
> - if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
> - HSW_PWR_WELL_STATE_ENABLED), 20))
> - DRM_ERROR("Timeout enabling power well\n");
> - }
> -
> - hsw_power_well_post_enable(dev_priv);
> - } else {
> - if (enable_requested) {
> - I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
> - POSTING_READ(HSW_PWR_WELL_DRIVER);
> - DRM_DEBUG_KMS("Requesting to disable the power well\n");
> - }
> - }
> -}
> -
> -static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - hsw_set_power_well(dev_priv, power_well, power_well->count > 0);
> -
> - /*
> - * We're taking over the BIOS, so clear any requests made by it since
> - * the driver is in charge now.
> - */
> - if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
> - I915_WRITE(HSW_PWR_WELL_BIOS, 0);
> -}
> -
> -static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - hsw_set_power_well(dev_priv, power_well, true);
> -}
> -
> -static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - hsw_set_power_well(dev_priv, power_well, false);
> -}
> -
> -static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> -}
> -
> -static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - return true;
> -}
> -
> -static void vlv_set_power_well(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well, bool enable)
> -{
> - enum punit_power_well power_well_id = power_well->data;
> - u32 mask;
> - u32 state;
> - u32 ctrl;
> -
> - mask = PUNIT_PWRGT_MASK(power_well_id);
> - state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
> - PUNIT_PWRGT_PWR_GATE(power_well_id);
> -
> - mutex_lock(&dev_priv->rps.hw_lock);
> -
> -#define COND \
> - ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
> -
> - if (COND)
> - goto out;
> -
> - ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
> - ctrl &= ~mask;
> - ctrl |= state;
> - vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl);
> -
> - if (wait_for(COND, 100))
> - DRM_ERROR("timout setting power well state %08x (%08x)\n",
> - state,
> - vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
> -
> -#undef COND
> -
> -out:
> - mutex_unlock(&dev_priv->rps.hw_lock);
> -}
> -
> -static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - vlv_set_power_well(dev_priv, power_well, power_well->count > 0);
> -}
> -
> -static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - vlv_set_power_well(dev_priv, power_well, true);
> -}
> -
> -static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - vlv_set_power_well(dev_priv, power_well, false);
> -}
> -
> -static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - int power_well_id = power_well->data;
> - bool enabled = false;
> - u32 mask;
> - u32 state;
> - u32 ctrl;
> -
> - mask = PUNIT_PWRGT_MASK(power_well_id);
> - ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
> -
> - mutex_lock(&dev_priv->rps.hw_lock);
> -
> - state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
> - /*
> - * We only ever set the power-on and power-gate states, anything
> - * else is unexpected.
> - */
> - WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) &&
> - state != PUNIT_PWRGT_PWR_GATE(power_well_id));
> - if (state == ctrl)
> - enabled = true;
> -
> - /*
> - * A transient state at this point would mean some unexpected party
> - * is poking at the power controls too.
> - */
> - ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
> - WARN_ON(ctrl != state);
> -
> - mutex_unlock(&dev_priv->rps.hw_lock);
> -
> - return enabled;
> -}
> -
> -static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
> -
> - vlv_set_power_well(dev_priv, power_well, true);
> -
> - spin_lock_irq(&dev_priv->irq_lock);
> - valleyview_enable_display_irqs(dev_priv);
> - spin_unlock_irq(&dev_priv->irq_lock);
> -
> - /*
> - * During driver initialization/resume we can avoid restoring the
> - * part of the HW/SW state that will be inited anyway explicitly.
> - */
> - if (dev_priv->power_domains.initializing)
> - return;
> -
> - intel_hpd_init(dev_priv->dev);
> -
> - i915_redisable_vga_power_on(dev_priv->dev);
> -}
> -
> -static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
> -
> - spin_lock_irq(&dev_priv->irq_lock);
> - valleyview_disable_display_irqs(dev_priv);
> - spin_unlock_irq(&dev_priv->irq_lock);
> -
> - vlv_set_power_well(dev_priv, power_well, false);
> -
> - vlv_power_sequencer_reset(dev_priv);
> -}
> -
> -static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
> -
> - /*
> - * Enable the CRI clock source so we can get at the
> - * display and the reference clock for VGA
> - * hotplug / manual detection.
> - */
> - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> - udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
> -
> - vlv_set_power_well(dev_priv, power_well, true);
> -
> - /*
> - * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
> - * 6. De-assert cmn_reset/side_reset. Same as VLV X0.
> - * a. GUnit 0x2110 bit[0] set to 1 (def 0)
> - * b. The other bits such as sfr settings / modesel may all
> - * be set to 0.
> - *
> - * This should only be done on init and resume from S3 with
> - * both PLLs disabled, or we risk losing DPIO and PLL
> - * synchronization.
> - */
> - I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST);
> -}
> -
> -static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - enum pipe pipe;
> -
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
> -
> - for_each_pipe(dev_priv, pipe)
> - assert_pll_disabled(dev_priv, pipe);
> -
> - /* Assert common reset */
> - I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) & ~DPIO_CMNRST);
> -
> - vlv_set_power_well(dev_priv, power_well, false);
> -}
> -
> -static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - enum dpio_phy phy;
> -
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
> - power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
> -
> - /*
> - * Enable the CRI clock source so we can get at the
> - * display and the reference clock for VGA
> - * hotplug / manual detection.
> - */
> - if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
> - phy = DPIO_PHY0;
> - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> - DPLL_REFA_CLK_ENABLE_VLV);
> - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> - } else {
> - phy = DPIO_PHY1;
> - I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) |
> - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> - }
> - udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
> - vlv_set_power_well(dev_priv, power_well, true);
> -
> - /* Poll for phypwrgood signal */
> - if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1))
> - DRM_ERROR("Display PHY %d is not power up\n", phy);
> -
> - I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) |
> - PHY_COM_LANE_RESET_DEASSERT(phy));
> -}
> -
> -static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - enum dpio_phy phy;
> -
> - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
> - power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
> -
> - if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
> - phy = DPIO_PHY0;
> - assert_pll_disabled(dev_priv, PIPE_A);
> - assert_pll_disabled(dev_priv, PIPE_B);
> - } else {
> - phy = DPIO_PHY1;
> - assert_pll_disabled(dev_priv, PIPE_C);
> - }
> -
> - I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) &
> - ~PHY_COM_LANE_RESET_DEASSERT(phy));
> -
> - vlv_set_power_well(dev_priv, power_well, false);
> -}
> -
> -static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - enum pipe pipe = power_well->data;
> - bool enabled;
> - u32 state, ctrl;
> -
> - mutex_lock(&dev_priv->rps.hw_lock);
> -
> - state = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe);
> - /*
> - * We only ever set the power-on and power-gate states, anything
> - * else is unexpected.
> - */
> - WARN_ON(state != DP_SSS_PWR_ON(pipe) && state != DP_SSS_PWR_GATE(pipe));
> - enabled = state == DP_SSS_PWR_ON(pipe);
> -
> - /*
> - * A transient state at this point would mean some unexpected party
> - * is poking at the power controls too.
> - */
> - ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSC_MASK(pipe);
> - WARN_ON(ctrl << 16 != state);
> -
> - mutex_unlock(&dev_priv->rps.hw_lock);
> -
> - return enabled;
> -}
> -
> -static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well,
> - bool enable)
> -{
> - enum pipe pipe = power_well->data;
> - u32 state;
> - u32 ctrl;
> -
> - state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe);
> -
> - mutex_lock(&dev_priv->rps.hw_lock);
> -
> -#define COND \
> - ((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe)) == state)
> -
> - if (COND)
> - goto out;
> -
> - ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> - ctrl &= ~DP_SSC_MASK(pipe);
> - ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe);
> - vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, ctrl);
> -
> - if (wait_for(COND, 100))
> - DRM_ERROR("timout setting power well state %08x (%08x)\n",
> - state,
> - vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ));
> -
> -#undef COND
> -
> -out:
> - mutex_unlock(&dev_priv->rps.hw_lock);
> -}
> -
> -static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - chv_set_pipe_power_well(dev_priv, power_well, power_well->count > 0);
> -}
> -
> -static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - WARN_ON_ONCE(power_well->data != PIPE_A &&
> - power_well->data != PIPE_B &&
> - power_well->data != PIPE_C);
> -
> - chv_set_pipe_power_well(dev_priv, power_well, true);
> -}
> -
> -static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - WARN_ON_ONCE(power_well->data != PIPE_A &&
> - power_well->data != PIPE_B &&
> - power_well->data != PIPE_C);
> -
> - chv_set_pipe_power_well(dev_priv, power_well, false);
> -}
> -
> -static void check_power_well_state(struct drm_i915_private *dev_priv,
> - struct i915_power_well *power_well)
> -{
> - bool enabled = power_well->ops->is_enabled(dev_priv, power_well);
> -
> - if (power_well->always_on || !i915.disable_power_well) {
> - if (!enabled)
> - goto mismatch;
> -
> - return;
> - }
> -
> - if (enabled != (power_well->count > 0))
> - goto mismatch;
> -
> - return;
> -
> -mismatch:
> - WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
> - power_well->name, power_well->always_on, enabled,
> - power_well->count, i915.disable_power_well);
> -}
> -
> -void intel_display_power_get(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain)
> -{
> - struct i915_power_domains *power_domains;
> - struct i915_power_well *power_well;
> - int i;
> -
> - intel_runtime_pm_get(dev_priv);
> -
> - power_domains = &dev_priv->power_domains;
> -
> - mutex_lock(&power_domains->lock);
> -
> - for_each_power_well(i, power_well, BIT(domain), power_domains) {
> - if (!power_well->count++) {
> - DRM_DEBUG_KMS("enabling %s\n", power_well->name);
> - power_well->ops->enable(dev_priv, power_well);
> - power_well->hw_enabled = true;
> - }
> -
> - check_power_well_state(dev_priv, power_well);
> - }
> -
> - power_domains->domain_use_count[domain]++;
> -
> - mutex_unlock(&power_domains->lock);
> -}
> -
> -void intel_display_power_put(struct drm_i915_private *dev_priv,
> - enum intel_display_power_domain domain)
> -{
> - struct i915_power_domains *power_domains;
> - struct i915_power_well *power_well;
> - int i;
> -
> - power_domains = &dev_priv->power_domains;
> -
> - mutex_lock(&power_domains->lock);
> -
> - WARN_ON(!power_domains->domain_use_count[domain]);
> - power_domains->domain_use_count[domain]--;
> -
> - for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
> - WARN_ON(!power_well->count);
> -
> - if (!--power_well->count && i915.disable_power_well) {
> - DRM_DEBUG_KMS("disabling %s\n", power_well->name);
> - power_well->hw_enabled = false;
> - power_well->ops->disable(dev_priv, power_well);
> - }
> -
> - check_power_well_state(dev_priv, power_well);
> - }
> -
> - mutex_unlock(&power_domains->lock);
> -
> - intel_runtime_pm_put(dev_priv);
> -}
> -
> -static struct i915_power_domains *hsw_pwr;
> -
> -/* Display audio driver power well request */
> -int i915_request_power_well(void)
> -{
> - struct drm_i915_private *dev_priv;
> -
> - if (!hsw_pwr)
> - return -ENODEV;
> -
> - dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> - power_domains);
> - intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(i915_request_power_well);
> -
> -/* Display audio driver power well release */
> -int i915_release_power_well(void)
> -{
> - struct drm_i915_private *dev_priv;
> -
> - if (!hsw_pwr)
> - return -ENODEV;
> -
> - dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> - power_domains);
> - intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
> - return 0;
> -}
> -EXPORT_SYMBOL_GPL(i915_release_power_well);
> -
> -/*
> - * Private interface for the audio driver to get CDCLK in kHz.
> - *
> - * Caller must request power well using i915_request_power_well() prior to
> - * making the call.
> - */
> -int i915_get_cdclk_freq(void)
> -{
> - struct drm_i915_private *dev_priv;
> -
> - if (!hsw_pwr)
> - return -ENODEV;
> -
> - dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> - power_domains);
> -
> - return intel_ddi_get_cdclk_freq(dev_priv);
> -}
> -EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
> -
> -
> -#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
> -
> -#define HSW_ALWAYS_ON_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PIPE_A) | \
> - BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
> - BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_CRT) | \
> - BIT(POWER_DOMAIN_PLLS) | \
> - BIT(POWER_DOMAIN_INIT))
> -#define HSW_DISPLAY_POWER_DOMAINS ( \
> - (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define BDW_ALWAYS_ON_POWER_DOMAINS ( \
> - HSW_ALWAYS_ON_POWER_DOMAINS | \
> - BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER))
> -#define BDW_DISPLAY_POWER_DOMAINS ( \
> - (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT)
> -#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK
> -
> -#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_CRT) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_PIPE_A_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PIPE_A) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_PIPE_B_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PIPE_B) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_PIPE_C_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PIPE_C) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_DPIO_CMN_D_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -#define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS ( \
> - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> - BIT(POWER_DOMAIN_INIT))
> -
> -static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
> - .sync_hw = i9xx_always_on_power_well_noop,
> - .enable = i9xx_always_on_power_well_noop,
> - .disable = i9xx_always_on_power_well_noop,
> - .is_enabled = i9xx_always_on_power_well_enabled,
> -};
> -
> -static const struct i915_power_well_ops chv_pipe_power_well_ops = {
> - .sync_hw = chv_pipe_power_well_sync_hw,
> - .enable = chv_pipe_power_well_enable,
> - .disable = chv_pipe_power_well_disable,
> - .is_enabled = chv_pipe_power_well_enabled,
> -};
> -
> -static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = {
> - .sync_hw = vlv_power_well_sync_hw,
> - .enable = chv_dpio_cmn_power_well_enable,
> - .disable = chv_dpio_cmn_power_well_disable,
> - .is_enabled = vlv_power_well_enabled,
> -};
> -
> -static struct i915_power_well i9xx_always_on_power_well[] = {
> - {
> - .name = "always-on",
> - .always_on = 1,
> - .domains = POWER_DOMAIN_MASK,
> - .ops = &i9xx_always_on_power_well_ops,
> - },
> -};
> -
> -static const struct i915_power_well_ops hsw_power_well_ops = {
> - .sync_hw = hsw_power_well_sync_hw,
> - .enable = hsw_power_well_enable,
> - .disable = hsw_power_well_disable,
> - .is_enabled = hsw_power_well_enabled,
> -};
> -
> -static struct i915_power_well hsw_power_wells[] = {
> - {
> - .name = "always-on",
> - .always_on = 1,
> - .domains = HSW_ALWAYS_ON_POWER_DOMAINS,
> - .ops = &i9xx_always_on_power_well_ops,
> - },
> - {
> - .name = "display",
> - .domains = HSW_DISPLAY_POWER_DOMAINS,
> - .ops = &hsw_power_well_ops,
> - },
> -};
> -
> -static struct i915_power_well bdw_power_wells[] = {
> - {
> - .name = "always-on",
> - .always_on = 1,
> - .domains = BDW_ALWAYS_ON_POWER_DOMAINS,
> - .ops = &i9xx_always_on_power_well_ops,
> - },
> - {
> - .name = "display",
> - .domains = BDW_DISPLAY_POWER_DOMAINS,
> - .ops = &hsw_power_well_ops,
> - },
> -};
> -
> -static const struct i915_power_well_ops vlv_display_power_well_ops = {
> - .sync_hw = vlv_power_well_sync_hw,
> - .enable = vlv_display_power_well_enable,
> - .disable = vlv_display_power_well_disable,
> - .is_enabled = vlv_power_well_enabled,
> -};
> -
> -static const struct i915_power_well_ops vlv_dpio_cmn_power_well_ops = {
> - .sync_hw = vlv_power_well_sync_hw,
> - .enable = vlv_dpio_cmn_power_well_enable,
> - .disable = vlv_dpio_cmn_power_well_disable,
> - .is_enabled = vlv_power_well_enabled,
> -};
> -
> -static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
> - .sync_hw = vlv_power_well_sync_hw,
> - .enable = vlv_power_well_enable,
> - .disable = vlv_power_well_disable,
> - .is_enabled = vlv_power_well_enabled,
> -};
> -
> -static struct i915_power_well vlv_power_wells[] = {
> - {
> - .name = "always-on",
> - .always_on = 1,
> - .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
> - .ops = &i9xx_always_on_power_well_ops,
> - },
> - {
> - .name = "display",
> - .domains = VLV_DISPLAY_POWER_DOMAINS,
> - .data = PUNIT_POWER_WELL_DISP2D,
> - .ops = &vlv_display_power_well_ops,
> - },
> - {
> - .name = "dpio-tx-b-01",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
> - },
> - {
> - .name = "dpio-tx-b-23",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
> - },
> - {
> - .name = "dpio-tx-c-01",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
> - },
> - {
> - .name = "dpio-tx-c-23",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
> - },
> - {
> - .name = "dpio-common",
> - .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
> - .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
> - .ops = &vlv_dpio_cmn_power_well_ops,
> - },
> -};
> -
> -static struct i915_power_well chv_power_wells[] = {
> - {
> - .name = "always-on",
> - .always_on = 1,
> - .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
> - .ops = &i9xx_always_on_power_well_ops,
> - },
> -#if 0
> - {
> - .name = "display",
> - .domains = VLV_DISPLAY_POWER_DOMAINS,
> - .data = PUNIT_POWER_WELL_DISP2D,
> - .ops = &vlv_display_power_well_ops,
> - },
> - {
> - .name = "pipe-a",
> - .domains = CHV_PIPE_A_POWER_DOMAINS,
> - .data = PIPE_A,
> - .ops = &chv_pipe_power_well_ops,
> - },
> - {
> - .name = "pipe-b",
> - .domains = CHV_PIPE_B_POWER_DOMAINS,
> - .data = PIPE_B,
> - .ops = &chv_pipe_power_well_ops,
> - },
> - {
> - .name = "pipe-c",
> - .domains = CHV_PIPE_C_POWER_DOMAINS,
> - .data = PIPE_C,
> - .ops = &chv_pipe_power_well_ops,
> - },
> -#endif
> - {
> - .name = "dpio-common-bc",
> - /*
> - * XXX: cmnreset for one PHY seems to disturb the other.
> - * As a workaround keep both powered on at the same
> - * time for now.
> - */
> - .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
> - .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
> - .ops = &chv_dpio_cmn_power_well_ops,
> - },
> - {
> - .name = "dpio-common-d",
> - /*
> - * XXX: cmnreset for one PHY seems to disturb the other.
> - * As a workaround keep both powered on at the same
> - * time for now.
> - */
> - .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
> - .data = PUNIT_POWER_WELL_DPIO_CMN_D,
> - .ops = &chv_dpio_cmn_power_well_ops,
> - },
> -#if 0
> - {
> - .name = "dpio-tx-b-01",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
> - },
> - {
> - .name = "dpio-tx-b-23",
> - .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
> - },
> - {
> - .name = "dpio-tx-c-01",
> - .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
> - },
> - {
> - .name = "dpio-tx-c-23",
> - .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> - VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
> - },
> - {
> - .name = "dpio-tx-d-01",
> - .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
> - CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_01,
> - },
> - {
> - .name = "dpio-tx-d-23",
> - .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
> - CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
> - .ops = &vlv_dpio_power_well_ops,
> - .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_23,
> - },
> -#endif
> -};
> -
> -static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv,
> - enum punit_power_well power_well_id)
> -{
> - struct i915_power_domains *power_domains = &dev_priv->power_domains;
> - struct i915_power_well *power_well;
> - int i;
> -
> - for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
> - if (power_well->data == power_well_id)
> - return power_well;
> - }
> -
> - return NULL;
> -}
> -
> -#define set_power_wells(power_domains, __power_wells) ({ \
> - (power_domains)->power_wells = (__power_wells); \
> - (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
> -})
> -
> -int intel_power_domains_init(struct drm_i915_private *dev_priv)
> -{
> - struct i915_power_domains *power_domains = &dev_priv->power_domains;
> -
> - mutex_init(&power_domains->lock);
> -
> - /*
> - * The enabling order will be from lower to higher indexed wells,
> - * the disabling order is reversed.
> - */
> - if (IS_HASWELL(dev_priv->dev)) {
> - set_power_wells(power_domains, hsw_power_wells);
> - hsw_pwr = power_domains;
> - } else if (IS_BROADWELL(dev_priv->dev)) {
> - set_power_wells(power_domains, bdw_power_wells);
> - hsw_pwr = power_domains;
> - } else if (IS_CHERRYVIEW(dev_priv->dev)) {
> - set_power_wells(power_domains, chv_power_wells);
> - } else if (IS_VALLEYVIEW(dev_priv->dev)) {
> - set_power_wells(power_domains, vlv_power_wells);
> - } else {
> - set_power_wells(power_domains, i9xx_always_on_power_well);
> - }
> -
> - return 0;
> -}
> -
> -void intel_power_domains_remove(struct drm_i915_private *dev_priv)
> -{
> - hsw_pwr = NULL;
> -}
> -
> -static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
> -{
> - struct i915_power_domains *power_domains = &dev_priv->power_domains;
> - struct i915_power_well *power_well;
> - int i;
> -
> - mutex_lock(&power_domains->lock);
> - for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
> - power_well->ops->sync_hw(dev_priv, power_well);
> - power_well->hw_enabled = power_well->ops->is_enabled(dev_priv,
> - power_well);
> - }
> - mutex_unlock(&power_domains->lock);
> -}
> -
> -static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
> -{
> - struct i915_power_well *cmn =
> - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
> - struct i915_power_well *disp2d =
> - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DISP2D);
> -
> - /* nothing to do if common lane is already off */
> - if (!cmn->ops->is_enabled(dev_priv, cmn))
> - return;
> -
> - /* If the display might be already active skip this */
> - if (disp2d->ops->is_enabled(dev_priv, disp2d) &&
> - I915_READ(DPIO_CTL) & DPIO_CMNRST)
> - return;
> -
> - DRM_DEBUG_KMS("toggling display PHY side reset\n");
> -
> - /* cmnlane needs DPLL registers */
> - disp2d->ops->enable(dev_priv, disp2d);
> -
> - /*
> - * From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx:
> - * Need to assert and de-assert PHY SB reset by gating the
> - * common lane power, then un-gating it.
> - * Simply ungating isn't enough to reset the PHY enough to get
> - * ports and lanes running.
> - */
> - cmn->ops->disable(dev_priv, cmn);
> -}
> -
> -void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct i915_power_domains *power_domains = &dev_priv->power_domains;
> -
> - power_domains->initializing = true;
> -
> - if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
> - mutex_lock(&power_domains->lock);
> - vlv_cmnlane_wa(dev_priv);
> - mutex_unlock(&power_domains->lock);
> - }
> -
> - /* For now, we need the power well to be always enabled. */
> - intel_display_set_init_power(dev_priv, true);
> - intel_power_domains_resume(dev_priv);
> - power_domains->initializing = false;
> -}
> -
> -void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
> -{
> - intel_runtime_pm_get(dev_priv);
> -}
> -
> -void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
> -{
> - intel_runtime_pm_put(dev_priv);
> -}
> -
> -void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct device *device = &dev->pdev->dev;
> -
> - if (!HAS_RUNTIME_PM(dev))
> - return;
> -
> - pm_runtime_get_sync(device);
> - WARN(dev_priv->pm.suspended, "Device still suspended.\n");
> -}
> -
> -void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct device *device = &dev->pdev->dev;
> -
> - if (!HAS_RUNTIME_PM(dev))
> - return;
> -
> - WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n");
> - pm_runtime_get_noresume(device);
> -}
> -
> -void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct device *device = &dev->pdev->dev;
> -
> - if (!HAS_RUNTIME_PM(dev))
> - return;
> -
> - pm_runtime_mark_last_busy(device);
> - pm_runtime_put_autosuspend(device);
> -}
> -
> -void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct device *device = &dev->pdev->dev;
> -
> - if (!HAS_RUNTIME_PM(dev))
> - return;
> -
> - pm_runtime_set_active(device);
> -
> - /*
> - * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
> - * requirement.
> - */
> - if (!intel_enable_rc6(dev)) {
> - DRM_INFO("RC6 disabled, disabling runtime PM support\n");
> - return;
> - }
> -
> - pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
> - pm_runtime_mark_last_busy(device);
> - pm_runtime_use_autosuspend(device);
> -
> - pm_runtime_put_autosuspend(device);
> -}
> -
> -void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
> -{
> - struct drm_device *dev = dev_priv->dev;
> - struct device *device = &dev->pdev->dev;
> -
> - if (!HAS_RUNTIME_PM(dev))
> - return;
> -
> - if (!intel_enable_rc6(dev))
> - return;
> -
> - /* Make sure we're not suspended first. */
> - pm_runtime_get_sync(device);
> - pm_runtime_disable(device);
> -}
>
> static void intel_init_fbc(struct drm_i915_private *dev_priv)
> {
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> new file mode 100644
> index 000000000000..23f97ee79fde
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -0,0 +1,1190 @@
> +/*
> + * Copyright © 2012-2014 Intel Corporation
> + *
> + * 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, sublicense,
> + * 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 NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS 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.
> + *
> + * Authors:
> + * Eugeni Dodonov <eugeni.dodonov at intel.com>
> + * Daniel Vetter <daniel.vetter at ffwll.ch>
> + *
> + */
> +
> +#include <linux/pm_runtime.h>
> +#include <linux/vgaarb.h>
> +
> +#include "i915_drv.h"
> +#include "intel_drv.h"
> +#include <drm/i915_powerwell.h>
> +
> +static struct i915_power_domains *hsw_pwr;
> +
> +#define for_each_power_well(i, power_well, domain_mask, power_domains) \
> + for (i = 0; \
> + i < (power_domains)->power_well_count && \
> + ((power_well) = &(power_domains)->power_wells[i]); \
> + i++) \
> + if ((power_well)->domains & (domain_mask))
> +
> +#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
> + for (i = (power_domains)->power_well_count - 1; \
> + i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
> + i--) \
> + if ((power_well)->domains & (domain_mask))
> +
> +/**
> + * We should only use the power well if we explicitly asked the hardware to
> + * enable it, so check if it's enabled and also check if we've requested it to
> + * be enabled.
> + */
> +static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + return I915_READ(HSW_PWR_WELL_DRIVER) ==
> + (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
> +}
> +
> +bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain)
> +{
> + struct i915_power_domains *power_domains;
> + struct i915_power_well *power_well;
> + bool is_enabled;
> + int i;
> +
> + if (dev_priv->pm.suspended)
> + return false;
> +
> + power_domains = &dev_priv->power_domains;
> +
> + is_enabled = true;
> +
> + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
> + if (power_well->always_on)
> + continue;
> +
> + if (!power_well->hw_enabled) {
> + is_enabled = false;
> + break;
> + }
> + }
> +
> + return is_enabled;
> +}
> +
> +bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain)
> +{
> + struct i915_power_domains *power_domains;
> + bool ret;
> +
> + power_domains = &dev_priv->power_domains;
> +
> + mutex_lock(&power_domains->lock);
> + ret = intel_display_power_enabled_unlocked(dev_priv, domain);
> + mutex_unlock(&power_domains->lock);
> +
> + return ret;
> +}
> +
> +/*
> + * 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
> + * to be enabled, and it will only be disabled if none of the registers is
> + * requesting it to be enabled.
> + */
> +static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> +
> + /*
> + * After we re-enable the power well, if we touch VGA register 0x3d5
> + * we'll get unclaimed register interrupts. This stops after we write
> + * anything to the VGA MSR register. The vgacon module uses this
> + * register all the time, so if we unbind our driver and, as a
> + * consequence, bind vgacon, we'll get stuck in an infinite loop at
> + * console_unlock(). So make here we touch the VGA MSR register, making
> + * sure vgacon can keep working normally without triggering interrupts
> + * and error messages.
> + */
> + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
> + outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
> + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
> +
> + if (IS_BROADWELL(dev))
> + gen8_irq_power_well_post_enable(dev_priv);
> +}
> +
> +static void hsw_set_power_well(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well, bool enable)
> +{
> + bool is_enabled, enable_requested;
> + uint32_t tmp;
> +
> + tmp = I915_READ(HSW_PWR_WELL_DRIVER);
> + is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
> + enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
> +
> + if (enable) {
> + if (!enable_requested)
> + I915_WRITE(HSW_PWR_WELL_DRIVER,
> + HSW_PWR_WELL_ENABLE_REQUEST);
> +
> + if (!is_enabled) {
> + DRM_DEBUG_KMS("Enabling power well\n");
> + if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) &
> + HSW_PWR_WELL_STATE_ENABLED), 20))
> + DRM_ERROR("Timeout enabling power well\n");
> + }
> +
> + hsw_power_well_post_enable(dev_priv);
> + } else {
> + if (enable_requested) {
> + I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
> + POSTING_READ(HSW_PWR_WELL_DRIVER);
> + DRM_DEBUG_KMS("Requesting to disable the power well\n");
> + }
> + }
> +}
> +
> +static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + hsw_set_power_well(dev_priv, power_well, power_well->count > 0);
> +
> + /*
> + * We're taking over the BIOS, so clear any requests made by it since
> + * the driver is in charge now.
> + */
> + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
> + I915_WRITE(HSW_PWR_WELL_BIOS, 0);
> +}
> +
> +static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + hsw_set_power_well(dev_priv, power_well, true);
> +}
> +
> +static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + hsw_set_power_well(dev_priv, power_well, false);
> +}
> +
> +static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> +}
> +
> +static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + return true;
> +}
> +
> +static void vlv_set_power_well(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well, bool enable)
> +{
> + enum punit_power_well power_well_id = power_well->data;
> + u32 mask;
> + u32 state;
> + u32 ctrl;
> +
> + mask = PUNIT_PWRGT_MASK(power_well_id);
> + state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
> + PUNIT_PWRGT_PWR_GATE(power_well_id);
> +
> + mutex_lock(&dev_priv->rps.hw_lock);
> +
> +#define COND \
> + ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
> +
> + if (COND)
> + goto out;
> +
> + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
> + ctrl &= ~mask;
> + ctrl |= state;
> + vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl);
> +
> + if (wait_for(COND, 100))
> + DRM_ERROR("timout setting power well state %08x (%08x)\n",
> + state,
> + vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
> +
> +#undef COND
> +
> +out:
> + mutex_unlock(&dev_priv->rps.hw_lock);
> +}
> +
> +static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + vlv_set_power_well(dev_priv, power_well, power_well->count > 0);
> +}
> +
> +static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + vlv_set_power_well(dev_priv, power_well, true);
> +}
> +
> +static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + vlv_set_power_well(dev_priv, power_well, false);
> +}
> +
> +static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + int power_well_id = power_well->data;
> + bool enabled = false;
> + u32 mask;
> + u32 state;
> + u32 ctrl;
> +
> + mask = PUNIT_PWRGT_MASK(power_well_id);
> + ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
> +
> + mutex_lock(&dev_priv->rps.hw_lock);
> +
> + state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
> + /*
> + * We only ever set the power-on and power-gate states, anything
> + * else is unexpected.
> + */
> + WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) &&
> + state != PUNIT_PWRGT_PWR_GATE(power_well_id));
> + if (state == ctrl)
> + enabled = true;
> +
> + /*
> + * A transient state at this point would mean some unexpected party
> + * is poking at the power controls too.
> + */
> + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
> + WARN_ON(ctrl != state);
> +
> + mutex_unlock(&dev_priv->rps.hw_lock);
> +
> + return enabled;
> +}
> +
> +static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
> +
> + vlv_set_power_well(dev_priv, power_well, true);
> +
> + spin_lock_irq(&dev_priv->irq_lock);
> + valleyview_enable_display_irqs(dev_priv);
> + spin_unlock_irq(&dev_priv->irq_lock);
> +
> + /*
> + * During driver initialization/resume we can avoid restoring the
> + * part of the HW/SW state that will be inited anyway explicitly.
> + */
> + if (dev_priv->power_domains.initializing)
> + return;
> +
> + intel_hpd_init(dev_priv->dev);
> +
> + i915_redisable_vga_power_on(dev_priv->dev);
> +}
> +
> +static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
> +
> + spin_lock_irq(&dev_priv->irq_lock);
> + valleyview_disable_display_irqs(dev_priv);
> + spin_unlock_irq(&dev_priv->irq_lock);
> +
> + vlv_set_power_well(dev_priv, power_well, false);
> +
> + vlv_power_sequencer_reset(dev_priv);
> +}
> +
> +static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
> +
> + /*
> + * Enable the CRI clock source so we can get at the
> + * display and the reference clock for VGA
> + * hotplug / manual detection.
> + */
> + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> + DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> + udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
> +
> + vlv_set_power_well(dev_priv, power_well, true);
> +
> + /*
> + * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
> + * 6. De-assert cmn_reset/side_reset. Same as VLV X0.
> + * a. GUnit 0x2110 bit[0] set to 1 (def 0)
> + * b. The other bits such as sfr settings / modesel may all
> + * be set to 0.
> + *
> + * This should only be done on init and resume from S3 with
> + * both PLLs disabled, or we risk losing DPIO and PLL
> + * synchronization.
> + */
> + I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST);
> +}
> +
> +static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + enum pipe pipe;
> +
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
> +
> + for_each_pipe(dev_priv, pipe)
> + assert_pll_disabled(dev_priv, pipe);
> +
> + /* Assert common reset */
> + I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) & ~DPIO_CMNRST);
> +
> + vlv_set_power_well(dev_priv, power_well, false);
> +}
> +
> +static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + enum dpio_phy phy;
> +
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
> + power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
> +
> + /*
> + * Enable the CRI clock source so we can get at the
> + * display and the reference clock for VGA
> + * hotplug / manual detection.
> + */
> + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
> + phy = DPIO_PHY0;
> + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> + DPLL_REFA_CLK_ENABLE_VLV);
> + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
> + DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> + } else {
> + phy = DPIO_PHY1;
> + I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) |
> + DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
> + }
> + udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
> + vlv_set_power_well(dev_priv, power_well, true);
> +
> + /* Poll for phypwrgood signal */
> + if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1))
> + DRM_ERROR("Display PHY %d is not power up\n", phy);
> +
> + I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) |
> + PHY_COM_LANE_RESET_DEASSERT(phy));
> +}
> +
> +static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + enum dpio_phy phy;
> +
> + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
> + power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
> +
> + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
> + phy = DPIO_PHY0;
> + assert_pll_disabled(dev_priv, PIPE_A);
> + assert_pll_disabled(dev_priv, PIPE_B);
> + } else {
> + phy = DPIO_PHY1;
> + assert_pll_disabled(dev_priv, PIPE_C);
> + }
> +
> + I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) &
> + ~PHY_COM_LANE_RESET_DEASSERT(phy));
> +
> + vlv_set_power_well(dev_priv, power_well, false);
> +}
> +
> +static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + enum pipe pipe = power_well->data;
> + bool enabled;
> + u32 state, ctrl;
> +
> + mutex_lock(&dev_priv->rps.hw_lock);
> +
> + state = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe);
> + /*
> + * We only ever set the power-on and power-gate states, anything
> + * else is unexpected.
> + */
> + WARN_ON(state != DP_SSS_PWR_ON(pipe) && state != DP_SSS_PWR_GATE(pipe));
> + enabled = state == DP_SSS_PWR_ON(pipe);
> +
> + /*
> + * A transient state at this point would mean some unexpected party
> + * is poking at the power controls too.
> + */
> + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSC_MASK(pipe);
> + WARN_ON(ctrl << 16 != state);
> +
> + mutex_unlock(&dev_priv->rps.hw_lock);
> +
> + return enabled;
> +}
> +
> +static void chv_set_pipe_power_well(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well,
> + bool enable)
> +{
> + enum pipe pipe = power_well->data;
> + u32 state;
> + u32 ctrl;
> +
> + state = enable ? DP_SSS_PWR_ON(pipe) : DP_SSS_PWR_GATE(pipe);
> +
> + mutex_lock(&dev_priv->rps.hw_lock);
> +
> +#define COND \
> + ((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & DP_SSS_MASK(pipe)) == state)
> +
> + if (COND)
> + goto out;
> +
> + ctrl = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
> + ctrl &= ~DP_SSC_MASK(pipe);
> + ctrl |= enable ? DP_SSC_PWR_ON(pipe) : DP_SSC_PWR_GATE(pipe);
> + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, ctrl);
> +
> + if (wait_for(COND, 100))
> + DRM_ERROR("timout setting power well state %08x (%08x)\n",
> + state,
> + vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ));
> +
> +#undef COND
> +
> +out:
> + mutex_unlock(&dev_priv->rps.hw_lock);
> +}
> +
> +static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + chv_set_pipe_power_well(dev_priv, power_well, power_well->count > 0);
> +}
> +
> +static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + WARN_ON_ONCE(power_well->data != PIPE_A &&
> + power_well->data != PIPE_B &&
> + power_well->data != PIPE_C);
> +
> + chv_set_pipe_power_well(dev_priv, power_well, true);
> +}
> +
> +static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + WARN_ON_ONCE(power_well->data != PIPE_A &&
> + power_well->data != PIPE_B &&
> + power_well->data != PIPE_C);
> +
> + chv_set_pipe_power_well(dev_priv, power_well, false);
> +}
> +
> +static void check_power_well_state(struct drm_i915_private *dev_priv,
> + struct i915_power_well *power_well)
> +{
> + bool enabled = power_well->ops->is_enabled(dev_priv, power_well);
> +
> + if (power_well->always_on || !i915.disable_power_well) {
> + if (!enabled)
> + goto mismatch;
> +
> + return;
> + }
> +
> + if (enabled != (power_well->count > 0))
> + goto mismatch;
> +
> + return;
> +
> +mismatch:
> + WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
> + power_well->name, power_well->always_on, enabled,
> + power_well->count, i915.disable_power_well);
> +}
> +
> +void intel_display_power_get(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain)
> +{
> + struct i915_power_domains *power_domains;
> + struct i915_power_well *power_well;
> + int i;
> +
> + intel_runtime_pm_get(dev_priv);
> +
> + power_domains = &dev_priv->power_domains;
> +
> + mutex_lock(&power_domains->lock);
> +
> + for_each_power_well(i, power_well, BIT(domain), power_domains) {
> + if (!power_well->count++) {
> + DRM_DEBUG_KMS("enabling %s\n", power_well->name);
> + power_well->ops->enable(dev_priv, power_well);
> + power_well->hw_enabled = true;
> + }
> +
> + check_power_well_state(dev_priv, power_well);
> + }
> +
> + power_domains->domain_use_count[domain]++;
> +
> + mutex_unlock(&power_domains->lock);
> +}
> +
> +void intel_display_power_put(struct drm_i915_private *dev_priv,
> + enum intel_display_power_domain domain)
> +{
> + struct i915_power_domains *power_domains;
> + struct i915_power_well *power_well;
> + int i;
> +
> + power_domains = &dev_priv->power_domains;
> +
> + mutex_lock(&power_domains->lock);
> +
> + WARN_ON(!power_domains->domain_use_count[domain]);
> + power_domains->domain_use_count[domain]--;
> +
> + for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
> + WARN_ON(!power_well->count);
> +
> + if (!--power_well->count && i915.disable_power_well) {
> + DRM_DEBUG_KMS("disabling %s\n", power_well->name);
> + power_well->hw_enabled = false;
> + power_well->ops->disable(dev_priv, power_well);
> + }
> +
> + check_power_well_state(dev_priv, power_well);
> + }
> +
> + mutex_unlock(&power_domains->lock);
> +
> + intel_runtime_pm_put(dev_priv);
> +}
> +
> +#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
> +
> +#define HSW_ALWAYS_ON_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PIPE_A) | \
> + BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
> + BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_CRT) | \
> + BIT(POWER_DOMAIN_PLLS) | \
> + BIT(POWER_DOMAIN_INIT))
> +#define HSW_DISPLAY_POWER_DOMAINS ( \
> + (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define BDW_ALWAYS_ON_POWER_DOMAINS ( \
> + HSW_ALWAYS_ON_POWER_DOMAINS | \
> + BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER))
> +#define BDW_DISPLAY_POWER_DOMAINS ( \
> + (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT)
> +#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK
> +
> +#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_CRT) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_PIPE_A_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PIPE_A) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_PIPE_B_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PIPE_B) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_PIPE_C_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PIPE_C) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_DPIO_CMN_D_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
> + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +#define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS ( \
> + BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
> + BIT(POWER_DOMAIN_INIT))
> +
> +static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
> + .sync_hw = i9xx_always_on_power_well_noop,
> + .enable = i9xx_always_on_power_well_noop,
> + .disable = i9xx_always_on_power_well_noop,
> + .is_enabled = i9xx_always_on_power_well_enabled,
> +};
> +
> +static const struct i915_power_well_ops chv_pipe_power_well_ops = {
> + .sync_hw = chv_pipe_power_well_sync_hw,
> + .enable = chv_pipe_power_well_enable,
> + .disable = chv_pipe_power_well_disable,
> + .is_enabled = chv_pipe_power_well_enabled,
> +};
> +
> +static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = {
> + .sync_hw = vlv_power_well_sync_hw,
> + .enable = chv_dpio_cmn_power_well_enable,
> + .disable = chv_dpio_cmn_power_well_disable,
> + .is_enabled = vlv_power_well_enabled,
> +};
> +
> +static struct i915_power_well i9xx_always_on_power_well[] = {
> + {
> + .name = "always-on",
> + .always_on = 1,
> + .domains = POWER_DOMAIN_MASK,
> + .ops = &i9xx_always_on_power_well_ops,
> + },
> +};
> +
> +static const struct i915_power_well_ops hsw_power_well_ops = {
> + .sync_hw = hsw_power_well_sync_hw,
> + .enable = hsw_power_well_enable,
> + .disable = hsw_power_well_disable,
> + .is_enabled = hsw_power_well_enabled,
> +};
> +
> +static struct i915_power_well hsw_power_wells[] = {
> + {
> + .name = "always-on",
> + .always_on = 1,
> + .domains = HSW_ALWAYS_ON_POWER_DOMAINS,
> + .ops = &i9xx_always_on_power_well_ops,
> + },
> + {
> + .name = "display",
> + .domains = HSW_DISPLAY_POWER_DOMAINS,
> + .ops = &hsw_power_well_ops,
> + },
> +};
> +
> +static struct i915_power_well bdw_power_wells[] = {
> + {
> + .name = "always-on",
> + .always_on = 1,
> + .domains = BDW_ALWAYS_ON_POWER_DOMAINS,
> + .ops = &i9xx_always_on_power_well_ops,
> + },
> + {
> + .name = "display",
> + .domains = BDW_DISPLAY_POWER_DOMAINS,
> + .ops = &hsw_power_well_ops,
> + },
> +};
> +
> +static const struct i915_power_well_ops vlv_display_power_well_ops = {
> + .sync_hw = vlv_power_well_sync_hw,
> + .enable = vlv_display_power_well_enable,
> + .disable = vlv_display_power_well_disable,
> + .is_enabled = vlv_power_well_enabled,
> +};
> +
> +static const struct i915_power_well_ops vlv_dpio_cmn_power_well_ops = {
> + .sync_hw = vlv_power_well_sync_hw,
> + .enable = vlv_dpio_cmn_power_well_enable,
> + .disable = vlv_dpio_cmn_power_well_disable,
> + .is_enabled = vlv_power_well_enabled,
> +};
> +
> +static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
> + .sync_hw = vlv_power_well_sync_hw,
> + .enable = vlv_power_well_enable,
> + .disable = vlv_power_well_disable,
> + .is_enabled = vlv_power_well_enabled,
> +};
> +
> +static struct i915_power_well vlv_power_wells[] = {
> + {
> + .name = "always-on",
> + .always_on = 1,
> + .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
> + .ops = &i9xx_always_on_power_well_ops,
> + },
> + {
> + .name = "display",
> + .domains = VLV_DISPLAY_POWER_DOMAINS,
> + .data = PUNIT_POWER_WELL_DISP2D,
> + .ops = &vlv_display_power_well_ops,
> + },
> + {
> + .name = "dpio-tx-b-01",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
> + },
> + {
> + .name = "dpio-tx-b-23",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
> + },
> + {
> + .name = "dpio-tx-c-01",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
> + },
> + {
> + .name = "dpio-tx-c-23",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
> + },
> + {
> + .name = "dpio-common",
> + .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
> + .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
> + .ops = &vlv_dpio_cmn_power_well_ops,
> + },
> +};
> +
> +static struct i915_power_well chv_power_wells[] = {
> + {
> + .name = "always-on",
> + .always_on = 1,
> + .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
> + .ops = &i9xx_always_on_power_well_ops,
> + },
> +#if 0
> + {
> + .name = "display",
> + .domains = VLV_DISPLAY_POWER_DOMAINS,
> + .data = PUNIT_POWER_WELL_DISP2D,
> + .ops = &vlv_display_power_well_ops,
> + },
> + {
> + .name = "pipe-a",
> + .domains = CHV_PIPE_A_POWER_DOMAINS,
> + .data = PIPE_A,
> + .ops = &chv_pipe_power_well_ops,
> + },
> + {
> + .name = "pipe-b",
> + .domains = CHV_PIPE_B_POWER_DOMAINS,
> + .data = PIPE_B,
> + .ops = &chv_pipe_power_well_ops,
> + },
> + {
> + .name = "pipe-c",
> + .domains = CHV_PIPE_C_POWER_DOMAINS,
> + .data = PIPE_C,
> + .ops = &chv_pipe_power_well_ops,
> + },
> +#endif
> + {
> + .name = "dpio-common-bc",
> + /*
> + * XXX: cmnreset for one PHY seems to disturb the other.
> + * As a workaround keep both powered on at the same
> + * time for now.
> + */
> + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
> + .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
> + .ops = &chv_dpio_cmn_power_well_ops,
> + },
> + {
> + .name = "dpio-common-d",
> + /*
> + * XXX: cmnreset for one PHY seems to disturb the other.
> + * As a workaround keep both powered on at the same
> + * time for now.
> + */
> + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS,
> + .data = PUNIT_POWER_WELL_DPIO_CMN_D,
> + .ops = &chv_dpio_cmn_power_well_ops,
> + },
> +#if 0
> + {
> + .name = "dpio-tx-b-01",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
> + },
> + {
> + .name = "dpio-tx-b-23",
> + .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
> + },
> + {
> + .name = "dpio-tx-c-01",
> + .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
> + },
> + {
> + .name = "dpio-tx-c-23",
> + .domains = VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
> + VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
> + },
> + {
> + .name = "dpio-tx-d-01",
> + .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
> + CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_01,
> + },
> + {
> + .name = "dpio-tx-d-23",
> + .domains = CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS |
> + CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS,
> + .ops = &vlv_dpio_power_well_ops,
> + .data = PUNIT_POWER_WELL_DPIO_TX_D_LANES_23,
> + },
> +#endif
> +};
> +
> +static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv,
> + enum punit_power_well power_well_id)
> +{
> + struct i915_power_domains *power_domains = &dev_priv->power_domains;
> + struct i915_power_well *power_well;
> + int i;
> +
> + for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
> + if (power_well->data == power_well_id)
> + return power_well;
> + }
> +
> + return NULL;
> +}
> +
> +#define set_power_wells(power_domains, __power_wells) ({ \
> + (power_domains)->power_wells = (__power_wells); \
> + (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
> +})
> +
> +int intel_power_domains_init(struct drm_i915_private *dev_priv)
> +{
> + struct i915_power_domains *power_domains = &dev_priv->power_domains;
> +
> + mutex_init(&power_domains->lock);
> +
> + /*
> + * The enabling order will be from lower to higher indexed wells,
> + * the disabling order is reversed.
> + */
> + if (IS_HASWELL(dev_priv->dev)) {
> + set_power_wells(power_domains, hsw_power_wells);
> + hsw_pwr = power_domains;
> + } else if (IS_BROADWELL(dev_priv->dev)) {
> + set_power_wells(power_domains, bdw_power_wells);
> + hsw_pwr = power_domains;
> + } else if (IS_CHERRYVIEW(dev_priv->dev)) {
> + set_power_wells(power_domains, chv_power_wells);
> + } else if (IS_VALLEYVIEW(dev_priv->dev)) {
> + set_power_wells(power_domains, vlv_power_wells);
> + } else {
> + set_power_wells(power_domains, i9xx_always_on_power_well);
> + }
> +
> + return 0;
> +}
> +
> +void intel_power_domains_remove(struct drm_i915_private *dev_priv)
> +{
> + hsw_pwr = NULL;
> +}
> +
> +static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
> +{
> + struct i915_power_domains *power_domains = &dev_priv->power_domains;
> + struct i915_power_well *power_well;
> + int i;
> +
> + mutex_lock(&power_domains->lock);
> + for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
> + power_well->ops->sync_hw(dev_priv, power_well);
> + power_well->hw_enabled = power_well->ops->is_enabled(dev_priv,
> + power_well);
> + }
> + mutex_unlock(&power_domains->lock);
> +}
> +
> +static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
> +{
> + struct i915_power_well *cmn =
> + lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
> + struct i915_power_well *disp2d =
> + lookup_power_well(dev_priv, PUNIT_POWER_WELL_DISP2D);
> +
> + /* nothing to do if common lane is already off */
> + if (!cmn->ops->is_enabled(dev_priv, cmn))
> + return;
> +
> + /* If the display might be already active skip this */
> + if (disp2d->ops->is_enabled(dev_priv, disp2d) &&
> + I915_READ(DPIO_CTL) & DPIO_CMNRST)
> + return;
> +
> + DRM_DEBUG_KMS("toggling display PHY side reset\n");
> +
> + /* cmnlane needs DPLL registers */
> + disp2d->ops->enable(dev_priv, disp2d);
> +
> + /*
> + * From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx:
> + * Need to assert and de-assert PHY SB reset by gating the
> + * common lane power, then un-gating it.
> + * Simply ungating isn't enough to reset the PHY enough to get
> + * ports and lanes running.
> + */
> + cmn->ops->disable(dev_priv, cmn);
> +}
> +
> +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct i915_power_domains *power_domains = &dev_priv->power_domains;
> +
> + power_domains->initializing = true;
> +
> + if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
> + mutex_lock(&power_domains->lock);
> + vlv_cmnlane_wa(dev_priv);
> + mutex_unlock(&power_domains->lock);
> + }
> +
> + /* For now, we need the power well to be always enabled. */
> + intel_display_set_init_power(dev_priv, true);
> + intel_power_domains_resume(dev_priv);
> + power_domains->initializing = false;
> +}
> +
> +void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
> +{
> + intel_runtime_pm_get(dev_priv);
> +}
> +
> +void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
> +{
> + intel_runtime_pm_put(dev_priv);
> +}
> +
> +void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct device *device = &dev->pdev->dev;
> +
> + if (!HAS_RUNTIME_PM(dev))
> + return;
> +
> + pm_runtime_get_sync(device);
> + WARN(dev_priv->pm.suspended, "Device still suspended.\n");
> +}
> +
> +void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct device *device = &dev->pdev->dev;
> +
> + if (!HAS_RUNTIME_PM(dev))
> + return;
> +
> + WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n");
> + pm_runtime_get_noresume(device);
> +}
> +
> +void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct device *device = &dev->pdev->dev;
> +
> + if (!HAS_RUNTIME_PM(dev))
> + return;
> +
> + pm_runtime_mark_last_busy(device);
> + pm_runtime_put_autosuspend(device);
> +}
> +
> +void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct device *device = &dev->pdev->dev;
> +
> + if (!HAS_RUNTIME_PM(dev))
> + return;
> +
> + pm_runtime_set_active(device);
> +
> + /*
> + * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
> + * requirement.
> + */
> + if (!intel_enable_rc6(dev)) {
> + DRM_INFO("RC6 disabled, disabling runtime PM support\n");
> + return;
> + }
> +
> + pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
> + pm_runtime_mark_last_busy(device);
> + pm_runtime_use_autosuspend(device);
> +
> + pm_runtime_put_autosuspend(device);
> +}
> +
> +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + struct device *device = &dev->pdev->dev;
> +
> + if (!HAS_RUNTIME_PM(dev))
> + return;
> +
> + if (!intel_enable_rc6(dev))
> + return;
> +
> + /* Make sure we're not suspended first. */
> + pm_runtime_get_sync(device);
> + pm_runtime_disable(device);
> +}
> +
> +/* Display audio driver power well request */
> +int i915_request_power_well(void)
> +{
> + struct drm_i915_private *dev_priv;
> +
> + if (!hsw_pwr)
> + return -ENODEV;
> +
> + dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> + power_domains);
> + intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(i915_request_power_well);
> +
> +/* Display audio driver power well release */
> +int i915_release_power_well(void)
> +{
> + struct drm_i915_private *dev_priv;
> +
> + if (!hsw_pwr)
> + return -ENODEV;
> +
> + dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> + power_domains);
> + intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(i915_release_power_well);
> +
> +/*
> + * Private interface for the audio driver to get CDCLK in kHz.
> + *
> + * Caller must request power well using i915_request_power_well() prior to
> + * making the call.
> + */
> +int i915_get_cdclk_freq(void)
> +{
> + struct drm_i915_private *dev_priv;
> +
> + if (!hsw_pwr)
> + return -ENODEV;
> +
> + dev_priv = container_of(hsw_pwr, struct drm_i915_private,
> + power_domains);
> +
> + return intel_ddi_get_cdclk_freq(dev_priv);
> +}
> +EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
More information about the Intel-gfx
mailing list