Skip to content

Commit

Permalink
UPSTREAM: drm/i915/gen9: Turn DC handling into a power well
Browse files Browse the repository at this point in the history
Handle DC off as a power well where enabling the power well will prevent
the DMC to enter selected DC states (required around modesets and Aux
A). Disabling the power well will allow DC states again. For now the
highest DC state is DC6 for Skylake and DC5 for Broxton but will be
configurable for Skylake in a later patch.

v2: Check both DC5 and DC6 bits in power well enabled function (Ville)
v3:
- Remove unneeded DC_OFF case in skl_set_power_well() (Imre)
- Add PW2 dependency to DC_OFF (Imre)
v4: Put DC_OFF before PW2 in BXT power well array

Signed-off-by: Patrik Jakobsson <patrik.jakobsson@linux.intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
[fixed line over 80 and parenthesis alignment checkpatch warns (imre)]
Link: http://patchwork.freedesktop.org/patch/msgid/1447687201-24759-1-git-send-email-patrik.jakobsson@linux.intel.com
(cherry picked from commit 9f836f9
 git://anongit.freedesktop.org/drm-intel drm-intel-next-queued)
Signed-off-by: Joe Konno <joe.konno@intel.com>

BUG=chrome-os-partner:41884
TEST=Use powertop to verify PC8 and PC10 residencies with screen On/Off
TEST=Verify PSR status with a PSR enabled display

Change-Id: I40db917dcb738aead7757ffd86d0e2d12f1660ba
Reviewed-on: https://chromium-review.googlesource.com/315862
Commit-Ready: Marc Herbert <marc.herbert@intel.com>
Tested-by: Prathyushi Nangia <prathyushi.nangia@intel.com>
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
  • Loading branch information
Patrik Jakobsson authored and chrome-bot committed Jan 15, 2016
1 parent 43eedad commit 28cd654
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 35 deletions.
6 changes: 0 additions & 6 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1001,9 +1001,6 @@ static int i915_pm_resume(struct device *dev)

static int skl_suspend_complete(struct drm_i915_private *dev_priv)
{
if (dev_priv->csr.dmc_payload)
skl_enable_dc6(dev_priv);

return 0;
}

Expand Down Expand Up @@ -1048,9 +1045,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv)

static int skl_resume_prepare(struct drm_i915_private *dev_priv)
{
if (dev_priv->csr.dmc_payload)
skl_disable_dc6(dev_priv);

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ enum skl_disp_power_wells {

/* Not actual bit groups. Used as IDs for lookup_power_well() */
SKL_DISP_PW_ALWAYS_ON,
SKL_DISP_PW_DC_OFF,
};

#define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2))
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -13311,6 +13311,9 @@ static int intel_atomic_commit(struct drm_device *dev,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
bool modeset = needs_modeset(crtc->state);

if (modeset)
intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);

if (modeset && crtc->state->active) {
update_scanline_offset(to_intel_crtc(crtc));
dev_priv->display.crtc_enable(crtc);
Expand All @@ -13321,6 +13324,9 @@ static int intel_atomic_commit(struct drm_device *dev,

drm_atomic_helper_commit_planes_on_crtc(crtc_state);
intel_post_plane_update(intel_crtc);

if (modeset)
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
}

/* FIXME: add subpixel order */
Expand Down
112 changes: 83 additions & 29 deletions drivers/gpu/drm/i915/intel_runtime_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@
* present for a given platform.
*/

#define GEN9_ENABLE_DC5(dev) 0
#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev)

#define for_each_power_well(i, power_well, domain_mask, power_domains) \
for (i = 0; \
i < (power_domains)->power_well_count && \
Expand Down Expand Up @@ -307,9 +304,15 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
#define SKL_DISPLAY_DDI_D_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS ( \
SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
BIT(POWER_DOMAIN_MODESET) | \
BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_INIT))
#define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \
(POWER_DOMAIN_MASK & ~( \
SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \
SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) | \
BIT(POWER_DOMAIN_INIT))

#define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS ( \
Expand Down Expand Up @@ -337,6 +340,11 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_PLLS) | \
BIT(POWER_DOMAIN_INIT))
#define BXT_DISPLAY_DC_OFF_POWER_DOMAINS ( \
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
BIT(POWER_DOMAIN_MODESET) | \
BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_INIT))
#define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \
(POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS | \
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \
Expand Down Expand Up @@ -485,15 +493,6 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
}

static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
{
assert_can_disable_dc5(dev_priv);

DRM_DEBUG_KMS("Disabling DC5\n");

gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
}

static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
Expand Down Expand Up @@ -521,6 +520,14 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv)
"DC6 already programmed to be disabled.\n");
}

static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
{
assert_can_disable_dc5(dev_priv);
assert_can_disable_dc6(dev_priv);

gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
}

void skl_enable_dc6(struct drm_i915_private *dev_priv)
{
assert_can_enable_dc6(dev_priv);
Expand Down Expand Up @@ -588,17 +595,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
"Invalid for power well status to be enabled, unless done by the BIOS, \
when request is to disable!\n");
if (power_well->data == SKL_DISP_PW_2) {
if (GEN9_ENABLE_DC5(dev))
gen9_disable_dc5(dev_priv);
if (SKL_ENABLE_DC6(dev)) {
/*
* DDI buffer programming unnecessary during driver-load/resume
* as it's already done during modeset initialization then.
* It's also invalid here as encoder list is still uninitialized.
*/
if (!dev_priv->power_domains.initializing)
intel_prepare_ddi(dev);
}
/*
* DDI buffer programming unnecessary during
* driver-load/resume as it's already done
* during modeset initialization then. It's
* also invalid here as encoder list is still
* uninitialized.
*/
if (!dev_priv->power_domains.initializing)
intel_prepare_ddi(dev);
}
I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
}
Expand All @@ -616,10 +621,6 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
POSTING_READ(HSW_PWR_WELL_DRIVER);
DRM_DEBUG_KMS("Disabling %s\n", power_well->name);

if (GEN9_ENABLE_DC5(dev) &&
power_well->data == SKL_DISP_PW_2)
gen9_enable_dc5(dev_priv);
}
}

Expand Down Expand Up @@ -694,6 +695,40 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv,
skl_set_power_well(dev_priv, power_well, false);
}

static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0;
}

static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
gen9_disable_dc5_dc6(dev_priv);
}

static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
if (IS_SKYLAKE(dev_priv))
skl_enable_dc6(dev_priv);
else
gen9_enable_dc5(dev_priv);
}

static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
if (power_well->count > 0) {
gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
} else {
if (IS_SKYLAKE(dev_priv))
gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
else
gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
}
}

static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
Expand Down Expand Up @@ -1516,6 +1551,13 @@ static const struct i915_power_well_ops skl_power_well_ops = {
.is_enabled = skl_power_well_enabled,
};

static const struct i915_power_well_ops gen9_dc_off_power_well_ops = {
.sync_hw = gen9_dc_off_power_well_sync_hw,
.enable = gen9_dc_off_power_well_enable,
.disable = gen9_dc_off_power_well_disable,
.is_enabled = gen9_dc_off_power_well_enabled,
};

static struct i915_power_well hsw_power_wells[] = {
{
.name = "always-on",
Expand Down Expand Up @@ -1689,6 +1731,12 @@ static struct i915_power_well skl_power_wells[] = {
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_MISC_IO,
},
{
.name = "DC off",
.domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
.data = SKL_DISP_PW_DC_OFF,
},
{
.name = "power well 2",
.domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS,
Expand Down Expand Up @@ -1763,12 +1811,18 @@ static struct i915_power_well bxt_power_wells[] = {
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_1,
},
{
.name = "DC off",
.domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS,
.ops = &gen9_dc_off_power_well_ops,
.data = SKL_DISP_PW_DC_OFF,
},
{
.name = "power well 2",
.domains = BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS,
.ops = &skl_power_well_ops,
.data = SKL_DISP_PW_2,
}
},
};

static int
Expand Down

0 comments on commit 28cd654

Please sign in to comment.