summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkrishna kishore <kthota@nvidia.com>2010-07-16 22:11:55 +0530
committerGary King <gking@nvidia.com>2010-07-26 15:09:29 -0700
commitdf8cf1f41f62864ba2131cc6920d917933b908c5 (patch)
tree368c5b3c14ebb937c81e033a3b11d90d7eeb08d7
parent69ceb273e12caf3ceb4bc3d2aeb69c441046ed6d (diff)
[ARM] tegra: suspend: add work-around for AP20 A03 LP0 restore
SDRAM initialization is broken in the boot ROM on AP20 A03, so LP0 restore needs to reload the first-stage bootloader and then jump to its LP0 restore sequence. to trigger this behavior, the lp0 flag is moved to a dummy location in the scratch register which the boot ROM ignores, but the bootloader will detect. Change-Id: Iea144e7440367938755ab66d67758558bc184b44 Reviewed-on: http://git-master/r/4022 Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/board.h5
-rw-r--r--arch/arm/mach-tegra/common.c15
-rw-r--r--arch/arm/mach-tegra/suspend.c12
3 files changed, 30 insertions, 2 deletions
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index d3e4f7e67fc4..e6801c4b5c24 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -44,5 +44,10 @@ int tegra_start_dvfsd(void);
#define tegra_start_dvfsd() (0)
#endif
+#define TEGRA_ALL_REVS (~0ul)
+bool tegra_chip_compare(u32 chip, u32 major_rev, u32 minor_rev);
+
+#define tegra_is_ap20_a03() tegra_chip_compare(0x20, 0x1, 0x3)
+
extern struct sys_timer tegra_timer;
#endif
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 984e1d326715..ce9decb0dfa2 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -31,6 +31,21 @@
#include "board.h"
+#define APB_MISC_HIDREV 0x804
+
+bool tegra_chip_compare(u32 chip, u32 major_rev, u32 minor_rev)
+{
+ void __iomem *misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ u32 val = readl(misc + APB_MISC_HIDREV);
+ u32 id = (val>>8) & 0xff;
+ u32 minor = (val>>16) & 0xf;
+ u32 major = (val>>4) & 0xf;
+
+ return (chip==id) &&
+ (minor_rev==minor || minor_rev==TEGRA_ALL_REVS) &&
+ (major_rev==major || major_rev==TEGRA_ALL_REVS);
+}
+
#ifdef CONFIG_DMABOUNCE
int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
{
diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c
index 8eda2fab9873..b0d84eee10ee 100644
--- a/arch/arm/mach-tegra/suspend.c
+++ b/arch/arm/mach-tegra/suspend.c
@@ -49,6 +49,7 @@
#include "nvrm/core/common/nvrm_message.h"
#include "power.h"
+#include "board.h"
/* NOTE: only add elements to the end of this structure, since the assembly
* code uses hard-coded offsets */
@@ -344,9 +345,16 @@ static void tegra_setup_warmboot(void)
{
u32 scratch0;
- /* Turn the WARMBOOT flag on in scratch0 */
scratch0 = readl(pmc + PMC_SCRATCH0);
- scratch0 |= 1;
+ /* lp0 restore is broken in the ap20 a03 boot rom, so fake the
+ * bootrom into performing a regular boot, but pass a flag to the
+ * bootloader to bypass the kernel reload and jump to the lp0
+ * restore sequence */
+ if (tegra_is_ap20_a03())
+ scratch0 |= (1<<5);
+ else
+ scratch0 |= 1;
+
pmc_32kwritel(scratch0, PMC_SCRATCH0);
/* Write the AVP warmboot entry address in SCRATCH1 */