Skip to contentSkip to conversation

bcm2835: wdt: support for the bcm2835/2836 wdt

PATCH New Paolo Pisati 2 participants 4 messages Jan 27, 2017 – Feb 10, 2017

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

PATCH 1/1 bcm2835: wdt: support for the bcm2835/2836 wdt

The following patch add support for the watchdog built into the bcm2835/2836 chips, using the max timeout (~15s).

By default the watchdog is compiled in, but disabled. To enable it, apply the following patch:

include/configs/rpi.h +1 -0
@@ -109,6 +109,7 @@
 
 /* Watchdog support */
 #define CONFIG_BCM2835_WDT
+#define CONFIG_HW_WATCHDOG
 
 /* Console configuration */
 #define CONFIG_SYS_CBSIZE              1024
Signature · 18 lines
2.7.4

Tested on my RaspberryPi2.

Paolo Pisati (1):
  bcm2835_wdt: support for the BCM2835/2836 watchdog

 arch/arm/mach-bcm283x/reset.c  | 21 ++++++++++++++++++---
 board/raspberrypi/rpi/rpi.c    |  4 ++++
 drivers/watchdog/Makefile      |  1 +
 drivers/watchdog/bcm2835_wdt.c | 34 ++++++++++++++++++++++++++++++++++
 include/configs/rpi.h          |  3 +++
 scripts/config_whitelist.txt   |  1 +
 6 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 drivers/watchdog/bcm2835_wdt.c

-- 
2.7.4
#1 lore raw

PATCH 1/1 bcm2835_wdt: support for the BCM2835/2836 watchdog

---
 arch/arm/mach-bcm283x/reset.c  | 21 ++++++++++++++++++---
 board/raspberrypi/rpi/rpi.c    |  4 ++++
 drivers/watchdog/Makefile      |  1 +
 drivers/watchdog/bcm2835_wdt.c | 34 ++++++++++++++++++++++++++++++++++
 include/configs/rpi.h          |  3 +++
 scripts/config_whitelist.txt   |  1 +
 6 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 drivers/watchdog/bcm2835_wdt.c
arch/arm/mach-bcm283x/reset.c +18 -3
index 685815c..b62cb8a 100644
@@ -21,18 +21,33 @@
  */
 #define BCM2835_WDOG_RSTS_RASPBERRYPI_HALT	0x555
 
+/* max ticks timeout */
+#define BCM2835_WDOG_MAX_TIMEOUT	0x000fffff
+
+#ifdef CONFIG_BCM2835_WDT
+extern void hw_watchdog_disable(void);
+#else
+void hw_watchdog_disable(void) {}
+#endif
+
 __efi_runtime_data struct bcm2835_wdog_regs *wdog_regs =
 	(struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;
 
-void __efi_runtime reset_cpu(ulong addr)
+void __efi_runtime reset_cpu(ulong ticks)
 {
-	uint32_t rstc;
+	uint32_t rstc, timeout;
+
+	if (ticks == 0) {
+		hw_watchdog_disable();
+		timeout = RESET_TIMEOUT;
+	} else
+		timeout = ticks & BCM2835_WDOG_MAX_TIMEOUT;
 
 	rstc = readl(&wdog_regs->rstc);
 	rstc &= ~BCM2835_WDOG_RSTC_WRCFG_MASK;
 	rstc |= BCM2835_WDOG_RSTC_WRCFG_FULL_RESET;
 
-	writel(BCM2835_WDOG_PASSWORD | RESET_TIMEOUT, &wdog_regs->wdog);
+	writel(BCM2835_WDOG_PASSWORD | timeout, &wdog_regs->wdog);
 	writel(BCM2835_WDOG_PASSWORD | rstc, &wdog_regs->rstc);
 }
 
board/raspberrypi/rpi/rpi.c +4 -0
index 22e87a2..106e518 100644
@@ -22,6 +22,7 @@
 #ifdef CONFIG_ARM64
 #include <asm/armv8/mmu.h>
 #endif
+#include <watchdog.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -478,6 +479,9 @@ static void rpi_disable_inactive_uart(void)
 
 int board_init(void)
 {
+#ifdef CONFIG_HW_WATCHDOG
+	hw_watchdog_init();
+#endif
 #ifndef CONFIG_PL01X_SERIAL
 	rpi_disable_inactive_uart();
 #endif
drivers/watchdog/Makefile +1 -0
index a007ae8..3b328ec 100644
@@ -15,3 +15,4 @@ obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
 obj-$(CONFIG_BFIN_WATCHDOG)  += bfin_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
+obj-$(CONFIG_BCM2835_WDT)       += bcm2835_wdt.o
drivers/watchdog/bcm2835_wdt.c new file +34 -0
new file mode 100644
index 0000000..c76b164
@@ -0,0 +1,34 @@
+/*
+ * Watchdog driver for Broadcom BCM2835
+ *
+ * Copyright (C) 2017 Paolo Pisati <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/wdog.h>
+
+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+#define MAX_TIMEOUT   0xf /* ~15s */
+
+bool enabled = true;
+
+extern void reset_cpu(ulong ticks);
+
+void hw_watchdog_reset(void)
+{
+	if (enabled)
+		reset_cpu(SECS_TO_WDOG_TICKS(MAX_TIMEOUT));
+}
+
+void hw_watchdog_init(void)
+{
+	hw_watchdog_reset();
+}
+
+void hw_watchdog_disable(void)
+{
+	enabled = false;
+}
include/configs/rpi.h +3 -0
index 45d8824..c34c84b 100644
@@ -107,6 +107,9 @@
 #define CONFIG_CONS_INDEX		0
 #define CONFIG_BAUDRATE			115200
 
+/* Watchdog support */
+#define CONFIG_BCM2835_WDT
+
 /* Console configuration */
 #define CONFIG_SYS_CBSIZE		1024
 #define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE +		\
scripts/config_whitelist.txt +1 -0
index 00ee3f1..eb6cb8a 100644
@@ -294,6 +294,7 @@ CONFIG_BCH_CONST_M
 CONFIG_BCH_CONST_PARAMS
 CONFIG_BCH_CONST_T
 CONFIG_BCM2835_GPIO
+CONFIG_BCM2835_WDT
 CONFIG_BCM283X_MU_SERIAL
 CONFIG_BCM_SF2_ETH
 CONFIG_BCM_SF2_ETH_DEFAULT_PORT
Signature · 1 line
2.7.4
#2 lore raw

PATCH 1/1 bcm2835_wdt: support for the BCM2835/2836 watchdog

Quoted 30 lines · On Freitag, 27. Januar 2017 10:59:05 CET Paolo Pisati wrote:
---
 arch/arm/mach-bcm283x/reset.c  | 21 ++++++++++++++++++---
 board/raspberrypi/rpi/rpi.c    |  4 ++++
 drivers/watchdog/Makefile      |  1 +
 drivers/watchdog/bcm2835_wdt.c | 34 ++++++++++++++++++++++++++++++++++
 include/configs/rpi.h          |  3 +++
 scripts/config_whitelist.txt   |  1 +
 6 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 drivers/watchdog/bcm2835_wdt.c
arch/arm/mach-bcm283x/reset.c +9 -0
index 685815c..b62cb8a 100644
@@ -21,18 +21,33 @@
  */
 #define BCM2835_WDOG_RSTS_RASPBERRYPI_HALT	0x555
 
+/* max ticks timeout */
+#define BCM2835_WDOG_MAX_TIMEOUT	0x000fffff
+
+#ifdef CONFIG_BCM2835_WDT
+extern void hw_watchdog_disable(void);
+#else
+void hw_watchdog_disable(void) {}
+#endif
+
 __efi_runtime_data struct bcm2835_wdog_regs *wdog_regs =
 	(struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;

arch/arm/mach-bcm283x/reset.c line 42

Quoted 10 lines
arch/arm/mach-bcm283x/reset.c +6 -2
 
-void __efi_runtime reset_cpu(ulong addr)
+void __efi_runtime reset_cpu(ulong ticks)
 {
-	uint32_t rstc;
+	uint32_t rstc, timeout;
+
+	if (ticks == 0) {
+		hw_watchdog_disable();
+		timeout = RESET_TIMEOUT;

This is wrong. The efi runtime reset function calls this as reset_cpu(0), and then tries to call hw_watchdog_disable, which is not marked as __efi_runtime.

Actually, I can see no reason the watchdog setup piggybacks on the reset_cpu funtion.

Quoted 16 lines
arch/arm/mach-bcm283x/reset.c +3 -1
+	} else
+		timeout = ticks & BCM2835_WDOG_MAX_TIMEOUT;
 
 	rstc = readl(&wdog_regs->rstc);
 	rstc &= ~BCM2835_WDOG_RSTC_WRCFG_MASK;
 	rstc |= BCM2835_WDOG_RSTC_WRCFG_FULL_RESET;
 
-	writel(BCM2835_WDOG_PASSWORD | RESET_TIMEOUT, &wdog_regs->wdog);
+	writel(BCM2835_WDOG_PASSWORD | timeout, &wdog_regs->wdog);
 	writel(BCM2835_WDOG_PASSWORD | rstc, &wdog_regs->rstc);
 }
 
board/raspberrypi/rpi/rpi.c +0 -0
index 22e87a2..106e518 100644

[...]

scripts/config_whitelist.txt CONFIG_BCH_CONST_M · line 300

Quoted 10 lines
scripts/config_whitelist.txt +1 -0
@@ -294,6 +294,7 @@ CONFIG_BCH_CONST_M
 CONFIG_BCH_CONST_PARAMS
 CONFIG_BCH_CONST_T
 CONFIG_BCM2835_GPIO
+CONFIG_BCM2835_WDT
 CONFIG_BCM283X_MU_SERIAL
 CONFIG_BCM_SF2_ETH
 CONFIG_BCM_SF2_ETH_DEFAULT_PORT

I think the rule is no new CONFIG_xxx options, but appropriate options in KConfig.

Kind regards,

Stefan

#3 lore raw

PATCH 1/1 bcm2835_wdt: support for the BCM2835/2836 watchdog

Quoted 5 lines · Stefan
Quoted 5 lines

...

arch/arm/mach-bcm283x/reset.c +1 -0
+
 __efi_runtime_data struct bcm2835_wdog_regs *wdog_regs =
 	(struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;
Quoted 12 lines

arch/arm/mach-bcm283x/reset.c line 42

Quoted 9 lines
arch/arm/mach-bcm283x/reset.c +6 -2
-void __efi_runtime reset_cpu(ulong addr)
+void __efi_runtime reset_cpu(ulong ticks)
 {
-	uint32_t rstc;
+	uint32_t rstc, timeout;
+
+	if (ticks == 0) {
+		hw_watchdog_disable();
+		timeout = RESET_TIMEOUT;

This is wrong. The efi runtime reset function calls this as reset_cpu(0), and then tries to call hw_watchdog_disable, which is not marked as __efi_runtime.

Ok.

Quoted 2 lines

Actually, I can see no reason the watchdog setup piggybacks on the reset_cpu funtion.

Because there's a window after reset_cpu() is called but before real reset happens, and if hw_watchdog_reset() is called in between, it breaks the reset procedure.

There must be a mechanism for reset_cpu() to disable the watchdog driver so it won't interfere.

Quoted 3 lines

I think the rule is no new CONFIG_xxx options, but appropriate options in KConfig.

I'll send a V2.

Signature · 2 lines
bye,
p.