summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp/dp_display.c
diff options
context:
space:
mode:
authorAbhinav Kumar <abhinavk@codeaurora.org>2020-09-12 23:49:32 +0300
committerRob Clark <robdclark@chromium.org>2020-09-15 20:54:35 +0300
commit158b9aa74479c9979b7b4806cefdbf0c9a72ba49 (patch)
tree6768265267b788f69ada719bc8440524ee63b0e8 /drivers/gpu/drm/msm/dp/dp_display.c
parentbf4a1b3127d34b0b6ee0565b31ff699b3dc9c48e (diff)
downloadlinux-158b9aa74479c9979b7b4806cefdbf0c9a72ba49.tar.xz
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_display.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 32d2236b20b2..6f7795dc9bc3 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -82,7 +82,6 @@ struct dp_display_private {
/* state variables */
bool core_initialized;
- bool power_on;
bool hpd_irq_on;
bool audio_supported;
@@ -104,6 +103,9 @@ struct dp_display_private {
struct dp_display_mode dp_mode;
struct msm_dp dp_display;
+ /* wait for audio signaling */
+ struct completion audio_comp;
+
/* event related only access by event thread */
struct mutex event_mutex;
wait_queue_head_t event_q;
@@ -177,6 +179,15 @@ static int dp_del_event(struct dp_display_private *dp_priv, u32 event)
return 0;
}
+void dp_display_signal_audio_complete(struct msm_dp *dp_display)
+{
+ struct dp_display_private *dp;
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ complete_all(&dp->audio_comp);
+}
+
static int dp_display_bind(struct device *dev, struct device *master,
void *data)
{
@@ -599,6 +610,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
/* signal the disconnect event early to ensure proper teardown */
dp_display_handle_plugged_change(g_dp_display, false);
+ reinit_completion(&dp->audio_comp);
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK |
DP_DP_IRQ_HPD_INT_MASK, true);
@@ -793,15 +805,18 @@ static int dp_display_prepare(struct msm_dp *dp)
static int dp_display_enable(struct dp_display_private *dp, u32 data)
{
int rc = 0;
+ struct msm_dp *dp_display;
- if (dp->power_on) {
+ dp_display = g_dp_display;
+
+ if (dp_display->power_on) {
DRM_DEBUG_DP("Link already setup, return\n");
return 0;
}
rc = dp_ctrl_on_stream(dp->ctrl);
if (!rc)
- dp->power_on = true;
+ dp_display->power_on = true;
/* complete resume_comp regardless it is armed or not */
complete(&dp->resume_comp);
@@ -829,14 +844,27 @@ static int dp_display_post_enable(struct msm_dp *dp_display)
static int dp_display_disable(struct dp_display_private *dp, u32 data)
{
- if (!dp->power_on)
+ struct msm_dp *dp_display;
+
+ dp_display = g_dp_display;
+
+ if (!dp_display->power_on)
return -EINVAL;
+ /* wait only if audio was enabled */
+ if (dp_display->audio_enabled) {
+ if (!wait_for_completion_timeout(&dp->audio_comp,
+ HZ * 5))
+ DRM_ERROR("audio comp timeout\n");
+ }
+
+ dp_display->audio_enabled = false;
+
dp_ctrl_off(dp->ctrl);
dp->core_initialized = false;
- dp->power_on = false;
+ dp_display->power_on = false;
return 0;
}
@@ -1152,6 +1180,8 @@ static int dp_display_probe(struct platform_device *pdev)
/* Store DP audio handle inside DP display */
g_dp_display->dp_audio = dp->audio;
+ init_completion(&dp->audio_comp);
+
platform_set_drvdata(pdev, g_dp_display);
rc = component_add(&pdev->dev, &dp_display_comp_ops);