Signed-off-by: Rodrigo Vivi <rodrigo.vivi at gmail.com> --- drivers/gpu/drm/i915/intel_dp.c | 169 +++++++++++++++++++++------------------- 1 file changed, 87 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a7f3bd1..c5ea419 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1362,7 +1362,79 @@ static bool intel_edp_is_psr_enabled(struct drm_device *dev) return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; } -static void intel_edp_psr_enable_src(struct intel_dp *intel_dp) + +void intel_edp_psr_write_vsc(struct intel_dp* intel_dp, + struct edp_vsc_psr *vsc_psr) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); + + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder); + u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder); + uint32_t *data = (uint32_t *) vsc_psr; + unsigned int i; + u32 val = I915_READ(ctl_reg); + + /* As per eDP spec, wait for vblank to send SDP VSC packet */ + intel_wait_for_vblank(dev, crtc->pipe); + + /* As per BSPec (Pipe Video Data Island Packet), besides wait for + vsync we need to disable the video DIP being updated before program + video DIP data buffer registers for DIP being updated.*/ + I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW); + POSTING_READ(ctl_reg); + + for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) { + if (i < sizeof(struct edp_vsc_psr)) + I915_WRITE(data_reg + i, *data++); + else + I915_WRITE(data_reg + i, 0); + } + + I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW); + POSTING_READ(ctl_reg); +} + +static void intel_edp_psr_enable_sink(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 edp_vsc_psr psr_vsc; + uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp); + int precharge = 0x3; + int msg_size = 5; /* Header(4) + Message(1) */ + + /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */ + memset(&psr_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + intel_edp_psr_write_vsc(intel_dp, &psr_vsc); + + /* Enable PSR in sink */ + if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) + intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, + DP_PSR_ENABLE & + ~DP_PSR_MAIN_LINK_ACTIVE); + else + intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, + DP_PSR_ENABLE | + DP_PSR_MAIN_LINK_ACTIVE); + + /* Setup AUX registers */ + I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND); + I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION); + I915_WRITE(EDP_PSR_AUX_CTL, + DP_AUX_CH_CTL_TIME_OUT_400us | + (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | + (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | + (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); +} + +static void intel_edp_psr_enable_source(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; @@ -1415,44 +1487,29 @@ static void intel_edp_psr_enable_src(struct intel_dp *intel_dp) }; } + /* Avoid continuous PSR exit by masking memup and hpd */ + I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP | + EDP_PSR_DEBUG_MASK_HPD); + + /* Disable unused interrupts */ + I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED | + GEN6_PM_RP_DOWN_EI_EXPIRED); + + I915_WRITE(EDP_PSR_CTL, val | EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES | max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | EDP_PSR_ENABLE); } -void intel_edp_psr_write_vsc(struct intel_dp* intel_dp, - struct edp_vsc_psr *vsc_psr) +static void intel_edp_psr_do_enable(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_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); - - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder); - u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder); - uint32_t *data = (uint32_t *) vsc_psr; - unsigned int i; - u32 val = I915_READ(ctl_reg); - - /* As per eDP spec, wait for vblank to send SDP VSC packet */ - intel_wait_for_vblank(dev, crtc->pipe); - - /* As per BSPec (Pipe Video Data Island Packet), besides wait for - vsync we need to disable the video DIP being updated before program - video DIP data buffer registers for DIP being updated.*/ - I915_WRITE(ctl_reg, val & ~VIDEO_DIP_ENABLE_VSC_HSW); - POSTING_READ(ctl_reg); - for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) { - if (i < sizeof(struct edp_vsc_psr)) - I915_WRITE(data_reg + i, *data++); - else - I915_WRITE(data_reg + i, 0); - } + /* Enable PSR on the panel */ + intel_edp_psr_enable_sink(intel_dp); - I915_WRITE(ctl_reg, val | VIDEO_DIP_ENABLE_VSC_HSW); - POSTING_READ(ctl_reg); + /* Enable PSR on the host */ + intel_edp_psr_enable_source(intel_dp); } static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp) @@ -1526,58 +1583,6 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp) return true; } -void intel_edp_psr_do_enable(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 edp_vsc_psr psr_vsc; - uint32_t aux_clock_divider = get_aux_clock_divider(intel_dp); - int precharge = 0x3; - int msg_size = 5; /* Header(4) + Message(1) */ - - if (!intel_edp_psr_match_conditions(intel_dp) || - intel_edp_is_psr_enabled(dev)) - return; - - /* Prepare VSC packet as per EDP 1.3 spec, Table 3.10 */ - memset(&psr_vsc, 0, sizeof(psr_vsc)); - psr_vsc.sdp_header.HB0 = 0; - psr_vsc.sdp_header.HB1 = 0x7; - psr_vsc.sdp_header.HB2 = 0x2; - psr_vsc.sdp_header.HB3 = 0x8; - intel_edp_psr_write_vsc(intel_dp, &psr_vsc); - - /* Enable PSR in sink */ - if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) - intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, - DP_PSR_ENABLE & - ~DP_PSR_MAIN_LINK_ACTIVE); - else - intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG, - DP_PSR_ENABLE | - DP_PSR_MAIN_LINK_ACTIVE); - - /* Setup AUX registers */ - I915_WRITE(EDP_PSR_AUX_DATA1, EDP_PSR_DPCD_COMMAND); - I915_WRITE(EDP_PSR_AUX_DATA2, EDP_PSR_DPCD_NORMAL_OPERATION); - I915_WRITE(EDP_PSR_AUX_CTL, - DP_AUX_CH_CTL_TIME_OUT_400us | - (msg_size << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | - (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); - - /* Avoid continuous PSR exit by masking memup and hpd */ - I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD); - - /* Disable unused interrupts */ - I915_WRITE(GEN6_PMINTRMSK, GEN6_PM_RP_UP_EI_EXPIRED | - GEN6_PM_RP_DOWN_EI_EXPIRED); - - /* Enable PSR on the host */ - intel_edp_psr_enable_src(intel_dp); -} - void intel_edp_psr_enable(struct intel_dp* intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); -- 1.7.11.7