From: bui duc phuc <[email protected]>

The LCDC on R8A7740 may show a completely white screen after resuming
from suspend (s2idle or s2ram).

After resume, both Set A and Set B registers are reset to 0. As the
Frame End interrupt is not generated while the controller is stopped
(DO=0), the hardware register switching mechanism is not triggered.
Consequently, Set A remains at 0x00000000 even though a valid Start
Address is written to Set B, resulting in a white screen.

This is a timing-dependent race condition. In some configurations,
debug options slow down the resume path enough for a Frame End
interrupt to occur, which can mask the issue.

Fix this by priming both register sets with the Start Address while the
controller is stopped, ensuring a valid base address is available
immediately after resume.

Tested-by: Geert Uytterhoeven <[email protected]>
Reviewed-by: Geert Uytterhoeven <[email protected]>
Signed-off-by: bui duc phuc <[email protected]>
---

Note:
It was originally posted in March and has already received both 
Reviewed-by and Tested-by tags. I'm resending it to bring it back 
to attention in case it was overlooked.

Changes in v4:
 - No functional changes.
 - Resend.

Changes:
 - v3 
   Update commit message, add Tested-by and Reviewed-by tags 
 - v2 
   Fix incorrect use of lcdc_write_mirror() for LDSA2R in
   the DO=0 path; use lcdc_write() to update both register
   sets as intended.


 .../gpu/drm/renesas/shmobile/shmob_drm_plane.c  | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c 
b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
index 148de34af785..92e7fb464cb3 100644
--- a/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/renesas/shmobile/shmob_drm_plane.c
@@ -70,6 +70,7 @@ static void shmob_drm_primary_plane_setup(struct 
shmob_drm_plane *splane,
        struct shmob_drm_plane_state *sstate = to_shmob_plane_state(state);
        struct shmob_drm_device *sdev = to_shmob_device(splane->base.dev);
        struct drm_framebuffer *fb = state->fb;
+       u32 ldcnt2r;
 
        /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
        lcdc_write(sdev, LDDFR, sstate->format->lddfr | LDDFR_CF1);
@@ -78,11 +79,19 @@ static void shmob_drm_primary_plane_setup(struct 
shmob_drm_plane *splane,
        /* Word and long word swap. */
        lcdc_write(sdev, LDDDSR, sstate->format->ldddsr);
 
-       lcdc_write_mirror(sdev, LDSA1R, sstate->dma[0]);
-       if (shmob_drm_format_is_yuv(sstate->format))
-               lcdc_write_mirror(sdev, LDSA2R, sstate->dma[1]);
+       ldcnt2r = lcdc_read(sdev, LDCNT2R);
+
+       if (ldcnt2r & LDCNT2R_DO) {
+               lcdc_write_mirror(sdev, LDSA1R, sstate->dma[0]);
+               if (shmob_drm_format_is_yuv(sstate->format))
+                       lcdc_write_mirror(sdev, LDSA2R, sstate->dma[1]);
 
-       lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS);
+               lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ 
LDRCNTR_MRS);
+       } else {
+               lcdc_write(sdev, LDSA1R, sstate->dma[0]);
+               if (shmob_drm_format_is_yuv(sstate->format))
+                       lcdc_write(sdev, LDSA2R, sstate->dma[1]);
+       }
 }
 
 static void shmob_drm_overlay_plane_setup(struct shmob_drm_plane *splane,
-- 
2.43.0

Reply via email to