Thread (38 messages) 38 messages, 5 authors, 2017-10-12
STALE3198d

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

From: linux@roeck-us.net (Guenter Roeck)
Date: 2017-08-14 15:04:34
Also in: linux-watchdog

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
quoted hunk ↗ jump to hunk
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 <redacted>
---
 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 at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help