* [PATCH 00/14] i915 kerneldocs part 1
@ 2014-09-30 8:56 Daniel Vetter
2014-09-30 8:56 ` [PATCH 01/14] drm/i915: Remove intel_modeset_suspend_hw Daniel Vetter
` (14 more replies)
0 siblings, 15 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
Hi all,
So I've decided that it's really time to (slowly) crawl through i915 and
document everything. It's going to take years, but here's a start at least.
I realize that this has good chances to create a constant stream of little
conflicts all over. Well, so be it, I really think we need this.
Overall approach is fairly simple:
1. Clean up interfaces for a set of functions.
2. Extract them into a new file grouped nicely together.
3. Write kerneldoc including short overview section.
4. Repeat.
So here's the first batch. Comments & flames highly welcome. Review assignments
below (counts for all the patches above the block).
Cheers, Daniel
Daniel Vetter (14):
drm/i915: Remove intel_modeset_suspend_hw
drm/i915: Extract intel_runtime_pm.c
drm/i915: Bikeshed rpm functions name a bit.
drm/i915: Move intel_display_set_init_power to intel_runtime_pm.c
drm/i915: Call runtime_pm_disable directly
drm/i915: Kerneldoc for intel_runtime_pm.c
Reviewer: Imre
drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
drm/i915: Use dev_priv instead of dev in irq setup functions
drm/i915: kerneldoc for interrupt enable/disable functions
drm/i915: Extract intel_fifo_underrun.c
drm/i915: Use dev_priv in public intel_fifo_underrun.c functions
drm/i915: Add wrappers to handle fifo underrun interrupts
drm/i915: Filter gmch fifo underruns in the shared handler
drm/i915: kerneldoc for intel_fifo_underrun.c
Reviewer: Paulo
Documentation/DocBook/drm.tmpl | 26 +
drivers/gpu/drm/i915/Makefile | 5 +-
drivers/gpu/drm/i915/i915_debugfs.c | 2 +-
drivers/gpu/drm/i915/i915_dma.c | 25 +-
drivers/gpu/drm/i915/i915_drv.c | 14 +-
drivers/gpu/drm/i915/i915_drv.h | 22 +-
drivers/gpu/drm/i915/i915_irq.c | 491 +++-------
drivers/gpu/drm/i915/intel_crt.c | 2 +-
drivers/gpu/drm/i915/intel_ddi.c | 8 +-
drivers/gpu/drm/i915/intel_display.c | 84 +-
drivers/gpu/drm/i915/intel_dp.c | 2 +-
drivers/gpu/drm/i915/intel_drv.h | 62 +-
drivers/gpu/drm/i915/intel_dsi.c | 2 +-
drivers/gpu/drm/i915/intel_fifo_underrun.c | 380 ++++++++
drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
drivers/gpu/drm/i915/intel_lvds.c | 2 +-
drivers/gpu/drm/i915/intel_pm.c | 1159 -----------------------
drivers/gpu/drm/i915/intel_runtime_pm.c | 1372 ++++++++++++++++++++++++++++
18 files changed, 2016 insertions(+), 1644 deletions(-)
create mode 100644 drivers/gpu/drm/i915/intel_fifo_underrun.c
create mode 100644 drivers/gpu/drm/i915/intel_runtime_pm.c
--
2.1.1
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH 01/14] drm/i915: Remove intel_modeset_suspend_hw
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c Daniel Vetter
` (13 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development
Cc: Daniel Vetter, Daniel Vetter, Reviewed-by: Paulo Zanoni
Another layer of indirection for just an lpt-only w/a is a bit
excessive. Reduce it.
This was added in
commit 7d708ee40a6b9ca1112a322e554c887df105b025
Author: Imre Deak <imre.deak@intel.com>
Date: Wed Apr 17 14:04:50 2013 +0300
drm/i915: HSW: allow PCH clock gating for suspend
Cc: Imre Deak <imre.deak@intel.com>
Cc: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
drivers/gpu/drm/i915/i915_drv.c | 2 +-
drivers/gpu/drm/i915/i915_drv.h | 1 -
drivers/gpu/drm/i915/intel_display.c | 5 -----
3 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 8ce1b13ad97e..f07b8518cd39 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -582,7 +582,7 @@ static int i915_drm_freeze(struct drm_device *dev)
intel_suspend_gt_powersave(dev);
- intel_modeset_suspend_hw(dev);
+ intel_suspend_hw(dev);
}
i915_gem_suspend_gtt_mappings(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 999bd57cab65..bbc16e4622dc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2814,7 +2814,6 @@ static inline void intel_unregister_dsm_handler(void) { return; }
/* modesetting */
extern void intel_modeset_init_hw(struct drm_device *dev);
-extern void intel_modeset_suspend_hw(struct drm_device *dev);
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 858011d22482..d3ebfa02250f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12721,11 +12721,6 @@ void intel_modeset_init_hw(struct drm_device *dev)
intel_enable_gt_powersave(dev);
}
-void intel_modeset_suspend_hw(struct drm_device *dev)
-{
- intel_suspend_hw(dev);
-}
-
void intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c
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 ` Daniel Vetter
2014-09-30 12:22 ` Imre Deak
2014-09-30 8:56 ` [PATCH 03/14] drm/i915: Bikeshed rpm functions name a bit Daniel Vetter
` (12 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Geez is the audio hack ugly.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
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);
--
2.1.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 03/14] drm/i915: Bikeshed rpm functions name a bit.
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 8:56 ` 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
` (11 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
- fini goes with init, so call it intel_power_domains_fini. While
at it shovel some of the fini code that leaked out of it back in.
- give power_enabled functions the verb _is_ to make the meaning clearer.
Also use a __ prefix instead of _unlocked to really discourage users.
- rename runtime_pm_init/fini to enable/disable since that's what they do.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_debugfs.c | 2 +-
drivers/gpu/drm/i915/i915_dma.c | 12 ++++--------
drivers/gpu/drm/i915/i915_drv.h | 2 +-
drivers/gpu/drm/i915/i915_irq.c | 6 +++---
drivers/gpu/drm/i915/intel_crt.c | 2 +-
drivers/gpu/drm/i915/intel_ddi.c | 8 ++++----
drivers/gpu/drm/i915/intel_display.c | 26 +++++++++++++-------------
drivers/gpu/drm/i915/intel_dp.c | 2 +-
drivers/gpu/drm/i915/intel_drv.h | 14 +++++++-------
drivers/gpu/drm/i915/intel_dsi.c | 2 +-
drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
drivers/gpu/drm/i915/intel_lvds.c | 2 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 21 +++++++++++++--------
13 files changed, 51 insertions(+), 50 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 0ba5c7145240..b1b3de2ebde2 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -716,7 +716,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
for_each_pipe(dev_priv, pipe) {
- if (!intel_display_power_enabled(dev_priv,
+ if (!intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_PIPE(pipe))) {
seq_printf(m, "Pipe %c power disabled\n",
pipe_name(pipe));
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 0bc1583114e7..9aeec0df5658 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1798,12 +1798,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (IS_GEN5(dev))
intel_gpu_ips_init(dev_priv);
- intel_init_runtime_pm(dev_priv);
+ intel_runtime_pm_enable(dev_priv);
return 0;
out_power_well:
- intel_power_domains_remove(dev_priv);
+ intel_power_domains_fini(dev_priv);
drm_vblank_cleanup(dev);
out_gem_unload:
WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
@@ -1846,15 +1846,11 @@ int i915_driver_unload(struct drm_device *dev)
return ret;
}
- intel_fini_runtime_pm(dev_priv);
+ intel_runtime_pm_disable(dev_priv);
intel_gpu_ips_teardown();
- /* The i915.ko module is still not prepared to be loaded when
- * the power well is not enabled, so just enable it in case
- * we're going to unload/reload. */
- intel_display_set_init_power(dev_priv, true);
- intel_power_domains_remove(dev_priv);
+ intel_power_domains_fini(dev_priv);
i915_teardown_sysfs(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index bbc16e4622dc..1d8a4b7bf61a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1392,7 +1392,7 @@ struct ilk_wm_values {
*
* Our driver uses the autosuspend delay feature, which means we'll only really
* suspend if we stay with zero refcount for a certain amount of time. The
- * default value is currently very conservative (see intel_init_runtime_pm), but
+ * default value is currently very conservative (see intel_runtime_pm_enable), but
* it can be changed with the standard runtime PM files from sysfs.
*
* The irqs_disabled variable becomes true exactly after we disable the IRQs and
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index a08cdc62f841..1ddfc81caaaa 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -3462,8 +3462,8 @@ static void gen8_irq_reset(struct drm_device *dev)
gen8_gt_irq_reset(dev_priv);
for_each_pipe(dev_priv, pipe)
- if (intel_display_power_enabled(dev_priv,
- POWER_DOMAIN_PIPE(pipe)))
+ if (intel_display_power_is_enabled(dev_priv,
+ POWER_DOMAIN_PIPE(pipe)))
GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
GEN5_IRQ_RESET(GEN8_DE_PORT_);
@@ -3807,7 +3807,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
for_each_pipe(dev_priv, pipe)
- if (intel_display_power_enabled(dev_priv,
+ if (intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_PIPE(pipe)))
GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
dev_priv->de_irq_mask[pipe],
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 9212e6504e0f..dacaad5f4e34 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -72,7 +72,7 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
u32 tmp;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
tmp = I915_READ(crt->adpa_reg);
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index b63d4fa204a3..8a715736dca8 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -962,7 +962,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
uint32_t tmp;
power_domain = intel_display_port_power_domain(intel_encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
if (!intel_encoder->get_hw_state(intel_encoder, &pipe))
@@ -1008,7 +1008,7 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
int i;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
tmp = I915_READ(DDI_BUF_CTL(port));
@@ -1296,7 +1296,7 @@ static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
{
uint32_t val;
- if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(WRPLL_CTL(pll->id));
@@ -1486,7 +1486,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
break;
}
- if (intel_display_power_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
+ if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
if (temp & (AUDIO_OUTPUT_ENABLE_A << (intel_crtc->pipe * 4)))
pipe_config->has_audio = true;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d3ebfa02250f..9c90f1e94ce5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1210,7 +1210,7 @@ void assert_pipe(struct drm_i915_private *dev_priv,
(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
state = true;
- if (!intel_display_power_enabled(dev_priv,
+ if (!intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
cur_state = false;
} else {
@@ -6396,8 +6396,8 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
- if (!intel_display_power_enabled(dev_priv,
- POWER_DOMAIN_PIPE(crtc->pipe)))
+ if (!intel_display_power_is_enabled(dev_priv,
+ POWER_DOMAIN_PIPE(crtc->pipe)))
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
@@ -7406,8 +7406,8 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
- if (!intel_display_power_enabled(dev_priv,
- POWER_DOMAIN_PIPE(crtc->pipe)))
+ if (!intel_display_power_is_enabled(dev_priv,
+ POWER_DOMAIN_PIPE(crtc->pipe)))
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
@@ -7804,7 +7804,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
enum intel_display_power_domain pfit_domain;
uint32_t tmp;
- if (!intel_display_power_enabled(dev_priv,
+ if (!intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_PIPE(crtc->pipe)))
return false;
@@ -7833,7 +7833,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
pipe_config->cpu_transcoder = TRANSCODER_EDP;
}
- if (!intel_display_power_enabled(dev_priv,
+ if (!intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
return false;
@@ -7846,7 +7846,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
intel_get_pipe_timings(crtc, pipe_config);
pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
- if (intel_display_power_enabled(dev_priv, pfit_domain))
+ if (intel_display_power_is_enabled(dev_priv, pfit_domain))
ironlake_get_pfit_config(crtc, pipe_config);
if (IS_HASWELL(dev))
@@ -11436,7 +11436,7 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
{
uint32_t val;
- if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
return false;
val = I915_READ(PCH_DPLL(pll->id));
@@ -13056,7 +13056,7 @@ void i915_redisable_vga(struct drm_device *dev)
* level, just check if the power well is enabled instead of trying to
* follow the "don't touch the power well if we don't need it" policy
* the rest of the driver uses. */
- if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_VGA))
+ if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_VGA))
return;
i915_redisable_vga_power_on(dev);
@@ -13434,8 +13434,8 @@ intel_display_capture_error_state(struct drm_device *dev)
for_each_pipe(dev_priv, i) {
error->pipe[i].power_domain_on =
- intel_display_power_enabled_unlocked(dev_priv,
- POWER_DOMAIN_PIPE(i));
+ __intel_display_power_is_enabled(dev_priv,
+ POWER_DOMAIN_PIPE(i));
if (!error->pipe[i].power_domain_on)
continue;
@@ -13470,7 +13470,7 @@ intel_display_capture_error_state(struct drm_device *dev)
enum transcoder cpu_transcoder = transcoders[i];
error->transcoder[i].power_domain_on =
- intel_display_power_enabled_unlocked(dev_priv,
+ __intel_display_power_is_enabled(dev_priv,
POWER_DOMAIN_TRANSCODER(cpu_transcoder));
if (!error->transcoder[i].power_domain_on)
continue;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c5ec821fa5fb..2bceada656f8 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1819,7 +1819,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
u32 tmp;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
tmp = I915_READ(intel_dp->output_reg);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a963dd870994..8e2cbaa4b61a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1075,15 +1075,15 @@ extern struct drm_display_mode *intel_find_panel_downclock(
/* 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_fini(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);
+void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
+void intel_runtime_pm_disable(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);
+bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain);
+bool __intel_display_power_is_enabled(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,
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 5bd9e09ad3c5..0b184079de14 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -344,7 +344,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
DRM_DEBUG_KMS("\n");
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
/* XXX: this only works for one DSI output */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 7fed5bedc10f..cf87def7b5b3 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -690,7 +690,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
u32 tmp;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
tmp = I915_READ(intel_hdmi->hdmi_reg);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index a6bd1422e38f..2b50c98dd6b0 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -76,7 +76,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
u32 tmp;
power_domain = intel_display_port_power_domain(encoder);
- if (!intel_display_power_enabled(dev_priv, power_domain))
+ if (!intel_display_power_is_enabled(dev_priv, power_domain))
return false;
tmp = I915_READ(lvds_encoder->reg);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 23f97ee79fde..f72cb58ea3c9 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -60,8 +60,8 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
(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)
+bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain)
{
struct i915_power_domains *power_domains;
struct i915_power_well *power_well;
@@ -88,8 +88,8 @@ bool intel_display_power_enabled_unlocked(struct drm_i915_private *dev_priv,
return is_enabled;
}
-bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
- enum intel_display_power_domain domain)
+bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
+ enum intel_display_power_domain domain)
{
struct i915_power_domains *power_domains;
bool ret;
@@ -97,7 +97,7 @@ bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
power_domains = &dev_priv->power_domains;
mutex_lock(&power_domains->lock);
- ret = intel_display_power_enabled_unlocked(dev_priv, domain);
+ ret = __intel_display_power_is_enabled(dev_priv, domain);
mutex_unlock(&power_domains->lock);
return ret;
@@ -981,8 +981,13 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
return 0;
}
-void intel_power_domains_remove(struct drm_i915_private *dev_priv)
+void intel_power_domains_fini(struct drm_i915_private *dev_priv)
{
+ /* The i915.ko module is still not prepared to be loaded when
+ * the power well is not enabled, so just enable it in case
+ * we're going to unload/reload. */
+ intel_display_set_init_power(dev_priv, true);
+
hsw_pwr = NULL;
}
@@ -1097,7 +1102,7 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
-void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
+void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
@@ -1123,7 +1128,7 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
-void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
+void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 04/14] drm/i915: Move intel_display_set_init_power to intel_runtime_pm.c
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (2 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 03/14] drm/i915: Bikeshed rpm functions name a bit Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 05/14] drm/i915: Call runtime_pm_disable directly Daniel Vetter
` (10 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
I've decided to not move intel_display_port_power_domain because
that's just a hack in our design ...
---
drivers/gpu/drm/i915/intel_display.c | 14 --------------
drivers/gpu/drm/i915/intel_drv.h | 3 ++-
drivers/gpu/drm/i915/intel_runtime_pm.c | 14 ++++++++++++++
3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9c90f1e94ce5..1dd470fcddf2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4463,20 +4463,6 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
return mask;
}
-void intel_display_set_init_power(struct drm_i915_private *dev_priv,
- bool enable)
-{
- if (dev_priv->power_domains.init_power_on == enable)
- return;
-
- if (enable)
- intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
- else
- intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
-
- dev_priv->power_domains.init_power_on = enable;
-}
-
static void modeset_update_crtc_power_domains(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8e2cbaa4b61a..ce1b5e99eb56 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -926,7 +926,6 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
bool intel_crtc_active(struct drm_crtc *crtc);
void hsw_enable_ips(struct intel_crtc *crtc);
void hsw_disable_ips(struct intel_crtc *crtc);
-void intel_display_set_init_power(struct drm_i915_private *dev, bool enable);
enum intel_display_power_domain
intel_display_port_power_domain(struct intel_encoder *intel_encoder);
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
@@ -1094,6 +1093,8 @@ 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_display_set_init_power(struct drm_i915_private *dev, bool enable);
+
/* intel_pm.c */
void intel_init_clock_gating(struct drm_device *dev);
void intel_suspend_hw(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index f72cb58ea3c9..db3716d93dcf 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -103,6 +103,20 @@ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
return ret;
}
+void intel_display_set_init_power(struct drm_i915_private *dev_priv,
+ bool enable)
+{
+ if (dev_priv->power_domains.init_power_on == enable)
+ return;
+
+ if (enable)
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+ else
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ dev_priv->power_domains.init_power_on = enable;
+}
+
/*
* 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
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 05/14] drm/i915: Call runtime_pm_disable directly
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (3 preceding siblings ...)
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 ` 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
` (9 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
Allows us to mark it static and so forgoe the kerneldoc for it.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_dma.c | 4 +---
drivers/gpu/drm/i915/intel_drv.h | 1 -
drivers/gpu/drm/i915/intel_runtime_pm.c | 34 +++++++++++++++++----------------
3 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9aeec0df5658..7075bd2adee8 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1846,12 +1846,10 @@ int i915_driver_unload(struct drm_device *dev)
return ret;
}
- intel_runtime_pm_disable(dev_priv);
+ intel_power_domains_fini(dev_priv);
intel_gpu_ips_teardown();
- intel_power_domains_fini(dev_priv);
-
i915_teardown_sysfs(dev);
WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ce1b5e99eb56..bf321993a88e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1077,7 +1077,6 @@ int intel_power_domains_init(struct drm_i915_private *);
void intel_power_domains_fini(struct drm_i915_private *);
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
-void intel_runtime_pm_disable(struct drm_i915_private *dev_priv);
bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index db3716d93dcf..c49fee218e1b 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -995,8 +995,26 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
return 0;
}
+static void intel_runtime_pm_disable(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);
+}
+
void intel_power_domains_fini(struct drm_i915_private *dev_priv)
{
+ intel_runtime_pm_disable(dev_priv);
+
/* The i915.ko module is still not prepared to be loaded when
* the power well is not enabled, so just enable it in case
* we're going to unload/reload. */
@@ -1142,22 +1160,6 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
-void intel_runtime_pm_disable(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)
{
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 06/14] drm/i915: Kerneldoc for intel_runtime_pm.c
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (4 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 05/14] drm/i915: Call runtime_pm_disable directly Daniel Vetter
@ 2014-09-30 8:56 ` 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
` (8 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
I've decided not to document the functions exported to the audio
driver since really, they shouldn't exist ...
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
Documentation/DocBook/drm.tmpl | 12 +++
drivers/gpu/drm/i915/intel_runtime_pm.c | 163 +++++++++++++++++++++++++++++++-
2 files changed, 174 insertions(+), 1 deletion(-)
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 7ad61284ad5f..69e422ab8352 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -3788,6 +3788,18 @@ int num_ioctls;</synopsis>
those have basic support through the gma500 drm driver.
</para>
<sect1>
+ <title>Core Driver Infrastructure</title>
+ <para>
+ This section covers core driver infrastructure used by both the display
+ and the GEM parts of the driver.
+ </para>
+ <sect2>
+ <title>Runtime Power Management</title>
+!Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
+!Idrivers/gpu/drm/i915/intel_runtime_pm.c
+ </sect2>
+ </sect1>
+ <sect1>
<title>Display Hardware Handling</title>
<para>
This section covers everything related to the display hardware including
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index c49fee218e1b..6fa781a5b15c 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -33,6 +33,23 @@
#include "intel_drv.h"
#include <drm/i915_powerwell.h>
+/**
+ * DOC: runtime pm
+ *
+ * The i915 driver supports dynamic enabling and disabling of entire hardware
+ * blocks at runtime. This is especially important on the display side where
+ * software is supposed to control many power gates manually on recent hardware,
+ * since on the GT side a lot of the power management is done by the hardware.
+ * But even there some manual control at the device level is required.
+ *
+ * Since i915 supports a diverse set of platforms with a unified codebase and
+ * hardware engineers just love to shuffle functionality around between power
+ * domains there's a sizeable amount of indirection required. This file provides
+ * generic functions to the driver for grabbing and releasing references for
+ * abstract power domains. It then maps those to the actual power domains
+ * present for a given platform.
+ */
+
static struct i915_power_domains *hsw_pwr;
#define for_each_power_well(i, power_well, domain_mask, power_domains) \
@@ -48,7 +65,7 @@ static struct i915_power_domains *hsw_pwr;
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.
@@ -60,6 +77,18 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
(HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
}
+/**
+ * __intel_display_power_is_enabled - unlocked check for a power domain
+ * @dev_priv: i915 device instance
+ * @domain: power domain to check
+ *
+ * This is the unlocked version of intel_display_power_is_enabled() and should
+ * only be used from error capture and recovery code where deadlocks are
+ * possible.
+ *
+ * Returns:
+ * True when the power domain is enabled, false otherwise.
+ */
bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain)
{
@@ -88,6 +117,23 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
return is_enabled;
}
+/**
+ * intel_display_power_is_enabled - unlocked check for a power domain
+ * @dev_priv: i915 device instance
+ * @domain: power domain to check
+ *
+ * This function can be used to check the hw power domain state. It is mostly
+ * used in hardware state readout functions. Everywhere else code should rely
+ * upon explicit power domain reference counting to ensure that the hardware
+ * block is powered up before accessing it.
+ *
+ * Callers must hold the relevant modesetting locks to ensure that concurrent
+ * threads can't disable the power well while the caller tries to read a few
+ * registers.
+ *
+ * Returns:
+ * True when the power domain is enabled, false otherwise.
+ */
bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain)
{
@@ -103,6 +149,16 @@ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
return ret;
}
+/**
+ * intel_display_set_init_power - set the initial power domain state
+ * @dev_priv: i915 device instance
+ * @enable: whether to enable or disable the initial power domain state
+ *
+ * For simplicity our driver load/unload and system suspend/resume code assumes
+ * that all power domains are always enabled. This functions controls the state
+ * of this little hack. While the initial power domain state is enabled runtime
+ * pm is effectively disabled.
+ */
void intel_display_set_init_power(struct drm_i915_private *dev_priv,
bool enable)
{
@@ -556,6 +612,18 @@ mismatch:
power_well->count, i915.disable_power_well);
}
+/**
+ * intel_display_power_get - grab a power domain reference
+ * @dev_priv: i915 device instance
+ * @domain: power domain to reference
+ *
+ * This function grabs a power domain reference for @domain and ensures that the
+ * power domain and all it's parents are powered up. Therefore users should only
+ * grab a reference to the innermost power domain they need.
+ *
+ * Any power domain reference obtained by this function must have a symmetric
+ * call to intel_display_power_put() to release the reference again.
+ */
void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain)
{
@@ -584,6 +652,15 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
mutex_unlock(&power_domains->lock);
}
+/**
+ * intel_display_power_put - release a power domain reference
+ * @dev_priv: i915 device instance
+ * @domain: power domain to reference
+ *
+ * This function drops the power domain reference obtained by
+ * intel_display_power_get() and might power down the corresponding hardware
+ * block right away if this is the last reference.
+ */
void intel_display_power_put(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain)
{
@@ -968,6 +1045,13 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr
(power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
})
+/**
+ * intel_power_domains_init - initializes the power domain structures
+ * @dev_priv: i915 device instance
+ *
+ * Initializes the power domain structures for @dev_priv depending upon the
+ * supported platform.
+ */
int intel_power_domains_init(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
@@ -1011,6 +1095,14 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
pm_runtime_disable(device);
}
+/**
+ * intel_power_domains_fini - finalizes the power domain structures
+ * @dev_priv: i915 device instance
+ *
+ * Finalizes the power domain structures for @dev_priv depending upon the
+ * supported platform. This function also disables runtime pm and ensures that
+ * the device stays powered up so that the driver can be reloaded.
+ */
void intel_power_domains_fini(struct drm_i915_private *dev_priv)
{
intel_runtime_pm_disable(dev_priv);
@@ -1069,6 +1161,13 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
cmn->ops->disable(dev_priv, cmn);
}
+/**
+ * intel_power_domains_init_hw - initialize hardware power domain state
+ * @dev_priv: i915 device instance
+ *
+ * This function initializes the hardware power domain state and enables all
+ * power domains using intel_display_set_init_power().
+ */
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -1088,16 +1187,46 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
power_domains->initializing = false;
}
+/**
+ * intel_aux_display_runtime_get - grab an auxilliary power domain reference
+ * @dev_priv: i915 device instance
+ *
+ * This function grabs a power domain reference for the auxilliary power domain
+ * (for access to the GMBUS and DP AUX blocks) and ensures that it and all it's
+ * parents are powered up. Therefore users should only grab a reference to the
+ * innermost power domain they need.
+ *
+ * Any power domain reference obtained by this function must have a symmetric
+ * call to intel_aux_display_runtime_put() to release the reference again.
+ */
void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
{
intel_runtime_pm_get(dev_priv);
}
+/**
+ * intel_aux_display_runtime_put - release an auxilliary power domain reference
+ * @dev_priv: i915 device instance
+ *
+ * This function drops the auxilliary power domain reference obtained by
+ * intel_aux_display_runtime_get() and might power down the corresponding
+ * hardware block right away if this is the last reference.
+ */
void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
{
intel_runtime_pm_put(dev_priv);
}
+/**
+ * intel_runtime_pm_get - grab a runtime pm reference
+ * @dev_priv: i915 device instance
+ *
+ * This function grabs a device-level runtime pm reference (mostly used for GEM
+ * code to ensure the GTT or GT is on) and ensures that it is powered up.
+ *
+ * Any power domain reference obtained by this function must have a symmetric
+ * call to intel_runtime_pm_put() to release the reference again.
+ */
void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -1110,6 +1239,20 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
WARN(dev_priv->pm.suspended, "Device still suspended.\n");
}
+/**
+ * intel_runtime_pm_get - grab a runtime pm reference
+ * @dev_priv: i915 device instance
+ *
+ * This function grabs a device-level runtime pm reference (mostly used for GEM
+ * code to ensure the GTT or GT is on).
+ *
+ * It will _not_ power up the device but instead only check that it's power on.
+ * Therefore it is only valid to call this functions from contexts where the
+ * device is known to be powered up and where trying to power it up would result
+ * in hilarity and deadlocks. That pretty much means only the system
+ * suspend/resume code where this is used to grab runtime pm references for
+ * delayed setup down in work items.
+ */
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -1122,6 +1265,14 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
pm_runtime_get_noresume(device);
}
+/**
+ * intel_runtime_pm_put - release a runtime pm reference
+ * @dev_priv: i915 device instance
+ *
+ * This function drops the device-level runtime pm reference obtained by
+ * intel_runtime_pm_get() and might power down the corresponding
+ * hardware block right away if this is the last reference.
+ */
void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -1134,6 +1285,16 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
+/**
+ * intel_runtime_pm_enable - enable runtime pm
+ * @dev_priv: i915 device instance
+ *
+ * This function enables runtime pm at the end of the driver load sequence.
+ *
+ * Note that this function does currently not enable runtime pm for the
+ * subordinate display power domains. That is only done on the first modeset
+ * using intel_display_set_init_power().
+ */
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (5 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 06/14] drm/i915: Kerneldoc for intel_runtime_pm.c Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-10-02 20:36 ` Paulo Zanoni
2014-09-30 8:56 ` [PATCH 08/14] drm/i915: Use dev_priv instead of dev in irq setup functions Daniel Vetter
` (7 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Double negations just parse harder. Also this allows us to ditch some
init code since clearing to 0 dtrt. Also ditch the assignment in
intel_pm_setup, that's not redundant since we do the assignement now
while setting up interrupts.
While at it do engage in a bit of OCD and wrap up the few lines of
setup/teardown code into little helper functions: intel_irq_fini for
cleanup and intel_irq_init_hw for hw setup.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
drivers/gpu/drm/i915/i915_dma.c | 9 +--------
drivers/gpu/drm/i915/i915_drv.h | 4 +++-
drivers/gpu/drm/i915/i915_irq.c | 26 +++++++++++++++++++++-----
drivers/gpu/drm/i915/intel_display.c | 4 +---
drivers/gpu/drm/i915/intel_drv.h | 2 +-
drivers/gpu/drm/i915/intel_pm.c | 1 -
6 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7075bd2adee8..969f0cff9fef 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1338,14 +1338,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_power_domains_init_hw(dev_priv);
- /*
- * We enable some interrupt sources in our postinstall hooks, so mark
- * interrupts as enabled _before_ actually enabling them to avoid
- * special cases in our ordering checks.
- */
- dev_priv->pm._irqs_disabled = false;
-
- ret = drm_irq_install(dev, dev->pdev->irq);
+ ret = intel_irq_init_hw(dev_priv);
if (ret)
goto cleanup_gem_stolen;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1d8a4b7bf61a..1eec0e81a5ca 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1405,7 +1405,7 @@ struct ilk_wm_values {
*/
struct i915_runtime_pm {
bool suspended;
- bool _irqs_disabled;
+ bool irqs_enabled;
};
enum intel_pipe_crc_source {
@@ -2285,6 +2285,8 @@ void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
int new_delay);
extern void intel_irq_init(struct drm_device *dev);
extern void intel_hpd_init(struct drm_device *dev);
+int intel_irq_init_hw(struct drm_i915_private *dev_priv);
+void intel_irq_fini(struct drm_i915_private *dev_priv);
extern void intel_uncore_sanitize(struct drm_device *dev);
extern void intel_uncore_early_sanitize(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1ddfc81caaaa..d9d09a9b4fc7 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -4656,9 +4656,6 @@ void intel_irq_init(struct drm_device *dev)
pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- /* Haven't installed the IRQ handler yet */
- dev_priv->pm._irqs_disabled = true;
-
if (IS_GEN2(dev)) {
dev->max_vblank_count = 0;
dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
@@ -4767,13 +4764,32 @@ void intel_hpd_init(struct drm_device *dev)
spin_unlock_irq(&dev_priv->irq_lock);
}
+int intel_irq_init_hw(struct drm_i915_private *dev_priv)
+{
+ /*
+ * We enable some interrupt sources in our postinstall hooks, so mark
+ * interrupts as enabled _before_ actually enabling them to avoid
+ * special cases in our ordering checks.
+ */
+ dev_priv->pm.irqs_enabled = true;
+
+ return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
+}
+
+void intel_irq_fini(struct drm_i915_private *dev_priv)
+{
+ drm_irq_uninstall(dev_priv->dev);
+ intel_hpd_cancel_work(dev_priv);
+ dev_priv->pm.irqs_enabled = false;
+}
+
/* Disable interrupts so we can allow runtime PM. */
void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
dev->driver->irq_uninstall(dev);
- dev_priv->pm._irqs_disabled = true;
+ dev_priv->pm.irqs_enabled = false;
}
/* Restore interrupts so we can recover from runtime PM. */
@@ -4781,7 +4797,7 @@ void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->pm._irqs_disabled = false;
+ dev_priv->pm.irqs_enabled = true;
dev->driver->irq_preinstall(dev);
dev->driver->irq_postinstall(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1dd470fcddf2..41607ac3e6eb 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13263,9 +13263,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
* Too much stuff here (turning of rps, connectors, ...) would
* experience fancy races otherwise.
*/
- drm_irq_uninstall(dev);
- intel_hpd_cancel_work(dev_priv);
- dev_priv->pm._irqs_disabled = true;
+ intel_irq_fini(dev_priv);
/*
* Due to the hpd irq storm handling the hotplug work can re-arm the
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index bf321993a88e..cf07e2225911 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -764,7 +764,7 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
* We only use drm_irq_uninstall() at unload and VT switch, so
* this is the only thing we need to check.
*/
- return !dev_priv->pm._irqs_disabled;
+ return dev_priv->pm.irqs_enabled;
}
int intel_get_crtc_scanline(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 06c1ea0a7bfd..bf79f86ed06b 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -6507,5 +6507,4 @@ void intel_pm_setup(struct drm_device *dev)
intel_gen6_powersave_work);
dev_priv->pm.suspended = false;
- dev_priv->pm._irqs_disabled = false;
}
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 08/14] drm/i915: Use dev_priv instead of dev in irq setup functions
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (6 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/ Daniel Vetter
@ 2014-09-30 8:56 ` 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
` (6 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
It's the new world order!
Not going full monty on these here and rolling this out throughout the
subsequent call chains since this is just for the kerneldoc. Later on
we can go more crazy, especially once we've embedded drm_device
correctly.
v2: Also frob the runtime_pm functions ...
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
drivers/gpu/drm/i915/i915_dma.c | 4 ++--
drivers/gpu/drm/i915/i915_drv.c | 12 +++++-----
drivers/gpu/drm/i915/i915_drv.h | 4 ++--
drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++------------------
drivers/gpu/drm/i915/intel_drv.h | 4 ++--
drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +-
6 files changed, 31 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 969f0cff9fef..f50ecb18525f 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1363,7 +1363,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
goto cleanup_gem;
/* Only enable hotplug handling once the fbdev is fully set up. */
- intel_hpd_init(dev);
+ intel_hpd_init(dev_priv);
/*
* Some ports require correctly set-up hpd registers for detection to
@@ -1733,7 +1733,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_freewq;
}
- intel_irq_init(dev);
+ intel_irq_init(dev_priv);
intel_uncore_sanitize(dev);
/* Try to make sure MCHBAR is enabled before poking at it */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index f07b8518cd39..605a4c4580d5 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -575,7 +575,7 @@ static int i915_drm_freeze(struct drm_device *dev)
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
- intel_runtime_pm_disable_interrupts(dev);
+ intel_runtime_pm_disable_interrupts(dev_priv);
intel_hpd_cancel_work(dev_priv);
intel_suspend_encoders(dev_priv);
@@ -681,7 +681,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
mutex_unlock(&dev->struct_mutex);
/* We need working interrupts for modeset enabling ... */
- intel_runtime_pm_restore_interrupts(dev);
+ intel_runtime_pm_enable_interrupts(dev_priv);
intel_modeset_init_hw(dev);
@@ -703,7 +703,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
* bother with the tiny race here where we might loose hotplug
* notifications.
* */
- intel_hpd_init(dev);
+ intel_hpd_init(dev_priv);
/* Config may have changed between suspend and resume */
drm_helper_hpd_irq_event(dev);
}
@@ -1446,12 +1446,12 @@ static int intel_runtime_suspend(struct device *device)
* intel_mark_idle().
*/
cancel_work_sync(&dev_priv->rps.work);
- intel_runtime_pm_disable_interrupts(dev);
+ intel_runtime_pm_disable_interrupts(dev_priv);
ret = intel_suspend_complete(dev_priv);
if (ret) {
DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret);
- intel_runtime_pm_restore_interrupts(dev);
+ intel_runtime_pm_enable_interrupts(dev_priv);
return ret;
}
@@ -1511,7 +1511,7 @@ static int intel_runtime_resume(struct device *device)
i915_gem_init_swizzling(dev);
gen6_update_ring_freq(dev);
- intel_runtime_pm_restore_interrupts(dev);
+ intel_runtime_pm_enable_interrupts(dev_priv);
intel_reset_gt_powersave(dev);
if (ret)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1eec0e81a5ca..854f1b92d3df 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2283,8 +2283,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
int new_delay);
-extern void intel_irq_init(struct drm_device *dev);
-extern void intel_hpd_init(struct drm_device *dev);
+extern void intel_irq_init(struct drm_i915_private *dev_priv);
+extern void intel_hpd_init(struct drm_i915_private *dev_priv);
int intel_irq_init_hw(struct drm_i915_private *dev_priv);
void intel_irq_fini(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d9d09a9b4fc7..2c436e6c55b0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -4631,9 +4631,9 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work)
intel_runtime_pm_put(dev_priv);
}
-void intel_irq_init(struct drm_device *dev)
+void intel_irq_init(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_device *dev = dev_priv->dev;
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
@@ -4642,7 +4642,7 @@ void intel_irq_init(struct drm_device *dev)
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
/* Let's track the enabled rps events */
- if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
+ if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
/* WaGsvRC0ResidencyMethod:vlv */
dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
else
@@ -4656,10 +4656,10 @@ void intel_irq_init(struct drm_device *dev)
pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- if (IS_GEN2(dev)) {
+ if (IS_GEN2(dev_priv)) {
dev->max_vblank_count = 0;
dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
- } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+ } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
} else {
@@ -4672,7 +4672,7 @@ void intel_irq_init(struct drm_device *dev)
* Gen2 doesn't have a hardware frame counter and so depends on
* vblank interrupts to produce sane vblank seuquence numbers.
*/
- if (!IS_GEN2(dev))
+ if (!IS_GEN2(dev_priv))
dev->vblank_disable_immediate = true;
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -4680,7 +4680,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
}
- if (IS_CHERRYVIEW(dev)) {
+ if (IS_CHERRYVIEW(dev_priv)) {
dev->driver->irq_handler = cherryview_irq_handler;
dev->driver->irq_preinstall = cherryview_irq_preinstall;
dev->driver->irq_postinstall = cherryview_irq_postinstall;
@@ -4688,7 +4688,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->enable_vblank = valleyview_enable_vblank;
dev->driver->disable_vblank = valleyview_disable_vblank;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
- } else if (IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev_priv)) {
dev->driver->irq_handler = valleyview_irq_handler;
dev->driver->irq_preinstall = valleyview_irq_preinstall;
dev->driver->irq_postinstall = valleyview_irq_postinstall;
@@ -4696,7 +4696,7 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->enable_vblank = valleyview_enable_vblank;
dev->driver->disable_vblank = valleyview_disable_vblank;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
- } else if (IS_GEN8(dev)) {
+ } else if (IS_GEN8(dev_priv)) {
dev->driver->irq_handler = gen8_irq_handler;
dev->driver->irq_preinstall = gen8_irq_reset;
dev->driver->irq_postinstall = gen8_irq_postinstall;
@@ -4713,12 +4713,12 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->disable_vblank = ironlake_disable_vblank;
dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
} else {
- if (INTEL_INFO(dev)->gen == 2) {
+ if (INTEL_INFO(dev_priv)->gen == 2) {
dev->driver->irq_preinstall = i8xx_irq_preinstall;
dev->driver->irq_postinstall = i8xx_irq_postinstall;
dev->driver->irq_handler = i8xx_irq_handler;
dev->driver->irq_uninstall = i8xx_irq_uninstall;
- } else if (INTEL_INFO(dev)->gen == 3) {
+ } else if (INTEL_INFO(dev_priv)->gen == 3) {
dev->driver->irq_preinstall = i915_irq_preinstall;
dev->driver->irq_postinstall = i915_irq_postinstall;
dev->driver->irq_uninstall = i915_irq_uninstall;
@@ -4736,9 +4736,9 @@ void intel_irq_init(struct drm_device *dev)
}
}
-void intel_hpd_init(struct drm_device *dev)
+void intel_hpd_init(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_device *dev = dev_priv->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
int i;
@@ -4784,20 +4784,16 @@ void intel_irq_fini(struct drm_i915_private *dev_priv)
}
/* Disable interrupts so we can allow runtime PM. */
-void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
+void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- dev->driver->irq_uninstall(dev);
+ dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
dev_priv->pm.irqs_enabled = false;
}
/* Restore interrupts so we can recover from runtime PM. */
-void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
+void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
dev_priv->pm.irqs_enabled = true;
- dev->driver->irq_preinstall(dev);
- dev->driver->irq_postinstall(dev);
+ dev_priv->dev->driver->irq_preinstall(dev_priv->dev);
+ dev_priv->dev->driver->irq_postinstall(dev_priv->dev);
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cf07e2225911..aba3ea938427 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -756,8 +756,8 @@ void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen8_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
-void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
-void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
+void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
+void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
static inline bool intel_irqs_enabled(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
index 6fa781a5b15c..8e322513a44a 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -377,7 +377,7 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
if (dev_priv->power_domains.initializing)
return;
- intel_hpd_init(dev_priv->dev);
+ intel_hpd_init(dev_priv);
i915_redisable_vga_power_on(dev_priv->dev);
}
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 09/14] drm/i915: kerneldoc for interrupt enable/disable functions
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (7 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 08/14] drm/i915: Use dev_priv instead of dev in irq setup functions Daniel Vetter
@ 2014-09-30 8:56 ` 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
` (5 subsequent siblings)
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Just start with the basics for now.
Since there's a lot of different functionality in i915_irq.c I've
decided to split it into different sections and pull in just the
relevant functions. Splitting into different files looks like a lot
more work since the interrupt handlers do an awful lot of reuse all
over.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
Documentation/DocBook/drm.tmpl | 9 ++++++
drivers/gpu/drm/i915/i915_irq.c | 61 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 69e422ab8352..e8ef0f9c7396 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -3798,6 +3798,14 @@ int num_ioctls;</synopsis>
!Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
!Idrivers/gpu/drm/i915/intel_runtime_pm.c
</sect2>
+ <sect2>
+ <title>Interrupt Handling</title>
+!Pdrivers/gpu/drm/i915/i915_irq.c interrupt handling
+!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_init intel_irq_init_hw intel_hpd_init
+!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_fini
+!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
+!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
+ </sect2>
</sect1>
<sect1>
<title>Display Hardware Handling</title>
@@ -3951,5 +3959,6 @@ int num_ioctls;</synopsis>
</sect2>
</sect1>
</chapter>
+!Cdrivers/gpu/drm/i915/i915_irq.c
</part>
</book>
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 2c436e6c55b0..039625c22be4 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -37,6 +37,14 @@
#include "i915_trace.h"
#include "intel_drv.h"
+/**
+ * DOC: interrupt handling
+ *
+ * These functions provide the basic support for enabling and disabling the
+ * interrupt handling support. There's a lot more functionality in i915_irq.c
+ * and related files, but that will be described in separate chapters.
+ */
+
static const u32 hpd_ibx[] = {
[HPD_CRT] = SDE_CRT_HOTPLUG,
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
@@ -4631,6 +4639,13 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work)
intel_runtime_pm_put(dev_priv);
}
+/**
+ * intel_irq_init - initializes irq support
+ * @dev_priv: i915 device instance
+ *
+ * This function initializes all the irq support including work items, timers
+ * and all the vtables. It does not setup the interrupt itself though.
+ */
void intel_irq_init(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -4736,6 +4751,18 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
}
}
+/**
+ * intel_hpd_init - initializes and enables hpd support
+ * @dev_priv: i915 device instance
+ *
+ * This function enables the hotplug support. It requires that interrupts have
+ * already been enabled with intel_irq_init_hw(). From this point on hotplug and
+ * poll request can run concurrently to other code, so locking rules must be
+ * obeyed.
+ *
+ * This is a separate step from interrupt enabling to simplify the locking rules
+ * in the driver load and resume code.
+ */
void intel_hpd_init(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -4764,6 +4791,17 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock);
}
+/**
+ * intel_irq_init_hw - enables the hardware interrupt
+ * @dev_priv: i915 device instance
+ *
+ * This function enables the hardware interrupt handling, but leaves the hotplug
+ * handling still disabled. It is called after intel_irq_init().
+ *
+ * In the driver load and resume code we need working interrupts in a few places
+ * but don't want to deal with the hassle of concurrent probe and hotplug
+ * workers. Hence the split into this two-stage approach.
+ */
int intel_irq_init_hw(struct drm_i915_private *dev_priv)
{
/*
@@ -4776,6 +4814,13 @@ int intel_irq_init_hw(struct drm_i915_private *dev_priv)
return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
}
+/**
+ * intel_irq_fini - finilizes all irq handling
+ * @dev_priv: i915 device instance
+ *
+ * This stops interrupt and hotplug handling and unregisters and frees all
+ * resources acquired in the init functions.
+ */
void intel_irq_fini(struct drm_i915_private *dev_priv)
{
drm_irq_uninstall(dev_priv->dev);
@@ -4783,14 +4828,26 @@ void intel_irq_fini(struct drm_i915_private *dev_priv)
dev_priv->pm.irqs_enabled = false;
}
-/* Disable interrupts so we can allow runtime PM. */
+/**
+ * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
+ * @dev_priv: i915 device instance
+ *
+ * This function is used to disable interrupts at runtime, both in the runtime
+ * pm and the system suspend/resume code.
+ */
void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
{
dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
dev_priv->pm.irqs_enabled = false;
}
-/* Restore interrupts so we can recover from runtime PM. */
+/**
+ * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
+ * @dev_priv: i915 device instance
+ *
+ * This function is used to enable interrupts at runtime, both in the runtime
+ * pm and the system suspend/resume code.
+ */
void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
{
dev_priv->pm.irqs_enabled = true;
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 10/14] drm/i915: Extract intel_fifo_underrun.c
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (8 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 09/14] drm/i915: kerneldoc for interrupt enable/disable functions Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 11/14] drm/i915: Use dev_priv in public intel_fifo_underrun.c functions Daniel Vetter
` (4 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Prep work for some nice documentation. Requires that we export the
display irq enable/disable functions on ilk/ibx. But we already export
them for vlv/i915. So not more inconsistency.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/i915_drv.h | 11 +
drivers/gpu/drm/i915/i915_irq.c | 296 +--------------------------
drivers/gpu/drm/i915/intel_drv.h | 9 +-
drivers/gpu/drm/i915/intel_fifo_underrun.c | 311 +++++++++++++++++++++++++++++
5 files changed, 334 insertions(+), 294 deletions(-)
create mode 100644 drivers/gpu/drm/i915/intel_fifo_underrun.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 3a6bce047f6f..75fd7de9bf4b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -45,6 +45,7 @@ i915-y += intel_renderstate_gen6.o \
# modesetting core code
i915-y += intel_bios.o \
intel_display.o \
+ intel_fifo_underrun.o \
intel_frontbuffer.o \
intel_modes.o \
intel_overlay.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 854f1b92d3df..aa23d99b7b8b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2306,6 +2306,17 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv);
void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
+void
+ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
+void
+ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
+void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask);
+#define ibx_enable_display_interrupt(dev_priv, bits) \
+ ibx_display_interrupt_update((dev_priv), (bits), (bits))
+#define ibx_disable_display_interrupt(dev_priv, bits) \
+ ibx_display_interrupt_update((dev_priv), (bits), 0)
/* i915_gem.c */
int i915_gem_init_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 039625c22be4..8e33180e01df 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -139,7 +139,7 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
} while (0)
/* For display hotplug interrupt */
-static void
+void
ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
{
assert_spin_locked(&dev_priv->irq_lock);
@@ -154,7 +154,7 @@ ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
}
}
-static void
+void
ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
{
assert_spin_locked(&dev_priv->irq_lock);
@@ -238,24 +238,6 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
snb_update_pm_irq(dev_priv, mask, 0);
}
-static bool ivb_can_enable_err_int(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *crtc;
- enum pipe pipe;
-
- assert_spin_locked(&dev_priv->irq_lock);
-
- for_each_pipe(dev_priv, pipe) {
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-
- if (crtc->cpu_fifo_underrun_disabled)
- return false;
- }
-
- return true;
-}
-
/**
* bdw_update_pm_irq - update GT interrupt 2
* @dev_priv: driver private
@@ -296,130 +278,15 @@ void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
bdw_update_pm_irq(dev_priv, mask, 0);
}
-static bool cpt_can_enable_serr_int(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- enum pipe pipe;
- struct intel_crtc *crtc;
-
- assert_spin_locked(&dev_priv->irq_lock);
-
- for_each_pipe(dev_priv, pipe) {
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-
- if (crtc->pch_fifo_underrun_disabled)
- return false;
- }
-
- return true;
-}
-
-void i9xx_check_fifo_underruns(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *crtc;
-
- spin_lock_irq(&dev_priv->irq_lock);
-
- for_each_intel_crtc(dev, crtc) {
- u32 reg = PIPESTAT(crtc->pipe);
- u32 pipestat;
-
- if (crtc->cpu_fifo_underrun_disabled)
- continue;
-
- pipestat = I915_READ(reg) & 0xffff0000;
- if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
- continue;
-
- I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
- POSTING_READ(reg);
-
- DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
- }
-
- spin_unlock_irq(&dev_priv->irq_lock);
-}
-
-static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe,
- bool enable, bool old)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg = PIPESTAT(pipe);
- u32 pipestat = I915_READ(reg) & 0xffff0000;
-
- assert_spin_locked(&dev_priv->irq_lock);
-
- if (enable) {
- I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
- POSTING_READ(reg);
- } else {
- if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
- DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
- }
-}
-
-static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe, bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
- DE_PIPEB_FIFO_UNDERRUN;
-
- if (enable)
- ironlake_enable_display_irq(dev_priv, bit);
- else
- ironlake_disable_display_irq(dev_priv, bit);
-}
-
-static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe,
- bool enable, bool old)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- if (enable) {
- I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
-
- if (!ivb_can_enable_err_int(dev))
- return;
-
- ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
- } else {
- ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
-
- if (old &&
- I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
- DRM_ERROR("uncleared fifo underrun on pipe %c\n",
- pipe_name(pipe));
- }
- }
-}
-
-static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe, bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- assert_spin_locked(&dev_priv->irq_lock);
-
- if (enable)
- dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
- else
- dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
- I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
- POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
-}
-
/**
* ibx_display_interrupt_update - update SDEIMR
* @dev_priv: driver private
* @interrupt_mask: mask of interrupt bits to update
* @enabled_irq_mask: mask of interrupt bits to enable
*/
-static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
- uint32_t interrupt_mask,
- uint32_t enabled_irq_mask)
+void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask)
{
uint32_t sdeimr = I915_READ(SDEIMR);
sdeimr &= ~interrupt_mask;
@@ -433,159 +300,6 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
I915_WRITE(SDEIMR, sdeimr);
POSTING_READ(SDEIMR);
}
-#define ibx_enable_display_interrupt(dev_priv, bits) \
- ibx_display_interrupt_update((dev_priv), (bits), (bits))
-#define ibx_disable_display_interrupt(dev_priv, bits) \
- ibx_display_interrupt_update((dev_priv), (bits), 0)
-
-static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
- enum transcoder pch_transcoder,
- bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
- SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
-
- if (enable)
- ibx_enable_display_interrupt(dev_priv, bit);
- else
- ibx_disable_display_interrupt(dev_priv, bit);
-}
-
-static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
- enum transcoder pch_transcoder,
- bool enable, bool old)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (enable) {
- I915_WRITE(SERR_INT,
- SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
-
- if (!cpt_can_enable_serr_int(dev))
- return;
-
- ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
- } else {
- ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
-
- if (old && I915_READ(SERR_INT) &
- SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
- DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
- transcoder_name(pch_transcoder));
- }
- }
-}
-
-/**
- * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
- * @pipe: pipe
- * @enable: true if we want to report FIFO underrun errors, false otherwise
- *
- * This function makes us disable or enable CPU fifo underruns for a specific
- * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
- * reporting for one pipe may also disable all the other CPU error interruts for
- * the other pipes, due to the fact that there's just one interrupt mask/enable
- * bit for all the pipes.
- *
- * Returns the previous state of underrun reporting.
- */
-static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe, bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- bool old;
-
- assert_spin_locked(&dev_priv->irq_lock);
-
- old = !intel_crtc->cpu_fifo_underrun_disabled;
- intel_crtc->cpu_fifo_underrun_disabled = !enable;
-
- if (HAS_GMCH_DISPLAY(dev))
- i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
- else if (IS_GEN5(dev) || IS_GEN6(dev))
- ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
- else if (IS_GEN7(dev))
- ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
- else if (IS_GEN8(dev))
- broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
-
- return old;
-}
-
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
- enum pipe pipe, bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long flags;
- bool ret;
-
- spin_lock_irqsave(&dev_priv->irq_lock, flags);
- ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
- spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
-
- return ret;
-}
-
-static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
- enum pipe pipe)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
- return !intel_crtc->cpu_fifo_underrun_disabled;
-}
-
-/**
- * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
- * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
- * @enable: true if we want to report FIFO underrun errors, false otherwise
- *
- * This function makes us disable or enable PCH fifo underruns for a specific
- * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
- * underrun reporting for one transcoder may also disable all the other PCH
- * error interruts for the other transcoders, due to the fact that there's just
- * one interrupt mask/enable bit for all the transcoders.
- *
- * Returns the previous state of underrun reporting.
- */
-bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
- enum transcoder pch_transcoder,
- bool enable)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- unsigned long flags;
- bool old;
-
- /*
- * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
- * has only one pch transcoder A that all pipes can use. To avoid racy
- * pch transcoder -> pipe lookups from interrupt code simply store the
- * underrun statistics in crtc A. Since we never expose this anywhere
- * nor use it outside of the fifo underrun code here using the "wrong"
- * crtc on LPT won't cause issues.
- */
-
- spin_lock_irqsave(&dev_priv->irq_lock, flags);
-
- old = !intel_crtc->pch_fifo_underrun_disabled;
- intel_crtc->pch_fifo_underrun_disabled = !enable;
-
- if (HAS_PCH_IBX(dev))
- ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
- else
- cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
-
- spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
- return old;
-}
static void
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index aba3ea938427..90c30bf7ac10 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -743,13 +743,17 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
return container_of(intel_hdmi, struct intel_digital_port, hdmi);
}
-
-/* i915_irq.c */
+/* intel_fifo_underrun.c */
bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
enum pipe pipe, bool enable);
bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
enum transcoder pch_transcoder,
bool enable);
+void i9xx_check_fifo_underruns(struct drm_device *dev);
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+ enum pipe pipe);
+
+/* i915_irq.c */
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
@@ -768,7 +772,6 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
}
int intel_get_crtc_scanline(struct intel_crtc *crtc);
-void i9xx_check_fifo_underruns(struct drm_device *dev);
void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv);
/* intel_crt.c */
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
new file mode 100644
index 000000000000..783794839e16
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+static bool ivb_can_enable_err_int(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ enum pipe pipe;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ for_each_pipe(dev_priv, pipe) {
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+ if (crtc->cpu_fifo_underrun_disabled)
+ return false;
+ }
+
+ return true;
+}
+
+static bool cpt_can_enable_serr_int(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum pipe pipe;
+ struct intel_crtc *crtc;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ for_each_pipe(dev_priv, pipe) {
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+ if (crtc->pch_fifo_underrun_disabled)
+ return false;
+ }
+
+ return true;
+}
+
+void i9xx_check_fifo_underruns(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+
+ spin_lock_irq(&dev_priv->irq_lock);
+
+ for_each_intel_crtc(dev, crtc) {
+ u32 reg = PIPESTAT(crtc->pipe);
+ u32 pipestat;
+
+ if (crtc->cpu_fifo_underrun_disabled)
+ continue;
+
+ pipestat = I915_READ(reg) & 0xffff0000;
+ if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
+ continue;
+
+ I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+ POSTING_READ(reg);
+
+ DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
+ }
+
+ spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe,
+ bool enable, bool old)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg = PIPESTAT(pipe);
+ u32 pipestat = I915_READ(reg) & 0xffff0000;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if (enable) {
+ I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+ POSTING_READ(reg);
+ } else {
+ if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+ }
+}
+
+static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
+ DE_PIPEB_FIFO_UNDERRUN;
+
+ if (enable)
+ ironlake_enable_display_irq(dev_priv, bit);
+ else
+ ironlake_disable_display_irq(dev_priv, bit);
+}
+
+static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe,
+ bool enable, bool old)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ if (enable) {
+ I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+
+ if (!ivb_can_enable_err_int(dev))
+ return;
+
+ ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ } else {
+ ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+
+ if (old &&
+ I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
+ DRM_ERROR("uncleared fifo underrun on pipe %c\n",
+ pipe_name(pipe));
+ }
+ }
+}
+
+static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ if (enable)
+ dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
+ else
+ dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
+ I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+ POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+}
+
+static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
+ SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
+
+ if (enable)
+ ibx_enable_display_interrupt(dev_priv, bit);
+ else
+ ibx_disable_display_interrupt(dev_priv, bit);
+}
+
+static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable, bool old)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (enable) {
+ I915_WRITE(SERR_INT,
+ SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+
+ if (!cpt_can_enable_serr_int(dev))
+ return;
+
+ ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
+ } else {
+ ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
+
+ if (old && I915_READ(SERR_INT) &
+ SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
+ DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
+ transcoder_name(pch_transcoder));
+ }
+ }
+}
+
+/**
+ * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pipe: pipe
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable CPU fifo underruns for a specific
+ * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
+ * reporting for one pipe may also disable all the other CPU error interruts for
+ * the other pipes, due to the fact that there's just one interrupt mask/enable
+ * bit for all the pipes.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ bool old;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ old = !intel_crtc->cpu_fifo_underrun_disabled;
+ intel_crtc->cpu_fifo_underrun_disabled = !enable;
+
+ if (HAS_GMCH_DISPLAY(dev))
+ i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
+ ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
+ else if (IS_GEN7(dev))
+ ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
+ else if (IS_GEN8(dev))
+ broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
+
+ return old;
+}
+
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+ ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+ return ret;
+}
+
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+ enum pipe pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ return !intel_crtc->cpu_fifo_underrun_disabled;
+}
+
+/**
+ * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable PCH fifo underruns for a specific
+ * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
+ * underrun reporting for one transcoder may also disable all the other PCH
+ * error interruts for the other transcoders, due to the fact that there's just
+ * one interrupt mask/enable bit for all the transcoders.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ unsigned long flags;
+ bool old;
+
+ /*
+ * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
+ * has only one pch transcoder A that all pipes can use. To avoid racy
+ * pch transcoder -> pipe lookups from interrupt code simply store the
+ * underrun statistics in crtc A. Since we never expose this anywhere
+ * nor use it outside of the fifo underrun code here using the "wrong"
+ * crtc on LPT won't cause issues.
+ */
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+
+ old = !intel_crtc->pch_fifo_underrun_disabled;
+ intel_crtc->pch_fifo_underrun_disabled = !enable;
+
+ if (HAS_PCH_IBX(dev))
+ ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+ else
+ cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
+
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+ return old;
+}
--
2.1.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 11/14] drm/i915: Use dev_priv in public intel_fifo_underrun.c functions
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (9 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 10/14] drm/i915: Extract intel_fifo_underrun.c Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 12/14] drm/i915: Add wrappers to handle fifo underrun interrupts Daniel Vetter
` (3 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
It's the new rule!
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++++-----------
drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++-------------
drivers/gpu/drm/i915/intel_drv.h | 8 +++----
drivers/gpu/drm/i915/intel_fifo_underrun.c | 25 ++++++++++-----------
4 files changed, 58 insertions(+), 45 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8e33180e01df..bf695839c5d6 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1772,7 +1772,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
* handle.
*/
mask = 0;
- if (__cpu_fifo_underrun_reporting_enabled(dev, pipe))
+ if (__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
mask |= PIPE_FIFO_UNDERRUN_STATUS;
switch (pipe) {
@@ -1819,7 +1819,8 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe,
+ false))
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
}
@@ -1987,12 +1988,14 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
if (pch_iir & SDE_TRANSA_FIFO_UNDER)
- if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv,
+ TRANSCODER_A,
false))
DRM_ERROR("PCH transcoder A FIFO underrun\n");
if (pch_iir & SDE_TRANSB_FIFO_UNDER)
- if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv,
+ TRANSCODER_B,
false))
DRM_ERROR("PCH transcoder B FIFO underrun\n");
}
@@ -2008,7 +2011,7 @@ static void ivb_err_int_handler(struct drm_device *dev)
for_each_pipe(dev_priv, pipe) {
if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
- if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
+ if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe,
false))
DRM_ERROR("Pipe %c FIFO underrun\n",
pipe_name(pipe));
@@ -2034,17 +2037,17 @@ static void cpt_serr_int_handler(struct drm_device *dev)
DRM_ERROR("PCH poison interrupt\n");
if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
false))
DRM_ERROR("PCH transcoder A FIFO underrun\n");
if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_B,
false))
DRM_ERROR("PCH transcoder B FIFO underrun\n");
if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_C,
false))
DRM_ERROR("PCH transcoder C FIFO underrun\n");
@@ -2112,7 +2115,9 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
intel_check_page_flip(dev, pipe);
if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
- if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+ if (intel_set_cpu_fifo_underrun_reporting(dev_priv,
+ pipe,
+ false))
DRM_ERROR("Pipe %c FIFO underrun\n",
pipe_name(pipe));
@@ -2328,7 +2333,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
hsw_pipe_crc_irq_handler(dev, pipe);
if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
- if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
+ if (intel_set_cpu_fifo_underrun_reporting(dev_priv,
+ pipe,
false))
DRM_ERROR("Pipe %c FIFO underrun\n",
pipe_name(pipe));
@@ -3835,7 +3841,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+ intel_set_cpu_fifo_underrun_reporting(dev_priv,
+ pipe, false))
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
}
@@ -4029,7 +4036,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+ intel_set_cpu_fifo_underrun_reporting(dev_priv,
+ pipe, false))
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
}
@@ -4257,7 +4265,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
i9xx_pipe_crc_irq_handler(dev, pipe);
if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+ intel_set_cpu_fifo_underrun_reporting(dev_priv,
+ pipe, false))
DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 41607ac3e6eb..33d3fba26864 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4069,8 +4069,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
- intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
@@ -4179,13 +4179,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
if (intel_crtc->config.has_pch_encoder) {
- intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ true);
dev_priv->display.fdi_link_train(crtc);
}
@@ -4261,7 +4262,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
encoder->disable(encoder);
if (intel_crtc->config.has_pch_encoder)
- intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
intel_disable_pipe(intel_crtc);
@@ -4275,7 +4276,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
ironlake_fdi_disable(crtc);
ironlake_disable_pch_transcoder(dev_priv, pipe);
- intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
if (HAS_PCH_CPT(dev)) {
/* disable TRANS_DP_CTL */
@@ -4328,7 +4329,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
}
if (intel_crtc->config.has_pch_encoder)
- intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ false);
intel_disable_pipe(intel_crtc);
if (intel_crtc->config.dp_encoder_is_mst)
@@ -4342,7 +4344,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
if (intel_crtc->config.has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
- intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
+ intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
+ true);
intel_ddi_fdi_disable(crtc);
}
@@ -4719,6 +4722,7 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
static void valleyview_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
@@ -4747,7 +4751,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_pll_enable)
@@ -4780,7 +4784,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
intel_crtc_enable_planes(crtc);
/* Underruns don't raise interrupts, so check manually. */
- i9xx_check_fifo_underruns(dev);
+ i9xx_check_fifo_underruns(dev_priv);
}
static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
@@ -4795,6 +4799,7 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
static void i9xx_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
int pipe = intel_crtc->pipe;
@@ -4816,7 +4821,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
if (!IS_GEN2(dev))
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
@@ -4847,10 +4852,10 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
* but leave the pipe running.
*/
if (IS_GEN2(dev))
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
/* Underruns don't raise interrupts, so check manually. */
- i9xx_check_fifo_underruns(dev);
+ i9xx_check_fifo_underruns(dev_priv);
}
static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@ -4886,7 +4891,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
* but leave the pipe running.
*/
if (IS_GEN2(dev))
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
/*
* Vblank time updates from the shadow to live plane control register
@@ -4932,7 +4937,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
}
if (!IS_GEN2(dev))
- intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
+ intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
intel_crtc->active = false;
intel_update_watermarks(crtc);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 90c30bf7ac10..5e7bfec646c2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -744,13 +744,13 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
}
/* intel_fifo_underrun.c */
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum pipe pipe, bool enable);
-bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder,
bool enable);
-void i9xx_check_fifo_underruns(struct drm_device *dev);
-bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
enum pipe pipe);
/* i915_irq.c */
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 783794839e16..0b4eaf94b3e7 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -64,14 +64,13 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
return true;
}
-void i9xx_check_fifo_underruns(struct drm_device *dev)
+void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc;
spin_lock_irq(&dev_priv->irq_lock);
- for_each_intel_crtc(dev, crtc) {
+ for_each_intel_crtc(dev_priv->dev, crtc) {
u32 reg = PIPESTAT(crtc->pipe);
u32 pipestat;
@@ -239,24 +238,23 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
return old;
}
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum pipe pipe, bool enable)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long flags;
bool ret;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
+ ret = __intel_set_cpu_fifo_underrun_reporting(dev_priv->dev, pipe,
+ enable);
spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
return ret;
}
-bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -277,11 +275,10 @@ bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
*
* Returns the previous state of underrun reporting.
*/
-bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder,
bool enable)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
unsigned long flags;
@@ -301,10 +298,12 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
old = !intel_crtc->pch_fifo_underrun_disabled;
intel_crtc->pch_fifo_underrun_disabled = !enable;
- if (HAS_PCH_IBX(dev))
- ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+ if (HAS_PCH_IBX(dev_priv->dev))
+ ibx_set_fifo_underrun_reporting(dev_priv->dev, pch_transcoder,
+ enable);
else
- cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
+ cpt_set_fifo_underrun_reporting(dev_priv->dev, pch_transcoder,
+ enable, old);
spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
return old;
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 12/14] drm/i915: Add wrappers to handle fifo underrun interrupts
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (10 preceding siblings ...)
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 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 13/14] drm/i915: Filter gmch fifo underruns in the shared handler Daniel Vetter
` (2 subsequent siblings)
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Way too much copypasta all over. And this also clarifies a bit what's
going on since it separates the "do we have an underrun irq" from the
"should we report the underrun" check.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
drivers/gpu/drm/i915/i915_irq.c | 69 ++++++++----------------------
drivers/gpu/drm/i915/intel_drv.h | 4 ++
drivers/gpu/drm/i915/intel_fifo_underrun.c | 17 ++++++++
3 files changed, 39 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index bf695839c5d6..27aa43672d5c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1818,10 +1818,8 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe,
- false))
- DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
}
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
@@ -1988,16 +1986,10 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
if (pch_iir & SDE_TRANSA_FIFO_UNDER)
- if (intel_set_pch_fifo_underrun_reporting(dev_priv,
- TRANSCODER_A,
- false))
- DRM_ERROR("PCH transcoder A FIFO underrun\n");
+ intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_A);
if (pch_iir & SDE_TRANSB_FIFO_UNDER)
- if (intel_set_pch_fifo_underrun_reporting(dev_priv,
- TRANSCODER_B,
- false))
- DRM_ERROR("PCH transcoder B FIFO underrun\n");
+ intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_B);
}
static void ivb_err_int_handler(struct drm_device *dev)
@@ -2010,12 +2002,8 @@ static void ivb_err_int_handler(struct drm_device *dev)
DRM_ERROR("Poison interrupt\n");
for_each_pipe(dev_priv, pipe) {
- if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
- if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe,
- false))
- DRM_ERROR("Pipe %c FIFO underrun\n",
- pipe_name(pipe));
- }
+ if (err_int & ERR_INT_FIFO_UNDERRUN(pipe))
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
if (IS_IVYBRIDGE(dev))
@@ -2037,19 +2025,13 @@ static void cpt_serr_int_handler(struct drm_device *dev)
DRM_ERROR("PCH poison interrupt\n");
if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
- false))
- DRM_ERROR("PCH transcoder A FIFO underrun\n");
+ intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_A);
if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_B,
- false))
- DRM_ERROR("PCH transcoder B FIFO underrun\n");
+ intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_B);
if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
- if (intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_C,
- false))
- DRM_ERROR("PCH transcoder C FIFO underrun\n");
+ intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_C);
I915_WRITE(SERR_INT, serr_int);
}
@@ -2115,11 +2097,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
intel_check_page_flip(dev, pipe);
if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
- if (intel_set_cpu_fifo_underrun_reporting(dev_priv,
- pipe,
- false))
- DRM_ERROR("Pipe %c FIFO underrun\n",
- pipe_name(pipe));
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
if (de_iir & DE_PIPE_CRC_DONE(pipe))
i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -2332,13 +2310,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
hsw_pipe_crc_irq_handler(dev, pipe);
- if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
- if (intel_set_cpu_fifo_underrun_reporting(dev_priv,
- pipe,
- false))
- DRM_ERROR("Pipe %c FIFO underrun\n",
- pipe_name(pipe));
- }
+ if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN)
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
@@ -3840,10 +3813,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev_priv,
- pipe, false))
- DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
}
iir = new_iir;
@@ -4035,10 +4006,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev_priv,
- pipe, false))
- DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
}
if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -4264,10 +4233,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
i9xx_pipe_crc_irq_handler(dev, pipe);
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
- intel_set_cpu_fifo_underrun_reporting(dev_priv,
- pipe, false))
- DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
}
if (blc_event || (iir & I915_ASLE_INTERRUPT))
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5e7bfec646c2..c91737dbbc5d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -749,6 +749,10 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder,
bool enable);
+void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
+ enum pipe pipe);
+void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
+ enum transcoder pch_transcoder);
void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
enum pipe pipe);
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 0b4eaf94b3e7..854d29e18555 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -308,3 +308,20 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
return old;
}
+
+void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
+{
+ if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
+ DRM_ERROR("CPU pipe %c FIFO underrun\n",
+ pipe_name(pipe));
+}
+
+void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
+ enum transcoder pch_transcoder)
+{
+ if (intel_set_pch_fifo_underrun_reporting(dev_priv, pch_transcoder,
+ false))
+ DRM_ERROR("PCH transcoder %c FIFO underrun\n",
+ transcoder_name(pch_transcoder));
+}
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 13/14] drm/i915: Filter gmch fifo underruns in the shared handler
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (11 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 12/14] drm/i915: Add wrappers to handle fifo underrun interrupts Daniel Vetter
@ 2014-09-30 8:56 ` Daniel Vetter
2014-09-30 8:56 ` [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c Daniel Vetter
2014-09-30 13:16 ` [PATCH 00/14] i915 kerneldocs part 1 Imre Deak
14 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter
This simplifies the code in the vlv irq handler. Also this now
means that we correctly filter underruns on gen2-4.
And as the real upshot I need to document one less function for
the fifo underrun code.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
drivers/gpu/drm/i915/i915_irq.c | 6 +++---
drivers/gpu/drm/i915/intel_drv.h | 2 --
drivers/gpu/drm/i915/intel_fifo_underrun.c | 9 +++++++--
3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 27aa43672d5c..baa2a0a9cc92 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1771,9 +1771,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
* we need to be careful that we only handle what we want to
* handle.
*/
- mask = 0;
- if (__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
- mask |= PIPE_FIFO_UNDERRUN_STATUS;
+
+ /* fifo underruns are filterered in the underrun handler. */
+ mask = PIPE_FIFO_UNDERRUN_STATUS;
switch (pipe) {
case PIPE_A:
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c91737dbbc5d..91e2b128c537 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -754,8 +754,6 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder);
void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv);
-bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
- enum pipe pipe);
/* i915_irq.c */
void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 854d29e18555..02909259bfb6 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -252,8 +252,8 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
return ret;
}
-bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
{
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -312,6 +312,11 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
+ /* GMCH can't disable fifo underruns, filter them. */
+ if (HAS_GMCH_DISPLAY(dev_priv->dev) &&
+ !__cpu_fifo_underrun_reporting_enabled(dev_priv, pipe))
+ return;
+
if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
DRM_ERROR("CPU pipe %c FIFO underrun\n",
pipe_name(pipe));
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (12 preceding siblings ...)
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 ` Daniel Vetter
2014-10-03 18:00 ` Paulo Zanoni
2014-09-30 13:16 ` [PATCH 00/14] i915 kerneldocs part 1 Imre Deak
14 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-09-30 8:56 UTC (permalink / raw)
To: Intel Graphics Development; +Cc: Daniel Vetter, Daniel Vetter
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
Documentation/DocBook/drm.tmpl | 5 ++
drivers/gpu/drm/i915/intel_fifo_underrun.c | 82 +++++++++++++++++++++++-------
2 files changed, 70 insertions(+), 17 deletions(-)
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index e8ef0f9c7396..9356f16847d9 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -3831,6 +3831,11 @@ int num_ioctls;</synopsis>
!Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb
</sect2>
<sect2>
+ <title>Display FIFO Underrun Reporting</title>
+!Pdrivers/gpu/drm/i915/intel_fifo_underrun.c fifo underrun handling
+!Idrivers/gpu/drm/i915/intel_fifo_underrun.c
+ </sect2>
+ <sect2>
<title>Plane Configuration</title>
<para>
This section covers plane configuration and composition with the
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 02909259bfb6..dfffad41664e 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -28,6 +28,26 @@
#include "i915_drv.h"
#include "intel_drv.h"
+/**
+ * DOC: fifo underrun handling
+ *
+ * The i915 driver checks for display fifo underruns using the interrupt signals
+ * provided by the hardware. This is enabled by default and fairly useful to
+ * debug display issues, especially watermark settings.
+ *
+ * If an underrun is detected this is logged into dmesg. To avoid flooding logs
+ * and occupying the cpu underrun interrupts are disabled after the first
+ * occurance until the next modeset on a given pipe.
+ *
+ * Note that underrun detection on gmch platforms is a bit more ugly since there
+ * is no interrupt (despite that the signalling bit is in the PIPESTATE pipe
+ * interrupt register). Also on some other platforms underrun interrupts are
+ * shared, which means that if we detect an underrun we need to disable underrun
+ * reporting on all pipes.
+ *
+ * The code also supports underrun detection on the PCH transcoder.
+ */
+
static bool ivb_can_enable_err_int(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -64,6 +84,14 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
return true;
}
+/**
+ * i9xx_check_fifo_underruns - check for fifo underruns
+ * @dev_priv: i915 device instance
+ *
+ * This function checks for fifo underruns on GMCH platforms. This needs to be
+ * done manually on modeset to make sure that we catch all underruns since they
+ * do not generate an interrupt by themselves on these platforms.
+ */
void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
{
struct intel_crtc *crtc;
@@ -199,20 +227,6 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
}
}
-/**
- * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
- * @pipe: pipe
- * @enable: true if we want to report FIFO underrun errors, false otherwise
- *
- * This function makes us disable or enable CPU fifo underruns for a specific
- * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
- * reporting for one pipe may also disable all the other CPU error interruts for
- * the other pipes, due to the fact that there's just one interrupt mask/enable
- * bit for all the pipes.
- *
- * Returns the previous state of underrun reporting.
- */
static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
enum pipe pipe, bool enable)
{
@@ -238,6 +252,22 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
return old;
}
+/**
+ * intel_set_cpu_fifo_underrun_reporting - set cpu fifo underrrun reporting state
+ * @dev_priv: i915 device instance
+ * @pipe: (CPU) pipe to set state for
+ * @enable: whether underruns should be reported or not
+ *
+ * This function sets the fifo underrun state for @pipe. It is used in the
+ * modeset code to avoid false positives since on many platforms underruns are
+ * expected when disabling or enabling the pipe.
+ *
+ * Notice that on some platforms disabling underrun reports for one pipe
+ * disables for all due to shared interrupts. Actual reporting is still per-pipe
+ * though.
+ *
+ * Returns the previous state of underrun reporting.
+ */
bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
enum pipe pipe, bool enable)
{
@@ -262,10 +292,10 @@ static bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_p
}
/**
- * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
+ * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
+ * @dev_priv: i915 device instance
* @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
- * @enable: true if we want to report FIFO underrun errors, false otherwise
+ * @enable: whether underruns should be reported or not
*
* This function makes us disable or enable PCH fifo underruns for a specific
* PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
@@ -309,6 +339,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
return old;
}
+/**
+ * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
+ * @dev_priv: i915 device instance
+ * @pipe: (CPU) pipe to set state for
+ *
+ * This handles a CPU fifo underrun interrupt, generating an underrun warning
+ * into dmesg if underrun reporting is enabled and then disables the underrun
+ * interrupt to avoid an irq storm.
+ */
void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
@@ -322,6 +361,15 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
pipe_name(pipe));
}
+/**
+ * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
+ * @dev_priv: i915 device instance
+ * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
+ *
+ * This handles a PCH fifo underrun interrupt, generating an underrun warning
+ * into dmesg if underrun reporting is enabled and then disables the underrun
+ * interrupt to avoid an irq storm.
+ */
void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
enum transcoder pch_transcoder)
{
--
2.1.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c
2014-09-30 8:56 ` [PATCH 02/14] drm/i915: Extract intel_runtime_pm.c Daniel Vetter
@ 2014-09-30 12:22 ` Imre Deak
0 siblings, 0 replies; 28+ messages in thread
From: Imre Deak @ 2014-09-30 12:22 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development
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
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 05/14] drm/i915: Call runtime_pm_disable directly
2014-09-30 8:56 ` [PATCH 05/14] drm/i915: Call runtime_pm_disable directly Daniel Vetter
@ 2014-09-30 12:46 ` Imre Deak
0 siblings, 0 replies; 28+ messages in thread
From: Imre Deak @ 2014-09-30 12:46 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Intel Graphics Development
On Tue, 2014-09-30 at 10:56 +0200, Daniel Vetter wrote:
> Allows us to mark it static and so forgoe the kerneldoc for it.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
> drivers/gpu/drm/i915/i915_dma.c | 4 +---
> drivers/gpu/drm/i915/intel_drv.h | 1 -
> drivers/gpu/drm/i915/intel_runtime_pm.c | 34 +++++++++++++++++----------------
> 3 files changed, 19 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 9aeec0df5658..7075bd2adee8 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1846,12 +1846,10 @@ int i915_driver_unload(struct drm_device *dev)
> return ret;
> }
>
> - intel_runtime_pm_disable(dev_priv);
> + intel_power_domains_fini(dev_priv);
>
> intel_gpu_ips_teardown();
>
> - intel_power_domains_fini(dev_priv);
> -
> i915_teardown_sysfs(dev);
>
> WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index ce1b5e99eb56..bf321993a88e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1077,7 +1077,6 @@ int intel_power_domains_init(struct drm_i915_private *);
> void intel_power_domains_fini(struct drm_i915_private *);
> void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
> void intel_runtime_pm_enable(struct drm_i915_private *dev_priv);
> -void intel_runtime_pm_disable(struct drm_i915_private *dev_priv);
>
> bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
> enum intel_display_power_domain domain);
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index db3716d93dcf..c49fee218e1b 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -995,8 +995,26 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
> return 0;
> }
>
> +static void intel_runtime_pm_disable(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);
> +}
> +
> void intel_power_domains_fini(struct drm_i915_private *dev_priv)
> {
> + intel_runtime_pm_disable(dev_priv);
> +
This is also called on the driver load error path, where we didn't yet
call intel_runtime_pm_enable(). It works and I'm ok with it, but I
thought it's worth mentioning.
> /* The i915.ko module is still not prepared to be loaded when
> * the power well is not enabled, so just enable it in case
> * we're going to unload/reload. */
> @@ -1142,22 +1160,6 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
> pm_runtime_put_autosuspend(device);
> }
>
> -void intel_runtime_pm_disable(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)
> {
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 06/14] drm/i915: Kerneldoc for intel_runtime_pm.c
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
0 siblings, 0 replies; 28+ messages in thread
From: Imre Deak @ 2014-09-30 13:11 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Intel Graphics Development
On Tue, 2014-09-30 at 10:56 +0200, Daniel Vetter wrote:
> I've decided not to document the functions exported to the audio
> driver since really, they shouldn't exist ...
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
> Documentation/DocBook/drm.tmpl | 12 +++
> drivers/gpu/drm/i915/intel_runtime_pm.c | 163 +++++++++++++++++++++++++++++++-
> 2 files changed, 174 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 7ad61284ad5f..69e422ab8352 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -3788,6 +3788,18 @@ int num_ioctls;</synopsis>
> those have basic support through the gma500 drm driver.
> </para>
> <sect1>
> + <title>Core Driver Infrastructure</title>
> + <para>
> + This section covers core driver infrastructure used by both the display
> + and the GEM parts of the driver.
> + </para>
> + <sect2>
> + <title>Runtime Power Management</title>
> +!Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
> +!Idrivers/gpu/drm/i915/intel_runtime_pm.c
> + </sect2>
> + </sect1>
> + <sect1>
> <title>Display Hardware Handling</title>
> <para>
> This section covers everything related to the display hardware including
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index c49fee218e1b..6fa781a5b15c 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -33,6 +33,23 @@
> #include "intel_drv.h"
> #include <drm/i915_powerwell.h>
>
> +/**
> + * DOC: runtime pm
> + *
> + * The i915 driver supports dynamic enabling and disabling of entire hardware
> + * blocks at runtime. This is especially important on the display side where
> + * software is supposed to control many power gates manually on recent hardware,
> + * since on the GT side a lot of the power management is done by the hardware.
> + * But even there some manual control at the device level is required.
> + *
> + * Since i915 supports a diverse set of platforms with a unified codebase and
> + * hardware engineers just love to shuffle functionality around between power
> + * domains there's a sizeable amount of indirection required. This file provides
> + * generic functions to the driver for grabbing and releasing references for
> + * abstract power domains. It then maps those to the actual power domains
Imo "actual power wells" would reflect better the code and bspec.
> + * present for a given platform.
> + */
> +
> static struct i915_power_domains *hsw_pwr;
>
> #define for_each_power_well(i, power_well, domain_mask, power_domains) \
> @@ -48,7 +65,7 @@ static struct i915_power_domains *hsw_pwr;
> 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.
> @@ -60,6 +77,18 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
> (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
> }
>
> +/**
> + * __intel_display_power_is_enabled - unlocked check for a power domain
> + * @dev_priv: i915 device instance
> + * @domain: power domain to check
> + *
> + * This is the unlocked version of intel_display_power_is_enabled() and should
> + * only be used from error capture and recovery code where deadlocks are
> + * possible.
> + *
> + * Returns:
> + * True when the power domain is enabled, false otherwise.
> + */
> bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
> enum intel_display_power_domain domain)
> {
> @@ -88,6 +117,23 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
> return is_enabled;
> }
>
> +/**
> + * intel_display_power_is_enabled - unlocked check for a power domain
> + * @dev_priv: i915 device instance
> + * @domain: power domain to check
> + *
> + * This function can be used to check the hw power domain state. It is mostly
> + * used in hardware state readout functions. Everywhere else code should rely
> + * upon explicit power domain reference counting to ensure that the hardware
> + * block is powered up before accessing it.
> + *
> + * Callers must hold the relevant modesetting locks to ensure that concurrent
> + * threads can't disable the power well while the caller tries to read a few
> + * registers.
> + *
> + * Returns:
> + * True when the power domain is enabled, false otherwise.
> + */
> bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
> enum intel_display_power_domain domain)
> {
> @@ -103,6 +149,16 @@ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
> return ret;
> }
>
> +/**
> + * intel_display_set_init_power - set the initial power domain state
> + * @dev_priv: i915 device instance
> + * @enable: whether to enable or disable the initial power domain state
> + *
> + * For simplicity our driver load/unload and system suspend/resume code assumes
> + * that all power domains are always enabled. This functions controls the state
> + * of this little hack. While the initial power domain state is enabled runtime
> + * pm is effectively disabled.
> + */
> void intel_display_set_init_power(struct drm_i915_private *dev_priv,
> bool enable)
> {
> @@ -556,6 +612,18 @@ mismatch:
> power_well->count, i915.disable_power_well);
> }
>
> +/**
> + * intel_display_power_get - grab a power domain reference
> + * @dev_priv: i915 device instance
> + * @domain: power domain to reference
> + *
> + * This function grabs a power domain reference for @domain and ensures that the
> + * power domain and all it's parents are powered up. Therefore users should only
its*; also one more spot somewhere below
> + * grab a reference to the innermost power domain they need.
> + *
> + * Any power domain reference obtained by this function must have a symmetric
> + * call to intel_display_power_put() to release the reference again.
> + */
> void intel_display_power_get(struct drm_i915_private *dev_priv,
> enum intel_display_power_domain domain)
> {
> @@ -584,6 +652,15 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
> mutex_unlock(&power_domains->lock);
> }
>
> +/**
> + * intel_display_power_put - release a power domain reference
> + * @dev_priv: i915 device instance
> + * @domain: power domain to reference
> + *
> + * This function drops the power domain reference obtained by
> + * intel_display_power_get() and might power down the corresponding hardware
> + * block right away if this is the last reference.
> + */
> void intel_display_power_put(struct drm_i915_private *dev_priv,
> enum intel_display_power_domain domain)
> {
> @@ -968,6 +1045,13 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr
> (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
> })
>
> +/**
> + * intel_power_domains_init - initializes the power domain structures
> + * @dev_priv: i915 device instance
> + *
> + * Initializes the power domain structures for @dev_priv depending upon the
> + * supported platform.
> + */
> int intel_power_domains_init(struct drm_i915_private *dev_priv)
> {
> struct i915_power_domains *power_domains = &dev_priv->power_domains;
> @@ -1011,6 +1095,14 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
> pm_runtime_disable(device);
> }
>
> +/**
> + * intel_power_domains_fini - finalizes the power domain structures
> + * @dev_priv: i915 device instance
> + *
> + * Finalizes the power domain structures for @dev_priv depending upon the
> + * supported platform. This function also disables runtime pm and ensures that
> + * the device stays powered up so that the driver can be reloaded.
> + */
> void intel_power_domains_fini(struct drm_i915_private *dev_priv)
> {
> intel_runtime_pm_disable(dev_priv);
> @@ -1069,6 +1161,13 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
> cmn->ops->disable(dev_priv, cmn);
> }
>
> +/**
> + * intel_power_domains_init_hw - initialize hardware power domain state
> + * @dev_priv: i915 device instance
> + *
> + * This function initializes the hardware power domain state and enables all
> + * power domains using intel_display_set_init_power().
> + */
> void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -1088,16 +1187,46 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
> power_domains->initializing = false;
> }
>
> +/**
> + * intel_aux_display_runtime_get - grab an auxilliary power domain reference
> + * @dev_priv: i915 device instance
> + *
> + * This function grabs a power domain reference for the auxilliary power domain
> + * (for access to the GMBUS and DP AUX blocks) and ensures that it and all it's
> + * parents are powered up. Therefore users should only grab a reference to the
> + * innermost power domain they need.
> + *
> + * Any power domain reference obtained by this function must have a symmetric
> + * call to intel_aux_display_runtime_put() to release the reference again.
> + */
> void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
> {
> intel_runtime_pm_get(dev_priv);
> }
>
> +/**
> + * intel_aux_display_runtime_put - release an auxilliary power domain reference
> + * @dev_priv: i915 device instance
> + *
> + * This function drops the auxilliary power domain reference obtained by
> + * intel_aux_display_runtime_get() and might power down the corresponding
> + * hardware block right away if this is the last reference.
> + */
> void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
> {
> intel_runtime_pm_put(dev_priv);
> }
>
> +/**
> + * intel_runtime_pm_get - grab a runtime pm reference
> + * @dev_priv: i915 device instance
> + *
> + * This function grabs a device-level runtime pm reference (mostly used for GEM
> + * code to ensure the GTT or GT is on) and ensures that it is powered up.
> + *
> + * Any power domain reference obtained by this function must have a symmetric
s/power domain/runtime pm/
> + * call to intel_runtime_pm_put() to release the reference again.
> + */
> void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -1110,6 +1239,20 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
> WARN(dev_priv->pm.suspended, "Device still suspended.\n");
> }
>
> +/**
> + * intel_runtime_pm_get - grab a runtime pm reference
intel_runtime_pm_get_noresume
> + * @dev_priv: i915 device instance
> + *
> + * This function grabs a device-level runtime pm reference (mostly used for GEM
> + * code to ensure the GTT or GT is on).
> + *
> + * It will _not_ power up the device but instead only check that it's power on.
> + * Therefore it is only valid to call this functions from contexts where the
> + * device is known to be powered up and where trying to power it up would result
> + * in hilarity and deadlocks. That pretty much means only the system
> + * suspend/resume code where this is used to grab runtime pm references for
> + * delayed setup down in work items.
For consistency the need to call intel_runtime_pm_put() should be
mentioned here too.
> + */
> void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -1122,6 +1265,14 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
> pm_runtime_get_noresume(device);
> }
>
> +/**
> + * intel_runtime_pm_put - release a runtime pm reference
> + * @dev_priv: i915 device instance
> + *
> + * This function drops the device-level runtime pm reference obtained by
> + * intel_runtime_pm_get() and might power down the corresponding
> + * hardware block right away if this is the last reference.
> + */
> void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -1134,6 +1285,16 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
> pm_runtime_put_autosuspend(device);
> }
>
> +/**
> + * intel_runtime_pm_enable - enable runtime pm
> + * @dev_priv: i915 device instance
> + *
> + * This function enables runtime pm at the end of the driver load sequence.
> + *
> + * Note that this function does currently not enable runtime pm for the
> + * subordinate display power domains. That is only done on the first modeset
> + * using intel_display_set_init_power().
> + */
> void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 00/14] i915 kerneldocs part 1
2014-09-30 8:56 [PATCH 00/14] i915 kerneldocs part 1 Daniel Vetter
` (13 preceding siblings ...)
2014-09-30 8:56 ` [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c Daniel Vetter
@ 2014-09-30 13:16 ` Imre Deak
2014-10-01 8:42 ` Daniel Vetter
14 siblings, 1 reply; 28+ messages in thread
From: Imre Deak @ 2014-09-30 13:16 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Intel Graphics Development
On Tue, 2014-09-30 at 10:56 +0200, Daniel Vetter wrote:
> Hi all,
>
> So I've decided that it's really time to (slowly) crawl through i915 and
> document everything. It's going to take years, but here's a start at least.
>
> I realize that this has good chances to create a constant stream of little
> conflicts all over. Well, so be it, I really think we need this.
>
> Overall approach is fairly simple:
> 1. Clean up interfaces for a set of functions.
> 2. Extract them into a new file grouped nicely together.
> 3. Write kerneldoc including short overview section.
> 4. Repeat.
>
> So here's the first batch. Comments & flames highly welcome. Review assignments
> below (counts for all the patches above the block).
>
> Cheers, Daniel
>
> Daniel Vetter (14):
> drm/i915: Remove intel_modeset_suspend_hw
> drm/i915: Extract intel_runtime_pm.c
> drm/i915: Bikeshed rpm functions name a bit.
> drm/i915: Move intel_display_set_init_power to intel_runtime_pm.c
> drm/i915: Call runtime_pm_disable directly
> drm/i915: Kerneldoc for intel_runtime_pm.c
>
> Reviewer: Imre
With the optional nitpicks I sent separately for the above 6 patches:
Reviewed-by: Imre Deak <imre.deak@intel.com>
>
> drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
> drm/i915: Use dev_priv instead of dev in irq setup functions
> drm/i915: kerneldoc for interrupt enable/disable functions
> drm/i915: Extract intel_fifo_underrun.c
> drm/i915: Use dev_priv in public intel_fifo_underrun.c functions
> drm/i915: Add wrappers to handle fifo underrun interrupts
> drm/i915: Filter gmch fifo underruns in the shared handler
> drm/i915: kerneldoc for intel_fifo_underrun.c
>
> Reviewer: Paulo
>
> Documentation/DocBook/drm.tmpl | 26 +
> drivers/gpu/drm/i915/Makefile | 5 +-
> drivers/gpu/drm/i915/i915_debugfs.c | 2 +-
> drivers/gpu/drm/i915/i915_dma.c | 25 +-
> drivers/gpu/drm/i915/i915_drv.c | 14 +-
> drivers/gpu/drm/i915/i915_drv.h | 22 +-
> drivers/gpu/drm/i915/i915_irq.c | 491 +++-------
> drivers/gpu/drm/i915/intel_crt.c | 2 +-
> drivers/gpu/drm/i915/intel_ddi.c | 8 +-
> drivers/gpu/drm/i915/intel_display.c | 84 +-
> drivers/gpu/drm/i915/intel_dp.c | 2 +-
> drivers/gpu/drm/i915/intel_drv.h | 62 +-
> drivers/gpu/drm/i915/intel_dsi.c | 2 +-
> drivers/gpu/drm/i915/intel_fifo_underrun.c | 380 ++++++++
> drivers/gpu/drm/i915/intel_hdmi.c | 2 +-
> drivers/gpu/drm/i915/intel_lvds.c | 2 +-
> drivers/gpu/drm/i915/intel_pm.c | 1159 -----------------------
> drivers/gpu/drm/i915/intel_runtime_pm.c | 1372 ++++++++++++++++++++++++++++
> 18 files changed, 2016 insertions(+), 1644 deletions(-)
> create mode 100644 drivers/gpu/drm/i915/intel_fifo_underrun.c
> create mode 100644 drivers/gpu/drm/i915/intel_runtime_pm.c
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 00/14] i915 kerneldocs part 1
2014-09-30 13:16 ` [PATCH 00/14] i915 kerneldocs part 1 Imre Deak
@ 2014-10-01 8:42 ` Daniel Vetter
0 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-10-01 8:42 UTC (permalink / raw)
To: Imre Deak; +Cc: Daniel Vetter, Intel Graphics Development
On Tue, Sep 30, 2014 at 04:16:38PM +0300, Imre Deak wrote:
> On Tue, 2014-09-30 at 10:56 +0200, Daniel Vetter wrote:
> > Hi all,
> >
> > So I've decided that it's really time to (slowly) crawl through i915 and
> > document everything. It's going to take years, but here's a start at least.
> >
> > I realize that this has good chances to create a constant stream of little
> > conflicts all over. Well, so be it, I really think we need this.
> >
> > Overall approach is fairly simple:
> > 1. Clean up interfaces for a set of functions.
> > 2. Extract them into a new file grouped nicely together.
> > 3. Write kerneldoc including short overview section.
> > 4. Repeat.
> >
> > So here's the first batch. Comments & flames highly welcome. Review assignments
> > below (counts for all the patches above the block).
> >
> > Cheers, Daniel
> >
> > Daniel Vetter (14):
> > drm/i915: Remove intel_modeset_suspend_hw
> > drm/i915: Extract intel_runtime_pm.c
> > drm/i915: Bikeshed rpm functions name a bit.
> > drm/i915: Move intel_display_set_init_power to intel_runtime_pm.c
> > drm/i915: Call runtime_pm_disable directly
> > drm/i915: Kerneldoc for intel_runtime_pm.c
> >
> > Reviewer: Imre
>
> With the optional nitpicks I sent separately for the above 6 patches:
> Reviewed-by: Imre Deak <imre.deak@intel.com>
All nitpicks (plus a few more spelling fixes I've spotted) applied and
patches merged, thanks a lot for your review.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
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
0 siblings, 1 reply; 28+ messages in thread
From: Paulo Zanoni @ 2014-10-02 20:36 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development
2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Double negations just parse harder. Also this allows us to ditch some
> init code since clearing to 0 dtrt. Also ditch the assignment in
> intel_pm_setup, that's not redundant since we do the assignement now
> while setting up interrupts.
>
> While at it do engage in a bit of OCD and wrap up the few lines of
> setup/teardown code into little helper functions: intel_irq_fini for
> cleanup and intel_irq_init_hw for hw setup.
So the werid thing is that we now have:
- intel_irq_init
- intel_irq_init_hw
- intel_irq_fini
But the intel_irq_fini doesn't finish what intel_irq_init started, it
finishes what intel_irq_init_hw started. Since the functions you
introduced are basically wrappers to drm_irq_{un,}install, my bikeshed
would be to call the new functions simply intel_irq_install and
intel_irq_uninstall.
With or without that: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
> drivers/gpu/drm/i915/i915_dma.c | 9 +--------
> drivers/gpu/drm/i915/i915_drv.h | 4 +++-
> drivers/gpu/drm/i915/i915_irq.c | 26 +++++++++++++++++++++-----
> drivers/gpu/drm/i915/intel_display.c | 4 +---
> drivers/gpu/drm/i915/intel_drv.h | 2 +-
> drivers/gpu/drm/i915/intel_pm.c | 1 -
> 6 files changed, 27 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 7075bd2adee8..969f0cff9fef 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1338,14 +1338,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
>
> intel_power_domains_init_hw(dev_priv);
>
> - /*
> - * We enable some interrupt sources in our postinstall hooks, so mark
> - * interrupts as enabled _before_ actually enabling them to avoid
> - * special cases in our ordering checks.
> - */
> - dev_priv->pm._irqs_disabled = false;
> -
> - ret = drm_irq_install(dev, dev->pdev->irq);
> + ret = intel_irq_init_hw(dev_priv);
> if (ret)
> goto cleanup_gem_stolen;
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1d8a4b7bf61a..1eec0e81a5ca 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1405,7 +1405,7 @@ struct ilk_wm_values {
> */
> struct i915_runtime_pm {
> bool suspended;
> - bool _irqs_disabled;
> + bool irqs_enabled;
> };
>
> enum intel_pipe_crc_source {
> @@ -2285,6 +2285,8 @@ void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
> int new_delay);
> extern void intel_irq_init(struct drm_device *dev);
> extern void intel_hpd_init(struct drm_device *dev);
> +int intel_irq_init_hw(struct drm_i915_private *dev_priv);
> +void intel_irq_fini(struct drm_i915_private *dev_priv);
>
> extern void intel_uncore_sanitize(struct drm_device *dev);
> extern void intel_uncore_early_sanitize(struct drm_device *dev,
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 1ddfc81caaaa..d9d09a9b4fc7 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -4656,9 +4656,6 @@ void intel_irq_init(struct drm_device *dev)
>
> pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
>
> - /* Haven't installed the IRQ handler yet */
> - dev_priv->pm._irqs_disabled = true;
> -
> if (IS_GEN2(dev)) {
> dev->max_vblank_count = 0;
> dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
> @@ -4767,13 +4764,32 @@ void intel_hpd_init(struct drm_device *dev)
> spin_unlock_irq(&dev_priv->irq_lock);
> }
>
> +int intel_irq_init_hw(struct drm_i915_private *dev_priv)
> +{
> + /*
> + * We enable some interrupt sources in our postinstall hooks, so mark
> + * interrupts as enabled _before_ actually enabling them to avoid
> + * special cases in our ordering checks.
> + */
> + dev_priv->pm.irqs_enabled = true;
> +
> + return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
> +}
> +
> +void intel_irq_fini(struct drm_i915_private *dev_priv)
> +{
> + drm_irq_uninstall(dev_priv->dev);
> + intel_hpd_cancel_work(dev_priv);
> + dev_priv->pm.irqs_enabled = false;
> +}
> +
> /* Disable interrupts so we can allow runtime PM. */
> void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
>
> dev->driver->irq_uninstall(dev);
> - dev_priv->pm._irqs_disabled = true;
> + dev_priv->pm.irqs_enabled = false;
> }
>
> /* Restore interrupts so we can recover from runtime PM. */
> @@ -4781,7 +4797,7 @@ void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
>
> - dev_priv->pm._irqs_disabled = false;
> + dev_priv->pm.irqs_enabled = true;
> dev->driver->irq_preinstall(dev);
> dev->driver->irq_postinstall(dev);
> }
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 1dd470fcddf2..41607ac3e6eb 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -13263,9 +13263,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
> * Too much stuff here (turning of rps, connectors, ...) would
> * experience fancy races otherwise.
> */
> - drm_irq_uninstall(dev);
> - intel_hpd_cancel_work(dev_priv);
> - dev_priv->pm._irqs_disabled = true;
> + intel_irq_fini(dev_priv);
>
> /*
> * Due to the hpd irq storm handling the hotplug work can re-arm the
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index bf321993a88e..cf07e2225911 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -764,7 +764,7 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
> * We only use drm_irq_uninstall() at unload and VT switch, so
> * this is the only thing we need to check.
> */
> - return !dev_priv->pm._irqs_disabled;
> + return dev_priv->pm.irqs_enabled;
> }
>
> int intel_get_crtc_scanline(struct intel_crtc *crtc);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 06c1ea0a7bfd..bf79f86ed06b 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -6507,5 +6507,4 @@ void intel_pm_setup(struct drm_device *dev)
> intel_gen6_powersave_work);
>
> dev_priv->pm.suspended = false;
> - dev_priv->pm._irqs_disabled = false;
> }
> --
> 2.1.1
>
--
Paulo Zanoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 08/14] drm/i915: Use dev_priv instead of dev in irq setup functions
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
0 siblings, 0 replies; 28+ messages in thread
From: Paulo Zanoni @ 2014-10-02 20:46 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development
2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> It's the new world order!
>
> Not going full monty on these here and rolling this out throughout the
> subsequent call chains since this is just for the kerneldoc. Later on
> we can go more crazy, especially once we've embedded drm_device
> correctly.
>
> v2: Also frob the runtime_pm functions ...
Needs rebase. If you plan to do it correctly:
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
If your rebase contains a bug: Nacked-by: Paulo Zanoni
<paulo.r.zanoni@intel.com>
>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
> drivers/gpu/drm/i915/i915_dma.c | 4 ++--
> drivers/gpu/drm/i915/i915_drv.c | 12 +++++-----
> drivers/gpu/drm/i915/i915_drv.h | 4 ++--
> drivers/gpu/drm/i915/i915_irq.c | 40 +++++++++++++++------------------
> drivers/gpu/drm/i915/intel_drv.h | 4 ++--
> drivers/gpu/drm/i915/intel_runtime_pm.c | 2 +-
> 6 files changed, 31 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 969f0cff9fef..f50ecb18525f 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1363,7 +1363,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
> goto cleanup_gem;
>
> /* Only enable hotplug handling once the fbdev is fully set up. */
> - intel_hpd_init(dev);
> + intel_hpd_init(dev_priv);
>
> /*
> * Some ports require correctly set-up hpd registers for detection to
> @@ -1733,7 +1733,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
> goto out_freewq;
> }
>
> - intel_irq_init(dev);
> + intel_irq_init(dev_priv);
> intel_uncore_sanitize(dev);
>
> /* Try to make sure MCHBAR is enabled before poking at it */
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index f07b8518cd39..605a4c4580d5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -575,7 +575,7 @@ static int i915_drm_freeze(struct drm_device *dev)
>
> flush_delayed_work(&dev_priv->rps.delayed_resume_work);
>
> - intel_runtime_pm_disable_interrupts(dev);
> + intel_runtime_pm_disable_interrupts(dev_priv);
> intel_hpd_cancel_work(dev_priv);
>
> intel_suspend_encoders(dev_priv);
> @@ -681,7 +681,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
> mutex_unlock(&dev->struct_mutex);
>
> /* We need working interrupts for modeset enabling ... */
> - intel_runtime_pm_restore_interrupts(dev);
> + intel_runtime_pm_enable_interrupts(dev_priv);
>
> intel_modeset_init_hw(dev);
>
> @@ -703,7 +703,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
> * bother with the tiny race here where we might loose hotplug
> * notifications.
> * */
> - intel_hpd_init(dev);
> + intel_hpd_init(dev_priv);
> /* Config may have changed between suspend and resume */
> drm_helper_hpd_irq_event(dev);
> }
> @@ -1446,12 +1446,12 @@ static int intel_runtime_suspend(struct device *device)
> * intel_mark_idle().
> */
> cancel_work_sync(&dev_priv->rps.work);
> - intel_runtime_pm_disable_interrupts(dev);
> + intel_runtime_pm_disable_interrupts(dev_priv);
>
> ret = intel_suspend_complete(dev_priv);
> if (ret) {
> DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret);
> - intel_runtime_pm_restore_interrupts(dev);
> + intel_runtime_pm_enable_interrupts(dev_priv);
>
> return ret;
> }
> @@ -1511,7 +1511,7 @@ static int intel_runtime_resume(struct device *device)
> i915_gem_init_swizzling(dev);
> gen6_update_ring_freq(dev);
>
> - intel_runtime_pm_restore_interrupts(dev);
> + intel_runtime_pm_enable_interrupts(dev_priv);
> intel_reset_gt_powersave(dev);
>
> if (ret)
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1eec0e81a5ca..854f1b92d3df 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2283,8 +2283,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
>
> void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
> int new_delay);
> -extern void intel_irq_init(struct drm_device *dev);
> -extern void intel_hpd_init(struct drm_device *dev);
> +extern void intel_irq_init(struct drm_i915_private *dev_priv);
> +extern void intel_hpd_init(struct drm_i915_private *dev_priv);
> int intel_irq_init_hw(struct drm_i915_private *dev_priv);
> void intel_irq_fini(struct drm_i915_private *dev_priv);
>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index d9d09a9b4fc7..2c436e6c55b0 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -4631,9 +4631,9 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work)
> intel_runtime_pm_put(dev_priv);
> }
>
> -void intel_irq_init(struct drm_device *dev)
> +void intel_irq_init(struct drm_i915_private *dev_priv)
> {
> - struct drm_i915_private *dev_priv = dev->dev_private;
> + struct drm_device *dev = dev_priv->dev;
>
> INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
> INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
> @@ -4642,7 +4642,7 @@ void intel_irq_init(struct drm_device *dev)
> INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
>
> /* Let's track the enabled rps events */
> - if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
> + if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
> /* WaGsvRC0ResidencyMethod:vlv */
> dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
> else
> @@ -4656,10 +4656,10 @@ void intel_irq_init(struct drm_device *dev)
>
> pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
>
> - if (IS_GEN2(dev)) {
> + if (IS_GEN2(dev_priv)) {
> dev->max_vblank_count = 0;
> dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
> - } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
> + } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
> dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
> dev->driver->get_vblank_counter = gm45_get_vblank_counter;
> } else {
> @@ -4672,7 +4672,7 @@ void intel_irq_init(struct drm_device *dev)
> * Gen2 doesn't have a hardware frame counter and so depends on
> * vblank interrupts to produce sane vblank seuquence numbers.
> */
> - if (!IS_GEN2(dev))
> + if (!IS_GEN2(dev_priv))
> dev->vblank_disable_immediate = true;
>
> if (drm_core_check_feature(dev, DRIVER_MODESET)) {
> @@ -4680,7 +4680,7 @@ void intel_irq_init(struct drm_device *dev)
> dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
> }
>
> - if (IS_CHERRYVIEW(dev)) {
> + if (IS_CHERRYVIEW(dev_priv)) {
> dev->driver->irq_handler = cherryview_irq_handler;
> dev->driver->irq_preinstall = cherryview_irq_preinstall;
> dev->driver->irq_postinstall = cherryview_irq_postinstall;
> @@ -4688,7 +4688,7 @@ void intel_irq_init(struct drm_device *dev)
> dev->driver->enable_vblank = valleyview_enable_vblank;
> dev->driver->disable_vblank = valleyview_disable_vblank;
> dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
> - } else if (IS_VALLEYVIEW(dev)) {
> + } else if (IS_VALLEYVIEW(dev_priv)) {
> dev->driver->irq_handler = valleyview_irq_handler;
> dev->driver->irq_preinstall = valleyview_irq_preinstall;
> dev->driver->irq_postinstall = valleyview_irq_postinstall;
> @@ -4696,7 +4696,7 @@ void intel_irq_init(struct drm_device *dev)
> dev->driver->enable_vblank = valleyview_enable_vblank;
> dev->driver->disable_vblank = valleyview_disable_vblank;
> dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
> - } else if (IS_GEN8(dev)) {
> + } else if (IS_GEN8(dev_priv)) {
> dev->driver->irq_handler = gen8_irq_handler;
> dev->driver->irq_preinstall = gen8_irq_reset;
> dev->driver->irq_postinstall = gen8_irq_postinstall;
> @@ -4713,12 +4713,12 @@ void intel_irq_init(struct drm_device *dev)
> dev->driver->disable_vblank = ironlake_disable_vblank;
> dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
> } else {
> - if (INTEL_INFO(dev)->gen == 2) {
> + if (INTEL_INFO(dev_priv)->gen == 2) {
> dev->driver->irq_preinstall = i8xx_irq_preinstall;
> dev->driver->irq_postinstall = i8xx_irq_postinstall;
> dev->driver->irq_handler = i8xx_irq_handler;
> dev->driver->irq_uninstall = i8xx_irq_uninstall;
> - } else if (INTEL_INFO(dev)->gen == 3) {
> + } else if (INTEL_INFO(dev_priv)->gen == 3) {
> dev->driver->irq_preinstall = i915_irq_preinstall;
> dev->driver->irq_postinstall = i915_irq_postinstall;
> dev->driver->irq_uninstall = i915_irq_uninstall;
> @@ -4736,9 +4736,9 @@ void intel_irq_init(struct drm_device *dev)
> }
> }
>
> -void intel_hpd_init(struct drm_device *dev)
> +void intel_hpd_init(struct drm_i915_private *dev_priv)
> {
> - struct drm_i915_private *dev_priv = dev->dev_private;
> + struct drm_device *dev = dev_priv->dev;
> struct drm_mode_config *mode_config = &dev->mode_config;
> struct drm_connector *connector;
> int i;
> @@ -4784,20 +4784,16 @@ void intel_irq_fini(struct drm_i915_private *dev_priv)
> }
>
> /* Disable interrupts so we can allow runtime PM. */
> -void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
> +void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
> {
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> - dev->driver->irq_uninstall(dev);
> + dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
> dev_priv->pm.irqs_enabled = false;
> }
>
> /* Restore interrupts so we can recover from runtime PM. */
> -void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
> +void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
> {
> - struct drm_i915_private *dev_priv = dev->dev_private;
> -
> dev_priv->pm.irqs_enabled = true;
> - dev->driver->irq_preinstall(dev);
> - dev->driver->irq_postinstall(dev);
> + dev_priv->dev->driver->irq_preinstall(dev_priv->dev);
> + dev_priv->dev->driver->irq_postinstall(dev_priv->dev);
> }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index cf07e2225911..aba3ea938427 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -756,8 +756,8 @@ void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> void gen8_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> -void intel_runtime_pm_disable_interrupts(struct drm_device *dev);
> -void intel_runtime_pm_restore_interrupts(struct drm_device *dev);
> +void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
> +void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
> static inline bool intel_irqs_enabled(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
> index 6fa781a5b15c..8e322513a44a 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -377,7 +377,7 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
> if (dev_priv->power_domains.initializing)
> return;
>
> - intel_hpd_init(dev_priv->dev);
> + intel_hpd_init(dev_priv);
>
> i915_redisable_vga_power_on(dev_priv->dev);
> }
> --
> 2.1.1
>
--
Paulo Zanoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 09/14] drm/i915: kerneldoc for interrupt enable/disable functions
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
0 siblings, 0 replies; 28+ messages in thread
From: Paulo Zanoni @ 2014-10-02 20:55 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development
2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Just start with the basics for now.
>
> Since there's a lot of different functionality in i915_irq.c I've
> decided to split it into different sections and pull in just the
> relevant functions. Splitting into different files looks like a lot
> more work since the interrupt handlers do an awful lot of reuse all
> over.
>
If you do the rename I suggested in patch 7, you'll have to change this patch.
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
> Documentation/DocBook/drm.tmpl | 9 ++++++
> drivers/gpu/drm/i915/i915_irq.c | 61 +++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 68 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 69e422ab8352..e8ef0f9c7396 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -3798,6 +3798,14 @@ int num_ioctls;</synopsis>
> !Pdrivers/gpu/drm/i915/intel_runtime_pm.c runtime pm
> !Idrivers/gpu/drm/i915/intel_runtime_pm.c
> </sect2>
> + <sect2>
> + <title>Interrupt Handling</title>
> +!Pdrivers/gpu/drm/i915/i915_irq.c interrupt handling
> +!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_init intel_irq_init_hw intel_hpd_init
> +!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_fini
> +!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts
> +!Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts
> + </sect2>
> </sect1>
> <sect1>
> <title>Display Hardware Handling</title>
> @@ -3951,5 +3959,6 @@ int num_ioctls;</synopsis>
> </sect2>
> </sect1>
> </chapter>
> +!Cdrivers/gpu/drm/i915/i915_irq.c
> </part>
> </book>
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 2c436e6c55b0..039625c22be4 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -37,6 +37,14 @@
> #include "i915_trace.h"
> #include "intel_drv.h"
>
> +/**
> + * DOC: interrupt handling
> + *
> + * These functions provide the basic support for enabling and disabling the
> + * interrupt handling support. There's a lot more functionality in i915_irq.c
> + * and related files, but that will be described in separate chapters.
> + */
> +
> static const u32 hpd_ibx[] = {
> [HPD_CRT] = SDE_CRT_HOTPLUG,
> [HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
> @@ -4631,6 +4639,13 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work)
> intel_runtime_pm_put(dev_priv);
> }
>
> +/**
> + * intel_irq_init - initializes irq support
> + * @dev_priv: i915 device instance
> + *
> + * This function initializes all the irq support including work items, timers
> + * and all the vtables. It does not setup the interrupt itself though.
> + */
> void intel_irq_init(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -4736,6 +4751,18 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
> }
> }
>
> +/**
> + * intel_hpd_init - initializes and enables hpd support
> + * @dev_priv: i915 device instance
> + *
> + * This function enables the hotplug support. It requires that interrupts have
> + * already been enabled with intel_irq_init_hw(). From this point on hotplug and
> + * poll request can run concurrently to other code, so locking rules must be
> + * obeyed.
> + *
> + * This is a separate step from interrupt enabling to simplify the locking rules
> + * in the driver load and resume code.
> + */
> void intel_hpd_init(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
> @@ -4764,6 +4791,17 @@ void intel_hpd_init(struct drm_i915_private *dev_priv)
> spin_unlock_irq(&dev_priv->irq_lock);
> }
>
> +/**
> + * intel_irq_init_hw - enables the hardware interrupt
> + * @dev_priv: i915 device instance
> + *
> + * This function enables the hardware interrupt handling, but leaves the hotplug
> + * handling still disabled. It is called after intel_irq_init().
> + *
> + * In the driver load and resume code we need working interrupts in a few places
> + * but don't want to deal with the hassle of concurrent probe and hotplug
> + * workers. Hence the split into this two-stage approach.
> + */
> int intel_irq_init_hw(struct drm_i915_private *dev_priv)
> {
> /*
> @@ -4776,6 +4814,13 @@ int intel_irq_init_hw(struct drm_i915_private *dev_priv)
> return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
> }
>
> +/**
> + * intel_irq_fini - finilizes all irq handling
> + * @dev_priv: i915 device instance
> + *
> + * This stops interrupt and hotplug handling and unregisters and frees all
> + * resources acquired in the init functions.
> + */
> void intel_irq_fini(struct drm_i915_private *dev_priv)
> {
> drm_irq_uninstall(dev_priv->dev);
> @@ -4783,14 +4828,26 @@ void intel_irq_fini(struct drm_i915_private *dev_priv)
> dev_priv->pm.irqs_enabled = false;
> }
>
> -/* Disable interrupts so we can allow runtime PM. */
> +/**
> + * intel_runtime_pm_disable_interrupts - runtime interrupt disabling
> + * @dev_priv: i915 device instance
> + *
> + * This function is used to disable interrupts at runtime, both in the runtime
> + * pm and the system suspend/resume code.
> + */
> void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
> {
> dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
> dev_priv->pm.irqs_enabled = false;
> }
>
> -/* Restore interrupts so we can recover from runtime PM. */
> +/**
> + * intel_runtime_pm_enable_interrupts - runtime interrupt enabling
> + * @dev_priv: i915 device instance
> + *
> + * This function is used to enable interrupts at runtime, both in the runtime
> + * pm and the system suspend/resume code.
> + */
> void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv)
> {
> dev_priv->pm.irqs_enabled = true;
> --
> 2.1.1
>
--
Paulo Zanoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
2014-10-02 20:36 ` Paulo Zanoni
@ 2014-10-03 9:19 ` Daniel Vetter
2014-10-03 9:27 ` Chris Wilson
0 siblings, 1 reply; 28+ messages in thread
From: Daniel Vetter @ 2014-10-03 9:19 UTC (permalink / raw)
To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter
On Thu, Oct 02, 2014 at 05:36:11PM -0300, Paulo Zanoni wrote:
> 2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > Double negations just parse harder. Also this allows us to ditch some
> > init code since clearing to 0 dtrt. Also ditch the assignment in
> > intel_pm_setup, that's not redundant since we do the assignement now
> > while setting up interrupts.
> >
> > While at it do engage in a bit of OCD and wrap up the few lines of
> > setup/teardown code into little helper functions: intel_irq_fini for
> > cleanup and intel_irq_init_hw for hw setup.
>
> So the werid thing is that we now have:
> - intel_irq_init
> - intel_irq_init_hw
> - intel_irq_fini
>
> But the intel_irq_fini doesn't finish what intel_irq_init started, it
> finishes what intel_irq_init_hw started. Since the functions you
> introduced are basically wrappers to drm_irq_{un,}install, my bikeshed
> would be to call the new functions simply intel_irq_install and
> intel_irq_uninstall.
I like this idea, so changed the names while merging.
> With or without that: Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Thanks for the review.
-Daniel
>
> >
> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> > ---
> > drivers/gpu/drm/i915/i915_dma.c | 9 +--------
> > drivers/gpu/drm/i915/i915_drv.h | 4 +++-
> > drivers/gpu/drm/i915/i915_irq.c | 26 +++++++++++++++++++++-----
> > drivers/gpu/drm/i915/intel_display.c | 4 +---
> > drivers/gpu/drm/i915/intel_drv.h | 2 +-
> > drivers/gpu/drm/i915/intel_pm.c | 1 -
> > 6 files changed, 27 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> > index 7075bd2adee8..969f0cff9fef 100644
> > --- a/drivers/gpu/drm/i915/i915_dma.c
> > +++ b/drivers/gpu/drm/i915/i915_dma.c
> > @@ -1338,14 +1338,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
> >
> > intel_power_domains_init_hw(dev_priv);
> >
> > - /*
> > - * We enable some interrupt sources in our postinstall hooks, so mark
> > - * interrupts as enabled _before_ actually enabling them to avoid
> > - * special cases in our ordering checks.
> > - */
> > - dev_priv->pm._irqs_disabled = false;
> > -
> > - ret = drm_irq_install(dev, dev->pdev->irq);
> > + ret = intel_irq_init_hw(dev_priv);
> > if (ret)
> > goto cleanup_gem_stolen;
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index 1d8a4b7bf61a..1eec0e81a5ca 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -1405,7 +1405,7 @@ struct ilk_wm_values {
> > */
> > struct i915_runtime_pm {
> > bool suspended;
> > - bool _irqs_disabled;
> > + bool irqs_enabled;
> > };
> >
> > enum intel_pipe_crc_source {
> > @@ -2285,6 +2285,8 @@ void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
> > int new_delay);
> > extern void intel_irq_init(struct drm_device *dev);
> > extern void intel_hpd_init(struct drm_device *dev);
> > +int intel_irq_init_hw(struct drm_i915_private *dev_priv);
> > +void intel_irq_fini(struct drm_i915_private *dev_priv);
> >
> > extern void intel_uncore_sanitize(struct drm_device *dev);
> > extern void intel_uncore_early_sanitize(struct drm_device *dev,
> > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> > index 1ddfc81caaaa..d9d09a9b4fc7 100644
> > --- a/drivers/gpu/drm/i915/i915_irq.c
> > +++ b/drivers/gpu/drm/i915/i915_irq.c
> > @@ -4656,9 +4656,6 @@ void intel_irq_init(struct drm_device *dev)
> >
> > pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
> >
> > - /* Haven't installed the IRQ handler yet */
> > - dev_priv->pm._irqs_disabled = true;
> > -
> > if (IS_GEN2(dev)) {
> > dev->max_vblank_count = 0;
> > dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
> > @@ -4767,13 +4764,32 @@ void intel_hpd_init(struct drm_device *dev)
> > spin_unlock_irq(&dev_priv->irq_lock);
> > }
> >
> > +int intel_irq_init_hw(struct drm_i915_private *dev_priv)
> > +{
> > + /*
> > + * We enable some interrupt sources in our postinstall hooks, so mark
> > + * interrupts as enabled _before_ actually enabling them to avoid
> > + * special cases in our ordering checks.
> > + */
> > + dev_priv->pm.irqs_enabled = true;
> > +
> > + return drm_irq_install(dev_priv->dev, dev_priv->dev->pdev->irq);
> > +}
> > +
> > +void intel_irq_fini(struct drm_i915_private *dev_priv)
> > +{
> > + drm_irq_uninstall(dev_priv->dev);
> > + intel_hpd_cancel_work(dev_priv);
> > + dev_priv->pm.irqs_enabled = false;
> > +}
> > +
> > /* Disable interrupts so we can allow runtime PM. */
> > void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
> > {
> > struct drm_i915_private *dev_priv = dev->dev_private;
> >
> > dev->driver->irq_uninstall(dev);
> > - dev_priv->pm._irqs_disabled = true;
> > + dev_priv->pm.irqs_enabled = false;
> > }
> >
> > /* Restore interrupts so we can recover from runtime PM. */
> > @@ -4781,7 +4797,7 @@ void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
> > {
> > struct drm_i915_private *dev_priv = dev->dev_private;
> >
> > - dev_priv->pm._irqs_disabled = false;
> > + dev_priv->pm.irqs_enabled = true;
> > dev->driver->irq_preinstall(dev);
> > dev->driver->irq_postinstall(dev);
> > }
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 1dd470fcddf2..41607ac3e6eb 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -13263,9 +13263,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
> > * Too much stuff here (turning of rps, connectors, ...) would
> > * experience fancy races otherwise.
> > */
> > - drm_irq_uninstall(dev);
> > - intel_hpd_cancel_work(dev_priv);
> > - dev_priv->pm._irqs_disabled = true;
> > + intel_irq_fini(dev_priv);
> >
> > /*
> > * Due to the hpd irq storm handling the hotplug work can re-arm the
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index bf321993a88e..cf07e2225911 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -764,7 +764,7 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
> > * We only use drm_irq_uninstall() at unload and VT switch, so
> > * this is the only thing we need to check.
> > */
> > - return !dev_priv->pm._irqs_disabled;
> > + return dev_priv->pm.irqs_enabled;
> > }
> >
> > int intel_get_crtc_scanline(struct intel_crtc *crtc);
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 06c1ea0a7bfd..bf79f86ed06b 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -6507,5 +6507,4 @@ void intel_pm_setup(struct drm_device *dev)
> > intel_gen6_powersave_work);
> >
> > dev_priv->pm.suspended = false;
> > - dev_priv->pm._irqs_disabled = false;
> > }
> > --
> > 2.1.1
> >
>
>
>
> --
> Paulo Zanoni
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
2014-10-03 9:19 ` Daniel Vetter
@ 2014-10-03 9:27 ` Chris Wilson
2014-10-03 11:49 ` Daniel Vetter
0 siblings, 1 reply; 28+ messages in thread
From: Chris Wilson @ 2014-10-03 9:27 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter
On Fri, Oct 03, 2014 at 11:19:26AM +0200, Daniel Vetter wrote:
> On Thu, Oct 02, 2014 at 05:36:11PM -0300, Paulo Zanoni wrote:
> > 2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > > Double negations just parse harder. Also this allows us to ditch some
> > > init code since clearing to 0 dtrt. Also ditch the assignment in
> > > intel_pm_setup, that's not redundant since we do the assignement now
> > > while setting up interrupts.
> > >
> > > While at it do engage in a bit of OCD and wrap up the few lines of
> > > setup/teardown code into little helper functions: intel_irq_fini for
> > > cleanup and intel_irq_init_hw for hw setup.
> >
> > So the werid thing is that we now have:
> > - intel_irq_init
> > - intel_irq_init_hw
> > - intel_irq_fini
> >
> > But the intel_irq_fini doesn't finish what intel_irq_init started, it
> > finishes what intel_irq_init_hw started. Since the functions you
> > introduced are basically wrappers to drm_irq_{un,}install, my bikeshed
> > would be to call the new functions simply intel_irq_install and
> > intel_irq_uninstall.
>
> I like this idea, so changed the names while merging.
Is it worth the divergence? I think the right pattern for other areas of
the driver is:
init
while :
resume
suspend
fini
That becomes something like
intel_irq_init
i915_gem_init
...
while :
intel_irq_resume
i915_gem_resume (formerly i95_gem_init_hw)
...
i915_gem_suspend
intel_irq_suspend
...
i915_gem_fini
intel_irq_fini
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 07/14] drm/i915: s/pm._irqs_disabled/pm.irqs_enabled/
2014-10-03 9:27 ` Chris Wilson
@ 2014-10-03 11:49 ` Daniel Vetter
0 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-10-03 11:49 UTC (permalink / raw)
To: Chris Wilson, Daniel Vetter, Paulo Zanoni, Daniel Vetter,
Intel Graphics Development, Daniel Vetter
On Fri, Oct 03, 2014 at 10:27:26AM +0100, Chris Wilson wrote:
> On Fri, Oct 03, 2014 at 11:19:26AM +0200, Daniel Vetter wrote:
> > On Thu, Oct 02, 2014 at 05:36:11PM -0300, Paulo Zanoni wrote:
> > > 2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > > > Double negations just parse harder. Also this allows us to ditch some
> > > > init code since clearing to 0 dtrt. Also ditch the assignment in
> > > > intel_pm_setup, that's not redundant since we do the assignement now
> > > > while setting up interrupts.
> > > >
> > > > While at it do engage in a bit of OCD and wrap up the few lines of
> > > > setup/teardown code into little helper functions: intel_irq_fini for
> > > > cleanup and intel_irq_init_hw for hw setup.
> > >
> > > So the werid thing is that we now have:
> > > - intel_irq_init
> > > - intel_irq_init_hw
> > > - intel_irq_fini
> > >
> > > But the intel_irq_fini doesn't finish what intel_irq_init started, it
> > > finishes what intel_irq_init_hw started. Since the functions you
> > > introduced are basically wrappers to drm_irq_{un,}install, my bikeshed
> > > would be to call the new functions simply intel_irq_install and
> > > intel_irq_uninstall.
> >
> > I like this idea, so changed the names while merging.
>
> Is it worth the divergence? I think the right pattern for other areas of
> the driver is:
>
> init
> while :
> resume
> suspend
> fini
>
> That becomes something like
>
> intel_irq_init
> i915_gem_init
> ...
> while :
> intel_irq_resume
> i915_gem_resume (formerly i95_gem_init_hw)
> ...
> i915_gem_suspend
> intel_irq_suspend
> ...
> i915_gem_fini
> intel_irq_fini
irq_install/uninstall is only done a driver load/unload time, so doesn't
really fit into the pattern. At runtime (for system suspend/resume and
anything else) we now disable/enable interrupts using the runtime pm
functions.
Unfoturnately that part is hand-rolled since runtime pm is still
completely orthogonal to system s/r.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c
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
0 siblings, 1 reply; 28+ messages in thread
From: Paulo Zanoni @ 2014-10-03 18:00 UTC (permalink / raw)
To: Daniel Vetter; +Cc: Daniel Vetter, Intel Graphics Development
2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Patch 10/14: Needs rebase, but ok.
Patch 11/14: Ok.
Patch 12/14: Nice one, but:
- I've seen you complaining about lines bigger than 80 columns before,
so I obviously have to do the same here :)
- Can't we now unexport (make them static)
intel_set_{pch,cpu}_fifo_underrun_reporting()? Due to the rebasing
problem I couldn't check this.
Patch 13/14: Ok.
Patch 14/14: Since you recently submitted a patch fixing spelling
errors, I'll ask you to run a spell checker here too. I usually just
go with ":set spell" in the only text editor that exists. Some stuff:
PIPESTATE, occurance, interrup, interrup.
For all patches, with or without changes:
Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> ---
> Documentation/DocBook/drm.tmpl | 5 ++
> drivers/gpu/drm/i915/intel_fifo_underrun.c | 82 +++++++++++++++++++++++-------
> 2 files changed, 70 insertions(+), 17 deletions(-)
>
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index e8ef0f9c7396..9356f16847d9 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -3831,6 +3831,11 @@ int num_ioctls;</synopsis>
> !Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb
> </sect2>
> <sect2>
> + <title>Display FIFO Underrun Reporting</title>
> +!Pdrivers/gpu/drm/i915/intel_fifo_underrun.c fifo underrun handling
> +!Idrivers/gpu/drm/i915/intel_fifo_underrun.c
> + </sect2>
> + <sect2>
> <title>Plane Configuration</title>
> <para>
> This section covers plane configuration and composition with the
> diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> index 02909259bfb6..dfffad41664e 100644
> --- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
> +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> @@ -28,6 +28,26 @@
> #include "i915_drv.h"
> #include "intel_drv.h"
>
> +/**
> + * DOC: fifo underrun handling
> + *
> + * The i915 driver checks for display fifo underruns using the interrupt signals
> + * provided by the hardware. This is enabled by default and fairly useful to
> + * debug display issues, especially watermark settings.
> + *
> + * If an underrun is detected this is logged into dmesg. To avoid flooding logs
> + * and occupying the cpu underrun interrupts are disabled after the first
> + * occurance until the next modeset on a given pipe.
> + *
> + * Note that underrun detection on gmch platforms is a bit more ugly since there
> + * is no interrupt (despite that the signalling bit is in the PIPESTATE pipe
> + * interrupt register). Also on some other platforms underrun interrupts are
> + * shared, which means that if we detect an underrun we need to disable underrun
> + * reporting on all pipes.
> + *
> + * The code also supports underrun detection on the PCH transcoder.
> + */
> +
> static bool ivb_can_enable_err_int(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -64,6 +84,14 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
> return true;
> }
>
> +/**
> + * i9xx_check_fifo_underruns - check for fifo underruns
> + * @dev_priv: i915 device instance
> + *
> + * This function checks for fifo underruns on GMCH platforms. This needs to be
> + * done manually on modeset to make sure that we catch all underruns since they
> + * do not generate an interrupt by themselves on these platforms.
> + */
> void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
> {
> struct intel_crtc *crtc;
> @@ -199,20 +227,6 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
> }
> }
>
> -/**
> - * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
> - * @dev: drm device
> - * @pipe: pipe
> - * @enable: true if we want to report FIFO underrun errors, false otherwise
> - *
> - * This function makes us disable or enable CPU fifo underruns for a specific
> - * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
> - * reporting for one pipe may also disable all the other CPU error interruts for
> - * the other pipes, due to the fact that there's just one interrupt mask/enable
> - * bit for all the pipes.
> - *
> - * Returns the previous state of underrun reporting.
> - */
> static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
> enum pipe pipe, bool enable)
> {
> @@ -238,6 +252,22 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
> return old;
> }
>
> +/**
> + * intel_set_cpu_fifo_underrun_reporting - set cpu fifo underrrun reporting state
> + * @dev_priv: i915 device instance
> + * @pipe: (CPU) pipe to set state for
> + * @enable: whether underruns should be reported or not
> + *
> + * This function sets the fifo underrun state for @pipe. It is used in the
> + * modeset code to avoid false positives since on many platforms underruns are
> + * expected when disabling or enabling the pipe.
> + *
> + * Notice that on some platforms disabling underrun reports for one pipe
> + * disables for all due to shared interrupts. Actual reporting is still per-pipe
> + * though.
> + *
> + * Returns the previous state of underrun reporting.
> + */
> bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
> enum pipe pipe, bool enable)
> {
> @@ -262,10 +292,10 @@ static bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_p
> }
>
> /**
> - * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
> - * @dev: drm device
> + * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
> + * @dev_priv: i915 device instance
> * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
> - * @enable: true if we want to report FIFO underrun errors, false otherwise
> + * @enable: whether underruns should be reported or not
> *
> * This function makes us disable or enable PCH fifo underruns for a specific
> * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
> @@ -309,6 +339,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
> return old;
> }
>
> +/**
> + * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
> + * @dev_priv: i915 device instance
> + * @pipe: (CPU) pipe to set state for
> + *
> + * This handles a CPU fifo underrun interrupt, generating an underrun warning
> + * into dmesg if underrun reporting is enabled and then disables the underrun
> + * interrupt to avoid an irq storm.
> + */
> void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> enum pipe pipe)
> {
> @@ -322,6 +361,15 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> pipe_name(pipe));
> }
>
> +/**
> + * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
> + * @dev_priv: i915 device instance
> + * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
> + *
> + * This handles a PCH fifo underrun interrupt, generating an underrun warning
> + * into dmesg if underrun reporting is enabled and then disables the underrun
> + * interrupt to avoid an irq storm.
> + */
> void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> enum transcoder pch_transcoder)
> {
> --
> 2.1.1
>
--
Paulo Zanoni
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH 14/14] drm/i915: kerneldoc for intel_fifo_underrun.c
2014-10-03 18:00 ` Paulo Zanoni
@ 2014-10-03 20:51 ` Daniel Vetter
0 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-10-03 20:51 UTC (permalink / raw)
To: Paulo Zanoni; +Cc: Daniel Vetter, Intel Graphics Development, Daniel Vetter
On Fri, Oct 03, 2014 at 03:00:46PM -0300, Paulo Zanoni wrote:
> 2014-09-30 5:56 GMT-03:00 Daniel Vetter <daniel.vetter@ffwll.ch>:
> > Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
>
> Patch 10/14: Needs rebase, but ok.
Was just an || IS_GEN9 from the skl patches.
> Patch 11/14: Ok.
> Patch 12/14: Nice one, but:
> - I've seen you complaining about lines bigger than 80 columns before,
> so I obviously have to do the same here :)
> - Can't we now unexport (make them static)
Fixed.
> intel_set_{pch,cpu}_fifo_underrun_reporting()? Due to the rebasing
> problem I couldn't check this.
Still needed to hide underruns in some parts of the modeset sequence, so
gets called from intel_display.c. Kerneldoc even explains this ;-)
> Patch 13/14: Ok.
> Patch 14/14: Since you recently submitted a patch fixing spelling
> errors, I'll ask you to run a spell checker here too. I usually just
> go with ":set spell" in the only text editor that exists. Some stuff:
> PIPESTATE, occurance, interrup, interrup.
Fixed.
> For all patches, with or without changes:
> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Thanks a lot for your review.
Cheers, Daniel
>
> > ---
> > Documentation/DocBook/drm.tmpl | 5 ++
> > drivers/gpu/drm/i915/intel_fifo_underrun.c | 82 +++++++++++++++++++++++-------
> > 2 files changed, 70 insertions(+), 17 deletions(-)
> >
> > diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> > index e8ef0f9c7396..9356f16847d9 100644
> > --- a/Documentation/DocBook/drm.tmpl
> > +++ b/Documentation/DocBook/drm.tmpl
> > @@ -3831,6 +3831,11 @@ int num_ioctls;</synopsis>
> > !Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb
> > </sect2>
> > <sect2>
> > + <title>Display FIFO Underrun Reporting</title>
> > +!Pdrivers/gpu/drm/i915/intel_fifo_underrun.c fifo underrun handling
> > +!Idrivers/gpu/drm/i915/intel_fifo_underrun.c
> > + </sect2>
> > + <sect2>
> > <title>Plane Configuration</title>
> > <para>
> > This section covers plane configuration and composition with the
> > diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> > index 02909259bfb6..dfffad41664e 100644
> > --- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
> > +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
> > @@ -28,6 +28,26 @@
> > #include "i915_drv.h"
> > #include "intel_drv.h"
> >
> > +/**
> > + * DOC: fifo underrun handling
> > + *
> > + * The i915 driver checks for display fifo underruns using the interrupt signals
> > + * provided by the hardware. This is enabled by default and fairly useful to
> > + * debug display issues, especially watermark settings.
> > + *
> > + * If an underrun is detected this is logged into dmesg. To avoid flooding logs
> > + * and occupying the cpu underrun interrupts are disabled after the first
> > + * occurance until the next modeset on a given pipe.
> > + *
> > + * Note that underrun detection on gmch platforms is a bit more ugly since there
> > + * is no interrupt (despite that the signalling bit is in the PIPESTATE pipe
> > + * interrupt register). Also on some other platforms underrun interrupts are
> > + * shared, which means that if we detect an underrun we need to disable underrun
> > + * reporting on all pipes.
> > + *
> > + * The code also supports underrun detection on the PCH transcoder.
> > + */
> > +
> > static bool ivb_can_enable_err_int(struct drm_device *dev)
> > {
> > struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -64,6 +84,14 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
> > return true;
> > }
> >
> > +/**
> > + * i9xx_check_fifo_underruns - check for fifo underruns
> > + * @dev_priv: i915 device instance
> > + *
> > + * This function checks for fifo underruns on GMCH platforms. This needs to be
> > + * done manually on modeset to make sure that we catch all underruns since they
> > + * do not generate an interrupt by themselves on these platforms.
> > + */
> > void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
> > {
> > struct intel_crtc *crtc;
> > @@ -199,20 +227,6 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
> > }
> > }
> >
> > -/**
> > - * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
> > - * @dev: drm device
> > - * @pipe: pipe
> > - * @enable: true if we want to report FIFO underrun errors, false otherwise
> > - *
> > - * This function makes us disable or enable CPU fifo underruns for a specific
> > - * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
> > - * reporting for one pipe may also disable all the other CPU error interruts for
> > - * the other pipes, due to the fact that there's just one interrupt mask/enable
> > - * bit for all the pipes.
> > - *
> > - * Returns the previous state of underrun reporting.
> > - */
> > static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
> > enum pipe pipe, bool enable)
> > {
> > @@ -238,6 +252,22 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
> > return old;
> > }
> >
> > +/**
> > + * intel_set_cpu_fifo_underrun_reporting - set cpu fifo underrrun reporting state
> > + * @dev_priv: i915 device instance
> > + * @pipe: (CPU) pipe to set state for
> > + * @enable: whether underruns should be reported or not
> > + *
> > + * This function sets the fifo underrun state for @pipe. It is used in the
> > + * modeset code to avoid false positives since on many platforms underruns are
> > + * expected when disabling or enabling the pipe.
> > + *
> > + * Notice that on some platforms disabling underrun reports for one pipe
> > + * disables for all due to shared interrupts. Actual reporting is still per-pipe
> > + * though.
> > + *
> > + * Returns the previous state of underrun reporting.
> > + */
> > bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
> > enum pipe pipe, bool enable)
> > {
> > @@ -262,10 +292,10 @@ static bool __cpu_fifo_underrun_reporting_enabled(struct drm_i915_private *dev_p
> > }
> >
> > /**
> > - * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
> > - * @dev: drm device
> > + * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
> > + * @dev_priv: i915 device instance
> > * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
> > - * @enable: true if we want to report FIFO underrun errors, false otherwise
> > + * @enable: whether underruns should be reported or not
> > *
> > * This function makes us disable or enable PCH fifo underruns for a specific
> > * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
> > @@ -309,6 +339,15 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
> > return old;
> > }
> >
> > +/**
> > + * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
> > + * @dev_priv: i915 device instance
> > + * @pipe: (CPU) pipe to set state for
> > + *
> > + * This handles a CPU fifo underrun interrupt, generating an underrun warning
> > + * into dmesg if underrun reporting is enabled and then disables the underrun
> > + * interrupt to avoid an irq storm.
> > + */
> > void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> > enum pipe pipe)
> > {
> > @@ -322,6 +361,15 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> > pipe_name(pipe));
> > }
> >
> > +/**
> > + * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrup
> > + * @dev_priv: i915 device instance
> > + * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
> > + *
> > + * This handles a PCH fifo underrun interrupt, generating an underrun warning
> > + * into dmesg if underrun reporting is enabled and then disables the underrun
> > + * interrupt to avoid an irq storm.
> > + */
> > void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
> > enum transcoder pch_transcoder)
> > {
> > --
> > 2.1.1
> >
>
>
>
> --
> Paulo Zanoni
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2014-10-03 20:52 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox