Re: [Freedreno] [PATCH v1 1/3] drm/msm/dpu: set dirty_fb flag while in self refresh mode

2023-04-03 Thread Vinod Polimera
> On Fri, 31 Mar 2023 at 16:59, Vinod Polimera 
> wrote:
> >
> > While in virtual terminal mode with PSR enabled, there will be
> > no atomic commits triggered without dirty_fb being set. This
> > will create a notion of no screen update. Allow atomic commit
> > when dirty_fb ioctl is issued, so that it can trigger a PSR exit
> > and shows update on the screen.
> 
> Will this impact non-VT workloads? If I remember correctly, we added
> dirty_fb handling to prevent the framework from limiting the page
> flips to vblank events (in DSI video mode).
> 
From the use case referred in the commit text ( 9e4dde28e  drm/msm: Avoid 
dirtyfb stalls on video mode displays (v2)).
There can be an impact on the workload. I can think of two solutions:
1) Add modparam to configure PSR wait time (SELF_REFRESH_AVG_SEED_MS 200) and 
application can set it to "-1" if they are operating on dirty_fb
2) In msm drivers, disable psr if dirty_fb_ioctl is requested from the 
framework and re-enable it during regular commit.
This will involve copying dirtyflags from drm fb ->msm_fb->dpu_plane and 
add atomic_check failure if ( dirty_flags &&  self_refresh_active).

Please let me know your thoughts on the above two.

Thanks,
Vinod.

> >
> > Reported-by: Bjorn Andersson 
> > Link:
> https://lore.kernel.org/all/20230326162723.3lo6pnsfdwzsvbhj@ripper/
> > Signed-off-by: Vinod Polimera 
> > ---
> >  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index ab636da..96f645e 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -1158,6 +1158,9 @@ static bool dpu_crtc_needs_dirtyfb(struct
> drm_crtc_state *cstate)
> > struct drm_crtc *crtc = cstate->crtc;
> > struct drm_encoder *encoder;
> >
> > +   if (cstate->self_refresh_active)
> > +   return true;
> > +
> > drm_for_each_encoder_mask (encoder, crtc->dev, cstate-
> >encoder_mask) {
> > if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) {
> > return true;
> > --
> > 2.7.4
> >
> 
> 
> --
> With best wishes
> Dmitry


Re: [Freedreno] [PATCH v1 3/3] msm: skip the atomic commit of self refresh while PSR running

2023-04-03 Thread Vinod Polimera
> On Fri, 31 Mar 2023 at 16:59, Vinod Polimera 
> wrote:
> >
> > In certain CPU stress conditions, there can be a delay in scheduling commit
> > work and it was observed that PSR commit from a different work queue
> was
> > scheduled. Avoid these commits as display is already in PSR mode.
> >
> > Signed-off-by: Vinod Polimera 
> > ---
> >  drivers/gpu/drm/msm/msm_atomic.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/msm/msm_atomic.c
> b/drivers/gpu/drm/msm/msm_atomic.c
> > index 645fe53..f8141bb 100644
> > --- a/drivers/gpu/drm/msm/msm_atomic.c
> > +++ b/drivers/gpu/drm/msm/msm_atomic.c
> > @@ -192,6 +192,9 @@ int msm_atomic_check(struct drm_device *dev,
> struct drm_atomic_state *state)
> > new_crtc_state->mode_changed = true;
> > state->allow_modeset = true;
> > }
> > +
> > +   if (old_crtc_state->self_refresh_active && new_crtc_state-
> >self_refresh_active)
> > +   return -EINVAL;
> 
> EINVAL here means that atomic_check will fail if both old and new
> states are in SR mode. For example, there might be a mode set for
> another CRTC (while keeping this one in SR mode). I don't think this
> is correct. We should skip/shortcut the commit, that's true. But I
> doubt that returning an error here is a proper way to do this. Please
> correct me if I'm wrong.

If there is a modeset on same crtc with a different connector. The 
new_crtc_state will not have self_refresh_active set.
Self_refresh_active is set from the helper library, which will duplicate the 
old_state and just adds self_refresh_active to true and active to false.
so we can be confident that if we are checking for self_refresh_active status 
then it should be coming from the library call.

Also the EINVAL is returned to the self_refresh library API and the function 
will be retired.
And self_refresh_active is cleared on every commit : 
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/gpu/drm/drm_atomic_state_helper.c#n158

The above is true for different crtc as well.
please let me know your comments.

Thanks,
Vinod.
 


[Freedreno] [PATCH v1 3/3] msm: skip the atomic commit of self refresh while PSR running

2023-03-31 Thread Vinod Polimera
In certain CPU stress conditions, there can be a delay in scheduling commit
work and it was observed that PSR commit from a different work queue was 
scheduled. Avoid these commits as display is already in PSR mode.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/msm_atomic.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 645fe53..f8141bb 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -192,6 +192,9 @@ int msm_atomic_check(struct drm_device *dev, struct 
drm_atomic_state *state)
new_crtc_state->mode_changed = true;
state->allow_modeset = true;
}
+
+   if (old_crtc_state->self_refresh_active && 
new_crtc_state->self_refresh_active)
+   return -EINVAL;
}
 
return drm_atomic_helper_check(dev, state);
-- 
2.7.4



[Freedreno] [PATCH v1 2/3] msm/disp/dpu: allow atomic_check in PSR usecase

2023-03-31 Thread Vinod Polimera
Certain flags like dirty_fb will be updated into the plane state
during crtc atomic_check. Allow those updates during PSR commit.

Reported-by: Bjorn Andersson 
Link: https://lore.kernel.org/all/20230326162723.3lo6pnsfdwzsvbhj@ripper/
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 96f645e..a02c7f4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1185,7 +1185,7 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
 
bool needs_dirtyfb = dpu_crtc_needs_dirtyfb(crtc_state);
 
-   if (!crtc_state->enable || !crtc_state->active) {
+   if (!crtc_state->enable || 
!drm_atomic_crtc_effectively_active(crtc_state)) {
DRM_DEBUG_ATOMIC("crtc%d -> enable %d, active %d, skip 
atomic_check\n",
crtc->base.id, crtc_state->enable,
crtc_state->active);
-- 
2.7.4



[Freedreno] [PATCH v1 1/3] drm/msm/dpu: set dirty_fb flag while in self refresh mode

2023-03-31 Thread Vinod Polimera
While in virtual terminal mode with PSR enabled, there will be
no atomic commits triggered without dirty_fb being set. This
will create a notion of no screen update. Allow atomic commit
when dirty_fb ioctl is issued, so that it can trigger a PSR exit
and shows update on the screen.

Reported-by: Bjorn Andersson 
Link: https://lore.kernel.org/all/20230326162723.3lo6pnsfdwzsvbhj@ripper/
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index ab636da..96f645e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1158,6 +1158,9 @@ static bool dpu_crtc_needs_dirtyfb(struct drm_crtc_state 
*cstate)
struct drm_crtc *crtc = cstate->crtc;
struct drm_encoder *encoder;
 
+   if (cstate->self_refresh_active)
+   return true;
+
drm_for_each_encoder_mask (encoder, crtc->dev, cstate->encoder_mask) {
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_CMD) {
return true;
-- 
2.7.4



[Freedreno] [PATCH v1 0/3] Fixes for PSR

2023-03-31 Thread Vinod Polimera
while in virtual terminal with PSR enabled, there will be
no atomic commits triggered resulting in no screen update.
Update the dirtyfb flag into plane state during atomic check 
to flush the pixel data explicitly.

Avoid scheduling PSR commits from different work queues while
running in PSR mode already.

Vinod Polimera (3):
  drm/msm/dpu: set dirty_fb flag while in self refresh mode
  msm/disp/dpu: allow atomic_check in PSR usecase
  msm: skip the atomic commit of self refresh while PSR running

 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 5 -
 drivers/gpu/drm/msm/msm_atomic.c | 3 +++
 2 files changed, 7 insertions(+), 1 deletion(-)

-- 
2.7.4



Re: [Freedreno] [PATCH v14 14/14] drm/msm/dp: set self refresh aware based on PSR support

2023-03-30 Thread Vinod Polimera


> -Original Message-
> From: Doug Anderson 
> Sent: Thursday, March 30, 2023 7:54 PM
> To: Vinod Polimera 
> Cc: Stephen Boyd ; Bjorn Andersson
> ; Vinod Polimera (QUIC)
> ; robdcl...@gmail.com; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; linux-
> ker...@vger.kernel.org; Kalyan Thota (QUIC) ;
> dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v14 14/14] drm/msm/dp: set self refresh aware based
> on PSR support
> 
> 
> Hi,
> 
> On Wed, Mar 29, 2023 at 8:47 AM Doug Anderson
>  wrote:
> >
> > Hi,
> >
> > On Wed, Mar 29, 2023 at 8:16 AM Vinod Polimera
> >  wrote:
> > >
> > >
> > >
> > > > -----Original Message-
> > > > From: Stephen Boyd 
> > > > Sent: Monday, March 27, 2023 9:58 PM
> > > > To: Bjorn Andersson ; Vinod Polimera (QUIC)
> > > > 
> > > > Cc: dri-de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> > > > freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; linux-
> > > > ker...@vger.kernel.org; robdcl...@gmail.com;
> diand...@chromium.org;
> > > > Kalyan Thota (QUIC) ;
> > > > dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> > > > ; Vishnuvardhan Prodduturi (QUIC)
> > > > ; Bjorn Andersson (QUIC)
> > > > ; Abhinav Kumar (QUIC)
> > > > ; Sankeerth Billakanti (QUIC)
> > > > 
> > > > Subject: Re: [PATCH v14 14/14] drm/msm/dp: set self refresh aware
> based
> > > > on PSR support
> > > >
> > > > Quoting Bjorn Andersson (2023-03-26 09:35:56)
> > > > > On Sun, Mar 26, 2023 at 09:27:23AM -0700, Bjorn Andersson wrote:
> > > > > > On Thu, Mar 02, 2023 at 10:03:17PM +0530, Vinod Polimera wrote:
> > > > > > > For the PSR to kick in, self_refresh_aware has to be set.
> > > > > > > Initialize it based on the PSR support for the eDP interface.
> > > > > > >
> > > > > >
> > > > > > When I boot my sc8280xp devices (CRD and X13s) to console with
> this
> > > > > > patch included I get a login prompt, and then there are no more
> screen
> > > > > > updates.
> > > > > >
> > > > > > Switching virtual terminal (ctrl+alt+fN) causes the screen to 
> > > > > > redraw.
> > > > > >
> > > > > > Blindly login in and launching Wayland works and from then on
> screen
> > > > > > updates works as expected.
> > > > > >
> > > > > > Switching from Wayland to another virtual terminal causes the
> problem
> > > > to
> > > > > > re-appear, no updates after the initial refresh, switching back go 
> > > > > > the
> > > > > > Wayland-terminal crashed the machine.
> > > > > >
> > > > >
> > > > > Also, trying to bring the eDP-screen back from DPMS gives me:
> > > > >
> > > > > <3>[ 2355.218099] [drm:dp_catalog_ctrl_set_pattern_state_bit
> [msm]]
> > > > *ERROR* set state_bit for link_train=1 failed
> > > > > <3>[ 2355.218926] [drm:dp_ctrl_setup_main_link [msm]] *ERROR*
> link
> > > > training #1 failed. ret=-110
> > > > > <3>[ 2355.262859] [drm:dp_catalog_ctrl_set_pattern_state_bit
> [msm]]
> > > > *ERROR* set state_bit for link_train=1 failed
> > > > > <3>[ 2355.263600] [drm:dp_ctrl_setup_main_link [msm]] *ERROR*
> link
> > > > training #1 failed. ret=-110
> > > > > <3>[ 2355.305211] [drm:dp_catalog_ctrl_set_pattern_state_bit
> [msm]]
> > > > *ERROR* set state_bit for link_train=1 failed
> > > > > <3>[ 2355.305955] [drm:dp_ctrl_setup_main_link [msm]] *ERROR*
> link
> > > > training #1 failed. ret=-110
> > > > > <3>[ 2355.345250] [drm:dp_catalog_ctrl_set_pattern_state_bit
> [msm]]
> > > > *ERROR* set state_bit for link_train=1 failed
> > > > > <3>[ 2355.346026] [drm:dp_ctrl_setup_main_link [msm]] *ERROR*
> link
> > > > training #1 failed. ret=-110
> > > > > <3>[ 2355.405650] [drm:dp_display_process_hpd_high [msm]]
> *ERROR*
> > > > failed to comp

Re: [Freedreno] [PATCH v14 14/14] drm/msm/dp: set self refresh aware based on PSR support

2023-03-29 Thread Vinod Polimera


> -Original Message-
> From: Stephen Boyd 
> Sent: Monday, March 27, 2023 9:58 PM
> To: Bjorn Andersson ; Vinod Polimera (QUIC)
> 
> Cc: dri-de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> Kalyan Thota (QUIC) ;
> dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v14 14/14] drm/msm/dp: set self refresh aware based
> on PSR support
>  
> Quoting Bjorn Andersson (2023-03-26 09:35:56)
> > On Sun, Mar 26, 2023 at 09:27:23AM -0700, Bjorn Andersson wrote:
> > > On Thu, Mar 02, 2023 at 10:03:17PM +0530, Vinod Polimera wrote:
> > > > For the PSR to kick in, self_refresh_aware has to be set.
> > > > Initialize it based on the PSR support for the eDP interface.
> > > >
> > >
> > > When I boot my sc8280xp devices (CRD and X13s) to console with this
> > > patch included I get a login prompt, and then there are no more screen
> > > updates.
> > >
> > > Switching virtual terminal (ctrl+alt+fN) causes the screen to redraw.
> > >
> > > Blindly login in and launching Wayland works and from then on screen
> > > updates works as expected.
> > >
> > > Switching from Wayland to another virtual terminal causes the problem
> to
> > > re-appear, no updates after the initial refresh, switching back go the
> > > Wayland-terminal crashed the machine.
> > >
> >
> > Also, trying to bring the eDP-screen back from DPMS gives me:
> >
> > <3>[ 2355.218099] [drm:dp_catalog_ctrl_set_pattern_state_bit [msm]]
> *ERROR* set state_bit for link_train=1 failed
> > <3>[ 2355.218926] [drm:dp_ctrl_setup_main_link [msm]] *ERROR* link
> training #1 failed. ret=-110
> > <3>[ 2355.262859] [drm:dp_catalog_ctrl_set_pattern_state_bit [msm]]
> *ERROR* set state_bit for link_train=1 failed
> > <3>[ 2355.263600] [drm:dp_ctrl_setup_main_link [msm]] *ERROR* link
> training #1 failed. ret=-110
> > <3>[ 2355.305211] [drm:dp_catalog_ctrl_set_pattern_state_bit [msm]]
> *ERROR* set state_bit for link_train=1 failed
> > <3>[ 2355.305955] [drm:dp_ctrl_setup_main_link [msm]] *ERROR* link
> training #1 failed. ret=-110
> > <3>[ 2355.345250] [drm:dp_catalog_ctrl_set_pattern_state_bit [msm]]
> *ERROR* set state_bit for link_train=1 failed
> > <3>[ 2355.346026] [drm:dp_ctrl_setup_main_link [msm]] *ERROR* link
> training #1 failed. ret=-110
> > <3>[ 2355.405650] [drm:dp_display_process_hpd_high [msm]] *ERROR*
> failed to complete DP link training
> > <3>[ 2355.668988]
> [drm:dpu_encoder_phys_vid_wait_for_commit_done:488] [dpu
> error]vblank timeout
> > <3>[ 2355.669030] [drm:dpu_kms_wait_for_commit_done:510] [dpu
> error]wait for commit done returned -110
> > <3>[ 2355.699989] [drm:dpu_encoder_frame_done_timeout:2398] [dpu
> error]enc35 frame done timeout
> >
> > And then the machine just resets.
> >
> 
> I saw similar behavior on ChromeOS after we picked the PSR patches into
> our kernel. I suspect it's the same problem. I switched back and forth
> between VT2 and the OOBE screen with ctrl+alt+forward and that showed
> what I typed on the virtual terminal after switching back and forth.
> It's like the redraw only happens once on the switch and never again. I
> switched back and forth enough times that it eventually crashed the
> kernel and rebooted. This was on CRD (sc7280-herobrine-crd.dts).
> 
> There's an animation on the OOBE screen that is working though, so
> perhaps PSR is working with the chrome compositor but not the virtual
> terminal? I haven't investigated.

I was able to reproduce the issue where in virtual terminal, I don't see any 
screen refresh despite typing in.
In the VT mode, I see that PSR is entered, but despite typing in there are no 
atomic commits triggered, hence the last buffer was always refreshed.

Queries from my side to Rob & Doug:
1) In VT mode, does the framework operates in single buffer mode without any 
commit for new updates ?
2) if above is true then, how does driver know if the framework operates in 
single buffer mode, to make any appropriate action
3) what is the expected behavior with the driver here ? should it return 
atomic_check failure, for single buffer mode operation or, it should exit PSR ?
4) is there any HINT passed down to the driver so that we can bank on it and 
act accordingly?

Thanks,
Vinod P.

 


Re: [Freedreno] [PATCH v14 13/14] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-03-14 Thread Vinod Polimera



> -Original Message-
> From: Vinod Polimera (QUIC) 
> Sent: Thursday, March 2, 2023 10:03 PM
> To: dri-de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> Cc: Vinod Polimera (QUIC) ; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> swb...@chromium.org; Kalyan Thota (QUIC) ;
> dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: [PATCH v14 13/14] drm/msm/disp/dpu: update dpu_enc crtc state
> on crtc enable/disable during self refresh
> 
> Populate the enocder software structure to reflect the updated
> crtc appropriately during crtc enable/disable for a new commit
> while taking care of the self refresh transitions when crtc
> disable is triggered from the drm self refresh library.
> 
> Signed-off-by: Vinod Polimera 

Reviewed-by: Dmitry Baryshkov 

Adding the RB tag which was reviewed by Dmitry on V13.

> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 29
> +
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> index 60e5984..b1ec0c3 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> @@ -1022,8 +1022,17 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
> 
>   DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
> 
> - if (old_crtc_state->self_refresh_active)
> + /* If disable is triggered while in self refresh mode,
> +  * reset the encoder software state so that in enable
> +  * it won't trigger a warn while assigning crtc.
> +  */
> + if (old_crtc_state->self_refresh_active) {
> + drm_for_each_encoder_mask(encoder, crtc->dev,
> + old_crtc_state->encoder_mask) {
> + dpu_encoder_assign_crtc(encoder, NULL);
> + }
>   return;
> + }
> 
>   /* Disable/save vblank irq handling */
>   drm_crtc_vblank_off(crtc);
> @@ -1036,7 +1045,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
>*/
>   if (dpu_encoder_get_intf_mode(encoder) ==
> INTF_MODE_VIDEO)
>   release_bandwidth = true;
> - dpu_encoder_assign_crtc(encoder, NULL);
> +
> + /*
> +  * If disable is triggered during psr active(e.g: screen dim in
> PSR),
> +  * we will need encoder->crtc connection to process the
> device sleep &
> +  * preserve it during psr sequence.
> +  */
> + if (!crtc->state->self_refresh_active)
> + dpu_encoder_assign_crtc(encoder, NULL);
>   }
> 
>   /* wait for frame_event_done completion */
> @@ -1084,6 +1100,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
>   struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
>   struct drm_encoder *encoder;
>   bool request_bandwidth = false;
> + struct drm_crtc_state *old_crtc_state;
> +
> + old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
> 
>   pm_runtime_get_sync(crtc->dev->dev);
> 
> @@ -1106,8 +1125,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
>   trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
>   dpu_crtc->enabled = true;
> 
> - drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state-
> >encoder_mask)
> - dpu_encoder_assign_crtc(encoder, crtc);
> + if (!old_crtc_state->self_refresh_active) {
> + drm_for_each_encoder_mask(encoder, crtc->dev, crtc-
> >state->encoder_mask)
> + dpu_encoder_assign_crtc(encoder, crtc);
> + }
> 
>   /* Enable/restore vblank irq handling */
>   drm_crtc_vblank_on(crtc);
> --
> 2.7.4



Re: [Freedreno] [PATCH v13 00/13] Add PSR support for eDP

2023-03-02 Thread Vinod Polimera


> -Original Message-
> From: Doug Anderson 
> Sent: Thursday, March 2, 2023 2:02 AM
> To: Vinod Polimera (QUIC) 
> Cc: dri-de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; swb...@chromium.org;
> Kalyan Thota (QUIC) ;
> dmitry.barysh...@linaro.org; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v13 00/13] Add PSR support for eDP
> 
> Hi,
> 
> On Wed, Mar 1, 2023 at 11:06 AM Doug Anderson
>  wrote:
> >
> > Hi,
> >
> > On Sun, Feb 12, 2023 at 8:29 AM Vinod Polimera
> >  wrote:
> > >
> > > Changes in v2:
> > >   - Use dp bridge to set psr entry/exit instead of dpu_enocder.
> > >   - Don't modify whitespaces.
> > >   - Set self refresh aware from atomic_check.
> > >   - Set self refresh aware only if psr is supported.
> > >   - Provide a stub for msm_dp_display_set_psr.
> > >   - Move dp functions to bridge code.
> > >
> > > Changes in v3:
> > >   - Change callback names to reflect atomic interfaces.
> > >   - Move bridge callback change to separate patch as suggested by Dmitry.
> > >   - Remove psr function declaration from msm_drv.h.
> > >   - Set self_refresh_aware flag only if psr is supported.
> > >   - Modify the variable names to simpler form.
> > >   - Define bit fields for PSR settings.
> > >   - Add comments explaining the steps to enter/exit psr.
> > >   - Change DRM_INFO to drm_dbg_db.
> > >
> > > Changes in v4:
> > >   - Move the get crtc functions to drm_atomic.
> > >   - Add atomic functions for DP bridge too.
> > >   - Add ternary operator to choose eDP or DP ops.
> > >   - Return true/false instead of 1/0.
> > >   - mode_valid missing in the eDP bridge ops.
> > >   - Move the functions to get crtc into drm_atomic.c.
> > >   - Fix compilation issues.
> > >   - Remove dpu_assign_crtc and get crtc from drm_enc instead of
> dpu_enc.
> > >   - Check for crtc state enable while reserving resources.
> > >
> > > Changes in v5:
> > >   - Move the mode_valid changes into a different patch.
> > >   - Complete psr_op_comp only when isr is set.
> > >   - Move the DP atomic callback changes to a different patch.
> > >   - Get crtc from drm connector state crtc.
> > >   - Move to separate patch for check for crtc state enable while
> > > reserving resources.
> > >
> > > Changes in v6:
> > >   - Remove crtc from dpu_encoder_virt struct.
> > >   - fix crtc check during vblank toggle crtc.
> > >   - Misc changes.
> > >
> > > Changes in v7:
> > >   - Add fix for underrun issue on kasan build.
> > >
> > > Changes in v8:
> > >   - Drop the enc spinlock as it won't serve any purpose in
> > > protetcing conn state.(Dmitry/Doug)
> > >
> > > Changes in v9:
> > >   - Update commit message and fix alignment using spaces.(Marijn)
> > >   - Misc changes.(Marijn)
> > >
> > > Changes in v10:
> > >   - Get crtc cached in dpu_enc during obj init.(Dmitry)
> > >
> > > Changes in v11:
> > >   - Remove crtc cached in dpu_enc during obj init.
> > >   - Update dpu_enc crtc state on crtc enable/disable during self refresh.
> > >
> > > Changes in v12:
> > >   - Update sc7180 intf mask to get intf timing gen status
> > > based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
> > >   - Remove "clear active interface in the datapath cleanup" change
> > > as it is already included.
> > >
> > > Changes in v13:
> > >   - Move core changes to top of the series.(Dmitry)
> > >   - Drop self refresh aware disable change after psr entry.(Dmitry)
> > >
> > > Vinod Polimera (13):
> > >   drm: add helper functions to retrieve old and new crtc
> > >   drm/bridge: use atomic enable/disable callbacks for panel bridge
> > >   drm/bridge: add psr support for panel bridge callbacks
> > >   drm/msm/disp/dpu: check for crtc enable rather than crtc active to
> > > release shared resources
> > >   drm/msm/disp/dpu: get timing engine status from intf status register
> > >   drm/msm/disp/dpu: wait for extra vsync till timing engine status is
> > > disabled
> > >   drm/msm/disp/dpu: reset 

[Freedreno] [PATCH v14 14/14] drm/msm/dp: set self refresh aware based on PSR support

2023-03-02 Thread Vinod Polimera
For the PSR to kick in, self_refresh_aware has to be set.
Initialize it based on the PSR support for the eDP interface.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/dp/dp_drm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 029e08c..785d766 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -117,6 +117,8 @@ static int edp_bridge_atomic_check(struct drm_bridge 
*drm_bridge,
if (WARN_ON(!conn_state))
return -ENODEV;
 
+   conn_state->self_refresh_aware = dp->psr_supported;
+
if (!conn_state->crtc || !crtc_state)
return 0;
 
-- 
2.7.4



[Freedreno] [PATCH v14 13/14] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-03-02 Thread Vinod Polimera
Populate the enocder software structure to reflect the updated
crtc appropriately during crtc enable/disable for a new commit
while taking care of the self refresh transitions when crtc
disable is triggered from the drm self refresh library.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 60e5984..b1ec0c3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1022,8 +1022,17 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-   if (old_crtc_state->self_refresh_active)
+   /* If disable is triggered while in self refresh mode,
+* reset the encoder software state so that in enable
+* it won't trigger a warn while assigning crtc.
+*/
+   if (old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   old_crtc_state->encoder_mask) {
+   dpu_encoder_assign_crtc(encoder, NULL);
+   }
return;
+   }
 
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
@@ -1036,7 +1045,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
+
+   /*
+* If disable is triggered during psr active(e.g: screen dim in 
PSR),
+* we will need encoder->crtc connection to process the device 
sleep &
+* preserve it during psr sequence.
+*/
+   if (!crtc->state->self_refresh_active)
+   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1084,6 +1100,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct drm_encoder *encoder;
bool request_bandwidth = false;
+   struct drm_crtc_state *old_crtc_state;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 
pm_runtime_get_sync(crtc->dev->dev);
 
@@ -1106,8 +1125,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
+   if (!old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask)
+   dpu_encoder_assign_crtc(encoder, crtc);
+   }
 
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
-- 
2.7.4



[Freedreno] [PATCH v14 12/14] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-03-02 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index f29a339..60e5984 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1021,6 +1022,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1577,7 +1581,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1614,6 +1618,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 01b7509..450abb1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1212,11 +1213,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index a683bd9..681dd2e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v14 11/14] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2023-03-02 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index c237003..01b7509 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1171,7 +1171,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1207,7 +1208,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2388,8 +2390,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v14 09/14] drm/msm/dp: Add basic PSR support for eDP

2023-03-02 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644

[Freedreno] [PATCH v14 10/14] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2023-03-02 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 86ed80c..ffb21a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -996,14 +996,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 3b38bd9..029e08c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -226,12 +226,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH v14 08/14] drm/msm/dp: use atomic callbacks for DP bridge ops

2023-03-02 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +++---
 drivers/gpu/drm/msm/dp/dp_drm.h | 9 ++---
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..985287e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1652,7 +1652,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1707,7 +1708,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1718,7 +1720,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 275370f..3252d50 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,9 +94,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
.atomic_reset   = drm_atomic_helper_bridge_reset,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid   = dp_bridge_mode_valid,
.get_modes= dp_bridge_get_modes,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 250f7c6..afe79b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH v14 07/14] drm/msm/disp/dpu: reset the datapath after timing engine disable

2023-03-02 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0396084..3a37429 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -588,6 +588,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v14 06/14] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2023-03-02 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..0396084 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v14 04/14] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2023-03-02 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 758261e..c237003 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -652,7 +652,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v14 05/14] drm/msm/disp/dpu: get timing engine status from intf status register

2023-03-02 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index cf053e8..85b29d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -78,7 +78,8 @@
 
 #define INTF_SDM845_MASK (0)
 
-#define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
+#define INTF_SC7180_MASK \
+   (BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index ddab9ca..08cd1a1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -213,17 +213,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v14 03/14] drm/bridge: add psr support for panel bridge callbacks

2023-03-02 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 04e9fb0..a2c6f30 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v14 01/14] drm: add helper functions to retrieve old and new crtc

2023-03-02 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5457c02..7cc39f6 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(const struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 92586ab..9a022ca 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH v14 02/14] drm/bridge: use atomic enable/disable callbacks for panel bridge

2023-03-02 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index e8aae3c..04e9fb0 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH v14 00/14] Add PSR support for eDP

2023-03-02 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - Get crtc cached in dpu_enc during obj init.(Dmitry)

Changes in v11:
  - Remove crtc cached in dpu_enc during obj init.
  - Update dpu_enc crtc state on crtc enable/disable during self refresh.

Changes in v12:
  - Update sc7180 intf mask to get intf timing gen status
based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
  - Remove "clear active interface in the datapath cleanup" change
as it is already included.

Changes in v13:
  - Move core changes to top of the series.(Dmitry)
  - Drop self refresh aware disable change after psr entry.(Dmitry)

Changes in v14:
  - Set self_refresh_aware for the PSR to kick in.

Vinod Polimera (14):
  drm: add helper functions to retrieve old and new crtc
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
during self refresh
  drm/msm/dp: set self refresh aware based on psr support

 drivers/gpu/drm/bridge/panel.c |  68 +++-
 drivers/gpu/drm/drm_atomic.c   |  60 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  40 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  26 +++-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   2 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 +++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 173 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 +
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 683 insertions(+), 43 deletions(-)

-- 
2.7.4



[Freedreno] [PATCH v13 13/13] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-02-12 Thread Vinod Polimera
Populate the enocder software structure to reflect the updated
crtc appropriately during crtc enable/disable for a new commit
while taking care of the self refresh transitions when crtc
disable is triggered from the drm self refresh library.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 60e5984..b1ec0c3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1022,8 +1022,17 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-   if (old_crtc_state->self_refresh_active)
+   /* If disable is triggered while in self refresh mode,
+* reset the encoder software state so that in enable
+* it won't trigger a warn while assigning crtc.
+*/
+   if (old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   old_crtc_state->encoder_mask) {
+   dpu_encoder_assign_crtc(encoder, NULL);
+   }
return;
+   }
 
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
@@ -1036,7 +1045,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
+
+   /*
+* If disable is triggered during psr active(e.g: screen dim in 
PSR),
+* we will need encoder->crtc connection to process the device 
sleep &
+* preserve it during psr sequence.
+*/
+   if (!crtc->state->self_refresh_active)
+   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1084,6 +1100,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct drm_encoder *encoder;
bool request_bandwidth = false;
+   struct drm_crtc_state *old_crtc_state;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 
pm_runtime_get_sync(crtc->dev->dev);
 
@@ -1106,8 +1125,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
+   if (!old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask)
+   dpu_encoder_assign_crtc(encoder, crtc);
+   }
 
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
-- 
2.7.4



[Freedreno] [PATCH v13 12/13] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-02-12 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index f29a339..60e5984 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1021,6 +1022,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1577,7 +1581,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1614,6 +1618,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 01b7509..450abb1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1212,11 +1213,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index a683bd9..681dd2e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v13 11/13] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2023-02-12 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index c237003..01b7509 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1171,7 +1171,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1207,7 +1208,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2388,8 +2390,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v13 10/13] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2023-02-12 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 86ed80c..ffb21a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -996,14 +996,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 3b38bd9..029e08c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -226,12 +226,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH v13 09/13] drm/msm/dp: Add basic PSR support for eDP

2023-02-12 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644

[Freedreno] [PATCH v13 08/13] drm/msm/dp: use atomic callbacks for DP bridge ops

2023-02-12 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +++---
 drivers/gpu/drm/msm/dp/dp_drm.h | 9 ++---
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..985287e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1652,7 +1652,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1707,7 +1708,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1718,7 +1720,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 275370f..3252d50 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,9 +94,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
.atomic_reset   = drm_atomic_helper_bridge_reset,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid   = dp_bridge_mode_valid,
.get_modes= dp_bridge_get_modes,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 250f7c6..afe79b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH v13 07/13] drm/msm/disp/dpu: reset the datapath after timing engine disable

2023-02-12 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0396084..3a37429 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -588,6 +588,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v13 05/13] drm/msm/disp/dpu: get timing engine status from intf status register

2023-02-12 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index cf053e8..85b29d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -78,7 +78,8 @@
 
 #define INTF_SDM845_MASK (0)
 
-#define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
+#define INTF_SC7180_MASK \
+   (BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index ddab9ca..08cd1a1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -213,17 +213,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v13 06/13] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2023-02-12 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..0396084 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v13 04/13] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2023-02-12 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 758261e..c237003 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -652,7 +652,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v13 03/13] drm/bridge: add psr support for panel bridge callbacks

2023-02-12 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 04e9fb0..a2c6f30 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v13 02/13] drm/bridge: use atomic enable/disable callbacks for panel bridge

2023-02-12 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index e8aae3c..04e9fb0 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH v13 01/13] drm: add helper functions to retrieve old and new crtc

2023-02-12 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5457c02..7cc39f6 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(const struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 92586ab..9a022ca 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH v13 00/13] Add PSR support for eDP

2023-02-12 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - Get crtc cached in dpu_enc during obj init.(Dmitry)

Changes in v11:
  - Remove crtc cached in dpu_enc during obj init.
  - Update dpu_enc crtc state on crtc enable/disable during self refresh.

Changes in v12:
  - Update sc7180 intf mask to get intf timing gen status
based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
  - Remove "clear active interface in the datapath cleanup" change
as it is already included.

Changes in v13:
  - Move core changes to top of the series.(Dmitry)
  - Drop self refresh aware disable change after psr entry.(Dmitry)

Vinod Polimera (13):
  drm: add helper functions to retrieve old and new crtc
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
during self refresh

 drivers/gpu/drm/bridge/panel.c |  68 +++-
 drivers/gpu/drm/drm_atomic.c   |  60 
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  40 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  26 +++-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   2 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 +++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 171 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 +
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 681 insertions(+), 43 deletions(-)

-- 
2.7.4



Re: [Freedreno] [PATCH v12 09/14] drm/msm/dp: disable self_refresh_aware after entering psr

2023-02-07 Thread Vinod Polimera


> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Tuesday, January 31, 2023 6:19 PM
> To: Vinod Polimera (QUIC) ; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> Cc: Sankeerth Billakanti (QUIC) ; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> swb...@chromium.org; Kalyan Thota (QUIC) ;
> Kuogee Hsieh (QUIC) ; Vishnuvardhan
> Prodduturi (QUIC) ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> 
> Subject: Re: [PATCH v12 09/14] drm/msm/dp: disable self_refresh_aware
> after entering psr
>  
> On 30/01/2023 17:11, Vinod Polimera wrote:
> > From: Sankeerth Billakanti 
> >
> > Updated frames get queued if self_refresh_aware is set when the
> > sink is in psr. To support bridge enable and avoid queuing of update
> > frames, reset the self_refresh_aware state after entering psr.
> >
> > Signed-off-by: Sankeerth Billakanti 
> > Signed-off-by: Vinod Polimera 
> > ---
> >   drivers/gpu/drm/msm/dp/dp_drm.c | 25 -
> >   1 file changed, 24 insertions(+), 1 deletion(-)
> 
> As I stated in v11's discussion, I do not like the way this change plays
> with the self_refresh_aware. Please find another way to work around the
> timing issue (let's probably continue the discussion back in v11).
> 
Currently we are not able to reproduce the issue with KASAN enabled and minimum 
cpu frequency builds.
We can revisit this patch if it is reproduced in future. Meanwhile I think on 
handling it in a different way.
Can we not consider this patch for current merge?

> --
> With best wishes
> Dmitry

Thanks,
Vinod P.


Re: [Freedreno] [PATCH v12 13/14] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-02-07 Thread Vinod Polimera


> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Tuesday, January 31, 2023 6:29 PM
> To: Vinod Polimera (QUIC) ; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> Cc: linux-ker...@vger.kernel.org; robdcl...@gmail.com;
> diand...@chromium.org; swb...@chromium.org; Kalyan Thota (QUIC)
> ; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v12 13/14] drm/msm/disp/dpu: add PSR support for eDP
> interface in dpu driver
> 
> 
> On 30/01/2023 17:11, Vinod Polimera wrote:
> > Enable PSR on eDP interface using drm self-refresh librabry.
> > This patch uses a trigger from self-refresh library to enter/exit
> > into PSR, when there are no updates from framework.
> >
> > Signed-off-by: Kalyan Thota 
> > Signed-off-by: Vinod Polimera 
> > Reviewed-by: Dmitry Baryshkov 
> > ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
> >   3 files changed, 27 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index f29a339..60e5984 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -21,6 +21,7 @@
> >   #include 
> >   #include 
> >   #include 
> > +#include 
> >
> >   #include "dpu_kms.h"
> >   #include "dpu_hw_lm.h"
> > @@ -1021,6 +1022,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
> >
> >   DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
> >
> > + if (old_crtc_state->self_refresh_active)
> > + return;
> > +
> 
> I have been looking at the crtc_needs_disable(). It explicitly mentions
> that 'We also need to run through the crtc_funcs->disable() function
> [..] if it's transitioning to self refresh mode...'. Don't we need to
> perform some cleanup here (like disabling the vblank irq handling,
> freeing the bandwidth, etc)?

When self refresh active is enabled, then we will clean up irq handling and 
bandwidth etc.
The above case is to handle display off commit triggered when we are in psr as 
all
 the resources are already cleaned up . we just need to do an early return.
> 
> >   /* Disable/save vblank irq handling */
> >   drm_crtc_vblank_off(crtc);
> >
> > @@ -1577,7 +1581,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device
> *dev, struct drm_plane *plane,
> >   {
> >   struct drm_crtc *crtc = NULL;
> >   struct dpu_crtc *dpu_crtc = NULL;
> > - int i;
> > + int i, ret;
> >
> >   dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
> >   if (!dpu_crtc)
> > @@ -1614,6 +1618,13 @@ struct drm_crtc *dpu_crtc_init(struct
> drm_device *dev, struct drm_plane *plane,
> >   /* initialize event handling */
> >   spin_lock_init(_crtc->event_lock);
> >
> > + ret = drm_self_refresh_helper_init(crtc);
> > + if (ret) {
> > + DPU_ERROR("Failed to initialize %s with self-refresh helpers 
> > %d\n",
> > + crtc->name, ret);
> > + return ERR_PTR(ret);
> > + }
> > +
> >   DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc-
> >name);
> >   return crtc;
> >   }
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > index 01b7509..450abb1 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > @@ -12,6 +12,7 @@
> >   #include 
> >   #include 
> >
> > +#include 
> >   #include 
> >   #include 
> >   #include 
> > @@ -1212,11 +1213,24 @@ static void
> dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
> >   struct drm_atomic_state *state)
> >   {
> >   struct dpu_encoder_virt *dpu_enc = NULL;
> > + struct drm_crtc *crtc;
> > + struct drm_crtc_state *old_state = NULL;
> >   int i = 0;
> >
> >   dpu_enc = to_dpu_encoder_virt(drm_enc);
> >   DPU_DEBUG_ENC(dpu_enc, "\n");
> >
> > + crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
> &

[Freedreno] [PATCH v12 11/14] drm/bridge: add psr support for panel bridge callbacks

2023-01-30 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 04e9fb0..a2c6f30 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v12 13/14] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-01-30 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index f29a339..60e5984 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1021,6 +1022,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1577,7 +1581,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1614,6 +1618,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 01b7509..450abb1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1212,11 +1213,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index a683bd9..681dd2e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v12 14/14] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-01-30 Thread Vinod Polimera
Populate the enocder software structure to reflect the updated
crtc appropriately during crtc enable/disable for a new commit
while taking care of the self refresh transitions when crtc
disable is triggered from the drm self refresh library.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 29 +
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 60e5984..b1ec0c3 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1022,8 +1022,17 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-   if (old_crtc_state->self_refresh_active)
+   /* If disable is triggered while in self refresh mode,
+* reset the encoder software state so that in enable
+* it won't trigger a warn while assigning crtc.
+*/
+   if (old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   old_crtc_state->encoder_mask) {
+   dpu_encoder_assign_crtc(encoder, NULL);
+   }
return;
+   }
 
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
@@ -1036,7 +1045,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
+
+   /*
+* If disable is triggered during psr active(e.g: screen dim in 
PSR),
+* we will need encoder->crtc connection to process the device 
sleep &
+* preserve it during psr sequence.
+*/
+   if (!crtc->state->self_refresh_active)
+   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1084,6 +1100,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct drm_encoder *encoder;
bool request_bandwidth = false;
+   struct drm_crtc_state *old_crtc_state;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 
pm_runtime_get_sync(crtc->dev->dev);
 
@@ -1106,8 +1125,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
+   if (!old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask)
+   dpu_encoder_assign_crtc(encoder, crtc);
+   }
 
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
-- 
2.7.4



[Freedreno] [PATCH v12 12/14] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2023-01-30 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index c237003..01b7509 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1171,7 +1171,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1207,7 +1208,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2388,8 +2390,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v12 10/14] drm/bridge: use atomic enable/disable callbacks for panel bridge

2023-01-30 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index e8aae3c..04e9fb0 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH v12 09/14] drm/msm/dp: disable self_refresh_aware after entering psr

2023-01-30 Thread Vinod Polimera
From: Sankeerth Billakanti 

Updated frames get queued if self_refresh_aware is set when the
sink is in psr. To support bridge enable and avoid queuing of update
frames, reset the self_refresh_aware state after entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/dp/dp_drm.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 029e08c..01ca148b 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -134,6 +134,8 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *old_crtc_state;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
 
/*
 * Check the old state of the crtc to determine if the panel
@@ -150,10 +152,20 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
 
if (old_crtc_state && old_crtc_state->self_refresh_active) {
dp_display_set_psr(dp, false);
-   return;
+   goto psr_aware;
}
 
dp_bridge_atomic_enable(drm_bridge, old_bridge_state);
+
+psr_aware:
+   connector = drm_atomic_get_new_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
+
+   if (conn_state)
+   conn_state->self_refresh_aware = dp->psr_supported;
 }
 
 static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
@@ -164,6 +176,14 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
+
+   connector = drm_atomic_get_old_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
 
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state,
   drm_bridge->encoder);
@@ -190,6 +210,9 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
 * when display disable occurs while the sink is in psr state.
 */
if (new_crtc_state->self_refresh_active) {
+   if (conn_state)
+   conn_state->self_refresh_aware = false;
+
dp_display_set_psr(dp, true);
return;
} else if (old_crtc_state->self_refresh_active) {
-- 
2.7.4



[Freedreno] [PATCH v12 06/14] drm/msm/dp: use atomic callbacks for DP bridge ops

2023-01-30 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +++---
 drivers/gpu/drm/msm/dp/dp_drm.h | 9 ++---
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..985287e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1652,7 +1652,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1707,7 +1708,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1718,7 +1720,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 275370f..3252d50 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,9 +94,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
.atomic_reset   = drm_atomic_helper_bridge_reset,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid   = dp_bridge_mode_valid,
.get_modes= dp_bridge_get_modes,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 250f7c6..afe79b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH v12 08/14] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2023-01-30 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 86ed80c..ffb21a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -996,14 +996,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 3b38bd9..029e08c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -226,12 +226,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH v12 07/14] drm/msm/dp: Add basic PSR support for eDP

2023-01-30 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644

[Freedreno] [PATCH v12 05/14] drm: add helper functions to retrieve old and new crtc

2023-01-30 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5457c02..7cc39f6 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(const struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 92586ab..9a022ca 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH v12 04/14] drm/msm/disp/dpu: reset the datapath after timing engine disable

2023-01-30 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0396084..3a37429 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -588,6 +588,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v12 03/14] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2023-01-30 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..0396084 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v12 02/14] drm/msm/disp/dpu: get timing engine status from intf status register

2023-01-30 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  6 --
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index cf053e8..ce6e9e6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -78,9 +78,11 @@
 
 #define INTF_SDM845_MASK (0)
 
-#define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
+#define INTF_SC7180_MASK \
+   (BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
-#define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
+#define INTF_SC7280_MASK \
+   (INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN))
 
 #define IRQ_SDM845_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
 BIT(MDP_SSPP_TOP0_INTR2) | \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index ddab9ca..08cd1a1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -213,17 +213,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v12 01/14] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2023-01-30 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 758261e..c237003 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -652,7 +652,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v12 00/14] Add PSR support for eDP

2023-01-30 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - Get crtc cached in dpu_enc during obj init.(Dmitry)

Changes in v11:
  - Remove crtc cached in dpu_enc during obj init.
  - Update dpu_enc crtc state on crtc enable/disable during self refresh.

Changes in v12:
  - Update sc7180 intf mask to get intf timing gen status
based on DPU_INTF_STATUS_SUPPORTED bit.(Dmitry)
  - Remove "clear active interface in the datapath cleanup" change
as it is already included.
  - Move core changes to top of the series.(Dmitry)

Sankeerth Billakanti (1):
  drm/msm/dp: disable self_refresh_aware after entering psr

Vinod Polimera (13):
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm: add helper functions to retrieve old and new crtc
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
during self refresh

 drivers/gpu/drm/bridge/panel.c |  68 +++-
 drivers/gpu/drm/drm_atomic.c   |  60 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  40 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  26 ++-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   6 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   2 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 +
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 +
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 ++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 194 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 +++
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 706 insertions(+), 44 deletions(-)

-- 
2.7.4



Re: [Freedreno] [PATCH Resend v11 05/15] drm/msm/dp: disable self_refresh_aware after entering psr

2023-01-27 Thread Vinod Polimera
> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Tuesday, January 24, 2023 10:15 PM
> To: Vinod Polimera 
> Cc: Vinod Polimera (QUIC) ; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org; Sankeerth
> Billakanti (QUIC) ; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> swb...@chromium.org; Kalyan Thota (QUIC) ;
> Kuogee Hsieh (QUIC) ; Vishnuvardhan
> Prodduturi (QUIC) ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> 
> Subject: Re: [PATCH Resend v11 05/15] drm/msm/dp: disable
> self_refresh_aware after entering psr
> > 
> On Tue, 24 Jan 2023 at 17:10, Vinod Polimera 
> wrote:
> > > -Original Message-
> > > From: Dmitry Baryshkov 
> > > Sent: Tuesday, January 24, 2023 5:52 AM
> > > To: Vinod Polimera (QUIC) ; dri-
> > > de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> > > freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> > > Cc: Sankeerth Billakanti (QUIC) ; linux-
> > > ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> > > swb...@chromium.org; Kalyan Thota (QUIC)
> ;
> > > Kuogee Hsieh (QUIC) ; Vishnuvardhan
> > > Prodduturi (QUIC) ; Bjorn Andersson
> (QUIC)
> > > ; Abhinav Kumar (QUIC)
> > > 
> > > Subject: Re: [PATCH Resend v11 05/15] drm/msm/dp: disable
> > > self_refresh_aware after entering psr
> > >
> > >
> > > On 19/01/2023 16:26, Vinod Polimera wrote:
> > > > From: Sankeerth Billakanti 
> > > >
> > > > Updated frames get queued if self_refresh_aware is set when the
> > > > sink is in psr. To support bridge enable and avoid queuing of update
> > > > frames, reset the self_refresh_aware state after entering psr.
> > >
> > > I'm not convinced by this change. E.g. analogix code doesn't do this.
> > > Could you please clarify, why do you need to toggle the
> > > self_refresh_aware flag?
> > >
> > This was done to fix a bug reported by google. The use case is as follows:
> > CPU was running in a low frequency with debug build.
> > When self refresh was triggered by the library, due to system 
> > latency,
> the queued work was not scheduled.
> > There in another commit came and reinitialized the timer for the 
> > next
> PSR trigger.
> > This sequence happened multiple times  and we found there were
> multiple works which are stuck and yet to be run.
> 
> Where were workers stuck? Was it a busy loop around -EDEADLK /
> drm_modeset_backoff()? Also, what were ther ewma times for entry/exit
> avg times?
> 
It is not  an EDEADLK and return is successful.
Entry and exit times are proper but the work that is getting scheduled after 
timer expiry is happening very late.

> I'm asking because the issue that you are describing sounds like a
> generic one, not the driver-specific issue. And being generic it
> should be handled in a generic fascion, in drm_self_refresh_helper.c.
> 
> For example, I can imagine adding a variable to sr_data telling that
> the driver is in the process of transitioning to SR. Note: I did not
> perform a full research if it is a working solution or not. But from
> your description the driver really has to bail out early from
> drm_self_refresh_helper_entry_work().
> 
> > As PSR trigger is guarded by self_refresh_aware, we initialized the
> variable such that, if we are in PSR then until PSR exit, there cannot be any
> further PSR entry again.
> >
> https://chromium.googlesource.com/chromiumos/third_party/kernel/+/ref
> s/tags/v5.15.90/drivers/gpu/drm/drm_self_refresh_helper.c#105
> 
> Yes, and that's what triggered my attention. We are using a set of
> helpers, that depend on the self_refresh_aware being true. And
> suddenly under the hood we disable this flag. I'd say that I can not
> predict the effect this will have on the helpers library behaviour.
> 
> > This has solved few flicker issues during the stress testing.
> > > >
> > > > Signed-off-by: Sankeerth Billakanti 
> > > > Signed-off-by: Vinod Polimera 
> > > > ---
> > > >   drivers/gpu/drm/msm/dp/dp_drm.c | 27
> > > ++-
> > > >   1 file changed, 26 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c
> > > b/drivers/gpu/drm/msm/dp/dp_drm.c
> > > > index 029e08c..92d1a1b 100644
> > > > --- a/drivers/gpu/drm/msm/dp/dp_drm.c
> > > 

Re: [Freedreno] [PATCH Resend v11 05/15] drm/msm/dp: disable self_refresh_aware after entering psr

2023-01-24 Thread Vinod Polimera


> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Tuesday, January 24, 2023 5:52 AM
> To: Vinod Polimera (QUIC) ; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> Cc: Sankeerth Billakanti (QUIC) ; linux-
> ker...@vger.kernel.org; robdcl...@gmail.com; diand...@chromium.org;
> swb...@chromium.org; Kalyan Thota (QUIC) ;
> Kuogee Hsieh (QUIC) ; Vishnuvardhan
> Prodduturi (QUIC) ; Bjorn Andersson (QUIC)
> ; Abhinav Kumar (QUIC)
> 
> Subject: Re: [PATCH Resend v11 05/15] drm/msm/dp: disable
> self_refresh_aware after entering psr
> 
> WARNING: This email originated from outside of Qualcomm. Please be wary
> of any links or attachments, and do not enable macros.
> 
> On 19/01/2023 16:26, Vinod Polimera wrote:
> > From: Sankeerth Billakanti 
> >
> > Updated frames get queued if self_refresh_aware is set when the
> > sink is in psr. To support bridge enable and avoid queuing of update
> > frames, reset the self_refresh_aware state after entering psr.
> 
> I'm not convinced by this change. E.g. analogix code doesn't do this.
> Could you please clarify, why do you need to toggle the
> self_refresh_aware flag?
> 
This was done to fix a bug reported by google. The use case is as follows:
CPU was running in a low frequency with debug build.
When self refresh was triggered by the library, due to system latency, 
the queued work was not scheduled.
There in another commit came and reinitialized the timer for the next 
PSR trigger.
This sequence happened multiple times  and we found there were multiple 
works which are stuck and yet to be run.
As PSR trigger is guarded by self_refresh_aware, we initialized the 
variable such that, if we are in PSR then until PSR exit, there cannot be any 
further PSR entry again.

https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/tags/v5.15.90/drivers/gpu/drm/drm_self_refresh_helper.c#105
This has solved few flicker issues during the stress testing. 
> >
> > Signed-off-by: Sankeerth Billakanti 
> > Signed-off-by: Vinod Polimera 
> > ---
> >   drivers/gpu/drm/msm/dp/dp_drm.c | 27
> ++-
> >   1 file changed, 26 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c
> b/drivers/gpu/drm/msm/dp/dp_drm.c
> > index 029e08c..92d1a1b 100644
> > --- a/drivers/gpu/drm/msm/dp/dp_drm.c
> > +++ b/drivers/gpu/drm/msm/dp/dp_drm.c
> > @@ -134,6 +134,8 @@ static void edp_bridge_atomic_enable(struct
> drm_bridge *drm_bridge,
> >   struct drm_crtc_state *old_crtc_state;
> >   struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
> >   struct msm_dp *dp = dp_bridge->dp_display;
> > + struct drm_connector *connector;
> > + struct drm_connector_state *conn_state = NULL;
> >
> >   /*
> >* Check the old state of the crtc to determine if the panel
> > @@ -150,10 +152,22 @@ static void edp_bridge_atomic_enable(struct
> drm_bridge *drm_bridge,
> >
> >   if (old_crtc_state && old_crtc_state->self_refresh_active) {
> >   dp_display_set_psr(dp, false);
> > - return;
> > + goto psr_aware;
> >   }
> >
> >   dp_bridge_atomic_enable(drm_bridge, old_bridge_state);
> > +
> > +psr_aware:
> > + connector =
> drm_atomic_get_new_connector_for_encoder(atomic_state,
> > + drm_bridge->encoder);
> > + if (connector)
> > + conn_state =
> drm_atomic_get_new_connector_state(atomic_state,
> > + connector);
> > +
> > + if (conn_state) {
> > + conn_state->self_refresh_aware = dp->psr_supported;
> > + }
> 
> No need to wrap a single line statement in brackets.
> 
> > +
> >   }
> >
> >   static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
> > @@ -164,6 +178,14 @@ static void edp_bridge_atomic_disable(struct
> drm_bridge *drm_bridge,
> >   struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL;
> >   struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
> >   struct msm_dp *dp = dp_bridge->dp_display;
> > + struct drm_connector *connector;
> > + struct drm_connector_state *conn_state = NULL;
> > +
> > + connector =
> drm_atomic_get_old_connector_for_encoder(atomic_state,
> > + drm_bridge-&

[Freedreno] [PATCH Resend v11 15/15] drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable during self refresh

2023-01-19 Thread Vinod Polimera
Populate the enocder software structure to reflect the updated
crtc appropriately during crtc enable/disable for a new commit
while taking care of the self refresh transitions when crtc
disable is triggered from the drm self refresh library.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 31 ++-
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index d513aeb4..e8e456a 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1013,14 +1013,23 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
  
crtc);
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state);
-   struct drm_encoder *encoder;
+   struct drm_encoder *encoder = NULL;
unsigned long flags;
bool release_bandwidth = false;
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
-   if (old_crtc_state->self_refresh_active)
+   /* If disable is triggered while in self refresh mode,
+* reset the encoder software state so that in enable
+* it won't trigger a warn while assigning crtc.
+*/
+   if (old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev,
+   old_crtc_state->encoder_mask) {
+   dpu_encoder_assign_crtc(encoder, NULL);
+   }
return;
+   }
 
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
@@ -1033,7 +1042,14 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
+
+   /*
+* If disable is triggered during psr active(e.g: screen dim in 
PSR),
+* we will need encoder->crtc connection to process the device 
sleep &
+* preserve it during psr sequence.
+*/
+   if (!crtc->state->self_refresh_active)
+   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1081,6 +1097,9 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
struct drm_encoder *encoder;
bool request_bandwidth = false;
+   struct drm_crtc_state *old_crtc_state;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 
pm_runtime_get_sync(crtc->dev->dev);
 
@@ -1103,8 +1122,10 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
+   if (!old_crtc_state->self_refresh_active) {
+   drm_for_each_encoder_mask(encoder, crtc->dev, 
crtc->state->encoder_mask)
+   dpu_encoder_assign_crtc(encoder, crtc);
+   }
 
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
-- 
2.7.4



[Freedreno] [PATCH Resend v11 14/15] drm/msm/disp/dpu: clear active interface in the datapath cleanup

2023-01-19 Thread Vinod Polimera
Clear interface active register from the datapath for a clean shutdown of
the datapath.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 9cf1263..30dee50 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2085,6 +2085,9 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
if (phys_enc->hw_pp->merge_3d)
intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
 
+   if (phys_enc->hw_intf)
+   intf_cfg.intf = phys_enc->hw_intf->idx;
+
if (ctl->ops.reset_intf_cfg)
ctl->ops.reset_intf_cfg(ctl, _cfg);
 
-- 
2.7.4



[Freedreno] [PATCH Resend v11 13/15] drm/msm/disp/dpu: reset the datapath after timing engine disable

2023-01-19 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0396084..3a37429 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -588,6 +588,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH Resend v11 12/15] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2023-01-19 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 48c4810..0396084 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH Resend v11 11/15] drm/msm/disp/dpu: get timing engine status from intf status register

2023-01-19 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 4375e72..0244a7b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -80,7 +80,8 @@
 
 #define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
 
-#define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
+#define INTF_SC7280_MASK \
+   (INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define IRQ_SDM845_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
 BIT(MDP_SSPP_TOP0_INTR2) | \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 978e3bd..79c18fe 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -213,17 +213,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH Resend v11 10/15] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2023-01-19 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index c264801..d513aeb4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1018,6 +1019,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1572,7 +1576,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1609,6 +1613,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 29d6cda..9cf1263 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1211,11 +1212,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index d612419..4da77e40 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH Resend v11 09/15] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2023-01-19 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 1757856..29d6cda 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -651,7 +651,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH Resend v11 08/15] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2023-01-19 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index d1a528f..1757856 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1170,7 +1170,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1206,7 +1207,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2387,8 +2389,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH Resend v11 07/15] drm/bridge: add psr support for panel bridge callbacks

2023-01-19 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Daniel Vetter 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 04e9fb0..a2c6f30 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH Resend v11 05/15] drm/msm/dp: disable self_refresh_aware after entering psr

2023-01-19 Thread Vinod Polimera
From: Sankeerth Billakanti 

Updated frames get queued if self_refresh_aware is set when the
sink is in psr. To support bridge enable and avoid queuing of update
frames, reset the self_refresh_aware state after entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/dp/dp_drm.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 029e08c..92d1a1b 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -134,6 +134,8 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *old_crtc_state;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
 
/*
 * Check the old state of the crtc to determine if the panel
@@ -150,10 +152,22 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
 
if (old_crtc_state && old_crtc_state->self_refresh_active) {
dp_display_set_psr(dp, false);
-   return;
+   goto psr_aware;
}
 
dp_bridge_atomic_enable(drm_bridge, old_bridge_state);
+
+psr_aware:
+   connector = drm_atomic_get_new_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
+
+   if (conn_state) {
+   conn_state->self_refresh_aware = dp->psr_supported;
+   }
+
 }
 
 static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
@@ -164,6 +178,14 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
+
+   connector = drm_atomic_get_old_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
 
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state,
   drm_bridge->encoder);
@@ -190,6 +212,9 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
 * when display disable occurs while the sink is in psr state.
 */
if (new_crtc_state->self_refresh_active) {
+   if (conn_state)
+   conn_state->self_refresh_aware = false;
+
dp_display_set_psr(dp, true);
return;
} else if (old_crtc_state->self_refresh_active) {
-- 
2.7.4



[Freedreno] [PATCH Resend v11 06/15] drm/bridge: use atomic enable/disable callbacks for panel bridge

2023-01-19 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index e8aae3c..04e9fb0 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH Resend v11 03/15] drm/msm/dp: Add basic PSR support for eDP

2023-01-19 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644

[Freedreno] [PATCH Resend v11 04/15] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2023-01-19 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 86ed80c..ffb21a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -996,14 +996,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 3b38bd9..029e08c 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -226,12 +226,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH Resend v11 02/15] drm/msm/dp: use atomic callbacks for DP bridge ops

2023-01-19 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c | 9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 6 +++---
 drivers/gpu/drm/msm/dp/dp_drm.h | 9 ++---
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index bde1a7c..985287e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1652,7 +1652,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1707,7 +1708,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1718,7 +1720,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 275370f..3252d50 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,9 +94,9 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
.atomic_reset   = drm_atomic_helper_bridge_reset,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
.mode_valid   = dp_bridge_mode_valid,
.get_modes= dp_bridge_get_modes,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 250f7c6..afe79b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH Resend v11 01/15] drm: add helper functions to retrieve old and new crtc

2023-01-19 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5457c02..7cc39f6 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(const struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 92586ab..9a022ca 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH Resend v11 00/15] Add PSR support for eDP

2023-01-19 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - Get crtc cached in dpu_enc during obj init.(Dmitry)

Changes in v11:
  - Remove crtc cached in dpu_enc during obj init.
  - Update dpu_enc crtc state on crtc enable/disable during self refresh.

Sankeerth Billakanti (1):
  drm/msm/dp: disable self_refresh_aware after entering psr

Vinod Polimera (14):
  drm: add helper functions to retrieve old and new crtc
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm/msm/disp/dpu: clear active interface in the datapath cleanup
  drm/msm/disp/dpu: update dpu_enc crtc state on crtc enable/disable
during self refresh

 drivers/gpu/drm/bridge/panel.c |  68 ++-
 drivers/gpu/drm/drm_atomic.c   |  60 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  42 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  29 ++-
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   2 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 +
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 +
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 ++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 196 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 +++
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 710 insertions(+), 44 deletions(-)

-- 
2.7.4



[Freedreno] [PATCH v10 15/15] drm/msm/disp/dpu: clear active interface in the datapath cleanup

2022-12-22 Thread Vinod Polimera
Clear interface active register from the datapath for a clean shutdown of
the datapath.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index e13a309..b49c8dc 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2108,6 +2108,9 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
if (phys_enc->hw_pp->merge_3d)
intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
 
+   if (phys_enc->hw_intf)
+   intf_cfg.intf = phys_enc->hw_intf->idx;
+
if (ctl->ops.reset_intf_cfg)
ctl->ops.reset_intf_cfg(ctl, _cfg);
 
-- 
2.7.4



[Freedreno] [PATCH v10 14/15] drm/msm/disp/dpu: reset the datapath after timing engine disable

2022-12-22 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 685cb44..a597cca 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -591,6 +591,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v10 13/15] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2022-12-22 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0f71e8f..685cb44 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -526,6 +526,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -570,6 +571,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v10 12/15] drm/msm/disp/dpu: get timing engine status from intf status register

2022-12-22 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 2196e20..0e410cd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -77,7 +77,8 @@
 
 #define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
 
-#define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
+#define INTF_SC7280_MASK \
+   (INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define IRQ_SDM845_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
 BIT(MDP_SSPP_TOP0_INTR2) | \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 3b645d5..b16b428 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -204,17 +204,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v10 07/15] drm/bridge: use atomic enable/disable callbacks for panel bridge

2022-12-22 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 216af76..3558cbf 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



[Freedreno] [PATCH v10 06/15] drm/msm/dp: disable self_refresh_aware after entering psr

2022-12-22 Thread Vinod Polimera
From: Sankeerth Billakanti 

Updated frames get queued if self_refresh_aware is set when the
sink is in psr. To support bridge enable and avoid queuing of update
frames, reset the self_refresh_aware state after entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/dp/dp_drm.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index d3e9010..0f262a6 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -131,6 +131,8 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *old_crtc_state;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
 
/*
 * Check the old state of the crtc to determine if the panel
@@ -147,10 +149,22 @@ static void edp_bridge_atomic_enable(struct drm_bridge 
*drm_bridge,
 
if (old_crtc_state && old_crtc_state->self_refresh_active) {
dp_display_set_psr(dp, false);
-   return;
+   goto psr_aware;
}
 
dp_bridge_atomic_enable(drm_bridge, old_bridge_state);
+
+psr_aware:
+   connector = drm_atomic_get_new_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
+
+   if (conn_state) {
+   conn_state->self_refresh_aware = dp->psr_supported;
+   }
+
 }
 
 static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
@@ -161,6 +175,14 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL;
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state = NULL;
+
+   connector = drm_atomic_get_old_connector_for_encoder(atomic_state,
+   drm_bridge->encoder);
+   if (connector)
+   conn_state = drm_atomic_get_new_connector_state(atomic_state,
+   connector);
 
crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state,
   drm_bridge->encoder);
@@ -187,6 +209,9 @@ static void edp_bridge_atomic_disable(struct drm_bridge 
*drm_bridge,
 * when display disable occurs while the sink is in psr state.
 */
if (new_crtc_state->self_refresh_active) {
+   if (conn_state)
+   conn_state->self_refresh_aware = false;
+
dp_display_set_psr(dp, true);
return;
} else if (old_crtc_state->self_refresh_active) {
-- 
2.7.4



[Freedreno] [PATCH v10 11/15] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2022-12-22 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 289d51e..386b037 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1018,6 +1019,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1572,7 +1576,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1610,6 +1614,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index f454964..e13a309 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1243,11 +1244,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 264d571..3ab12f0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v10 10/15] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2022-12-22 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 98f38d6..f454964 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -683,7 +683,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v10 09/15] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2022-12-22 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 5055d56..98f38d6 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1202,7 +1202,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1238,7 +1239,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2417,8 +2419,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v10 08/15] drm/bridge: add psr support for panel bridge callbacks

2022-12-22 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 3558cbf..5e77e38 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v10 00/15] Add PSR support for eDP

2022-12-22 Thread Vinod Polimera
Changes in v2:
  - Use dp bridge to set psr entry/exit instead of dpu_enocder.
  - Don't modify whitespaces.
  - Set self refresh aware from atomic_check.
  - Set self refresh aware only if psr is supported.
  - Provide a stub for msm_dp_display_set_psr.
  - Move dp functions to bridge code.

Changes in v3:
  - Change callback names to reflect atomic interfaces.
  - Move bridge callback change to separate patch as suggested by Dmitry.
  - Remove psr function declaration from msm_drv.h.
  - Set self_refresh_aware flag only if psr is supported.
  - Modify the variable names to simpler form.
  - Define bit fields for PSR settings.
  - Add comments explaining the steps to enter/exit psr.
  - Change DRM_INFO to drm_dbg_db. 

Changes in v4:
  - Move the get crtc functions to drm_atomic.
  - Add atomic functions for DP bridge too.
  - Add ternary operator to choose eDP or DP ops.
  - Return true/false instead of 1/0.
  - mode_valid missing in the eDP bridge ops.
  - Move the functions to get crtc into drm_atomic.c.
  - Fix compilation issues.
  - Remove dpu_assign_crtc and get crtc from drm_enc instead of dpu_enc.
  - Check for crtc state enable while reserving resources.

Changes in v5:
  - Move the mode_valid changes into a different patch.
  - Complete psr_op_comp only when isr is set.
  - Move the DP atomic callback changes to a different patch.
  - Get crtc from drm connector state crtc.
  - Move to separate patch for check for crtc state enable while
reserving resources.

Changes in v6:
  - Remove crtc from dpu_encoder_virt struct.
  - fix crtc check during vblank toggle crtc.
  - Misc changes. 

Changes in v7:
  - Add fix for underrun issue on kasan build.

Changes in v8:
  - Drop the enc spinlock as it won't serve any purpose in
protetcing conn state.(Dmitry/Doug)

Changes in v9:
  - Update commit message and fix alignment using spaces.(Marijn)
  - Misc changes.(Marijn)

Changes in v10:
  - get crtc cached in dpu_enc during obj init.(Dmitry)

Sankeerth Billakanti (1):
  drm/msm/dp: disable self_refresh_aware after entering psr

Vinod Polimera (14):
  drm/msm/disp/dpu: cache crtc obj in the dpu_encoder during
initialization
  drm: add helper functions to retrieve old and new crtc
  drm/msm/dp: use atomic callbacks for DP bridge ops
  drm/msm/dp: Add basic PSR support for eDP
  drm/msm/dp: use the eDP bridge ops to validate eDP modes
  drm/bridge: use atomic enable/disable callbacks for panel bridge
  drm/bridge: add psr support for panel bridge callbacks
  drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder
functions
  drm/msm/disp/dpu: check for crtc enable rather than crtc active to
release shared resources
  drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver
  drm/msm/disp/dpu: get timing engine status from intf status register
  drm/msm/disp/dpu: wait for extra vsync till timing engine status is
disabled
  drm/msm/disp/dpu: reset the datapath after timing engine disable
  drm/msm/disp/dpu: clear active interface in the datapath cleanup

 drivers/gpu/drm/bridge/panel.c |  68 ++-
 drivers/gpu/drm/drm_atomic.c   |  60 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c   |  17 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c|  45 +++--
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   |  22 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |   3 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h |  12 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|   8 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c|   3 +-
 drivers/gpu/drm/msm/dp/dp_catalog.c|  80 
 drivers/gpu/drm/msm/dp/dp_catalog.h|   4 +
 drivers/gpu/drm/msm/dp/dp_ctrl.c   |  80 
 drivers/gpu/drm/msm/dp/dp_ctrl.h   |   3 +
 drivers/gpu/drm/msm/dp/dp_display.c|  36 ++--
 drivers/gpu/drm/msm/dp/dp_display.h|   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c| 206 -
 drivers/gpu/drm/msm/dp/dp_drm.h|   9 +-
 drivers/gpu/drm/msm/dp/dp_link.c   |  36 
 drivers/gpu/drm/msm/dp/dp_panel.c  |  22 +++
 drivers/gpu/drm/msm/dp/dp_panel.h  |   6 +
 drivers/gpu/drm/msm/dp/dp_reg.h|  27 +++
 include/drm/drm_atomic.h   |   7 +
 22 files changed, 696 insertions(+), 60 deletions(-)

-- 
2.7.4



[Freedreno] [PATCH v10 05/15] drm/msm/dp: use the eDP bridge ops to validate eDP modes

2022-12-22 Thread Vinod Polimera
The eDP and DP interfaces shared the bridge operations and
the eDP specific changes were implemented under is_edp check.
To add psr support for eDP, we started using a new set of eDP
bridge ops. We are moving the eDP specific code in the
dp_bridge_mode_valid function to a new eDP function,
edp_bridge_mode_valid under the eDP bridge ops.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  8 
 drivers/gpu/drm/msm/dp/dp_drm.c | 34 +-
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 7ec81b8..91642a0 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -984,14 +984,6 @@ enum drm_mode_status dp_bridge_mode_valid(struct 
drm_bridge *bridge,
return -EINVAL;
}
 
-   /*
-* The eDP controller currently does not have a reliable way of
-* enabling panel power to read sink capabilities. So, we rely
-* on the panel driver to populate only supported modes for now.
-*/
-   if (dp->is_edp)
-   return MODE_OK;
-
if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
return MODE_CLOCK_HIGH;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index df66df0..d3e9010 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -223,12 +223,44 @@ static void edp_bridge_atomic_post_disable(struct 
drm_bridge *drm_bridge,
dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
 }
 
+/**
+ * edp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+   struct msm_dp *dp;
+   int mode_pclk_khz = mode->clock;
+
+   dp = to_dp_bridge(bridge)->dp_display;
+
+   if (!dp || !mode_pclk_khz || !dp->connector) {
+   DRM_ERROR("invalid params\n");
+   return -EINVAL;
+   }
+
+   if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+   return MODE_CLOCK_HIGH;
+
+   /*
+* The eDP controller currently does not have a reliable way of
+* enabling panel power to read sink capabilities. So, we rely
+* on the panel driver to populate only supported modes for now.
+*/
+   return MODE_OK;
+}
+
 static const struct drm_bridge_funcs edp_bridge_ops = {
.atomic_enable = edp_bridge_atomic_enable,
.atomic_disable = edp_bridge_atomic_disable,
.atomic_post_disable = edp_bridge_atomic_post_disable,
.mode_set = dp_bridge_mode_set,
-   .mode_valid = dp_bridge_mode_valid,
+   .mode_valid = edp_bridge_mode_valid,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-- 
2.7.4



[Freedreno] [PATCH v10 04/15] drm/msm/dp: Add basic PSR support for eDP

2022-12-22 Thread Vinod Polimera
Add support for basic panel self refresh (PSR) feature for eDP.
Add a new interface to set PSR state in the sink from DPU.
Program the eDP controller to issue PSR enter and exit SDP to
the sink.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/dp/dp_catalog.c |  80 ++
 drivers/gpu/drm/msm/dp/dp_catalog.h |   4 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.c|  80 ++
 drivers/gpu/drm/msm/dp/dp_ctrl.h|   3 +
 drivers/gpu/drm/msm/dp/dp_display.c |  19 ++
 drivers/gpu/drm/msm/dp/dp_display.h |   2 +
 drivers/gpu/drm/msm/dp/dp_drm.c | 133 +++-
 drivers/gpu/drm/msm/dp/dp_link.c|  36 ++
 drivers/gpu/drm/msm/dp/dp_panel.c   |  22 ++
 drivers/gpu/drm/msm/dp/dp_panel.h   |   6 ++
 drivers/gpu/drm/msm/dp/dp_reg.h |  27 
 11 files changed, 411 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c 
b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 676279d..c12a5d9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -47,6 +47,14 @@
 #define DP_INTERRUPT_STATUS2_MASK \
(DP_INTERRUPT_STATUS2 << DP_INTERRUPT_STATUS_MASK_SHIFT)
 
+#define DP_INTERRUPT_STATUS4 \
+   (PSR_UPDATE_INT | PSR_CAPTURE_INT | PSR_EXIT_INT | \
+   PSR_UPDATE_ERROR_INT | PSR_WAKE_ERROR_INT)
+
+#define DP_INTERRUPT_MASK4 \
+   (PSR_UPDATE_MASK | PSR_CAPTURE_MASK | PSR_EXIT_MASK | \
+   PSR_UPDATE_ERROR_MASK | PSR_WAKE_ERROR_MASK)
+
 struct dp_catalog_private {
struct device *dev;
struct drm_device *drm_dev;
@@ -359,6 +367,23 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog 
*dp_catalog)
ln_mapping);
 }
 
+void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog,
+   bool enable)
+{
+   u32 val;
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+
+   val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
+
+   if (enable)
+   val |= DP_MAINLINK_CTRL_ENABLE;
+   else
+   val &= ~DP_MAINLINK_CTRL_ENABLE;
+
+   dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val);
+}
+
 void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
bool enable)
 {
@@ -610,6 +635,47 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog 
*dp_catalog)
dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
+{
+   /* trigger sdp */
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
+   dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0);
+}
+
+void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 config;
+
+   /* enable PSR1 function */
+   config = dp_read_link(catalog, REG_PSR_CONFIG);
+   config |= PSR1_SUPPORTED;
+   dp_write_link(catalog, REG_PSR_CONFIG, config);
+
+   dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
+   dp_catalog_enable_sdp(catalog);
+}
+
+void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 cmd;
+
+   cmd = dp_read_link(catalog, REG_PSR_CMD);
+
+   cmd &= ~(PSR_ENTER | PSR_EXIT);
+
+   if (enter)
+   cmd |= PSR_ENTER;
+   else
+   cmd |= PSR_EXIT;
+
+   dp_catalog_enable_sdp(catalog);
+   dp_write_link(catalog, REG_PSR_CMD, cmd);
+}
+
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
@@ -645,6 +711,20 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog 
*dp_catalog)
return isr & (mask | ~DP_DP_HPD_INT_MASK);
 }
 
+u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog)
+{
+   struct dp_catalog_private *catalog = container_of(dp_catalog,
+   struct dp_catalog_private, dp_catalog);
+   u32 intr, intr_ack;
+
+   intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4);
+   intr_ack = (intr & DP_INTERRUPT_STATUS4)
+   << DP_INTERRUPT_STATUS_ACK_SHIFT;
+   dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack);
+
+   return intr;
+}
+
 int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
 {
struct dp_catalog_private *catalog = container_of(dp_catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h 
b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 1f717f4..2174bb5 100644

[Freedreno] [PATCH v10 03/15] drm/msm/dp: use atomic callbacks for DP bridge ops

2022-12-22 Thread Vinod Polimera
Use atomic variants for DP bridge callback functions so that
the atomic state can be accessed in the interface drivers.
The atomic state will help the driver find out if the display
is in self refresh state.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/msm/dp/dp_display.c |  9 ++---
 drivers/gpu/drm/msm/dp/dp_drm.c | 16 
 drivers/gpu/drm/msm/dp/dp_drm.h |  9 ++---
 3 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 7ff60e5..c04a02b 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1643,7 +1643,8 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct 
drm_device *dev,
return 0;
 }
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1698,7 +1699,8 @@ void dp_bridge_enable(struct drm_bridge *drm_bridge)
mutex_unlock(_display->event_mutex);
 }
 
-void dp_bridge_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
@@ -1709,7 +1711,8 @@ void dp_bridge_disable(struct drm_bridge *drm_bridge)
dp_ctrl_push_idle(dp_display->ctrl);
 }
 
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state)
 {
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 6db82f9..77c34cb 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -94,14 +94,14 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
.atomic_reset   = drm_atomic_helper_bridge_reset,
-   .enable   = dp_bridge_enable,
-   .disable  = dp_bridge_disable,
-   .post_disable = dp_bridge_post_disable,
-   .mode_set = dp_bridge_mode_set,
-   .mode_valid   = dp_bridge_mode_valid,
-   .get_modes= dp_bridge_get_modes,
-   .detect   = dp_bridge_detect,
-   .atomic_check = dp_bridge_atomic_check,
+   .atomic_enable  = dp_bridge_atomic_enable,
+   .atomic_disable = dp_bridge_atomic_disable,
+   .atomic_post_disable= dp_bridge_atomic_post_disable,
+   .mode_set   = dp_bridge_mode_set,
+   .mode_valid = dp_bridge_mode_valid,
+   .get_modes  = dp_bridge_get_modes,
+   .detect = dp_bridge_detect,
+   .atomic_check   = dp_bridge_atomic_check,
 };
 
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 82035db..e69c0b9 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -23,9 +23,12 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp 
*dp_display, struct dr
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device 
*dev,
struct drm_encoder *encoder);
 
-void dp_bridge_enable(struct drm_bridge *drm_bridge);
-void dp_bridge_disable(struct drm_bridge *drm_bridge);
-void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
+struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
+ struct drm_bridge_state *old_bridge_state);
+void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
+  struct drm_bridge_state *old_bridge_state);
 enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
  const struct drm_display_info *info,
  const struct drm_display_mode *mode);
-- 
2.7.4



[Freedreno] [PATCH v10 02/15] drm: add helper functions to retrieve old and new crtc

2022-12-22 Thread Vinod Polimera
Add new helper functions, drm_atomic_get_old_crtc_for_encoder
and drm_atomic_get_new_crtc_for_encoder to retrieve the
corresponding crtc for the encoder.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Douglas Anderson 
---
 drivers/gpu/drm/drm_atomic.c | 60 
 include/drm/drm_atomic.h |  7 ++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index f197f59..941fd6d 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,6 +985,66 @@ drm_atomic_get_new_connector_for_encoder(struct 
drm_atomic_state *state,
 EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
 
 /**
+ * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that was connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The old crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_old_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_old_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_old_crtc_for_encoder);
+
+/**
+ * drm_atomic_get_new_crtc_for_encoder - Get new crtc for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc state for
+ *
+ * This function finds and returns the crtc that will be connected to @encoder
+ * as specified by the @state.
+ *
+ * Returns: The new crtc connected to @encoder, or NULL if the encoder is
+ * not connected.
+ */
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+   struct drm_encoder *encoder)
+{
+   struct drm_connector *connector;
+   struct drm_connector_state *conn_state;
+
+   connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
+   if (!connector)
+   return NULL;
+
+   conn_state = drm_atomic_get_new_connector_state(state, connector);
+   if (!conn_state)
+   return NULL;
+
+   return conn_state->crtc;
+}
+EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
+
+/**
  * drm_atomic_get_connector_state - get connector state
  * @state: global atomic state object
  * @connector: connector to get state object for
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 10b1990..fdbd656 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -528,6 +528,13 @@ struct drm_connector *
 drm_atomic_get_new_connector_for_encoder(struct drm_atomic_state *state,
 struct drm_encoder *encoder);
 
+struct drm_crtc *
+drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+struct drm_crtc *
+drm_atomic_get_new_crtc_for_encoder(struct drm_atomic_state *state,
+struct drm_encoder *encoder);
+
 /**
  * drm_atomic_get_existing_crtc_state - get CRTC state, if it exists
  * @state: global atomic state object
-- 
2.7.4



[Freedreno] [PATCH v10 01/15] drm/msm/disp/dpu: cache crtc obj in the dpu_encoder during initialization

2022-12-22 Thread Vinod Polimera
Cache crtc obj in the dpu encoder during initialization.
This will avoid extracting crtc from connector state there by
simplifying the obj access whenever it is required.

This patch is dependent on the series:
https://patchwork.freedesktop.org/series/110969/

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c|  4 
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 16 +---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  1 +
 3 files changed, 6 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 3f72d38..289d51e 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -1029,7 +1029,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 */
if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
release_bandwidth = true;
-   dpu_encoder_assign_crtc(encoder, NULL);
}
 
/* wait for frame_event_done completion */
@@ -1099,9 +1098,6 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
dpu_crtc->enabled = true;
 
-   drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
-   dpu_encoder_assign_crtc(encoder, crtc);
-
/* Enable/restore vblank irq handling */
drm_crtc_vblank_on(crtc);
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index a585036..5055d56 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1317,7 +1317,6 @@ static void dpu_encoder_vblank_callback(struct 
drm_encoder *drm_enc,
struct dpu_encoder_phys *phy_enc)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
-   unsigned long lock_flags;
 
if (!drm_enc || !phy_enc)
return;
@@ -1325,12 +1324,11 @@ static void dpu_encoder_vblank_callback(struct 
drm_encoder *drm_enc,
DPU_ATRACE_BEGIN("encoder_vblank_callback");
dpu_enc = to_dpu_encoder_virt(drm_enc);
 
-   atomic_inc(_enc->vsync_cnt);
+   if (!dpu_enc->crtc)
+   return;
 
-   spin_lock_irqsave(_enc->enc_spinlock, lock_flags);
-   if (dpu_enc->crtc)
-   dpu_crtc_vblank_callback(dpu_enc->crtc);
-   spin_unlock_irqrestore(_enc->enc_spinlock, lock_flags);
+   atomic_inc(_enc->vsync_cnt);
+   dpu_crtc_vblank_callback(dpu_enc->crtc);
 
DPU_ATRACE_END("encoder_vblank_callback");
 }
@@ -1369,17 +1367,13 @@ void dpu_encoder_toggle_vblank_for_crtc(struct 
drm_encoder *drm_enc,
struct drm_crtc *crtc, bool enable)
 {
struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
-   unsigned long lock_flags;
int i;
 
trace_dpu_enc_vblank_cb(DRMID(drm_enc), enable);
 
-   spin_lock_irqsave(_enc->enc_spinlock, lock_flags);
-   if (dpu_enc->crtc != crtc) {
-   spin_unlock_irqrestore(_enc->enc_spinlock, lock_flags);
+   if (!dpu_enc->crtc || dpu_enc->crtc != crtc) {
return;
}
-   spin_unlock_irqrestore(_enc->enc_spinlock, lock_flags);
 
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 93221a2..264d571 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -801,6 +801,7 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms)
}
priv->crtcs[priv->num_crtcs++] = crtc;
encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
+   dpu_encoder_assign_crtc(encoder, crtc);
i++;
}
 
-- 
2.7.4



Re: [Freedreno] [PATCH v9 01/15] drm/msm/disp/dpu: clear dpu_assign_crtc and get crtc from connector state instead of dpu_enc

2022-12-21 Thread Vinod Polimera


> -Original Message-
> From: Dmitry Baryshkov 
> Sent: Wednesday, December 14, 2022 9:05 PM
> To: Vinod Polimera (QUIC) ; dri-
> de...@lists.freedesktop.org; linux-arm-...@vger.kernel.org;
> freedreno@lists.freedesktop.org; devicet...@vger.kernel.org
> Cc: linux-ker...@vger.kernel.org; robdcl...@gmail.com;
> diand...@chromium.org; swb...@chromium.org; Kalyan Thota (QUIC)
> ; Kuogee Hsieh (QUIC)
> ; Vishnuvardhan Prodduturi (QUIC)
> ; Bjorn Andersson (QUIC)
> ; Aravind Venkateswaran (QUIC)
> ; Abhinav Kumar (QUIC)
> ; Sankeerth Billakanti (QUIC)
> 
> Subject: Re: [PATCH v9 01/15] drm/msm/disp/dpu: clear dpu_assign_crtc and
> get crtc from connector state instead of dpu_enc
> 
> WARNING: This email originated from outside of Qualcomm. Please be wary
> of any links or attachments, and do not enable macros.
> 
> On 14/12/2022 12:05, Vinod Polimera wrote:
> > Update crtc retrieval from dpu_enc to dpu_enc connector state,
> > since new links get set as part of the dpu enc virt mode set.
> > The dpu_enc->crtc cache is no more needed, hence cleaning it as
> > part of this change.
> >
> > This patch is dependent on the series:
> > https://patchwork.freedesktop.org/series/110969/
> >
> > Signed-off-by: Vinod Polimera 
> > ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c|  4 ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 42 +-
> ---
> >   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h |  8 --
> >   3 files changed, 13 insertions(+), 41 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > index 3f72d38..289d51e 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
> > @@ -1029,7 +1029,6 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
> >*/
> >   if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
> >   release_bandwidth = true;
> > - dpu_encoder_assign_crtc(encoder, NULL);
> >   }
> >
> >   /* wait for frame_event_done completion */
> > @@ -1099,9 +1098,6 @@ static void dpu_crtc_enable(struct drm_crtc *crtc,
> >   trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc);
> >   dpu_crtc->enabled = true;
> >
> > - drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state-
> >encoder_mask)
> > - dpu_encoder_assign_crtc(encoder, crtc);
> > -
> >   /* Enable/restore vblank irq handling */
> >   drm_crtc_vblank_on(crtc);
> >   }
> > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > index a585036..b9b254d 100644
> > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> > @@ -132,11 +132,6 @@ enum dpu_enc_rc_states {
> >* @intfs_swapped:  Whether or not the phys_enc interfaces have been
> swapped
> >*  for partial update right-only cases, such as pingpong
> >*  split where virtual pingpong does not generate IRQs
> > - * @crtc:Pointer to the currently assigned crtc. Normally you
> > - *   would use crtc->state->encoder_mask to determine the
> > - *   link between encoder/crtc. However in this case we 
> > need
> > - *   to track crtc in the disable() hook which is called
> > - *   _after_ encoder_mask is cleared.
> >* @connector:  If a mode is set, cached pointer to the active
> connector
> >* @crtc_kickoff_cb:Callback into CRTC that will flush & 
> > start
> >*  all CTL paths
> > @@ -181,7 +176,6 @@ struct dpu_encoder_virt {
> >
> >   bool intfs_swapped;
> >
> > - struct drm_crtc *crtc;
> >   struct drm_connector *connector;
> >
> >   struct dentry *debugfs_root;
> > @@ -1317,7 +1311,7 @@ static void dpu_encoder_vblank_callback(struct
> drm_encoder *drm_enc,
> >   struct dpu_encoder_phys *phy_enc)
> >   {
> >   struct dpu_encoder_virt *dpu_enc = NULL;
> > - unsigned long lock_flags;
> > + struct drm_crtc *crtc;
> >
> >   if (!drm_enc || !phy_enc)
> >   return;
> > @@ -1325,12 +1319,13 @@ static void dpu_encoder_vblank_callback(struct
> drm_encoder *drm_enc,
> >   DPU_ATRACE_BEGIN("encoder_vblank_callback");
> >   

[Freedreno] [PATCH v9 15/15] drm/msm/disp/dpu: clear active interface in the datapath cleanup

2022-12-14 Thread Vinod Polimera
Clear interface active register from the datapath for a clean shutdown of
the datapath.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index a3ba696..bdff09c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2098,6 +2098,9 @@ void dpu_encoder_helper_phys_cleanup(struct 
dpu_encoder_phys *phys_enc)
if (phys_enc->hw_pp->merge_3d)
intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
 
+   if (phys_enc->hw_intf)
+   intf_cfg.intf = phys_enc->hw_intf->idx;
+
if (ctl->ops.reset_intf_cfg)
ctl->ops.reset_intf_cfg(ctl, _cfg);
 
-- 
2.7.4



[Freedreno] [PATCH v9 14/15] drm/msm/disp/dpu: reset the datapath after timing engine disable

2022-12-14 Thread Vinod Polimera
Reset the datapath after disabling the timing gen, such that
it can start on a clean slate when the intf is enabled back.
This was a recommended sequence from the DPU HW programming guide.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 685cb44..a597cca 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -591,6 +591,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   dpu_encoder_helper_phys_cleanup(phys_enc);
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v9 13/15] drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled

2022-12-14 Thread Vinod Polimera
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera 
---
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c| 21 +
 1 file changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
index 0f71e8f..685cb44 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
@@ -526,6 +526,7 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
 {
unsigned long lock_flags;
int ret;
+   struct intf_status intf_status = {0};
 
if (!phys_enc->parent || !phys_enc->parent->dev) {
DPU_ERROR("invalid encoder/device\n");
@@ -570,6 +571,26 @@ static void dpu_encoder_phys_vid_disable(struct 
dpu_encoder_phys *phys_enc)
}
}
 
+   if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+   phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, 
_status);
+
+   /*
+* Wait for a vsync if timing en status is on after timing engine
+* is disabled.
+*/
+   if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+   spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+   dpu_encoder_phys_inc_pending(phys_enc);
+   spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+   ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+   if (ret) {
+   atomic_set(_enc->pending_kickoff_cnt, 0);
+   DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+ DRMID(phys_enc->parent),
+ phys_enc->hw_intf->idx - INTF_0, ret);
+   }
+   }
+
phys_enc->enable_state = DPU_ENC_DISABLED;
 }
 
-- 
2.7.4



[Freedreno] [PATCH v9 12/15] drm/msm/disp/dpu: get timing engine status from intf status register

2022-12-14 Thread Vinod Polimera
Recommended way of reading the interface timing gen status is via
status register. Timing gen status register will give a reliable status
of the interface especially during ON/OFF transitions. This support was
added from DPU version 5.0.0.

Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c |  3 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 12 +++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c|  8 +++-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index 2196e20..0e410cd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -77,7 +77,8 @@
 
 #define INTF_SC7180_MASK BIT(DPU_INTF_INPUT_CTRL) | BIT(DPU_INTF_TE)
 
-#define INTF_SC7280_MASK INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN)
+#define INTF_SC7280_MASK \
+   (INTF_SC7180_MASK | BIT(DPU_DATA_HCTL_EN) | 
BIT(DPU_INTF_STATUS_SUPPORTED))
 
 #define IRQ_SDM845_MASK (BIT(MDP_SSPP_TOP0_INTR) | \
 BIT(MDP_SSPP_TOP0_INTR2) | \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 3b645d5..b16b428 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -204,17 +204,19 @@ enum {
 
 /**
  * INTF sub-blocks
- * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
- *  pixel data arrives to this INTF
- * @DPU_INTF_TE INTF block has TE configuration support
- * @DPU_DATA_HCTL_ENAllows data to be transferred at different rate
-than video timing
+ * @DPU_INTF_INPUT_CTRL Supports the setting of pp block from which
+ *  pixel data arrives to this INTF
+ * @DPU_INTF_TE INTF block has TE configuration support
+ * @DPU_DATA_HCTL_ENAllows data to be transferred at different 
rate
+ *  than video timing
+ * @DPU_INTF_STATUS_SUPPORTED   INTF block has INTF_STATUS register
  * @DPU_INTF_MAX
  */
 enum {
DPU_INTF_INPUT_CTRL = 0x1,
DPU_INTF_TE,
DPU_DATA_HCTL_EN,
+   DPU_INTF_STATUS_SUPPORTED,
DPU_INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
index 7ce66bf..84ee2ef 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c
@@ -62,6 +62,7 @@
 #define   INTF_LINE_COUNT   0x0B0
 
 #define   INTF_MUX  0x25C
+#define   INTF_STATUS   0x26C
 
 #define INTF_CFG_ACTIVE_H_EN   BIT(29)
 #define INTF_CFG_ACTIVE_V_EN   BIT(30)
@@ -297,8 +298,13 @@ static void dpu_hw_intf_get_status(
struct intf_status *s)
 {
struct dpu_hw_blk_reg_map *c = >hw;
+   unsigned long cap = intf->cap->features;
+
+   if (cap & BIT(DPU_INTF_STATUS_SUPPORTED))
+   s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
+   else
+   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
 
-   s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
if (s->is_en) {
s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
-- 
2.7.4



[Freedreno] [PATCH v9 11/15] drm/msm/disp/dpu: add PSR support for eDP interface in dpu driver

2022-12-14 Thread Vinod Polimera
Enable PSR on eDP interface using drm self-refresh librabry.
This patch uses a trigger from self-refresh library to enter/exit
into PSR, when there are no updates from framework.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c| 13 -
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 14 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c |  2 +-
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 289d51e..386b037 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -21,6 +21,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "dpu_kms.h"
 #include "dpu_hw_lm.h"
@@ -1018,6 +1019,9 @@ static void dpu_crtc_disable(struct drm_crtc *crtc,
 
DRM_DEBUG_KMS("crtc%d\n", crtc->base.id);
 
+   if (old_crtc_state->self_refresh_active)
+   return;
+
/* Disable/save vblank irq handling */
drm_crtc_vblank_off(crtc);
 
@@ -1572,7 +1576,7 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
 {
struct drm_crtc *crtc = NULL;
struct dpu_crtc *dpu_crtc = NULL;
-   int i;
+   int i, ret;
 
dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL);
if (!dpu_crtc)
@@ -1610,6 +1614,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, 
struct drm_plane *plane,
/* initialize event handling */
spin_lock_init(_crtc->event_lock);
 
+   ret = drm_self_refresh_helper_init(crtc);
+   if (ret) {
+   DPU_ERROR("Failed to initialize %s with self-refresh helpers 
%d\n",
+   crtc->name, ret);
+   return ERR_PTR(ret);
+   }
+
DRM_DEBUG_KMS("%s: successfully initialized crtc\n", dpu_crtc->name);
return crtc;
 }
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index dbf0d96..a3ba696 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -12,6 +12,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -1237,11 +1238,24 @@ static void dpu_encoder_virt_atomic_disable(struct 
drm_encoder *drm_enc,
struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_state = NULL;
int i = 0;
 
dpu_enc = to_dpu_encoder_virt(drm_enc);
DPU_DEBUG_ENC(dpu_enc, "\n");
 
+   crtc = drm_atomic_get_old_crtc_for_encoder(state, drm_enc);
+   if (crtc)
+   old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+   /*
+* The encoder is already disabled if self refresh mode was set earlier,
+* in the old_state for the corresponding crtc.
+*/
+   if (old_state && old_state->self_refresh_active)
+   return;
+
mutex_lock(_enc->enc_lock);
dpu_enc->enabled = false;
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 93221a2..a969874 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -491,7 +491,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms 
*kms,
return;
}
 
-   if (!crtc->state->active) {
+   if (!drm_atomic_crtc_effectively_active(crtc->state)) {
DPU_DEBUG("[crtc:%d] not active\n", crtc->base.id);
return;
}
-- 
2.7.4



[Freedreno] [PATCH v9 10/15] drm/msm/disp/dpu: check for crtc enable rather than crtc active to release shared resources

2022-12-14 Thread Vinod Polimera
According to KMS documentation, The driver must not release any shared
resources if active is set to false but enable still true.

Fixes: ccc862b957c6 ("drm/msm/dpu: Fix reservation failures in modeset")
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index a0cb089..dbf0d96 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -677,7 +677,7 @@ static int dpu_encoder_virt_atomic_check(
if (drm_atomic_crtc_needs_modeset(crtc_state)) {
dpu_rm_release(global_state, drm_enc);
 
-   if (!crtc_state->active_changed || crtc_state->active)
+   if (!crtc_state->active_changed || crtc_state->enable)
ret = dpu_rm_reserve(_kms->rm, global_state,
drm_enc, crtc_state, topology);
}
-- 
2.7.4



[Freedreno] [PATCH v9 08/15] drm/bridge: add psr support for panel bridge callbacks

2022-12-14 Thread Vinod Polimera
This change will handle the psr entry exit cases in the panel
bridge atomic callback functions. For example, the panel power
should not turn off if the panel is entering psr.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
---
 drivers/gpu/drm/bridge/panel.c | 48 ++
 1 file changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 3558cbf..5e77e38 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -113,6 +113,18 @@ static void panel_bridge_atomic_pre_enable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_prepare(panel_bridge->panel);
 }
@@ -121,6 +133,18 @@ static void panel_bridge_atomic_enable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *old_crtc_state;
+
+   crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+   if (old_crtc_state && old_crtc_state->self_refresh_active)
+   return;
 
drm_panel_enable(panel_bridge->panel);
 }
@@ -129,6 +153,18 @@ static void panel_bridge_atomic_disable(struct drm_bridge 
*bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_disable(panel_bridge->panel);
 }
@@ -137,6 +173,18 @@ static void panel_bridge_atomic_post_disable(struct 
drm_bridge *bridge,
struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
+   struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
+   struct drm_encoder *encoder = bridge->encoder;
+   struct drm_crtc *crtc;
+   struct drm_crtc_state *new_crtc_state;
+
+   crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, encoder);
+   if (!crtc)
+   return;
+
+   new_crtc_state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+   if (new_crtc_state && new_crtc_state->self_refresh_active)
+   return;
 
drm_panel_unprepare(panel_bridge->panel);
 }
-- 
2.7.4



[Freedreno] [PATCH v9 09/15] drm/msm/disp/dpu: use atomic enable/disable callbacks for encoder functions

2022-12-14 Thread Vinod Polimera
Use atomic variants for encoder callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Kalyan Thota 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index b9b254d..a0cb089 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1196,7 +1196,8 @@ void dpu_encoder_virt_runtime_resume(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int ret = 0;
@@ -1232,7 +1233,8 @@ static void dpu_encoder_virt_enable(struct drm_encoder 
*drm_enc)
mutex_unlock(_enc->enc_lock);
 }
 
-static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc)
+static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
+   struct drm_atomic_state *state)
 {
struct dpu_encoder_virt *dpu_enc = NULL;
int i = 0;
@@ -2407,8 +2409,8 @@ static void dpu_encoder_frame_done_timeout(struct 
timer_list *t)
 
 static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = {
.atomic_mode_set = dpu_encoder_virt_atomic_mode_set,
-   .disable = dpu_encoder_virt_disable,
-   .enable = dpu_encoder_virt_enable,
+   .atomic_disable = dpu_encoder_virt_atomic_disable,
+   .atomic_enable = dpu_encoder_virt_atomic_enable,
.atomic_check = dpu_encoder_virt_atomic_check,
 };
 
-- 
2.7.4



[Freedreno] [PATCH v9 07/15] drm/bridge: use atomic enable/disable callbacks for panel bridge

2022-12-14 Thread Vinod Polimera
Use atomic variants for panel bridge callback functions such that
certain states like self-refresh can be accessed as part of
enable/disable sequence.

Signed-off-by: Sankeerth Billakanti 
Signed-off-by: Vinod Polimera 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/bridge/panel.c | 20 
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 216af76..3558cbf 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -109,28 +109,32 @@ static void panel_bridge_detach(struct drm_bridge *bridge)
drm_connector_cleanup(connector);
 }
 
-static void panel_bridge_pre_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_prepare(panel_bridge->panel);
 }
 
-static void panel_bridge_enable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_enable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_enable(panel_bridge->panel);
 }
 
-static void panel_bridge_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
drm_panel_disable(panel_bridge->panel);
 }
 
-static void panel_bridge_post_disable(struct drm_bridge *bridge)
+static void panel_bridge_atomic_post_disable(struct drm_bridge *bridge,
+   struct drm_bridge_state *old_bridge_state)
 {
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
 
@@ -159,10 +163,10 @@ static void panel_bridge_debugfs_init(struct drm_bridge 
*bridge,
 static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
.attach = panel_bridge_attach,
.detach = panel_bridge_detach,
-   .pre_enable = panel_bridge_pre_enable,
-   .enable = panel_bridge_enable,
-   .disable = panel_bridge_disable,
-   .post_disable = panel_bridge_post_disable,
+   .atomic_pre_enable = panel_bridge_atomic_pre_enable,
+   .atomic_enable = panel_bridge_atomic_enable,
+   .atomic_disable = panel_bridge_atomic_disable,
+   .atomic_post_disable = panel_bridge_atomic_post_disable,
.get_modes = panel_bridge_get_modes,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
-- 
2.7.4



  1   2   3   >