From: Dave Stevenson <[email protected]>

Audio can be triggered by the HPD handler and start up before video has
been restored, calling vc4_hdmi_write_infoframe() for the audio infoframe.
vc4_hdmi_write_infoframe() needs Packet RAM to be on to store the
infoframe, however, if the video hasn't been enabled,
vc4_hdmi_encoder_post_crtc_enable() hasn't been called and therefore, the
Packet RAM can be disabled by the time vc4_hdmi_write_infoframe() executes,
causing the following splat:

[  201.570266] ------------[ cut here ]------------
[  201.570293] Packet RAM has to be on to store the packet.
[  201.570367] WARNING: drivers/gpu/drm/vc4/vc4_hdmi.c:683 at 
vc4_hdmi_write_infoframe+0x404/0x494 [vc4], CPU#0: wireplumber/1606
[...]
[  201.658650] Hardware name: Raspberry Pi 4 Model B Rev 1.5 (DT)
[...]
[  201.758499] Call trace:
[  201.760967]  vc4_hdmi_write_infoframe+0x404/0x494 [vc4] (P)
[  201.766607]  vc4_hdmi_write_audio_infoframe+0x1c/0x28 [vc4]
[  201.772247]  write_infoframe+0xbc/0x140 [drm_display_helper]
[  201.777975]  
drm_atomic_helper_connector_hdmi_update_audio_infoframe+0x80/0xdc 
[drm_display_helper]
[  201.787140]  vc4_hdmi_audio_prepare+0x4ac/0x570 [vc4]
[  201.792252]  drm_connector_hdmi_audio_prepare+0x24/0x30 [drm_display_helper]
[  201.799390]  hdmi_codec_prepare+0x100/0x160 [snd_soc_hdmi_codec]
[  201.805471]  snd_soc_pcm_dai_prepare+0xd4/0x100 [snd_soc_core]
[  201.811375]  __soc_pcm_prepare+0x60/0x12c [snd_soc_core]
[  201.816752]  soc_pcm_prepare+0x34/0x58 [snd_soc_core]
[  201.821863]  snd_pcm_do_prepare+0x70/0x8c [snd_pcm]
[  201.826798]  snd_pcm_action_nonatomic+0xe4/0x174 [snd_pcm]
[  201.832350]  snd_pcm_prepare+0xc8/0xd8 [snd_pcm]
[  201.837021]  snd_pcm_common_ioctl+0x458/0x614 [snd_pcm]
[  201.842308]  snd_pcm_ioctl+0x30/0x48 [snd_pcm]
[  201.846802]  __arm64_sys_ioctl+0x88/0xd8
[  201.850769]  invoke_syscall+0x48/0xf4
[  201.854470]  el0_svc_common+0x80/0xd8
[  201.858171]  do_el0_svc+0x1c/0x28
[  201.861520]  el0_svc+0x3c/0xb0
[  201.864605]  el0t_64_sync_handler+0x68/0xdc
[  201.868834]  el0t_64_sync+0x198/0x19c
[  201.872536] ---[ end trace 0000000000000000 ]---

Considering that Packet RAM enable is essentially a power management
configuration, move its enabling/disabling to the Runtime PM hooks.

Note that post_crtc_disable() still stops all infoframes, but keeps Packet
RAM enabled, leaving it to be disabled by runtime suspend.

Link: https://github.com/raspberrypi/linux/issues/7069
Fixes: b47a72f30768 ("drm/vc4: hdmi: Switch to HDMI connector")
Signed-off-by: Dave Stevenson <[email protected]>
Signed-off-by: Maíra Canal <[email protected]>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 17c8635c5afa..d4672aa81d85 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -894,7 +894,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct 
drm_encoder *encoder,
 
        spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 
-       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, VC4_HDMI_RAM_PACKET_ENABLE);
 
        HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | 
VC4_HD_VID_CTL_CLRRGB);
 
@@ -1663,9 +1663,6 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct 
drm_encoder *encoder,
                WARN_ONCE(ret, "Timeout waiting for "
                          "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
        } else {
-               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
-                          HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
-                          ~(VC4_HDMI_RAM_PACKET_ENABLE));
                HDMI_WRITE(HDMI_SCHEDULER_CONTROL,
                           HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                           ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
@@ -1684,9 +1681,6 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct 
drm_encoder *encoder,
                WARN_ON(!(HDMI_READ(HDMI_SCHEDULER_CONTROL) &
                          VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE));
 
-               HDMI_WRITE(HDMI_RAM_PACKET_CONFIG,
-                          VC4_HDMI_RAM_PACKET_ENABLE);
-
                spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
                vc4_hdmi->packet_ram_enabled = true;
 
@@ -3143,6 +3137,11 @@ static int vc5_hdmi_init_resources(struct drm_device 
*drm,
 static int vc4_hdmi_runtime_suspend(struct device *dev)
 {
        struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
+       spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 
        clk_disable_unprepare(vc4_hdmi->audio_clock);
        clk_disable_unprepare(vc4_hdmi->hsm_clock);
@@ -3153,9 +3152,8 @@ static int vc4_hdmi_runtime_suspend(struct device *dev)
 static int vc4_hdmi_runtime_resume(struct device *dev)
 {
        struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
-       unsigned long __maybe_unused flags;
+       unsigned long rate, flags;
        u32 __maybe_unused value;
-       unsigned long rate;
        int ret;
 
        ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
@@ -3201,6 +3199,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
        }
 #endif
 
+       spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
+       HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, VC4_HDMI_RAM_PACKET_ENABLE);
+       spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
+
        return 0;
 
 err_disable_clk:

-- 
2.55.0

Reply via email to