Skip to contentSkip to conversation

ARM: restart-notifier support for some architectures

RFC PATCH New Heiko Stübner 3 participants 8 messages Jul 6, 2014 – Jul 8, 2014

Subsystems (5)
lore
Share & tools
lore

Heiko Stübner

author maintainer
#0 lore raw

cover ARM: restart-notifier support for some architectures

This series provides restart-notifier integration for the architectures I care about - S3C24XX and Rockchip.

It of course depends on "kernel: Add support for restart notifier call chain" from Guenter Roeck.

Samsung machines can generally be reset using their watchdog, but some also provide a special software-reset register in their system controller.

The rockchip reset integration of course also depends on the core clock support series, currently still under review.

Heiko Stuebner (3):
watchdog: s3c2410: add restart notifier
clk: samsung: register restart notifiers for s3c2412 and s3c2443
clk: rockchip: add restart notifier

 drivers/clk/rockchip/clk-rk3188.c |  2 ++
 drivers/clk/rockchip/clk-rk3288.c |  2 ++
 drivers/clk/rockchip/clk.c        | 23 +++++++++++++++++++++++
 drivers/clk/rockchip/clk.h        |  1 +
 drivers/clk/samsung/clk-s3c2412.c | 28 ++++++++++++++++++++++++++++
 drivers/clk/samsung/clk-s3c2443.c | 18 ++++++++++++++++++
 drivers/watchdog/s3c2410_wdt.c    | 33 +++++++++++++++++++++++++++++++++
 7 files changed, 107 insertions(+)
Signature · 1 line
1.9.0
author maintainer
#1 lore raw

RFC PATCH 1/3 watchdog: s3c2410: add restart notifier

On a lot of Samsung systems the watchdog is responsible for restarting the system and until now this code was contained in plat-samsung/watchdog-reset.c .

With the introduction of the restart notifiers, this code can now move into driver itself, removing the need for arch-specific code.

Tested on a S3C2442 based GTA02

---
 drivers/watchdog/s3c2410_wdt.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
drivers/watchdog/s3c2410_wdt.c +33 -0
index 7c6ccd0..3f89912 100644
@@ -41,6 +41,7 @@
 #include <linux/of.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/reboot.h>
 
 #define S3C2410_WTCON		0x00
 #define S3C2410_WTDAT		0x04
@@ -438,6 +439,31 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 }
 #endif
 
+static struct s3c2410_wdt *s3c2410wdt_restart_ctx;
+static int s3c2410wdt_restart_notify(struct notifier_block *this,
+				     unsigned long mode, void *cmd)
+{
+	void __iomem *wdt_base = s3c2410wdt_restart_ctx->reg_base;
+
+	/* disable watchdog, to be safe  */
+	writel(0, wdt_base + S3C2410_WTCON);
+
+	/* put initial values into count and data */
+	writel(0x80, wdt_base + S3C2410_WTCNT);
+	writel(0x80, wdt_base + S3C2410_WTDAT);
+
+	/* set the watchdog to go and reset... */
+	writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
+		S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
+		wdt_base + S3C2410_WTCON);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block s3c2410wdt_restart_notifier = {
+	.notifier_call = s3c2410wdt_restart_notify,
+};
+
 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
 {
 	unsigned int rst_stat;
@@ -592,6 +618,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, wdt);
 
+	s3c2410wdt_restart_ctx = wdt;
+	ret = register_restart_notifier(&s3c2410wdt_restart_notifier);
+	if (ret)
+		pr_err("cannot register restart notifier, %d\n", ret);
+
 	/* print out a statement of readiness */
 
 	wtcon = readl(wdt->reg_base + S3C2410_WTCON);
@@ -621,6 +652,8 @@ static int s3c2410wdt_remove(struct platform_device *dev)
 	int ret;
 	struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
 
+	unregister_restart_notifier(&s3c2410wdt_restart_notifier);
+
 	ret = s3c2410wdt_mask_and_disable_reset(wdt, true);
 	if (ret < 0)
 		return ret;
Signature · 1 line
1.9.0
#2 lore raw

RFC PATCH 1/3 watchdog: s3c2410: add restart notifier

Hi Heiko,

Quoted 25 lines · Heiko St?bner

On a lot of Samsung systems the watchdog is responsible for restarting the system and until now this code was contained in plat-samsung/watchdog-reset.c .

With the introduction of the restart notifiers, this code can now move into driver itself, removing the need for arch-specific code.

Tested on a S3C2442 based GTA02

---
 drivers/watchdog/s3c2410_wdt.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
drivers/watchdog/s3c2410_wdt.c +1 -0
index 7c6ccd0..3f89912 100644
@@ -41,6 +41,7 @@
 #include <linux/of.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/reboot.h>
 
 #define S3C2410_WTCON		0x00
 #define S3C2410_WTDAT		0x04

drivers/watchdog/s3c2410_wdt.c static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) · line 442

Quoted 4 lines
drivers/watchdog/s3c2410_wdt.c +1 -0
@@ -438,6 +439,31 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 }
 #endif
 
+static struct s3c2410_wdt *s3c2410wdt_restart_ctx;

This isn't the most elegant way to store context data. Maybe you could embed the notifier_block struct into s3c2410_wdt struct and then use container of to retrieve it from s3c2410wdt_restart_notify()?

Quoted 6 lines
drivers/watchdog/s3c2410_wdt.c +6 -0
+static int s3c2410wdt_restart_notify(struct notifier_block *this,
+				     unsigned long mode, void *cmd)
+{
+	void __iomem *wdt_base = s3c2410wdt_restart_ctx->reg_base;
+
+	/* disable watchdog, to be safe  */

drivers/watchdog/s3c2410_wdt.c static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) · line 458

Quoted 10 lines
drivers/watchdog/s3c2410_wdt.c +10 -0
+	writel(0, wdt_base + S3C2410_WTCON);
+
+	/* put initial values into count and data */
+	writel(0x80, wdt_base + S3C2410_WTCNT);
+	writel(0x80, wdt_base + S3C2410_WTDAT);
+
+	/* set the watchdog to go and reset... */
+	writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 |
+		S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20),
+		wdt_base + S3C2410_WTCON);

I wonder whether you shouldn't wait a bit here for the reset to be actually triggered.

Best regards,
Tomasz

maintainer
#3 lore raw

RFC PATCH 1/3 watchdog: s3c2410: add restart notifier

Quoted 31 lines · Tomasz Figa

Hi Heiko,

Quoted 28 lines · Heiko St?bner

On a lot of Samsung systems the watchdog is responsible for restarting the system and until now this code was contained in plat-samsung/watchdog-reset.c .

With the introduction of the restart notifiers, this code can now move into driver itself, removing the need for arch-specific code.

Tested on a S3C2442 based GTA02

---
 drivers/watchdog/s3c2410_wdt.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
drivers/watchdog/s3c2410_wdt.c +1 -0
index 7c6ccd0..3f89912 100644
@@ -41,6 +41,7 @@
 #include <linux/of.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/reboot.h>
 
 #define S3C2410_WTCON		0x00
 #define S3C2410_WTDAT		0x04
@@ -438,6 +439,31 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 }
 #endif
 
Quoted 6 lines

drivers/watchdog/s3c2410_wdt.c static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) · line 442

Quoted 1 line
drivers/watchdog/s3c2410_wdt.c +1 -0
+static struct s3c2410_wdt *s3c2410wdt_restart_ctx;

This isn't the most elegant way to store context data. Maybe you could embed the notifier_block struct into s3c2410_wdt struct and then use container of to retrieve it from s3c2410wdt_restart_notify()?

Excellent idea. I'll do that for the moxart handler as well.

Guenter

author maintainer
#4 lore raw

RFC PATCH 2/3 clk: samsung: register restart notifiers for s3c2412 and s3c2443

In reply to Heiko Stübner

S3C2412, S3C2443 and their derivatives contain a special software-reset register in their system-controller.

Therefore register a restart-notifier for those.

Tested on a s3c2416-based board, s3c2412 compile-tested.

---
 drivers/clk/samsung/clk-s3c2412.c | 28 ++++++++++++++++++++++++++++
 drivers/clk/samsung/clk-s3c2443.c | 18 ++++++++++++++++++
 2 files changed, 46 insertions(+)
drivers/clk/samsung/clk-s3c2412.c +28 -0
index 23e4313..840f9bd 100644
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
+#include <linux/reboot.h>
 
 #include <dt-bindings/clock/s3c2412.h>
 
@@ -26,6 +27,7 @@
 #define CLKCON		0x0c
 #define CLKDIVN		0x14
 #define CLKSRC		0x1c
+#define SWRST		0x30
 
 /* list of PLLs to be registered */
 enum s3c2412_plls {
@@ -204,6 +206,27 @@ struct samsung_clock_alias s3c2412_aliases[] __initdata = {
 	ALIAS(MSYSCLK, NULL, "fclk"),
 };
 
+static int s3c2412_restart_notify(struct notifier_block *this,
+				  unsigned long mode, void *cmd)
+{
+	/* errata "Watch-dog/Software Reset Problem" specifies that
+	 * this reset must be done with the SYSCLK sourced from
+	 * EXTCLK instead of FOUT to avoid a glitch in the reset
+	 * mechanism.
+	 *
+	 * See the watchdog section of the S3C2412 manual for more
+	 * information on this fix.
+	 */
+
+	__raw_writel(0x00, reg_base + CLKSRC);
+	__raw_writel(0x533C2412, reg_base + SWRST);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block s3c2412_restart_notifier = {
+	.notifier_call = s3c2412_restart_notify,
+};
+
 /*
  * fixed rate clocks generated outside the soc
  * Only necessary until the devicetree-move is complete
@@ -233,6 +256,7 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
 				    unsigned long ext_f, void __iomem *base)
 {
 	struct samsung_clk_provider *ctx;
+	int ret;
 	reg_base = base;
 
 	if (np) {
@@ -265,6 +289,10 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f,
 				   ARRAY_SIZE(s3c2412_aliases));
 
 	s3c2412_clk_sleep_init();
+
+	ret = register_restart_notifier(&s3c2412_restart_notifier);
+	if (ret)
+		pr_warn("cannot register restart notifier, %d\n", ret);
 }
 
 static void __init s3c2412_clk_init(struct device_node *np)
drivers/clk/samsung/clk-s3c2443.c +18 -0
index c4bbdab..0be33cc 100644
@@ -14,6 +14,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/syscore_ops.h>
+#include <linux/reboot.h>
 
 #include <dt-bindings/clock/s3c2443.h>
 
@@ -33,6 +34,7 @@
 #define HCLKCON		0x30
 #define PCLKCON		0x34
 #define SCLKCON		0x38
+#define SWRST		0x44
 
 /* the soc types */
 enum supported_socs {
@@ -354,6 +356,17 @@ struct samsung_clock_alias s3c2450_aliases[] __initdata = {
 	ALIAS(PCLK_I2C1, "s3c2410-i2c.1", "i2c"),
 };
 
+static int s3c2443_restart_notify(struct notifier_block *this,
+				  unsigned long mode, void *cmd)
+{
+	__raw_writel(0x533c2443, reg_base + SWRST);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block s3c2443_restart_notifier = {
+	.notifier_call = s3c2443_restart_notify,
+};
+
 /*
  * fixed rate clocks generated outside the soc
  * Only necessary until the devicetree-move is complete
@@ -378,6 +391,7 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
 				    void __iomem *base)
 {
 	struct samsung_clk_provider *ctx;
+	int ret;
 	reg_base = base;
 
 	if (np) {
@@ -445,6 +459,10 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f,
 	}
 
 	s3c2443_clk_sleep_init();
+
+	ret = register_restart_notifier(&s3c2443_restart_notifier);
+	if (ret)
+		pr_warn("cannot register restart notifier, %d\n", ret);
 }
 
 static void __init s3c2416_clk_init(struct device_node *np)
Signature · 1 line
1.9.0
#5 lore raw

RFC PATCH 2/3 clk: samsung: register restart notifiers for s3c2412 and s3c2443

Hi Heiko,

Quoted 4 lines · Heiko St?bner

S3C2412, S3C2443 and their derivatives contain a special software-reset register in their system-controller.

Therefore register a restart-notifier for those.

I wonder if we really need to differentiate between these SoCs instead of just using the watchdog reset for all of them. If there is no reason to prefer software reset, then some code could be removed and things would be more unified.

Best regards,
Tomasz

maintainer
#6 lore raw

RFC PATCH 2/3 clk: samsung: register restart notifiers for s3c2412 and s3c2443

Quoted 6 lines · Tomasz Figa

Hi Heiko,

Quoted 3 lines · Heiko St?bner

S3C2412, S3C2443 and their derivatives contain a special software-reset register in their system-controller.

Quoted 7 lines
Quoted 1 line

Therefore register a restart-notifier for those.

I wonder if we really need to differentiate between these SoCs instead of just using the watchdog reset for all of them. If there is no reason to prefer software reset, then some code could be removed and things would be more unified.

Depends if the other method is always available. If not, it might make sense to register this handler with lower priority to have a fallback.

Guenter

author maintainer
#7 lore raw

RFC PATCH 3/3 clk: rockchip: add restart notifier

In reply to Heiko Stübner

Add infrastructure to write the correct value to the restart register and register the restart notifier for both rk3188 (including rk3066) and rk3188.

---
 drivers/clk/rockchip/clk-rk3188.c |  2 ++
 drivers/clk/rockchip/clk-rk3288.c |  2 ++
 drivers/clk/rockchip/clk.c        | 23 +++++++++++++++++++++++
 drivers/clk/rockchip/clk.h        |  1 +
 4 files changed, 28 insertions(+)
drivers/clk/rockchip/clk-rk3188.c +2 -0
index a83a6d8..71b661a 100644
@@ -631,6 +631,8 @@ static void __init rk3188_common_clk_init(struct device_node *np)
 
 	rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(RK2928_GLB_SRST_FST);
 }
 
 static void __init rk3066a_clk_init(struct device_node *np)
drivers/clk/rockchip/clk-rk3288.c +2 -0
index 0d8c6c5..b604217 100644
@@ -713,5 +713,7 @@ static void __init rk3288_clk_init(struct device_node *np)
 
 	rockchip_register_softrst(np, 9, reg_base + RK3288_SOFTRST_CON(0),
 				  ROCKCHIP_SOFTRST_HIWORD_MASK);
+
+	rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
 }
 CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
drivers/clk/rockchip/clk.c +23 -0
index 278cf9d..0594941 100644
@@ -25,6 +25,7 @@
 #include <linux/clk-provider.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
+#include <linux/reboot.h>
 #include "clk.h"
 
 /**
@@ -242,3 +243,25 @@ void __init rockchip_clk_register_branches(
 		rockchip_clk_add_lookup(clk, list->id);
 	}
 }
+
+static unsigned int reg_restart;
+static int rockchip_restart_notify(struct notifier_block *this,
+				   unsigned long mode, void *cmd)
+{
+	writel(0xfdb9, reg_base + reg_restart);
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block rockchip_restart_notifier = {
+	.notifier_call = rockchip_restart_notify,
+};
+
+void __init rockchip_register_restart_notifier(unsigned int reg)
+{
+	int ret;
+
+	reg_restart = reg;
+	ret = register_restart_notifier(&rockchip_restart_notifier);
+	if (ret)
+		pr_err("cannot register restart notifier, %d\n", ret);
+}
drivers/clk/rockchip/clk.h +1 -0
index 887cbde..0b5eab5 100644
@@ -329,6 +329,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
 				    unsigned int nr_clk);
 void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
 				unsigned int nr_pll, int grf_lock_offset);
+void rockchip_register_restart_notifier(unsigned int reg);
 
 #define ROCKCHIP_SOFTRST_HIWORD_MASK	BIT(0)
 
Signature · 1 line
1.9.0