summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMin-wuk Lee <mlee@nvidia.com>2013-09-06 17:43:06 +0900
committerGabby Lee <galee@nvidia.com>2013-09-10 19:02:19 -0700
commit8a2f117c4472919ec22263c858fbac1a91ee5e72 (patch)
tree5b3c24ad96831464848e70d253e59238cf17d58c
parentedf22c31968ec0658e1315f9c6d468f3961c9e1e (diff)
tegra: video: hdmi: WAR: ensure hdcp register access with clk enabled
There is a race condition between hdcp upstream and hdmi disable during suspend/resume stress with hdmi plugged-in. WAR by making host1x/hdmi clk enabled and hdmi clk out of reset. Bug 1349507 Change-Id: I6870066358900d6f6798b3e20bc59bf5645f25b8 Original-author: Roger Hsieh <rhsieh@nvidia.com> Signed-off-by: Roger Hsieh <rhsieh@nvidia.com> Signed-off-by: Min-wuk Lee <mlee@nvidia.com> Reviewed-on: http://git-master/r/271389 GVS: Gerrit_Virtual_Submit Reviewed-by: Gabby Lee <galee@nvidia.com> Tested-by: Gabby Lee <galee@nvidia.com>
-rw-r--r--drivers/video/tegra/dc/hdmi.c38
-rw-r--r--security/tf_driver/tf_device.c5
2 files changed, 39 insertions, 4 deletions
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index ccce7c707f35..0f98cd75acaa 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -109,6 +109,7 @@ struct tegra_dc_hdmi_data {
};
struct tegra_dc_hdmi_data *dc_hdmi;
+atomic_t __maybe_unused tf_hdmi_enable = ATOMIC_INIT(0);
#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
const struct tmds_config tmds_config[] = {
@@ -470,6 +471,34 @@ static inline void tegra_hdmi_hotplug_enable(struct tegra_dc_hdmi_data *hdmi)
enable_irq(gpio_to_irq(dc->out->hotplug_gpio));
}
+void tegra_hdmi_enable_clk(void)
+{
+ struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
+ struct tegra_dc *dc = hdmi->dc;
+
+ mutex_lock(&dc->lock);
+ clk_prepare_enable(hdmi->disp1_clk);
+ clk_prepare_enable(hdmi->disp2_clk);
+ clk_prepare_enable(hdmi->clk);
+ mutex_unlock(&dc->lock);
+ atomic_set(&tf_hdmi_enable, 1);
+}
+EXPORT_SYMBOL(tegra_hdmi_enable_clk);
+
+void tegra_hdmi_disable_clk(void)
+{
+ struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
+ struct tegra_dc *dc = hdmi->dc;
+
+ atomic_set(&tf_hdmi_enable, 0);
+ mutex_lock(&dc->lock);
+ clk_disable_unprepare(hdmi->clk);
+ clk_disable_unprepare(hdmi->disp1_clk);
+ clk_disable_unprepare(hdmi->disp2_clk);
+ mutex_unlock(&dc->lock);
+
+}
+EXPORT_SYMBOL(tegra_hdmi_disable_clk);
#ifdef CONFIG_DEBUG_FS
static int dbg_hdmi_show(struct seq_file *m, void *unused)
@@ -1840,9 +1869,11 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
clk_set_rate(hdmi->clk, dc->mode.pclk);
clk_prepare_enable(hdmi->clk);
- tegra_periph_reset_assert(hdmi->clk);
- mdelay(1);
- tegra_periph_reset_deassert(hdmi->clk);
+ if (!atomic_read(&tf_hdmi_enable)) {
+ tegra_periph_reset_assert(hdmi->clk);
+ mdelay(1);
+ tegra_periph_reset_deassert(hdmi->clk);
+ }
/* TODO: copy HDCP keys from KFUSE to HDMI */
@@ -2059,7 +2090,6 @@ static void tegra_dc_hdmi_disable(struct tegra_dc *dc)
clk_disable_unprepare(hdmi->hda2codec_clk);
clk_disable_unprepare(hdmi->hda_clk);
#endif
- tegra_periph_reset_assert(hdmi->clk);
hdmi->clk_enabled = false;
clk_disable_unprepare(hdmi->clk);
tegra_dvfs_set_rate(hdmi->clk, 0);
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c
index 70d6a70a6244..3a10acf93b1f 100644
--- a/security/tf_driver/tf_device.c
+++ b/security/tf_driver/tf_device.c
@@ -55,6 +55,9 @@
* Forward Declarations
*----------------------------------------------------------------------------*/
+extern void tegra_hdmi_enable_clk(void);
+extern void tegra_hdmi_disable_clk(void);
+
/*
* Creates and registers the device to be managed by the specified driver.
*
@@ -743,10 +746,12 @@ static long tf_device_ioctl(struct file *file, unsigned int ioctl_num,
break;
case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND:
+ tegra_hdmi_enable_clk();
trace_invoke_client_command(NVSEC_INVOKE_CMD_START);
result = tf_invoke_client_command(connection,
&command, &answer);
trace_invoke_client_command(NVSEC_INVOKE_CMD_DONE);
+ tegra_hdmi_disable_clk();
break;
case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: