The Apple iMac10,1 and iMac11,2 (RV730/DCE3.2) drive their internal eDP
panel through an LVTMA power sequencer whose enable bit (PWRSEQ_EN in
LVTMA_PWRSEQ_CNTL) is programmed exactly once, by EFI at cold boot.
Apple's minimal ATOM tables never touch it afterwards, so any GPU
re-initialisation - S3 resume or a GPU-lockup reset - clears PWRSEQ_EN
and the panel comes back dark while the rest of the GPU resumes fine.

The driver never programs this register itself; on every other radeon
board the platform firmware maintains it across a re-POST, which is why
this only bites the Apple machines. Re-assert PWRSEQ_EN in the eDP
DPMS-on path when it is found cleared; the hardware then runs the
DIGON->DE->VARY_BL->BLON power-on sequence on its own. Both failure
paths pass through here, as radeon_gpu_reset() restores the modeset
state via radeon_resume_kms(), so a single site covers resume and reset.

The write is gated to Apple parts and to exactly DCE3.2 (ASIC_IS_DCE32
is >= RV730, so DCE4+ must be excluded - Apple also shipped DCE5, e.g.
the 2011 MacBook Pro, where the register lives at a different offset).
It is skipped when the sequencer is already enabled, so lit panels,
DCE4+ boards and non-Apple boards are untouched. DCE3.2 places the
register 0x18 above the documented R600 offset.

Only iMac11,2 is verified on hardware; iMac10,1 shares the same RV730
design and Apple EFI behaviour.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/5719
Signed-off-by: Mario Limonciello <[email protected]>
---
 drivers/gpu/drm/radeon/atombios_encoders.c | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c 
b/drivers/gpu/drm/radeon/atombios_encoders.c
index 8b3f8303a967e..5b9c72bf40994 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -1646,6 +1646,38 @@ radeon_atom_encoder_dpms_avivo(struct drm_encoder 
*encoder, int mode)
        }
 }
 
+/*
+ * Apple's EFI enables the internal eDP panel power sequencer
+ * (LVTMA_PWRSEQ_CNTL) exactly once, at cold boot, and its minimal ATOM tables
+ * never touch it afterwards.  Any GPU re-initialisation - S3 resume or a GPU
+ * reset - clears PWRSEQ_EN, so the panel comes back dark on the DCE3.2 iMacs
+ * (iMac10,1 / iMac11,2, RV730).  Re-assert PWRSEQ_EN when we find it cleared;
+ * the hardware then runs the DIGON->DE->VARY_BL->BLON power-on sequence 
itself.
+ * DCE3.2 places the register 0x18 above the R600 offset.
+ *
+ * This is restricted to Apple DCE3.2 parts: the register lives at a different
+ * offset on DCE4+ (which Apple also shipped, e.g. the 2011 MacBook Pro), and
+ * non-Apple boards program the sequencer from their own firmware.  The
+ * read-modify-write only fires when the sequencer is actually disabled, so a
+ * lit panel is never disturbed.
+ *
+ * https://gitlab.freedesktop.org/drm/amd/-/issues/5719
+ */
+static void radeon_atom_apple_edp_pwrseq_restore(struct radeon_device *rdev)
+{
+       u32 pwrseq_cntl = R600_LVTMA_PWRSEQ_CNTL + 0x18;
+
+       if (rdev->pdev->subsystem_vendor != PCI_VENDOR_ID_APPLE)
+               return;
+       if (!ASIC_IS_DCE32(rdev) || ASIC_IS_DCE4(rdev))
+               return;
+
+       if (!(RREG32(pwrseq_cntl) & AVIVO_LVTMA_PWRSEQ_EN))
+               WREG32(pwrseq_cntl, AVIVO_LVTMA_PWRSEQ_EN |
+                                   AVIVO_LVTMA_SYNCEN_OVRD |
+                                   AVIVO_LVTMA_DIGON);
+}
+
 static void
 radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
 {
@@ -1711,6 +1743,10 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder 
*encoder, int mode)
                                atombios_dig_encoder_setup(encoder, 
ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
                }
                if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                       /* restore the panel power sequencer on Apple eDP iMacs
+                        * that lose it across resume/reset (see helper above)
+                        */
+                       radeon_atom_apple_edp_pwrseq_restore(rdev);
                        if (rdev->mode_info.bl_encoder)
                                atombios_set_backlight_level(radeon_encoder, 
dig->backlight_level);
                        else
-- 
2.43.0

Reply via email to