summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dp/dp_audio.c
diff options
context:
space:
mode:
authorAbhinav Kumar <abhinavk@codeaurora.org>2020-09-12 13:49:32 -0700
committerRob Clark <robdclark@chromium.org>2020-09-15 10:54:35 -0700
commit158b9aa74479c9979b7b4806cefdbf0c9a72ba49 (patch)
tree6768265267b788f69ada719bc8440524ee63b0e8 /drivers/gpu/drm/msm/dp/dp_audio.c
parentbf4a1b3127d34b0b6ee0565b31ff699b3dc9c48e (diff)
downloadlinux-158b9aa74479c9979b7b4806cefdbf0c9a72ba49.tar.bz2
drm/msm/dp: wait for audio notification before disabling clocks
In the current implementation, there is a very small window for the audio side to safely signal the hdmi_code_shutdown() before the clocks are disabled. Add some synchronization between the DP display and DP audio module to safely disable the clocks to avoid unclocked access from audio side. In addition, audio side can open the sound card even if DP monitor is not connected. Avoid programming hardware registers in this case and bail out early. Changes in v4: - removed some leftover prints Changes in v5: - fix crash when user tries to play audio in suspended state Changes in v6: - rebased on top of latest patchset of dependency Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org> Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_audio.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_audio.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index 11fa5ad7a801..82a8673ab8da 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -497,8 +497,23 @@ int dp_audio_hw_params(struct device *dev,
int rc = 0;
struct dp_audio_private *audio;
struct platform_device *pdev;
+ struct msm_dp *dp_display;
pdev = to_platform_device(dev);
+ dp_display = platform_get_drvdata(pdev);
+
+ /*
+ * there could be cases where sound card can be opened even
+ * before OR even when DP is not connected . This can cause
+ * unclocked access as the audio subsystem relies on the DP
+ * driver to maintain the correct state of clocks. To protect
+ * such cases check for connection status and bail out if not
+ * connected.
+ */
+ if (!dp_display->power_on) {
+ rc = -EINVAL;
+ goto end;
+ }
audio = dp_audio_get_data(pdev);
if (IS_ERR(audio)) {
@@ -512,6 +527,8 @@ int dp_audio_hw_params(struct device *dev,
dp_audio_setup_acr(audio);
dp_audio_safe_to_exit_level(audio);
dp_audio_enable(audio, true);
+ dp_display->audio_enabled = true;
+
end:
return rc;
}
@@ -520,15 +537,30 @@ static void dp_audio_shutdown(struct device *dev, void *data)
{
struct dp_audio_private *audio;
struct platform_device *pdev;
+ struct msm_dp *dp_display;
pdev = to_platform_device(dev);
+ dp_display = platform_get_drvdata(pdev);
audio = dp_audio_get_data(pdev);
if (IS_ERR(audio)) {
DRM_ERROR("failed to get audio data\n");
return;
}
+ /*
+ * if audio was not enabled there is no need
+ * to execute the shutdown and we can bail out early.
+ * This also makes sure that we dont cause an unclocked
+ * access when audio subsystem calls this without DP being
+ * connected. is_connected cannot be used here as its set
+ * to false earlier than this call
+ */
+ if (!dp_display->audio_enabled)
+ return;
+
dp_audio_enable(audio, false);
+ /* signal the dp display to safely shutdown clocks */
+ dp_display_signal_audio_complete(dp_display);
}
static const struct hdmi_codec_ops dp_audio_codec_ops = {