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@xxxxxxxxx> Looks ok, but needs to be rebased on commit 08524a9ffa396c56ff3fbec9cfd80edd3fa6a058 Author: Satheeshakrishna M <satheeshakrishna.m@xxxxxxxxx> 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@xxxxxxxxx> > + * Daniel Vetter <daniel.vetter@xxxxxxxx> > + * > + */ > + > +#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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx