summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_hdmi.c
diff options
context:
space:
mode:
authorVille Syrjälä2015-07-08 22:45:55 +0200
committerDaniel Vetter2015-08-26 14:35:06 +0200
commitb0b3384612bd4ce608c5d95626149311bb43f121 (patch)
tree66ef34fe92d38b81faf7e71760e11ee3cb3a8673 /drivers/gpu/drm/i915/intel_hdmi.c
parentdrm/i915: Implement PHY lane power gating for CHV (diff)
downloadkernel-qcow2-linux-b0b3384612bd4ce608c5d95626149311bb43f121.tar.gz
kernel-qcow2-linux-b0b3384612bd4ce608c5d95626149311bb43f121.tar.xz
kernel-qcow2-linux-b0b3384612bd4ce608c5d95626149311bb43f121.zip
drm/i915: Trick CL2 into life on CHV when using pipe B with port B
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ä <ville.syrjala@linux.intel.com> Reviewed-by: Deepak S <deepak.s@linux.intel.com> [danvet: Amend commit message with extended explanation.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hdmi.c')
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c23
1 files changed, 23 insertions, 0 deletions
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)