@@ -1594,6 +1594,9 @@
#define EDP_PSR_STATUS_CTL 0x64840
#define EDP_PSR_STATUS_MASK (7<<29)
#define EDP_PSR_PERF_CNT 0x64844
+#define EDP_PSR_DEBUG_CTL 0x64860
+#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26)
+#define EDP_PSR_DEBUG_MASK_HPD (1<<25)
/* VGA port control */
#define ADPA 0x61100
@@ -958,9 +958,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc)
temp |= TRANS_DDI_PHSYNC;
if (cpu_transcoder == TRANSCODER_EDP) {
+ struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
switch (pipe) {
case PIPE_A:
- temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
+ if (intel_dp->psr_dpcd[0] & 0x1)
+ temp |= TRANS_DDI_EDP_INPUT_A_ON;
+ else
+ temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
break;
case PIPE_B:
temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
@@ -83,6 +83,13 @@ static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp)
return intel_dig_port->base.base.dev;
}
+static struct drm_crtc *intel_dp_to_crtc(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+
+ return intel_dig_port->base.base.crtc;
+}
+
static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
{
return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
@@ -1472,6 +1479,169 @@ static void intel_edp_psr_setup(struct intel_dp *intel_dp)
intel_dp->psr_setup = 1;
}
+static bool
+intel_edp_is_psr_enabled(struct intel_dp* intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ return (I915_READ(EDP_PSR_CTL) & (1<<31)) ? true : false;
+}
+
+
+static void
+intel_edp_psr_enable_src(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t max_sleep_time = 0x1f;
+ uint32_t val = 0x0;
+
+ /* Use VBT values which are parsed in
+ * dev_priv->idle_frames,
+ * but the BIOS initializes this to zero today
+ * so hardcode
+ */
+ uint32_t idle_frames = 6;
+
+ if (intel_dp->psr_dpcd[1] & 0x1) {
+ /* No link training on PSR Exit required */
+ val |= EDP_PSR_TP2_TP3_TIME_0us;
+ val |= EDP_PSR_TP1_TIME_0us;
+ val |= EDP_PSR_SKIP_AUX_EXIT;
+ } else {
+ /* Use these Values from VBT
+ * Case values are timings for HSW as of now
+ * in multiple of 100us
+ */
+ switch(dev_priv->wakeup_tp1) {
+ case 1:
+ val |= EDP_PSR_TP1_TIME_100us;
+ break;
+ case 5:
+ val |= EDP_PSR_TP1_TIME_500us;
+ break;
+ case 25:
+ val |= EDP_PSR_TP1_TIME_2500us;
+ break;
+ default:
+ val |= EDP_PSR_TP1_TIME_500us;
+ break;
+ };
+ switch(dev_priv->wakeup_tp2_tp3) {
+ case 1:
+ val |= EDP_PSR_TP2_TP3_TIME_100us;
+ break;
+ case 5:
+ val |= EDP_PSR_TP2_TP3_TIME_500us;
+ break;
+ case 25:
+ val |= EDP_PSR_TP2_TP3_TIME_2500us;
+ break;
+ default:
+ val |= EDP_PSR_TP2_TP3_TIME_500us;
+ break;
+ };
+ }
+
+ /* Disable main link. Anyway in HSW steppings today
+ * link standby does not work
+ *
+ * Later used VBT info (already parsed and available)
+ * while supporting standby we need to program
+ * val |= EDP_PSR_MIN_LINK_ENTRY_TIME_X_LINES based on VBT
+ */
+ val = (val & ~EDP_PSR_LINK_STANDBY) |
+ (max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT) |
+ (idle_frames << EDP_PSR_IDLE_FRAME_SHIFT) |
+ EDP_PSR_ENABLE;
+
+ I915_WRITE(EDP_PSR_CTL, val);
+}
+
+void intel_edp_enable_psr(struct intel_dp* intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp_to_crtc(intel_dp));
+ struct edp_vsc_psr psr_vsc;
+ uint32_t *vsc_data = (uint32_t *) &psr_vsc;
+ int i = 0, vsc_len = sizeof(struct edp_vsc_psr);
+
+ if (!is_edp_psr(intel_dp))
+ return;
+
+ /* setup AUX registers in case returned from pm states */
+ intel_edp_psr_setup(intel_dp);
+
+ /* Check if PSR is already enabled */
+ if (!intel_edp_is_psr_enabled(intel_dp)) {
+ /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */
+ memset(&psr_vsc, 0, sizeof(psr_vsc));
+ psr_vsc.sdp_header.id = 0;
+ psr_vsc.sdp_header.type = 0x7;
+ psr_vsc.sdp_header.revision = 0x2;
+ psr_vsc.sdp_header.valid_payload_bytes = 0x8;
+
+ /* As per eDP spec, wait for vblank to send SDP VSC packet */
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ /* Load the VSC DIP packet */
+ for(i = 0; i < vsc_len; i += 4)
+ I915_WRITE((VIDEO_DIP_VSC_DATA_EDP + i), vsc_data[i]);
+#if 0
+ /* TBD:
+ * We might not have to do explicitely as hardware will take care of this */
+ /* Enable the DIP register */
+ val = I915_READ(VIDEO_DIP_CTL_EDP);
+ I915_WRITE(VIDEO_DIP_CTL_EDP, val | VIDEOP_DIP_VSC);
+#endif
+ /* Enable PSR in sink by setting bit 0 in DPCD config reg
+ * along with the transmitter state during PSR active
+ * Transmitter state later can be ready from VBT. As of now
+ * program the full link down
+ *
+ */
+ intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
+ DP_PSR_ENABLE &
+ ~DP_PSR_MAIN_LINK_ACTIVE);
+
+ /* Enable PSR on the host */
+ intel_edp_psr_enable_src(intel_dp);
+ }
+}
+
+void intel_edp_disable_psr(struct intel_dp* intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp_to_crtc(intel_dp));
+ uint32_t val;
+ if (!intel_edp_is_psr_enabled(intel_dp))
+ return;
+
+ val = I915_READ(EDP_PSR_CTL);
+ I915_WRITE(EDP_PSR_CTL, (val & ~EDP_PSR_ENABLE));
+
+ /* Wait till PSR is idle */
+ if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) & EDP_PSR_STATUS_MASK) == 0, 2000, 10))
+ DRM_ERROR("Timed out waiting for PSR Idle State\n");
+
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+#if 0
+ /* TBD:
+ * Following is not yet confirmed from H/W team.
+ * As per last discussion we do not need to disable
+ * VSC DIP explicitely. Just maintaining the code in
+ * case we have to do this later at some point
+ */
+
+ /* Disable VSC DIP */
+ val = I915_READ(VIDEO_DIP_CTL_EDP);
+ I915_WRITE(VIDEO_DIP_CTL_EDP, val & ~VIDEOP_DIP_VSC);
+#endif
+}
+
static void intel_enable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -704,4 +704,7 @@ extern bool
intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
+extern void intel_edp_enable_psr(struct intel_dp* intel_dp);
+extern void intel_edp_disable_psr(struct intel_dp* intel_dp);
+
#endif /* __INTEL_DRV_H__ */