Had to conditionalize some HSW bits and add virtual functions for get/set on the power wells. Signed-off-by: Jesse Barnes <jbarnes@xxxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 10 +- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_pm.c | 128 +++------------------- drivers/gpu/drm/i915/intel_uncore.c | 211 ++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ca74ef2..4e97840 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -401,6 +401,14 @@ struct drm_i915_display_funcs { struct intel_uncore_funcs { void (*force_wake_get)(struct drm_i915_private *dev_priv); void (*force_wake_put)(struct drm_i915_private *dev_priv); + void (*set_display_power)(struct drm_i915_private *dev_priv, + bool enable); + bool (*display_power_enabled)(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain); + void (*display_power_get)(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain); + void (*display_power_put)(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain); }; struct intel_uncore { @@ -1702,7 +1710,7 @@ struct drm_i915_file_private { #define HAS_IPS(dev) (IS_ULT(dev)) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) -#define HAS_POWER_WELL(dev) (IS_HASWELL(dev)) +#define HAS_POWER_WELL(dev) (IS_HASWELL(dev) || IS_VALLEYVIEW(dev)) #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev)) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 476d98b..9317383 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -798,6 +798,8 @@ void intel_display_power_get(struct drm_device *dev, enum intel_display_power_domain domain); void intel_display_power_put(struct drm_device *dev, enum intel_display_power_domain domain); +void __intel_power_well_get(struct i915_power_well *power_well); +void __intel_power_well_put(struct i915_power_well *power_well); void intel_init_power_well(struct drm_device *dev); void intel_set_power_well(struct drm_device *dev, bool enable); void intel_enable_gt_powersave(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0b4de57..d1abc42 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5367,146 +5367,48 @@ bool intel_display_power_enabled(struct drm_device *dev, if (!HAS_POWER_WELL(dev)) return true; - switch (domain) { - case POWER_DOMAIN_PIPE_A: - case POWER_DOMAIN_TRANSCODER_EDP: - return true; - case POWER_DOMAIN_VGA: - case POWER_DOMAIN_PIPE_B: - case POWER_DOMAIN_PIPE_C: - case POWER_DOMAIN_PIPE_A_PANEL_FITTER: - case POWER_DOMAIN_PIPE_B_PANEL_FITTER: - case POWER_DOMAIN_PIPE_C_PANEL_FITTER: - case POWER_DOMAIN_TRANSCODER_A: - case POWER_DOMAIN_TRANSCODER_B: - case POWER_DOMAIN_TRANSCODER_C: - return I915_READ(HSW_PWR_WELL_DRIVER) == - (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED); - default: - BUG(); - } + return dev_priv->uncore.funcs.display_power_enabled(dev_priv, domain); } -static void __intel_set_power_well(struct drm_device *dev, bool enable) +void __intel_power_well_get(struct i915_power_well *power_well) { + struct drm_device *dev = power_well->device; struct drm_i915_private *dev_priv = dev->dev_private; - 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"); - } - } else { - if (enable_requested) { - unsigned long irqflags; - enum pipe p; - - I915_WRITE(HSW_PWR_WELL_DRIVER, 0); - POSTING_READ(HSW_PWR_WELL_DRIVER); - DRM_DEBUG_KMS("Requesting to disable the power well\n"); - - /* - * After this, the registers on the pipes that are part - * of the power well will become zero, so we have to - * adjust our counters according to that. - * - * FIXME: Should we do this in general in - * drm_vblank_post_modeset? - */ - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for_each_pipe(p) - if (p != PIPE_A) - dev->last_vblank[p] = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } - } -} - -static void __intel_power_well_get(struct i915_power_well *power_well) -{ if (!power_well->count++) - __intel_set_power_well(power_well->device, true); + dev_priv->uncore.funcs.set_display_power(dev_priv, true); } -static void __intel_power_well_put(struct i915_power_well *power_well) +void __intel_power_well_put(struct i915_power_well *power_well) { + struct drm_device *dev = power_well->device; + struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!power_well->count); if (!--power_well->count) - __intel_set_power_well(power_well->device, false); + dev_priv->uncore.funcs.set_display_power(dev_priv, false); } void intel_display_power_get(struct drm_device *dev, enum intel_display_power_domain domain) { struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_power_well *power_well = &dev_priv->power_well; if (!HAS_POWER_WELL(dev)) return; - switch (domain) { - case POWER_DOMAIN_PIPE_A: - case POWER_DOMAIN_TRANSCODER_EDP: - return; - case POWER_DOMAIN_VGA: - case POWER_DOMAIN_PIPE_B: - case POWER_DOMAIN_PIPE_C: - case POWER_DOMAIN_PIPE_A_PANEL_FITTER: - case POWER_DOMAIN_PIPE_B_PANEL_FITTER: - case POWER_DOMAIN_PIPE_C_PANEL_FITTER: - case POWER_DOMAIN_TRANSCODER_A: - case POWER_DOMAIN_TRANSCODER_B: - case POWER_DOMAIN_TRANSCODER_C: - spin_lock_irq(&power_well->lock); - __intel_power_well_get(power_well); - spin_unlock_irq(&power_well->lock); - return; - default: - BUG(); - } + dev_priv->uncore.funcs.display_power_get(dev_priv, domain); } void intel_display_power_put(struct drm_device *dev, enum intel_display_power_domain domain) { struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_power_well *power_well = &dev_priv->power_well; if (!HAS_POWER_WELL(dev)) return; - switch (domain) { - case POWER_DOMAIN_PIPE_A: - case POWER_DOMAIN_TRANSCODER_EDP: - return; - case POWER_DOMAIN_VGA: - case POWER_DOMAIN_PIPE_B: - case POWER_DOMAIN_PIPE_C: - case POWER_DOMAIN_PIPE_A_PANEL_FITTER: - case POWER_DOMAIN_PIPE_B_PANEL_FITTER: - case POWER_DOMAIN_PIPE_C_PANEL_FITTER: - case POWER_DOMAIN_TRANSCODER_A: - case POWER_DOMAIN_TRANSCODER_B: - case POWER_DOMAIN_TRANSCODER_C: - spin_lock_irq(&power_well->lock); - __intel_power_well_put(power_well); - spin_unlock_irq(&power_well->lock); - return; - default: - BUG(); - } + dev_priv->uncore.funcs.display_power_put(dev_priv, domain); } static struct i915_power_well *hsw_pwr; @@ -5595,7 +5497,8 @@ static void intel_resume_power_well(struct drm_device *dev) return; spin_lock_irq(&power_well->lock); - __intel_set_power_well(dev, power_well->count > 0); + dev_priv->uncore.funcs.set_display_power(dev_priv, + power_well->count > 0); spin_unlock_irq(&power_well->lock); } @@ -5618,8 +5521,9 @@ void intel_init_power_well(struct drm_device *dev) /* 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); + if (IS_HASWELL(dev)) + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST) + I915_WRITE(HSW_PWR_WELL_BIOS, 0); } /* Disables PC8 so we can use the GMBUS and DP AUX interrupts. */ diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 288a3a6..ef5d7fd 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -216,6 +216,209 @@ static void gen6_force_wake_work(struct work_struct *work) spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); } +static void hsw_display_power_get(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + struct i915_power_well *power_well = &dev_priv->power_well; + + switch (domain) { + case POWER_DOMAIN_PIPE_A: + case POWER_DOMAIN_TRANSCODER_EDP: + return; + case POWER_DOMAIN_VGA: + case POWER_DOMAIN_PIPE_B: + case POWER_DOMAIN_PIPE_C: + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + case POWER_DOMAIN_TRANSCODER_A: + case POWER_DOMAIN_TRANSCODER_B: + case POWER_DOMAIN_TRANSCODER_C: + spin_lock_irq(&power_well->lock); + __intel_power_well_get(power_well); + spin_unlock_irq(&power_well->lock); + return; + default: + BUG(); + } +} + +static void hsw_display_power_put(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + struct i915_power_well *power_well = &dev_priv->power_well; + switch (domain) { + case POWER_DOMAIN_PIPE_A: + case POWER_DOMAIN_TRANSCODER_EDP: + return; + case POWER_DOMAIN_VGA: + case POWER_DOMAIN_PIPE_B: + case POWER_DOMAIN_PIPE_C: + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + case POWER_DOMAIN_TRANSCODER_A: + case POWER_DOMAIN_TRANSCODER_B: + case POWER_DOMAIN_TRANSCODER_C: + spin_lock_irq(&power_well->lock); + __intel_power_well_put(power_well); + spin_unlock_irq(&power_well->lock); + return; + default: + BUG(); + } +} + +static void vlv_display_power_get(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + struct i915_power_well *power_well = &dev_priv->power_well; + + spin_lock_irq(&power_well->lock); + __intel_power_well_get(power_well); + spin_unlock_irq(&power_well->lock); +} + +static void vlv_display_power_put(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + struct i915_power_well *power_well = &dev_priv->power_well; + + spin_lock_irq(&power_well->lock); + __intel_power_well_put(power_well); + spin_unlock_irq(&power_well->lock); +} + +static bool hsw_display_power_enabled(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + switch (domain) { + case POWER_DOMAIN_PIPE_A: + case POWER_DOMAIN_TRANSCODER_EDP: + return true; + case POWER_DOMAIN_VGA: + case POWER_DOMAIN_PIPE_B: + case POWER_DOMAIN_PIPE_C: + case POWER_DOMAIN_PIPE_A_PANEL_FITTER: + case POWER_DOMAIN_PIPE_B_PANEL_FITTER: + case POWER_DOMAIN_PIPE_C_PANEL_FITTER: + case POWER_DOMAIN_TRANSCODER_A: + case POWER_DOMAIN_TRANSCODER_B: + case POWER_DOMAIN_TRANSCODER_C: + return I915_READ(HSW_PWR_WELL_DRIVER) == + (HSW_PWR_WELL_ENABLE_REQUEST | + HSW_PWR_WELL_STATE_ENABLED); + default: + BUG(); + } +} + +static bool __vlv_get_power_well(struct drm_i915_private *dev_priv, + u32 pwrgt_mask) +{ + u32 reg_val; + + mutex_lock(&dev_priv->rps.hw_lock); + reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS); + mutex_unlock(&dev_priv->rps.hw_lock); + + return !(reg_val & pwrgt_mask); +} + +static bool vlv_display_power_enabled(struct drm_i915_private *dev_priv, + enum intel_display_power_domain domain) +{ + return __vlv_get_power_well(dev_priv, DISP2D_PWRGT); +} + +static void hsw_set_display_power(struct drm_i915_private *dev_priv, + bool enable) +{ + struct drm_device *dev = dev_priv->dev; + 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"); + } + } else { + if (enable_requested) { + unsigned long irqflags; + enum pipe p; + + I915_WRITE(HSW_PWR_WELL_DRIVER, 0); + POSTING_READ(HSW_PWR_WELL_DRIVER); + DRM_DEBUG_KMS("Requesting to disable the power well\n"); + + /* + * After this, the registers on the pipes that are part + * of the power well will become zero, so we have to + * adjust our counters according to that. + * + * FIXME: Should we do this in general in + * drm_vblank_post_modeset? + */ + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for_each_pipe(p) + if (p != PIPE_A) + dev->last_vblank[p] = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + } + } +} + +static void __vlv_set_power_well(struct drm_i915_private *dev_priv, + u32 pwrgt_mask, bool enable) +{ + u32 reg_val; + + mutex_lock(&dev_priv->rps.hw_lock); + reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS); + if (enable) { + if (reg_val & pwrgt_mask) { + reg_val &= ~pwrgt_mask; + vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, + reg_val); + if (wait_for(!(vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & pwrgt_mask), 100)) + DRM_ERROR("timed out waiting for power well enable\n"); + } + } else { + reg_val |= pwrgt_mask; + vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, reg_val); + if (wait_for(vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & pwrgt_mask, 100)) + DRM_ERROR("timed out waiting for power well disable\n"); } + reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS); + mutex_unlock(&dev_priv->rps.hw_lock); +} + +static void vlv_set_display_power(struct drm_i915_private *dev_priv, + bool enable) +{ + __vlv_set_power_well(dev_priv, DISP2D_PWRGT, enable); +} + +static void vlv_set_render_power(struct drm_i915_private *dev_priv, bool enable) +{ + __vlv_set_power_well(dev_priv, RENDER_PWRGT, enable); +} + +static void vlv_set_media_power(struct drm_i915_private *dev_priv, bool enable) +{ + __vlv_set_power_well(dev_priv, MEDIA_PWRGT, enable); +} + void intel_uncore_early_sanitize(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -234,9 +437,17 @@ void intel_uncore_init(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) { dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; + dev_priv->uncore.funcs.set_display_power = vlv_set_display_power; + dev_priv->uncore.funcs.display_power_enabled = vlv_display_power_enabled; + dev_priv->uncore.funcs.display_power_get = vlv_display_power_get; + dev_priv->uncore.funcs.display_power_put = vlv_display_power_put; } else if (IS_HASWELL(dev)) { dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; + dev_priv->uncore.funcs.set_display_power = hsw_set_display_power; + dev_priv->uncore.funcs.display_power_enabled = hsw_display_power_enabled; + dev_priv->uncore.funcs.display_power_get = hsw_display_power_get; + dev_priv->uncore.funcs.display_power_put = hsw_display_power_put; } else if (IS_IVYBRIDGE(dev)) { u32 ecobus; -- 1.8.3.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx