diff options
author | Alex Frid <afrid@nvidia.com> | 2011-10-22 19:06:33 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2011-10-26 15:56:07 -0700 |
commit | 677c01d3d9edaf7e91f09de5025e7864b6a288d8 (patch) | |
tree | 59bdb4de7a1ae484eefc489fdf040b3a2a0aafa3 | |
parent | c65d7a774f9d7112001cfe38bfe45d3d7e498d9a (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.c | 48 |
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) |