summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2016-02-02 15:01:12 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:17:52 -0700
commit88af065f71baa8f7166b399bc5211732cf394b02 (patch)
tree58504924ab85aecf055bd6126e0b5f4c42781965 /drivers/video/fbdev
parent62be9c73b908d1f335a1844da9236eea4a0f9aa6 (diff)
msm: mdss: hdmi: protect hpd power from multi-thread access
HPD (Hot Plug Detect) can be powered on or off by down stream device like MHL or slimport driver based on cable connection triggered by user. In response to that, HDMI transmitter power on and off is triggered in a different thread. There can be a race condition with transmitter power on/off and HPD power on and off with fast plug in/out. Protect these functionalities using mutex to avoid such race conditions and keep the HDMI state machine in valid state. Change-Id: I7fa8de10b96ca3cf674a0b7cf83b0f96cc177509 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c45
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.h1
2 files changed, 19 insertions, 27 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index a136da353a47..cdc8cc52f5c7 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -887,6 +887,8 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
goto end;
}
+ hdmi_ctrl->audio_ack_enabled = false;
+
hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0);
hdmi_tx_wait_for_audio_engine(hdmi_ctrl);
hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
@@ -1944,7 +1946,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
struct dss_io_data *io;
hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
- if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+ if (!hdmi_ctrl) {
DEV_DBG("%s: invalid input\n", __func__);
return;
}
@@ -1952,6 +1954,11 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
mutex_lock(&hdmi_ctrl->tx_lock);
+ if (!hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("hpd not initialized\n");
+ goto end;
+ }
+
DEV_DBG("%s: %s\n", __func__,
hdmi_ctrl->hpd_state ? "CONNECT" : "DISCONNECT");
@@ -1978,9 +1985,6 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
hdmi_tx_send_cable_notification(hdmi_ctrl, false);
}
end:
- if (!completion_done(&hdmi_ctrl->hpd_int_done))
- complete_all(&hdmi_ctrl->hpd_int_done);
-
mutex_unlock(&hdmi_ctrl->tx_lock);
} /* hdmi_tx_hpd_int_work */
@@ -3964,9 +3968,6 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->hpd_initialized = false;
hdmi_ctrl->hpd_off_pending = false;
- if (!completion_done(&hdmi_ctrl->hpd_off_done))
- complete_all(&hdmi_ctrl->hpd_off_done);
-
DEV_DBG("%s: HPD is now OFF\n", __func__);
} /* hdmi_tx_hpd_off */
@@ -4039,21 +4040,9 @@ static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
return -EINVAL;
}
- DEV_INFO("%s: %d\n", __func__, on);
+ DEV_DBG("%s: %d\n", __func__, on);
if (on) {
- if (hdmi_ctrl->hpd_off_pending) {
- u32 timeout;
-
- reinit_completion(&hdmi_ctrl->hpd_off_done);
- timeout = wait_for_completion_timeout(
- &hdmi_ctrl->hpd_off_done, HZ);
- if (!timeout) {
- hdmi_ctrl->hpd_off_pending = false;
- DEV_ERR("%s: hpd off still pending\n",
- __func__);
- return 0;
- }
- }
+ hdmi_ctrl->hpd_off_pending = false;
rc = hdmi_tx_hpd_on(hdmi_ctrl);
} else {
@@ -4078,6 +4067,8 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
return -EINVAL;
}
+ mutex_lock(&hdmi_ctrl->tx_lock);
+
/* mhl status should override */
hdmi_ctrl->mhl_hpd_on = on;
@@ -4088,7 +4079,7 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
} else {
DEV_DBG("%s: hpd is already '%s'. return\n", __func__,
hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled");
- return rc;
+ goto end;
}
if (!rc) {
@@ -4099,9 +4090,9 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on)
DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__,
on ? "enable" : "disable", rc);
}
-
+end:
+ mutex_unlock(&hdmi_ctrl->tx_lock);
return rc;
-
}
static irqreturn_t hdmi_tx_isr(int irq, void *data)
@@ -4131,6 +4122,9 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data)
(DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
+ if (!completion_done(&hdmi_ctrl->hpd_int_done))
+ complete_all(&hdmi_ctrl->hpd_int_done);
+
/*
* check if this is a spurious interrupt, if yes, reset
* interrupts and return
@@ -4272,7 +4266,6 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->hpd_initialized = false;
hdmi_ctrl->hpd_off_pending = false;
init_completion(&hdmi_ctrl->hpd_int_done);
- init_completion(&hdmi_ctrl->hpd_off_done);
INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work);
@@ -4516,7 +4509,7 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data,
if (!hdmi_ctrl->hpd_feature_on)
goto end;
- if (!hdmi_ctrl->panel_power_on)
+ if (!hdmi_ctrl->hpd_state && !hdmi_ctrl->panel_power_on)
hdmi_tx_hpd_off(hdmi_ctrl);
hdmi_ctrl->panel_suspend = true;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index 89f0be0f3143..4507cac30463 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -157,7 +157,6 @@ struct hdmi_tx_ctrl {
struct hdmi_util_ds_data ds_data;
struct completion hpd_int_done;
- struct completion hpd_off_done;
struct work_struct hpd_int_work;
struct delayed_work hdcp_cb_work;