From 4c60b81986b4e1dc80faa718a60dd9849dd4f4f7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 24 Sep 2021 14:27:38 +0200 Subject: [PATCH 010/828] drm/vc4: hdmi: Check the device state in prepare() Even though we already check that the encoder->crtc pointer is there during in startup(), which is part of the open() path in ASoC, nothing guarantees that our encoder state won't change between the time when we open the device and the time we prepare it. Move the sanity checks we do in startup() to a helper and call it from prepare(). Fixes: 91e99e113929 ("drm/vc4: hdmi: Register HDMI codec") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -1397,20 +1397,36 @@ static inline struct vc4_hdmi *dai_to_hd return snd_soc_card_get_drvdata(card); } +static bool vc4_hdmi_audio_can_stream(struct vc4_hdmi *vc4_hdmi) +{ + struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; + + lockdep_assert_held(&vc4_hdmi->mutex); + + /* + * The encoder doesn't have a CRTC until the first modeset. + */ + if (!encoder->crtc) + return false; + + /* + * If the encoder is currently in DVI mode, treat the codec DAI + * as missing. + */ + if (!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & VC4_HDMI_RAM_PACKET_ENABLE)) + return false; + + return true; +} + static int vc4_hdmi_audio_startup(struct device *dev, void *data) { struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev); - struct drm_encoder *encoder = &vc4_hdmi->encoder.base.base; unsigned long flags; mutex_lock(&vc4_hdmi->mutex); - /* - * If the HDMI encoder hasn't probed, or the encoder is - * currently in DVI mode, treat the codec dai as missing. - */ - if (!encoder->crtc || !(HDMI_READ(HDMI_RAM_PACKET_CONFIG) & - VC4_HDMI_RAM_PACKET_ENABLE)) { + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { mutex_unlock(&vc4_hdmi->mutex); return -ENODEV; } @@ -1540,6 +1556,11 @@ static int vc4_hdmi_audio_prepare(struct mutex_lock(&vc4_hdmi->mutex); + if (!vc4_hdmi_audio_can_stream(vc4_hdmi)) { + mutex_unlock(&vc4_hdmi->mutex); + return -EINVAL; + } + vc4_hdmi_audio_set_mai_clock(vc4_hdmi, sample_rate); spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);