From 770effb19fbdcb44c6bdacf4a78571d28393f48f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:45:51 +0300 Subject: drm/i915: Add locking around chv_phy_control_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_priv->chv_phy_control is protected by the power_domains->lock elsewhere, so also grab it when initializing chv_phy_control. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 821644d1b544..974c4cbf3fdb 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1685,7 +1685,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) power_domains->initializing = true; if (IS_CHERRYVIEW(dev)) { + mutex_lock(&power_domains->lock); chv_phy_control_init(dev_priv); + mutex_unlock(&power_domains->lock); } else if (IS_VALLEYVIEW(dev)) { mutex_lock(&power_domains->lock); vlv_cmnlane_wa(dev_priv); -- cgit v1.2.3 From 5a8fbb7d192b96de3d258164e5fc95b769d698c3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 15:25:53 +0300 Subject: drm/i915: Move DPLL ref/cri/VGA mode frobbing to the disp2d well enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bunch of stuff needs the DPLL ref/cri clocks on both VLV and CHV, and having VGA mode enabled causes some problems for CHV. So let's just pull the code to configure those bits into the disp2d well enable hook. With the DPLL disable code also fixed to leave those bits alone we should now have a consistent DPLL state all the time even if the DPLL is disabled. This also neatly removes some duplicated code between the VLV and CHV codepaths. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 45 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 974c4cbf3fdb..0588baaed14a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -853,6 +853,25 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, static void vlv_display_power_well_init(struct drm_i915_private *dev_priv) { + enum pipe pipe; + + /* + * Enable the CRI clock source so we can get at the + * display and the reference clock for VGA + * hotplug / manual detection. Supposedly DSI also + * needs the ref clock up and running. + * + * CHV DPLL B/C have some issues if VGA mode is enabled. + */ + for_each_pipe(dev_priv->dev, pipe) { + u32 val = I915_READ(DPLL(pipe)); + + val |= DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + if (pipe != PIPE_A) + val |= DPLL_INTEGRATED_CRI_CLK_VLV; + + I915_WRITE(DPLL(pipe), val); + } spin_lock_irq(&dev_priv->irq_lock); valleyview_enable_display_irqs(dev_priv); @@ -904,13 +923,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, { 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_VGA_MODE_DIS | - DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); @@ -953,22 +966,12 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, 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) { + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) phy = DPIO_PHY0; - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REF_CLK_ENABLE_VLV); - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); - } else { + else phy = DPIO_PHY1; - I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS | - DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); - } + + /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); -- cgit v1.2.3 From e0fce78f041014846d77940d3a350a4cffe4ab2b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:45:54 +0300 Subject: drm/i915: Implement PHY lane power gating for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Powergate the PHY lanes when they're not needed. For HDMI all four lanes are needed always, but for DP we can enable only the needed lanes. To power down the unused lanes we use some power down override bits in the DISPLAY_PHY_CONTROL register. Without the overrides it appears that the hardware always powers on all the lanes. When the port is disabled the power down override is not needed and the lanes will shut off on their own. That also means the override is critical to actually be able to access the DPIO registers before the port is actually enabled. Additionally the common lanes will power down when not needed. CL1 remains on as long as anything else is on, CL2 will shut down when all the lanes in the same channel will shut down. There is one exception for CL2 that will be dealt in a separate patch for clarity. With potentially some lanes powered down, the DP code now has to check the number of active lanes before accessing PCS/TX registers. All registers in powered down blocks will reads as 0xffffffff, and soe we would drown in warnings from vlv_dpio_read() if we allowed the code to access all those registers. Another important detail in the DP code is the "TX latency optimal" setting. Normally the second TX lane acts as some kind of reset master, with the other lanes as slaves. But when only a single lane is enabled, that single lane obviously has to be the master. A bit of extra care is needed to reconstruct the initial state of the DISPLAY_PHY_CONTROL register since it can't be read safely. So instead read the actual lane status from the DPLL/PHY_STATUS registers and use that to determine which lanes ought to be powergated initially. We also need to switch the PHY power modes to "deep PSR" to avoid a hard system hang when powering down the single channel PHY. Also sprinkle a few debug prints around so that we can monitor the DISPLAY_PHY_STATUS changes without having to read it and risk corrupting it. v2: Add locking to chv_powergate_phy_lanes() v3: Actually enable dynamic powerdown in the PHY and deal with the fallout Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 ++ drivers/gpu/drm/i915/intel_dp.c | 141 +++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 4 + drivers/gpu/drm/i915/intel_hdmi.c | 4 + drivers/gpu/drm/i915/intel_runtime_pm.c | 123 ++++++++++++++++++++++++++-- 5 files changed, 221 insertions(+), 59 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 211b73ab7780..6918ffab168e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1135,9 +1135,15 @@ enum skl_disp_power_wells { #define _CHV_CMN_DW19_CH0 0x814c #define _CHV_CMN_DW6_CH1 0x8098 +#define DPIO_DYNPWRDOWNEN_CH1 (1 << 28) /* CL2 DW6 only */ #define CHV_CMN_USEDCLKCHANNEL (1 << 13) + #define CHV_CMN_DW19(ch) _PIPE(ch, _CHV_CMN_DW19_CH0, _CHV_CMN_DW6_CH1) +#define CHV_CMN_DW28 0x8170 +#define DPIO_CL1POWERDOWNEN (1 << 23) +#define DPIO_DYNPWRDOWNEN_CH0 (1 << 22) + #define CHV_CMN_DW30 0x8178 #define DPIO_LRC_BYPASS (1 << 3) @@ -2192,10 +2198,12 @@ enum skl_disp_power_wells { #define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240) #define DPLL_PORTD_READY_MASK (0xf) #define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100) +#define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2*(phy)+(ch)+27)) #define PHY_LDO_DELAY_0NS 0x0 #define PHY_LDO_DELAY_200NS 0x1 #define PHY_LDO_DELAY_600NS 0x2 #define PHY_LDO_SEQ_DELAY(delay, phy) ((delay) << (2*(phy)+23)) +#define PHY_CH_POWER_DOWN_OVRD(mask, phy, ch) ((mask) << (8*(phy)+4*(ch)+11)) #define PHY_CH_SU_PSR 0x1 #define PHY_CH_DEEP_PSR 0x7 #define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1ff063e31584..c0eaf130ed9b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -133,6 +133,11 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp); static void vlv_steal_power_sequencer(struct drm_device *dev, enum pipe pipe); +static unsigned int intel_dp_unused_lane_mask(int lane_count) +{ + return ~((1 << lane_count) - 1) & 0xf; +} + static int intel_dp_max_link_bw(struct intel_dp *intel_dp) { @@ -2432,17 +2437,21 @@ static void chv_post_disable_dp(struct intel_encoder *encoder) val |= CHV_PCS_REQ_SOFTRESET_EN; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); - val |= CHV_PCS_REQ_SOFTRESET_EN; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); + val |= CHV_PCS_REQ_SOFTRESET_EN; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + } val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); - val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); + val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + } mutex_unlock(&dev_priv->sb_lock); } @@ -2562,7 +2571,6 @@ static void intel_enable_dp(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); uint32_t dp_reg = I915_READ(intel_dp->output_reg); - unsigned int lane_mask = 0x0; if (WARN_ON(dp_reg & DP_PORT_EN)) return; @@ -2580,9 +2588,15 @@ static void intel_enable_dp(struct intel_encoder *encoder) pps_unlock(intel_dp); - if (IS_VALLEYVIEW(dev)) + if (IS_VALLEYVIEW(dev)) { + unsigned int lane_mask = 0x0; + + if (IS_CHERRYVIEW(dev)) + lane_mask = intel_dp_unused_lane_mask(crtc->config->lane_count); + vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp), lane_mask); + } intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); @@ -2809,31 +2823,40 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) val &= ~DPIO_LANEDESKEW_STRAP_OVRD; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); - val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val &= ~DPIO_LANEDESKEW_STRAP_OVRD; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + } /* Deassert soft data lane reset*/ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); - val |= CHV_PCS_REQ_SOFTRESET_EN; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); + val |= CHV_PCS_REQ_SOFTRESET_EN; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + } val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); - val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); + val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + } /* Program Tx lane latency optimal setting*/ - for (i = 0; i < 4; i++) { + for (i = 0; i < intel_crtc->config->lane_count; i++) { /* Set the upar bit */ - data = (i == 1) ? 0x0 : 0x1; + if (intel_crtc->config->lane_count == 1) + data = 0x0; + else + data = (i == 1) ? 0x0 : 0x1; vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), data << DPIO_UPAR_SHIFT); } @@ -2854,9 +2877,11 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) val |= DPIO_TX2_STAGGER_MASK(0x1f); vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); - val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val |= DPIO_TX2_STAGGER_MASK(0x1f); + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + } vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | @@ -2865,12 +2890,14 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) DPIO_TX1_STAGGER_MULT(6) | DPIO_TX2_STAGGER_MULT(0)); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), - DPIO_LANESTAGGER_STRAP(stagger) | - DPIO_LANESTAGGER_STRAP_OVRD | - DPIO_TX1_STAGGER_MASK(0x1f) | - DPIO_TX1_STAGGER_MULT(7) | - DPIO_TX2_STAGGER_MULT(5)); + if (intel_crtc->config->lane_count > 2) { + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), + DPIO_LANESTAGGER_STRAP(stagger) | + DPIO_LANESTAGGER_STRAP_OVRD | + DPIO_TX1_STAGGER_MASK(0x1f) | + DPIO_TX1_STAGGER_MULT(7) | + DPIO_TX2_STAGGER_MULT(5)); + } mutex_unlock(&dev_priv->sb_lock); @@ -2886,10 +2913,14 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) to_intel_crtc(encoder->base.crtc); enum dpio_channel ch = vlv_dport_to_channel(dport); enum pipe pipe = intel_crtc->pipe; + unsigned int lane_mask = + intel_dp_unused_lane_mask(intel_crtc->config->lane_count); u32 val; intel_dp_prepare(encoder); + chv_phy_powergate_lanes(encoder, true, lane_mask); + mutex_lock(&dev_priv->sb_lock); /* program left/right clock distribution */ @@ -2920,13 +2951,15 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) val |= CHV_PCS_USEDCLKCHANNEL; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); - val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; - if (pipe != PIPE_B) - val &= ~CHV_PCS_USEDCLKCHANNEL; - else - val |= CHV_PCS_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); + val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; + if (pipe != PIPE_B) + val &= ~CHV_PCS_USEDCLKCHANNEL; + else + val |= CHV_PCS_USEDCLKCHANNEL; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); + } /* * This a a bit weird since generally CL @@ -2963,6 +2996,8 @@ static void chv_dp_post_pll_disable(struct intel_encoder *encoder) } mutex_unlock(&dev_priv->sb_lock); + + chv_phy_powergate_lanes(encoder, false, 0x0); } /* @@ -3298,24 +3333,28 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); - val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); - val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); - val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); + val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); + val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + } val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); - val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); - val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); + val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); + val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); + } /* Program swing deemph */ - for (i = 0; i < 4; i++) { + for (i = 0; i < intel_crtc->config->lane_count; i++) { val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); val &= ~DPIO_SWING_DEEMPH9P5_MASK; val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT; @@ -3323,7 +3362,7 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) } /* Program swing margin */ - for (i = 0; i < 4; i++) { + for (i = 0; i < intel_crtc->config->lane_count; i++) { val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); val &= ~DPIO_SWING_MARGIN000_MASK; @@ -3346,7 +3385,7 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) * For now, for this unique transition scale selection, set bit * 27 for ch0 and ch1. */ - for (i = 0; i < 4; i++) { + for (i = 0; i < intel_crtc->config->lane_count; i++) { val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); if (chv_need_uniq_trans_scale(train_set)) val |= DPIO_TX_UNIQ_TRANS_SCALE_EN; @@ -3360,9 +3399,11 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); - val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + if (intel_crtc->config->lane_count > 2) { + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + } /* LRC Bypass */ val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index aa7971798639..df420d892ffe 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1361,6 +1361,10 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv); void intel_display_set_init_power(struct drm_i915_private *dev, bool enable); +void chv_phy_powergate_lanes(struct intel_encoder *encoder, + bool override, unsigned int mask); + + /* 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_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 269937a7919a..f1ecc2cbbd48 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1628,6 +1628,8 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder) intel_hdmi_prepare(encoder); + chv_phy_powergate_lanes(encoder, true, 0x0); + mutex_lock(&dev_priv->sb_lock); /* program left/right clock distribution */ @@ -1701,6 +1703,8 @@ static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder) } mutex_unlock(&dev_priv->sb_lock); + + chv_phy_powergate_lanes(encoder, false, 0x0); } static void vlv_hdmi_post_disable(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 0588baaed14a..a1597712d27d 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -962,14 +962,19 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { enum dpio_phy phy; + enum pipe pipe; + uint32_t tmp; 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) + if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { + pipe = PIPE_A; phy = DPIO_PHY0; - else + } else { + pipe = PIPE_C; phy = DPIO_PHY1; + } /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -979,8 +984,26 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1)) DRM_ERROR("Display PHY %d is not power up\n", phy); + mutex_lock(&dev_priv->sb_lock); + + /* Enable dynamic power down */ + tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28); + tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp); + + if (power_well->data == PUNIT_POWER_WELL_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); + } + + mutex_unlock(&dev_priv->sb_lock); + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy); I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); + + DRM_DEBUG_KMS("Enabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", + phy, dev_priv->chv_phy_control); } static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, @@ -1004,6 +1027,35 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); vlv_set_power_well(dev_priv, power_well, false); + + DRM_DEBUG_KMS("Disabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", + phy, dev_priv->chv_phy_control); +} + +void chv_phy_powergate_lanes(struct intel_encoder *encoder, + bool override, unsigned int mask) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct i915_power_domains *power_domains = &dev_priv->power_domains; + enum dpio_phy phy = vlv_dport_to_phy(enc_to_dig_port(&encoder->base)); + enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base)); + + mutex_lock(&power_domains->lock); + + dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD(0xf, phy, ch); + dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD(mask, phy, ch); + + if (override) + dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD_EN(phy, ch); + else + dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD_EN(phy, ch); + + I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); + + DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d lanes 0x%x (PHY_CONTROL=0x%08x)\n", + phy, ch, mask, dev_priv->chv_phy_control); + + mutex_unlock(&power_domains->lock); } static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv, @@ -1630,19 +1682,72 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) * DISPLAY_PHY_CONTROL can get corrupted if read. As a * workaround never ever read DISPLAY_PHY_CONTROL, and * instead maintain a shadow copy ourselves. Use the actual - * power well state to reconstruct the expected initial - * value. + * power well state and lane status to reconstruct the + * expected initial value. */ dev_priv->chv_phy_control = PHY_LDO_SEQ_DELAY(PHY_LDO_DELAY_600NS, DPIO_PHY0) | PHY_LDO_SEQ_DELAY(PHY_LDO_DELAY_600NS, DPIO_PHY1) | - PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH0) | - PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH1) | - PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY1, DPIO_CH0); - if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) + PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY0, DPIO_CH0) | + PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY0, DPIO_CH1) | + PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY1, DPIO_CH0); + + /* + * If all lanes are disabled we leave the override disabled + * with all power down bits cleared to match the state we + * would use after disabling the port. Otherwise enable the + * override and set the lane powerdown bits accding to the + * current lane status. + */ + if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { + uint32_t status = I915_READ(DPLL(PIPE_A)); + unsigned int mask; + + mask = status & DPLL_PORTB_READY_MASK; + if (mask == 0xf) + mask = 0x0; + else + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0); + + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH0); + + mask = (status & DPLL_PORTC_READY_MASK) >> 4; + if (mask == 0xf) + mask = 0x0; + else + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1); + + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1); + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0); - if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) + } + + if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { + uint32_t status = I915_READ(DPIO_PHY_STATUS); + unsigned int mask; + + mask = status & DPLL_PORTD_READY_MASK; + + if (mask == 0xf) + mask = 0x0; + else + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0); + + dev_priv->chv_phy_control |= + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0); + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1); + } + + I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); + + DRM_DEBUG_KMS("Initial PHY_CONTROL=0x%08x\n", + dev_priv->chv_phy_control); } static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) -- cgit v1.2.3 From b0b3384612bd4ce608c5d95626149311bb43f121 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:45:55 +0300 Subject: drm/i915: Trick CL2 into life on CHV when using pipe B with port B MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normmally the common lane in a PHY channel gets powered up when some of the data lanes get powered up. But when we're driving port B with pipe B we don't want to enabled any of the data lanes, and just want the DPLL in the common lane to be active. To make that happens we have to temporarily enable some data lanes after which we can access the DPLL registers in the common lane. Once the pipe is up and running we can drop the power override on the data lanes allowing them to shut down. From this point forward the common lane will in fact stay powered on until the data lanes in the other channel get powered down. Ville's extended explanation from the review thread: On Wed, Aug 19, 2015 at 07:47:41AM +0530, Deepak wrote: > One Q, why only for port B? Port C is also in same common lane right? Port B is in the first PHY channel which also houses CL1. CL1 always powers up whenever any lanes in either PHY channel are powered up. CL2 only powers up if lanes in the second channel (ie. the one with port C) powers up. So in this scenario (pipe B->port B) we want the DPLL from CL2, but ideally we only want to power up the lanes for port B. Powering up port B lanes will only power up CL1, but as we need CL2 instead we need to, temporarily, power up some lanes in port C as well. Crossing the streams the other way (pipe A->port C) is not a problem since CL1 powers up whenever anything else powers up. So powering up some port C lanes is enough on its own to make the CL1 DPLL operational, even though CL1 and the lanes live in separate channels. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S [danvet: Amend commit message with extended explanation.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_hdmi.c | 23 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c0eaf130ed9b..b032eef8aeb8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2902,6 +2902,12 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->sb_lock); intel_enable_dp(encoder); + + /* Second common lane will stay alive on its own now */ + if (dport->release_cl2_override) { + chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false); + dport->release_cl2_override = false; + } } static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) @@ -2919,6 +2925,14 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder) intel_dp_prepare(encoder); + /* + * Must trick the second common lane into life. + * Otherwise we can't even access the PLL. + */ + if (ch == DPIO_CH0 && pipe == PIPE_B) + dport->release_cl2_override = + !chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true); + chv_phy_powergate_lanes(encoder, true, lane_mask); mutex_lock(&dev_priv->sb_lock); @@ -2997,6 +3011,15 @@ static void chv_dp_post_pll_disable(struct intel_encoder *encoder) mutex_unlock(&dev_priv->sb_lock); + /* + * Leave the power down bit cleared for at least one + * lane so that chv_powergate_phy_ch() will power + * on something when the channel is otherwise unused. + * When the port is off and the override is removed + * the lanes power down anyway, so otherwise it doesn't + * really matter what the state of power down bits is + * after this. + */ chv_phy_powergate_lanes(encoder, false, 0x0); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index df420d892ffe..72c1181bd7f5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -779,6 +779,7 @@ struct intel_digital_port { struct intel_dp dp; struct intel_hdmi hdmi; enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool); + bool release_cl2_override; }; struct intel_dp_mst_encoder { @@ -1363,6 +1364,8 @@ void intel_display_set_init_power(struct drm_i915_private *dev, bool enable); void chv_phy_powergate_lanes(struct intel_encoder *encoder, bool override, unsigned int mask); +bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, + enum dpio_channel ch, bool override); /* intel_pm.c */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f1ecc2cbbd48..7c56053d4240 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1628,6 +1628,14 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder) intel_hdmi_prepare(encoder); + /* + * Must trick the second common lane into life. + * Otherwise we can't even access the PLL. + */ + if (ch == DPIO_CH0 && pipe == PIPE_B) + dport->release_cl2_override = + !chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true); + chv_phy_powergate_lanes(encoder, true, 0x0); mutex_lock(&dev_priv->sb_lock); @@ -1704,6 +1712,15 @@ static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder) mutex_unlock(&dev_priv->sb_lock); + /* + * Leave the power down bit cleared for at least one + * lane so that chv_powergate_phy_ch() will power + * on something when the channel is otherwise unused. + * When the port is off and the override is removed + * the lanes power down anyway, so otherwise it doesn't + * really matter what the state of power down bits is + * after this. + */ chv_phy_powergate_lanes(encoder, false, 0x0); } @@ -1925,6 +1942,12 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) g4x_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport, 0x0); + + /* Second common lane will stay alive on its own now */ + if (dport->release_cl2_override) { + chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false); + dport->release_cl2_override = false; + } } static void intel_hdmi_destroy(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index a1597712d27d..4a43885e571d 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1032,6 +1032,35 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, phy, dev_priv->chv_phy_control); } +bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, + enum dpio_channel ch, bool override) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + bool was_override; + + mutex_lock(&power_domains->lock); + + was_override = dev_priv->chv_phy_control & PHY_CH_POWER_DOWN_OVRD_EN(phy, ch); + + if (override == was_override) + goto out; + + if (override) + dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD_EN(phy, ch); + else + dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD_EN(phy, ch); + + I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); + + DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d (DPIO_PHY_CONTROL=0x%08x)\n", + phy, ch, dev_priv->chv_phy_control); + +out: + mutex_unlock(&power_domains->lock); + + return was_override; +} + void chv_phy_powergate_lanes(struct intel_encoder *encoder, bool override, unsigned int mask) { -- cgit v1.2.3 From ee27921824e6ad0ca2d8e5abfa12cf4d853ded6c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:45:57 +0300 Subject: drm/i915: Enable DPIO SUS clock gating on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV has supports some form of automagic clock gating for the DPIO SUS clock. We can simply enable the magic bits and the hardware should take care of the rest. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6918ffab168e..6ed7141c9505 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1143,6 +1143,10 @@ enum skl_disp_power_wells { #define CHV_CMN_DW28 0x8170 #define DPIO_CL1POWERDOWNEN (1 << 23) #define DPIO_DYNPWRDOWNEN_CH0 (1 << 22) +#define DPIO_SUS_CLK_CONFIG_ON (0 << 0) +#define DPIO_SUS_CLK_CONFIG_CLKREQ (1 << 0) +#define DPIO_SUS_CLK_CONFIG_GATE (2 << 0) +#define DPIO_SUS_CLK_CONFIG_GATE_CLKREQ (3 << 0) #define CHV_CMN_DW30 0x8178 #define DPIO_LRC_BYPASS (1 << 3) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 4a43885e571d..ef043b2c06b2 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -988,7 +988,8 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, /* Enable dynamic power down */ tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28); - tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN; + tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN | + DPIO_SUS_CLK_CONFIG_GATE_CLKREQ; vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp); if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { -- cgit v1.2.3 From 3e28878635cc3bb3159445dc9cfbdc3d34eb8daf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:45:58 +0300 Subject: drm/i915: Force CL2 off in CHV x1 PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can choose to leave the display PHY CL2 powerdown up to some hardware signals, or we can force it. The BXT code forces the nonexistent CL2 in the x1 PHY to power down. Follow suit on CHV. Maybe it can still save some extra power by disabling some extra logic in CL1, or something. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_runtime_pm.c | 9 +++++++++ 2 files changed, 10 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6ed7141c9505..439bb27a63be 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1149,6 +1149,7 @@ enum skl_disp_power_wells { #define DPIO_SUS_CLK_CONFIG_GATE_CLKREQ (3 << 0) #define CHV_CMN_DW30 0x8178 +#define DPIO_CL2_LDOFUSE_PWRENB (1 << 6) #define DPIO_LRC_BYPASS (1 << 3) #define _TXLANE(ch, lane, offset) ((ch ? 0x2400 : 0) + \ diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index ef043b2c06b2..a0df156ee92e 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -996,6 +996,15 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, 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); + } else { + /* + * Force the non-existing CL2 off. BXT does this + * too, so maybe it saves some power even though + * CL2 doesn't exist? + */ + tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); + tmp |= DPIO_CL2_LDOFUSE_PWRENB; + vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, tmp); } mutex_unlock(&dev_priv->sb_lock); -- cgit v1.2.3 From 6669e39f95b5530ca8cb9137703ceb5e83e5d648 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:46:00 +0300 Subject: drm/i915: Add some CHV DPIO lane power state asserts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add some checks that the state of the DPIO lanes is more or less what we expect based on the overrides. The hardware only provides two bits per channel indicating whether all or some of the lanes are powered down, so we can't do an exact check. Additionally, CL2 powering down before we can check it adds another twist. To work around this we simply check for the 0 value of the CL2 register (which is what we get when it's powered down) and adjust our expectations. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 8 +++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 439bb27a63be..8a180230e206 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1099,6 +1099,12 @@ enum skl_disp_power_wells { #define DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE 1 /* 1: coarse & 0 : fine */ #define CHV_PLL_DW9(ch) _PIPE(ch, _CHV_PLL_DW9_CH0, _CHV_PLL_DW9_CH1) +#define _CHV_CMN_DW0_CH0 0x8100 +#define DPIO_ALLDL_POWERDOWN_SHIFT_CH0 19 +#define DPIO_ANYDL_POWERDOWN_SHIFT_CH0 18 +#define DPIO_ALLDL_POWERDOWN (1 << 1) +#define DPIO_ANYDL_POWERDOWN (1 << 0) + #define _CHV_CMN_DW5_CH0 0x8114 #define CHV_BUFRIGHTENA1_DISABLE (0 << 20) #define CHV_BUFRIGHTENA1_NORMAL (1 << 20) @@ -1135,6 +1141,8 @@ enum skl_disp_power_wells { #define _CHV_CMN_DW19_CH0 0x814c #define _CHV_CMN_DW6_CH1 0x8098 +#define DPIO_ALLDL_POWERDOWN_SHIFT_CH1 30 /* CL2 DW6 only */ +#define DPIO_ANYDL_POWERDOWN_SHIFT_CH1 29 /* CL2 DW6 only */ #define DPIO_DYNPWRDOWNEN_CH1 (1 << 28) /* CL2 DW6 only */ #define CHV_CMN_USEDCLKCHANNEL (1 << 13) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index a0df156ee92e..7991eff01662 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1042,6 +1042,58 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, phy, dev_priv->chv_phy_control); } +static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpio_phy phy, + enum dpio_channel ch, bool override, unsigned int mask) +{ + enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C; + u32 reg, val, expected, actual; + + if (ch == DPIO_CH0) + reg = _CHV_CMN_DW0_CH0; + else + reg = _CHV_CMN_DW6_CH1; + + mutex_lock(&dev_priv->sb_lock); + val = vlv_dpio_read(dev_priv, pipe, reg); + mutex_unlock(&dev_priv->sb_lock); + + /* + * This assumes !override is only used when the port is disabled. + * All lanes should power down even without the override when + * the port is disabled. + */ + if (!override || mask == 0xf) { + expected = DPIO_ALLDL_POWERDOWN | DPIO_ANYDL_POWERDOWN; + /* + * If CH1 common lane is not active anymore + * (eg. for pipe B DPLL) the entire channel will + * shut down, which causes the common lane registers + * to read as 0. That means we can't actually check + * the lane power down status bits, but as the entire + * register reads as 0 it's a good indication that the + * channel is indeed entirely powered down. + */ + if (ch == DPIO_CH1 && val == 0) + expected = 0; + } else if (mask != 0x0) { + expected = DPIO_ANYDL_POWERDOWN; + } else { + expected = 0; + } + + if (ch == DPIO_CH0) + actual = val >> DPIO_ANYDL_POWERDOWN_SHIFT_CH0; + else + actual = val >> DPIO_ANYDL_POWERDOWN_SHIFT_CH1; + actual &= DPIO_ALLDL_POWERDOWN | DPIO_ANYDL_POWERDOWN; + + WARN(actual != expected, + "Unexpected DPIO lane power down: all %d, any %d. Expected: all %d, any %d. (0x%x = 0x%08x)\n", + !!(actual & DPIO_ALLDL_POWERDOWN), !!(actual & DPIO_ANYDL_POWERDOWN), + !!(expected & DPIO_ALLDL_POWERDOWN), !!(expected & DPIO_ANYDL_POWERDOWN), + reg, val); +} + bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, enum dpio_channel ch, bool override) { @@ -1094,6 +1146,8 @@ void chv_phy_powergate_lanes(struct intel_encoder *encoder, DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d lanes 0x%x (PHY_CONTROL=0x%08x)\n", phy, ch, mask, dev_priv->chv_phy_control); + assert_chv_phy_powergate(dev_priv, phy, ch, override, mask); + mutex_unlock(&power_domains->lock); } -- cgit v1.2.3 From 30142273a3e83936fd7b45aa5339311a9295ca51 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 8 Jul 2015 23:46:01 +0300 Subject: drm/i915: Add CHV PHY LDO power sanity checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At various points when changing the DPIO lane/phy power states, construct an expected value of the DISPLAY_PHY_STATUS register and compare it with the real thing. To construct the expected value we look at our shadow PHY_CONTROL register value (which should match what we've just written to the hardware), and we also need to look at the actual state of the cmn power wells as a disabled power well causes the relevant LDO status to be reported as 'on' in DISPLAY_PHY_STATUS. When initially powering up the PHY it performs various internal calibrations for which it fully powers up. That means that if we check for the expetected power state immediately upon releasing cmnreset we would get the occasional false positive. But we can of course poll until the expected value appears. It shouldn't be too long so this shouldn't make modesets substantially longer. One extra complication is introduced when we cross the streams, ie. drive port B with pipe B. In this case we trick CL2 (where the DPLL lives) into life by temporaily powering up the lanes in the second channel, and once the pipe is up and runnign we release the lane power override. At that point the power state of CL2 has somehow gotten entangled with the power state of the first channel. That means that constructing the expected DISPLAY_PHY_STATUS value is a bit tricky since based on the lane power states in the second channel, CL2 should also be powered down. But we can use the DPLL enable bit to determine when CL2 should be alive even if the lanes are powered down. However the power state of CL2 isn't actually tied in with the DPLL state, but to the state of the lanes in first channel, so we have to avoid checking the expected state between shutting down the DPLL and powering down the lanes in the first channel. So no calling assert_chv_phy_status() before the DISPLAY_PHY_CONTROL write in chv_phy_powergate_lanes(), but after the write is a safe time to check. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_runtime_pm.c | 126 +++++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 17 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8a180230e206..c82db2aed55c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2223,6 +2223,8 @@ enum skl_disp_power_wells { #define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) #define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104) #define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30)) +#define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6-(6*(phy)+3*(ch)))) +#define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8-(6*(phy)+3*(ch)+(spline)))) /* * The i830 generation, in LVDS mode, defines P1 as the bit number set within diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 7991eff01662..b1bd25e1e853 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -958,6 +958,107 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, vlv_set_power_well(dev_priv, power_well, false); } +#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1) + +static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, + int 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 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); + struct i915_power_well *cmn_d = + lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); + u32 phy_control = dev_priv->chv_phy_control; + u32 phy_status = 0; + u32 tmp; + + if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { + phy_status |= PHY_POWERGOOD(DPIO_PHY0); + + /* this assumes override is only used to enable lanes */ + if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0)) == 0) + phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0); + + if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1)) == 0) + phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1); + + /* CL1 is on whenever anything is on in either channel */ + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0) | + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1))) + phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH0); + + /* + * The DPLLB check accounts for the pipe B + port A usage + * with CL2 powered up but all the lanes in the second channel + * powered down. + */ + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1)) && + (I915_READ(DPLL(PIPE_B)) & DPLL_VCO_ENABLE) == 0) + phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH1); + + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY0, DPIO_CH0))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 0); + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY0, DPIO_CH0))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 1); + + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY0, DPIO_CH1))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 0); + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY0, DPIO_CH1))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1); + } + + if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { + phy_status |= PHY_POWERGOOD(DPIO_PHY1); + + /* this assumes override is only used to enable lanes */ + if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0)) == 0) + phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0); + + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0))) + phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY1, DPIO_CH0); + + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY1, DPIO_CH0))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0); + if (BITS_SET(phy_control, + PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY1, DPIO_CH0))) + phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1); + } + + /* + * The PHY may be busy with some initial calibration and whatnot, + * so the power state can take a while to actually change. + */ + if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS)) == phy_status, 10)) + WARN(phy_status != tmp, + "Unexpected PHY_STATUS 0x%08x, expected 0x%08x (PHY_CONTROL=0x%08x)\n", + tmp, phy_status, dev_priv->chv_phy_control); +} + +#undef BITS_SET + static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -1014,6 +1115,8 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Enabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", phy, dev_priv->chv_phy_control); + + assert_chv_phy_status(dev_priv); } static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, @@ -1040,6 +1143,8 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Disabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", phy, dev_priv->chv_phy_control); + + assert_chv_phy_status(dev_priv); } static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpio_phy phy, @@ -1117,6 +1222,8 @@ bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d (DPIO_PHY_CONTROL=0x%08x)\n", phy, ch, dev_priv->chv_phy_control); + assert_chv_phy_status(dev_priv); + out: mutex_unlock(&power_domains->lock); @@ -1146,6 +1253,8 @@ void chv_phy_powergate_lanes(struct intel_encoder *encoder, DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d lanes 0x%x (PHY_CONTROL=0x%08x)\n", phy, ch, mask, dev_priv->chv_phy_control); + assert_chv_phy_status(dev_priv); + assert_chv_phy_powergate(dev_priv, phy, ch, override, mask); mutex_unlock(&power_domains->lock); @@ -1312,8 +1421,6 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, 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) | \ @@ -1575,21 +1682,6 @@ static struct i915_power_well chv_power_wells[] = { }, }; -static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, - int 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; -} - bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, int power_well_id) { -- cgit v1.2.3 From 6ff8ab0d0fab914755cb79b1e0469dd7123cc471 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Sep 2015 08:20:28 -0700 Subject: drm/i915: make CSR firmware messages less verbose Use WARN_ONCE in a bunch of places and demote a message that would continually spam us. Signed-off-by: Jesse Barnes Acked-by: Damien Lespiau Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 12 +++++------ drivers/gpu/drm/i915/intel_runtime_pm.c | 36 ++++++++++++++++----------------- 2 files changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index ba1ae031e6fd..765dfcd15727 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -454,10 +454,10 @@ void intel_csr_ucode_fini(struct drm_device *dev) void assert_csr_loaded(struct drm_i915_private *dev_priv) { - WARN(intel_csr_load_status_get(dev_priv) != FW_LOADED, - "CSR is not loaded.\n"); - WARN(!I915_READ(CSR_PROGRAM_BASE), - "CSR program storage start is NULL\n"); - WARN(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); - WARN(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); + WARN_ONCE(intel_csr_load_status_get(dev_priv) != FW_LOADED, + "CSR is not loaded.\n"); + WARN_ONCE(!I915_READ(CSR_PROGRAM_BASE), + "CSR program storage start is NULL\n"); + WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); + WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); } diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 3f682a1a08ce..85c35fdfac65 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -463,14 +463,14 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, SKL_DISP_PW_2); - WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC5.\n"); - WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); - WARN(pg2_enabled, "PG2 not disabled to enable DC5.\n"); + WARN_ONCE(!IS_SKYLAKE(dev), "Platform doesn't support DC5.\n"); + WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); + WARN_ONCE(pg2_enabled, "PG2 not disabled to enable DC5.\n"); - WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5), - "DC5 already programmed to be enabled.\n"); - WARN(dev_priv->pm.suspended, - "DC5 cannot be enabled, if platform is runtime-suspended.\n"); + WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5), + "DC5 already programmed to be enabled.\n"); + WARN_ONCE(dev_priv->pm.suspended, + "DC5 cannot be enabled, if platform is runtime-suspended.\n"); assert_csr_loaded(dev_priv); } @@ -486,8 +486,8 @@ static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) if (dev_priv->power_domains.initializing) return; - WARN(!pg2_enabled, "PG2 not enabled to disable DC5.\n"); - WARN(dev_priv->pm.suspended, + WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n"); + WARN_ONCE(dev_priv->pm.suspended, "Disabling of DC5 while platform is runtime-suspended should never happen.\n"); } @@ -526,12 +526,12 @@ static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC6.\n"); - WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); - WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, - "Backlight is not disabled.\n"); - WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), - "DC6 already programmed to be enabled.\n"); + WARN_ONCE(!IS_SKYLAKE(dev), "Platform doesn't support DC6.\n"); + WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); + WARN_ONCE(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, + "Backlight is not disabled.\n"); + WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + "DC6 already programmed to be enabled.\n"); assert_csr_loaded(dev_priv); } @@ -546,8 +546,8 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv) return; assert_csr_loaded(dev_priv); - WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), - "DC6 already programmed to be disabled.\n"); + WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + "DC6 already programmed to be disabled.\n"); } static void skl_enable_dc6(struct drm_i915_private *dev_priv) @@ -670,7 +670,7 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, wait_for((state = intel_csr_load_status_get(dev_priv)) != FW_UNINITIALIZED, 1000); if (state != FW_LOADED) - DRM_ERROR("CSR firmware not ready (%d)\n", + DRM_DEBUG("CSR firmware not ready (%d)\n", state); else if (SKL_ENABLE_DC6(dev)) -- cgit v1.2.3 From 08aef7caa14f1c0b7c5d79d61d279bcedc188ab9 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Wed, 26 Aug 2015 01:36:09 +0530 Subject: drm/i915/skl: Block disable call for pw1 if dmc firmware is present. Another interesting criteria to work dmc as expected is pw1 to be enabled by driver and dmc will shut it off in its execution sequence. If already disabled by driver dmc will get confuse and behave differently than expected found during pc10 entry issue for skl. So berfore we disable power-well 1, added check if dmc firmware is present and driver will not disable power well 1, but for any reason if firmware is not present of failed to load we can shut off the power well 1 which will save some power. As skl is currently fully dependent on dmc to go in lowest possible power state (dc6) but the same is not applicable for bxt. Display engine can enter into dc9 without dmc, hence unblocking disable call. v1: Initial version. v2: Rebased as per current patch series. Cc: Daniel Vetter Cc: Damien Lespiau Cc: Imre Deak Cc: Sunil Kamath Signed-off-by: Animesh Manna Signed-off-by: Vathsala Nagaraju Reviewed-by: A.Sunil Kamath Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 85c35fdfac65..4a815bb6cfca 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -656,9 +656,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, } } else { if (enable_requested) { - 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 (IS_SKYLAKE(dev) && + (power_well->data == SKL_DISP_PW_1) && + (intel_csr_load_status_get(dev_priv) == FW_LOADED)) + DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n"); + else { + 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) || SKL_ENABLE_DC6(dev)) && power_well->data == SKL_DISP_PW_2) { -- cgit v1.2.3 From 165ed87c47ae7dd0deab53d552a29d7985569c28 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 23 Sep 2015 14:37:17 -0700 Subject: drm/i915: fixup runtime PM handling v2 According to the PCI docs and Rafael, we don't need to be doing explicit enables and disables in our init and teardown routines, as they're taken care of by the PCI core. So drop the pm_runtime_disable() at teardown and pm_runtime_set_active() at init. This fixes one failure of the basic-pci-d3-state test on my BYT. v2: drop extra get_noresume() and put_noidle() (Rafael) Signed-off-by: Jesse Barnes Cc: "Rafael J. Wysocki" Acked-by: "Rafael J. Wysocki" Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 4a815bb6cfca..e1fdbabaf2bf 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1828,7 +1828,6 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv) /* Make sure we're not suspended first. */ pm_runtime_get_sync(device); - pm_runtime_disable(device); } /** @@ -2120,8 +2119,6 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) 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. -- cgit v1.2.3 From 3be60de9e9dc92c852c196cf4b62e287fa53963c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 8 Sep 2015 18:05:45 +0300 Subject: drm/i915: Skip CHV PHY asserts until PHY has been fully reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BIOS can leave the CHV display PHY in some odd state where some of the LDOs/lanes won't power down fully when unused. This will trigger a host of asserts that were added in: 30142273a3e83936fd7b45aa5339311a9295ca51 drm/i915: Add CHV PHY LDO power sanity checks 6669e39f95b5530ca8cb9137703ceb5e83e5d648 drm/i915: Add some CHV DPIO lane power state asserts To avoid that, skip the asserts until the PHY power well has been disabled at least once. That will fully reset the PHY, and once brought back up, the dynamic power down features will work correctly. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_runtime_pm.c | 46 ++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1eab9bab152a..35bf5cb04785 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1953,6 +1953,9 @@ struct drm_i915_private { bool edp_low_vswing; + /* perform PHY state sanity checks? */ + bool chv_phy_assert[2]; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index e1fdbabaf2bf..0cfe4c14866a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -993,8 +993,29 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); u32 phy_control = dev_priv->chv_phy_control; u32 phy_status = 0; + u32 phy_status_mask = 0xffffffff; u32 tmp; + /* + * The BIOS can leave the PHY is some weird state + * where it doesn't fully power down some parts. + * Disable the asserts until the PHY has been fully + * reset (ie. the power well has been disabled at + * least once). + */ + if (!dev_priv->chv_phy_assert[DPIO_PHY0]) + phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 1) | + PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH1) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 0) | + PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1)); + + if (!dev_priv->chv_phy_assert[DPIO_PHY1]) + phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY1, DPIO_CH0) | + 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)) { phy_status |= PHY_POWERGOOD(DPIO_PHY0); @@ -1055,11 +1076,13 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1); } + phy_status &= phy_status_mask; + /* * The PHY may be busy with some initial calibration and whatnot, * so the power state can take a while to actually change. */ - if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS)) == phy_status, 10)) + if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS) & phy_status_mask) == phy_status, 10)) WARN(phy_status != tmp, "Unexpected PHY_STATUS 0x%08x, expected 0x%08x (PHY_CONTROL=0x%08x)\n", tmp, phy_status, dev_priv->chv_phy_control); @@ -1152,6 +1175,9 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Disabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n", phy, dev_priv->chv_phy_control); + /* PHY is fully reset now, so we can enable the PHY state asserts */ + dev_priv->chv_phy_assert[phy] = true; + assert_chv_phy_status(dev_priv); } @@ -1161,6 +1187,16 @@ static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpi enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C; u32 reg, val, expected, actual; + /* + * The BIOS can leave the PHY is some weird state + * where it doesn't fully power down some parts. + * Disable the asserts until the PHY has been fully + * reset (ie. the power well has been disabled at + * least once). + */ + if (!dev_priv->chv_phy_assert[phy]) + return; + if (ch == DPIO_CH0) reg = _CHV_CMN_DW0_CH0; else @@ -1916,6 +1952,10 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1); dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0); + + dev_priv->chv_phy_assert[DPIO_PHY0] = false; + } else { + dev_priv->chv_phy_assert[DPIO_PHY0] = true; } if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { @@ -1934,6 +1974,10 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0); dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1); + + dev_priv->chv_phy_assert[DPIO_PHY1] = false; + } else { + dev_priv->chv_phy_assert[DPIO_PHY1] = true; } I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); -- cgit v1.2.3 From 1b0e3a049efe471c399674fd954500ce97438d30 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 5 Nov 2015 23:04:11 +0200 Subject: drm/i915/skl: disable display side power well support for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The display power well support on this platform is in a somewhat broken state atm, so disable it by default. This in effect will get rid of incorrect assert WARNs about the CSR/DMC firmware not being loaded during power well toggling. It also removes a problem during driver loading where a register is accessed while its backing power well is down, resulting in another WARN. Until we come up with the root cause of the second problem and the proper fix for both issues, keep all display side power wells on. Also clarify a bit the option description. Reported-by: Dave Airlie Reference: http://mid.gmane.org/CAPM=9tyjBQjSBTKa49cRr6SYkpNW7Pq-fUFznZZ8Y1snvvk7mA@mail.gmail.com Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/1446757451-2777-1-git-send-email-imre.deak@intel.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_params.c | 5 +++-- drivers/gpu/drm/i915/intel_runtime_pm.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_runtime_pm.c') diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index ca9b8f644ffe..96bb23865eac 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -38,7 +38,7 @@ struct i915_params i915 __read_mostly = { .enable_ppgtt = -1, .enable_psr = 0, .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT), - .disable_power_well = 1, + .disable_power_well = -1, .enable_ips = 1, .prefault_disable = 0, .load_detect_test = 0, @@ -127,7 +127,8 @@ MODULE_PARM_DESC(preliminary_hw_support, module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600); MODULE_PARM_DESC(disable_power_well, - "Disable the power well when possible (default: true)"); + "Disable display power wells when possible " + "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600); MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)"); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 0cfe4c14866a..1aedf2762dff 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1810,6 +1810,21 @@ static struct i915_power_well bxt_power_wells[] = { } }; +static int +sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv, + int disable_power_well) +{ + if (disable_power_well >= 0) + return !!disable_power_well; + + if (IS_SKYLAKE(dev_priv)) { + DRM_DEBUG_KMS("Disabling display power well support\n"); + return 0; + } + + return 1; +} + #define set_power_wells(power_domains, __power_wells) ({ \ (power_domains)->power_wells = (__power_wells); \ (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ @@ -1826,6 +1841,9 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; + i915.disable_power_well = sanitize_disable_power_well_option(dev_priv, + i915.disable_power_well); + mutex_init(&power_domains->lock); /* -- cgit v1.2.3