Skip to contentSkip to conversation

Armada 370/XP watchdog support

PATCH Superseded Ezequiel Garcia 5 participants 42 messages Jan 22, 2014 – Jan 27, 2014

Subsystems (6)

v4 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v4 cover Armada 370/XP watchdog support

After some lengthy discussion on the [v2] and [v3] patchsets, here's a new round. I hope I haven't forgotten anything.

[v2] http://www.spinics.net/lists/arm-kernel/msg302104.html

[v3] http://www.spinics.net/lists/arm-kernel/msg302245.html

The main changes from v3 are:

* It wasn't nice to break DT compatibility by adding a second resource requirement, so we provided a fallback to use the RSTOUT address. All in all, the solution doesn't look too bad.

* Added a full watchdog stop at driver probe time, *before* the call to request_irq().

Notice that currently the request_irq() doesn't seem to clear the pending interruption. This means the BRIDGE_CAUSE clear removal is still not safe.

This should be fixed sooner than later and, of course, before this gets merged.

* Rework the interruption request, to use devm_request_irq() and avoid dealing with IRQ releasing.

* Added proper clock error handling and fixed the probe() error path.

* Typos and minor issues got fixed

Thanks to everyone who has helped reviewing the previous sets! It's certainly easier to move forward when you get so much nice feedback...

Ezequiel Garcia (18):
ARM: Introduce atomic MMIO modify
clocksource: orion: Use atomic access for shared registers
watchdog: orion: Add clock error handling
watchdog: orion: Use atomic access for shared registers
watchdog: orion: Remove unused macros
watchdog: orion: Make sure the watchdog is initially stopped
watchdog: orion: Handle IRQ
watchdog: orion: Make RSTOUT register a separate resource
watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
watchdog: orion: Introduce an orion_watchdog device structure
watchdog: orion: Introduce per-compatible of_device_id data
watchdog: orion: Add per-compatible clock initialization
watchdog: orion: Add per-compatible watchdog start implementation
watchdog: orion: Add support for Armada 370 and Armada XP SoC
ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
watchdog: orion: Enable the build on ARCH_MVEBU
ARM: mvebu: Enable watchdog support in defconfig

 .../devicetree/bindings/watchdog/marvel.txt        |   8 +-
 arch/arm/boot/dts/armada-370-xp.dtsi               |   4 +
 arch/arm/boot/dts/armada-370.dtsi                  |   5 +
 arch/arm/boot/dts/armada-xp.dtsi                   |   6 +
 arch/arm/boot/dts/kirkwood.dtsi                    |   2 +-
 arch/arm/configs/mvebu_defconfig                   |   2 +
 arch/arm/include/asm/io.h                          |   6 +
 arch/arm/kernel/io.c                               |  35 ++
 arch/arm/mach-dove/include/mach/bridge-regs.h      |   1 +
 arch/arm/mach-kirkwood/include/mach/bridge-regs.h  |   1 +
 arch/arm/mach-mv78xx0/include/mach/bridge-regs.h   |   1 +
 arch/arm/mach-orion5x/include/mach/bridge-regs.h   |   1 +
 arch/arm/plat-orion/common.c                       |  10 +-
 drivers/clocksource/time-orion.c                   |  28 +-
 drivers/watchdog/Kconfig                           |   2 +-
 drivers/watchdog/orion_wdt.c                       | 370 ++++++++++++++++-----
 16 files changed, 373 insertions(+), 109 deletions(-)
Signature · 1 line
1.8.1.5
#1 lore raw

PATCH v4 1/18 ARM: Introduce atomic MMIO modify

Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API.

Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers.

We add relaxed and non-relaxed variants, by using writel_relaxed and writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register.

---
 arch/arm/include/asm/io.h |  6 ++++++
 arch/arm/kernel/io.c      | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)
arch/arm/include/asm/io.h +6 -0
index fbeb39c..8aa4cca 100644
@@ -38,6 +38,12 @@
 #define isa_bus_to_virt phys_to_virt
 
 /*
+ * Atomic MMIO-wide IO modify
+ */
+extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set);
+extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
+
+/*
  * Generic IO read/write.  These perform native-endian accesses.  Note
  * that some architectures will want to re-define __raw_{read,write}w.
  */
arch/arm/kernel/io.c +35 -0
index dcd5b4d..9203cf8 100644
@@ -1,6 +1,41 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
+
+static DEFINE_RAW_SPINLOCK(__io_lock);
+
+/*
+ * Generic atomic MMIO modify.
+ *
+ * Allows thread-safe access to registers shared by unrelated subsystems.
+ * The access is protected by a single MMIO-wide lock.
+ */
+void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
+{
+	unsigned long flags;
+	u32 value;
+
+	raw_spin_lock_irqsave(&__io_lock, flags);
+	value = readl_relaxed(reg) & ~mask;
+	value |= (set & mask);
+	writel_relaxed(value, reg);
+	raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify_relaxed);
+
+void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
+{
+	unsigned long flags;
+	u32 value;
+
+	raw_spin_lock_irqsave(&__io_lock, flags);
+	value = readl_relaxed(reg) & ~mask;
+	value |= (set & mask);
+	writel(value, reg);
+	raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify);
 
 /*
  * Copy data from IO memory space to "real" memory space.
Signature · 1 line
1.8.1.5
#2 lore raw

PATCH v4 1/18 ARM: Introduce atomic MMIO modify

Russell,

Quoted 12 lines · Ezequiel Garcia

Some SoC have MMIO regions that are shared across orthogonal subsystems. This commit implements a possible solution for the thread-safe access of such regions through a spinlock-protected API.

Concurrent access is protected with a single spinlock for the entire MMIO address space. While this protects shared-registers, it also serializes access to unrelated/unshared registers.

We add relaxed and non-relaxed variants, by using writel_relaxed and writel, respectively. The rationale for this is that some users may not require register write completion but only thread-safe access to a register.

Quoted 5 lines
---
 arch/arm/include/asm/io.h |  6 ++++++
 arch/arm/kernel/io.c      | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

This has been in your patch tracker for a while:

http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7930/1

When you requested Acks, we sent them:

http://www.spinics.net/lists/arm-kernel/msg300250.html

Is there anything more you need from us? The rest of this series depends on this patch. Could you place it in a topic branch so we can base the rest of the series off of it? Or, if you prefer, Ack it and drop it from your patch tracker? I'm fine either way.

thx,

Jason.

Quoted 67 lines
arch/arm/include/asm/io.h +6 -0
index fbeb39c..8aa4cca 100644
@@ -38,6 +38,12 @@
 #define isa_bus_to_virt phys_to_virt
 
 /*
+ * Atomic MMIO-wide IO modify
+ */
+extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set);
+extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
+
+/*
  * Generic IO read/write.  These perform native-endian accesses.  Note
  * that some architectures will want to re-define __raw_{read,write}w.
  */
arch/arm/kernel/io.c +35 -0
index dcd5b4d..9203cf8 100644
@@ -1,6 +1,41 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
+
+static DEFINE_RAW_SPINLOCK(__io_lock);
+
+/*
+ * Generic atomic MMIO modify.
+ *
+ * Allows thread-safe access to registers shared by unrelated subsystems.
+ * The access is protected by a single MMIO-wide lock.
+ */
+void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
+{
+	unsigned long flags;
+	u32 value;
+
+	raw_spin_lock_irqsave(&__io_lock, flags);
+	value = readl_relaxed(reg) & ~mask;
+	value |= (set & mask);
+	writel_relaxed(value, reg);
+	raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify_relaxed);
+
+void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
+{
+	unsigned long flags;
+	u32 value;
+
+	raw_spin_lock_irqsave(&__io_lock, flags);
+	value = readl_relaxed(reg) & ~mask;
+	value |= (set & mask);
+	writel(value, reg);
+	raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify);
 
 /*
  * Copy data from IO memory space to "real" memory space.
Signature · 1 line
1.8.1.5
#3 lore raw

PATCH v4 2/18 clocksource: orion: Use atomic access for shared registers

In reply to Ezequiel Garcia

Replace the driver-specific thread-safe shared register API by the recently introduced atomic_io_clear_set().

---
 drivers/clocksource/time-orion.c | 28 ++++++++++------------------
 1 file changed, 10 insertions(+), 18 deletions(-)
drivers/clocksource/time-orion.c +10 -18
index 9c7f018..3f14e56 100644
@@ -35,20 +35,6 @@
 #define ORION_ONESHOT_MAX	0xfffffffe
 
 static void __iomem *timer_base;
-static DEFINE_SPINLOCK(timer_ctrl_lock);
-
-/*
- * Thread-safe access to TIMER_CTRL register
- * (shared with watchdog timer)
- */
-void orion_timer_ctrl_clrset(u32 clr, u32 set)
-{
-	spin_lock(&timer_ctrl_lock);
-	writel((readl(timer_base + TIMER_CTRL) & ~clr) | set,
-		timer_base + TIMER_CTRL);
-	spin_unlock(&timer_ctrl_lock);
-}
-EXPORT_SYMBOL(orion_timer_ctrl_clrset);
 
 /*
  * Free-running clocksource handling.
@@ -68,7 +54,8 @@ static int orion_clkevt_next_event(unsigned long delta,
 {
 	/* setup and enable one-shot timer */
 	writel(delta, timer_base + TIMER1_VAL);
-	orion_timer_ctrl_clrset(TIMER1_RELOAD_EN, TIMER1_EN);
+	atomic_io_modify(timer_base + TIMER_CTRL,
+		TIMER1_RELOAD_EN | TIMER1_EN, TIMER1_EN);
 
 	return 0;
 }
@@ -80,10 +67,13 @@ static void orion_clkevt_mode(enum clock_event_mode mode,
 		/* setup and enable periodic timer at 1/HZ intervals */
 		writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD);
 		writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL);
-		orion_timer_ctrl_clrset(0, TIMER1_RELOAD_EN | TIMER1_EN);
+		atomic_io_modify(timer_base + TIMER_CTRL,
+			TIMER1_RELOAD_EN | TIMER1_EN,
+			TIMER1_RELOAD_EN | TIMER1_EN);
 	} else {
 		/* disable timer */
-		orion_timer_ctrl_clrset(TIMER1_RELOAD_EN | TIMER1_EN, 0);
+		atomic_io_modify(timer_base + TIMER_CTRL,
+			TIMER1_RELOAD_EN | TIMER1_EN, 0);
 	}
 }
 
@@ -131,7 +121,9 @@ static void __init orion_timer_init(struct device_node *np)
 	/* setup timer0 as free-running clocksource */
 	writel(~0, timer_base + TIMER0_VAL);
 	writel(~0, timer_base + TIMER0_RELOAD);
-	orion_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | TIMER0_EN);
+	atomic_io_modify(timer_base + TIMER_CTRL,
+		TIMER0_RELOAD_EN | TIMER0_EN,
+		TIMER0_RELOAD_EN | TIMER0_EN);
 	clocksource_mmio_init(timer_base + TIMER0_VAL, "orion_clocksource",
 			      clk_get_rate(clk), 300, 32,
 			      clocksource_mmio_readl_down);
Signature · 1 line
1.8.1.5
#4 lore raw

PATCH v4 3/18 watchdog: orion: Add clock error handling

In reply to Ezequiel Garcia

This commit adds a check for clk_prepare_enable success and introduces an error path to disable the clock properly.

---
 drivers/watchdog/orion_wdt.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/watchdog/orion_wdt.c +19 -10
index f7722a4..7f19fa3 100644
@@ -151,17 +151,24 @@ static int orion_wdt_probe(struct platform_device *pdev)
 	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
-		return -ENODEV;
+		return PTR_ERR(clk);
 	}
-	clk_prepare_enable(clk);
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		return ret;
 	wdt_tclk = clk_get_rate(clk);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
+	if (!res) {
+		ret = -ENODEV;
+		goto disable_clk;
+	}
+
 	wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!wdt_reg)
-		return -ENOMEM;
+	if (!wdt_reg) {
+		ret = -ENOMEM;
+		goto disable_clk;
+	}
 
 	wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
 
@@ -171,14 +178,16 @@ static int orion_wdt_probe(struct platform_device *pdev)
 
 	watchdog_set_nowayout(&orion_wdt, nowayout);
 	ret = watchdog_register_device(&orion_wdt);
-	if (ret) {
-		clk_disable_unprepare(clk);
-		return ret;
-	}
+	if (ret)
+		goto disable_clk;
 
 	pr_info("Initial timeout %d sec%s\n",
 		orion_wdt.timeout, nowayout ? ", nowayout" : "");
 	return 0;
+
+disable_clk:
+	clk_disable_unprepare(clk);
+	return ret;
 }
 
 static int orion_wdt_remove(struct platform_device *pdev)
Signature · 1 line
1.8.1.5
#6 lore raw

PATCH v4 4/18 watchdog: orion: Use atomic access for shared registers

In reply to Ezequiel Garcia

Since the timer control register is shared with the clocksource driver, use the recently introduced atomic_io_clear_set() to access such register. Given the watchdog core already provides serialization for all the watchdog ops, this commit allows to remove the spinlock entirely.

---
 drivers/watchdog/orion_wdt.c | 42 +++++-------------------------------------
 1 file changed, 5 insertions(+), 37 deletions(-)
drivers/watchdog/orion_wdt.c +5 -37
index 7f19fa3..b92a991 100644
@@ -20,7 +20,6 @@
 #include <linux/watchdog.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/spinlock.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/of.h>
@@ -46,25 +45,16 @@ static unsigned int wdt_max_duration;	/* (seconds) */
 static struct clk *clk;
 static unsigned int wdt_tclk;
 static void __iomem *wdt_reg;
-static DEFINE_SPINLOCK(wdt_lock);
 
 static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 {
-	spin_lock(&wdt_lock);
-
 	/* Reload watchdog duration */
 	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
-
-	spin_unlock(&wdt_lock);
 	return 0;
 }
 
 static int orion_wdt_start(struct watchdog_device *wdt_dev)
 {
-	u32 reg;
-
-	spin_lock(&wdt_lock);
-
 	/* Set watchdog duration */
 	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
 
@@ -72,48 +62,26 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
 	writel(~WDT_INT_REQ, BRIDGE_CAUSE);
 
 	/* Enable watchdog timer */
-	reg = readl(wdt_reg + TIMER_CTRL);
-	reg |= WDT_EN;
-	writel(reg, wdt_reg + TIMER_CTRL);
+	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
 
 	/* Enable reset on watchdog */
-	reg = readl(RSTOUTn_MASK);
-	reg |= WDT_RESET_OUT_EN;
-	writel(reg, RSTOUTn_MASK);
-
-	spin_unlock(&wdt_lock);
+	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
 	return 0;
 }
 
 static int orion_wdt_stop(struct watchdog_device *wdt_dev)
 {
-	u32 reg;
-
-	spin_lock(&wdt_lock);
-
 	/* Disable reset on watchdog */
-	reg = readl(RSTOUTn_MASK);
-	reg &= ~WDT_RESET_OUT_EN;
-	writel(reg, RSTOUTn_MASK);
+	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
 
 	/* Disable watchdog timer */
-	reg = readl(wdt_reg + TIMER_CTRL);
-	reg &= ~WDT_EN;
-	writel(reg, wdt_reg + TIMER_CTRL);
-
-	spin_unlock(&wdt_lock);
+	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
 	return 0;
 }
 
 static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
 {
-	unsigned int time_left;
-
-	spin_lock(&wdt_lock);
-	time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
-	spin_unlock(&wdt_lock);
-
-	return time_left;
+	return readl(wdt_reg + WDT_VAL) / wdt_tclk;
 }
 
 static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
Signature · 1 line
1.8.1.5
maintainer
#7 lore raw

PATCH v4 4/18 watchdog: orion: Use atomic access for shared registers

Quoted 6 lines · Ezequiel Garcia

Since the timer control register is shared with the clocksource driver, use the recently introduced atomic_io_clear_set() to access such register. Given the watchdog core already provides serialization for all the watchdog ops, this commit allows to remove the spinlock entirely.

#8 lore raw

PATCH v4 5/18 watchdog: orion: Remove unused macros

In reply to Ezequiel Garcia

These are not used anywhere so it's safe to remove them.

---
 drivers/watchdog/orion_wdt.c | 2 --
 1 file changed, 2 deletions(-)
drivers/watchdog/orion_wdt.c +0 -2
index b92a991..6746033 100644
@@ -33,8 +33,6 @@
 #define WDT_VAL			0x0024
 
 #define WDT_MAX_CYCLE_COUNT	0xffffffff
-#define WDT_IN_USE		0
-#define WDT_OK_TO_CLOSE		1
 
 #define WDT_RESET_OUT_EN	BIT(1)
 #define WDT_INT_REQ		BIT(3)
Signature · 1 line
1.8.1.5
#10 lore raw

PATCH v4 6/18 watchdog: orion: Make sure the watchdog is initially stopped

In reply to Ezequiel Garcia

Having the watchdog initially fully stopped is important to avoid any spurious watchdog triggers, in case the registers are not in its reset state.

---
 drivers/watchdog/orion_wdt.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/watchdog/orion_wdt.c +3 -0
index 6746033..2dbeee9 100644
@@ -142,6 +142,9 @@ static int orion_wdt_probe(struct platform_device *pdev)
 	orion_wdt.max_timeout = wdt_max_duration;
 	watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
 
+	/* Let's make sure the watchdog is fully stopped */
+	orion_wdt_stop(&orion_wdt);
+
 	watchdog_set_nowayout(&orion_wdt, nowayout);
 	ret = watchdog_register_device(&orion_wdt);
 	if (ret)
Signature · 1 line
1.8.1.5
#12 lore raw

PATCH v4 7/18 watchdog: orion: Handle IRQ

In reply to Ezequiel Garcia

DT-enabled where an irqchip driver for the brigde interrupt controller is available can handle the watchdog IRQ properly. Therefore, we request the interruption and add a dummy handler that merely calls panic().

This is done in order to have an initial 'ack' of the interruption, which clears the watchdog state.

Furthermore, since some platforms don't have such IRQ, this commit makes the interruption specification optional.

---
 .../devicetree/bindings/watchdog/marvel.txt        |  2 ++
 drivers/watchdog/orion_wdt.c                       | 24 +++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +2 -0
index 5dc8d30..0731fbd 100644
@@ -7,6 +7,7 @@ Required Properties:
 
 Optional properties:
 
+- interrupts	: Contains the IRQ for watchdog expiration
 - timeout-sec	: Contains the watchdog timeout in seconds
 
 Example:
@@ -14,6 +15,7 @@ Example:
 	wdt at 20300 {
 		compatible = "marvell,orion-wdt";
 		reg = <0x20300 0x28>;
+		interrupts = <3>;
 		timeout-sec = <10>;
 		status = "okay";
 	};
drivers/watchdog/orion_wdt.c +23 -1
index 2dbeee9..f5e7b17 100644
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
@@ -109,10 +110,16 @@ static struct watchdog_device orion_wdt = {
 	.min_timeout = 1,
 };
 
+static irqreturn_t orion_wdt_irq(int irq, void *devid)
+{
+	panic("Watchdog Timeout");
+	return IRQ_HANDLED;
+}
+
 static int orion_wdt_probe(struct platform_device *pdev)
 {
 	struct resource *res;
-	int ret;
+	int ret, irq;
 
 	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
@@ -145,6 +152,21 @@ static int orion_wdt_probe(struct platform_device *pdev)
 	/* Let's make sure the watchdog is fully stopped */
 	orion_wdt_stop(&orion_wdt);
 
+	/* It's important to request the IRQ once the watchdog is disabled */
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0) {
+		/*
+		 * Not all supported platforms specify an interruption for the
+		 * watchdog, so let's make it optional.
+		 */
+		ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0,
+				       pdev->name, &orion_wdt);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to request IRQ\n");
+			goto disable_clk;
+		}
+	}
+
 	watchdog_set_nowayout(&orion_wdt, nowayout);
 	ret = watchdog_register_device(&orion_wdt);
 	if (ret)
Signature · 1 line
1.8.1.5
maintainer
#13 lore raw

PATCH v4 7/18 watchdog: orion: Handle IRQ

Quoted 67 lines · Ezequiel Garcia

DT-enabled where an irqchip driver for the brigde interrupt controller is available can handle the watchdog IRQ properly. Therefore, we request the interruption and add a dummy handler that merely calls panic().

This is done in order to have an initial 'ack' of the interruption, which clears the watchdog state.

Furthermore, since some platforms don't have such IRQ, this commit makes the interruption specification optional.

---
  .../devicetree/bindings/watchdog/marvel.txt        |  2 ++
  drivers/watchdog/orion_wdt.c                       | 24 +++++++++++++++++++++-
  2 files changed, 25 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +2 -0
index 5dc8d30..0731fbd 100644
@@ -7,6 +7,7 @@ Required Properties:
 
  Optional properties:
 
+- interrupts	: Contains the IRQ for watchdog expiration
  - timeout-sec	: Contains the watchdog timeout in seconds
 
  Example:
@@ -14,6 +15,7 @@ Example:
  	wdt at 20300 {
  		compatible = "marvell,orion-wdt";
  		reg = <0x20300 0x28>;
+		interrupts = <3>;
  		timeout-sec = <10>;
  		status = "okay";
  	};
drivers/watchdog/orion_wdt.c +8 -1
index 2dbeee9..f5e7b17 100644
@@ -19,6 +19,7 @@
  #include <linux/platform_device.h>
  #include <linux/watchdog.h>
  #include <linux/init.h>
+#include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/clk.h>
  #include <linux/err.h>
@@ -109,10 +110,16 @@ static struct watchdog_device orion_wdt = {
  	.min_timeout = 1,
  };
 
+static irqreturn_t orion_wdt_irq(int irq, void *devid)
+{
+	panic("Watchdog Timeout");
+	return IRQ_HANDLED;
+}
+
  static int orion_wdt_probe(struct platform_device *pdev)
  {
  	struct resource *res;
-	int ret;
+	int ret, irq;
 
  	clk = devm_clk_get(&pdev->dev, NULL);
  	if (IS_ERR(clk)) {

drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 155

Quoted 4 lines
drivers/watchdog/orion_wdt.c +1 -0
@@ -145,6 +152,21 @@ static int orion_wdt_probe(struct platform_device *pdev)
  	/* Let's make sure the watchdog is fully stopped */
  	orion_wdt_stop(&orion_wdt);
 
+	/* It's important to request the IRQ once the watchdog is disabled */

s/once/only after/

drivers/watchdog/orion_wdt.c static int orion_wdt_probe(struct platform_device *pdev) · line 159

Quoted 4 lines
drivers/watchdog/orion_wdt.c +4 -0
+	irq = platform_get_irq(pdev, 0);
+	if (irq >= 0) {
+		/*
+		 * Not all supported platforms specify an interruption for the

s/interruption/interrupt pin/ (or interrupt)

Nitpicks, so

#14 lore raw

PATCH v4 7/18 watchdog: orion: Handle IRQ

In reply to Ezequiel Garcia

Dear Ezequiel Garcia,

Quoted 3 lines · Ezequiel Garcia

DT-enabled where an irqchip driver for the brigde interrupt controller is available can handle the watchdog IRQ properly. Therefore, we request the interruption and add a dummy handler that merely calls panic().

I don't quiite understand the first sentence of this commit log, and the commit title looks wrong. Maybe a bad copy/paste or something?

Quoted 2 lines

This is done in order to have an initial 'ack' of the interruption,

interruption -> interrupt

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#15 lore raw

PATCH v4 7/18 watchdog: orion: Handle IRQ

Quoted 10 lines · Thomas Petazzoni

Dear Ezequiel Garcia,

Quoted 3 lines · Ezequiel Garcia

DT-enabled where an irqchip driver for the brigde interrupt controller is available can handle the watchdog IRQ properly. Therefore, we request the interruption and add a dummy handler that merely calls panic().

I don't quiite understand the first sentence of this commit log, and the commit title looks wrong. Maybe a bad copy/paste or something?

Hm... yes it doesn't look right. It should read:

"DT-enabled platforms, where the irqchip driver for the brigde interrupt controller is available, can handle the watchdog IRQ properly. Therefore, we request the interrupt and add a dummy handler that merely calls panic()".

I guess we can re-phrase it be a bit more readable.

Why does th commit title looks wrong? By requesting the IRQ we are "handling it", no?

Quoted 5 lines
Quoted 2 lines

This is done in order to have an initial 'ack' of the interruption,

interruption -> interrupt

Right.

Signature · 3 lines
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
#16 lore raw

PATCH v4 7/18 watchdog: orion: Handle IRQ

Dear Ezequiel Garcia,

Quoted 9 lines · Ezequiel Garcia
Quoted 3 lines

I don't quiite understand the first sentence of this commit log, and the commit title looks wrong. Maybe a bad copy/paste or something?

Hm... yes it doesn't look right. It should read:

"DT-enabled platforms, where the irqchip driver for the brigde interrupt controller is available, can handle the watchdog IRQ properly. Therefore, we request the interrupt and add a dummy handler that merely calls panic()".

Ok.

Quoted 4 lines

I guess we can re-phrase it be a bit more readable.

Why does th commit title looks wrong? By requesting the IRQ we are "handling it", no?

Right, but it looks "truncated". Maybe something like:

watchdog: orion: handle irq to avoid having to clear BRIDGE_CLAUSE

or something like that (adjust to the actual reality, I haven't followed all the implications).

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#17 lore raw

PATCH v4 8/18 watchdog: orion: Make RSTOUT register a separate resource

In reply to Ezequiel Garcia

In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.

To prevent a compatibility break, this commit adds a fallback to a hardcoded RSTOUT address.

---
 .../devicetree/bindings/watchdog/marvel.txt        |  6 ++-
 arch/arm/mach-dove/include/mach/bridge-regs.h      |  1 +
 arch/arm/mach-kirkwood/include/mach/bridge-regs.h  |  1 +
 arch/arm/mach-mv78xx0/include/mach/bridge-regs.h   |  1 +
 arch/arm/mach-orion5x/include/mach/bridge-regs.h   |  1 +
 arch/arm/plat-orion/common.c                       | 10 +++--
 drivers/watchdog/orion_wdt.c                       | 44 +++++++++++++++++++++-
 7 files changed, 56 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +4 -2
index 0731fbd..1544fe9 100644
@@ -3,7 +3,9 @@
 Required Properties:
 
 - Compatibility : "marvell,orion-wdt"
-- reg		: Address of the timer registers
+- reg		: Should contain two entries: first one with the
+		  timer control address, second one with the
+		  rstout enable address.
 
 Optional properties:
 
@@ -14,7 +16,7 @@ Example:
 
 	wdt at 20300 {
 		compatible = "marvell,orion-wdt";
-		reg = <0x20300 0x28>;
+		reg = <0x20300 0x28>, <0x20108 0x4>;
 		interrupts = <3>;
 		timeout-sec = <10>;
 		status = "okay";
arch/arm/mach-dove/include/mach/bridge-regs.h +1 -0
index 5362df3..f4a5b34 100644
@@ -21,6 +21,7 @@
 #define  CPU_CTRL_PCIE1_LINK	0x00000008
 
 #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
 #define  SOFT_RESET_OUT_EN	0x00000004
 
 #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-kirkwood/include/mach/bridge-regs.h +1 -0
index 8b9d1c9..60f6421 100644
@@ -21,6 +21,7 @@
 #define CPU_RESET		0x00000002
 
 #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
 #define SOFT_RESET_OUT_EN	0x00000004
 
 #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +1 -0
index 5f03484..e20d6da 100644
@@ -15,6 +15,7 @@
 #define L2_WRITETHROUGH		0x00020000
 
 #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
 #define SOFT_RESET_OUT_EN	0x00000004
 
 #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-orion5x/include/mach/bridge-regs.h +1 -0
index f727d03..5766e3f 100644
@@ -18,6 +18,7 @@
 #define CPU_CTRL		(ORION5X_BRIDGE_VIRT_BASE + 0x104)
 
 #define RSTOUTn_MASK		(ORION5X_BRIDGE_VIRT_BASE + 0x108)
+#define RSTOUTn_MASK_PHYS	(ORION5X_BRIDGE_PHYS_BASE + 0x108)
 
 #define CPU_SOFT_RESET		(ORION5X_BRIDGE_VIRT_BASE + 0x10c)
 
arch/arm/plat-orion/common.c +6 -4
index c66d163..3375037 100644
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
 /*****************************************************************************
  * Watchdog
  ****************************************************************************/
-static struct resource orion_wdt_resource =
-		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
+static struct resource orion_wdt_resource[] = {
+		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+		DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
 
 static struct platform_device orion_wdt_device = {
 	.name		= "orion_wdt",
 	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &orion_wdt_resource,
+	.num_resources	= ARRAY_SIZE(orion_wdt_resource),
+	.resource	= orion_wdt_resource,
 };
 
 void __init orion_wdt_init(void)
drivers/watchdog/orion_wdt.c +42 -2

80 lines not on this page · raw message

Signature · 1 line
1.8.1.5
maintainer
#18 lore raw

PATCH v4 8/18 watchdog: orion: Make RSTOUT register a separate resource

Quoted 175 lines · Ezequiel Garcia

In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.

To prevent a compatibility break, this commit adds a fallback to a hardcoded RSTOUT address.

---
  .../devicetree/bindings/watchdog/marvel.txt        |  6 ++-
  arch/arm/mach-dove/include/mach/bridge-regs.h      |  1 +
  arch/arm/mach-kirkwood/include/mach/bridge-regs.h  |  1 +
  arch/arm/mach-mv78xx0/include/mach/bridge-regs.h   |  1 +
  arch/arm/mach-orion5x/include/mach/bridge-regs.h   |  1 +
  arch/arm/plat-orion/common.c                       | 10 +++--
  drivers/watchdog/orion_wdt.c                       | 44 +++++++++++++++++++++-
  7 files changed, 56 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +4 -2
index 0731fbd..1544fe9 100644
@@ -3,7 +3,9 @@
  Required Properties:
 
  - Compatibility : "marvell,orion-wdt"
-- reg		: Address of the timer registers
+- reg		: Should contain two entries: first one with the
+		  timer control address, second one with the
+		  rstout enable address.
 
  Optional properties:
 
@@ -14,7 +16,7 @@ Example:
 
  	wdt at 20300 {
  		compatible = "marvell,orion-wdt";
-		reg = <0x20300 0x28>;
+		reg = <0x20300 0x28>, <0x20108 0x4>;
  		interrupts = <3>;
  		timeout-sec = <10>;
  		status = "okay";
arch/arm/mach-dove/include/mach/bridge-regs.h +1 -0
index 5362df3..f4a5b34 100644
@@ -21,6 +21,7 @@
  #define  CPU_CTRL_PCIE1_LINK	0x00000008
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define  SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-kirkwood/include/mach/bridge-regs.h +1 -0
index 8b9d1c9..60f6421 100644
@@ -21,6 +21,7 @@
  #define CPU_RESET		0x00000002
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +1 -0
index 5f03484..e20d6da 100644
@@ -15,6 +15,7 @@
  #define L2_WRITETHROUGH		0x00020000
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-orion5x/include/mach/bridge-regs.h +1 -0
index f727d03..5766e3f 100644
@@ -18,6 +18,7 @@
  #define CPU_CTRL		(ORION5X_BRIDGE_VIRT_BASE + 0x104)
 
  #define RSTOUTn_MASK		(ORION5X_BRIDGE_VIRT_BASE + 0x108)
+#define RSTOUTn_MASK_PHYS	(ORION5X_BRIDGE_PHYS_BASE + 0x108)
 
  #define CPU_SOFT_RESET		(ORION5X_BRIDGE_VIRT_BASE + 0x10c)
 
arch/arm/plat-orion/common.c +6 -4
index c66d163..3375037 100644
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
  /*****************************************************************************
   * Watchdog
   ****************************************************************************/
-static struct resource orion_wdt_resource =
-		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
+static struct resource orion_wdt_resource[] = {
+		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+		DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
 
  static struct platform_device orion_wdt_device = {
  	.name		= "orion_wdt",
  	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &orion_wdt_resource,
+	.num_resources	= ARRAY_SIZE(orion_wdt_resource),
+	.resource	= orion_wdt_resource,
  };
 
  void __init orion_wdt_init(void)
drivers/watchdog/orion_wdt.c +23 -2
index f5e7b17..ba8eea9d 100644
@@ -26,6 +26,12 @@
  #include <linux/of.h>
  #include <mach/bridge-regs.h>
 
+/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
+#define ORION_RSTOUT_MASK_OFFSET	0x20108
+
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INTERNAL_REGS_MASK		~(SZ_1M - 1)
+
  /*
   * Watchdog timer block registers.
   */
@@ -44,6 +50,7 @@ static unsigned int wdt_max_duration;	/* (seconds) */
  static struct clk *clk;
  static unsigned int wdt_tclk;
  static void __iomem *wdt_reg;
+static void __iomem *wdt_rstout;
 
  static int orion_wdt_ping(struct watchdog_device *wdt_dev)
  {
@@ -64,14 +71,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
  	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
 
  	/* Enable reset on watchdog */
-	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
  	return 0;
  }
 
  static int orion_wdt_stop(struct watchdog_device *wdt_dev)
  {
  	/* Disable reset on watchdog */
-	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
+	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
 
  	/* Disable watchdog timer */
  	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
@@ -116,6 +123,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
  	return IRQ_HANDLED;
  }
 
+/*
+ * The original devicetree binding for this driver specified only
+ * one memory resource, so in order to keep DT backwards compatibility
+ * we try to fallback to a hardcoded register address, if the resource
+ * is missing from the devicetree.
+ */
+static void __iomem *try_rstout_ioremap(struct platform_device *pdev,
+					phys_addr_t internal_regs)
+{
+	struct resource *res;
+	phys_addr_t rstout;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res)

drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 149

Quoted 10 lines
drivers/watchdog/orion_wdt.c +10 -0
+		return devm_ioremap(&pdev->dev, res->start,
+				    resource_size(res));
+
+	/* This workaround works only for "orion-wdt", DT-enabled */
+	if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
+		return NULL;
+
+	rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
+
+	WARN(1, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n", rstout);

WARN seems to be a bit excessive here. Is that on purpose (sorry if that was discussed and I missed it) ?

Assuming it is on purpose

#19 lore raw

PATCH v4 8/18 watchdog: orion: Make RSTOUT register a separate resource

Quoted 189 lines · Guenter Roeck
Quoted 175 lines · Ezequiel Garcia

In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration.

To prevent a compatibility break, this commit adds a fallback to a hardcoded RSTOUT address.

---
  .../devicetree/bindings/watchdog/marvel.txt        |  6 ++-
  arch/arm/mach-dove/include/mach/bridge-regs.h      |  1 +
  arch/arm/mach-kirkwood/include/mach/bridge-regs.h  |  1 +
  arch/arm/mach-mv78xx0/include/mach/bridge-regs.h   |  1 +
  arch/arm/mach-orion5x/include/mach/bridge-regs.h   |  1 +
  arch/arm/plat-orion/common.c                       | 10 +++--
  drivers/watchdog/orion_wdt.c                       | 44 +++++++++++++++++++++-
  7 files changed, 56 insertions(+), 8 deletions(-)
Documentation/devicetree/bindings/watchdog/marvel.txt +4 -2
index 0731fbd..1544fe9 100644
@@ -3,7 +3,9 @@
  Required Properties:
 
  - Compatibility : "marvell,orion-wdt"
-- reg		: Address of the timer registers
+- reg		: Should contain two entries: first one with the
+		  timer control address, second one with the
+		  rstout enable address.
 
  Optional properties:
 
@@ -14,7 +16,7 @@ Example:
 
  	wdt at 20300 {
  		compatible = "marvell,orion-wdt";
-		reg = <0x20300 0x28>;
+		reg = <0x20300 0x28>, <0x20108 0x4>;
  		interrupts = <3>;
  		timeout-sec = <10>;
  		status = "okay";
arch/arm/mach-dove/include/mach/bridge-regs.h +1 -0
index 5362df3..f4a5b34 100644
@@ -21,6 +21,7 @@
  #define  CPU_CTRL_PCIE1_LINK	0x00000008
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define  SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-kirkwood/include/mach/bridge-regs.h +1 -0
index 8b9d1c9..60f6421 100644
@@ -21,6 +21,7 @@
  #define CPU_RESET		0x00000002
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +1 -0
index 5f03484..e20d6da 100644
@@ -15,6 +15,7 @@
  #define L2_WRITETHROUGH		0x00020000
 
  #define RSTOUTn_MASK		(BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS	(BRIDGE_PHYS_BASE + 0x0108)
  #define SOFT_RESET_OUT_EN	0x00000004
 
  #define SYSTEM_SOFT_RESET	(BRIDGE_VIRT_BASE + 0x010c)
arch/arm/mach-orion5x/include/mach/bridge-regs.h +1 -0
index f727d03..5766e3f 100644
@@ -18,6 +18,7 @@
  #define CPU_CTRL		(ORION5X_BRIDGE_VIRT_BASE + 0x104)
 
  #define RSTOUTn_MASK		(ORION5X_BRIDGE_VIRT_BASE + 0x108)
+#define RSTOUTn_MASK_PHYS	(ORION5X_BRIDGE_PHYS_BASE + 0x108)
 
  #define CPU_SOFT_RESET		(ORION5X_BRIDGE_VIRT_BASE + 0x10c)
 
arch/arm/plat-orion/common.c +6 -4
index c66d163..3375037 100644
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
  /*****************************************************************************
   * Watchdog
   ****************************************************************************/
-static struct resource orion_wdt_resource =
-		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
+static struct resource orion_wdt_resource[] = {
+		DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+		DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
 
  static struct platform_device orion_wdt_device = {
  	.name		= "orion_wdt",
  	.id		= -1,
-	.num_resources	= 1,
-	.resource	= &orion_wdt_resource,
+	.num_resources	= ARRAY_SIZE(orion_wdt_resource),
+	.resource	= orion_wdt_resource,
  };
 
  void __init orion_wdt_init(void)
drivers/watchdog/orion_wdt.c +23 -2
index f5e7b17..ba8eea9d 100644
@@ -26,6 +26,12 @@
  #include <linux/of.h>
  #include <mach/bridge-regs.h>
 
+/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
+#define ORION_RSTOUT_MASK_OFFSET	0x20108
+
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INTERNAL_REGS_MASK		~(SZ_1M - 1)
+
  /*
   * Watchdog timer block registers.
   */
@@ -44,6 +50,7 @@ static unsigned int wdt_max_duration;	/* (seconds) */
  static struct clk *clk;
  static unsigned int wdt_tclk;
  static void __iomem *wdt_reg;
+static void __iomem *wdt_rstout;
 
  static int orion_wdt_ping(struct watchdog_device *wdt_dev)
  {
@@ -64,14 +71,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
  	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
 
  	/* Enable reset on watchdog */
-	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
  	return 0;
  }
 
  static int orion_wdt_stop(struct watchdog_device *wdt_dev)
  {
  	/* Disable reset on watchdog */
-	atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
+	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
 
  	/* Disable watchdog timer */
  	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
@@ -116,6 +123,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
  	return IRQ_HANDLED;
  }
 
+/*
+ * The original devicetree binding for this driver specified only
+ * one memory resource, so in order to keep DT backwards compatibility
+ * we try to fallback to a hardcoded register address, if the resource
+ * is missing from the devicetree.
+ */
+static void __iomem *try_rstout_ioremap(struct platform_device *pdev,
+					phys_addr_t internal_regs)
+{
+	struct resource *res;
+	phys_addr_t rstout;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (res)

drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 149

Quoted 10 lines
drivers/watchdog/orion_wdt.c +10 -0
+		return devm_ioremap(&pdev->dev, res->start,
+				    resource_size(res));
+
+	/* This workaround works only for "orion-wdt", DT-enabled */
+	if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
+		return NULL;
+
+	rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
+
+	WARN(1, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n", rstout);

WARN seems to be a bit excessive here. Is that on purpose (sorry if that was discussed and I missed it) ?

Quoted 4 lines

Assuming it is on purpose

Yes, it's on purpose. We want users to notice this and be aware they have a broken dtb (hence the sign firmware bug).

Signature · 3 lines
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
#20 lore raw

PATCH v4 8/18 watchdog: orion: Make RSTOUT register a separate resource

In reply to Ezequiel Garcia

Dear Ezequiel Garcia,

drivers/watchdog/orion_wdt.c line 33

Quoted 5 lines · Ezequiel Garcia
drivers/watchdog/orion_wdt.c +5 -0
+/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
+#define ORION_RSTOUT_MASK_OFFSET	0x20108
+
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INTERNAL_REGS_MASK		~(SZ_1M - 1)

I'm not a big fan of hardcoding the internal register window size in a driver. I would have preferred to have used the offset between the watchdog registers and the rstout register, but since this one is *before* the watchdog registers, it would have to be a negative offset. Not sure how to handle this.

drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 133

Quoted 8 lines
drivers/watchdog/orion_wdt.c +8 -0
+/*
+ * The original devicetree binding for this driver specified only
+ * one memory resource, so in order to keep DT backwards compatibility
+ * we try to fallback to a hardcoded register address, if the resource
+ * is missing from the devicetree.
+ */
+static void __iomem *try_rstout_ioremap(struct platform_device *pdev,
+					phys_addr_t internal_regs)

Why is it called "try" ? It actually does the mapping. So I would prefer the function to be named:

orion_wdt_ioremap_rstout()

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#21 lore raw

PATCH v4 8/18 watchdog: orion: Make RSTOUT register a separate resource

On Sun, Jan 26, 2014 at 09:17:53AM +0100, Thomas Petazzoni wrote:
[..]

Quoted 12 lines

drivers/watchdog/orion_wdt.c static irqreturn_t orion_wdt_irq(int irq, void *devid) · line 133

Quoted 8 lines
drivers/watchdog/orion_wdt.c +8 -0
+/*
+ * The original devicetree binding for this driver specified only
+ * one memory resource, so in order to keep DT backwards compatibility
+ * we try to fallback to a hardcoded register address, if the resource
+ * is missing from the devicetree.
+ */
+static void __iomem *try_rstout_ioremap(struct platform_device *pdev,
+					phys_addr_t internal_regs)

Why is it called "try" ? It actually does the mapping. So I would prefer the function to be named:

Quoted 2 lines

orion_wdt_ioremap_rstout()

Ah, yes. This is a left over from the previous attempt.

Signature · 3 lines
Ezequiel Garc?a, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
#22 lore raw

PATCH v4 9/18 watchdog: orion: Remove unneeded BRIDGE_CAUSE clear

In reply to Ezequiel Garcia

After adding the IRQ request, the BRIDGE_CAUSE bit should be cleared by the bridge interrupt controller. There's no longer a need to do it in the watchdog driver, so we can simply remove it.

---
 drivers/watchdog/orion_wdt.c | 5 -----
 1 file changed, 5 deletions(-)
drivers/watchdog/orion_wdt.c +0 -5
index ba8eea9d..80f6a77 100644
@@ -24,7 +24,6 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/of.h>
-#include <mach/bridge-regs.h>
 
 /* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
 #define ORION_RSTOUT_MASK_OFFSET	0x20108
@@ -42,7 +41,6 @@
 #define WDT_MAX_CYCLE_COUNT	0xffffffff
 
 #define WDT_RESET_OUT_EN	BIT(1)
-#define WDT_INT_REQ		BIT(3)
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
@@ -64,9 +62,6 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
 	/* Set watchdog duration */
 	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
 
-	/* Clear watchdog timer interrupt */
-	writel(~WDT_INT_REQ, BRIDGE_CAUSE);
-
 	/* Enable watchdog timer */
 	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
 
Signature · 1 line
1.8.1.5
#24 lore raw

PATCH v4 10/18 watchdog: orion: Introduce an orion_watchdog device structure

In reply to Ezequiel Garcia

In order to prepare to support multiple compatible-strings, this commit adds a device structure to hold the driver's state.

---
 drivers/watchdog/orion_wdt.c | 104 ++++++++++++++++++++++++++-----------------
 1 file changed, 64 insertions(+), 40 deletions(-)
drivers/watchdog/orion_wdt.c +64 -40
index 80f6a77..96dba41 100644
@@ -44,45 +44,56 @@
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
-static unsigned int wdt_max_duration;	/* (seconds) */
-static struct clk *clk;
-static unsigned int wdt_tclk;
-static void __iomem *wdt_reg;
-static void __iomem *wdt_rstout;
+
+struct orion_watchdog {
+	struct watchdog_device wdt;
+	void __iomem *reg;
+	void __iomem *rstout;
+	unsigned long clk_rate;
+	struct clk *clk;
+};
 
 static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 {
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 	/* Reload watchdog duration */
-	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+	writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
 	return 0;
 }
 
 static int orion_wdt_start(struct watchdog_device *wdt_dev)
 {
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
 	/* Set watchdog duration */
-	writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+	writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
 
 	/* Enable watchdog timer */
-	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
+	atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
 
 	/* Enable reset on watchdog */
-	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+	atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+
 	return 0;
 }
 
 static int orion_wdt_stop(struct watchdog_device *wdt_dev)
 {
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
 	/* Disable reset on watchdog */
-	atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
+	atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
 
 	/* Disable watchdog timer */
-	atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
+	atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+
 	return 0;
 }
 
 static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
 {
-	return readl(wdt_reg + WDT_VAL) / wdt_tclk;
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+	return readl(dev->reg + WDT_VAL) / dev->clk_rate;
 }
 
 static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -106,12 +117,6 @@ static const struct watchdog_ops orion_wdt_ops = {
 	.get_timeleft = orion_wdt_get_timeleft,
 };
 
-static struct watchdog_device orion_wdt = {
-	.info = &orion_wdt_info,
-	.ops = &orion_wdt_ops,
-	.min_timeout = 1,
-};
-
 static irqreturn_t orion_wdt_irq(int irq, void *devid)
 {
 	panic("Watchdog Timeout");
@@ -147,18 +152,29 @@ static void __iomem * try_rstout_ioremap(struct platform_device *pdev,
 
 static int orion_wdt_probe(struct platform_device *pdev)
 {
+	struct orion_watchdog *dev;
+	unsigned int wdt_max_duration;	/* (seconds) */
 	struct resource *res;
 	int ret, irq;
 
-	clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(clk)) {
+	dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
+			   GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->wdt.info = &orion_wdt_info;
+	dev->wdt.ops = &orion_wdt_ops;
+	dev->wdt.min_timeout = 1;
+
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
 		dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
-		return PTR_ERR(clk);
+		return PTR_ERR(dev->clk);
 	}
-	ret = clk_prepare_enable(clk);
+	ret = clk_prepare_enable(dev->clk);
 	if (ret)
 		return ret;
-	wdt_tclk = clk_get_rate(clk);
+	dev->clk_rate = clk_get_rate(dev->clk);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -166,26 +182,30 @@ static int orion_wdt_probe(struct platform_device *pdev)
 		goto disable_clk;
 	}
 
-	wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!wdt_reg) {
+	dev->reg = devm_ioremap(&pdev->dev, res->start,
+			       resource_size(res));
+	if (!dev->reg) {
 		ret = -ENOMEM;
 		goto disable_clk;
 	}
 
-	wdt_rstout = try_rstout_ioremap(pdev, res->start & INTERNAL_REGS_MASK);
-	if (!wdt_rstout) {
+	dev->rstout = try_rstout_ioremap(pdev, res->start & INTERNAL_REGS_MASK);
+	if (!dev->rstout) {
 		ret = -ENODEV;
 		goto disable_clk;
 	}
 
-	wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+	wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate;
+
+	dev->wdt.timeout = wdt_max_duration;
+	dev->wdt.max_timeout = wdt_max_duration;
+	watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev);
 
-	orion_wdt.timeout = wdt_max_duration;
-	orion_wdt.max_timeout = wdt_max_duration;
-	watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
+	platform_set_drvdata(pdev, &dev->wdt);
+	watchdog_set_drvdata(&dev->wdt, dev);
 
 	/* Let's make sure the watchdog is fully stopped */
-	orion_wdt_stop(&orion_wdt);
+	orion_wdt_stop(&dev->wdt);
 
 	/* It's important to request the IRQ once the watchdog is disabled */
 	irq = platform_get_irq(pdev, 0);
@@ -195,37 +215,41 @@ static int orion_wdt_probe(struct platform_device *pdev)
 		 * watchdog, so let's make it optional.
 		 */
 		ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0,
-				       pdev->name, &orion_wdt);
+				       pdev->name, dev);
 		if (ret < 0) {
 			dev_err(&pdev->dev, "failed to request IRQ\n");
 			goto disable_clk;
 		}
 	}
 
-	watchdog_set_nowayout(&orion_wdt, nowayout);
-	ret = watchdog_register_device(&orion_wdt);
+	watchdog_set_nowayout(&dev->wdt, nowayout);
+	ret = watchdog_register_device(&dev->wdt);
 	if (ret)
 		goto disable_clk;
 
 	pr_info("Initial timeout %d sec%s\n",
-		orion_wdt.timeout, nowayout ? ", nowayout" : "");
+		dev->wdt.timeout, nowayout ? ", nowayout" : "");
 	return 0;
 
 disable_clk:
-	clk_disable_unprepare(clk);
+	clk_disable_unprepare(dev->clk);
 	return ret;
 }
 
 static int orion_wdt_remove(struct platform_device *pdev)
 {
-	watchdog_unregister_device(&orion_wdt);
-	clk_disable_unprepare(clk);
+	struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+	watchdog_unregister_device(wdt_dev);
+	clk_disable_unprepare(dev->clk);
 	return 0;
 }
 
 static void orion_wdt_shutdown(struct platform_device *pdev)
 {
-	orion_wdt_stop(&orion_wdt);
+	struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+	orion_wdt_stop(wdt_dev);
 }
 
 static const struct of_device_id orion_wdt_of_match_table[] = {
Signature · 1 line
1.8.1.5
#26 lore raw

PATCH v4 11/18 watchdog: orion: Introduce per-compatible of_device_id data

In reply to Ezequiel Garcia

This commit adds an orion_watchdog_data structure to hold compatible-data information. This allows to remove the driver-wide definition and to be able to add support for multiple compatible-strings in the future.

---
 drivers/watchdog/orion_wdt.c | 58 +++++++++++++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 17 deletions(-)
drivers/watchdog/orion_wdt.c +41 -17
index 96dba41..c978bcd 100644
@@ -24,6 +24,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 /* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
 #define ORION_RSTOUT_MASK_OFFSET	0x20108
@@ -35,29 +36,33 @@
  * Watchdog timer block registers.
  */
 #define TIMER_CTRL		0x0000
-#define WDT_EN			0x0010
-#define WDT_VAL			0x0024
 
 #define WDT_MAX_CYCLE_COUNT	0xffffffff
 
-#define WDT_RESET_OUT_EN	BIT(1)
-
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
 
+struct orion_watchdog_data {
+	int wdt_counter_offset;
+	int wdt_enable_bit;
+	int rstout_enable_bit;
+};
+
 struct orion_watchdog {
 	struct watchdog_device wdt;
 	void __iomem *reg;
 	void __iomem *rstout;
 	unsigned long clk_rate;
 	struct clk *clk;
+	const struct orion_watchdog_data *data;
 };
 
 static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 	/* Reload watchdog duration */
-	writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+	writel(dev->clk_rate * wdt_dev->timeout,
+	       dev->reg + dev->data->wdt_counter_offset);
 	return 0;
 }
 
@@ -66,13 +71,16 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 
 	/* Set watchdog duration */
-	writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+	writel(dev->clk_rate * wdt_dev->timeout,
+	       dev->reg + dev->data->wdt_counter_offset);
 
 	/* Enable watchdog timer */
-	atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
+	atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+						dev->data->wdt_enable_bit);
 
 	/* Enable reset on watchdog */
-	atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+	atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+				      dev->data->rstout_enable_bit);
 
 	return 0;
 }
@@ -82,10 +90,10 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 
 	/* Disable reset on watchdog */
-	atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
+	atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 0);
 
 	/* Disable watchdog timer */
-	atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+	atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
 
 	return 0;
 }
@@ -93,7 +101,7 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
 static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
-	return readl(dev->reg + WDT_VAL) / dev->clk_rate;
+	return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate;
 }
 
 static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -150,9 +158,25 @@ static void __iomem * try_rstout_ioremap(struct platform_device *pdev,
 	return devm_ioremap(&pdev->dev, rstout, 0x4);
 }
 
+static const struct orion_watchdog_data orion_data = {
+	.rstout_enable_bit = BIT(1),
+	.wdt_enable_bit = BIT(4),
+	.wdt_counter_offset = 0x24,
+};
+
+static const struct of_device_id orion_wdt_of_match_table[] = {
+	{
+		.compatible = "marvell,orion-wdt",
+		.data = &orion_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
+
 static int orion_wdt_probe(struct platform_device *pdev)
 {
 	struct orion_watchdog *dev;
+	const struct of_device_id *match;
 	unsigned int wdt_max_duration;	/* (seconds) */
 	struct resource *res;
 	int ret, irq;
@@ -162,9 +186,15 @@ static int orion_wdt_probe(struct platform_device *pdev)
 	if (!dev)
 		return -ENOMEM;
 
+	match = of_match_device(orion_wdt_of_match_table, &pdev->dev);
+	if (!match)
+		/* Default legacy match */
+		match = &orion_wdt_of_match_table[0];
+
 	dev->wdt.info = &orion_wdt_info;
 	dev->wdt.ops = &orion_wdt_ops;
 	dev->wdt.min_timeout = 1;
+	dev->data = match->data;
 
 	dev->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dev->clk)) {
@@ -252,12 +282,6 @@ static void orion_wdt_shutdown(struct platform_device *pdev)
 	orion_wdt_stop(wdt_dev);
 }
 
-static const struct of_device_id orion_wdt_of_match_table[] = {
-	{ .compatible = "marvell,orion-wdt", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
-
 static struct platform_driver orion_wdt_driver = {
 	.probe		= orion_wdt_probe,
 	.remove		= orion_wdt_remove,
Signature · 1 line
1.8.1.5
maintainer
#27 lore raw

PATCH v4 11/18 watchdog: orion: Introduce per-compatible of_device_id data

Quoted 5 lines · Ezequiel Garcia

This commit adds an orion_watchdog_data structure to hold compatible-data information. This allows to remove the driver-wide definition and to be able to add support for multiple compatible-strings in the future.

#28 lore raw

PATCH v4 12/18 watchdog: orion: Add per-compatible clock initialization

In reply to Ezequiel Garcia

Following the introduction of the compatible-data field, it's now possible to further abstract the clock initialization. This will allow to support SoC with a different clock setup.

---
 drivers/watchdog/orion_wdt.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)
drivers/watchdog/orion_wdt.c +25 -8
index c978bcd..5ce5d48 100644
@@ -42,10 +42,14 @@
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
 
+struct orion_watchdog;
+
 struct orion_watchdog_data {
 	int wdt_counter_offset;
 	int wdt_enable_bit;
 	int rstout_enable_bit;
+	int (*clock_init) (struct platform_device *,
+			   struct orion_watchdog *);
 };
 
 struct orion_watchdog {
@@ -57,6 +61,22 @@ struct orion_watchdog {
 	const struct orion_watchdog_data *data;
 };
 
+static int orion_wdt_clock_init(struct platform_device *pdev,
+				struct orion_watchdog *dev)
+{
+	int ret;
+
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk))
+		return PTR_ERR(dev->clk);
+	ret = clk_prepare_enable(dev->clk);
+	if (ret)
+		return ret;
+
+	dev->clk_rate = clk_get_rate(dev->clk);
+	return 0;
+}
+
 static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -162,6 +182,7 @@ static const struct orion_watchdog_data orion_data = {
 	.rstout_enable_bit = BIT(1),
 	.wdt_enable_bit = BIT(4),
 	.wdt_counter_offset = 0x24,
+	.clock_init = orion_wdt_clock_init,
 };
 
 static const struct of_device_id orion_wdt_of_match_table[] = {
@@ -196,15 +217,11 @@ static int orion_wdt_probe(struct platform_device *pdev)
 	dev->wdt.min_timeout = 1;
 	dev->data = match->data;
 
-	dev->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(dev->clk)) {
-		dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
-		return PTR_ERR(dev->clk);
-	}
-	ret = clk_prepare_enable(dev->clk);
-	if (ret)
+	ret = dev->data->clock_init(pdev, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot initialize clock\n");
 		return ret;
-	dev->clk_rate = clk_get_rate(dev->clk);
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
Signature · 1 line
1.8.1.5
#30 lore raw

PATCH v4 13/18 watchdog: orion: Add per-compatible watchdog start implementation

In reply to Ezequiel Garcia

To handle differences between SoCs this commit adds per-compatible string start() function for the watchdog kick-off. This is preparation work and makes no functionality changes to the current driver.

---
 drivers/watchdog/orion_wdt.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/watchdog/orion_wdt.c +11 -1
index 5ce5d48..471d6d9 100644
@@ -50,6 +50,7 @@ struct orion_watchdog_data {
 	int rstout_enable_bit;
 	int (*clock_init) (struct platform_device *,
 			   struct orion_watchdog *);
+	int (*start) (struct watchdog_device *);
 };
 
 struct orion_watchdog {
@@ -86,7 +87,7 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 	return 0;
 }
 
-static int orion_wdt_start(struct watchdog_device *wdt_dev)
+static int orion_start(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 
@@ -105,6 +106,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
 	return 0;
 }
 
+static int orion_wdt_start(struct watchdog_device *wdt_dev)
+{
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+	/* There are some per-SoC quirks to handle */
+	return dev->data->start(wdt_dev);
+}
+
 static int orion_wdt_stop(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -183,6 +192,7 @@ static const struct orion_watchdog_data orion_data = {
 	.wdt_enable_bit = BIT(4),
 	.wdt_counter_offset = 0x24,
 	.clock_init = orion_wdt_clock_init,
+	.start = orion_start,
 };
 
 static const struct of_device_id orion_wdt_of_match_table[] = {
Signature · 1 line
1.8.1.5
maintainer
#31 lore raw

PATCH v4 13/18 watchdog: orion: Add per-compatible watchdog start implementation

Quoted 5 lines · Ezequiel Garcia

To handle differences between SoCs this commit adds per-compatible string start() function for the watchdog kick-off. This is preparation work and makes no functionality changes to the current driver.

#32 lore raw

PATCH v4 14/18 watchdog: orion: Add support for Armada 370 and Armada XP SoC

In reply to Ezequiel Garcia

Using the added infrastructure for handling SoC differences, this commit adds support for the watchdog controller available in Armada 370 and Armada XP SoCs.

---
 drivers/watchdog/orion_wdt.c | 94 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)
drivers/watchdog/orion_wdt.c +94 -0
index 471d6d9..90e8b53 100644
@@ -36,9 +36,17 @@
  * Watchdog timer block registers.
  */
 #define TIMER_CTRL		0x0000
+#define TIMER_A370_STATUS	0x04
 
 #define WDT_MAX_CYCLE_COUNT	0xffffffff
 
+#define WDT_A370_RATIO_MASK(v)	((v) << 16)
+#define WDT_A370_RATIO_SHIFT	5
+#define WDT_A370_RATIO		(1 << WDT_A370_RATIO_SHIFT)
+
+#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
+#define WDT_A370_EXPIRED	BIT(31)
+
 static bool nowayout = WATCHDOG_NOWAYOUT;
 static int heartbeat = -1;		/* module parameter (seconds) */
 
@@ -78,6 +86,48 @@ static int orion_wdt_clock_init(struct platform_device *pdev,
 	return 0;
 }
 
+static int armada370_wdt_clock_init(struct platform_device *pdev,
+				    struct orion_watchdog *dev)
+{
+	int ret;
+
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk))
+		return PTR_ERR(dev->clk);
+	ret = clk_prepare_enable(dev->clk);
+	if (ret)
+		return ret;
+
+	/* Setup watchdog input clock */
+	atomic_io_modify(dev->reg + TIMER_CTRL,
+			WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
+			WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
+
+	dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
+	return 0;
+}
+
+static int armadaxp_wdt_clock_init(struct platform_device *pdev,
+				   struct orion_watchdog *dev)
+{
+	int ret;
+
+	dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
+	if (IS_ERR(dev->clk))
+		return PTR_ERR(dev->clk);
+	ret = clk_prepare_enable(dev->clk);
+	if (ret)
+		return ret;
+
+	/* Enable the fixed watchdog clock input */
+	atomic_io_modify(dev->reg + TIMER_CTRL,
+			 WDT_AXP_FIXED_ENABLE_BIT,
+			 WDT_AXP_FIXED_ENABLE_BIT);
+
+	dev->clk_rate = clk_get_rate(dev->clk);
+	return 0;
+}
+
 static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -87,6 +137,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
 	return 0;
 }
 
+static int armada370_start(struct watchdog_device *wdt_dev)
+{
+	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+	/* Set watchdog duration */
+	writel(dev->clk_rate * wdt_dev->timeout,
+	       dev->reg + dev->data->wdt_counter_offset);
+
+	/* Clear the watchdog expiration bit */
+	atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
+
+	/* Enable watchdog timer */
+	atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+						dev->data->wdt_enable_bit);
+
+	atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+				      dev->data->rstout_enable_bit);
+	return 0;
+}
+
 static int orion_start(struct watchdog_device *wdt_dev)
 {
 	struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -195,11 +265,35 @@ static const struct orion_watchdog_data orion_data = {
 	.start = orion_start,
 };
 
+static const struct orion_watchdog_data armada370_data = {
+	.rstout_enable_bit = BIT(8),
+	.wdt_enable_bit = BIT(8),
+	.wdt_counter_offset = 0x34,
+	.clock_init = armada370_wdt_clock_init,
+	.start = armada370_start,
+};
+
+static const struct orion_watchdog_data armadaxp_data = {
+	.rstout_enable_bit = BIT(8),
+	.wdt_enable_bit = BIT(8),
+	.wdt_counter_offset = 0x34,
+	.clock_init = armadaxp_wdt_clock_init,
+	.start = armada370_start,
+};
+
 static const struct of_device_id orion_wdt_of_match_table[] = {
 	{
 		.compatible = "marvell,orion-wdt",
 		.data = &orion_data,
 	},
+	{
+		.compatible = "marvell,armada-370-wdt",
+		.data = &armada370_data,
+	},
+	{
+		.compatible = "marvell,armada-xp-wdt",
+		.data = &armadaxp_data,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
Signature · 1 line
1.8.1.5
#34 lore raw

PATCH v4 15/18 ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree

In reply to Ezequiel Garcia

Add the DT nodes to enable watchdog support available in Armada 370 and Armada XP SoCs.

---
 arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++++
 arch/arm/boot/dts/armada-370.dtsi    | 5 +++++
 arch/arm/boot/dts/armada-xp.dtsi     | 6 ++++++
 3 files changed, 15 insertions(+)
arch/arm/boot/dts/armada-370-xp.dtsi +4 -0
index 7f10f62..96e0389 100644
@@ -151,6 +151,10 @@
 				interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
 			};
 
+			watchdog at 20300 {
+				reg = <0x20300 0x34>, <0x20704 0x4>;
+			};
+
 			sata at a0000 {
 				compatible = "marvell,orion-sata";
 				reg = <0xa0000 0x5000>;
arch/arm/boot/dts/armada-370.dtsi +5 -0
index 7a4b82e..aebed9e 100644
@@ -168,6 +168,11 @@
 				clocks = <&coreclk 2>;
 			};
 
+			watchdog at 20300 {
+				compatible = "marvell,armada-370-wdt";
+				clocks = <&coreclk 2>;
+			};
+
 			coreclk: mvebu-sar at 18230 {
 				compatible = "marvell,armada-370-core-clock";
 				reg = <0x18230 0x08>;
arch/arm/boot/dts/armada-xp.dtsi +6 -0
index 281c644..8c6c06c 100644
@@ -74,6 +74,12 @@
 				clock-names = "nbclk", "fixed";
 			};
 
+			watchdog at 20300 {
+				compatible = "marvell,armada-xp-wdt";
+				clocks = <&coreclk 2>, <&refclk>;
+				clock-names = "nbclk", "fixed";
+			};
+
 			coreclk: mvebu-sar at 18230 {
 				compatible = "marvell,armada-xp-core-clock";
 				reg = <0x18230 0x08>;
Signature · 1 line
1.8.1.5
#35 lore raw

PATCH v4 16/18 ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree

In reply to Ezequiel Garcia

In order to support multiplatform builds the watchdog devicetree binding was modified and now the 'reg' property is specified to need two entries. This commit adds the second entry as-per the new specification.

---
 arch/arm/boot/dts/kirkwood.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/boot/dts/kirkwood.dtsi +1 -1
index 8b73c80..80a56b0 100644
@@ -165,7 +165,7 @@
 
 		wdt: watchdog-timer at 20300 {
 			compatible = "marvell,orion-wdt";
-			reg = <0x20300 0x28>;
+			reg = <0x20300 0x28>, <0x20108 0x4>;
 			interrupt-parent = <&bridge_intc>;
 			interrupts = <3>;
 			clocks = <&gate_clk 7>;
Signature · 1 line
1.8.1.5
#36 lore raw

PATCH v4 17/18 watchdog: orion: Enable the build on ARCH_MVEBU

In reply to Ezequiel Garcia

After adding support for Armada 370/XP SoC let's enable the build on these platforms.

---
 drivers/watchdog/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/watchdog/Kconfig +1 -1
index 5be6e91..8b79012 100644
@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG
 
 config ORION_WATCHDOG
 	tristate "Orion watchdog"
-	depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
+	depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU
 	select WATCHDOG_CORE
 	help
 	  Say Y here if to include support for the watchdog timer
Signature · 1 line
1.8.1.5
#37 lore raw

PATCH v4 18/18 ARM: mvebu: Enable watchdog support in defconfig

In reply to Ezequiel Garcia

Now that we have proper support for Armada 370/XP watchdog let's enable it in the defconfig.

---
 arch/arm/configs/mvebu_defconfig | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/configs/mvebu_defconfig +2 -0
index 594d706..84ec924 100644
@@ -60,6 +60,8 @@ CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_THERMAL=y
 CONFIG_ARMADA_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_ORION_WATCHDOG=y
 CONFIG_USB_SUPPORT=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
Signature · 1 line
1.8.1.5
#39 lore raw

v4 cover Armada 370/XP watchdog support

Quoted 8 lines · Sebastian Hesselbarth
Quoted 3 lines · Ezequiel Garcia

After some lengthy discussion on the [v2] and [v3] patchsets, here's a new round. I hope I haven't forgotten anything.

on Dove.

Great, thanks a lot!

Signature · 7 lines
Ezequiel García, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#40 lore raw

v4 cover Armada 370/XP watchdog support

In reply to Sebastian Hesselbarth

Hi Sebastian,

Quoted 7 lines · Sebastian Hesselbarth
Quoted 3 lines · Ezequiel Garcia

After some lengthy discussion on the [v2] and [v3] patchsets, here's a new round. I hope I haven't forgotten anything.

As currently Dove doesn't have watchdog support in the devicetree, I've added it to the v5 (which I'll submit now) with your Tested-by on all the patchset.

Thanks a lot for the test,

Signature · 7 lines
Ezequiel García, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#41 lore raw

v4 cover Armada 370/XP watchdog support

In reply to Ezequiel Garcia

On Wed, Jan 22, 2014 at 08:04:57PM -0300, Ezequiel Garcia wrote:
[..]

Quoted 15 lines

Thanks to everyone who has helped reviewing the previous sets! It's certainly easier to move forward when you get so much nice feedback...

Ezequiel Garcia (18):
ARM: Introduce atomic MMIO modify
clocksource: orion: Use atomic access for shared registers
watchdog: orion: Add clock error handling
watchdog: orion: Use atomic access for shared registers
watchdog: orion: Remove unused macros
watchdog: orion: Make sure the watchdog is initially stopped
watchdog: orion: Handle IRQ
watchdog: orion: Make RSTOUT register a separate resource
watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
watchdog: orion: Introduce an orion_watchdog device structure

Quoted 9 lines

watchdog: orion: Introduce per-compatible of_device_id data
watchdog: orion: Add per-compatible clock initialization
watchdog: orion: Add per-compatible watchdog start implementation
watchdog: orion: Add support for Armada 370 and Armada XP SoC
ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
watchdog: orion: Enable the build on ARCH_MVEBU
ARM: mvebu: Enable watchdog support in defconfig

[..]

If at all possible I'd like to get some acks or reviews from the people that has followed, reviewed and discussed this series with me.

Jason, Arnd, Andrew?

Signature · 7 lines
Ezequiel García, Free Electrons
Embedded Linux, Kernel and Android Engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html