aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/intel_runtime_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c')
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c1005
1 files changed, 677 insertions, 328 deletions
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 6b5aa3b074ec..0fdabce647ab 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -52,10 +52,6 @@
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
enum i915_power_well_id power_well_id);
-static struct i915_power_well *
-lookup_power_well(struct drm_i915_private *dev_priv,
- enum i915_power_well_id power_well_id);
-
const char *
intel_display_power_domain_str(enum intel_display_power_domain domain)
{
@@ -159,17 +155,17 @@ intel_display_power_domain_str(enum intel_display_power_domain domain)
static void intel_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- DRM_DEBUG_KMS("enabling %s\n", power_well->name);
- power_well->ops->enable(dev_priv, power_well);
+ DRM_DEBUG_KMS("enabling %s\n", power_well->desc->name);
+ power_well->desc->ops->enable(dev_priv, power_well);
power_well->hw_enabled = true;
}
static void intel_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- DRM_DEBUG_KMS("disabling %s\n", power_well->name);
+ DRM_DEBUG_KMS("disabling %s\n", power_well->desc->name);
power_well->hw_enabled = false;
- power_well->ops->disable(dev_priv, power_well);
+ power_well->desc->ops->disable(dev_priv, power_well);
}
static void intel_power_well_get(struct drm_i915_private *dev_priv,
@@ -183,7 +179,7 @@ static void intel_power_well_put(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
WARN(!power_well->count, "Use count on power well %s is already zero",
- power_well->name);
+ power_well->desc->name);
if (!--power_well->count)
intel_power_well_disable(dev_priv, power_well);
@@ -213,7 +209,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
is_enabled = true;
for_each_power_domain_well_rev(dev_priv, power_well, BIT_ULL(domain)) {
- if (power_well->always_on)
+ if (power_well->desc->always_on)
continue;
if (!power_well->hw_enabled) {
@@ -257,30 +253,6 @@ 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)
-{
- 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
@@ -323,26 +295,29 @@ static void hsw_power_well_pre_disable(struct drm_i915_private *dev_priv,
static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
/* Timeout for PW1:10 us, AUX:not specified, other PWs:20 us. */
WARN_ON(intel_wait_for_register(dev_priv,
- HSW_PWR_WELL_CTL_DRIVER(id),
- HSW_PWR_WELL_CTL_STATE(id),
- HSW_PWR_WELL_CTL_STATE(id),
+ regs->driver,
+ HSW_PWR_WELL_CTL_STATE(pw_idx),
+ HSW_PWR_WELL_CTL_STATE(pw_idx),
1));
}
static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv,
- enum i915_power_well_id id)
+ const struct i915_power_well_regs *regs,
+ int pw_idx)
{
- u32 req_mask = HSW_PWR_WELL_CTL_REQ(id);
+ u32 req_mask = HSW_PWR_WELL_CTL_REQ(pw_idx);
u32 ret;
- ret = I915_READ(HSW_PWR_WELL_CTL_BIOS(id)) & req_mask ? 1 : 0;
- ret |= I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & req_mask ? 2 : 0;
- ret |= I915_READ(HSW_PWR_WELL_CTL_KVMR) & req_mask ? 4 : 0;
- ret |= I915_READ(HSW_PWR_WELL_CTL_DEBUG(id)) & req_mask ? 8 : 0;
+ ret = I915_READ(regs->bios) & req_mask ? 1 : 0;
+ ret |= I915_READ(regs->driver) & req_mask ? 2 : 0;
+ if (regs->kvmr.reg)
+ ret |= I915_READ(regs->kvmr) & req_mask ? 4 : 0;
+ ret |= I915_READ(regs->debug) & req_mask ? 8 : 0;
return ret;
}
@@ -350,7 +325,8 @@ static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv,
static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
bool disabled;
u32 reqs;
@@ -363,14 +339,14 @@ static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv,
* Skip the wait in case any of the request bits are set and print a
* diagnostic message.
*/
- wait_for((disabled = !(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) &
- HSW_PWR_WELL_CTL_STATE(id))) ||
- (reqs = hsw_power_well_requesters(dev_priv, id)), 1);
+ wait_for((disabled = !(I915_READ(regs->driver) &
+ HSW_PWR_WELL_CTL_STATE(pw_idx))) ||
+ (reqs = hsw_power_well_requesters(dev_priv, regs, pw_idx)), 1);
if (disabled)
return;
DRM_DEBUG_KMS("%s forced on (bios:%d driver:%d kvmr:%d debug:%d)\n",
- power_well->name,
+ power_well->desc->name,
!!(reqs & 1), !!(reqs & 2), !!(reqs & 4), !!(reqs & 8));
}
@@ -386,14 +362,15 @@ static void gen9_wait_for_power_well_fuses(struct drm_i915_private *dev_priv,
static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
- bool wait_fuses = power_well->hsw.has_fuses;
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
+ bool wait_fuses = power_well->desc->hsw.has_fuses;
enum skl_power_gate uninitialized_var(pg);
u32 val;
if (wait_fuses) {
- pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_TO_PG(id) :
- SKL_PW_TO_PG(id);
+ pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) :
+ SKL_PW_CTL_IDX_TO_PG(pw_idx);
/*
* For PW1 we have to wait both for the PW0/PG0 fuse state
* before enabling the power well and PW1/PG1's own fuse
@@ -405,52 +382,55 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
gen9_wait_for_power_well_fuses(dev_priv, SKL_PG0);
}
- val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
- I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id));
+ val = I915_READ(regs->driver);
+ I915_WRITE(regs->driver, val | HSW_PWR_WELL_CTL_REQ(pw_idx));
hsw_wait_for_power_well_enable(dev_priv, power_well);
/* Display WA #1178: cnl */
if (IS_CANNONLAKE(dev_priv) &&
- (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C ||
- id == CNL_DISP_PW_AUX_D || id == CNL_DISP_PW_AUX_F)) {
- val = I915_READ(CNL_AUX_ANAOVRD1(id));
+ pw_idx >= GLK_PW_CTL_IDX_AUX_B &&
+ pw_idx <= CNL_PW_CTL_IDX_AUX_F) {
+ val = I915_READ(CNL_AUX_ANAOVRD1(pw_idx));
val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS;
- I915_WRITE(CNL_AUX_ANAOVRD1(id), val);
+ I915_WRITE(CNL_AUX_ANAOVRD1(pw_idx), val);
}
if (wait_fuses)
gen9_wait_for_power_well_fuses(dev_priv, pg);
- hsw_power_well_post_enable(dev_priv, power_well->hsw.irq_pipe_mask,
- power_well->hsw.has_vga);
+ hsw_power_well_post_enable(dev_priv,
+ power_well->desc->hsw.irq_pipe_mask,
+ power_well->desc->hsw.has_vga);
}
static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
u32 val;
- hsw_power_well_pre_disable(dev_priv, power_well->hsw.irq_pipe_mask);
+ hsw_power_well_pre_disable(dev_priv,
+ power_well->desc->hsw.irq_pipe_mask);
- val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
- I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id),
- val & ~HSW_PWR_WELL_CTL_REQ(id));
+ val = I915_READ(regs->driver);
+ I915_WRITE(regs->driver, val & ~HSW_PWR_WELL_CTL_REQ(pw_idx));
hsw_wait_for_power_well_disable(dev_priv, power_well);
}
-#define ICL_AUX_PW_TO_PORT(pw) ((pw) - ICL_DISP_PW_AUX_A)
+#define ICL_AUX_PW_TO_PORT(pw_idx) ((pw_idx) - ICL_PW_CTL_IDX_AUX_A)
static void
icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
- enum port port = ICL_AUX_PW_TO_PORT(id);
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
+ enum port port = ICL_AUX_PW_TO_PORT(pw_idx);
u32 val;
- val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
- I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id));
+ val = I915_READ(regs->driver);
+ I915_WRITE(regs->driver, val | HSW_PWR_WELL_CTL_REQ(pw_idx));
val = I915_READ(ICL_PORT_CL_DW12(port));
I915_WRITE(ICL_PORT_CL_DW12(port), val | ICL_LANE_ENABLE_AUX);
@@ -462,16 +442,16 @@ static void
icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
- enum port port = ICL_AUX_PW_TO_PORT(id);
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
+ enum port port = ICL_AUX_PW_TO_PORT(pw_idx);
u32 val;
val = I915_READ(ICL_PORT_CL_DW12(port));
I915_WRITE(ICL_PORT_CL_DW12(port), val & ~ICL_LANE_ENABLE_AUX);
- val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
- I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id),
- val & ~HSW_PWR_WELL_CTL_REQ(id));
+ val = I915_READ(regs->driver);
+ I915_WRITE(regs->driver, val & ~HSW_PWR_WELL_CTL_REQ(pw_idx));
hsw_wait_for_power_well_disable(dev_priv, power_well);
}
@@ -484,22 +464,22 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv,
static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
- u32 mask = HSW_PWR_WELL_CTL_REQ(id) | HSW_PWR_WELL_CTL_STATE(id);
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
+ u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx) |
+ HSW_PWR_WELL_CTL_STATE(pw_idx);
- return (I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & mask) == mask;
+ return (I915_READ(regs->driver) & mask) == mask;
}
static void assert_can_enable_dc9(struct drm_i915_private *dev_priv)
{
- enum i915_power_well_id id = SKL_DISP_PW_2;
-
WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9),
"DC9 already programmed to be enabled.\n");
WARN_ONCE(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5,
"DC5 still not disabled to enable DC9.\n");
- WARN_ONCE(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) &
- HSW_PWR_WELL_CTL_REQ(id),
+ WARN_ONCE(I915_READ(HSW_PWR_WELL_CTL2) &
+ HSW_PWR_WELL_CTL_REQ(SKL_PW_CTL_IDX_PW_2),
"Power well 2 on.\n");
WARN_ONCE(intel_irqs_enabled(dev_priv),
"Interrupts not disabled yet.\n");
@@ -668,6 +648,27 @@ static void assert_csr_loaded(struct drm_i915_private *dev_priv)
WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
}
+static struct i915_power_well *
+lookup_power_well(struct drm_i915_private *dev_priv,
+ enum i915_power_well_id power_well_id)
+{
+ struct i915_power_well *power_well;
+
+ for_each_power_well(dev_priv, power_well)
+ if (power_well->desc->id == power_well_id)
+ return power_well;
+
+ /*
+ * It's not feasible to add error checking code to the callers since
+ * this condition really shouldn't happen and it doesn't even make sense
+ * to abort things like display initialization sequences. Just return
+ * the first power well and hope the WARN gets reported so we can fix
+ * our driver.
+ */
+ WARN(1, "Power well %d not defined for this platform\n", power_well_id);
+ return &dev_priv->power_domains.power_wells[0];
+}
+
static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
{
bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv,
@@ -723,54 +724,57 @@ static void skl_enable_dc6(struct drm_i915_private *dev_priv)
static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id id = power_well->id;
- u32 mask = HSW_PWR_WELL_CTL_REQ(id);
- u32 bios_req = I915_READ(HSW_PWR_WELL_CTL_BIOS(id));
+ const struct i915_power_well_regs *regs = power_well->desc->hsw.regs;
+ int pw_idx = power_well->desc->hsw.idx;
+ u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx);
+ u32 bios_req = I915_READ(regs->bios);
/* Take over the request bit if set by BIOS. */
if (bios_req & mask) {
- u32 drv_req = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
+ u32 drv_req = I915_READ(regs->driver);
if (!(drv_req & mask))
- I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), drv_req | mask);
- I915_WRITE(HSW_PWR_WELL_CTL_BIOS(id), bios_req & ~mask);
+ I915_WRITE(regs->driver, drv_req | mask);
+ I915_WRITE(regs->bios, bios_req & ~mask);
}
}
static void bxt_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- bxt_ddi_phy_init(dev_priv, power_well->bxt.phy);
+ bxt_ddi_phy_init(dev_priv, power_well->desc->bxt.phy);
}
static void bxt_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- bxt_ddi_phy_uninit(dev_priv, power_well->bxt.phy);
+ bxt_ddi_phy_uninit(dev_priv, power_well->desc->bxt.phy);
}
static bool bxt_dpio_cmn_power_well_enabled(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- return bxt_ddi_phy_is_enabled(dev_priv, power_well->bxt.phy);
+ return bxt_ddi_phy_is_enabled(dev_priv, power_well->desc->bxt.phy);
}
static void bxt_verify_ddi_phy_power_wells(struct drm_i915_private *dev_priv)
{
struct i915_power_well *power_well;
- power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_A);
+ power_well = lookup_power_well(dev_priv, BXT_DISP_PW_DPIO_CMN_A);
if (power_well->count > 0)
- bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy);
+ bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy);
- power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_BC);
+ power_well = lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC);
if (power_well->count > 0)
- bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy);
+ bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy);
if (IS_GEMINILAKE(dev_priv)) {
- power_well = lookup_power_well(dev_priv, GLK_DPIO_CMN_C);
+ power_well = lookup_power_well(dev_priv,
+ GLK_DISP_PW_DPIO_CMN_C);
if (power_well->count > 0)
- bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy);
+ bxt_ddi_phy_verify_state(dev_priv,
+ power_well->desc->bxt.phy);
}
}
@@ -869,14 +873,14 @@ static void i830_pipes_power_well_sync_hw(struct drm_i915_private *dev_priv,
static void vlv_set_power_well(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well, bool enable)
{
- enum i915_power_well_id power_well_id = power_well->id;
+ int pw_idx = power_well->desc->vlv.idx;
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);
+ mask = PUNIT_PWRGT_MASK(pw_idx);
+ state = enable ? PUNIT_PWRGT_PWR_ON(pw_idx) :
+ PUNIT_PWRGT_PWR_GATE(pw_idx);
mutex_lock(&dev_priv->pcu_lock);
@@ -917,14 +921,14 @@ static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- enum i915_power_well_id power_well_id = power_well->id;
+ int pw_idx = power_well->desc->vlv.idx;
bool enabled = false;
u32 mask;
u32 state;
u32 ctrl;
- mask = PUNIT_PWRGT_MASK(power_well_id);
- ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
+ mask = PUNIT_PWRGT_MASK(pw_idx);
+ ctrl = PUNIT_PWRGT_PWR_ON(pw_idx);
mutex_lock(&dev_priv->pcu_lock);
@@ -933,8 +937,8 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
* 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));
+ WARN_ON(state != PUNIT_PWRGT_PWR_ON(pw_idx) &&
+ state != PUNIT_PWRGT_PWR_GATE(pw_idx));
if (state == ctrl)
enabled = true;
@@ -1045,8 +1049,6 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv)
static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DISP2D);
-
vlv_set_power_well(dev_priv, power_well, true);
vlv_display_power_well_init(dev_priv);
@@ -1055,8 +1057,6 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DISP2D);
-
vlv_display_power_well_deinit(dev_priv);
vlv_set_power_well(dev_priv, power_well, false);
@@ -1065,8 +1065,6 @@ static void vlv_display_power_well_disable(struct drm_i915_private *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->id != PUNIT_POWER_WELL_DPIO_CMN_BC);
-
/* since ref/cri clock was enabled */
udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
@@ -1091,8 +1089,6 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
{
enum pipe pipe;
- WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC);
-
for_each_pipe(dev_priv, pipe)
assert_pll_disabled(dev_priv, pipe);
@@ -1104,32 +1100,14 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
#define POWER_DOMAIN_MASK (GENMASK_ULL(POWER_DOMAIN_NUM - 1, 0))
-static struct i915_power_well *
-lookup_power_well(struct drm_i915_private *dev_priv,
- enum i915_power_well_id power_well_id)
-{
- struct i915_power_domains *power_domains = &dev_priv->power_domains;
- int i;
-
- for (i = 0; i < power_domains->power_well_count; i++) {
- struct i915_power_well *power_well;
-
- power_well = &power_domains->power_wells[i];
- if (power_well->id == power_well_id)
- return power_well;
- }
-
- return NULL;
-}
-
#define BITS_SET(val, bits) (((val) & (bits)) == (bits))
static void assert_chv_phy_status(struct drm_i915_private *dev_priv)
{
struct i915_power_well *cmn_bc =
- lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
+ lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC);
struct i915_power_well *cmn_d =
- lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D);
+ lookup_power_well(dev_priv, CHV_DISP_PW_DPIO_CMN_D);
u32 phy_control = dev_priv->chv_phy_control;
u32 phy_status = 0;
u32 phy_status_mask = 0xffffffff;
@@ -1154,7 +1132,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv)
PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0) |
PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1));
- if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) {
+ if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) {
phy_status |= PHY_POWERGOOD(DPIO_PHY0);
/* this assumes override is only used to enable lanes */
@@ -1195,7 +1173,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv)
phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1);
}
- if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) {
+ if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) {
phy_status |= PHY_POWERGOOD(DPIO_PHY1);
/* this assumes override is only used to enable lanes */
@@ -1239,10 +1217,10 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
enum pipe pipe;
uint32_t tmp;
- WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC &&
- power_well->id != PUNIT_POWER_WELL_DPIO_CMN_D);
+ WARN_ON_ONCE(power_well->desc->id != VLV_DISP_PW_DPIO_CMN_BC &&
+ power_well->desc->id != CHV_DISP_PW_DPIO_CMN_D);
- if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) {
pipe = PIPE_A;
phy = DPIO_PHY0;
} else {
@@ -1270,7 +1248,7 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
DPIO_SUS_CLK_CONFIG_GATE_CLKREQ;
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp);
- if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) {
tmp = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW6_CH1);
tmp |= DPIO_DYNPWRDOWNEN_CH1;
vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW6_CH1, tmp);
@@ -1301,10 +1279,10 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
{
enum dpio_phy phy;
- WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC &&
- power_well->id != PUNIT_POWER_WELL_DPIO_CMN_D);
+ WARN_ON_ONCE(power_well->desc->id != VLV_DISP_PW_DPIO_CMN_BC &&
+ power_well->desc->id != CHV_DISP_PW_DPIO_CMN_D);
- if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) {
phy = DPIO_PHY0;
assert_pll_disabled(dev_priv, PIPE_A);
assert_pll_disabled(dev_priv, PIPE_B);
@@ -1516,8 +1494,6 @@ out:
static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- WARN_ON_ONCE(power_well->id != CHV_DISP_PW_PIPE_A);
-
chv_set_pipe_power_well(dev_priv, power_well, true);
vlv_display_power_well_init(dev_priv);
@@ -1526,8 +1502,6 @@ static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv,
static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- WARN_ON_ONCE(power_well->id != CHV_DISP_PW_PIPE_A);
-
vlv_display_power_well_deinit(dev_priv);
chv_set_pipe_power_well(dev_priv, power_well, false);
@@ -2022,6 +1996,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO))
#define ICL_AUX_A_IO_POWER_DOMAINS ( \
+ BIT_ULL(POWER_DOMAIN_AUX_IO_A) | \
BIT_ULL(POWER_DOMAIN_AUX_A))
#define ICL_AUX_B_IO_POWER_DOMAINS ( \
BIT_ULL(POWER_DOMAIN_AUX_B))
@@ -2063,13 +2038,13 @@ static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = {
.is_enabled = vlv_power_well_enabled,
};
-static struct i915_power_well i9xx_always_on_power_well[] = {
+static const struct i915_power_well_desc i9xx_always_on_power_well[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
};
@@ -2080,19 +2055,19 @@ static const struct i915_power_well_ops i830_pipes_power_well_ops = {
.is_enabled = i830_pipes_power_well_enabled,
};
-static struct i915_power_well i830_power_wells[] = {
+static const struct i915_power_well_desc i830_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "pipes",
.domains = I830_PIPES_POWER_DOMAINS,
.ops = &i830_pipes_power_well_ops,
- .id = I830_DISP_PW_PIPES,
+ .id = DISP_PW_ID_NONE,
},
};
@@ -2117,13 +2092,20 @@ static const struct i915_power_well_ops bxt_dpio_cmn_power_well_ops = {
.is_enabled = bxt_dpio_cmn_power_well_enabled,
};
-static struct i915_power_well hsw_power_wells[] = {
+static const struct i915_power_well_regs hsw_power_well_regs = {
+ .bios = HSW_PWR_WELL_CTL1,
+ .driver = HSW_PWR_WELL_CTL2,
+ .kvmr = HSW_PWR_WELL_CTL3,
+ .debug = HSW_PWR_WELL_CTL4,
+};
+
+static const struct i915_power_well_desc hsw_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "display",
@@ -2131,18 +2113,20 @@ static struct i915_power_well hsw_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = HSW_DISP_PW_GLOBAL,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = HSW_PW_CTL_IDX_GLOBAL,
.hsw.has_vga = true,
},
},
};
-static struct i915_power_well bdw_power_wells[] = {
+static const struct i915_power_well_desc bdw_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "display",
@@ -2150,6 +2134,8 @@ static struct i915_power_well bdw_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = HSW_DISP_PW_GLOBAL,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = HSW_PW_CTL_IDX_GLOBAL,
.hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C),
.hsw.has_vga = true,
},
@@ -2177,19 +2163,22 @@ static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
.is_enabled = vlv_power_well_enabled,
};
-static struct i915_power_well vlv_power_wells[] = {
+static const struct i915_power_well_desc vlv_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "display",
.domains = VLV_DISPLAY_POWER_DOMAINS,
- .id = PUNIT_POWER_WELL_DISP2D,
.ops = &vlv_display_power_well_ops,
+ .id = VLV_DISP_PW_DISP2D,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DISP2D,
+ },
},
{
.name = "dpio-tx-b-01",
@@ -2198,7 +2187,10 @@ static struct i915_power_well vlv_power_wells[] = {
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
.ops = &vlv_dpio_power_well_ops,
- .id = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
+ .id = DISP_PW_ID_NONE,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_B_LANES_01,
+ },
},
{
.name = "dpio-tx-b-23",
@@ -2207,7 +2199,10 @@ static struct i915_power_well vlv_power_wells[] = {
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
.ops = &vlv_dpio_power_well_ops,
- .id = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
+ .id = DISP_PW_ID_NONE,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_B_LANES_23,
+ },
},
{
.name = "dpio-tx-c-01",
@@ -2216,7 +2211,10 @@ static struct i915_power_well vlv_power_wells[] = {
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
.ops = &vlv_dpio_power_well_ops,
- .id = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
+ .id = DISP_PW_ID_NONE,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_C_LANES_01,
+ },
},
{
.name = "dpio-tx-c-23",
@@ -2225,23 +2223,29 @@ static struct i915_power_well vlv_power_wells[] = {
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
.ops = &vlv_dpio_power_well_ops,
- .id = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
+ .id = DISP_PW_ID_NONE,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_C_LANES_23,
+ },
},
{
.name = "dpio-common",
.domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
- .id = PUNIT_POWER_WELL_DPIO_CMN_BC,
.ops = &vlv_dpio_cmn_power_well_ops,
+ .id = VLV_DISP_PW_DPIO_CMN_BC,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_BC,
+ },
},
};
-static struct i915_power_well chv_power_wells[] = {
+static const struct i915_power_well_desc chv_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "display",
@@ -2251,20 +2255,26 @@ static struct i915_power_well chv_power_wells[] = {
* required for any pipe to work.
*/
.domains = CHV_DISPLAY_POWER_DOMAINS,
- .id = CHV_DISP_PW_PIPE_A,
.ops = &chv_pipe_power_well_ops,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "dpio-common-bc",
.domains = CHV_DPIO_CMN_BC_POWER_DOMAINS,
- .id = PUNIT_POWER_WELL_DPIO_CMN_BC,
.ops = &chv_dpio_cmn_power_well_ops,
+ .id = VLV_DISP_PW_DPIO_CMN_BC,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_BC,
+ },
},
{
.name = "dpio-common-d",
.domains = CHV_DPIO_CMN_D_POWER_DOMAINS,
- .id = PUNIT_POWER_WELL_DPIO_CMN_D,
.ops = &chv_dpio_cmn_power_well_ops,
+ .id = CHV_DISP_PW_DPIO_CMN_D,
+ {
+ .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_D,
+ },
},
};
@@ -2275,18 +2285,18 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
bool ret;
power_well = lookup_power_well(dev_priv, power_well_id);
- ret = power_well->ops->is_enabled(dev_priv, power_well);
+ ret = power_well->desc->ops->is_enabled(dev_priv, power_well);
return ret;
}
-static struct i915_power_well skl_power_wells[] = {
+static const struct i915_power_well_desc skl_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 1",
@@ -2295,6 +2305,8 @@ static struct i915_power_well skl_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_1,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_1,
.hsw.has_fuses = true,
},
},
@@ -2304,12 +2316,16 @@ static struct i915_power_well skl_power_wells[] = {
.domains = 0,
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_MISC_IO,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_MISC_IO,
+ },
},
{
.name = "DC off",
.domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
- .id = SKL_DISP_PW_DC_OFF,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 2",
@@ -2317,6 +2333,8 @@ static struct i915_power_well skl_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_2,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_2,
.hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C),
.hsw.has_vga = true,
.hsw.has_fuses = true,
@@ -2326,35 +2344,51 @@ static struct i915_power_well skl_power_wells[] = {
.name = "DDI A/E IO power well",
.domains = SKL_DISPLAY_DDI_IO_A_E_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_A_E,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_A_E,
+ },
},
{
.name = "DDI B IO power well",
.domains = SKL_DISPLAY_DDI_IO_B_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_B,
+ },
},
{
.name = "DDI C IO power well",
.domains = SKL_DISPLAY_DDI_IO_C_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_C,
+ },
},
{
.name = "DDI D IO power well",
.domains = SKL_DISPLAY_DDI_IO_D_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_D,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_D,
+ },
},
};
-static struct i915_power_well bxt_power_wells[] = {
+static const struct i915_power_well_desc bxt_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 1",
@@ -2362,6 +2396,8 @@ static struct i915_power_well bxt_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_1,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_1,
.hsw.has_fuses = true,
},
},
@@ -2369,7 +2405,7 @@ static struct i915_power_well bxt_power_wells[] = {
.name = "DC off",
.domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
- .id = SKL_DISP_PW_DC_OFF,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 2",
@@ -2377,6 +2413,8 @@ static struct i915_power_well bxt_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_2,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_2,
.hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C),
.hsw.has_vga = true,
.hsw.has_fuses = true,
@@ -2386,7 +2424,7 @@ static struct i915_power_well bxt_power_wells[] = {
.name = "dpio-common-a",
.domains = BXT_DPIO_CMN_A_POWER_DOMAINS,
.ops = &bxt_dpio_cmn_power_well_ops,
- .id = BXT_DPIO_CMN_A,
+ .id = BXT_DISP_PW_DPIO_CMN_A,
{
.bxt.phy = DPIO_PHY1,
},
@@ -2395,20 +2433,20 @@ static struct i915_power_well bxt_power_wells[] = {
.name = "dpio-common-bc",
.domains = BXT_DPIO_CMN_BC_POWER_DOMAINS,
.ops = &bxt_dpio_cmn_power_well_ops,
- .id = BXT_DPIO_CMN_BC,
+ .id = VLV_DISP_PW_DPIO_CMN_BC,
{
.bxt.phy = DPIO_PHY0,
},
},
};
-static struct i915_power_well glk_power_wells[] = {
+static const struct i915_power_well_desc glk_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 1",
@@ -2417,6 +2455,8 @@ static struct i915_power_well glk_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_1,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_1,
.hsw.has_fuses = true,
},
},
@@ -2424,7 +2464,7 @@ static struct i915_power_well glk_power_wells[] = {
.name = "DC off",
.domains = GLK_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
- .id = SKL_DISP_PW_DC_OFF,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 2",
@@ -2432,6 +2472,8 @@ static struct i915_power_well glk_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_2,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_2,
.hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C),
.hsw.has_vga = true,
.hsw.has_fuses = true,
@@ -2441,7 +2483,7 @@ static struct i915_power_well glk_power_wells[] = {
.name = "dpio-common-a",
.domains = GLK_DPIO_CMN_A_POWER_DOMAINS,
.ops = &bxt_dpio_cmn_power_well_ops,
- .id = BXT_DPIO_CMN_A,
+ .id = BXT_DISP_PW_DPIO_CMN_A,
{
.bxt.phy = DPIO_PHY1,
},
@@ -2450,7 +2492,7 @@ static struct i915_power_well glk_power_wells[] = {
.name = "dpio-common-b",
.domains = GLK_DPIO_CMN_B_POWER_DOMAINS,
.ops = &bxt_dpio_cmn_power_well_ops,
- .id = BXT_DPIO_CMN_BC,
+ .id = VLV_DISP_PW_DPIO_CMN_BC,
{
.bxt.phy = DPIO_PHY0,
},
@@ -2459,7 +2501,7 @@ static struct i915_power_well glk_power_wells[] = {
.name = "dpio-common-c",
.domains = GLK_DPIO_CMN_C_POWER_DOMAINS,
.ops = &bxt_dpio_cmn_power_well_ops,
- .id = GLK_DPIO_CMN_C,
+ .id = GLK_DISP_PW_DPIO_CMN_C,
{
.bxt.phy = DPIO_PHY2,
},
@@ -2468,47 +2510,71 @@ static struct i915_power_well glk_power_wells[] = {
.name = "AUX A",
.domains = GLK_DISPLAY_AUX_A_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = GLK_DISP_PW_AUX_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_A,
+ },
},
{
.name = "AUX B",
.domains = GLK_DISPLAY_AUX_B_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = GLK_DISP_PW_AUX_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_B,
+ },
},
{
.name = "AUX C",
.domains = GLK_DISPLAY_AUX_C_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = GLK_DISP_PW_AUX_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_C,
+ },
},
{
.name = "DDI A IO power well",
.domains = GLK_DISPLAY_DDI_IO_A_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = GLK_DISP_PW_DDI_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_DDI_A,
+ },
},
{
.name = "DDI B IO power well",
.domains = GLK_DISPLAY_DDI_IO_B_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_B,
+ },
},
{
.name = "DDI C IO power well",
.domains = GLK_DISPLAY_DDI_IO_C_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_C,
+ },
},
};
-static struct i915_power_well cnl_power_wells[] = {
+static const struct i915_power_well_desc cnl_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 1",
@@ -2517,6 +2583,8 @@ static struct i915_power_well cnl_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_1,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_1,
.hsw.has_fuses = true,
},
},
@@ -2524,31 +2592,47 @@ static struct i915_power_well cnl_power_wells[] = {
.name = "AUX A",
.domains = CNL_DISPLAY_AUX_A_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_AUX_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_A,
+ },
},
{
.name = "AUX B",
.domains = CNL_DISPLAY_AUX_B_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_AUX_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_B,
+ },
},
{
.name = "AUX C",
.domains = CNL_DISPLAY_AUX_C_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_AUX_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_AUX_C,
+ },
},
{
.name = "AUX D",
.domains = CNL_DISPLAY_AUX_D_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_AUX_D,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = CNL_PW_CTL_IDX_AUX_D,
+ },
},
{
.name = "DC off",
.domains = CNL_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
- .id = SKL_DISP_PW_DC_OFF,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 2",
@@ -2556,6 +2640,8 @@ static struct i915_power_well cnl_power_wells[] = {
.ops = &hsw_power_well_ops,
.id = SKL_DISP_PW_2,
{
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_PW_2,
.hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C),
.hsw.has_vga = true,
.hsw.has_fuses = true,
@@ -2565,37 +2651,61 @@ static struct i915_power_well cnl_power_wells[] = {
.name = "DDI A IO power well",
.domains = CNL_DISPLAY_DDI_A_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_DDI_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = GLK_PW_CTL_IDX_DDI_A,
+ },
},
{
.name = "DDI B IO power well",
.domains = CNL_DISPLAY_DDI_B_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_B,
+ },
},
{
.name = "DDI C IO power well",
.domains = CNL_DISPLAY_DDI_C_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_C,
+ },
},
{
.name = "DDI D IO power well",
.domains = CNL_DISPLAY_DDI_D_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = SKL_DISP_PW_DDI_D,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = SKL_PW_CTL_IDX_DDI_D,
+ },
},
{
.name = "DDI F IO power well",
.domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_DDI_F,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = CNL_PW_CTL_IDX_DDI_F,
+ },
},
{
.name = "AUX F",
.domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = CNL_DISP_PW_AUX_F,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = CNL_PW_CTL_IDX_AUX_F,
+ },
},
};
@@ -2606,147 +2716,239 @@ static const struct i915_power_well_ops icl_combo_phy_aux_power_well_ops = {
.is_enabled = hsw_power_well_enabled,
};
-static struct i915_power_well icl_power_wells[] = {
+static const struct i915_power_well_regs icl_aux_power_well_regs = {
+ .bios = ICL_PWR_WELL_CTL_AUX1,
+ .driver = ICL_PWR_WELL_CTL_AUX2,
+ .debug = ICL_PWR_WELL_CTL_AUX4,
+};
+
+static const struct i915_power_well_regs icl_ddi_power_well_regs = {
+ .bios = ICL_PWR_WELL_CTL_DDI1,
+ .driver = ICL_PWR_WELL_CTL_DDI2,
+ .debug = ICL_PWR_WELL_CTL_DDI4,
+};
+
+static const struct i915_power_well_desc icl_power_wells[] = {
{
.name = "always-on",
.always_on = 1,
.domains = POWER_DOMAIN_MASK,
.ops = &i9xx_always_on_power_well_ops,
- .id = I915_DISP_PW_ALWAYS_ON,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 1",
/* Handled by the DMC firmware */
.domains = 0,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_1,
- .hsw.has_fuses = true,
+ .id = SKL_DISP_PW_1,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_PW_1,
+ .hsw.has_fuses = true,
+ },
},
{
.name = "power well 2",
.domains = ICL_PW_2_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_2,
- .hsw.has_fuses = true,
+ .id = SKL_DISP_PW_2,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_PW_2,
+ .hsw.has_fuses = true,
+ },
},
{
.name = "DC off",
.domains = ICL_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
- .id = SKL_DISP_PW_DC_OFF,
+ .id = DISP_PW_ID_NONE,
},
{
.name = "power well 3",
.domains = ICL_PW_3_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_3,
- .hsw.irq_pipe_mask = BIT(PIPE_B),
- .hsw.has_vga = true,
- .hsw.has_fuses = true,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_PW_3,
+ .hsw.irq_pipe_mask = BIT(PIPE_B),
+ .hsw.has_vga = true,
+ .hsw.has_fuses = true,
+ },
},
{
.name = "DDI A IO",
.domains = ICL_DDI_IO_A_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_A,
+ },
},
{
.name = "DDI B IO",
.domains = ICL_DDI_IO_B_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_B,
+ },
},
{
.name = "DDI C IO",
.domains = ICL_DDI_IO_C_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_C,
+ },
},
{
.name = "DDI D IO",
.domains = ICL_DDI_IO_D_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_D,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_D,
+ },
},
{
.name = "DDI E IO",
.domains = ICL_DDI_IO_E_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_E,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_E,
+ },
},
{
.name = "DDI F IO",
.domains = ICL_DDI_IO_F_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_DDI_F,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_ddi_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_DDI_F,
+ },
},
{
.name = "AUX A",
.domains = ICL_AUX_A_IO_POWER_DOMAINS,
.ops = &icl_combo_phy_aux_power_well_ops,
- .id = ICL_DISP_PW_AUX_A,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_A,
+ },
},
{
.name = "AUX B",
.domains = ICL_AUX_B_IO_POWER_DOMAINS,
.ops = &icl_combo_phy_aux_power_well_ops,
- .id = ICL_DISP_PW_AUX_B,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_B,
+ },
},
{
.name = "AUX C",
.domains = ICL_AUX_C_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_C,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_C,
+ },
},
{
.name = "AUX D",
.domains = ICL_AUX_D_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_D,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_D,
+ },
},
{
.name = "AUX E",
.domains = ICL_AUX_E_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_E,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_E,
+ },
},
{
.name = "AUX F",
.domains = ICL_AUX_F_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_F,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_F,
+ },
},
{
.name = "AUX TBT1",
.domains = ICL_AUX_TBT1_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_TBT1,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT1,
+ },
},
{
.name = "AUX TBT2",
.domains = ICL_AUX_TBT2_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_TBT2,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT2,
+ },
},
{
.name = "AUX TBT3",
.domains = ICL_AUX_TBT3_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_TBT3,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT3,
+ },
},
{
.name = "AUX TBT4",
.domains = ICL_AUX_TBT4_IO_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_AUX_TBT4,
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &icl_aux_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT4,
+ },
},
{
.name = "power well 4",
.domains = ICL_PW_4_POWER_DOMAINS,
.ops = &hsw_power_well_ops,
- .id = ICL_DISP_PW_4,
- .hsw.has_fuses = true,
- .hsw.irq_pipe_mask = BIT(PIPE_C),
+ .id = DISP_PW_ID_NONE,
+ {
+ .hsw.regs = &hsw_power_well_regs,
+ .hsw.idx = ICL_PW_CTL_IDX_PW_4,
+ .hsw.has_fuses = true,
+ .hsw.irq_pipe_mask = BIT(PIPE_C),
+ },
},
};
@@ -2809,26 +3011,41 @@ static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
return mask;
}
-static void assert_power_well_ids_unique(struct drm_i915_private *dev_priv)
+static int
+__set_power_wells(struct i915_power_domains *power_domains,
+ const struct i915_power_well_desc *power_well_descs,
+ int power_well_count)
{
- struct i915_power_domains *power_domains = &dev_priv->power_domains;
- u64 power_well_ids;
+ u64 power_well_ids = 0;
int i;
- power_well_ids = 0;
- for (i = 0; i < power_domains->power_well_count; i++) {
- enum i915_power_well_id id = power_domains->power_wells[i].id;
+ power_domains->power_well_count = power_well_count;
+ power_domains->power_wells =
+ kcalloc(power_well_count,
+ sizeof(*power_domains->power_wells),
+ GFP_KERNEL);
+ if (!power_domains->power_wells)
+ return -ENOMEM;
+
+ for (i = 0; i < power_well_count; i++) {
+ enum i915_power_well_id id = power_well_descs[i].id;
+
+ power_domains->power_wells[i].desc = &power_well_descs[i];
+
+ if (id == DISP_PW_ID_NONE)
+ continue;
WARN_ON(id >= sizeof(power_well_ids) * 8);
WARN_ON(power_well_ids & BIT_ULL(id));
power_well_ids |= BIT_ULL(id);
}
+
+ return 0;
}
-#define set_power_wells(power_domains, __power_wells) ({ \
- (power_domains)->power_wells = (__power_wells); \
- (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
-})
+#define set_power_wells(power_domains, __power_well_descs) \
+ __set_power_wells(power_domains, __power_well_descs, \
+ ARRAY_SIZE(__power_well_descs))
/**
* intel_power_domains_init - initializes the power domain structures
@@ -2840,6 +3057,7 @@ static void assert_power_well_ids_unique(struct drm_i915_private *dev_priv)
int intel_power_domains_init(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ int err;
i915_modparams.disable_power_well =
sanitize_disable_power_well_option(dev_priv,
@@ -2856,15 +3074,15 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
* the disabling order is reversed.
*/
if (IS_ICELAKE(dev_priv)) {
- set_power_wells(power_domains, icl_power_wells);
+ err = set_power_wells(power_domains, icl_power_wells);
} else if (IS_HASWELL(dev_priv)) {
- set_power_wells(power_domains, hsw_power_wells);
+ err = set_power_wells(power_domains, hsw_power_wells);
} else if (IS_BROADWELL(dev_priv)) {
- set_power_wells(power_domains, bdw_power_wells);
+ err = set_power_wells(power_domains, bdw_power_wells);
} else if (IS_GEN9_BC(dev_priv)) {
- set_power_wells(power_domains, skl_power_wells);
+ err = set_power_wells(power_domains, skl_power_wells);
} else if (IS_CANNONLAKE(dev_priv)) {
- set_power_wells(power_domains, cnl_power_wells);
+ err = set_power_wells(power_domains, cnl_power_wells);
/*
* DDI and Aux IO are getting enabled for all ports
@@ -2876,57 +3094,31 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
power_domains->power_well_count -= 2;
} else if (IS_BROXTON(dev_priv)) {
- set_power_wells(power_domains, bxt_power_wells);
+ err = set_power_wells(power_domains, bxt_power_wells);
} else if (IS_GEMINILAKE(dev_priv)) {
- set_power_wells(power_domains, glk_power_wells);
+ err = set_power_wells(power_domains, glk_power_wells);
} else if (IS_CHERRYVIEW(dev_priv)) {
- set_power_wells(power_domains, chv_power_wells);
+ err = set_power_wells(power_domains, chv_power_wells);
} else if (IS_VALLEYVIEW(dev_priv)) {
- set_power_wells(power_domains, vlv_power_wells);
+ err = set_power_wells(power_domains, vlv_power_wells);
} else if (IS_I830(dev_priv)) {
- set_power_wells(power_domains, i830_power_wells);
+ err = set_power_wells(power_domains, i830_power_wells);
} else {
- set_power_wells(power_domains, i9xx_always_on_power_well);
+ err = set_power_wells(power_domains, i9xx_always_on_power_well);
}
- assert_power_well_ids_unique(dev_priv);
-
- return 0;
+ return err;
}
/**
- * intel_power_domains_fini - finalizes the power domain structures
+ * intel_power_domains_cleanup - clean up power domains resources
* @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.
+ * Release any resources acquired by intel_power_domains_init()
*/
-void intel_power_domains_fini(struct drm_i915_private *dev_priv)
+void intel_power_domains_cleanup(struct drm_i915_private *dev_priv)
{
- struct device *kdev = &dev_priv->drm.pdev->dev;
-
- /*
- * 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.
- * The following also reacquires the RPM reference the core passed
- * to the driver during loading, which is dropped in
- * intel_runtime_pm_enable(). We have to hand back the control of the
- * device to the core with this reference held.
- */
- intel_display_set_init_power(dev_priv, true);
-
- /* Remove the refcount we took to keep power well support disabled. */
- if (!i915_modparams.disable_power_well)
- intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
-
- /*
- * Remove the refcount we took in intel_runtime_pm_enable() in case
- * the platform doesn't support runtime PM.
- */
- if (!HAS_RUNTIME_PM(dev_priv))
- pm_runtime_put(kdev);
+ kfree(dev_priv->power_domains.power_wells);
}
static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
@@ -2936,9 +3128,9 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
mutex_lock(&power_domains->lock);
for_each_power_well(dev_priv, power_well) {
- power_well->ops->sync_hw(dev_priv, power_well);
- power_well->hw_enabled = power_well->ops->is_enabled(dev_priv,
- power_well);
+ power_well->desc->ops->sync_hw(dev_priv, power_well);
+ power_well->hw_enabled =
+ power_well->desc->ops->is_enabled(dev_priv, power_well);
}
mutex_unlock(&power_domains->lock);
}
@@ -3360,7 +3552,7 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
* The AUX IO power wells will be enabled on demand.
*/
mutex_lock(&power_domains->lock);
- well = lookup_power_well(dev_priv, ICL_DISP_PW_1);
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
intel_power_well_enable(dev_priv, well);
mutex_unlock(&power_domains->lock);
@@ -3373,9 +3565,8 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv,
/* 7. Setup MBUS. */
icl_mbus_init(dev_priv);
- /* 8. CHICKEN_DCPR_1 */
- I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) |
- CNL_DDI_CLOCK_REG_ACCESS_ON);
+ if (resume && dev_priv->csr.dmc_payload)
+ intel_csr_load_program(dev_priv);
}
static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
@@ -3401,7 +3592,7 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
* disabled at this point.
*/
mutex_lock(&power_domains->lock);
- well = lookup_power_well(dev_priv, ICL_DISP_PW_1);
+ well = lookup_power_well(dev_priv, SKL_DISP_PW_1);
intel_power_well_disable(dev_priv, well);
mutex_unlock(&power_domains->lock);
@@ -3416,9 +3607,9 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv)
static void chv_phy_control_init(struct drm_i915_private *dev_priv)
{
struct i915_power_well *cmn_bc =
- lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
+ lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC);
struct i915_power_well *cmn_d =
- lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D);
+ lookup_power_well(dev_priv, CHV_DISP_PW_DPIO_CMN_D);
/*
* DISPLAY_PHY_CONTROL can get corrupted if read. As a
@@ -3441,7 +3632,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv)
* override and set the lane powerdown bits accding to the
* current lane status.
*/
- if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) {
+ if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) {
uint32_t status = I915_READ(DPLL(PIPE_A));
unsigned int mask;
@@ -3472,7 +3663,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv)
dev_priv->chv_phy_assert[DPIO_PHY0] = true;
}
- if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) {
+ if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) {
uint32_t status = I915_READ(DPIO_PHY_STATUS);
unsigned int mask;
@@ -3503,20 +3694,20 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv)
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);
+ lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC);
struct i915_power_well *disp2d =
- lookup_power_well(dev_priv, PUNIT_POWER_WELL_DISP2D);
+ lookup_power_well(dev_priv, VLV_DISP_PW_DISP2D);
/* If the display might be already active skip this */
- if (cmn->ops->is_enabled(dev_priv, cmn) &&
- disp2d->ops->is_enabled(dev_priv, disp2d) &&
+ if (cmn->desc->ops->is_enabled(dev_priv, cmn) &&
+ disp2d->desc->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);
+ disp2d->desc->ops->enable(dev_priv, disp2d);
/*
* From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx:
@@ -3525,9 +3716,11 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
* Simply ungating isn't enough to reset the PHY enough to get
* ports and lanes running.
*/
- cmn->ops->disable(dev_priv, cmn);
+ cmn->desc->ops->disable(dev_priv, cmn);
}
+static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
+
/**
* intel_power_domains_init_hw - initialize hardware power domain state
* @dev_priv: i915 device instance
@@ -3535,9 +3728,14 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
*
* This function initializes the hardware power domain state and enables all
* power wells belonging to the INIT power domain. Power wells in other
- * domains (and not in the INIT domain) are referenced or disabled during the
- * modeset state HW readout. After that the reference count of each power well
- * must match its HW enabled state, see intel_power_domains_verify_state().
+ * domains (and not in the INIT domain) are referenced or disabled by
+ * intel_modeset_readout_hw_state(). After that the reference count of each
+ * power well must match its HW enabled state, see
+ * intel_power_domains_verify_state().
+ *
+ * It will return with power domains disabled (to be enabled later by
+ * intel_power_domains_enable()) and must be paired with
+ * intel_power_domains_fini_hw().
*/
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
{
@@ -3563,30 +3761,117 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
mutex_unlock(&power_domains->lock);
}
- /* For now, we need the power well to be always enabled. */
- intel_display_set_init_power(dev_priv, true);
+ /*
+ * Keep all power wells enabled for any dependent HW access during
+ * initialization and to make sure we keep BIOS enabled display HW
+ * resources powered until display HW readout is complete. We drop
+ * this reference in intel_power_domains_enable().
+ */
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
/* Disable power support if the user asked so. */
if (!i915_modparams.disable_power_well)
intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
intel_power_domains_sync_hw(dev_priv);
+
power_domains->initializing = false;
}
/**
+ * intel_power_domains_fini_hw - deinitialize hw power domain state
+ * @dev_priv: i915 device instance
+ *
+ * De-initializes the display power domain HW state. It also ensures that the
+ * device stays powered up so that the driver can be reloaded.
+ *
+ * It must be called with power domains already disabled (after a call to
+ * intel_power_domains_disable()) and must be paired with
+ * intel_power_domains_init_hw().
+ */
+void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv)
+{
+ /* Keep the power well enabled, but cancel its rpm wakeref. */
+ intel_runtime_pm_put(dev_priv);
+
+ /* Remove the refcount we took to keep power well support disabled. */
+ if (!i915_modparams.disable_power_well)
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ intel_power_domains_verify_state(dev_priv);
+}
+
+/**
+ * intel_power_domains_enable - enable toggling of display power wells
+ * @dev_priv: i915 device instance
+ *
+ * Enable the ondemand enabling/disabling of the display power wells. Note that
+ * power wells not belonging to POWER_DOMAIN_INIT are allowed to be toggled
+ * only at specific points of the display modeset sequence, thus they are not
+ * affected by the intel_power_domains_enable()/disable() calls. The purpose
+ * of these function is to keep the rest of power wells enabled until the end
+ * of display HW readout (which will acquire the power references reflecting
+ * the current HW state).
+ */
+void intel_power_domains_enable(struct drm_i915_private *dev_priv)
+{
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ intel_power_domains_verify_state(dev_priv);
+}
+
+/**
+ * intel_power_domains_disable - disable toggling of display power wells
+ * @dev_priv: i915 device instance
+ *
+ * Disable the ondemand enabling/disabling of the display power wells. See
+ * intel_power_domains_enable() for which power wells this call controls.
+ */
+void intel_power_domains_disable(struct drm_i915_private *dev_priv)
+{
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+
+ intel_power_domains_verify_state(dev_priv);
+}
+
+/**
* intel_power_domains_suspend - suspend power domain state
* @dev_priv: i915 device instance
+ * @suspend_mode: specifies the target suspend state (idle, mem, hibernation)
*
* This function prepares the hardware power domain state before entering
- * system suspend. It must be paired with intel_power_domains_init_hw().
+ * system suspend.
+ *
+ * It must be called with power domains already disabled (after a call to
+ * intel_power_domains_disable()) and paired with intel_power_domains_resume().
*/
-void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
+void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
+ enum i915_drm_suspend_mode suspend_mode)
{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+ /*
+ * In case of suspend-to-idle (aka S0ix) on a DMC platform without DC9
+ * support don't manually deinit the power domains. This also means the
+ * CSR/DMC firmware will stay active, it will power down any HW
+ * resources as required and also enable deeper system power states
+ * that would be blocked if the firmware was inactive.
+ */
+ if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC9) &&
+ suspend_mode == I915_DRM_SUSPEND_IDLE &&
+ dev_priv->csr.dmc_payload != NULL) {
+ intel_power_domains_verify_state(dev_priv);
+ return;
+ }
+
/*
* Even if power well support was disabled we still want to disable
- * power wells while we are system suspended.
+ * power wells if power domains must be deinitialized for suspend.
*/
- if (!i915_modparams.disable_power_well)
+ if (!i915_modparams.disable_power_well) {
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+ intel_power_domains_verify_state(dev_priv);
+ }
if (IS_ICELAKE(dev_priv))
icl_display_core_uninit(dev_priv);
@@ -3596,8 +3881,36 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
skl_display_core_uninit(dev_priv);
else if (IS_GEN9_LP(dev_priv))
bxt_display_core_uninit(dev_priv);
+
+ power_domains->display_core_suspended = true;
}
+/**
+ * intel_power_domains_resume - resume power domain state
+ * @dev_priv: i915 device instance
+ *
+ * This function resume the hardware power domain state during system resume.
+ *
+ * It will return with power domain support disabled (to be enabled later by
+ * intel_power_domains_enable()) and must be paired with
+ * intel_power_domains_suspend().
+ */
+void intel_power_domains_resume(struct drm_i915_private *dev_priv)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+
+ if (power_domains->display_core_suspended) {
+ intel_power_domains_init_hw(dev_priv, true);
+ power_domains->display_core_suspended = false;
+ } else {
+ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+ }
+
+ intel_power_domains_verify_state(dev_priv);
+}
+
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)
+
static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
@@ -3607,9 +3920,9 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
enum intel_display_power_domain domain;
DRM_DEBUG_DRIVER("%-25s %d\n",
- power_well->name, power_well->count);
+ power_well->desc->name, power_well->count);
- for_each_power_domain(domain, power_well->domains)
+ for_each_power_domain(domain, power_well->desc->domains)
DRM_DEBUG_DRIVER(" %-23s %d\n",
intel_display_power_domain_str(domain),
power_domains->domain_use_count[domain]);
@@ -3626,7 +3939,7 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv)
* acquiring reference counts for any power wells in use and disabling the
* ones left on by BIOS but not required by any active output.
*/
-void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
+static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
struct i915_power_well *power_well;
@@ -3645,22 +3958,25 @@ void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
* and PW1 power wells) are under FW control, so ignore them,
* since their state can change asynchronously.
*/
- if (!power_well->domains)
+ if (!power_well->desc->domains)
continue;
- enabled = power_well->ops->is_enabled(dev_priv, power_well);
- if ((power_well->count || power_well->always_on) != enabled)
+ enabled = power_well->desc->ops->is_enabled(dev_priv,
+ power_well);
+ if ((power_well->count || power_well->desc->always_on) !=
+ enabled)
DRM_ERROR("power well %s state mismatch (refcount %d/enabled %d)",
- power_well->name, power_well->count, enabled);
+ power_well->desc->name,
+ power_well->count, enabled);
domains_count = 0;
- for_each_power_domain(domain, power_well->domains)
+ for_each_power_domain(domain, power_well->desc->domains)
domains_count += power_domains->domain_use_count[domain];
if (power_well->count != domains_count) {
DRM_ERROR("power well %s refcount/domain refcount mismatch "
"(refcount %d/domains refcount %d)\n",
- power_well->name, power_well->count,
+ power_well->desc->name, power_well->count,
domains_count);
dump_domain_info = true;
}
@@ -3678,6 +3994,14 @@ void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
mutex_unlock(&power_domains->lock);
}
+#else
+
+static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv)
+{
+}
+
+#endif
+
/**
* intel_runtime_pm_get - grab a runtime pm reference
* @dev_priv: i915 device instance
@@ -3791,14 +4115,24 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
* 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().
+ * subordinate display power domains. That is done by
+ * intel_power_domains_enable().
*/
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
struct device *kdev = &pdev->dev;
+ /*
+ * Disable the system suspend direct complete optimization, which can
+ * leave the device suspended skipping the driver's suspend handlers
+ * if the device was already runtime suspended. This is needed due to
+ * the difference in our runtime and system suspend sequence and
+ * becaue the HDA driver may require us to enable the audio power
+ * domain during system suspend.
+ */
+ dev_pm_set_driver_flags(kdev, DPM_FLAG_NEVER_SKIP);
+
pm_runtime_set_autosuspend_delay(kdev, 10000); /* 10s */
pm_runtime_mark_last_busy(kdev);
@@ -3825,3 +4159,18 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
*/
pm_runtime_put_autosuspend(kdev);
}
+
+void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ struct device *kdev = &pdev->dev;
+
+ /* Transfer rpm ownership back to core */
+ WARN(pm_runtime_get_sync(&dev_priv->drm.pdev->dev) < 0,
+ "Failed to pass rpm ownership back to core\n");
+
+ pm_runtime_dont_use_autosuspend(kdev);
+
+ if (!HAS_RUNTIME_PM(dev_priv))
+ pm_runtime_put(kdev);
+}