Linux-Watchdog Archive on lore.kernel.org
 help / color / Atom feed
From: Srinivas Neeli <srinivas.neeli@xilinx.com>
To: linux@roeck-us.net, michal.simek@xilinx.com,
	shubhrajyoti.datta@xilinx.com, sgoud@xilinx.com
Cc: wim@linux-watchdog.org, linux-watchdog@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, git@xilinx.com
Subject: [PATCH 7/9] watchdog: of_xilinx_wdt: Add Versal support
Date: Thu, 16 Jan 2020 18:56:55 +0530
Message-ID: <1579181217-31127-8-git-send-email-srinivas.neeli@xilinx.com> (raw)
In-Reply-To: <1579181217-31127-1-git-send-email-srinivas.neeli@xilinx.com>

From: Srinivas Goud <srinivas.goud@xilinx.com>

Versal watchdog driver uses generic watchdog mode.
Generic watchdog contains closed and open window of equal timeout.
Generic watchdog will generate reset signal if it is not explicitly
refreshed in second window.

Signed-off-by: Srinivas Goud <srinivas.goud@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Srinivas Neeli <srinivas.neeli@xilinx.com>
---
 drivers/watchdog/of_xilinx_wdt.c | 150 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 1 deletion(-)

diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 3b93b60f1a00..d2c389d9eaa7 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -2,7 +2,7 @@
 /*
  * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
  *
- * (C) Copyright 2013 - 2014 Xilinx, Inc.
+ * (C) Copyright 2013 - 2020 Xilinx, Inc.
  * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
  */
 
@@ -18,10 +18,19 @@
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 
+#define XWT_WWDT_MIN_TIMEOUT		1
+#define XWT_WWDT_MAX_TIMEOUT		80
+
 /* Register offsets for the Wdt device */
 #define XWT_TWCSR0_OFFSET   0x0 /* Control/Status Register0 */
 #define XWT_TWCSR1_OFFSET   0x4 /* Control/Status Register1 */
 #define XWT_TBR_OFFSET      0x8 /* Timebase Register Offset */
+#define XWT_WWREF_OFFSET	0x1000 /* Refresh Register */
+#define XWT_WWCSR_OFFSET	0x2000 /* Control/Status Register */
+#define XWT_WWOFF_OFFSET	0x2008 /* Offset Register */
+#define XWT_WWCMP0_OFFSET	0x2010 /* Compare Value Register0 */
+#define XWT_WWCMP1_OFFSET	0x2014 /* Compare Value Register1 */
+#define XWT_WWWRST_OFFSET	0x2FD0 /* Warm Reset Register */
 
 /* Control/Status Register Masks  */
 #define XWT_CSR0_WRS_MASK	BIT(3) /* Reset status */
@@ -31,6 +40,15 @@
 /* Control/Status Register 0/1 bits  */
 #define XWT_CSRX_EWDT2_MASK	BIT(0) /* Enable bit 2 */
 
+/* Refresh Register Masks */
+#define XWT_WWREF_GWRR_MASK	BIT(0) /* Refresh and start new period */
+
+/* Generic Control/Status Register Masks  */
+#define XWT_WWCSR_GWEN_MASK	BIT(0) /* Enable Bit */
+
+/* Warm Reset Register Masks */
+#define XWT_WWRST_GWWRR_MASK	BIT(0) /* Warm Reset Register */
+
 /* SelfTest constants */
 #define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
 #define XWT_TIMER_FAILED            0xFFFFFFFF
@@ -41,9 +59,11 @@
  * enum xwdt_ip_type - WDT IP type.
  *
  * @XWDT_WDT: Soft wdt ip.
+ * @XWDT_WWDT: Window wdt ip.
  */
 enum xwdt_ip_type {
 	XWDT_WDT = 0,
+	XWDT_WWDT,
 };
 
 struct xwdt_devtype_data {
@@ -145,6 +165,126 @@ static const struct watchdog_ops xilinx_wdt_ops = {
 	.ping = xilinx_wdt_keepalive,
 };
 
+static int xilinx_wwdt_start(struct watchdog_device *wdd)
+{
+	int ret;
+	u32 control_status_reg;
+	u64 count;
+	struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+	struct watchdog_device *xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
+
+	unsigned long clock_f = clk_get_rate(xdev->clk);
+
+	/* Calculate timeout count */
+	count = wdd->timeout * clock_f;
+	ret  = clk_enable(xdev->clk);
+	if (ret) {
+		dev_err(wdd->parent, "Failed to enable clock\n");
+		return ret;
+	}
+
+	spin_lock(&xdev->spinlock);
+
+	/*
+	 * Timeout count is half as there are two windows
+	 * first window overflow is ignored (interrupt),
+	 * reset is only generated at second window overflow
+	 */
+	count = count >> 1;
+
+	/* Disable the generic watchdog timer */
+	control_status_reg = ioread32(xdev->base + XWT_WWCSR_OFFSET);
+	control_status_reg &= ~(XWT_WWCSR_GWEN_MASK);
+	iowrite32(control_status_reg, xdev->base + XWT_WWCSR_OFFSET);
+
+	/* Set compare and offset registers for generic watchdog timeout */
+	iowrite32((u32)count, xdev->base + XWT_WWCMP0_OFFSET);
+	iowrite32((u32)0, xdev->base + XWT_WWCMP1_OFFSET);
+	iowrite32((u32)count, xdev->base + XWT_WWOFF_OFFSET);
+
+	/* Enable the generic watchdog timer */
+	control_status_reg = ioread32(xdev->base + XWT_WWCSR_OFFSET);
+	control_status_reg |= (XWT_WWCSR_GWEN_MASK);
+	iowrite32(control_status_reg, xdev->base + XWT_WWCSR_OFFSET);
+
+	spin_unlock(&xdev->spinlock);
+
+	dev_dbg(xilinx_wdt_wdd->parent, "Watchdog Started!\n");
+
+	return 0;
+}
+
+static int xilinx_wwdt_stop(struct watchdog_device *wdd)
+{
+	u32 control_status_reg;
+	struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+	struct watchdog_device *xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
+
+	spin_lock(&xdev->spinlock);
+
+	/* Disable the generic watchdog timer */
+	control_status_reg = ioread32(xdev->base + XWT_WWCSR_OFFSET);
+	control_status_reg &= ~(XWT_WWCSR_GWEN_MASK);
+	iowrite32(control_status_reg, xdev->base + XWT_WWCSR_OFFSET);
+
+	spin_unlock(&xdev->spinlock);
+
+	clk_disable(xdev->clk);
+
+	dev_dbg(xilinx_wdt_wdd->parent, "Watchdog Stopped!\n");
+
+	return 0;
+}
+
+static int xilinx_wwdt_keepalive(struct watchdog_device *wdd)
+{
+	struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+
+	spin_lock(&xdev->spinlock);
+
+	iowrite32(XWT_WWREF_GWRR_MASK, xdev->base + XWT_WWREF_OFFSET);
+
+	spin_unlock(&xdev->spinlock);
+
+	return 0;
+}
+
+static int xilinx_wwdt_set_timeout(struct watchdog_device *wdd,
+				   unsigned int new_time)
+{
+	struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
+	struct watchdog_device *xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
+
+	if (new_time < XWT_WWDT_MIN_TIMEOUT ||
+	    new_time > XWT_WWDT_MAX_TIMEOUT) {
+		dev_warn(xilinx_wdt_wdd->parent,
+			 "timeout value must be %d<=x<=%d, using %d\n",
+				XWT_WWDT_MIN_TIMEOUT,
+				XWT_WWDT_MAX_TIMEOUT, new_time);
+		return -EINVAL;
+	}
+
+	wdd->timeout = new_time;
+
+	return xilinx_wwdt_start(wdd);
+}
+
+static const struct watchdog_info xilinx_wwdt_ident = {
+	.options =  WDIOF_MAGICCLOSE |
+		WDIOF_KEEPALIVEPING |
+		WDIOF_SETTIMEOUT,
+	.firmware_version =	1,
+	.identity = "xlnx_wwdt watchdog",
+};
+
+static const struct watchdog_ops xilinx_wwdt_ops = {
+	.owner = THIS_MODULE,
+	.start = xilinx_wwdt_start,
+	.stop = xilinx_wwdt_stop,
+	.ping = xilinx_wwdt_keepalive,
+	.set_timeout = xilinx_wwdt_set_timeout,
+};
+
 static u32 xwdt_selftest(struct xwdt_device *xdev)
 {
 	int i;
@@ -181,11 +321,19 @@ static const struct xwdt_devtype_data xwdt_wdt_data = {
 	.xwdt_ops = &xilinx_wdt_ops,
 };
 
+static const struct xwdt_devtype_data xwdt_wwdt_data = {
+	.wdttype = XWDT_WWDT,
+	.xwdt_info = &xilinx_wwdt_ident,
+	.xwdt_ops = &xilinx_wwdt_ops,
+};
+
 static const struct of_device_id xwdt_of_match[] = {
 	{ .compatible = "xlnx,xps-timebase-wdt-1.00.a",
 		.data = &xwdt_wdt_data },
 	{ .compatible = "xlnx,xps-timebase-wdt-1.01.a",
 		.data = &xwdt_wdt_data },
+	{ .compatible = "xlnx,versal-wwdt-1.0",
+		.data = &xwdt_wwdt_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, xwdt_of_match);
-- 
2.7.4


  parent reply index

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-16 13:26 [PATCH 0/9] watchdog: of_xilinx_wdt: Update on watchdog driver Srinivas Neeli
2020-01-16 13:26 ` [PATCH 1/9] watchdog: of_xilinx_wdt: Add comment to spinlock Srinivas Neeli
2020-01-16 15:48   ` Guenter Roeck
2020-01-16 13:26 ` [PATCH 2/9] watchdog: of_xilinx_wdt: Used BIT macro Srinivas Neeli
2020-01-16 15:04   ` Guenter Roeck
2020-01-16 13:26 ` [PATCH 3/9] watchdog: of_xilinx_wdt: Used dev_dbg() Srinivas Neeli
2020-01-16 13:26 ` [PATCH 4/9] watchdog: of_xilinx_wdt: Initialize watchdog via data structure Srinivas Neeli
2020-01-16 13:26 ` [PATCH 5/9] watchdog: of_xilinx_wdt: Introduce wdttype enum for identification Srinivas Neeli
2020-01-16 13:26 ` [PATCH 6/9] dt-bindings: watchdog: xilinx: Add binding for Versal watchdog Srinivas Neeli
2020-01-16 13:26 ` Srinivas Neeli [this message]
2020-01-16 15:07   ` [PATCH 7/9] watchdog: of_xilinx_wdt: Add Versal support Guenter Roeck
2020-01-16 13:26 ` [PATCH 8/9] watchdog: of_xilinx_wdt: Wire setting up timeout via module parameter/DT Srinivas Neeli
2020-01-16 13:26 ` [PATCH 9/9] watchdog: of_xilinx_wdt: Skip printing pointer value Srinivas Neeli

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1579181217-31127-8-git-send-email-srinivas.neeli@xilinx.com \
    --to=srinivas.neeli@xilinx.com \
    --cc=git@xilinx.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=michal.simek@xilinx.com \
    --cc=sgoud@xilinx.com \
    --cc=shubhrajyoti.datta@xilinx.com \
    --cc=wim@linux-watchdog.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-Watchdog Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-watchdog/0 linux-watchdog/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-watchdog linux-watchdog/ https://lore.kernel.org/linux-watchdog \
		linux-watchdog@vger.kernel.org
	public-inbox-index linux-watchdog

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-watchdog


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git