Skip to contentSkip to conversation

Handle reboot for Exynos SoC via reboot_notifier

PATCH Superseded Pankaj Dubey 2 participants 5 messages Oct 1, 2014 – Oct 7, 2014

Subsystems (5)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v2 cover Handle reboot for Exynos SoC via reboot_notifier

This patch removes restart hook from machine_desc of Exynos, and moves respective code into reboot_notifiers.
Exynos5440 handles reboot via clock register so let's register a reboot_notifier in Exynos5440 clock driver.
For reset Exynos SoC, reboot is handled via PMU SWRESET register so let's register a reboot_notifier in PMU driver for handling this.

This patch is inspired and dependent on following patch series[1] from Geunter Roeck.

Also this patch is dependent on PMU platform driver patch [2] by me, and has been prepared on top of it.

[1]: kernel: Add support for kernel restart handler call chain
https://lkml.org/lkml/2014/8/19/652

[2]: ARM: Exynos: Convert PMU implementation into a platform driver
https://lkml.org/lkml/2014/9/30/219

I have tested reboot functionality on Exynos3250 based board, on kgene/for-next as well as linux-next's next-20140925 tag.

Patch v1 and related discussion can be found here
http://www.spinics.net/lists/linux-samsung-soc/msg37445.html

Changes since v1:
- Addressed review comments from Tomasz Figa. Removed usage of local variables where ever unnecessary.
- Make reg_base as global in clk-exynos5440.c file, to avoid iomapping it again in reboot_notifier handler.

Pankaj Dubey (2):
clk: samsung: exynos5440: move restart code into clock driver
ARM: EXYNOS: PMU: move restart code into pmu driver

 arch/arm/mach-exynos/common.h        |    1 -
 arch/arm/mach-exynos/exynos.c        |   23 -----------------------
 arch/arm/mach-exynos/pmu.c           |   25 +++++++++++++++++++++++++
 drivers/clk/samsung/clk-exynos5440.c |   30 +++++++++++++++++++++++++++++-
 4 files changed, 54 insertions(+), 25 deletions(-)
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v2 1/2 clk: samsung: exynos5440: move restart code into clock driver

Let's register reboot_notifier for Exynos5440 from it's clock driver for reboot functionality. So that we can cleanup restart hooks from machine specific file.

---
 arch/arm/mach-exynos/exynos.c        |   19 +------------------
 drivers/clk/samsung/clk-exynos5440.c |   30 +++++++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 19 deletions(-)
arch/arm/mach-exynos/exynos.c +1 -18
index 2f2f7b2..aa394cb 100644
@@ -139,24 +139,7 @@ static struct map_desc exynos5_iodesc[] __initdata = {
 
 static void exynos_restart(enum reboot_mode mode, const char *cmd)
 {
-	struct device_node *np;
-	u32 val = 0x1;
-	void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET;
-
-	if (of_machine_is_compatible("samsung,exynos5440")) {
-		u32 status;
-		np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
-
-		addr = of_iomap(np, 0) + 0xbc;
-		status = __raw_readl(addr);
-
-		addr = of_iomap(np, 0) + 0xcc;
-		val = __raw_readl(addr);
-
-		val = (val & 0xffff0000) | (status & 0xffff);
-	}
-
-	__raw_writel(val, addr);
+	__raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET);
 }
 
 static struct platform_device exynos_cpuidle = {
drivers/clk/samsung/clk-exynos5440.c +29 -1
index 00d1d00..994595b 100644
@@ -15,6 +15,8 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #include "clk.h"
 #include "clk-pll.h"
@@ -23,6 +25,8 @@
 #define CPU_CLK_STATUS		0xfc
 #define MISC_DOUT1		0x558
 
+static void __iomem *reg_base;
+
 /* parent clock name list */
 PNAME(mout_armclk_p)	= { "cplla", "cpllb" };
 PNAME(mout_spi_p)	= { "div125", "div200" };
@@ -89,10 +93,31 @@ static const struct of_device_id ext_clk_match[] __initconst = {
 	{},
 };
 
+static int exynos5440_clk_reboot_notify_handler(struct notifier_block *this,
+		unsigned long code, void *unused)
+{
+	if (code == SYS_RESTART) {
+		u32 val, status;
+
+		status = readl_relaxed(reg_base + 0xbc);
+		val = readl_relaxed(reg_base + 0xcc);
+		val = (val & 0xffff0000) | (status & 0xffff);
+		writel_relaxed(val, reg_base + 0xcc);
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ * Exynos5440 Clock reboot notifier, handles reboot functionality
+ */
+static struct notifier_block exynos5440_clk_reboot_notifier = {
+	.notifier_call = exynos5440_clk_reboot_notify_handler,
+	.priority = 128,
+};
+
 /* register exynos5440 clocks */
 static void __init exynos5440_clk_init(struct device_node *np)
 {
-	void __iomem *reg_base;
 	struct samsung_clk_provider *ctx;
 
 	reg_base = of_iomap(np, 0);
@@ -125,6 +150,9 @@ static void __init exynos5440_clk_init(struct device_node *np)
 
 	samsung_clk_of_add_provider(np, ctx);
 
+	if (register_reboot_notifier(&exynos5440_clk_reboot_notifier))
+		pr_err("exynos5440 clock can't register reboot notifier\n");
+
 	pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
 	pr_info("exynos5440 clock initialization complete\n");
 }
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v2 2/2 ARM: EXYNOS: PMU: move restart code into pmu driver

In reply to Pankaj Dubey

Let's register reboot_notifier from PMU driver for reboot functionality. So that we can remove restart hooks from machine specific file, and thus moving ahead when PMU moved to driver folder, this functionality can be reused for ARM64 based Exynos SoC's.

---
 arch/arm/mach-exynos/common.h |    1 -
 arch/arm/mach-exynos/exynos.c |    6 ------
 arch/arm/mach-exynos/pmu.c    |   25 +++++++++++++++++++++++++
 3 files changed, 25 insertions(+), 7 deletions(-)
arch/arm/mach-exynos/common.h +0 -1
index 431be1b..865f878 100644
@@ -12,7 +12,6 @@
 #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
 #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
-#include <linux/reboot.h>
 #include <linux/of.h>
 
 #define EXYNOS3250_SOC_ID	0xE3472000
arch/arm/mach-exynos/exynos.c +0 -6
index aa394cb..3aa75b8e 100644
@@ -137,11 +137,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
 	},
 };
 
-static void exynos_restart(enum reboot_mode mode, const char *cmd)
-{
-	__raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET);
-}
-
 static struct platform_device exynos_cpuidle = {
 	.name              = "exynos_cpuidle",
 #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
@@ -365,7 +360,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
 	.init_machine	= exynos_dt_machine_init,
 	.init_late	= exynos_init_late,
 	.dt_compat	= exynos_dt_compat,
-	.restart	= exynos_restart,
 	.reserve	= exynos_reserve,
 	.dt_fixup	= exynos_dt_fixup,
 MACHINE_END
arch/arm/mach-exynos/pmu.c +25 -0
index 1993e08..c0855a5 100644
@@ -11,7 +11,10 @@
 
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #include "exynos-pmu.h"
 #include "regs-pmu.h"
@@ -439,6 +442,15 @@ static void exynos5250_pmu_init(void)
 	pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
 }
 
+static int pmu_reboot_notify_handler(struct notifier_block *this,
+		unsigned long code, void *unused)
+{
+	if (code == SYS_RESTART)
+		pmu_raw_writel(0x1, EXYNOS_SWRESET);
+
+	return NOTIFY_DONE;
+}
+
 static const struct exynos_pmu_data exynos4210_pmu_data = {
 	.pmu_config	= exynos4210_pmu_config,
 };
@@ -478,11 +490,20 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
 	{ /*sentinel*/ },
 };
 
+/*
+ * Exynos PMU reboot notifier, handles reboot functionality
+ */
+static struct notifier_block pmu_reboot_notifier = {
+	.notifier_call = pmu_reboot_notify_handler,
+	.priority = 128,
+};
+
 static int exynos_pmu_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct resource *res;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	pmu_base_addr = devm_ioremap_resource(dev, res);
@@ -507,6 +528,10 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pmu_context);
 
+	ret = register_reboot_notifier(&pmu_reboot_notifier);
+	if (ret)
+		dev_err(dev, "can't register reboot notifier err=%d\n", ret);
+
 	dev_dbg(dev, "Exynos PMU Driver probe done\n");
 	return 0;
 }
Signature · 1 line
1.7.9.5
#3 lore raw

PATCH v2 2/2 ARM: EXYNOS: PMU: move restart code into pmu driver

Quoted 103 lines · Pankaj Dubey

Let's register reboot_notifier from PMU driver for reboot functionality. So that we can remove restart hooks from machine specific file, and thus moving ahead when PMU moved to driver folder, this functionality can be reused for ARM64 based Exynos SoC's.

---
  arch/arm/mach-exynos/common.h |    1 -
  arch/arm/mach-exynos/exynos.c |    6 ------
  arch/arm/mach-exynos/pmu.c    |   25 +++++++++++++++++++++++++
  3 files changed, 25 insertions(+), 7 deletions(-)
arch/arm/mach-exynos/common.h +0 -1
index 431be1b..865f878 100644
@@ -12,7 +12,6 @@
  #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
  #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
-#include <linux/reboot.h>
  #include <linux/of.h>
 
  #define EXYNOS3250_SOC_ID	0xE3472000
arch/arm/mach-exynos/exynos.c +0 -6
index aa394cb..3aa75b8e 100644
@@ -137,11 +137,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
  	},
  };
 
-static void exynos_restart(enum reboot_mode mode, const char *cmd)
-{
-	__raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET);
-}
-
  static struct platform_device exynos_cpuidle = {
  	.name              = "exynos_cpuidle",
  #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
@@ -365,7 +360,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
  	.init_machine	= exynos_dt_machine_init,
  	.init_late	= exynos_init_late,
  	.dt_compat	= exynos_dt_compat,
-	.restart	= exynos_restart,
  	.reserve	= exynos_reserve,
  	.dt_fixup	= exynos_dt_fixup,
  MACHINE_END
arch/arm/mach-exynos/pmu.c +21 -0
index 1993e08..c0855a5 100644
@@ -11,7 +11,10 @@
 
  #include <linux/io.h>
  #include <linux/of.h>
+#include <linux/of_address.h>
  #include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
  #include "exynos-pmu.h"
  #include "regs-pmu.h"
@@ -439,6 +442,15 @@ static void exynos5250_pmu_init(void)
  	pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
  }
 
+static int pmu_reboot_notify_handler(struct notifier_block *this,
+		unsigned long code, void *unused)
+{
+	if (code == SYS_RESTART)
+		pmu_raw_writel(0x1, EXYNOS_SWRESET);
+
+	return NOTIFY_DONE;
+}
+
  static const struct exynos_pmu_data exynos4210_pmu_data = {
  	.pmu_config	= exynos4210_pmu_config,
  };
@@ -478,11 +490,20 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
  	{ /*sentinel*/ },
  };
 
+/*
+ * Exynos PMU reboot notifier, handles reboot functionality
+ */
+static struct notifier_block pmu_reboot_notifier = {
+	.notifier_call = pmu_reboot_notify_handler,
+	.priority = 128,
+};
+
  static int exynos_pmu_probe(struct platform_device *pdev)
  {
  	const struct of_device_id *match;
  	struct device *dev = &pdev->dev;
  	struct resource *res;
+	int ret;
 
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	pmu_base_addr = devm_ioremap_resource(dev, res);

arch/arm/mach-exynos/pmu.c static int exynos_pmu_probe(struct platform_device *pdev) · line 537

Quoted 10 lines
arch/arm/mach-exynos/pmu.c +4 -0
@@ -507,6 +528,10 @@ static int exynos_pmu_probe(struct platform_device *pdev)
 
  	platform_set_drvdata(pdev, pmu_context);
 
+	ret = register_reboot_notifier(&pmu_reboot_notifier);
+	if (ret)
+		dev_err(dev, "can't register reboot notifier err=%d\n", ret);
+
  	dev_dbg(dev, "Exynos PMU Driver probe done\n");
  	return 0;
  }

Something went wrong here.

You don't want to register with reboot_notifier, but with restart_notifier. The code is not SYS_RESTART, but the value of reboot_mode.

The same applies to the other patch as well.

Guenter

#4 lore raw

PATCH v2 2/2 ARM: EXYNOS: PMU: move restart code into pmu driver

Hi,

Quoted 25 lines · Guenter Roeck
Quoted 10 lines · Pankaj Dubey

Let's register reboot_notifier from PMU driver for reboot functionality. So that we can remove restart hooks from machine specific file, and thus moving ahead when PMU moved to driver folder, this functionality can be reused for ARM64 based Exynos SoC's.

---
  arch/arm/mach-exynos/common.h |    1 -
  arch/arm/mach-exynos/exynos.c |    6 ------
  arch/arm/mach-exynos/pmu.c    |   25

+++++++++++++++++++++++++

Quoted 13 lines
  3 files changed, 25 insertions(+), 7 deletions(-)
(quoted diff) +0 -0

b/arch/arm/mach-exynos/common.h index 431be1b..865f878 100644

arch/arm/mach-exynos/common.h +0 -1
@@ -12,7 +12,6 @@
  #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
  #define __ARCH_ARM_MACH_EXYNOS_COMMON_H
 
-#include <linux/reboot.h>
  #include <linux/of.h>
 
Quoted 6 lines

arch/arm/mach-exynos/exynos.c static struct map_desc exynos5_iodesc[] __initdata

Quoted 6 lines
arch/arm/mach-exynos/common.h +0 -0
  #define EXYNOS3250_SOC_ID	0xE3472000
(quoted diff) +0 -0

b/arch/arm/mach-exynos/exynos.c index aa394cb..3aa75b8e 100644

arch/arm/mach-exynos/exynos.c +0 -0
@@ -137,11 +137,6 @@ static struct map_desc exynos5_iodesc[] __initdata

= {

Quoted 73 lines

arch/arm/mach-exynos/exynos.c DT_MACHINE_START(EXYNOS_DT, "SAMSUNG

Quoted 11 lines
arch/arm/mach-exynos/exynos.c +0 -4
  	},
  };
 
-static void exynos_restart(enum reboot_mode mode, const char *cmd) -{
-	__raw_writel(0x1, pmu_base_addr + EXYNOS_SWRESET);
-}
-
  static struct platform_device exynos_cpuidle = {
  	.name              = "exynos_cpuidle",
  #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
@@ -365,7 +360,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG

EXYNOS (Flattened Device Tree)")

arch/arm/mach-exynos/pmu.c static const struct of_device_id

Quoted 39 lines
arch/arm/mach-exynos/exynos.c +0 -1
  	.init_machine	= exynos_dt_machine_init,
  	.init_late	= exynos_init_late,
  	.dt_compat	= exynos_dt_compat,
-	.restart	= exynos_restart,
  	.reserve	= exynos_reserve,
  	.dt_fixup	= exynos_dt_fixup,
  MACHINE_END
arch/arm/mach-exynos/pmu.c +12 -0
index 1993e08..c0855a5 100644
@@ -11,7 +11,10 @@
 
  #include <linux/io.h>
  #include <linux/of.h>
+#include <linux/of_address.h>
  #include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
  #include "exynos-pmu.h"
  #include "regs-pmu.h"
@@ -439,6 +442,15 @@ static void exynos5250_pmu_init(void)
  	pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
  }
 
+static int pmu_reboot_notify_handler(struct notifier_block *this,
+		unsigned long code, void *unused)
+{
+	if (code == SYS_RESTART)
+		pmu_raw_writel(0x1, EXYNOS_SWRESET);
+
+	return NOTIFY_DONE;
+}
+
  static const struct exynos_pmu_data exynos4210_pmu_data = {
  	.pmu_config	= exynos4210_pmu_config,
  };
@@ -478,11 +490,20 @@ static const struct of_device_id

exynos_pmu_of_device_ids[] = {

Quoted 21 lines
arch/arm/mach-exynos/pmu.c +8 -0
  	{ /*sentinel*/ },
  };
 
+/*
+ * Exynos PMU reboot notifier, handles reboot functionality  */
+static struct notifier_block pmu_reboot_notifier = {
+	.notifier_call = pmu_reboot_notify_handler,
+	.priority = 128,
+};
+
  static int exynos_pmu_probe(struct platform_device *pdev)
  {
  	const struct of_device_id *match;
  	struct device *dev = &pdev->dev;
  	struct resource *res;
+	int ret;
 
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	pmu_base_addr = devm_ioremap_resource(dev, res); @@ -507,6 +528,10

@@ static int exynos_pmu_probe(struct platform_device *pdev)

Quoted 5 lines

arch/arm/mach-exynos/pmu.c static int exynos_pmu_probe(struct platform_device *pdev)

Quoted 5 lines
  	platform_set_drvdata(pdev, pmu_context);
arch/arm/mach-exynos/pmu.c +3 -0
+	ret = register_reboot_notifier(&pmu_reboot_notifier);
+	if (ret)
+		dev_err(dev, "can't register reboot notifier err=%d\n",

ret);

Quoted 9 lines
Quoted 5 lines

+
dev_dbg(dev, "Exynos PMU Driver probe done\n"); return 0;
}

Something went wrong here.

You don't want to register with reboot_notifier, but with

restart_notifier.

Quoted 4 lines

The code is not SYS_RESTART, but the value of reboot_mode.

The same applies to the other patch as well.

Yes, you are right. Thanks for review and pointing out this.

Originally restart hooks of Exynos machine_desc are getting called from machine_restart,
so I should have registered restart_notifier. Somehow I missed this part. I will update both patches shortly.

Thanks,
Pankaj Dubey

Quoted 1 line

Guenter