2013/7/1 Rodrigo Vivi <rodrigo.vivi at gmail.com>: > Adding Enable and Disable PSR functionalities. This includes setting the > PSR configuration over AUX, sending SDP VSC DIP over the eDP PIPE config, > enabling PSR in the sink via DPCD register and finally enabling PSR on > the host. > > This patch is based on initial PSR code by Sateesh Kavuri and Kumar Shobhit > but in a different implementation. > > v2: * moved functions around and changed its names. > * removed VSC DIP unset from disable. > * remove FBC wa. > * don't mask LSPS anymore. > * incorporate new crtc usage after a rebase. > v3: Make a clear separation between Sink (Panel) and Source (HW) enabling. > v4: Fix identation and other style issues raised by checkpatch (by Paulo). > v5: Changes according to Paulo's review: > static on write_vsc; > avoid using dp_to_dev when already calling dp_to_dig_port; > remove unecessary TP default time setting; > remove unecessary interrupts disabling; > remove unecessary wait_for_vblank whend disabling psr; > > Cc: Paulo Zanoni <paulo.r.zanoni at intel.com> > Credits-by: Sateesh Kavuri <sateesh.kavuri at intel.com> > Credits-by: Shobhit Kumar <shobhit.kumar at intel.com> > Signed-off-by: Rodrigo Vivi <rodrigo.vivi at gmail.com> > --- > drivers/gpu/drm/i915/i915_reg.h | 42 ++++++++++++ > drivers/gpu/drm/i915/intel_dp.c | 136 +++++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/intel_drv.h | 3 + > 3 files changed, 181 insertions(+) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 137be4c..caf57d8 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -1777,6 +1777,47 @@ > #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) > #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B) > > +/* HSW eDP PSR registers */ > +#define EDP_PSR_CTL 0x64800 > +#define EDP_PSR_ENABLE (1<<31) > +#define EDP_PSR_LINK_DISABLE (0<<27) > +#define EDP_PSR_LINK_STANDBY (1<<27) > +#define EDP_PSR_MIN_LINK_ENTRY_TIME_MASK (3<<25) > +#define EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES (0<<25) > +#define EDP_PSR_MIN_LINK_ENTRY_TIME_4_LINES (1<<25) > +#define EDP_PSR_MIN_LINK_ENTRY_TIME_2_LINES (2<<25) > +#define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES (3<<25) > +#define EDP_PSR_MAX_SLEEP_TIME_SHIFT 20 > +#define EDP_PSR_SKIP_AUX_EXIT (1<<12) > +#define EDP_PSR_TP1_TP2_SEL (0<<11) > +#define EDP_PSR_TP1_TP3_SEL (1<<11) > +#define EDP_PSR_TP2_TP3_TIME_500us (0<<8) > +#define EDP_PSR_TP2_TP3_TIME_100us (1<<8) > +#define EDP_PSR_TP2_TP3_TIME_2500us (2<<8) > +#define EDP_PSR_TP2_TP3_TIME_0us (3<<8) > +#define EDP_PSR_TP1_TIME_500us (0<<4) > +#define EDP_PSR_TP1_TIME_100us (1<<4) > +#define EDP_PSR_TP1_TIME_2500us (2<<4) > +#define EDP_PSR_TP1_TIME_0us (3<<4) > +#define EDP_PSR_IDLE_FRAME_SHIFT 0 > + > +#define EDP_PSR_AUX_CTL 0x64810 > +#define EDP_PSR_AUX_DATA1 0x64814 > +#define EDP_PSR_DPCD_COMMAND 0x80060000 > +#define EDP_PSR_AUX_DATA2 0x64818 > +#define EDP_PSR_DPCD_NORMAL_OPERATION (1<<24) > +#define EDP_PSR_AUX_DATA3 0x6481c > +#define EDP_PSR_AUX_DATA4 0x64820 > +#define EDP_PSR_AUX_DATA5 0x64824 > + > +#define EDP_PSR_STATUS_CTL 0x64840 > +#define EDP_PSR_STATUS_STATE_MASK (7<<29) > + > +#define EDP_PSR_DEBUG_CTL 0x64860 > +#define EDP_PSR_DEBUG_MASK_LPSP (1<<27) > +#define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) > +#define EDP_PSR_DEBUG_MASK_HPD (1<<25) > + > /* VGA port control */ > #define ADPA 0x61100 > #define PCH_ADPA 0xe1100 > @@ -2046,6 +2087,7 @@ > * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte > * of the infoframe structure specified by CEA-861. */ > #define VIDEO_DIP_DATA_SIZE 32 > +#define VIDEO_DIP_VSC_DATA_SIZE 36 > #define VIDEO_DIP_CTL 0x61170 > /* Pre HSW: */ > #define VIDEO_DIP_ENABLE (1 << 31) > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > index dca8fa6..5b49e31 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -1356,6 +1356,142 @@ static bool is_edp_psr(struct intel_dp *intel_dp) > intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; > } > > +static bool intel_edp_is_psr_enabled(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (!IS_HASWELL(dev)) > + return false; > + > + return I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; > +} > + > +static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp, > + struct edp_vsc_psr *vsc_psr) > +{ > + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); > + struct drm_device *dev = dig_port->base.base.dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + 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; > + > + /* 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, ~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, 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; > + uint32_t max_sleep_time = 0x1f; > + uint32_t idle_frames = 1; > + uint32_t val = 0x0; > + > + if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) { > + val |= EDP_PSR_LINK_STANDBY; > + val |= EDP_PSR_TP2_TP3_TIME_0us; > + val |= EDP_PSR_TP1_TIME_0us; > + val |= EDP_PSR_SKIP_AUX_EXIT; > + } else > + val |= EDP_PSR_LINK_DISABLE; > + > + /* 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); > + > + I915_WRITE(EDP_PSR_CTL, val | > + EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES | > + max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | > + idle_frames << EDP_PSR_IDLE_FRAME_SHIFT | > + EDP_PSR_ENABLE); > +} > + > +void intel_edp_psr_enable(struct intel_dp *intel_dp) > +{ > + struct drm_device *dev = intel_dp_to_dev(intel_dp); > + > + if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev)) > + return; > + > + /* Enable PSR on the panel */ > + intel_edp_psr_enable_sink(intel_dp); > + > + /* Enable PSR on the host */ > + intel_edp_psr_enable_source(intel_dp); > +} > + > +void intel_edp_psr_disable(struct intel_dp *intel_dp) > +{ > + struct drm_device *dev = intel_dp_to_dev(intel_dp); > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (!intel_edp_is_psr_enabled(dev)) > + return; > + > + I915_WRITE(EDP_PSR_CTL, I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE); > + > + /* Wait till PSR is idle */ > + if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) & > + EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10)) > + DRM_ERROR("Timed out waiting for PSR Idle State\n"); We do this wait while the pipe is running, right? I'm kinda afraid to do these sleeps/waits after the mode set... > +} > + > static void intel_disable_dp(struct intel_encoder *encoder) > { > struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 9b264ee..ff09c4c 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -840,4 +840,7 @@ extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev, > enum transcoder pch_transcoder, > bool enable); > > +extern void intel_edp_psr_enable(struct intel_dp *intel_dp); > +extern void intel_edp_psr_disable(struct intel_dp *intel_dp); > + > #endif /* __INTEL_DRV_H__ */ > -- > 1.8.1.4 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Paulo Zanoni