[09/11] watchdog: ftwdt010/aspeed: Merge Aspeed into FTWDT010

Message ID 20170812184318.10144-10-linus.walleij@linaro.org
State New
Headers show
Series
  • watchdog: Consolidate FTWDT010 derivatives
Related show

Commit Message

Linus Walleij Aug. 12, 2017, 6:43 p.m.
These two drivers is for the almost the same hardware,
the only differences are:
- The Aspeed IP block has been hacked to use a different
  magic value.
- The Aspeed has hard-wired 1MHz to the EXTCLK and
  apparently even disabled the use of PCLK for clocking
  the block on AST2500.

Delete the old Aspeed driver and augment the FTWDT010 to
probe on this platform too. Select the driver by default
for ARCH_ASPEED to make a smooth transition of the platform.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

---
 drivers/watchdog/Kconfig        |  18 +---
 drivers/watchdog/Makefile       |   1 -
 drivers/watchdog/aspeed_wdt.c   | 200 ----------------------------------------
 drivers/watchdog/ftwdt010_wdt.c |  25 ++++-
 4 files changed, 25 insertions(+), 219 deletions(-)
 delete mode 100644 drivers/watchdog/aspeed_wdt.c

-- 
2.13.4

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Guenter Roeck Aug. 14, 2017, 3:04 p.m. | #1
On Sat, Aug 12, 2017 at 08:43:16PM +0200, Linus Walleij wrote:
> These two drivers is for the almost the same hardware,

> the only differences are:

> - The Aspeed IP block has been hacked to use a different

>   magic value.

> - The Aspeed has hard-wired 1MHz to the EXTCLK and

>   apparently even disabled the use of PCLK for clocking

>   the block on AST2500.

> 

Confused. I thought the ast2500 is an EC. Am I missing something ?

Guenter

> Delete the old Aspeed driver and augment the FTWDT010 to

> probe on this platform too. Select the driver by default

> for ARCH_ASPEED to make a smooth transition of the platform.

> 

> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

> ---

>  drivers/watchdog/Kconfig        |  18 +---

>  drivers/watchdog/Makefile       |   1 -

>  drivers/watchdog/aspeed_wdt.c   | 200 ----------------------------------------

>  drivers/watchdog/ftwdt010_wdt.c |  25 ++++-

>  4 files changed, 25 insertions(+), 219 deletions(-)

>  delete mode 100644 drivers/watchdog/aspeed_wdt.c

> 

> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig

> index beef6bb5c6d9..0296fab14c35 100644

> --- a/drivers/watchdog/Kconfig

> +++ b/drivers/watchdog/Kconfig

> @@ -327,10 +327,11 @@ config FTWDT010_WATCHDOG

>  	select WATCHDOG_CORE

>  	default ARCH_GEMINI

>  	default ARCH_MOXART

> +	default ARCH_ASPEED

>  	help

>  	  Say Y here if to include support for the Faraday Technology

> -	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini

> -	  family of devices.

> +	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini,

> +	  MOXA ART and Aspeed families of devices.

>  

>  	  To compile this driver as a module, choose M here: the

>  	  module will be called ftwdt010_wdt.

> @@ -733,19 +734,6 @@ config RENESAS_RZAWDT

>  	  This driver adds watchdog support for the integrated watchdogs in the

>  	  Renesas RZ/A SoCs. These watchdogs can be used to reset a system.

>  

> -config ASPEED_WATCHDOG

> -	tristate "Aspeed 2400 watchdog support"

> -	depends on ARCH_ASPEED || COMPILE_TEST

> -	select WATCHDOG_CORE

> -	help

> -	  Say Y here to include support for the watchdog timer

> -	  in Apseed BMC SoCs.

> -

> -	  This driver is required to reboot the SoC.

> -

> -	  To compile this driver as a module, choose M here: the

> -	  module will be called aspeed_wdt.

> -

>  config ZX2967_WATCHDOG

>  	tristate "ZTE zx2967 SoCs watchdog support"

>  	depends on ARCH_ZX

> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile

> index fcab71f0a1c7..a9701d39928d 100644

> --- a/drivers/watchdog/Makefile

> +++ b/drivers/watchdog/Makefile

> @@ -82,7 +82,6 @@ obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o

>  obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o

>  obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o

>  obj-$(CONFIG_RENESAS_RZAWDT) += rza_wdt.o

> -obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o

>  obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o

>  obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o

>  obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o

> diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c

> deleted file mode 100644

> index 1c652582de40..000000000000

> --- a/drivers/watchdog/aspeed_wdt.c

> +++ /dev/null

> @@ -1,200 +0,0 @@

> -/*

> - * Copyright 2016 IBM Corporation

> - *

> - * Joel Stanley <joel@jms.id.au>

> - *

> - * This program is free software; you can redistribute it and/or

> - * modify it under the terms of the GNU General Public License

> - * as published by the Free Software Foundation; either version

> - * 2 of the License, or (at your option) any later version.

> - */

> -

> -#include <linux/delay.h>

> -#include <linux/io.h>

> -#include <linux/kernel.h>

> -#include <linux/module.h>

> -#include <linux/of.h>

> -#include <linux/platform_device.h>

> -#include <linux/watchdog.h>

> -

> -struct aspeed_wdt {

> -	struct watchdog_device	wdd;

> -	void __iomem		*base;

> -	u32			ctrl;

> -};

> -

> -static const struct of_device_id aspeed_wdt_of_table[] = {

> -	{ .compatible = "aspeed,ast2400-wdt" },

> -	{ .compatible = "aspeed,ast2500-wdt" },

> -	{ },

> -};

> -MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);

> -

> -#define WDT_STATUS		0x00

> -#define WDT_RELOAD_VALUE	0x04

> -#define WDT_RESTART		0x08

> -#define WDT_CTRL		0x0C

> -#define   WDT_CTRL_RESET_MODE_SOC	(0x00 << 5)

> -#define   WDT_CTRL_RESET_MODE_FULL_CHIP	(0x01 << 5)

> -#define   WDT_CTRL_1MHZ_CLK		BIT(4)

> -#define   WDT_CTRL_WDT_EXT		BIT(3)

> -#define   WDT_CTRL_WDT_INTR		BIT(2)

> -#define   WDT_CTRL_RESET_SYSTEM		BIT(1)

> -#define   WDT_CTRL_ENABLE		BIT(0)

> -

> -#define WDT_RESTART_MAGIC	0x4755

> -

> -/* 32 bits at 1MHz, in milliseconds */

> -#define WDT_MAX_TIMEOUT_MS	4294967

> -#define WDT_DEFAULT_TIMEOUT	30

> -#define WDT_RATE_1MHZ		1000000

> -

> -static struct aspeed_wdt *to_aspeed_wdt(struct watchdog_device *wdd)

> -{

> -	return container_of(wdd, struct aspeed_wdt, wdd);

> -}

> -

> -static void aspeed_wdt_enable(struct aspeed_wdt *wdt, int count)

> -{

> -	wdt->ctrl |= WDT_CTRL_ENABLE;

> -

> -	writel(0, wdt->base + WDT_CTRL);

> -	writel(count, wdt->base + WDT_RELOAD_VALUE);

> -	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);

> -	writel(wdt->ctrl, wdt->base + WDT_CTRL);

> -}

> -

> -static int aspeed_wdt_start(struct watchdog_device *wdd)

> -{

> -	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);

> -

> -	aspeed_wdt_enable(wdt, wdd->timeout * WDT_RATE_1MHZ);

> -

> -	return 0;

> -}

> -

> -static int aspeed_wdt_stop(struct watchdog_device *wdd)

> -{

> -	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);

> -

> -	wdt->ctrl &= ~WDT_CTRL_ENABLE;

> -	writel(wdt->ctrl, wdt->base + WDT_CTRL);

> -

> -	return 0;

> -}

> -

> -static int aspeed_wdt_ping(struct watchdog_device *wdd)

> -{

> -	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);

> -

> -	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);

> -

> -	return 0;

> -}

> -

> -static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,

> -				  unsigned int timeout)

> -{

> -	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);

> -	u32 actual;

> -

> -	wdd->timeout = timeout;

> -

> -	actual = min(timeout, wdd->max_hw_heartbeat_ms * 1000);

> -

> -	writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE);

> -	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);

> -

> -	return 0;

> -}

> -

> -static int aspeed_wdt_restart(struct watchdog_device *wdd,

> -			      unsigned long action, void *data)

> -{

> -	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);

> -

> -	aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000);

> -

> -	mdelay(1000);

> -

> -	return 0;

> -}

> -

> -static const struct watchdog_ops aspeed_wdt_ops = {

> -	.start		= aspeed_wdt_start,

> -	.stop		= aspeed_wdt_stop,

> -	.ping		= aspeed_wdt_ping,

> -	.set_timeout	= aspeed_wdt_set_timeout,

> -	.restart	= aspeed_wdt_restart,

> -	.owner		= THIS_MODULE,

> -};

> -

> -static const struct watchdog_info aspeed_wdt_info = {

> -	.options	= WDIOF_KEEPALIVEPING

> -			| WDIOF_MAGICCLOSE

> -			| WDIOF_SETTIMEOUT,

> -	.identity	= KBUILD_MODNAME,

> -};

> -

> -static int aspeed_wdt_probe(struct platform_device *pdev)

> -{

> -	struct aspeed_wdt *wdt;

> -	struct resource *res;

> -	int ret;

> -

> -	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);

> -	if (!wdt)

> -		return -ENOMEM;

> -

> -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

> -	wdt->base = devm_ioremap_resource(&pdev->dev, res);

> -	if (IS_ERR(wdt->base))

> -		return PTR_ERR(wdt->base);

> -

> -	/*

> -	 * The ast2400 wdt can run at PCLK, or 1MHz. The ast2500 only

> -	 * runs at 1MHz. We chose to always run at 1MHz, as there's no

> -	 * good reason to have a faster watchdog counter.

> -	 */

> -	wdt->wdd.info = &aspeed_wdt_info;

> -	wdt->wdd.ops = &aspeed_wdt_ops;

> -	wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;

> -	wdt->wdd.parent = &pdev->dev;

> -

> -	wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;

> -	watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);

> -

> -	/*

> -	 * Control reset on a per-device basis to ensure the

> -	 * host is not affected by a BMC reboot, so only reset

> -	 * the SOC and not the full chip

> -	 */

> -	wdt->ctrl = WDT_CTRL_RESET_MODE_SOC |

> -		WDT_CTRL_1MHZ_CLK |

> -		WDT_CTRL_RESET_SYSTEM;

> -

> -	if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE)  {

> -		aspeed_wdt_start(&wdt->wdd);

> -		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);

> -	}

> -

> -	ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);

> -	if (ret) {

> -		dev_err(&pdev->dev, "failed to register\n");

> -		return ret;

> -	}

> -

> -	return 0;

> -}

> -

> -static struct platform_driver aspeed_watchdog_driver = {

> -	.probe = aspeed_wdt_probe,

> -	.driver = {

> -		.name = KBUILD_MODNAME,

> -		.of_match_table = of_match_ptr(aspeed_wdt_of_table),

> -	},

> -};

> -module_platform_driver(aspeed_watchdog_driver);

> -

> -MODULE_DESCRIPTION("Aspeed Watchdog Driver");

> -MODULE_LICENSE("GPL");

> diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c

> index 912b55e67110..072da594bcbd 100644

> --- a/drivers/watchdog/ftwdt010_wdt.c

> +++ b/drivers/watchdog/ftwdt010_wdt.c

> @@ -7,6 +7,8 @@

>   * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>

>   * Inspired by the MOXA ART driver from Jonas Jensen:

>   * Copyright (C) 2013 Jonas Jensen <jonas.jensen@gmail.com>

> + * Inspired by the Aspeed driver from Joel Stanley <joel@jms.id.au>:

> + * Copyright 2016 IBM Corporation

>   *

>   * This program is free software; you can redistribute it and/or modify

>   * it under the terms of the GNU General Public License version 2 as

> @@ -32,7 +34,9 @@

>  #define FTWDT010_WDCR		0xC

>  

>  #define WDRESTART_MAGIC		0x5AB9

> +#define ASPEED_MAGIC		0x4755

>  

> +#define ASPEED_RESET_FULL_CHIP	BIT(5)

>  #define WDCR_EXTCLK		BIT(4)

>  #define WDCR_WDEXT		BIT(3)

>  #define WDCR_WDINTR		BIT(2)

> @@ -48,6 +52,7 @@ struct ftwdt010_wdt {

>  	struct clk		*extclk;

>  	unsigned int		clk_freq;

>  	bool			use_extclk;

> +	u32			magic;

>  };

>  

>  static inline

> @@ -63,7 +68,7 @@ static int ftwdt010_wdt_restart(struct watchdog_device *wdd,

>  	u32 enable;

>  

>  	writel(1, gwdt->base + FTWDT010_WDLOAD);

> -	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);

> +	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);

>  	enable = WDCR_SYS_RST | WDCR_ENABLE;

>  	if (gwdt->use_extclk)

>  		enable |= WDCR_EXTCLK;

> @@ -78,7 +83,7 @@ static int ftwdt010_wdt_start(struct watchdog_device *wdd)

>  	u32 enable;

>  

>  	writel(wdd->timeout * gwdt->clk_freq, gwdt->base + FTWDT010_WDLOAD);

> -	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);

> +	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);

>  	/* set clock before enabling */

>  	enable = WDCR_SYS_RST;

>  	if (gwdt->use_extclk)

> @@ -105,7 +110,7 @@ static int ftwdt010_wdt_ping(struct watchdog_device *wdd)

>  {

>  	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);

>  

> -	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);

> +	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);

>  

>  	return 0;

>  }

> @@ -153,6 +158,7 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)

>  	struct resource *res;

>  	struct ftwdt010_wdt *gwdt;

>  	unsigned int reg;

> +	bool is_aspeed;

>  	int irq;

>  	int ret;

>  

> @@ -167,6 +173,10 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)

>  

>  	gwdt->use_extclk = of_property_read_bool(np, "faraday,use-extclk");

>  

> +	/* We want to know if we are aspeed */

> +	is_aspeed = of_device_is_compatible(np, "aspeed,ast2400-wdt") ||

> +		of_device_is_compatible(np, "aspeed,ast2500-wdt");

> +

>  	gwdt->pclk = devm_clk_get(dev, "PCLK");

>  	if (!IS_ERR(gwdt->pclk)) {

>  		ret = clk_prepare_enable(gwdt->pclk);

> @@ -198,6 +208,11 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)

>  			gwdt->use_extclk = true;

>  			dev_info(dev, "assume 5MHz EXTCLK on Gemini\n");

>  		}

> +		if (is_aspeed) {

> +			gwdt->clk_freq = 1000000;

> +			gwdt->use_extclk = true;

> +			dev_info(dev, "assume 1MHz EXTCLK on Aspeed\n");

> +		}

>  	}

>  

>  	if (gwdt->clk_freq == 0) {

> @@ -211,6 +226,10 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)

>  	gwdt->wdd.min_timeout = 1;

>  	gwdt->wdd.max_timeout = UINT_MAX / gwdt->clk_freq;

>  	gwdt->wdd.parent = dev;

> +	if (is_aspeed)

> +		gwdt->magic = ASPEED_MAGIC;

> +	else

> +		gwdt->magic = WDRESTART_MAGIC;

>  

>  	/*

>  	 * If 'timeout-sec' unspecified in devicetree, assume a 13 second

> -- 

> 2.13.4

> 

> --

> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in

> the body of a message to majordomo@vger.kernel.org

> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Linus Walleij Aug. 24, 2017, 8:41 p.m. | #2
On Mon, Aug 14, 2017 at 5:04 PM, Guenter Roeck <linux@roeck-us.net> wrote:
> On Sat, Aug 12, 2017 at 08:43:16PM +0200, Linus Walleij wrote:

>> These two drivers is for the almost the same hardware,

>> the only differences are:

>> - The Aspeed IP block has been hacked to use a different

>>   magic value.

>> - The Aspeed has hard-wired 1MHz to the EXTCLK and

>>   apparently even disabled the use of PCLK for clocking

>>   the block on AST2500.

>>

> Confused. I thought the ast2500 is an EC. Am I missing something ?


Sorry I'm confused too now... What is EC?
Can you spell out that acronym, I never heard
it, or forgot it.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guenter Roeck Aug. 27, 2017, 5:13 p.m. | #3
On Thu, Aug 24, 2017 at 10:41:56PM +0200, Linus Walleij wrote:
> On Mon, Aug 14, 2017 at 5:04 PM, Guenter Roeck <linux@roeck-us.net> wrote:

> > On Sat, Aug 12, 2017 at 08:43:16PM +0200, Linus Walleij wrote:

> >> These two drivers is for the almost the same hardware,

> >> the only differences are:

> >> - The Aspeed IP block has been hacked to use a different

> >>   magic value.

> >> - The Aspeed has hard-wired 1MHz to the EXTCLK and

> >>   apparently even disabled the use of PCLK for clocking

> >>   the block on AST2500.

> >>

> > Confused. I thought the ast2500 is an EC. Am I missing something ?

> 

> Sorry I'm confused too now... What is EC?

> Can you spell out that acronym, I never heard

> it, or forgot it.


Embedded Controller

> 

> Yours,

> Linus Walleij

> --

> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in

> the body of a message to majordomo@vger.kernel.org

> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index beef6bb5c6d9..0296fab14c35 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -327,10 +327,11 @@  config FTWDT010_WATCHDOG
 	select WATCHDOG_CORE
 	default ARCH_GEMINI
 	default ARCH_MOXART
+	default ARCH_ASPEED
 	help
 	  Say Y here if to include support for the Faraday Technology
-	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini
-	  family of devices.
+	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini,
+	  MOXA ART and Aspeed families of devices.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ftwdt010_wdt.
@@ -733,19 +734,6 @@  config RENESAS_RZAWDT
 	  This driver adds watchdog support for the integrated watchdogs in the
 	  Renesas RZ/A SoCs. These watchdogs can be used to reset a system.
 
-config ASPEED_WATCHDOG
-	tristate "Aspeed 2400 watchdog support"
-	depends on ARCH_ASPEED || COMPILE_TEST
-	select WATCHDOG_CORE
-	help
-	  Say Y here to include support for the watchdog timer
-	  in Apseed BMC SoCs.
-
-	  This driver is required to reboot the SoC.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called aspeed_wdt.
-
 config ZX2967_WATCHDOG
 	tristate "ZTE zx2967 SoCs watchdog support"
 	depends on ARCH_ZX
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index fcab71f0a1c7..a9701d39928d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -82,7 +82,6 @@  obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
 obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
 obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o
 obj-$(CONFIG_RENESAS_RZAWDT) += rza_wdt.o
-obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o
 obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o
 obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o
 obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o
diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c
deleted file mode 100644
index 1c652582de40..000000000000
--- a/drivers/watchdog/aspeed_wdt.c
+++ /dev/null
@@ -1,200 +0,0 @@ 
-/*
- * Copyright 2016 IBM Corporation
- *
- * Joel Stanley <joel@jms.id.au>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/watchdog.h>
-
-struct aspeed_wdt {
-	struct watchdog_device	wdd;
-	void __iomem		*base;
-	u32			ctrl;
-};
-
-static const struct of_device_id aspeed_wdt_of_table[] = {
-	{ .compatible = "aspeed,ast2400-wdt" },
-	{ .compatible = "aspeed,ast2500-wdt" },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
-
-#define WDT_STATUS		0x00
-#define WDT_RELOAD_VALUE	0x04
-#define WDT_RESTART		0x08
-#define WDT_CTRL		0x0C
-#define   WDT_CTRL_RESET_MODE_SOC	(0x00 << 5)
-#define   WDT_CTRL_RESET_MODE_FULL_CHIP	(0x01 << 5)
-#define   WDT_CTRL_1MHZ_CLK		BIT(4)
-#define   WDT_CTRL_WDT_EXT		BIT(3)
-#define   WDT_CTRL_WDT_INTR		BIT(2)
-#define   WDT_CTRL_RESET_SYSTEM		BIT(1)
-#define   WDT_CTRL_ENABLE		BIT(0)
-
-#define WDT_RESTART_MAGIC	0x4755
-
-/* 32 bits at 1MHz, in milliseconds */
-#define WDT_MAX_TIMEOUT_MS	4294967
-#define WDT_DEFAULT_TIMEOUT	30
-#define WDT_RATE_1MHZ		1000000
-
-static struct aspeed_wdt *to_aspeed_wdt(struct watchdog_device *wdd)
-{
-	return container_of(wdd, struct aspeed_wdt, wdd);
-}
-
-static void aspeed_wdt_enable(struct aspeed_wdt *wdt, int count)
-{
-	wdt->ctrl |= WDT_CTRL_ENABLE;
-
-	writel(0, wdt->base + WDT_CTRL);
-	writel(count, wdt->base + WDT_RELOAD_VALUE);
-	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
-	writel(wdt->ctrl, wdt->base + WDT_CTRL);
-}
-
-static int aspeed_wdt_start(struct watchdog_device *wdd)
-{
-	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
-
-	aspeed_wdt_enable(wdt, wdd->timeout * WDT_RATE_1MHZ);
-
-	return 0;
-}
-
-static int aspeed_wdt_stop(struct watchdog_device *wdd)
-{
-	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
-
-	wdt->ctrl &= ~WDT_CTRL_ENABLE;
-	writel(wdt->ctrl, wdt->base + WDT_CTRL);
-
-	return 0;
-}
-
-static int aspeed_wdt_ping(struct watchdog_device *wdd)
-{
-	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
-
-	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
-
-	return 0;
-}
-
-static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,
-				  unsigned int timeout)
-{
-	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
-	u32 actual;
-
-	wdd->timeout = timeout;
-
-	actual = min(timeout, wdd->max_hw_heartbeat_ms * 1000);
-
-	writel(actual * WDT_RATE_1MHZ, wdt->base + WDT_RELOAD_VALUE);
-	writel(WDT_RESTART_MAGIC, wdt->base + WDT_RESTART);
-
-	return 0;
-}
-
-static int aspeed_wdt_restart(struct watchdog_device *wdd,
-			      unsigned long action, void *data)
-{
-	struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
-
-	aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000);
-
-	mdelay(1000);
-
-	return 0;
-}
-
-static const struct watchdog_ops aspeed_wdt_ops = {
-	.start		= aspeed_wdt_start,
-	.stop		= aspeed_wdt_stop,
-	.ping		= aspeed_wdt_ping,
-	.set_timeout	= aspeed_wdt_set_timeout,
-	.restart	= aspeed_wdt_restart,
-	.owner		= THIS_MODULE,
-};
-
-static const struct watchdog_info aspeed_wdt_info = {
-	.options	= WDIOF_KEEPALIVEPING
-			| WDIOF_MAGICCLOSE
-			| WDIOF_SETTIMEOUT,
-	.identity	= KBUILD_MODNAME,
-};
-
-static int aspeed_wdt_probe(struct platform_device *pdev)
-{
-	struct aspeed_wdt *wdt;
-	struct resource *res;
-	int ret;
-
-	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
-	if (!wdt)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	wdt->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(wdt->base))
-		return PTR_ERR(wdt->base);
-
-	/*
-	 * The ast2400 wdt can run at PCLK, or 1MHz. The ast2500 only
-	 * runs at 1MHz. We chose to always run at 1MHz, as there's no
-	 * good reason to have a faster watchdog counter.
-	 */
-	wdt->wdd.info = &aspeed_wdt_info;
-	wdt->wdd.ops = &aspeed_wdt_ops;
-	wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
-	wdt->wdd.parent = &pdev->dev;
-
-	wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
-	watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
-
-	/*
-	 * Control reset on a per-device basis to ensure the
-	 * host is not affected by a BMC reboot, so only reset
-	 * the SOC and not the full chip
-	 */
-	wdt->ctrl = WDT_CTRL_RESET_MODE_SOC |
-		WDT_CTRL_1MHZ_CLK |
-		WDT_CTRL_RESET_SYSTEM;
-
-	if (readl(wdt->base + WDT_CTRL) & WDT_CTRL_ENABLE)  {
-		aspeed_wdt_start(&wdt->wdd);
-		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
-	}
-
-	ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to register\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static struct platform_driver aspeed_watchdog_driver = {
-	.probe = aspeed_wdt_probe,
-	.driver = {
-		.name = KBUILD_MODNAME,
-		.of_match_table = of_match_ptr(aspeed_wdt_of_table),
-	},
-};
-module_platform_driver(aspeed_watchdog_driver);
-
-MODULE_DESCRIPTION("Aspeed Watchdog Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c
index 912b55e67110..072da594bcbd 100644
--- a/drivers/watchdog/ftwdt010_wdt.c
+++ b/drivers/watchdog/ftwdt010_wdt.c
@@ -7,6 +7,8 @@ 
  * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
  * Inspired by the MOXA ART driver from Jonas Jensen:
  * Copyright (C) 2013 Jonas Jensen <jonas.jensen@gmail.com>
+ * Inspired by the Aspeed driver from Joel Stanley <joel@jms.id.au>:
+ * Copyright 2016 IBM Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -32,7 +34,9 @@ 
 #define FTWDT010_WDCR		0xC
 
 #define WDRESTART_MAGIC		0x5AB9
+#define ASPEED_MAGIC		0x4755
 
+#define ASPEED_RESET_FULL_CHIP	BIT(5)
 #define WDCR_EXTCLK		BIT(4)
 #define WDCR_WDEXT		BIT(3)
 #define WDCR_WDINTR		BIT(2)
@@ -48,6 +52,7 @@  struct ftwdt010_wdt {
 	struct clk		*extclk;
 	unsigned int		clk_freq;
 	bool			use_extclk;
+	u32			magic;
 };
 
 static inline
@@ -63,7 +68,7 @@  static int ftwdt010_wdt_restart(struct watchdog_device *wdd,
 	u32 enable;
 
 	writel(1, gwdt->base + FTWDT010_WDLOAD);
-	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
+	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);
 	enable = WDCR_SYS_RST | WDCR_ENABLE;
 	if (gwdt->use_extclk)
 		enable |= WDCR_EXTCLK;
@@ -78,7 +83,7 @@  static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 	u32 enable;
 
 	writel(wdd->timeout * gwdt->clk_freq, gwdt->base + FTWDT010_WDLOAD);
-	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
+	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);
 	/* set clock before enabling */
 	enable = WDCR_SYS_RST;
 	if (gwdt->use_extclk)
@@ -105,7 +110,7 @@  static int ftwdt010_wdt_ping(struct watchdog_device *wdd)
 {
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
 
-	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
+	writel(gwdt->magic, gwdt->base + FTWDT010_WDRESTART);
 
 	return 0;
 }
@@ -153,6 +158,7 @@  static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct ftwdt010_wdt *gwdt;
 	unsigned int reg;
+	bool is_aspeed;
 	int irq;
 	int ret;
 
@@ -167,6 +173,10 @@  static int ftwdt010_wdt_probe(struct platform_device *pdev)
 
 	gwdt->use_extclk = of_property_read_bool(np, "faraday,use-extclk");
 
+	/* We want to know if we are aspeed */
+	is_aspeed = of_device_is_compatible(np, "aspeed,ast2400-wdt") ||
+		of_device_is_compatible(np, "aspeed,ast2500-wdt");
+
 	gwdt->pclk = devm_clk_get(dev, "PCLK");
 	if (!IS_ERR(gwdt->pclk)) {
 		ret = clk_prepare_enable(gwdt->pclk);
@@ -198,6 +208,11 @@  static int ftwdt010_wdt_probe(struct platform_device *pdev)
 			gwdt->use_extclk = true;
 			dev_info(dev, "assume 5MHz EXTCLK on Gemini\n");
 		}
+		if (is_aspeed) {
+			gwdt->clk_freq = 1000000;
+			gwdt->use_extclk = true;
+			dev_info(dev, "assume 1MHz EXTCLK on Aspeed\n");
+		}
 	}
 
 	if (gwdt->clk_freq == 0) {
@@ -211,6 +226,10 @@  static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	gwdt->wdd.min_timeout = 1;
 	gwdt->wdd.max_timeout = UINT_MAX / gwdt->clk_freq;
 	gwdt->wdd.parent = dev;
+	if (is_aspeed)
+		gwdt->magic = ASPEED_MAGIC;
+	else
+		gwdt->magic = WDRESTART_MAGIC;
 
 	/*
 	 * If 'timeout-sec' unspecified in devicetree, assume a 13 second