summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/imx.c52
-rw-r--r--arch/arm/mach-imx/imx51.c20
-rw-r--r--arch/arm/mach-imx/imx53.c4
-rw-r--r--arch/arm/mach-imx/imx6.c4
-rw-r--r--arch/arm/mach-imx/imx7.c19
-rw-r--r--arch/arm/mach-imx/include/mach/generic.h1
-rw-r--r--arch/arm/mach-imx/include/mach/reset-reason.h37
-rw-r--r--arch/arm/mach-imx/include/mach/vf610-regs.h3
-rw-r--r--arch/arm/mach-imx/include/mach/vf610.h51
-rw-r--r--arch/arm/mach-imx/vf610.c59
-rw-r--r--common/reset_source.c23
-rw-r--r--include/reset_source.h17
13 files changed, 276 insertions, 15 deletions
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 8ec846ccef..160ed4b084 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_IMX6) += imx6.o usb-imx6.o
CFLAGS_imx6.o := -march=armv7-a
lwl-$(CONFIG_ARCH_IMX6) += imx6-mmdc.o
obj-$(CONFIG_ARCH_IMX7) += imx7.o
+obj-$(CONFIG_ARCH_VF610) += vf610.o
obj-$(CONFIG_ARCH_IMX_XLOAD) += xload.o
obj-$(CONFIG_IMX_IIM) += iim.o
obj-$(CONFIG_IMX_OCOTP) += ocotp.o
diff --git a/arch/arm/mach-imx/imx.c b/arch/arm/mach-imx/imx.c
index 9400105c66..1b4c1b3df1 100644
--- a/arch/arm/mach-imx/imx.c
+++ b/arch/arm/mach-imx/imx.c
@@ -14,8 +14,10 @@
#include <common.h>
#include <of.h>
#include <init.h>
+#include <io.h>
#include <mach/revision.h>
#include <mach/generic.h>
+#include <mach/reset-reason.h>
static int __imx_silicon_revision = IMX_CHIP_REV_UNKNOWN;
@@ -28,7 +30,10 @@ void imx_set_silicon_revision(const char *soc, int revision)
{
__imx_silicon_revision = revision;
- pr_info("detected %s revision %d.%d\n", soc,
+ if (revision == IMX_CHIP_REV_UNKNOWN)
+ pr_info("detected %s revision unknown\n", soc);
+ else
+ pr_info("detected %s revision %d.%d\n", soc,
(revision >> 4) & 0xf,
revision & 0xf);
}
@@ -114,7 +119,7 @@ static int imx_init(void)
else if (cpu_is_mx7())
ret = imx7_init();
else if (cpu_is_vf610())
- ret = 0;
+ ret = vf610_init();
else
return -EINVAL;
@@ -147,3 +152,46 @@ static int imx_init(void)
return ret;
}
postcore_initcall(imx_init);
+
+const struct imx_reset_reason imx_reset_reasons[] = {
+ { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 },
+ { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 },
+ { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_WARM_BOOT, RESET_RST, 0 },
+ { /* sentinel */ }
+};
+
+void imx_set_reset_reason(void __iomem *srsr,
+ const struct imx_reset_reason *reasons)
+{
+ enum reset_src_type type = RESET_UKWN;
+ const u32 reg = readl(srsr);
+ int i, instance = 0;
+
+ /*
+ * SRSR register captures ALL reset event that occured since
+ * POR, so we need to clear it to make sure we only caputre
+ * the latest one.
+ */
+ writel(reg, srsr);
+
+ for (i = 0; reasons[i].mask; i++) {
+ if (reg & reasons[i].mask) {
+ type = reasons[i].type;
+ instance = reasons[i].instance;
+ break;
+ }
+ }
+
+ /*
+ * Report this with above default priority in order to make
+ * sure we'll always override info from watchdog driver.
+ */
+ reset_source_set_priority(type,
+ RESET_SOURCE_DEFAULT_PRIORITY + 1);
+ reset_source_set_instance(type, instance);
+
+ pr_info("i.MX reset reason %s (SRSR: 0x%08x)\n",
+ reset_source_name(), reg);
+}
diff --git a/arch/arm/mach-imx/imx51.c b/arch/arm/mach-imx/imx51.c
index ffe6a7c651..ec8cdd868b 100644
--- a/arch/arm/mach-imx/imx51.c
+++ b/arch/arm/mach-imx/imx51.c
@@ -21,6 +21,7 @@
#include <mach/revision.h>
#include <mach/clock-imx51_53.h>
#include <mach/generic.h>
+#include <mach/reset-reason.h>
#define IIM_SREV 0x24
@@ -43,7 +44,7 @@ static int imx51_silicon_revision(void)
static void imx51_ipu_mipi_setup(void)
{
- void __iomem *hsc_addr = (void __iomem *)MX51_MIPI_HSC_BASE_ADDR;
+ void __iomem *hsc_addr = IOMEM(MX51_MIPI_HSC_BASE_ADDR);
u32 val;
/* setup MIPI module to legacy mode */
@@ -57,7 +58,10 @@ static void imx51_ipu_mipi_setup(void)
int imx51_init(void)
{
+ void __iomem *src = IOMEM(MX51_SRC_BASE_ADDR);
+
imx_set_silicon_revision("i.MX51", imx51_silicon_revision());
+ imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons);
imx51_boot_save_loc();
add_generic_device("imx51-esdctl", 0, NULL, MX51_ESDCTL_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
imx51_ipu_mipi_setup();
@@ -97,7 +101,7 @@ int imx51_devices_init(void)
*/
static void imx51_setup_pll800_bug(void)
{
- void __iomem *base = (void *)MX51_PLL1_BASE_ADDR;
+ void __iomem *base = IOMEM(MX51_PLL1_BASE_ADDR);
u32 dp_config;
volatile int i;
@@ -132,7 +136,7 @@ static void imx51_setup_pll800_bug(void)
void imx51_init_lowlevel(unsigned int cpufreq_mhz)
{
- void __iomem *ccm = (void __iomem *)MX51_CCM_BASE_ADDR;
+ void __iomem *ccm = IOMEM(MX51_CCM_BASE_ADDR);
u32 r;
int rev = imx51_silicon_revision();
@@ -167,30 +171,30 @@ void imx51_init_lowlevel(unsigned int cpufreq_mhz)
switch (cpufreq_mhz) {
case 600:
- imx5_setup_pll_600((void __iomem *)MX51_PLL1_BASE_ADDR);
+ imx5_setup_pll_600(IOMEM(MX51_PLL1_BASE_ADDR));
break;
default:
/* Default maximum 800MHz */
if (rev <= IMX_CHIP_REV_3_0)
imx51_setup_pll800_bug();
else
- imx5_setup_pll_800((void __iomem *)MX51_PLL1_BASE_ADDR);
+ imx5_setup_pll_800(IOMEM(MX51_PLL1_BASE_ADDR));
break;
}
- imx5_setup_pll_665((void __iomem *)MX51_PLL3_BASE_ADDR);
+ imx5_setup_pll_665(IOMEM(MX51_PLL3_BASE_ADDR));
/* Switch peripheral to PLL 3 */
writel(0x000010C0, ccm + MX5_CCM_CBCMR);
writel(0x13239145, ccm + MX5_CCM_CBCDR);
- imx5_setup_pll_665((void __iomem *)MX51_PLL2_BASE_ADDR);
+ imx5_setup_pll_665(IOMEM(MX51_PLL2_BASE_ADDR));
/* Switch peripheral to PLL2 */
writel(0x19239145, ccm + MX5_CCM_CBCDR);
writel(0x000020C0, ccm + MX5_CCM_CBCMR);
- imx5_setup_pll_216((void __iomem *)MX51_PLL3_BASE_ADDR);
+ imx5_setup_pll_216(IOMEM(MX51_PLL3_BASE_ADDR));
/* Set the platform clock dividers */
writel(0x00000125, MX51_ARM_BASE_ADDR + 0x14);
diff --git a/arch/arm/mach-imx/imx53.c b/arch/arm/mach-imx/imx53.c
index 2758f1bbcf..56f1bda75e 100644
--- a/arch/arm/mach-imx/imx53.c
+++ b/arch/arm/mach-imx/imx53.c
@@ -21,6 +21,7 @@
#include <mach/revision.h>
#include <mach/clock-imx51_53.h>
#include <mach/generic.h>
+#include <mach/reset-reason.h>
#define SI_REV 0x48
@@ -52,7 +53,10 @@ static int imx53_silicon_revision(void)
int imx53_init(void)
{
+ void __iomem *src = IOMEM(MX53_SRC_BASE_ADDR);
+
imx53_silicon_revision();
+ imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons);
imx53_boot_save_loc();
add_generic_device("imx53-esdctl", 0, NULL, MX53_ESDCTL_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c
index 6c69c3604a..eaf9f2e413 100644
--- a/arch/arm/mach-imx/imx6.c
+++ b/arch/arm/mach-imx/imx6.c
@@ -20,6 +20,7 @@
#include <mach/imx6.h>
#include <mach/generic.h>
#include <mach/revision.h>
+#include <mach/reset-reason.h>
#include <mach/imx6-anadig.h>
#include <mach/imx6-regs.h>
#include <mach/generic.h>
@@ -189,6 +190,7 @@ int imx6_init(void)
{
const char *cputypestr;
u32 mx6_silicon_revision;
+ void __iomem *src = IOMEM(MX6_SRC_BASE_ADDR);
imx6_init_lowlevel();
@@ -233,7 +235,7 @@ int imx6_init(void)
}
imx_set_silicon_revision(cputypestr, mx6_silicon_revision);
-
+ imx_set_reset_reason(src + IMX_SRC_SRSR, imx_reset_reasons);
imx6_setup_ipu_qos();
imx6ul_enet_clk_init();
diff --git a/arch/arm/mach-imx/imx7.c b/arch/arm/mach-imx/imx7.c
index 4eef99c872..e49baf6f77 100644
--- a/arch/arm/mach-imx/imx7.c
+++ b/arch/arm/mach-imx/imx7.c
@@ -19,6 +19,7 @@
#include <mach/imx7.h>
#include <mach/generic.h>
#include <mach/revision.h>
+#include <mach/reset-reason.h>
#include <mach/imx7-regs.h>
void imx7_init_lowlevel(void)
@@ -167,10 +168,21 @@ static struct psci_ops imx7_psci_ops = {
.cpu_off = imx7_cpu_off,
};
+static const struct imx_reset_reason imx7_reset_reasons[] = {
+ { IMX_SRC_SRSR_IPP_RESET, RESET_POR, 0 },
+ { IMX_SRC_SRSR_WDOG1_RESET, RESET_WDG, 0 },
+ { IMX_SRC_SRSR_JTAG_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_JTAG_SW_RESET, RESET_JTAG, 0 },
+ { IMX_SRC_SRSR_WDOG3_RESET, RESET_WDG, 1 },
+ { IMX_SRC_SRSR_WDOG4_RESET, RESET_WDG, 2 },
+ { IMX_SRC_SRSR_TEMPSENSE_RESET, RESET_THERM, 0 },
+ { /* sentinel */ }
+};
+
int imx7_init(void)
{
const char *cputypestr;
- u32 imx7_silicon_revision;
+ void __iomem *src = IOMEM(MX7_SRC_BASE_ADDR);
imx7_init_lowlevel();
@@ -180,8 +192,6 @@ int imx7_init(void)
imx7_boot_save_loc();
- imx7_silicon_revision = imx7_cpu_revision();
-
psci_set_ops(&imx7_psci_ops);
switch (imx7_cpu_type()) {
@@ -196,7 +206,8 @@ int imx7_init(void)
break;
}
- imx_set_silicon_revision(cputypestr, imx7_silicon_revision);
+ imx_set_silicon_revision(cputypestr, imx7_cpu_revision());
+ imx_set_reset_reason(src + IMX7_SRC_SRSR, imx7_reset_reasons);
return 0;
}
diff --git a/arch/arm/mach-imx/include/mach/generic.h b/arch/arm/mach-imx/include/mach/generic.h
index dedb4bbf06..ad9d9cb022 100644
--- a/arch/arm/mach-imx/include/mach/generic.h
+++ b/arch/arm/mach-imx/include/mach/generic.h
@@ -36,6 +36,7 @@ int imx51_init(void);
int imx53_init(void);
int imx6_init(void);
int imx7_init(void);
+int vf610_init(void);
int imx1_devices_init(void);
int imx21_devices_init(void);
diff --git a/arch/arm/mach-imx/include/mach/reset-reason.h b/arch/arm/mach-imx/include/mach/reset-reason.h
new file mode 100644
index 0000000000..0f644a8c1d
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/reset-reason.h
@@ -0,0 +1,37 @@
+#ifndef __MACH_RESET_REASON_H__
+#define __MACH_RESET_REASON_H__
+
+#include <reset_source.h>
+
+#define IMX_SRC_SRSR_IPP_RESET BIT(0)
+#define IMX_SRC_SRSR_CSU_RESET BIT(2)
+#define IMX_SRC_SRSR_IPP_USER_RESET BIT(3)
+#define IMX_SRC_SRSR_WDOG1_RESET BIT(4)
+#define IMX_SRC_SRSR_JTAG_RESET BIT(5)
+#define IMX_SRC_SRSR_JTAG_SW_RESET BIT(6)
+#define IMX_SRC_SRSR_WDOG3_RESET BIT(7)
+#define IMX_SRC_SRSR_WDOG4_RESET BIT(8)
+#define IMX_SRC_SRSR_TEMPSENSE_RESET BIT(9)
+#define IMX_SRC_SRSR_WARM_BOOT BIT(16)
+
+#define IMX_SRC_SRSR 0x008
+#define IMX7_SRC_SRSR 0x05c
+
+#define VF610_SRC_SRSR_SW_RST BIT(18)
+#define VF610_SRC_SRSR_RESETB BIT(7)
+#define VF610_SRC_SRSR_JTAG_RST BIT(5)
+#define VF610_SRC_SRSR_WDOG_M4 BIT(4)
+#define VF610_SRC_SRSR_WDOG_A5 BIT(3)
+#define VF610_SRC_SRSR_POR_RST BIT(0)
+
+struct imx_reset_reason {
+ uint32_t mask;
+ enum reset_src_type type;
+ int instance;
+};
+
+void imx_set_reset_reason(void __iomem *, const struct imx_reset_reason *);
+
+extern const struct imx_reset_reason imx_reset_reasons[];
+
+#endif /* __MACH_RESET_REASON_H__ */
diff --git a/arch/arm/mach-imx/include/mach/vf610-regs.h b/arch/arm/mach-imx/include/mach/vf610-regs.h
index 87772ee76d..416b457aff 100644
--- a/arch/arm/mach-imx/include/mach/vf610-regs.h
+++ b/arch/arm/mach-imx/include/mach/vf610-regs.h
@@ -109,4 +109,7 @@
#define VF610_MSCM_IRSPRC_CP0_EN 1
#define VF610_MSCM_IRSPRC_NUM 112
+#define VF610_MSCM_CPxCOUNT 0x00c
+#define VF610_MSCM_CPxCFG1 0x014
+
#endif
diff --git a/arch/arm/mach-imx/include/mach/vf610.h b/arch/arm/mach-imx/include/mach/vf610.h
new file mode 100644
index 0000000000..6d00d2e457
--- /dev/null
+++ b/arch/arm/mach-imx/include/mach/vf610.h
@@ -0,0 +1,51 @@
+#ifndef __MACH_VF610_H
+#define __MACH_VF610_H
+
+#include <io.h>
+#include <mach/generic.h>
+#include <mach/vf610-regs.h>
+#include <mach/revision.h>
+
+#define VF610_CPUTYPE_VFx10 0x010
+
+#define VF610_CPUTYPE_VF610 0x610
+#define VF610_CPUTYPE_VF600 0x600
+#define VF610_CPUTYPE_VF510 0x510
+#define VF610_CPUTYPE_VF500 0x500
+
+#define VF610_ROM_VERSION_OFFSET 0x80
+
+static inline int __vf610_cpu_type(void)
+{
+ void __iomem *mscm = IOMEM(VF610_MSCM_BASE_ADDR);
+ const u32 cpxcount = readl(mscm + VF610_MSCM_CPxCOUNT);
+ const u32 cpxcfg1 = readl(mscm + VF610_MSCM_CPxCFG1);
+ int cpu_type;
+
+ cpu_type = cpxcount ? VF610_CPUTYPE_VF600 : VF610_CPUTYPE_VF500;
+
+ return cpxcfg1 ? cpu_type | VF610_CPUTYPE_VFx10 : cpu_type;
+}
+
+static inline int vf610_cpu_type(void)
+{
+ if (!cpu_is_vf610())
+ return 0;
+
+ return __vf610_cpu_type();
+}
+
+static inline int vf610_cpu_revision(void)
+{
+ if (!cpu_is_vf610())
+ return IMX_CHIP_REV_UNKNOWN;
+
+ /*
+ * There doesn't seem to be a documented way of retreiving
+ * silicon revision on VFxxx cpus, so we just report Mask ROM
+ * version instead
+ */
+ return readl(VF610_ROM_VERSION_OFFSET) & 0xff;
+}
+
+#endif
diff --git a/arch/arm/mach-imx/vf610.c b/arch/arm/mach-imx/vf610.c
new file mode 100644
index 0000000000..c535716c10
--- /dev/null
+++ b/arch/arm/mach-imx/vf610.c
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <init.h>
+#include <common.h>
+#include <io.h>
+#include <linux/sizes.h>
+#include <mach/generic.h>
+#include <mach/revision.h>
+#include <mach/vf610.h>
+#include <mach/reset-reason.h>
+
+static const struct imx_reset_reason vf610_reset_reasons[] = {
+ { VF610_SRC_SRSR_POR_RST, RESET_POR, 0 },
+ { VF610_SRC_SRSR_WDOG_A5, RESET_WDG, 0 },
+ { VF610_SRC_SRSR_WDOG_M4, RESET_WDG, 1 },
+ { VF610_SRC_SRSR_JTAG_RST, RESET_JTAG, 0 },
+ { VF610_SRC_SRSR_RESETB, RESET_EXT, 0 },
+ { VF610_SRC_SRSR_SW_RST, RESET_RST, 0 },
+ { /* sentinel */ }
+};
+
+int vf610_init(void)
+{
+ const char *cputypestr;
+ void __iomem *src = IOMEM(VF610_SRC_BASE_ADDR);
+
+ switch (vf610_cpu_type()) {
+ case VF610_CPUTYPE_VF610:
+ cputypestr = "VF610";
+ break;
+ case VF610_CPUTYPE_VF600:
+ cputypestr = "VF600";
+ break;
+ case VF610_CPUTYPE_VF510:
+ cputypestr = "VF510";
+ break;
+ case VF610_CPUTYPE_VF500:
+ cputypestr = "VF500";
+ break;
+ default:
+ cputypestr = "unknown VFxxx";
+ break;
+ }
+
+ imx_set_silicon_revision(cputypestr, vf610_cpu_revision());
+ imx_set_reset_reason(src + IMX_SRC_SRSR, vf610_reset_reasons);
+ return 0;
+}
diff --git a/common/reset_source.c b/common/reset_source.c
index 06e2ca85f5..338d7b9acb 100644
--- a/common/reset_source.c
+++ b/common/reset_source.c
@@ -32,6 +32,7 @@ static const char * const reset_src_names[] = {
static enum reset_src_type reset_source;
static unsigned int reset_source_priority;
+static int reset_source_instance;
enum reset_src_type reset_source_get(void)
{
@@ -39,6 +40,12 @@ enum reset_src_type reset_source_get(void)
}
EXPORT_SYMBOL(reset_source_get);
+int reset_source_get_instance(void)
+{
+ return reset_source_instance;
+}
+EXPORT_SYMBOL(reset_source_get_instance);
+
void reset_source_set_priority(enum reset_src_type st, unsigned int priority)
{
if (priority <= reset_source_priority)
@@ -46,17 +53,33 @@ void reset_source_set_priority(enum reset_src_type st, unsigned int priority)
reset_source = st;
reset_source_priority = priority;
+ reset_source_instance = 0;
pr_debug("Setting reset source to %s with priority %d\n",
reset_src_names[reset_source], priority);
}
EXPORT_SYMBOL(reset_source_set_priority);
+const char *reset_source_name(void)
+{
+ return reset_src_names[reset_source];
+}
+EXPORT_SYMBOL(reset_source_name);
+
+void reset_source_set_instance(enum reset_src_type type, int instance)
+{
+ if (reset_source == type)
+ reset_source_instance = instance;
+}
+EXPORT_SYMBOL(reset_source_set_instance);
+
static int reset_source_init(void)
{
globalvar_add_simple_enum("system.reset", (unsigned int *)&reset_source,
reset_src_names, ARRAY_SIZE(reset_src_names));
+ globalvar_add_simple_int("system.reset_instance", &reset_source_instance,
+ "%d");
return 0;
}
diff --git a/include/reset_source.h b/include/reset_source.h
index 3ff06b70ad..86e415abcf 100644
--- a/include/reset_source.h
+++ b/include/reset_source.h
@@ -27,22 +27,39 @@ enum reset_src_type {
#ifdef CONFIG_RESET_SOURCE
void reset_source_set_priority(enum reset_src_type, unsigned int priority);
enum reset_src_type reset_source_get(void);
+void reset_source_set_instance(enum reset_src_type type, int instance);
+int reset_source_get_instance(void);
unsigned int of_get_reset_source_priority(struct device_node *node);
+const char *reset_source_name(void);
#else
static inline void reset_source_set_priority(enum reset_src_type type,
unsigned int priority)
{
}
+static inline void reset_source_set_instance(enum reset_src_type type, int instance)
+{
+}
+
static inline enum reset_src_type reset_source_get(void)
{
return RESET_UKWN;
}
+static inline int reset_source_get_instance(void)
+{
+ return 0;
+}
+
static inline unsigned int of_get_reset_source_priority(struct device_node *node)
{
return 0;
}
+
+static inline const char *reset_source_name(void)
+{
+ return "unknown";
+}
#endif
#define RESET_SOURCE_DEFAULT_PRIORITY 100