summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-10-22 19:06:33 -0700
committerSimone Willett <swillett@nvidia.com>2011-10-26 15:56:07 -0700
commit677c01d3d9edaf7e91f09de5025e7864b6a288d8 (patch)
tree59bdb4de7a1ae484eefc489fdf040b3a2a0aafa3
parentc65d7a774f9d7112001cfe38bfe45d3d7e498d9a (diff)
ARM: tegra: power: Enable Tegra3 EMC bridge in suspend
When dvfs is suspended core rail is set to nominal voltage underneath clock framework. On Tegra3 DDR3 platforms low EMC rates are not safe at high voltage that exceeds EMC bridge minimum level. Enabling EMC bridge during suspend for Tegra3 DDR3 platforms guarantees safe EMC operations at high voltage. Change-Id: Ib653dd50071a07e92faa9e2c472211c75a8d1525 Reviewed-on: http://git-master/r/60118 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/tegra3_emc.c b/arch/arm/mach-tegra/tegra3_emc.c
index 76fd8ff0a8c9..98ad9326b375 100644
--- a/arch/arm/mach-tegra/tegra3_emc.c
+++ b/arch/arm/mach-tegra/tegra3_emc.c
@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -195,9 +196,10 @@ static int tegra_emc_table_size;
static u32 dram_dev_num;
static u32 emc_cfg_saved;
-
static u32 dram_type = -1;
+
static struct clk *emc;
+static struct clk *bridge;
static struct {
cputime64_t time_at_clock[TEGRA_EMC_TABLE_MAX_SIZE];
@@ -746,7 +748,8 @@ static bool is_emc_bridge(void)
{
int mv;
unsigned long rate;
- struct clk *bridge = tegra_get_clock_by_name("bridge.emc");
+
+ bridge = tegra_get_clock_by_name("bridge.emc");
BUG_ON(!bridge);
/* LPDDR2 does not need a bridge entry in DFS table: just lock bridge
@@ -772,6 +775,44 @@ static bool is_emc_bridge(void)
return true;
}
+static int tegra_emc_suspend_notify(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ if (event != PM_SUSPEND_PREPARE)
+ return NOTIFY_OK;
+
+ if (dram_type == DRAM_TYPE_DDR3) {
+ if (clk_enable(bridge)) {
+ pr_info("Tegra emc suspend:"
+ " failed to enable bridge.emc\n");
+ return NOTIFY_STOP;
+ }
+ pr_info("Tegra emc suspend: enabled bridge.emc\n");
+ }
+ return NOTIFY_OK;
+};
+static struct notifier_block tegra_emc_suspend_nb = {
+ .notifier_call = tegra_emc_suspend_notify,
+ .priority = 2,
+};
+
+static int tegra_emc_resume_notify(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ if (event != PM_POST_SUSPEND)
+ return NOTIFY_OK;
+
+ if (dram_type == DRAM_TYPE_DDR3) {
+ clk_disable(bridge);
+ pr_info("Tegra emc resume: disabled bridge.emc\n");
+ }
+ return NOTIFY_OK;
+};
+static struct notifier_block tegra_emc_resume_nb = {
+ .notifier_call = tegra_emc_resume_notify,
+ .priority = -1,
+};
+
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
{
int i;
@@ -871,6 +912,9 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
pr_err("tegra: invalid EMC DFS table: emc bridge not found");
}
pr_info("tegra: validated EMC DFS table\n");
+
+ register_pm_notifier(&tegra_emc_suspend_nb);
+ register_pm_notifier(&tegra_emc_resume_nb);
}
void tegra_emc_timing_invalidate(void)