* [PATCH] drm: shmobile: Fix blank screen after resume when LCDC is stopped
@ 2026-02-26 5:13 phucduc.bui
2026-02-26 5:40 ` [PATCH v2] " phucduc.bui
0 siblings, 1 reply; 4+ messages in thread
From: phucduc.bui @ 2026-02-26 5:13 UTC (permalink / raw)
To: dri-devel
Cc: laurent.pinchart, geert+renesas, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, linux-renesas-soc, linux-kernel,
phucduc.bui
From: bui duc phuc <phucduc.bui@gmail.com>
The LCDC controller on R8A7740 loses its register state during
deep sleep. Upon resume, the driver's Mirror Register mechanism
(MRS) fails to update active registers because the controller is
stopped (DO=0).
According to the datasheet (Section 38.7.1, Figure 38.13), the
Two-Set Register Switching logic only triggers a change between
Set A and Set B when a Frame End Interrupt occurs at the
completion of a display frame. During resume, as the LCDC is
stopped, no frame is processed and no Frame End pulse is
generated. This leaves the Display Data Start Address (SA)
pending in the standby set, while the active register (Side A)
remains at 0x00000000, preventing the display engine from
starting.Debug logs collected during resume confirm this
behavior, showing the start address written to the standby set
while the active register remains unchanged.
Prime both register sets when the LCDC is stopped:
If DO=0: Use lcdc_write() to force the Start Address (SA)
into both Set A and Set B registers. This bypasses the
switching logic and ensures the engine has a valid base
address immediately upon being enabled.
If DO=1: Maintain the standard Mirror mechanism and MRS
toggle for normal, tear-free operation.
Verified on R8A7740.
Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
---
.../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 9d166ab2af8b..21fd1e19beda 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_mirror(sdev, LDSA2R, sstate->dma[1]);
+ }
}
static void shmob_drm_overlay_plane_setup(struct shmob_drm_plane *splane,
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v2] drm: shmobile: Fix blank screen after resume when LCDC is stopped
2026-02-26 5:13 [PATCH] drm: shmobile: Fix blank screen after resume when LCDC is stopped phucduc.bui
@ 2026-02-26 5:40 ` phucduc.bui
2026-02-26 8:09 ` Geert Uytterhoeven
0 siblings, 1 reply; 4+ messages in thread
From: phucduc.bui @ 2026-02-26 5:40 UTC (permalink / raw)
To: phucduc.bui
Cc: airlied, dri-devel, geert+renesas, laurent.pinchart, linux-kernel,
linux-renesas-soc, maarten.lankhorst, mripard, simona,
tzimmermann
From: bui duc phuc <phucduc.bui@gmail.com>
The LCDC controller on R8A7740 loses its register state during
deep sleep. Upon resume, the driver's Mirror Register mechanism
(MRS) fails to update active registers because the controller is
stopped (DO=0).
According to the datasheet (Section 38.7.1, Figure 38.13), the
Two-Set Register Switching logic only triggers a change between
Set A and Set B when a Frame End Interrupt occurs at the
completion of a display frame. During resume, as the LCDC is
stopped, no frame is processed and no Frame End pulse is
generated. This leaves the Display Data Start Address (SA)
pending in the standby set, while the active register (Side A)
remains at 0x00000000, preventing the display engine from
starting.Debug logs collected during resume confirm this
behavior, showing the start address written to the standby set
while the active register remains unchanged.
Prime both register sets when the LCDC is stopped:
If DO=0: Use lcdc_write() to force the Start Address (SA)
into both Set A and Set B registers. This bypasses the
switching logic and ensures the engine has a valid base
address immediately upon being enabled.
If DO=1: Maintain the standard Mirror mechanism and MRS
toggle for normal, tear-free operation.
Verified on R8A7740.
Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
---
Changes in 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 9d166ab2af8b..6371bdc2371a 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
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2] drm: shmobile: Fix blank screen after resume when LCDC is stopped
2026-02-26 5:40 ` [PATCH v2] " phucduc.bui
@ 2026-02-26 8:09 ` Geert Uytterhoeven
2026-02-27 2:34 ` Claude review: " Claude Code Review Bot
0 siblings, 1 reply; 4+ messages in thread
From: Geert Uytterhoeven @ 2026-02-26 8:09 UTC (permalink / raw)
To: phucduc.bui
Cc: airlied, dri-devel, laurent.pinchart, linux-kernel,
linux-renesas-soc, maarten.lankhorst, mripard, simona,
tzimmermann
Hi Phucduc,
On Thu, 26 Feb 2026 at 06:40, <phucduc.bui@gmail.com> wrote:
> From: bui duc phuc <phucduc.bui@gmail.com>
>
> The LCDC controller on R8A7740 loses its register state during
> deep sleep. Upon resume, the driver's Mirror Register mechanism
> (MRS) fails to update active registers because the controller is
> stopped (DO=0).
>
> According to the datasheet (Section 38.7.1, Figure 38.13), the
> Two-Set Register Switching logic only triggers a change between
> Set A and Set B when a Frame End Interrupt occurs at the
> completion of a display frame. During resume, as the LCDC is
> stopped, no frame is processed and no Frame End pulse is
> generated. This leaves the Display Data Start Address (SA)
> pending in the standby set, while the active register (Side A)
> remains at 0x00000000, preventing the display engine from
> starting.Debug logs collected during resume confirm this
> behavior, showing the start address written to the standby set
> while the active register remains unchanged.
>
> Prime both register sets when the LCDC is stopped:
>
> If DO=0: Use lcdc_write() to force the Start Address (SA)
> into both Set A and Set B registers. This bypasses the
> switching logic and ensures the engine has a valid base
> address immediately upon being enabled.
>
> If DO=1: Maintain the standard Mirror mechanism and MRS
> toggle for normal, tear-free operation.
>
> Verified on R8A7740.
>
> Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
Thanks for your patch!
What do you mean by "deep sleep"? s2ram? In upstream, s2ram behaves
the same as s2idle, and the LCD works fine after resume from s2ram on
my Amadillo, with and without your patch,
What am I missing?
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 4+ messages in thread* Claude review: Re: [PATCH v2] drm: shmobile: Fix blank screen after resume when LCDC is stopped
2026-02-26 8:09 ` Geert Uytterhoeven
@ 2026-02-27 2:34 ` Claude Code Review Bot
0 siblings, 0 replies; 4+ messages in thread
From: Claude Code Review Bot @ 2026-02-27 2:34 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: Re: [PATCH v2] drm: shmobile: Fix blank screen after resume when LCDC is stopped
Author: Geert Uytterhoeven <geert@linux-m68k.org>
Patches: 3
Reviewed: 2026-02-27T12:34:03.437511
---
This mbox contains two versions of the same patch: v1 (`[PATCH]`) and v2 (`[PATCH v2]`), where v2 supersedes v1. The fix addresses a real issue with the SH Mobile LCDC driver where the display start address (SA) is written via the mirror register mechanism during resume, but the controller is stopped (DO=0) so no Frame End interrupt fires to transfer the mirrored value into the active register set.
The analysis is sound and well-supported by the hardware architecture:
- `lcdc_write_mirror()` writes to `reg + LCDC_MIRROR_OFFSET (0x2000)`, the standby/mirror register
- The MRS toggle requests the hardware to switch sets on the next Frame End
- When DO=0, no frames are processed, so the switch never occurs
- `lcdc_write()` writes directly to both Set A (`reg`) and Set B (`reg + LCDC_SIDE_B_OFFSET (0x1000)`) for banked registers (LDSA1R and LDSA2R are both banked per `lcdc_is_banked()`)
The commit ordering confirms the scenario: since shmobile uses the default `drm_atomic_helper_commit_tail()` (no custom `commit_tail` override), the sequence during a modeset/resume is:
1. `drm_atomic_helper_commit_planes()` → `shmob_drm_primary_plane_setup()` (DO=0 at this point)
2. `drm_atomic_helper_commit_modeset_enables()` → `shmob_drm_crtc_atomic_enable()` → `shmob_drm_crtc_start_stop(scrtc, true)` (sets DO=1)
So when the plane setup runs, the LCDC is indeed stopped and the mirror mechanism cannot work.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-02-27 2:34 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-26 5:13 [PATCH] drm: shmobile: Fix blank screen after resume when LCDC is stopped phucduc.bui
2026-02-26 5:40 ` [PATCH v2] " phucduc.bui
2026-02-26 8:09 ` Geert Uytterhoeven
2026-02-27 2:34 ` Claude review: " Claude Code Review Bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox