[PATCH 4/7] ARM: mmp: update the reset implementation
Haojian Zhuang
haojian.zhuang at marvell.com
Fri Apr 8 08:15:41 EDT 2011
Both PXA910 and MMP2 need watchdog reset, so add these features.
Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
arch/arm/mach-mmp/Makefile | 2 +-
arch/arm/mach-mmp/include/mach/regs-mpmu.h | 52 +++++++++++++
arch/arm/mach-mmp/include/mach/regs-timers.h | 2 +
arch/arm/mach-mmp/include/mach/system.h | 8 +--
arch/arm/mach-mmp/reset.c | 100 ++++++++++++++++++++++++++
5 files changed, 156 insertions(+), 8 deletions(-)
create mode 100644 arch/arm/mach-mmp/include/mach/regs-mpmu.h
create mode 100644 arch/arm/mach-mmp/reset.c
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 5c68382..6043f31 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,7 +2,7 @@
# Makefile for Marvell's PXA168 processors line
#
-obj-y += common.o clock.o devices.o time.o
+obj-y += common.o clock.o devices.o time.o reset.o
# SoC support
obj-$(CONFIG_CPU_PXA168) += pxa168.o irq-pxa168.o
diff --git a/arch/arm/mach-mmp/include/mach/regs-mpmu.h b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
new file mode 100644
index 0000000..e2fdc4e
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
@@ -0,0 +1,52 @@
+/*
+ * linux/arch/arm/mach-mmp/include/mach/regs-mpmu.h
+ *
+ * Main Power Management Unit
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_MACH_REGS_MPMU_H
+#define __ASM_MACH_REGS_MPMU_H
+
+#include <mach/addr-map.h>
+
+#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(off) (MPMU_VIRT_BASE + (off))
+
+#define MPMU_CPCR MPMU_REG(0x0000)
+#define MPMU_FCCR MPMU_REG(0x0008)
+#define MPMU_POCR MPMU_REG(0x000c)
+#define MPMU_POSR MPMU_REG(0x0010)
+#define MPMU_SUCCR MPMU_REG(0x0014)
+#define MPMU_VRCR MPMU_REG(0x0018)
+#define MPMU_OHCR MPMU_REG(0x001c)
+#define MPMU_CPRR MPMU_REG(0x0020)
+#define MPMU_CCGR MPMU_REG(0x0024)
+#define MPMU_GPCR MPMU_REG(0x0030)
+#define MPMU_PLL2CR MPMU_REG(0x0034)
+#define MPMU_SCCR MPMU_REG(0x0038)
+#define MPMU_ISCCRX0 MPMU_REG(0x0040)
+#define MPMU_ISCCRX1 MPMU_REG(0x0044)
+#define MPMU_CWUCRM MPMU_REG(0x004c)
+#define MPMU_PLL1_REG1 MPMU_REG(0x0050)
+#define MPMU_PLL1_REG2 MPMU_REG(0x0054)
+#define MPMU_PLL1_SSC MPMU_REG(0x0058)
+#define MPMU_PLL2_REG1 MPMU_REG(0x0060)
+#define MPMU_PLL2_REG2 MPMU_REG(0x0064)
+#define MPMU_PLL2_SSC MPMU_REG(0x0068)
+#define MPMU_SD_ROT_WAKE_CLR MPMU_REG(0x007c)
+#define MPMU_PLL2_CTRL1 MPMU_REG(0x0414)
+#define MPMU_TS MPMU_REG(0x0080)
+#define MPMU_WDTPCR MPMU_REG(0x0200)
+#define MPMU_APCR MPMU_REG(0x1000)
+#define MPMU_APSR MPMU_REG(0x1004)
+#define MPMU_APRR MPMU_REG(0x1020)
+#define MPMU_ACGR MPMU_REG(0x1024)
+#define MPMU_ARSR MPMU_REG(0x1028)
+#define MPMU_AWUCRS MPMU_REG(0x1048)
+#define MPMU_AWUCRM MPMU_REG(0x104c)
+
+#endif /* __ASM_MACH_REGS_MPMU_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-timers.h b/arch/arm/mach-mmp/include/mach/regs-timers.h
index 45589fe..17f56fe 100644
--- a/arch/arm/mach-mmp/include/mach/regs-timers.h
+++ b/arch/arm/mach-mmp/include/mach/regs-timers.h
@@ -15,6 +15,8 @@
#define TIMERS1_VIRT_BASE (APB_VIRT_BASE + 0x14000)
#define TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x16000)
+#define CP_TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x80000)
+#define MMP2_TIMERS2_VIRT_BASE (APB_VIRT_BASE + 0x80000)
#define TMR_CCR (0x0000)
#define TMR_TN_MM(n, m) (0x0004 + ((n) << 3) + (((n) + (m)) << 2))
diff --git a/arch/arm/mach-mmp/include/mach/system.h b/arch/arm/mach-mmp/include/mach/system.h
index 1a8a25e..31e15cf 100644
--- a/arch/arm/mach-mmp/include/mach/system.h
+++ b/arch/arm/mach-mmp/include/mach/system.h
@@ -16,11 +16,5 @@ static inline void arch_idle(void)
cpu_do_idle();
}
-static inline void arch_reset(char mode, const char *cmd)
-{
- if (cpu_is_pxa168())
- cpu_reset(0xffff0000);
- else
- cpu_reset(0);
-}
+extern void arch_reset(char mode, const char *cmd);
#endif /* __ASM_MACH_SYSTEM_H */
diff --git a/arch/arm/mach-mmp/reset.c b/arch/arm/mach-mmp/reset.c
new file mode 100644
index 0000000..57fa65e
--- /dev/null
+++ b/arch/arm/mach-mmp/reset.c
@@ -0,0 +1,100 @@
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <mach/regs-mpmu.h>
+#include <mach/regs-timers.h>
+#include <mach/cputype.h>
+#include <linux/delay.h>
+
+#define REG_RTC_BR0 (APB_VIRT_BASE + 0x010014)
+
+#define MPMU_APRR_CPR (1 << 0)
+#define MPMU_APRR_WDTR (1 << 4)
+#define MPMU_CPRR_DSPR (1 << 2)
+#define MPMU_CPRR_BBR (1 << 3)
+
+static void do_wdt_reset(const char *cmd)
+{
+ unsigned int reg, backup;
+ unsigned int watchdog_virt_base;
+ int i;
+ int match = 0, count = 0;
+
+ if (cpu_is_pxa910())
+ watchdog_virt_base = CP_TIMERS2_VIRT_BASE;
+ else if (cpu_is_pxa168())
+ watchdog_virt_base = TIMERS1_VIRT_BASE;
+ else if (cpu_is_mmp2())
+ watchdog_virt_base = MMP2_TIMERS2_VIRT_BASE;
+ else
+ return;
+
+ /* reset/enable WDT clock */
+ writel(0x7, MPMU_WDTPCR);
+ readl(MPMU_WDTPCR);
+ writel(0x3, MPMU_WDTPCR);
+ readl(MPMU_WDTPCR);
+
+ if (cpu_is_pxa910()) {
+ /* stores recovery flag into RTC register */
+ if (cmd && !strcmp(cmd, "recovery")) {
+ for (i = 0, backup = 0; i < 4; i++) {
+ backup <<= 8;
+ backup |= *(cmd + i);
+ }
+ do {
+ writel(backup, REG_RTC_BR0);
+ } while (readl(REG_RTC_BR0) != backup);
+ }
+ }
+
+ /* enable WDT reset */
+ writel(0xbaba, watchdog_virt_base + TMR_WFAR);
+ writel(0xeb10, watchdog_virt_base + TMR_WSAR);
+ writel(0x3, watchdog_virt_base + TMR_WMER);
+
+ if (cpu_is_pxa910()) {
+ /*hold CP first */
+ reg = readl(MPMU_APRR) | MPMU_APRR_CPR;
+ writel(reg, MPMU_APRR);
+ udelay(10);
+ /*CP reset MSA */
+ reg = readl(MPMU_CPRR) | MPMU_CPRR_DSPR | MPMU_CPRR_BBR;
+ writel(reg, MPMU_CPRR);
+ udelay(10);
+ }
+ /* negate hardware reset to the WDT after system reset */
+ reg = readl(MPMU_APRR) | MPMU_APRR_WDTR;
+ writel(reg, MPMU_APRR);
+
+ /* clear previous WDT status */
+ writel(0xbaba, watchdog_virt_base + TMR_WFAR);
+ writel(0xeb10, watchdog_virt_base + TMR_WSAR);
+ writel(0, watchdog_virt_base + TMR_WSR);
+
+ match = readl(watchdog_virt_base + TMR_WMR);
+ count = readl(watchdog_virt_base + TMR_WVR);
+
+ if (match - count > 0x20) {
+ /* set match counter */
+ writel(0xbaba, watchdog_virt_base + TMR_WFAR);
+ writel(0xeb10, watchdog_virt_base + TMR_WSAR);
+ writel(0x20 + count, watchdog_virt_base + TMR_WMR);
+ }
+}
+
+void arch_reset(char mode, const char *cmd)
+{
+ switch (mode) {
+ case 's':
+ /* Jump into ROM */
+ if (cpu_is_pxa168()) {
+ cpu_reset(0xffff0000);
+ break;
+ }
+ case 'w':
+ default:
+ do_wdt_reset(cmd);
+ break;
+ }
+}
--
1.5.6.5
More information about the linux-arm-kernel
mailing list