summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/sleep.h
diff options
context:
space:
mode:
authorKarthik Ramakrishnan <karthikr@nvidia.com>2012-08-13 19:09:16 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:33:06 -0700
commit5d251728785fbf4a34e98b78d07168a0241d5b6c (patch)
tree39a3e2d21cb76b86c12d2150e7115ec2d137b90c /arch/arm/mach-tegra/sleep.h
parentf7f40b5fd389527b7902c2989fc192a057568bf4 (diff)
arm: tegra: Set Core to 0.95V in LP1
When the device prepares for LP1, the Core voltage is set to the highest value(1.2V for Enterprise and Kai, and 1.3V for AP37 and Cardhu). This is to set for some of the driver suspend along the sequence need a higher emc frequency and thus a higher Core voltage. Since the sequence of drivers suspend depends on the sequence of their registration in the table, which in turn is platform-dependent, there is no right place in the LP1 entry path where the Core voltage can be set to a lower voltage. Hence, the Core voltage remains high in LP1 resulting in higher power. Thus, the only safe location where the Core voltage can be lowered is once all the drivers are suspended and the DRAM is set in self-refresh, at the final point just before the system is suspended in the IRAM code. This location at the assembly code ensures that no other module will be running and thus that nothing will require a higher core voltage. The Core is set to the lowest possible value since nothing requires it. It is then restored to the highest voltage as soon as the LP1 resume code is started so that all drivers are resumed safely. At the execution point in IRAM during LP1 suspend path, even the I2C clocks are gated. They must be reset first and then the I2C transaction is performed. An I2C transaction involves 4 bytes of data, to send the slave address, the Core voltage register address and 2 bytes of data which has the value to set the voltage(the second byte is not required for this transaction). Once these registers are set, the I2C transaction is performed by setting the I2C transaction register to 0xA02. After sending the I2C transaction, we wait for about 250us to check the status of the transaction and if not updated, wait for more time to check again. If after 2ms and the transaction fails to register, the transaction is aborted and the device is allowed to enter at high voltage. Since the failure rate of I2C transaction is very low at this point in execution where there will be no conflicts in the bus, it is okay to have Core high for some of the LP1 cycles. However, it is unacceptable for the I2C transaction to fail on the way from LP1 resume since the device cannot come up with a lower Core voltage. In this case, the transaction is retried again and again till it is successful. There is no way but to keep trying as the device would fail to resume with Core at 0.95V. Each platform(or each PMU) has different values for the I2C transaction ie. slave address, Core voltage register and the value to set the voltage. For the device in IRAM, it cannot access anything in SDRAM memory, these values needs to be pushed to IRAM memory before the device starts execution in IRAM. This is done during initialization of suspend code when it picks values from the board files and copies it to IRAM part of code, before the whole memory is copied to IRAM. This new feature is controlled by a KConfig variable TEGRA_LP1_950 which should be enabled once the board file of the device is updated with the right values. The device hangs when it does not have the right values for the I2C transaction. With this change in Core, LP1 power is reduced by 12mW in Enterprise, 20mW in AP37 and about 24mW in Kai. Bug 1035684 Change-Id: I4318c66fd70ab227ef0786d6a13286e020e4541d Signed-off-by: Karthik Ramakrishnan <karthikr@nvidia.com> (cherry picked from commit ab476f287376fd0ae51a9f298659f5eba19f0296) Reviewed-on: http://git-master/r/124779 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com> Rebase-Id: Re0625362698d402125337251c6b8337c2b2eb52d
Diffstat (limited to 'arch/arm/mach-tegra/sleep.h')
-rw-r--r--arch/arm/mach-tegra/sleep.h40
1 files changed, 40 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index c658e6589f65..43afbd03c6ee 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -252,6 +252,10 @@ int tegra2_finish_sleep_cpu_secondary(unsigned long int);
#else
extern unsigned int tegra3_iram_start;
extern unsigned int tegra3_iram_end;
+extern unsigned int lp1_register_pmuslave_addr;
+extern unsigned int lp1_register_i2c_base_addr;
+extern unsigned int lp1_register_core_lowvolt;
+extern unsigned int lp1_register_core_highvolt;
int tegra3_sleep_core_finish(unsigned long int);
int tegra3_sleep_cpu_secondary_finish(unsigned long int);
#endif
@@ -273,5 +277,41 @@ static inline void *tegra_iram_end(void)
return &tegra3_iram_end;
#endif
}
+
+static inline void *tegra_lp1_register_pmuslave_addr(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_pmuslave_addr;
+#endif
+}
+
+static inline void *tegra_lp1_register_i2c_base_addr(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_i2c_base_addr;
+#endif
+}
+
+static inline void *tegra_lp1_register_core_lowvolt(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_core_lowvolt;
+#endif
+}
+
+static inline void *tegra_lp1_register_core_highvolt(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_core_highvolt;
+#endif
+}
#endif
#endif