[Intel-gfx] [PATCH] drm/i915: Add Baytrail PSR Support.

Rodrigo Vivi rodrigo.vivi at gmail.com
Wed Jan 29 18:48:21 CET 2014


On Wed, Jan 29, 2014 at 2:38 PM, Ville Syrjälä
<ville.syrjala at linux.intel.com> wrote:
> On Wed, Jan 29, 2014 at 01:47:00PM -0200, Rodrigo Vivi wrote:
>> On Wed, Jan 29, 2014 at 12:56 PM, Ville Syrjälä
>> <ville.syrjala at linux.intel.com> wrote:
>> > On Wed, Jan 29, 2014 at 10:47:54AM -0200, Rodrigo Vivi wrote:
>> >> This patch adds PSR Support to Baytrail.
>> >>
>> >> Baytrail cannot easily detect screen updates and force PSR exit.
>> >> So we inactivate it on {busy_ioctl, set_domain, sw_finish and mark_busy
>> >> and update to enable it back on next display mark_idle.
>> >>
>> >> v2: Also inactivate PSR on cursor update.
>> >> v3: Inactivate PSR on mark_busy, dset_domain and sw_finish_ioctl, and
>> >>     early on page flip besides avoid initializing inactive/active flag
>> >>     more than once.
>> >> v4: Fix identation issues.
>> >> v5: Rebase and add Baytrail per pipe support although leaving PIPE_B
>> >>     support disabled by for now since it isn't working properly yet.
>> >> v6: Removing forgotten comment and useless clkgating definition.
>> >>
>> >> Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
>> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi at gmail.com>
>> >> ---
>> >>  drivers/gpu/drm/i915/i915_debugfs.c  |  36 ++++++-
>> >>  drivers/gpu/drm/i915/i915_drv.h      |   4 +-
>> >>  drivers/gpu/drm/i915/i915_gem.c      |   9 ++
>> >>  drivers/gpu/drm/i915/i915_reg.h      |  37 +++++++
>> >>  drivers/gpu/drm/i915/intel_display.c |  15 ++-
>> >>  drivers/gpu/drm/i915/intel_dp.c      | 204 +++++++++++++++++++++++++++++------
>> >>  drivers/gpu/drm/i915/intel_drv.h     |   1 +
>> >>  7 files changed, 267 insertions(+), 39 deletions(-)
>> >>
>> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>> >> index 4b852c6..c28de65 100644
>> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>> >> @@ -1900,6 +1900,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>> >>       struct drm_device *dev = node->minor->dev;
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>       u32 psrperf = 0;
>> >> +     u32 statA = 0;
>> >> +     u32 statB = 0;
>> >>       bool enabled = false;
>> >>
>> >>       intel_runtime_pm_get(dev_priv);
>> >> @@ -1907,14 +1909,38 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>> >>       seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
>> >>       seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
>> >>
>> >> -     enabled = HAS_PSR(dev) &&
>> >> -             I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> -     seq_printf(m, "Enabled: %s\n", yesno(enabled));
>> >> +     if (HAS_PSR(dev)) {
>> >> +             if (IS_VALLEYVIEW(dev)) {
>> >> +                     statA = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_A)) &
>> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +                     statB = I915_READ(VLV_EDP_PSR_STATUS_CTL(PIPE_B)) &
>> >> +                             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +                     enabled = ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                                (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE) ||
>> >> +                                (statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                                (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE));
>> >> +             } else
>> >> +                     enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     }
>> >> +     seq_printf(m, "Enabled: %s", yesno(enabled));
>> >>
>> >> -     if (HAS_PSR(dev))
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             if ((statA == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                 (statA == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> >> +                     seq_puts(m, " pipe A");
>> >> +             if ((statB == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +                 (statB == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
>> >> +                     seq_puts(m, " pipe B");
>> >> +     }
>> >> +
>> >> +     seq_puts(m, "\n");
>> >> +
>> >> +     /* VLV PSR has no kind of performance counter */
>> >> +     if (HAS_PSR(dev) && !IS_VALLEYVIEW(dev)) {
>> >>               psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
>> >>                       EDP_PSR_PERF_CNT_MASK;
>> >> -     seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> >> +             seq_printf(m, "Performance_Counter: %u\n", psrperf);
>> >> +     }
>> >>
>> >>       intel_runtime_pm_put(dev_priv);
>> >>       return 0;
>> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>> >> index 7c53d4d..34dee24 100644
>> >> --- a/drivers/gpu/drm/i915/i915_drv.h
>> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> >> @@ -747,6 +747,7 @@ struct i915_psr {
>> >>       bool sink_support;
>> >>       bool source_ok;
>> >>       bool setup_done;
>> >> +     bool active;
>> >>  };
>> >>
>> >>  enum intel_pch {
>> >> @@ -1866,7 +1867,8 @@ struct drm_i915_file_private {
>> >>
>> >>  #define HAS_DDI(dev)         (INTEL_INFO(dev)->has_ddi)
>> >>  #define HAS_FPGA_DBG_UNCLAIMED(dev)  (INTEL_INFO(dev)->has_fpga_dbg)
>> >> -#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev))
>> >> +#define HAS_PSR(dev)         (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
>> >> +                              IS_VALLEYVIEW(dev))
>> >>  #define HAS_PC8(dev)         (IS_HASWELL(dev)) /* XXX HSW:ULX */
>> >>  #define HAS_RUNTIME_PM(dev)  (IS_HASWELL(dev))
>> >>
>> >> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>> >> index 39770f7..01137fe 100644
>> >> --- a/drivers/gpu/drm/i915/i915_gem.c
>> >> +++ b/drivers/gpu/drm/i915/i915_gem.c
>> >> @@ -1256,6 +1256,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
>> >>               goto unlock;
>> >>       }
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       /* Try to flush the object off the GPU without holding the lock.
>> >>        * We will repeat the flush holding the lock in the normal manner
>> >>        * to catch cases where we are gazumped.
>> >> @@ -1299,6 +1302,9 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
>> >>       if (ret)
>> >>               return ret;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>> >>       if (&obj->base == NULL) {
>> >>               ret = -ENOENT;
>> >> @@ -4059,6 +4065,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
>> >>       if (ret)
>> >>               return ret;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >
>> > The locking for PSR seems to be as fubar as for FBC. Also the front
>> > buffer tracking is missing, but I guess I need to make that work for FBC
>> > first, and then we need to figure out how to tie it in w/ PSR.
>> >
>>
>> agree... I'll wait your fbc work.
>>
>> >> +
>> >>       obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
>> >>       if (&obj->base == NULL) {
>> >>               ret = -ENOENT;
>> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> >> index cbbaf26..2039d71 100644
>> >> --- a/drivers/gpu/drm/i915/i915_reg.h
>> >> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> >> @@ -1968,6 +1968,43 @@
>> >>  #define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
>> >>  #define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
>> >>
>> >> +/* VLV eDP PSR registers */
>> >> +#define _PSRCTLA                             (VLV_DISPLAY_BASE + 0x60090)
>> >> +#define _PSRCTLB                             (VLV_DISPLAY_BASE + 0x61090)
>> >> +#define  VLV_EDP_PSR_ENABLE                  (1<<0)
>> >> +#define  VLV_EDP_PSR_RESET                   (1<<1)
>> >> +#define  VLV_EDP_PSR_MODE_MASK                       (7<<2)
>> >> +#define  VLV_EDP_PSR_MODE_HW_TIMER           (1<<3)
>> >> +#define  VLV_EDP_PSR_MODE_SW_TIMER           (1<<2)
>> >> +#define  VLV_EDP_PSR_SINGLE_FRAME_UPDATE     (1<<7)
>> >> +#define  VLV_EDP_PSR_ACTIVE_ENTRY            (1<<8)
>> >> +#define  VLV_EDP_PSR_SRC_TRANSMITTER_STATE   (1<<9)
>> >> +#define  VLV_EDP_PSR_DBL_FRAME                       (1<<10)
>> >> +#define  VLV_EDP_PSR_FRAME_COUNT_MASK                (0xff<<16)
>> >> +#define  VLV_EDP_PSR_IDLE_FRAME_SHIFT                16
>> >> +#define  VLV_EDP_PSR_INT_TRANSITION          (1<<24)
>> >> +#define VLV_EDP_PSR_CTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
>> >
>> > Can we just name the PSR registers like in the spec? Eg. just
>> > VLV_PSRCTL(). Would make it easier to compare things w/ the spec.
>> >
>>
>> Done.
>>
>> >> +
>> >> +#define _VSCSDPA                     (VLV_DISPLAY_BASE + 0x600a0)
>> >> +#define _VSCSDPB                     (VLV_DISPLAY_BASE + 0x610a0)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_MASK   (3<<30)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_ONCE   (1<<31)
>> >> +#define  VLV_EDP_PSR_SDP_FREQ_EVFRAME        (1<<30)
>> >> +#define VLV_EDP_VSC_SDP_REG(pipe)    _PIPE(pipe, _VSCSDPA, _VSCSDPB)
>> >> +
>> >> +#define _PSRSTATA                    (VLV_DISPLAY_BASE + 0x60094)
>> >> +#define _PSRSTATB                    (VLV_DISPLAY_BASE + 0x61094)
>> >> +#define  VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
>> >> +#define  VLV_EDP_PSR_CURR_STATE_MASK 7
>> >> +#define  VLV_EDP_PSR_DISABLED                (0<<0)
>> >> +#define  VLV_EDP_PSR_INACTIVE                (1<<0)
>> >> +#define  VLV_EDP_PSR_IN_TRANS_TO_ACTIVE      (2<<0)
>> >> +#define  VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
>> >> +#define  VLV_EDP_PSR_ACTIVE_SF_UPDATE        (4<<0)
>> >> +#define  VLV_EDP_PSR_EXIT            (5<<0)
>> >> +#define  VLV_EDP_PSR_IN_TRANS                (1<<7)
>> >> +#define VLV_EDP_PSR_STATUS_CTL(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
>> >> +
>> >>  /* HSW+ eDP PSR registers */
>> >>  #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
>> >>  #define EDP_PSR_CTL(dev)                     (EDP_PSR_BASE(dev) + 0)
>> >> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> >> index 1a9aa19..081c8e2 100644
>> >> --- a/drivers/gpu/drm/i915/intel_display.c
>> >> +++ b/drivers/gpu/drm/i915/intel_display.c
>> >> @@ -7501,6 +7501,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
>> >>       u32 base = 0, pos = 0;
>> >>       bool visible;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       if (on)
>> >>               base = intel_crtc->cursor_addr;
>> >>
>> >> @@ -8228,16 +8231,20 @@ void intel_mark_idle(struct drm_device *dev)
>> >>
>> >>       if (dev_priv->info->gen >= 6)
>> >>               gen6_rps_idle(dev->dev_private);
>> >> +
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_update(dev);
>> >>  }
>> >>
>> >> +
>> >>  void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
>> >>                       struct intel_ring_buffer *ring)
>> >>  {
>> >>       struct drm_device *dev = obj->base.dev;
>> >>       struct drm_crtc *crtc;
>> >>
>> >> -     if (!i915.powersave)
>> >> -             return;
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >>
>> >>       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> >>               if (!crtc->fb)
>> >> @@ -8688,6 +8695,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
>> > nav>    if (work == NULL)
>>
>> sorry, I didn't get this..
>> what did you mean?
>
> Nothing. Just managed to misplace a few characters here I guess. I blame
> vim :)
>
>>
>> >>               return -ENOMEM;
>> >>
>> >> +     /* Inactivate PSR early in page flip */
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             intel_edp_psr_inactivate(dev);
>> >> +
>> >>       work->event = event;
>> >>       work->crtc = crtc;
>> >>       work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
>> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> >> index 30d4350..e9a0ace 100644
>> >> --- a/drivers/gpu/drm/i915/intel_dp.c
>> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> >> @@ -1578,21 +1578,35 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>> >>       }
>> >>  }
>> >>
>> >> -static bool is_edp_psr(struct drm_device *dev)
>> >> +static bool is_edp_psr(struct intel_dp *intel_dp)
>> >> +{
>> >> +     return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
>> >> +}
>> >> +
>> >> +static bool vlv_edp_is_psr_enabled_on_pipe(struct drm_device *dev, int pipe)
>> >>  {
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     uint32_t val;
>> >>
>> >> -     return dev_priv->psr.sink_support;
>> >> +     val = I915_READ(VLV_EDP_PSR_STATUS_CTL(pipe)) &
>> >> +             VLV_EDP_PSR_CURR_STATE_MASK;
>> >> +     return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
>> >> +             (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
>> >>  }
>> >>
>> >>  static bool intel_edp_is_psr_enabled(struct drm_device *dev)
>> >>  {
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>
>> >> -     if (!HAS_PSR(dev))
>> >> -             return false;
>> >> +     if (HAS_PSR(dev)) {
>> >> +             if (IS_VALLEYVIEW(dev))
>> >> +                     return vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_A) ||
>> >> +                             vlv_edp_is_psr_enabled_on_pipe(dev, PIPE_B);
>> >> +             else
>> >> +                     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     }
>> >>
>> >> -     return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
>> >> +     return false;
>> >>  }
>> >>
>> >>  static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> >> @@ -1626,28 +1640,49 @@ static void intel_edp_psr_write_vsc(struct intel_dp *intel_dp,
>> >>
>> >>  static void intel_edp_psr_setup(struct intel_dp *intel_dp)
>> >>  {
>> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >>       struct drm_i915_private *dev_priv = dev->dev_private;
>> >>       struct edp_vsc_psr psr_vsc;
>> >> +     uint32_t val;
>> >>
>> >>       if (dev_priv->psr.setup_done)
>> >>               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);
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_A));
>> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_A), val);
>> >> +
>> >> +             val  = I915_READ(VLV_EDP_VSC_SDP_REG(PIPE_B));
>> >> +             val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
>> >> +             val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
>> >> +             I915_WRITE(VLV_EDP_VSC_SDP_REG(PIPE_B), val);
>> >> +     } else {
>> >> +             /* 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);
>> >>
>> >> -     /* Avoid continuous PSR exit by masking memup and hpd */
>> >> -     I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> >> -                EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> >> +             /* Avoid continuous PSR exit by masking memup and hpd */
>> >> +             I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
>> >> +                        EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
>> >> +     }
>> >>
>> >>       dev_priv->psr.setup_done = true;
>> >>  }
>> >>
>> >> +static void vlv_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >> +{
>> >> +     /* Enable PSR in sink */
>> >> +     intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
>> >> +                                 DP_PSR_ENABLE);
>> >
>> > Don't we want the same main-link poweroff logic as HSW?
>>
>>
>> I can't remember why I'm not disabling main link here... So I did a
>> quickly try now and failure on tests was huge... so let's keep it
>> simple for now ;)
>
> I think you are disabling the main link currently. Or at least you're
> telling the sink that main link is going to be turned off, and you also
> leave the VLV_EDP_PSR_SRC_TRANSMITTER_STATE bit unset, so I think that
> should make the main link turn off. Well, since the pipe and port remain
> active, I don't know if the link actually turns off.
>
> I would assume that if you don't turn off the link, it would be easier
> to keep things happy. A bit weird that you had the opposite result.
>
> BTW now that I look at the HSW code, it seems buggy. When the sink
> doesn't require link training, we tell it that we're going to turn the
> link off, otherwise we tell it link will be on. But then we actually do
> the opposite in intel_edp_psr_enable_source().

afaI-can-remember I followed hsw-pm guide on this... but I might be wrong...
I'll comeback to psr hsw later anyway than I verify that and fix if needed.

>
>>
>> > Or maybe we
>> > should just keep the main link on always as long as we can't enter
>> > the low power states w/ DPLL/pipe/port off.
>> >
>> > Did you already figure out why that's not happening? Looking at the
>> > PSRSTAT registers, my guess is that D0i1 is where we end up currently,
>> > and that doesn't actually turn off anything but the planes (to stop
>> > memory fetches). D0i2 would turn off everything.
>>
>> no idea.. :(
>
> Did you check the status bit BTW? Does it say D0i1 or D0i2 when you're
> in PSR?

D0i1

>
>>
>> > But I guess we should anyway do this in steps. First getting the
>> > current stuff in, then trying to get into D0i2 state, and finally
>> > getting the display power well turned off when in PSR.
>>
>> Agree.
>>
>> >
>> > I think once we get to working on D0i2, we'll need to move the PSR
>> > wakeup to happen from a workqueue since it essentially requires a
>> > full modeset. Even now in your code it's somewhat questionable
>> > since you're doing stuff like aux transfers while holding
>> > struct_mutex.
>>
>> uhm... anything we should try now to improve?
>
> Hmm. We already seem to do some PSR setup while holding struct_mutex,
> but we don't hold it always. Although I think w/ HSW we end up
> protecting the PSR state w/ the modeset locks since we only fiddle
> with it during modesets. So for HSW we should just move the PSR update
> call in set_base outside struct_mutex.

I'm planning to change it on HSW to allow a kind of inactivate as well...

>
> But then for VLV, you want to call it from various places that already
> hold struct_mutex, so it's getting messy. Just moving it to a workqueue
> would seem like the easiest option here, and then you could grab the
> modeset locks in the work function.

uhm... I'm not sure... I don't think we need to delay the
psr_enable... the only issue I see here is double setup or psr-enable
along with psr-reset (inactivate)... don't you think a simple mutex
for psr_setup would solve in a simpler way?

>
>>
>> >
>> >> +}
>> >> +
>> >>  static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1678,6 +1713,28 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
>> >>                  (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
>> >>  }
>> >>
>> >> +static void vlv_edp_psr_enable_source(struct intel_dp *intel_dp)
>> >> +{
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >> +
>> >> +     uint32_t idle_frames = 1;
>> >> +     uint32_t val;
>> >> +
>> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>> >
>> > I don't think we want to preserve anything here. We need to make sure
>> > everything is initialized correctly rather than trusting some old junk
>> > in the register.
>>
>> Done.
>>
>> >
>> >> +     val |= VLV_EDP_PSR_ENABLE;
>> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> >> +
>> >> +     val |= VLV_EDP_PSR_MODE_HW_TIMER;
>> >> +     val &= ~VLV_EDP_PSR_FRAME_COUNT_MASK;
>> >> +     val |= idle_frames << EDP_PSR_IDLE_FRAME_SHIFT;
>> >> +
>> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> >> +}
>> >> +
>> >>  static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1719,8 +1776,8 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>> >>               return false;
>> >>       }
>> >>
>> >> -     if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> >> -         (dig_port->port != PORT_A)) {
>> >> +     if (HAS_DDI(dev) && ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>> >> +                          (dig_port->port != PORT_A))) {
>> >>               DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>> >>               return false;
>> >>       }
>> >> @@ -1765,37 +1822,83 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>> >>               return false;
>> >>       }
>> >>
>> >> +     /* Baytrail supports per-pipe PSR configuration, however PSR on
>> >> +     * PIPE_B isn't working properly. So let's keep it disabled for now. */
>> >> +     if (IS_VALLEYVIEW(dev) && intel_crtc->pipe != PIPE_A) {
>> >> +             DRM_DEBUG_KMS("PSR on BYT isn't enabled on pipe B.\n");
>> >> +             return false;
>> >> +     }
>> >> +
>> >>       dev_priv->psr.source_ok = true;
>> >>       return true;
>> >>  }
>> >>
>> >>  static void intel_edp_psr_do_enable(struct intel_dp *intel_dp)
>> >>  {
>> >> -     struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >>
>> >> -     if (!intel_edp_psr_match_conditions(intel_dp) ||
>> >> -         intel_edp_is_psr_enabled(dev))
>> >> -             return;
>> >> +     if (IS_VALLEYVIEW(dev)) {
>> >> +             if (vlv_edp_is_psr_enabled_on_pipe(dev, intel_crtc->pipe))
>> >> +                     return;
>> >> +     } else
>> >> +             if (intel_edp_is_psr_enabled(dev))
>> >> +                     return;
>> >>
>> >>       /* Setup PSR once */
>> >>       intel_edp_psr_setup(intel_dp);
>> >>
>> >>       /* Enable PSR on the panel */
>> >> -     intel_edp_psr_enable_sink(intel_dp);
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_enable_sink(intel_dp);
>> >> +     else
>> >> +             intel_edp_psr_enable_sink(intel_dp);
>> >>
>> >>       /* Enable PSR on the host */
>> >> -     intel_edp_psr_enable_source(intel_dp);
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_enable_source(intel_dp);
>> >> +     else
>> >> +             intel_edp_psr_enable_source(intel_dp);
>> >> +
>> >> +     dev_priv->psr.active = true;
>> >>  }
>> >>
>> >>  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))
>> >> +             return;
>> >>
>> >> -     if (intel_edp_psr_match_conditions(intel_dp) &&
>> >> -         !intel_edp_is_psr_enabled(dev))
>> >> +     if (intel_edp_psr_match_conditions(intel_dp))
>> >>               intel_edp_psr_do_enable(intel_dp);
>> >>  }
>> >>
>> >> +void vlv_edp_psr_disable(struct intel_dp *intel_dp)
>> >> +{
>> >> +     struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
>> >> +     struct drm_device *dev = intel_dig_port->base.base.dev;
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_crtc *intel_crtc =
>> >> +             to_intel_crtc(intel_dig_port->base.base.crtc);
>> >> +     uint32_t val = I915_READ(VLV_EDP_PSR_STATUS_CTL(intel_crtc->pipe));
>> >> +
>> >> +     if (!dev_priv->psr.setup_done)
>> >> +             return;
>> >> +
>> >> +     intel_edp_psr_inactivate(dev);
>> >> +
>> >> +     if (val & VLV_EDP_PSR_IN_TRANS)
>> >> +             udelay(250);
>> >
>> > Might we want a warning if the bit doesn't go down in expected time?
>>
>> Done.
>>
>> >
>> >> +
>> >> +     val = I915_READ(VLV_EDP_PSR_CTL(intel_crtc->pipe));
>> >> +     val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
>> >> +     val &= ~VLV_EDP_PSR_ENABLE;
>> >> +     val &= ~VLV_EDP_PSR_MODE_MASK;
>> >> +     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), val);
>> >> +}
>> >> +
>> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp)
>> >>  {
>> >>       struct drm_device *dev = intel_dp_to_dev(intel_dp);
>> >> @@ -1817,28 +1920,66 @@ void intel_edp_psr_update(struct drm_device *dev)
>> >>  {
>> >>       struct intel_encoder *encoder;
>> >>       struct intel_dp *intel_dp = NULL;
>> >> +     struct intel_crtc *intel_crtc;
>> >>
>> >>       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>> >>               if (encoder->type == INTEL_OUTPUT_EDP) {
>> >>                       intel_dp = enc_to_intel_dp(&encoder->base);
>> >>
>> >> -                     if (!is_edp_psr(dev))
>> >> +                     if (!is_edp_psr(intel_dp))
>> >>                               return;
>> >>
>> >> -                     if (!intel_edp_psr_match_conditions(intel_dp))
>> >> -                             intel_edp_psr_disable(intel_dp);
>> >> -                     else
>> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> >> +
>> >> +                     if (!intel_edp_psr_match_conditions(intel_dp)) {
>> >> +                             if (IS_VALLEYVIEW(dev))
>> >> +                                     vlv_edp_psr_disable(intel_dp);
>> >> +                             else
>> >> +                                     intel_edp_psr_disable(intel_dp);
>> >> +                     } else
>> >>                               if (!intel_edp_is_psr_enabled(dev))
>> >>                                       intel_edp_psr_do_enable(intel_dp);
>> >>               }
>> >>  }
>> >>
>> >> +void intel_edp_psr_inactivate(struct drm_device *dev)
>> >> +{
>> >> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> >> +     struct intel_encoder *encoder;
>> >> +     struct intel_crtc *intel_crtc;
>> >> +     struct intel_dp *intel_dp = NULL;
>> >> +
>> >> +     if (!dev_priv->psr.setup_done || !dev_priv->psr.active)
>> >> +             return;
>> >> +
>> >> +     list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head)
>> >> +             if (encoder->type == INTEL_OUTPUT_EDP) {
>> >> +                     intel_dp = enc_to_intel_dp(&encoder->base);
>> >> +                     intel_crtc = to_intel_crtc(encoder->base.crtc);
>> >> +
>> >> +                     if (!vlv_edp_is_psr_enabled_on_pipe(dev,
>> >> +                                                         intel_crtc->pipe))
>> >> +                             continue;
>> >> +
>> >> +                     dev_priv->psr.active = false;
>> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe),
>> >> +                                VLV_EDP_PSR_RESET);
>> >> +                     /* WaClearPSRReset:vlv */
>> >> +                     I915_WRITE(VLV_EDP_PSR_CTL(intel_crtc->pipe), 0);
>> >> +
>> >> +                     intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>> >> +             }
>> >> +}
>> >> +
>> >>  static void intel_disable_dp(struct intel_encoder *encoder)
>> >>  {
>> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>> >>       enum port port = dp_to_dig_port(intel_dp)->port;
>> >>       struct drm_device *dev = encoder->base.dev;
>> >>
>> >> +     if (IS_VALLEYVIEW(dev))
>> >> +             vlv_edp_psr_disable(intel_dp);
>> >> +
>> >>       /* Make sure the panel is off before trying to change the mode. But also
>> >>        * ensure that we have vdd while we switch off the panel. */
>> >>       intel_edp_backlight_off(intel_dp);
>> >> @@ -1895,6 +2036,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
>> >>       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>> >>
>> >>       intel_edp_backlight_on(intel_dp);
>> >> +     intel_edp_psr_enable(intel_dp);
>> >>  }
>> >>
>> >>  static void g4x_pre_enable_dp(struct intel_encoder *encoder)
>> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> >> index 71c1371..82026ef 100644
>> >> --- a/drivers/gpu/drm/i915/intel_drv.h
>> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> >> @@ -748,6 +748,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_enable(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_disable(struct intel_dp *intel_dp);
>> >>  void intel_edp_psr_update(struct drm_device *dev);
>> >> +void intel_edp_psr_inactivate(struct drm_device *dev);
>> >>
>> >>
>> >>  /* intel_dsi.c */
>> >> --
>> >> 1.8.1.2
>> >
>> > --
>> > Ville Syrjälä
>> > Intel OTC
>>
>> Thank you very much!
>>
>> --
>> Rodrigo Vivi
>> Blog: http://blog.vivi.eng.br
>
> --
> Ville Syrjälä
> Intel OTC



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br



More information about the Intel-gfx mailing list