On 13/07/17 16:51, Kieran Bingham wrote:
> Hi Laurent,
> 
> I've just seen Maxime's latest series "[PATCH 0/4] drm/sun4i: Fix a register
> access bug" and it relates directly to a comment I had in this patch:
> 
> On 12/07/17 17:35, Kieran Bingham wrote:
>> Hi Laurent,
>>
>> On 28/06/17 19:50, Laurent Pinchart wrote:
>>> Commit 52055bafa1ff ("drm: rcar-du: Move plane commit code from CRTC
>>> start to CRTC resume") changed the order of the plane commit and CRTC
>>> enable operations to accommodate the runtime PM requirements. However,
>>> this introduced corruption in the first displayed frame, as the CRTC is
>>> now enabled without any plane configured. On Gen2 hardware the first
>>> frame will be black and likely unnoticed, but on Gen3 hardware we end up
>>> starting the display before the VSP compositor, which is more
>>> noticeable.
>>>
>>> To fix this, revert the order of the commit operations back, and handle
>>> runtime PM requirements in the CRTC .atomic_begin() and .atomic_enable()
>>> helper operation handlers.
>>>
>>> Signed-off-by: Laurent Pinchart <[email protected]>
>>
>> I only have code reduction or comment suggestions below - so either with or
>> without those changes, feel free to add my:
>>
>> Reviewed-by: Kieran Bingham <[email protected]>
>>
>>> ---
>>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 66 
>>> ++++++++++++++++++++--------------
>>>  drivers/gpu/drm/rcar-du/rcar_du_crtc.h |  4 +--
>>>  drivers/gpu/drm/rcar-du/rcar_du_kms.c  |  2 +-
>>>  3 files changed, 43 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c 
>>> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> index 6b5219ef0ad2..76cdb88b2b8e 100644
>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
>>> @@ -448,14 +448,8 @@ static void rcar_du_crtc_wait_page_flip(struct 
>>> rcar_du_crtc *rcrtc)
>>>   * Start/Stop and Suspend/Resume
>>>   */
>>>  
>>> -static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>>> +static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
>>>  {
>>> -   struct drm_crtc *crtc = &rcrtc->crtc;
>>> -   bool interlaced;
>>> -
>>> -   if (rcrtc->started)
>>> -           return;
>>> -
>>>     /* Set display off and background to black */
>>>     rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
>>>     rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
>>> @@ -467,6 +461,18 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
>>> *rcrtc)
>>>     /* Start with all planes disabled. */
>>>     rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
>>>  
>>> +   /* Enable the VSP compositor. */
>>> +   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>>> +           rcar_du_vsp_enable(rcrtc);
>>> +
>>> +   /* Turn vertical blanking interrupt reporting on. */
>>> +   drm_crtc_vblank_on(&rcrtc->crtc);
>>> +}
>>> +
>>> +static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
>>> +{
>>> +   bool interlaced;
>>> +
>>>     /* Select master sync mode. This enables display operation in master
>>
>> Are we close enough here to fix this multiline comment style ?
>> (Not worth doing unless the patch is respun for other reasons ...)
>>
>> Actually - there are a lot in this file, so it would be better to do them 
>> all in
>> one hit/patch at a point of least conflicts ...
>>
>>
>>>      * sync mode (with the HSYNC and VSYNC signals configured as outputs and
>>>      * actively driven).
>>> @@ -477,24 +483,12 @@ static void rcar_du_crtc_start(struct rcar_du_crtc 
>>> *rcrtc)
>>>                          DSYSR_TVM_MASTER);
>>>  
>>>     rcar_du_group_start_stop(rcrtc->group, true);
>>> -
>>> -   /* Enable the VSP compositor. */
>>> -   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>>> -           rcar_du_vsp_enable(rcrtc);
>>> -
>>> -   /* Turn vertical blanking interrupt reporting back on. */
>>> -   drm_crtc_vblank_on(crtc);
>>> -
>>> -   rcrtc->started = true;
>>>  }
>>>  
>>>  static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
>>>  {
>>>     struct drm_crtc *crtc = &rcrtc->crtc;
>>>  
>>> -   if (!rcrtc->started)
>>> -           return;
>>> -
>>>     /* Disable all planes and wait for the change to take effect. This is
>>>      * required as the DSnPR registers are updated on vblank, and no vblank
>>>      * will occur once the CRTC is stopped. Disabling planes when starting
>>> @@ -525,8 +519,6 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc 
>>> *rcrtc)
>>>     rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
>>>  
>>>     rcar_du_group_start_stop(rcrtc->group, false);
>>> -
>>> -   rcrtc->started = false;
>>>  }
>>>  
>>>  void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
>>> @@ -546,12 +538,10 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
>>>             return;
>>>  
>>>     rcar_du_crtc_get(rcrtc);
>>> -   rcar_du_crtc_start(rcrtc);
>>> +   rcar_du_crtc_setup(rcrtc);
>>
>> Every call to _setup is immediately prefixed by a call to _get()
>>
>> Could the _get() be done in the _setup() for code reduction?
>>
>> I'm entirely open to that not happening here as it might be preferred to keep
>> the _get() and _start() separate for style purposes.
>>
>>>  
>>>     /* Commit the planes state. */
>>> -   if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
>>> -           rcar_du_vsp_enable(rcrtc);
>>> -   } else {
>>> +   if (!rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
>>>             for (i = 0; i < rcrtc->group->num_planes; ++i) {
>>>                     struct rcar_du_plane *plane = &rcrtc->group->planes[i];
>>>  
>>> @@ -563,6 +553,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
>>>     }
>>>  
>>>     rcar_du_crtc_update_planes(rcrtc);
>>> +   rcar_du_crtc_start(rcrtc);
>>>  }
>>>  
>>>  /* 
>>> -----------------------------------------------------------------------------
>>> @@ -574,7 +565,16 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc 
>>> *crtc,
>>>  {
>>>     struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
>>>  
>>> -   rcar_du_crtc_get(rcrtc);
>>> +   /*
>>> +    * If the CRTC has already been setup by the .atomic_begin() handler we
>>> +    * can skip the setup stage.
>>> +    */
>>> +   if (!rcrtc->initialized) {
>>> +           rcar_du_crtc_get(rcrtc);
>>> +           rcar_du_crtc_setup(rcrtc);
>>> +           rcrtc->initialized = true;
>>> +   }
>>> +
>>>     rcar_du_crtc_start(rcrtc);
>>>  }
>>>  
>>> @@ -593,6 +593,7 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc 
>>> *crtc,
>>>     }
>>>     spin_unlock_irq(&crtc->dev->event_lock);
>>>  
>>> +   rcrtc->initialized = false;
>>>     rcrtc->outputs = 0;
>>>  }
>>>  
>>> @@ -601,6 +602,19 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc 
>>> *crtc,
>>>  {
>>>     struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
>>>  
>>> +   WARN_ON(!crtc->state->enable);
>>
>> Is this necessary if it's handled by the rcrtc->initialized flag? or is it so
>> that we find out if it happens ?
>>
>> (Or is this due to the re-ordering of the _commit_tail() function below?)
>>
>>
>>> +
>>> +   /*
>>> +    * If a mode set is in progress we can be called with the CRTC disabled.
>>> +    * We then need to first setup the CRTC in order to configure planes.
>>> +    * The .atomic_enable() handler will notice and skip the CRTC setup.
>>> +    */
>>
>> I'm assuming this comment is the reason for the WARN_ON above ...
>>
>>
>>> +   if (!rcrtc->initialized) {
>>> +           rcar_du_crtc_get(rcrtc);
>>> +           rcar_du_crtc_setup(rcrtc);
>>> +           rcrtc->initialized = true;
>>> +   }
>>
>>
>> If the _get() was moved into the _setup(), and _setup() was protected by the
>> rcrtc->initialized flag, then _atomic_begin() _enable() and _resume() could 
>> all
>> just simply call _setup(). The _resume() should only ever be called with
>> rcrtc->initialized = false anyway, as that is set in _suspend()
>>
>>> +
>>>     if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
>>>             rcar_du_vsp_atomic_begin(rcrtc);
>>>  }
>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h 
>>> b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>>> index 0b6d26ecfc38..3cc376826592 100644
>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
>>> @@ -30,7 +30,7 @@ struct rcar_du_vsp;
>>>   * @extclock: external pixel dot clock (optional)
>>>   * @mmio_offset: offset of the CRTC registers in the DU MMIO block
>>>   * @index: CRTC software and hardware index
>>> - * @started: whether the CRTC has been started and is running
>>> + * @initialized: whether the CRTC has been initialized and clocks enabled
>>>   * @event: event to post when the pending page flip completes
>>>   * @flip_wait: wait queue used to signal page flip completion
>>>   * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this 
>>> CRTC
>>> @@ -45,7 +45,7 @@ struct rcar_du_crtc {
>>>     struct clk *extclock;
>>>     unsigned int mmio_offset;
>>>     unsigned int index;
>>> -   bool started;
>>> +   bool initialized;
>>>  
>>>     struct drm_pending_vblank_event *event;
>>>     wait_queue_head_t flip_wait;
>>> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c 
>>> b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>> index 82b978a5dae6..c2f382feca07 100644
>>> --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>> +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>>> @@ -255,9 +255,9 @@ static void rcar_du_atomic_commit_tail(struct 
>>> drm_atomic_state *old_state)
>>>  
>>>     /* Apply the atomic update. */
>>>     drm_atomic_helper_commit_modeset_disables(dev, old_state);
>>> -   drm_atomic_helper_commit_modeset_enables(dev, old_state);
>>>     drm_atomic_helper_commit_planes(dev, old_state,
>>>                                     DRM_PLANE_COMMIT_ACTIVE_ONLY);
>>
>> Except for DRM_PLANE_COMMIT_ACTIVE_ONLY, this function now looks very much 
>> like
>> the default drm_atomic_helper_commit_tail() code.
>>
>> Reading around other uses /variants of commit_tail() style functions in other
>> drivers has left me confused as to how the ordering affects things here.
>>
>> Could be worth adding a comment at least to describe why we can't use the
>> default helper...
> 
> Or better still ... Use Maxime's new :
> 
> [PATCH 1/4] drm/atomic: implement drm_atomic_helper_commit_tail for 
> runtime_pm users


Never mind - I've just looked again, and seen that this new helper function is
the ordering previous to *this* patch, and therefore isn't the same.

However - it's worth noting that Maxime's patch converts this function to the
new helper - which contradicts this patch's motivations.


>>
>>
>>> +   drm_atomic_helper_commit_modeset_enables(dev, old_state);
>>>  >          drm_atomic_helper_commit_hw_done(old_state);
>>>     drm_atomic_helper_wait_for_vblanks(dev, old_state);
>>>
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to