diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 89a8946..2ff537a 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,4 +1,5 @@ obj-y += clocksource.o gpio.o +obj-$(CONFIG_RESET_SOURCE) += reset_source.o obj-$(CONFIG_ARCH_IMX1) += speed-imx1.o imx1.o iomux-v1.o obj-$(CONFIG_ARCH_IMX25) += speed-imx25.o imx25.o iomux-v3.o obj-$(CONFIG_ARCH_IMX21) += speed-imx21.o imx21.o iomux-v1.o diff --git a/arch/arm/mach-imx/reset_source.c b/arch/arm/mach-imx/reset_source.c new file mode 100644 index 0000000..e7b2a90 --- /dev/null +++ b/arch/arm/mach-imx/reset_source.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2012 Juergen Beisert - + * + * 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 +#include +#include +#include +#include + +#ifdef CONFIG_ARCH_IMX1 +# define IMX_RESET_SRC_WDOG (1 << 1) +# define IMX_RESET_SRC_HRDRESET (1 << 0) +/* let the compiler sort out useless code on this arch */ +# define IMX_RESET_SRC_WARMSTART 0 +# define IMX_RESET_SRC_COLDSTART 0 +#else + /* WRSR checked for i.MX25, i.MX27, i.MX31, i.MX35 and i.MX51 */ +# define WDOG_WRSR 0x04 + /* valid for i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 */ +# define IMX_RESET_SRC_WARMSTART (1 << 0) + /* valid for i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 */ +# define IMX_RESET_SRC_WDOG (1 << 1) + /* valid for i.MX27, i.MX31, always '0' on i.MX25, i.MX35, i.MX51 */ +# define IMX_RESET_SRC_HRDRESET (1 << 3) + /* valid for i.MX27, i.MX31, always '0' on i.MX25, i.MX35, i.MX51 */ +# define IMX_RESET_SRC_COLDSTART (1 << 4) +#endif + +static unsigned read_detection_register(void) +{ +#ifdef CONFIG_ARCH_IMX1 + return readl(IMX_SYSCTRL_BASE); +#else + return readw(IMX_WDT_BASE + WDOG_WRSR); +#endif +} + +static int imx_detect_reset_source(void) +{ + unsigned reg = read_detection_register(); + + if (reg & IMX_RESET_SRC_COLDSTART) { + set_reset_source(RESET_POR); + return 0; + } + + if (reg & (IMX_RESET_SRC_HRDRESET | IMX_RESET_SRC_WARMSTART)) { + set_reset_source(RESET_RST); + return 0; + } + + if (reg & IMX_RESET_SRC_WDOG) { + set_reset_source(RESET_WDG); + return 0; + } + + /* else keep the default 'unknown' state */ + return 0; +} + +device_initcall(imx_detect_reset_source); diff --git a/arch/arm/mach-samsung/Makefile b/arch/arm/mach-samsung/Makefile index 6020587..f7db1f7 100644 --- a/arch/arm/mach-samsung/Makefile +++ b/arch/arm/mach-samsung/Makefile @@ -1,4 +1,5 @@ obj-y += s3c-timer.o generic.o +obj-$(CONFIG_RESET_SOURCE) += reset_source.o obj-lowlevel-$(CONFIG_ARCH_S3C24xx) += lowlevel-s3c24x0.o obj-lowlevel-$(CONFIG_ARCH_S5PCxx) += lowlevel-s5pcxx.o obj-$(CONFIG_ARCH_S3C24xx) += gpio-s3c24x0.o s3c24xx-clocks.o mem-s3c24x0.o diff --git a/arch/arm/mach-samsung/reset_source.c b/arch/arm/mach-samsung/reset_source.c new file mode 100644 index 0000000..2456e3f --- /dev/null +++ b/arch/arm/mach-samsung/reset_source.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2012 Juergen Beisert - + * + * 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 +#include +#include +#include +#include + +/* S3C2440 relevant */ +#define S3C2440_GSTATUS2 0xb4 +# define S3C2440_GSTATUS2_PWRST (1 << 0) +# define S3C2440_GSTATUS2_SLEEPRST (1 << 1) +# define S3C2440_GSTATUS2_WDRST (1 << 2) + +static int s3c_detect_reset_source(void) +{ + u32 reg = readl(S3C_GPIO_BASE + S3C2440_GSTATUS2); + + if (reg & S3C2440_GSTATUS2_PWRST) { + set_reset_source(RESET_POR); + writel(S3C2440_GSTATUS2_PWRST, + S3C_GPIO_BASE + S3C2440_GSTATUS2); + return 0; + } + + if (reg & S3C2440_GSTATUS2_SLEEPRST) { + set_reset_source(RESET_WKE); + writel(S3C2440_GSTATUS2_SLEEPRST, + S3C_GPIO_BASE + S3C2440_GSTATUS2); + return 0; + } + + if (reg & S3C2440_GSTATUS2_WDRST) { + set_reset_source(RESET_WDG); + writel(S3C2440_GSTATUS2_WDRST, + S3C_GPIO_BASE + S3C2440_GSTATUS2); + return 0; + } + + /* else keep the default 'unknown' state */ + return 0; +} + +device_initcall(s3c_detect_reset_source); diff --git a/common/Kconfig b/common/Kconfig index 8eec661..7eb5b49 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -559,6 +559,14 @@ config POLLER bool "generic polling infrastructure" +config RESET_SOURCE + bool "detect Reset cause" + depends on GLOBALVAR + help + Provide a global variable at runtine which reflects the possible cause + of the reset and why the bootloader is currently running. It can be + useful for any kind of system recovery or repair. + endmenu menu "Debugging " diff --git a/common/Makefile b/common/Makefile index d99dfa2..d74dffb 100644 --- a/common/Makefile +++ b/common/Makefile @@ -30,6 +30,7 @@ obj-y += misc.o obj-y += memsize.o obj-$(CONFIG_GLOBALVAR) += globalvar.o +obj-$(CONFIG_RESET_SOURCE) += reset_source.o obj-$(CONFIG_FILETYPE) += filetype.o obj-y += resource.o obj-$(CONFIG_MENU) += menu.o diff --git a/common/reset_source.c b/common/reset_source.c new file mode 100644 index 0000000..2a7f9ff --- /dev/null +++ b/common/reset_source.c @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2012 Juergen Beisert - + * + * 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 +#include +#include +#include +#include + +static const char * const reset_src_names[] = { + [RESET_UKWN] = "unknown", + [RESET_POR] = "POR", + [RESET_RST] = "RST", + [RESET_WDG] = "WDG", + [RESET_WKE] = "WKE", + [RESET_JTAG] = "JTAG", +}; + +void set_reset_source(enum reset_src_type st) +{ + setenv("global.system.reset", reset_src_names[st]); +} +EXPORT_SYMBOL(set_reset_source); + +/* ensure this runs after the 'global' device is already registerd */ +static int init_reset_source(void) +{ + globalvar_add_simple("system.reset"); + set_reset_source(RESET_UKWN); + return 0; +} + +coredevice_initcall(init_reset_source); diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c index b016910..1f987de 100644 --- a/drivers/watchdog/im28wd.c +++ b/drivers/watchdog/im28wd.c @@ -21,6 +21,7 @@ #include #include #include +#include #define MXS_RTC_CTRL 0x0 #define MXS_RTC_SET_ADDR 0x4 @@ -73,6 +74,27 @@ return 0; } +static void __maybe_unused imx28_detect_reset_source(const struct imx28_wd *p) +{ + u32 reg; + + reg = readl(p->regs + MXS_RTC_PERSISTENT0); + if (reg & MXS_RTC_PERSISTENT0_EXT_RST) { + writel(MXS_RTC_PERSISTENT0_EXT_RST, + p->regs + MXS_RTC_PERSISTENT0 + MXS_RTC_CLR_ADDR); + set_reset_source(RESET_POR); + return; + } + if (reg & MXS_RTC_PERSISTENT0_THM_RST) { + writel(MXS_RTC_PERSISTENT0_THM_RST, + p->regs + MXS_RTC_PERSISTENT0 + MXS_RTC_CLR_ADDR); + set_reset_source(RESET_RST); + return; + } + + set_reset_source(RESET_RST); +} + static int imx28_wd_probe(struct device_d *dev) { struct imx28_wd *priv; @@ -94,6 +116,9 @@ if (rc != 0) goto on_error; + if (IS_ENABLED(CONFIG_RESET_SOURCE)) + imx28_detect_reset_source(priv); + dev->priv = priv; return 0; diff --git a/include/reset_source.h b/include/reset_source.h new file mode 100644 index 0000000..6734fbde --- /dev/null +++ b/include/reset_source.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef __INCLUDE_RESET_SOURCE_H +# define __INCLUDE_RESET_SOURCE_H + +enum reset_src_type { + RESET_UKWN, /* maybe the SoC cannot detect the reset source */ + RESET_POR, /* Power On Reset (cold start) */ + RESET_RST, /* generic ReSeT (warm start) */ + RESET_WDG, /* watchdog */ + RESET_WKE, /* wake-up (some SoCs can handle this) */ + RESET_JTAG, /* JTAG reset */ +}; + +void set_reset_source(enum reset_src_type); + +#endif /* __INCLUDE_RESET_SOURCE_H */