From mboxrd@z Thu Jan 1 00:00:00 1970 From: Deepak S Subject: Re: [PATCH 6/7] drm/i915: Implement PHY lane power gating for CHV Date: Fri, 08 May 2015 20:19:12 +0530 Message-ID: <554CCCE8.1030302@linux.intel.com> References: <1428679293-6208-1-git-send-email-ville.syrjala@linux.intel.com> <1428679293-6208-7-git-send-email-ville.syrjala@linux.intel.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0700162485==" Return-path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTP id 6AFB96E952 for ; Fri, 8 May 2015 07:52:22 -0700 (PDT) In-Reply-To: <1428679293-6208-7-git-send-email-ville.syrjala@linux.intel.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" To: intel-gfx@lists.freedesktop.org List-Id: intel-gfx@lists.freedesktop.org This is a multi-part message in MIME format. --===============0700162485== Content-Type: multipart/alternative; boundary="------------020507060609010503020802" This is a multi-part message in MIME format. --------------020507060609010503020802 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable On Friday 10 April 2015 08:51 PM, ville.syrjala@linux.intel.com wrote: > From: Ville Syrj=C3=A4l=C3=A4 > > Powergate the PHY lanes when they're not needed. For HDMI all four lane= s > are needed always, but for DP we can enable only the needed lanes. And > when the port is not used all lanes can be power gated. This could > reduce power consumption a bit when only a subset of the lanes in the > PHY are required. > > A bit of extra care is needed to reconstruct the initial state of the > DPIO_PHY_CONTROL register since we can't read it. So instead we read th= e > actual lane status from the DPLL/PHY_STATUS registers and use that to > determine which lanes ought to be powergated initially. > > Also sprinkle a few debug prints around so that we can monitor the > DPIO_PHY_STATUS changes without having to read it and risk corrupting > it. > > Signed-off-by: Ville Syrj=C3=A4l=C3=A4 > --- > drivers/gpu/drm/i915/i915_reg.h | 2 + > drivers/gpu/drm/i915/intel_dp.c | 8 ++++ > drivers/gpu/drm/i915/intel_drv.h | 2 + > drivers/gpu/drm/i915/intel_hdmi.c | 5 +++ > drivers/gpu/drm/i915/intel_runtime_pm.c | 69 ++++++++++++++++++++++++= +++++++-- > 5 files changed, 82 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i91= 5_reg.h > index 977bad6..34c366a 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -1887,10 +1887,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/int= el_dp.c > index ac38fd8..0b43f99 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -2336,6 +2336,8 @@ static void chv_post_disable_dp(struct intel_enco= der *encoder) > =20 > intel_dp_link_down(intel_dp); > =20 > + chv_powergate_phy_lanes(encoder, 0xf); > + > mutex_lock(&dev_priv->dpio_lock); > =20 > /* Propagate soft reset to data lane reset */ > @@ -2482,6 +2484,12 @@ static void intel_enable_dp(struct intel_encoder= *encoder) > if (IS_VALLEYVIEW(dev)) > vlv_init_panel_power_sequencer(intel_dp); > =20 > + if (IS_CHERRYVIEW(dev)) { > + /* FIXME deal with lane reversal */ > + lane_mask =3D 0xf & ~((1 << intel_dp->lane_count) - 1); > + chv_powergate_phy_lanes(encoder, lane_mask); > + } > + > intel_dp_enable_port(intel_dp); > =20 > edp_panel_vdd_on(intel_dp); > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/in= tel_drv.h > index 3ec829a..54bcca8 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -1238,6 +1238,8 @@ void intel_runtime_pm_put(struct drm_i915_private= *dev_priv); > =20 > void intel_display_set_init_power(struct drm_i915_private *dev, bool = enable); > =20 > +void chv_powergate_phy_lanes(struct intel_encoder *encoder, unsigned i= nt 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/i= ntel_hdmi.c > index 24b0aa1..f5842c3 100644 > --- a/drivers/gpu/drm/i915/intel_hdmi.c > +++ b/drivers/gpu/drm/i915/intel_hdmi.c > @@ -916,6 +916,9 @@ static void intel_disable_hdmi(struct intel_encoder= *encoder) > I915_WRITE(intel_hdmi->hdmi_reg, temp); > POSTING_READ(intel_hdmi->hdmi_reg); > } > + > + if (IS_CHERRYVIEW(dev)) > + chv_powergate_phy_lanes(encoder, 0xf); > } > =20 > static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect= _dvi_limit) > @@ -1634,6 +1637,8 @@ static void chv_hdmi_pre_enable(struct intel_enco= der *encoder) > intel_crtc->config->has_hdmi_sink, > adjusted_mode); > =20 > + chv_powergate_phy_lanes(encoder, 0x0); > + > intel_enable_hdmi(encoder); > =20 > vlv_wait_port_ready(dev_priv, dport, 0x0); > diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/= i915/intel_runtime_pm.c > index 5cd8a51..d9e00d3 100644 > --- a/drivers/gpu/drm/i915/intel_runtime_pm.c > +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c > @@ -668,6 +668,9 @@ static void chv_dpio_cmn_power_well_enable(struct d= rm_i915_private *dev_priv, > =20 > dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(phy); > I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); > + > + DRM_DEBUG_KMS("Enabled DPIO PHY%d (DPIO_PHY_CONTROL=3D0x%08x)\n", > + phy, dev_priv->chv_phy_control); > } > =20 > static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *= dev_priv, > @@ -680,10 +683,15 @@ static void chv_dpio_cmn_power_well_disable(struc= t drm_i915_private *dev_priv, > =20 > if (power_well->data =3D=3D PUNIT_POWER_WELL_DPIO_CMN_BC) { > phy =3D DPIO_PHY0; > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH0) | > + PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH1); > assert_pll_disabled(dev_priv, PIPE_A); > assert_pll_disabled(dev_priv, PIPE_B); > } else { > phy =3D DPIO_PHY1; > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH0); > assert_pll_disabled(dev_priv, PIPE_C); > } > =20 > @@ -691,6 +699,25 @@ static void chv_dpio_cmn_power_well_disable(struct= drm_i915_private *dev_priv, > I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); > =20 > vlv_set_power_well(dev_priv, power_well, false); > + > + DRM_DEBUG_KMS("Disabled DPIO PHY%d (DPIO_PHY_CONTROL=3D0x%08x)\n", > + phy, dev_priv->chv_phy_control); > +} > + > +void chv_powergate_phy_lanes(struct intel_encoder *encoder, unsigned i= nt mask) > +{ > + struct drm_device *dev =3D encoder->base.dev; > + struct drm_i915_private *dev_priv =3D dev->dev_private; > + struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->base.crtc); > + enum dpio_phy phy =3D DPIO_PHY(intel_crtc->pipe); > + enum dpio_channel ch =3D vlv_dport_to_channel(enc_to_dig_port(&encode= r->base)); > + > + dev_priv->chv_phy_control &=3D ~PHY_CH_POWER_DOWN_OVRD(0xf, phy, ch); > + dev_priv->chv_phy_control |=3D PHY_CH_POWER_DOWN_OVRD(mask, 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 (DPIO_PHY_CONT= ROL=3D0x%08x)\n", > + phy, ch, mask, dev_priv->chv_phy_control); > } > =20 Hi Ville, I think based on the spec, we needto program 0x8170 as 0xxxC3xxxx to affe= ct the DDI0 power down and this reigster to be programted beforeDPIO_PHY_CONTROL ? Thanks Deepak > static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_= priv, > @@ -1402,19 +1429,53 @@ static void chv_phy_control_init(struct drm_i91= 5_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 =3D > + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0) | > + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1) | > + PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0) | > 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)) > + > + if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { > + uint32_t status =3D I915_READ(DPLL(PIPE_A)); > + unsigned int mask; > + > + mask =3D status & DPLL_PORTB_READY_MASK; > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH0); > + mask =3D (status & DPLL_PORTC_READY_MASK) >> 4; > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1); > + > dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY= 0); > - if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) > + } else { > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0) | > + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1); > + } > + > + if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { > + uint32_t status =3D I915_READ(DPIO_PHY_STATUS); > + unsigned int mask; > + > + mask =3D status & DPLL_PORTD_READY_MASK; > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0); > + > dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY= 1); > + } else { > + dev_priv->chv_phy_control |=3D > + PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0); > + } > + > + DRM_DEBUG_KMS("Initial DPIO_PHY_CONTROL=3D0x%08x\n", > + dev_priv->chv_phy_control); > } > =20 > static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) --------------020507060609010503020802 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

On Friday 10 April 2015 08:51 PM, ville.syrjala@linux.intel.com wrote:
From: Ville Syrj=C3=A4l=C3=A4 <ville.syrj=
ala@linux.intel.com>

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. And
when the port is not used all lanes can be power gated. This could
reduce power consumption a bit when only a subset of the lanes in the
PHY are required.

A bit of extra care is needed to reconstruct the initial state of the
DPIO_PHY_CONTROL register since we can't read it. So instead we read the
actual lane status from the DPLL/PHY_STATUS registers and use that to
determine which lanes ought to be powergated initially.

Also sprinkle a few debug prints around so that we can monitor the
DPIO_PHY_STATUS changes without having to read it and risk corrupting
it.

Signed-off-by: Ville Syrj=C3=A4l=C3=A4 <ville.syrjala@linux.in=
tel.com>
---
 drivers/gpu/drm/i915/i915_reg.h         |  2 +
 drivers/gpu/drm/i915/intel_dp.c         |  8 ++++
 drivers/gpu/drm/i915/intel_drv.h        |  2 +
 drivers/gpu/drm/i915/intel_hdmi.c       |  5 +++
 drivers/gpu/drm/i915/intel_runtime_pm.c | 69 +++++++++++++++++++++++++++=
++++--
 5 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_=
reg.h
index 977bad6..34c366a 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1887,10 +1887,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)+2=
7))
 #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 ac38fd8..0b43f99 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2336,6 +2336,8 @@ static void chv_post_disable_dp(struct intel_encode=
r *encoder)
=20
 	intel_dp_link_down(intel_dp);
=20
+	chv_powergate_phy_lanes(encoder, 0xf);
+
 	mutex_lock(&dev_priv->dpio_lock);
=20
 	/* Propagate soft reset to data lane reset */
@@ -2482,6 +2484,12 @@ static void intel_enable_dp(struct intel_encoder *=
encoder)
 	if (IS_VALLEYVIEW(dev))
 		vlv_init_panel_power_sequencer(intel_dp);
=20
+	if (IS_CHERRYVIEW(dev)) {
+		/* FIXME deal with lane reversal */
+		lane_mask =3D 0xf & ~((1 << intel_dp->lane_count) - 1);
+		chv_powergate_phy_lanes(encoder, lane_mask);
+	}
+
 	intel_dp_enable_port(intel_dp);
=20
 	edp_panel_vdd_on(intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/inte=
l_drv.h
index 3ec829a..54bcca8 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1238,6 +1238,8 @@ void intel_runtime_pm_put(struct drm_i915_private *=
dev_priv);
=20
 void intel_display_set_init_power(struct drm_i915_private *dev, bool ena=
ble);
=20
+void chv_powergate_phy_lanes(struct intel_encoder *encoder, 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/int=
el_hdmi.c
index 24b0aa1..f5842c3 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -916,6 +916,9 @@ static void intel_disable_hdmi(struct intel_encoder *=
encoder)
 		I915_WRITE(intel_hdmi->hdmi_reg, temp);
 		POSTING_READ(intel_hdmi->hdmi_reg);
 	}
+
+	if (IS_CHERRYVIEW(dev))
+		chv_powergate_phy_lanes(encoder, 0xf);
 }
=20
 static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dv=
i_limit)
@@ -1634,6 +1637,8 @@ static void chv_hdmi_pre_enable(struct intel_encode=
r *encoder)
 				   intel_crtc->config->has_hdmi_sink,
 				   adjusted_mode);
=20
+	chv_powergate_phy_lanes(encoder, 0x0);
+
 	intel_enable_hdmi(encoder);
=20
 	vlv_wait_port_ready(dev_priv, dport, 0x0);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i9=
15/intel_runtime_pm.c
index 5cd8a51..d9e00d3 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -668,6 +668,9 @@ static void chv_dpio_cmn_power_well_enable(struct drm=
_i915_private *dev_priv,
=20
 	dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(phy);
 	I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
+
+	DRM_DEBUG_KMS("Enabled DPIO PHY%d (DPIO_PHY_CONTROL=3D0x%08x)\n",
+		      phy, dev_priv->chv_phy_control);
 }
=20
 static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev=
_priv,
@@ -680,10 +683,15 @@ static void chv_dpio_cmn_power_well_disable(struct =
drm_i915_private *dev_priv,
=20
 	if (power_well->data =3D=3D PUNIT_POWER_WELL_DPIO_CMN_BC) {
 		phy =3D DPIO_PHY0;
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH0) |
+			PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH1);
 		assert_pll_disabled(dev_priv, PIPE_A);
 		assert_pll_disabled(dev_priv, PIPE_B);
 	} else {
 		phy =3D DPIO_PHY1;
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(0xf, phy, DPIO_CH0);
 		assert_pll_disabled(dev_priv, PIPE_C);
 	}
=20
@@ -691,6 +699,25 @@ static void chv_dpio_cmn_power_well_disable(struct d=
rm_i915_private *dev_priv,
 	I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
=20
 	vlv_set_power_well(dev_priv, power_well, false);
+
+	DRM_DEBUG_KMS("Disabled DPIO PHY%d (DPIO_PHY_CONTROL=3D0x%08x)\n",
+		      phy, dev_priv->chv_phy_control);
+}
+
+void chv_powergate_phy_lanes(struct intel_encoder *encoder, unsigned int=
 mask)
+{
+	struct drm_device *dev =3D encoder->base.dev;
+	struct drm_i915_private *dev_priv =3D dev->dev_private;
+	struct intel_crtc *intel_crtc =3D to_intel_crtc(encoder->base.crtc);
+	enum dpio_phy phy =3D DPIO_PHY(intel_crtc->pipe);
+	enum dpio_channel ch =3D vlv_dport_to_channel(enc_to_dig_port(&enco=
der->base));
+
+	dev_priv->chv_phy_control &=3D ~PHY_CH_POWER_DOWN_OVRD(0xf, phy,=
 ch);
+	dev_priv->chv_phy_control |=3D PHY_CH_POWER_DOWN_OVRD(mask, 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 (DPIO_PHY_CONTRO=
L=3D0x%08x)\n",
+		      phy, ch, mask, dev_priv->chv_phy_control);
 }
 
Hi Ville,
I think based on the spec, we need to pr=
ogram 0x8170 as 0xxxC3xxxx to affect the DDI0 power down
and this reigster to be programted before DPIO_PHY_CONTROL ?
Thanks
Deepak
 static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_pri=
v,
@@ -1402,19 +1429,53 @@ 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 =3D
+		PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0) |
+		PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1) |
+		PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0) |
 		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))
+
+	if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) {
+		uint32_t status =3D I915_READ(DPLL(PIPE_A));
+		unsigned int mask;
+
+		mask =3D status & DPLL_PORTB_READY_MASK;
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH0);
+		mask =3D (status & DPLL_PORTC_READY_MASK) >> 4;
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1);
+
 		dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY=
0);
-	if (cmn_d->ops->is_enabled(dev_priv, cmn_d))
+	} else {
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0) |
+			PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1);
+	}
+
+	if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) {
+		uint32_t status =3D I915_READ(DPIO_PHY_STATUS);
+		unsigned int mask;
+
+		mask =3D status & DPLL_PORTD_READY_MASK;
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0);
+
 		dev_priv->chv_phy_control |=3D PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY=
1);
+	} else {
+		dev_priv->chv_phy_control |=3D
+			PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0);
+	}
+
+	DRM_DEBUG_KMS("Initial DPIO_PHY_CONTROL=3D0x%08x\n",
+		      dev_priv->chv_phy_control);
 }
=20
 static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)

--------------020507060609010503020802-- --===============0700162485== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KSW50ZWwtZ2Z4 IG1haWxpbmcgbGlzdApJbnRlbC1nZnhAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHA6Ly9saXN0 cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pbnRlbC1nZngK --===============0700162485==--