Skip to contentSkip to conversation

ARM: BCM2835: Drop the init_irq() hook.

PATCH New Eric Anholt 7 participants 22 messages Apr 24, 2015 – Apr 29, 2015

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 ARM: BCM2835: Drop the init_irq() hook.

This is the default function that gets called if the hook is NULL.

---
 arch/arm/mach-bcm/board_bcm2835.c | 1 -
 1 file changed, 1 deletion(-)
arch/arm/mach-bcm/board_bcm2835.c +0 -1
index 9851ee8..49dd5b0 100644
@@ -113,7 +113,6 @@ static const char * const bcm2835_compat[] = {
 };
 
 DT_MACHINE_START(BCM2835, "BCM2835")
-	.init_irq = irqchip_init,
 	.init_machine = bcm2835_init,
 	.restart = bcm2835_restart,
 	.dt_compat = bcm2835_compat
Signature · 1 line
2.1.4
#1 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org

---

Note that power off has never worked for me, and just reboots as well. So I can't say that I've *really* tested the power off code.

 arch/arm/mach-bcm/board_bcm2835.c | 73 ---------------------------------------
 drivers/watchdog/bcm2835_wdt.c    | 62 +++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 73 deletions(-)
arch/arm/mach-bcm/board_bcm2835.c +0 -73
index 49dd5b0..0f7b9ea 100644
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/irqchip.h>
 #include <linux/of_address.h>
@@ -22,81 +21,10 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#define PM_RSTC				0x1c
-#define PM_RSTS				0x20
-#define PM_WDOG				0x24
-
-#define PM_PASSWORD			0x5a000000
-#define PM_RSTC_WRCFG_MASK		0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET	0x00000020
-#define PM_RSTS_HADWRH_SET		0x00000040
-
-static void __iomem *wdt_regs;
-
-/*
- * The machine restart method can be called from an atomic context so we won't
- * be able to ioremap the regs then.
- */
-static void bcm2835_setup_restart(void)
-{
-	struct device_node *np = of_find_compatible_node(NULL, NULL,
-						"brcm,bcm2835-pm-wdt");
-	if (WARN(!np, "unable to setup watchdog restart"))
-		return;
-
-	wdt_regs = of_iomap(np, 0);
-	WARN(!wdt_regs, "failed to remap watchdog regs");
-}
-
-static void bcm2835_restart(enum reboot_mode mode, const char *cmd)
-{
-	u32 val;
-
-	if (!wdt_regs)
-		return;
-
-	/* use a timeout of 10 ticks (~150us) */
-	writel_relaxed(10 | PM_PASSWORD, wdt_regs + PM_WDOG);
-	val = readl_relaxed(wdt_regs + PM_RSTC);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
-	writel_relaxed(val, wdt_regs + PM_RSTC);
-
-	/* No sleeping, possibly atomic. */
-	mdelay(1);
-}
-
-/*
- * We can't really power off, but if we do the normal reset scheme, and
- * indicate to bootcode.bin not to reboot, then most of the chip will be
- * powered off.
- */
-static void bcm2835_power_off(void)
-{
-	u32 val;
-
-	/*
-	 * We set the watchdog hard reset bit here to distinguish this reset
-	 * from the normal (full) reset. bootcode.bin will not reboot after a
-	 * hard reset.
-	 */
-	val = readl_relaxed(wdt_regs + PM_RSTS);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
-	writel_relaxed(val, wdt_regs + PM_RSTS);
-
-	/* Continue with normal reset mechanism */
-	bcm2835_restart(REBOOT_HARD, "");
-}
-
 static void __init bcm2835_init(void)
 {
 	int ret;
 
-	bcm2835_setup_restart();
-	if (wdt_regs)
-		pm_power_off = bcm2835_power_off;
-
 	bcm2835_init_clocks();
 
 	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
@@ -114,6 +42,5 @@ static const char * const bcm2835_compat[] = {
 
 DT_MACHINE_START(BCM2835, "BCM2835")
 	.init_machine = bcm2835_init,
-	.restart = bcm2835_restart,
 	.dt_compat = bcm2835_compat
 MACHINE_END
drivers/watchdog/bcm2835_wdt.c +62 -0

106 lines not on this page · raw message

Signature · 1 line
2.1.4
#2 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org

Any reason not to select BCM2835_WDT in the config by default then?

---

arch/arm/mach-bcm/Kconfig +1 -0
index 8b11f44..dd4856d 100644
@@ -116,6 +116,7 @@ config ARCH_BCM2835
        select CLKSRC_OF
        select PINCTRL
        select PINCTRL_BCM2835
+       select BCM2835_WDT
        help
          This enables support for the Broadcom BCM2835 SoC. This SoC is
          used in the Raspberry Pi and Roku 2 devices.
Signature · 1 line
Pranith
#3 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 4 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

The series,

Quoted 2 lines

Note that power off has never worked for me, and just reboots as well. So I can't say that I've *really* tested the power off code.

The RPi can't actually power itself off, but it used to be the case that if you rebooted it after setting up a certain register configuration, the firmware would put the device into a low-power state. This did work when it was first upstreamed. However, it no longer works. I believe this was due to a change in the firmware, which is why I don't always trust the firmware. I should really check what the downstream kernel does for power off now; I assume it must have changed since the code was upstreamed.

#4 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Aside from this, the patch looks great.

Arnd

maintainer
#5 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 18 lines · Arnd Bergmann

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Quoted 3 lines

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Why would that be needed ?

Guenter

#6 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 19 lines · On Sunday 26 April 2015 08:35:57 Guenter Roeck wrote:
Quoted 18 lines · Arnd Bergmann

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Quoted 5 lines
Quoted 3 lines

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Why would that be needed ?

devices can be unbound from drivers through sysfs, or using dynamic DT updates. If one does that, the watchdog driver will correctly destroy all information it has about the device, so if the power_off function still uses that pointer, it will crash.

Arnd

maintainer
#7 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 24 lines · Arnd Bergmann
Quoted 23 lines · On Sunday 26 April 2015 08:35:57 Guenter Roeck wrote:
Quoted 21 lines · Arnd Bergmann

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Quoted 7 lines
Quoted 1 line

Why would that be needed ?

devices can be unbound from drivers through sysfs, or using dynamic DT updates. If one does that, the watchdog driver will correctly destroy all information it has about the device, so if the power_off function still uses that pointer, it will crash.

Without calling its remove function ? That sounds odd. Lots of drivers would break if that was really the case.

Guenter

#8 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 27 lines · On Monday 27 April 2015 05:44:14 Guenter Roeck wrote:
Quoted 26 lines · Arnd Bergmann
Quoted 24 lines · On Sunday 26 April 2015 08:35:57 Guenter Roeck wrote:
Quoted 18 lines · Arnd Bergmann

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Quoted 3 lines

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Why would that be needed ?

Quoted 7 lines
Quoted 5 lines

devices can be unbound from drivers through sysfs, or using dynamic DT updates. If one does that, the watchdog driver will correctly destroy all information it has about the device, so if the power_off function still uses that pointer, it will crash.

Without calling its remove function ? That sounds odd. Lots of drivers would break if that was really the case.

I'm not sure what you mean now. The remove function gets called to do the final cleanup, and afterwards the device is deleted, so the remove function should make sure that no global variables point to the device any more.

This is not a concern for most other drivers, because they do not keep global pointers to device structures.

Arnd

maintainer
#9 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 36 lines · Arnd Bergmann
Quoted 27 lines · On Monday 27 April 2015 05:44:14 Guenter Roeck wrote:
Quoted 26 lines · Arnd Bergmann
Quoted 24 lines · On Sunday 26 April 2015 08:35:57 Guenter Roeck wrote:
Quoted 18 lines · Arnd Bergmann

drivers/watchdog/bcm2835_wdt.c static struct watchdog_device bcm2835_wdt_wdd = { · line 147

Quoted 13 lines · On Friday 24 April 2015 12:08:54 Eric Anholt wrote:
drivers/watchdog/bcm2835_wdt.c +13 -0
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+       struct device_node *np =
+               of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+       struct platform_device *pdev = of_find_device_by_node(np);
+       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+       u32 val;
+

Instead of doing the lookup again here, I'd suggest using a static variable in the driver to store the device pointer for the device used on power_off.

Quoted 3 lines

Make sure that the device remove callback assigns it back to NULL though and that the function checks for NULL pointer.

Why would that be needed ?

Quoted 7 lines
Quoted 5 lines

devices can be unbound from drivers through sysfs, or using dynamic DT updates. If one does that, the watchdog driver will correctly destroy all information it has about the device, so if the power_off function still uses that pointer, it will crash.

Without calling its remove function ? That sounds odd. Lots of drivers would break if that was really the case.

Quoted 8 lines

I'm not sure what you mean now. The remove function gets called to do the final cleanup, and afterwards the device is deleted, so the remove function should make sure that no global variables point to the device any more.

This is not a concern for most other drivers, because they do not keep global pointers to device structures.

The pointer to the power-off handler is removed in the device remove callback, and thus won't be called after the device is unbound.

Ultimately this is similar the the current code, which assumes that the call to of_find_device_by_node(np) never fails.

Guenter

#10 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 8 lines · On Monday 27 April 2015 06:28:46 Guenter Roeck wrote:
Quoted 1 line

The pointer to the power-off handler is removed in the device remove callback, and thus won't be called after the device is unbound.

Ultimately this is similar the the current code, which assumes that the call to of_find_device_by_node(np) never fails.

Ok, I missed that part. Yes, that works just as well.

Arnd

#11 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
maintainer
#12 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org

The patch will require a rebase to v4.0-rc1.

Thanks,
Guenter

maintainer
#13 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 11 lines · Guenter Roeck
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org

The patch will require a rebase to v4.0-rc1.

s/4.0/4.1/

Guenter

#14 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 7 lines · Guenter Roeck
Quoted 6 lines · Guenter Roeck
Quoted 5 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Quoted 6 lines
Quoted 5 lines
Quoted 2 lines
Cc linux-watchdog at vger.kernel.org

The patch will require a rebase to v4.0-rc1.

s/4.0/4.1/

It will? It seems to work fine, and the diff's the same. Is there some
new thing you were expecting in a rebase?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150427/16bb2623/attachment.sig>

maintainer
#15 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 12 lines · Eric Anholt
Quoted 10 lines · Guenter Roeck
Quoted 9 lines · Guenter Roeck
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

The patch will require a rebase to v4.0-rc1.

s/4.0/4.1/

It will? It seems to work fine, and the diff's the same. Is there some new thing you were expecting in a rebase?

All I can say is that it didn't apply for me. Maybe someone else has more luck.

Guenter

#16 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

Quoted 13 lines · Guenter Roeck
Quoted 12 lines · Eric Anholt
Quoted 10 lines · Guenter Roeck
Quoted 9 lines · Guenter Roeck
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

The patch will require a rebase to v4.0-rc1.

s/4.0/4.1/

It will? It seems to work fine, and the diff's the same. Is there some new thing you were expecting in a rebase?

All I can say is that it didn't apply for me. Maybe someone else has more luck.

I won't even try without a WDT Ack. ;)

#17 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Guenter Roeck
Quoted 13 lines · Guenter Roeck
Quoted 12 lines · Eric Anholt
Quoted 10 lines · Guenter Roeck
Quoted 9 lines · Guenter Roeck
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

The patch will require a rebase to v4.0-rc1.

s/4.0/4.1/

It will? It seems to work fine, and the diff's the same. Is there some new thing you were expecting in a rebase?

All I can say is that it didn't apply for me. Maybe someone else has more luck.

If you were trying to apply it to stock 4.1-rc1, it would fail. It was based on the for-rpi-next tree, since that's where I assume it would go in through.

If you'd like to take it through your tree I could send you that one,
but it'll mean conflicts for someone to resolve later.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150428/ed9d0a7d/attachment.sig>

#18 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
Quoted 8 lines

---

Note that power off has never worked for me, and just reboots as well. So I can't say that I've *really* tested the power off code.

 arch/arm/mach-bcm/board_bcm2835.c | 73 ---------------------------------------
 drivers/watchdog/bcm2835_wdt.c    | 62 +++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 73 deletions(-)

Please rebase and resend, just this patch, as requested by Guenter.

I'm going to take the other patch.

Quoted 216 lines
arch/arm/mach-bcm/board_bcm2835.c +0 -73
index 49dd5b0..0f7b9ea 100644
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/irqchip.h>
 #include <linux/of_address.h>
@@ -22,81 +21,10 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#define PM_RSTC				0x1c
-#define PM_RSTS				0x20
-#define PM_WDOG				0x24
-
-#define PM_PASSWORD			0x5a000000
-#define PM_RSTC_WRCFG_MASK		0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET	0x00000020
-#define PM_RSTS_HADWRH_SET		0x00000040
-
-static void __iomem *wdt_regs;
-
-/*
- * The machine restart method can be called from an atomic context so we won't
- * be able to ioremap the regs then.
- */
-static void bcm2835_setup_restart(void)
-{
-	struct device_node *np = of_find_compatible_node(NULL, NULL,
-						"brcm,bcm2835-pm-wdt");
-	if (WARN(!np, "unable to setup watchdog restart"))
-		return;
-
-	wdt_regs = of_iomap(np, 0);
-	WARN(!wdt_regs, "failed to remap watchdog regs");
-}
-
-static void bcm2835_restart(enum reboot_mode mode, const char *cmd)
-{
-	u32 val;
-
-	if (!wdt_regs)
-		return;
-
-	/* use a timeout of 10 ticks (~150us) */
-	writel_relaxed(10 | PM_PASSWORD, wdt_regs + PM_WDOG);
-	val = readl_relaxed(wdt_regs + PM_RSTC);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
-	writel_relaxed(val, wdt_regs + PM_RSTC);
-
-	/* No sleeping, possibly atomic. */
-	mdelay(1);
-}
-
-/*
- * We can't really power off, but if we do the normal reset scheme, and
- * indicate to bootcode.bin not to reboot, then most of the chip will be
- * powered off.
- */
-static void bcm2835_power_off(void)
-{
-	u32 val;
-
-	/*
-	 * We set the watchdog hard reset bit here to distinguish this reset
-	 * from the normal (full) reset. bootcode.bin will not reboot after a
-	 * hard reset.
-	 */
-	val = readl_relaxed(wdt_regs + PM_RSTS);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
-	writel_relaxed(val, wdt_regs + PM_RSTS);
-
-	/* Continue with normal reset mechanism */
-	bcm2835_restart(REBOOT_HARD, "");
-}
-
 static void __init bcm2835_init(void)
 {
 	int ret;
 
-	bcm2835_setup_restart();
-	if (wdt_regs)
-		pm_power_off = bcm2835_power_off;
-
 	bcm2835_init_clocks();
 
 	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
@@ -114,6 +42,5 @@ static const char * const bcm2835_compat[] = {
 
 DT_MACHINE_START(BCM2835, "BCM2835")
 	.init_machine = bcm2835_init,
-	.restart = bcm2835_restart,
 	.dt_compat = bcm2835_compat
 MACHINE_END
drivers/watchdog/bcm2835_wdt.c +62 -0
index 2b5a9bb..7116968 100644
@@ -13,20 +13,25 @@
  * option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 
 #define PM_RSTC				0x1c
+#define PM_RSTS				0x20
 #define PM_WDOG				0x24
 
 #define PM_PASSWORD			0x5a000000
 
 #define PM_WDOG_TIME_SET		0x000fffff
 #define PM_RSTC_WRCFG_CLR		0xffffffcf
+#define PM_RSTS_HADWRH_SET		0x00000040
 #define PM_RSTC_WRCFG_SET		0x00000030
 #define PM_RSTC_WRCFG_FULL_RESET	0x00000020
 #define PM_RSTC_RESET			0x00000102
@@ -37,6 +42,7 @@
 struct bcm2835_wdt {
 	void __iomem		*base;
 	spinlock_t		lock;
+	struct notifier_block	restart_handler;
 };
 
 static unsigned int heartbeat;
@@ -106,6 +112,53 @@ static struct watchdog_device bcm2835_wdt_wdd = {
 	.timeout =	WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
 };
 
+static int
+bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd)
+{
+	struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
+					       restart_handler);
+	u32 val;
+
+	/* use a timeout of 10 ticks (~150us) */
+	writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
+	val = readl_relaxed(wdt->base + PM_RSTC);
+	val &= PM_RSTC_WRCFG_CLR;
+	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
+	writel_relaxed(val, wdt->base + PM_RSTC);
+
+	/* No sleeping, possibly atomic. */
+	mdelay(1);
+
+	return 0;
+}
+
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+	struct device_node *np =
+		of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+	struct platform_device *pdev = of_find_device_by_node(np);
+	struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+	u32 val;
+
+	/*
+	 * We set the watchdog hard reset bit here to distinguish this reset
+	 * from the normal (full) reset. bootcode.bin will not reboot after a
+	 * hard reset.
+	 */
+	val = readl_relaxed(wdt->base + PM_RSTS);
+	val &= PM_RSTC_WRCFG_CLR;
+	val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
+	writel_relaxed(val, wdt->base + PM_RSTS);
+
+	/* Continue with normal reset mechanism */
+	bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL);
+}
+
 static int bcm2835_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -136,6 +189,12 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	wdt->restart_handler.notifier_call = bcm2835_restart;
+	wdt->restart_handler.priority = 128;
+	register_restart_handler(&wdt->restart_handler);
+	if (pm_power_off == NULL)
+		pm_power_off = bcm2835_power_off;
+
 	dev_info(dev, "Broadcom BCM2835 watchdog timer");
 	return 0;
 }
@@ -144,6 +203,9 @@ static int bcm2835_wdt_remove(struct platform_device *pdev)
 {
 	struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
 
+	unregister_restart_handler(&wdt->restart_handler);
+	if (pm_power_off == bcm2835_power_off)
+		pm_power_off = NULL;
 	watchdog_unregister_device(&bcm2835_wdt_wdd);
 	iounmap(wdt->base);
 
maintainer
#19 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 10 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

#20 lore raw

PATCH 2/2 ARM: BCM2835: Move the restart/power_off handling to the WDT driver.

In reply to Eric Anholt
Quoted 7 lines · Eric Anholt

Since the WDT is what's used to drive restart and power off, it makes more sense to keep it there, where the regs are already mapped and definitions for them provided. Note that this means you may need to add CONFIG_BCM2835_WDT to retain functionality of your kernel.

Cc linux-watchdog at vger.kernel.org
Quoted 8 lines

---

Note that power off has never worked for me, and just reboots as well. So I can't say that I've *really* tested the power off code.

 arch/arm/mach-bcm/board_bcm2835.c | 73 ---------------------------------------
 drivers/watchdog/bcm2835_wdt.c    | 62 +++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 73 deletions(-)

Applied with Guenter's Ack.

Quoted 216 lines
arch/arm/mach-bcm/board_bcm2835.c +0 -73
index 49dd5b0..0f7b9ea 100644
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/irqchip.h>
 #include <linux/of_address.h>
@@ -22,81 +21,10 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#define PM_RSTC				0x1c
-#define PM_RSTS				0x20
-#define PM_WDOG				0x24
-
-#define PM_PASSWORD			0x5a000000
-#define PM_RSTC_WRCFG_MASK		0x00000030
-#define PM_RSTC_WRCFG_FULL_RESET	0x00000020
-#define PM_RSTS_HADWRH_SET		0x00000040
-
-static void __iomem *wdt_regs;
-
-/*
- * The machine restart method can be called from an atomic context so we won't
- * be able to ioremap the regs then.
- */
-static void bcm2835_setup_restart(void)
-{
-	struct device_node *np = of_find_compatible_node(NULL, NULL,
-						"brcm,bcm2835-pm-wdt");
-	if (WARN(!np, "unable to setup watchdog restart"))
-		return;
-
-	wdt_regs = of_iomap(np, 0);
-	WARN(!wdt_regs, "failed to remap watchdog regs");
-}
-
-static void bcm2835_restart(enum reboot_mode mode, const char *cmd)
-{
-	u32 val;
-
-	if (!wdt_regs)
-		return;
-
-	/* use a timeout of 10 ticks (~150us) */
-	writel_relaxed(10 | PM_PASSWORD, wdt_regs + PM_WDOG);
-	val = readl_relaxed(wdt_regs + PM_RSTC);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
-	writel_relaxed(val, wdt_regs + PM_RSTC);
-
-	/* No sleeping, possibly atomic. */
-	mdelay(1);
-}
-
-/*
- * We can't really power off, but if we do the normal reset scheme, and
- * indicate to bootcode.bin not to reboot, then most of the chip will be
- * powered off.
- */
-static void bcm2835_power_off(void)
-{
-	u32 val;
-
-	/*
-	 * We set the watchdog hard reset bit here to distinguish this reset
-	 * from the normal (full) reset. bootcode.bin will not reboot after a
-	 * hard reset.
-	 */
-	val = readl_relaxed(wdt_regs + PM_RSTS);
-	val &= ~PM_RSTC_WRCFG_MASK;
-	val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
-	writel_relaxed(val, wdt_regs + PM_RSTS);
-
-	/* Continue with normal reset mechanism */
-	bcm2835_restart(REBOOT_HARD, "");
-}
-
 static void __init bcm2835_init(void)
 {
 	int ret;
 
-	bcm2835_setup_restart();
-	if (wdt_regs)
-		pm_power_off = bcm2835_power_off;
-
 	bcm2835_init_clocks();
 
 	ret = of_platform_populate(NULL, of_default_bus_match_table, NULL,
@@ -114,6 +42,5 @@ static const char * const bcm2835_compat[] = {
 
 DT_MACHINE_START(BCM2835, "BCM2835")
 	.init_machine = bcm2835_init,
-	.restart = bcm2835_restart,
 	.dt_compat = bcm2835_compat
 MACHINE_END
drivers/watchdog/bcm2835_wdt.c +62 -0
index 2b5a9bb..7116968 100644
@@ -13,20 +13,25 @@
  * option) any later version.
  */
 
+#include <linux/delay.h>
+#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
 #include <linux/of_address.h>
+#include <linux/of_platform.h>
 
 #define PM_RSTC				0x1c
+#define PM_RSTS				0x20
 #define PM_WDOG				0x24
 
 #define PM_PASSWORD			0x5a000000
 
 #define PM_WDOG_TIME_SET		0x000fffff
 #define PM_RSTC_WRCFG_CLR		0xffffffcf
+#define PM_RSTS_HADWRH_SET		0x00000040
 #define PM_RSTC_WRCFG_SET		0x00000030
 #define PM_RSTC_WRCFG_FULL_RESET	0x00000020
 #define PM_RSTC_RESET			0x00000102
@@ -37,6 +42,7 @@
 struct bcm2835_wdt {
 	void __iomem		*base;
 	spinlock_t		lock;
+	struct notifier_block	restart_handler;
 };
 
 static unsigned int heartbeat;
@@ -106,6 +112,53 @@ static struct watchdog_device bcm2835_wdt_wdd = {
 	.timeout =	WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
 };
 
+static int
+bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd)
+{
+	struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
+					       restart_handler);
+	u32 val;
+
+	/* use a timeout of 10 ticks (~150us) */
+	writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
+	val = readl_relaxed(wdt->base + PM_RSTC);
+	val &= PM_RSTC_WRCFG_CLR;
+	val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
+	writel_relaxed(val, wdt->base + PM_RSTC);
+
+	/* No sleeping, possibly atomic. */
+	mdelay(1);
+
+	return 0;
+}
+
+/*
+ * We can't really power off, but if we do the normal reset scheme, and
+ * indicate to bootcode.bin not to reboot, then most of the chip will be
+ * powered off.
+ */
+static void bcm2835_power_off(void)
+{
+	struct device_node *np =
+		of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt");
+	struct platform_device *pdev = of_find_device_by_node(np);
+	struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
+	u32 val;
+
+	/*
+	 * We set the watchdog hard reset bit here to distinguish this reset
+	 * from the normal (full) reset. bootcode.bin will not reboot after a
+	 * hard reset.
+	 */
+	val = readl_relaxed(wdt->base + PM_RSTS);
+	val &= PM_RSTC_WRCFG_CLR;
+	val |= PM_PASSWORD | PM_RSTS_HADWRH_SET;
+	writel_relaxed(val, wdt->base + PM_RSTS);
+
+	/* Continue with normal reset mechanism */
+	bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL);
+}
+
 static int bcm2835_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -136,6 +189,12 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	wdt->restart_handler.notifier_call = bcm2835_restart;
+	wdt->restart_handler.priority = 128;
+	register_restart_handler(&wdt->restart_handler);
+	if (pm_power_off == NULL)
+		pm_power_off = bcm2835_power_off;
+
 	dev_info(dev, "Broadcom BCM2835 watchdog timer");
 	return 0;
 }
@@ -144,6 +203,9 @@ static int bcm2835_wdt_remove(struct platform_device *pdev)
 {
 	struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
 
+	unregister_restart_handler(&wdt->restart_handler);
+	if (pm_power_off == bcm2835_power_off)
+		pm_power_off = NULL;
 	watchdog_unregister_device(&bcm2835_wdt_wdd);
 	iounmap(wdt->base);
 
#21 lore raw

PATCH 1/2 ARM: BCM2835: Drop the init_irq() hook.

In reply to Eric Anholt
Quoted 6 lines · Eric Anholt

This is the default function that gets called if the hook is NULL.

---
 arch/arm/mach-bcm/board_bcm2835.c | 1 -
 1 file changed, 1 deletion(-)

Applied with Lubomir and Stephen's Ack.

Quoted 12 lines
arch/arm/mach-bcm/board_bcm2835.c +0 -1
index 9851ee8..49dd5b0 100644
@@ -113,7 +113,6 @@ static const char * const bcm2835_compat[] = {
 };
 
 DT_MACHINE_START(BCM2835, "BCM2835")
-	.init_irq = irqchip_init,
 	.init_machine = bcm2835_init,
 	.restart = bcm2835_restart,
 	.dt_compat = bcm2835_compat