diff options
author | Ezequiel Garcia <ezequiel.garcia@free-electrons.com> | 2014-02-10 20:00:25 -0300 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-02-22 03:43:23 +0000 |
commit | 868eb61602d9c020fc9e21b42f3ccd301b36b94d (patch) | |
tree | b26c070e5d546b2c4e18f87ec4d1f00237b6331c /drivers/watchdog | |
parent | e97662e1e28da0da0702db213931d8f9a580970a (diff) | |
download | talos-op-linux-868eb61602d9c020fc9e21b42f3ccd301b36b94d.tar.gz talos-op-linux-868eb61602d9c020fc9e21b42f3ccd301b36b94d.zip |
watchdog: orion: Make RSTOUT register a separate resource
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.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Tested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
Acked-by: Wim Van Sebroeck <wim@iguana.be>
Tested-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/orion_wdt.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index b7067acd43a2..6061b838d396 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -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); @@ -82,7 +89,7 @@ static int orion_wdt_enabled(void) { bool enabled, running; - enabled = readl(RSTOUTn_MASK) & WDT_RESET_OUT_EN; + enabled = readl(wdt_rstout) & WDT_RESET_OUT_EN; running = readl(wdt_reg + TIMER_CTRL) & WDT_EN; return enabled && running; @@ -126,6 +133,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 *orion_wdt_ioremap_rstout(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) + 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); + return devm_ioremap(&pdev->dev, rstout, 0x4); +} + static int orion_wdt_probe(struct platform_device *pdev) { struct resource *res; @@ -153,6 +187,13 @@ static int orion_wdt_probe(struct platform_device *pdev) goto disable_clk; } + wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start & + INTERNAL_REGS_MASK); + if (!wdt_rstout) { + ret = -ENODEV; + goto disable_clk; + } + wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; orion_wdt.timeout = wdt_max_duration; |