From: Imre Deak <imre.deak@intel.com>
To: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Daniel Vetter <daniel.vetter@intel.com>,
Intel Graphics Development <intel-gfx@lists.freedesktop.org>
Subject: Re: [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c
Date: Tue, 30 Sep 2014 15:22:09 +0300 [thread overview]
Message-ID: <1412079729.18498.1.camel@intelbox> (raw)
In-Reply-To: <1412067410-9346-3-git-send-email-daniel.vetter@ffwll.ch>
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@intel.com>
Looks ok, but needs to be rebased on
commit 08524a9ffa396c56ff3fbec9cfd80edd3fa6a058
Author: Satheeshakrishna M <satheeshakrishna.m@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@intel.com>
> + * Daniel Vetter <daniel.vetter@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);
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2014-09-30 12:22 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
2014-09-30 8:56 ` [PATCH 01/14] drm/i915: Remove intel_modeset_suspend_hw Daniel Vetter
2014-09-30 8:56 ` [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c Daniel Vetter
2014-09-30 12:22 ` Imre Deak [this message]
2014-09-30 8:56 ` [PATCH 03/14] drm/i915: Bikeshed rpm functions name a bit Daniel Vetter
2014-09-30 8:56 ` [PATCH 04/14] drm/i915: Move intel_display_set_init_power to intel_runtime_pm.c Daniel Vetter
2014-09-30 8:56 ` [PATCH 05/14] drm/i915: Call runtime_pm_disable directly Daniel Vetter
2014-09-30 12:46 ` Imre Deak
2014-09-30 8:56 ` [PATCH 06/14] drm/i915: Kerneldoc for intel_runtime_pm.c Daniel Vetter
2014-09-30 13:11 ` Imre Deak
2014-09-30 8:56 ` [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/ Daniel Vetter
2014-10-02 20:36 ` Paulo Zanoni
2014-10-03 9:19 ` Daniel Vetter
2014-10-03 9:27 ` Chris Wilson
2014-10-03 11:49 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 08/14] drm/i915: Use dev_priv instead of dev in irq setup functions Daniel Vetter
2014-10-02 20:46 ` Paulo Zanoni
2014-09-30 8:56 ` [PATCH 09/14] drm/i915: kerneldoc for interrupt enable/disable functions Daniel Vetter
2014-10-02 20:55 ` Paulo Zanoni
2014-09-30 8:56 ` [PATCH 10/14] drm/i915: Extract intel_fifo_underrun.c Daniel Vetter
2014-09-30 8:56 ` [PATCH 11/14] drm/i915: Use dev_priv in public intel_fifo_underrun.c functions Daniel Vetter
2014-09-30 8:56 ` [PATCH 12/14] drm/i915: Add wrappers to handle fifo underrun interrupts Daniel Vetter
2014-09-30 8:56 ` [PATCH 13/14] drm/i915: Filter gmch fifo underruns in the shared handler Daniel Vetter
2014-09-30 8:56 ` [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c Daniel Vetter
2014-10-03 18:00 ` Paulo Zanoni
2014-10-03 20:51 ` Daniel Vetter
2014-09-30 13:16 ` [PATCH 00/14] i915 kerneldocs part 1 Imre Deak
2014-10-01 8:42 ` Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1412079729.18498.1.camel@intelbox \
--to=imre.deak@intel.com \
--cc=daniel.vetter@ffwll.ch \
--cc=daniel.vetter@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.