summaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/system.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/system.c')
-rw-r--r--arch/arm/mach-imx/system.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index df3d1ff0c288..3e923f6b1cf1 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
- * Copyright (C) 2006-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2014 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
* Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com
*
@@ -31,11 +31,69 @@
#include "common.h"
#include "hardware.h"
+#include "mx6.h"
static void __iomem *wdog_base;
static struct clk *wdog_clk;
static u32 wdog_source = 1; /* use WDOG1 default */
+#ifdef CONFIG_MXC_REBOOT_ANDROID_CMD
+/* This function will set a bit on SNVS_LPGPR[7-8] bits to enter
+ * special boot mode. These bits will not clear by watchdog reset, so
+ * it can be checked by bootloader to choose enter different mode.*/
+
+#define ANDROID_RECOVERY_BOOT (1 << 7)
+#define ANDROID_FASTBOOT_BOOT (1 << 8)
+
+#define AIPS1_ARB_BASE_ADDR 0x02000000
+#define ATZ1_BASE_ADDR AIPS1_ARB_BASE_ADDR
+#define AIPS1_OFF_BASE_ADDR (ATZ1_BASE_ADDR + 0x80000)
+#define MX6_SNVS_BASE_ADDR (AIPS1_OFF_BASE_ADDR + 0x4C000)
+#define SNVS_LPGPR 0x68
+#define SNVS_SIZE (1024*16)
+void do_switch_recovery(void)
+{
+ u32 reg;
+ u32 addr;
+ addr = ioremap(MX6_SNVS_BASE_ADDR, SNVS_SIZE);
+ if (!addr) {
+ pr_warn("SNVS ioremap failed!\n");
+ return;
+ }
+ reg = __raw_readl(addr + SNVS_LPGPR);
+ reg |= ANDROID_RECOVERY_BOOT;
+ __raw_writel(reg, (addr + SNVS_LPGPR));
+
+ iounmap(addr);
+}
+
+void do_switch_fastboot(void)
+{
+ u32 reg;
+ u32 addr;
+
+ addr = ioremap(MX6_SNVS_BASE_ADDR, SNVS_SIZE);
+ if (!addr) {
+ pr_warn("SNVS ioremap failed!\n");
+ return;
+ }
+
+ reg = __raw_readl(addr + SNVS_LPGPR);
+ reg |= ANDROID_FASTBOOT_BOOT;
+ __raw_writel(reg, addr + SNVS_LPGPR);
+
+ iounmap(addr);
+}
+#endif
+static void arch_reset_special_mode(char mode, const char *cmd)
+{
+#ifdef CONFIG_MXC_REBOOT_ANDROID_CMD
+ if (cmd && strcmp(cmd, "recovery") == 0)
+ do_switch_recovery();
+ else if (cmd && strcmp(cmd, "fastboot") == 0)
+ do_switch_fastboot();
+#endif
+}
/*
* Reset the system. It is called by machine_restart().
*/
@@ -43,6 +101,8 @@ void mxc_restart(char mode, const char *cmd)
{
unsigned int wcr_enable;
+ arch_reset_special_mode(mode, cmd);
+
if (wdog_clk)
clk_enable(wdog_clk);