aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2017-06-01 10:36:16 -0400
committerVille Syrjälä <ville.syrjala@linux.intel.com>2017-06-15 08:35:38 -0400
commit2ee0da163196baf9baa05b7464594342788213f2 (patch)
tree18541a15b485714a9be6d31f0bb3b5eb5b249b41
parentbb408dd2b2b040f7e483c21ed69353e80d890329 (diff)
drm/i915: Add i830 "pipes power well"
830 more or less requires both pipes and DPLLs to remain on as long as either pipe is needed. However, when neither pipe is actually needed, we can save a bit of power by turning everything off. To do that we add a new "power well" that turns both pipes and DPLLs on and off in the right order. Seems to save ~50mW on my Fujitsu-Siemens Lifebook S6010. This also avoids having to abuse the load detection to force pipe A on at init time. That was never very robust, and it only worked for one pipe, whereas 830 really needs both pipes enabled. As a bonus the 830 pipe quirk is now a bit more isolated from the rest of the mode setting infrastructure, which should mean that it's much less likely someone will accidentally break it in the future. The extra cost is of course slight code duplication, but that seems like a worthwile tradeoff here. v2; s/BIT/BIT_ULL/ Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20170601143619.27840-5-ville.syrjala@linux.intel.com Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/intel_display.c92
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c64
3 files changed, 157 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 731800542159..379679eb4366 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5836,6 +5836,10 @@ static void i9xx_crtc_disable(struct intel_crtc_state *old_crtc_state,
5836 5836
5837 if (!dev_priv->display.initial_watermarks) 5837 if (!dev_priv->display.initial_watermarks)
5838 intel_update_watermarks(intel_crtc); 5838 intel_update_watermarks(intel_crtc);
5839
5840 /* clock the pipe down to 640x480@60 to potentially save power */
5841 if (IS_I830(dev_priv))
5842 i830_enable_pipe(dev_priv, pipe);
5839} 5843}
5840 5844
5841static void intel_crtc_disable_noatomic(struct drm_crtc *crtc, 5845static void intel_crtc_disable_noatomic(struct drm_crtc *crtc,
@@ -15145,6 +15149,91 @@ int intel_modeset_init(struct drm_device *dev)
15145 return 0; 15149 return 0;
15146} 15150}
15147 15151
15152void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
15153{
15154 /* 640x480@60Hz, ~25175 kHz */
15155 struct dpll clock = {
15156 .m1 = 18,
15157 .m2 = 7,
15158 .p1 = 13,
15159 .p2 = 4,
15160 .n = 2,
15161 };
15162 u32 dpll, fp;
15163 int i;
15164
15165 WARN_ON(i9xx_calc_dpll_params(48000, &clock) != 25154);
15166
15167 DRM_DEBUG_KMS("enabling pipe %c due to force quirk (vco=%d dot=%d)\n",
15168 pipe_name(pipe), clock.vco, clock.dot);
15169
15170 fp = i9xx_dpll_compute_fp(&clock);
15171 dpll = (I915_READ(DPLL(pipe)) & DPLL_DVO_2X_MODE) |
15172 DPLL_VGA_MODE_DIS |
15173 ((clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT) |
15174 PLL_P2_DIVIDE_BY_4 |
15175 PLL_REF_INPUT_DREFCLK |
15176 DPLL_VCO_ENABLE;
15177
15178 I915_WRITE(FP0(pipe), fp);
15179 I915_WRITE(FP1(pipe), fp);
15180
15181 I915_WRITE(HTOTAL(pipe), (640 - 1) | ((800 - 1) << 16));
15182 I915_WRITE(HBLANK(pipe), (640 - 1) | ((800 - 1) << 16));
15183 I915_WRITE(HSYNC(pipe), (656 - 1) | ((752 - 1) << 16));
15184 I915_WRITE(VTOTAL(pipe), (480 - 1) | ((525 - 1) << 16));
15185 I915_WRITE(VBLANK(pipe), (480 - 1) | ((525 - 1) << 16));
15186 I915_WRITE(VSYNC(pipe), (490 - 1) | ((492 - 1) << 16));
15187 I915_WRITE(PIPESRC(pipe), ((640 - 1) << 16) | (480 - 1));
15188
15189 /*
15190 * Apparently we need to have VGA mode enabled prior to changing
15191 * the P1/P2 dividers. Otherwise the DPLL will keep using the old
15192 * dividers, even though the register value does change.
15193 */
15194 I915_WRITE(DPLL(pipe), dpll & ~DPLL_VGA_MODE_DIS);
15195 I915_WRITE(DPLL(pipe), dpll);
15196
15197 /* Wait for the clocks to stabilize. */
15198 POSTING_READ(DPLL(pipe));
15199 udelay(150);
15200
15201 /* The pixel multiplier can only be updated once the
15202 * DPLL is enabled and the clocks are stable.
15203 *
15204 * So write it again.
15205 */
15206 I915_WRITE(DPLL(pipe), dpll);
15207
15208 /* We do this three times for luck */
15209 for (i = 0; i < 3 ; i++) {
15210 I915_WRITE(DPLL(pipe), dpll);
15211 POSTING_READ(DPLL(pipe));
15212 udelay(150); /* wait for warmup */
15213 }
15214
15215 I915_WRITE(PIPECONF(pipe), PIPECONF_ENABLE | PIPECONF_PROGRESSIVE);
15216 POSTING_READ(PIPECONF(pipe));
15217}
15218
15219void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe)
15220{
15221 DRM_DEBUG_KMS("disabling pipe %c due to force quirk\n",
15222 pipe_name(pipe));
15223
15224 assert_plane_disabled(dev_priv, PLANE_A);
15225 assert_plane_disabled(dev_priv, PLANE_B);
15226
15227 I915_WRITE(PIPECONF(pipe), 0);
15228 POSTING_READ(PIPECONF(pipe));
15229
15230 if (wait_for(pipe_dsl_stopped(dev_priv, pipe), 100))
15231 DRM_ERROR("pipe %c off wait timed out\n", pipe_name(pipe));
15232
15233 I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS);
15234 POSTING_READ(DPLL(pipe));
15235}
15236
15148static void intel_enable_pipe_a(struct drm_device *dev, 15237static void intel_enable_pipe_a(struct drm_device *dev,
15149 struct drm_modeset_acquire_ctx *ctx) 15238 struct drm_modeset_acquire_ctx *ctx)
15150{ 15239{
@@ -15274,7 +15363,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc,
15274 crtc->plane = plane; 15363 crtc->plane = plane;
15275 } 15364 }
15276 15365
15277 if (dev_priv->quirks & QUIRK_PIPEA_FORCE && 15366 if (!IS_I830(dev_priv) &&
15367 dev_priv->quirks & QUIRK_PIPEA_FORCE &&
15278 crtc->pipe == PIPE_A && !crtc->active) { 15368 crtc->pipe == PIPE_A && !crtc->active) {
15279 /* BIOS forgot to enable pipe A, this mostly happens after 15369 /* BIOS forgot to enable pipe A, this mostly happens after
15280 * resume. Force-enable the pipe to fix this, the update_dpms 15370 * resume. Force-enable the pipe to fix this, the update_dpms
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2bc3326f4068..4d3982bb596a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1332,6 +1332,8 @@ void intel_set_cdclk(struct drm_i915_private *dev_priv,
1332 const struct intel_cdclk_state *cdclk_state); 1332 const struct intel_cdclk_state *cdclk_state);
1333 1333
1334/* intel_display.c */ 1334/* intel_display.c */
1335void i830_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
1336void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe);
1335enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc); 1337enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc);
1336void intel_update_rawclk(struct drm_i915_private *dev_priv); 1338void intel_update_rawclk(struct drm_i915_private *dev_priv);
1337int vlv_get_hpll_vco(struct drm_i915_private *dev_priv); 1339int vlv_get_hpll_vco(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 436ec7a7b843..efe80ed5fd4d 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -1041,6 +1041,38 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
1041 return true; 1041 return true;
1042} 1042}
1043 1043
1044static void i830_pipes_power_well_enable(struct drm_i915_private *dev_priv,
1045 struct i915_power_well *power_well)
1046{
1047 if ((I915_READ(PIPECONF(PIPE_A)) & PIPECONF_ENABLE) == 0)
1048 i830_enable_pipe(dev_priv, PIPE_A);
1049 if ((I915_READ(PIPECONF(PIPE_B)) & PIPECONF_ENABLE) == 0)
1050 i830_enable_pipe(dev_priv, PIPE_B);
1051}
1052
1053static void i830_pipes_power_well_disable(struct drm_i915_private *dev_priv,
1054 struct i915_power_well *power_well)
1055{
1056 i830_disable_pipe(dev_priv, PIPE_B);
1057 i830_disable_pipe(dev_priv, PIPE_A);
1058}
1059
1060static bool i830_pipes_power_well_enabled(struct drm_i915_private *dev_priv,
1061 struct i915_power_well *power_well)
1062{
1063 return I915_READ(PIPECONF(PIPE_A)) & PIPECONF_ENABLE &&
1064 I915_READ(PIPECONF(PIPE_B)) & PIPECONF_ENABLE;
1065}
1066
1067static void i830_pipes_power_well_sync_hw(struct drm_i915_private *dev_priv,
1068 struct i915_power_well *power_well)
1069{
1070 if (power_well->count > 0)
1071 i830_pipes_power_well_enable(dev_priv, power_well);
1072 else
1073 i830_pipes_power_well_disable(dev_priv, power_well);
1074}
1075
1044static void vlv_set_power_well(struct drm_i915_private *dev_priv, 1076static void vlv_set_power_well(struct drm_i915_private *dev_priv,
1045 struct i915_power_well *power_well, bool enable) 1077 struct i915_power_well *power_well, bool enable)
1046{ 1078{
@@ -1929,6 +1961,15 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
1929 BIT_ULL(POWER_DOMAIN_AUX_D) | \ 1961 BIT_ULL(POWER_DOMAIN_AUX_D) | \
1930 BIT_ULL(POWER_DOMAIN_INIT)) 1962 BIT_ULL(POWER_DOMAIN_INIT))
1931 1963
1964#define I830_PIPES_POWER_DOMAINS ( \
1965 BIT_ULL(POWER_DOMAIN_PIPE_A) | \
1966 BIT_ULL(POWER_DOMAIN_PIPE_B) | \
1967 BIT_ULL(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
1968 BIT_ULL(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \
1969 BIT_ULL(POWER_DOMAIN_TRANSCODER_A) | \
1970 BIT_ULL(POWER_DOMAIN_TRANSCODER_B) | \
1971 BIT_ULL(POWER_DOMAIN_INIT))
1972
1932static const struct i915_power_well_ops i9xx_always_on_power_well_ops = { 1973static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
1933 .sync_hw = i9xx_power_well_sync_hw_noop, 1974 .sync_hw = i9xx_power_well_sync_hw_noop,
1934 .enable = i9xx_always_on_power_well_noop, 1975 .enable = i9xx_always_on_power_well_noop,
@@ -1959,6 +2000,27 @@ static struct i915_power_well i9xx_always_on_power_well[] = {
1959 }, 2000 },
1960}; 2001};
1961 2002
2003static const struct i915_power_well_ops i830_pipes_power_well_ops = {
2004 .sync_hw = i830_pipes_power_well_sync_hw,
2005 .enable = i830_pipes_power_well_enable,
2006 .disable = i830_pipes_power_well_disable,
2007 .is_enabled = i830_pipes_power_well_enabled,
2008};
2009
2010static struct i915_power_well i830_power_wells[] = {
2011 {
2012 .name = "always-on",
2013 .always_on = 1,
2014 .domains = POWER_DOMAIN_MASK,
2015 .ops = &i9xx_always_on_power_well_ops,
2016 },
2017 {
2018 .name = "pipes",
2019 .domains = I830_PIPES_POWER_DOMAINS,
2020 .ops = &i830_pipes_power_well_ops,
2021 },
2022};
2023
1962static const struct i915_power_well_ops hsw_power_well_ops = { 2024static const struct i915_power_well_ops hsw_power_well_ops = {
1963 .sync_hw = hsw_power_well_sync_hw, 2025 .sync_hw = hsw_power_well_sync_hw,
1964 .enable = hsw_power_well_enable, 2026 .enable = hsw_power_well_enable,
@@ -2504,6 +2566,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
2504 set_power_wells(power_domains, chv_power_wells); 2566 set_power_wells(power_domains, chv_power_wells);
2505 } else if (IS_VALLEYVIEW(dev_priv)) { 2567 } else if (IS_VALLEYVIEW(dev_priv)) {
2506 set_power_wells(power_domains, vlv_power_wells); 2568 set_power_wells(power_domains, vlv_power_wells);
2569 } else if (IS_I830(dev_priv)) {
2570 set_power_wells(power_domains, i830_power_wells);
2507 } else { 2571 } else {
2508 set_power_wells(power_domains, i9xx_always_on_power_well); 2572 set_power_wells(power_domains, i9xx_always_on_power_well);
2509 } 2573 }