linux-watchdog.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] watchdog: sbsa: Support architecture version 1
@ 2021-05-17 12:10 Shaokun Zhang
  2021-05-17 13:41 ` Guenter Roeck
  0 siblings, 1 reply; 2+ messages in thread
From: Shaokun Zhang @ 2021-05-17 12:10 UTC (permalink / raw)
  To: linux-watchdog
  Cc: Shaokun Zhang, Wim Van Sebroeck, Guenter Roeck,
	Suravee Suthikulpanit, Al Stone, Jianchao Hu, Huiqiang Wang

For Armv8.6, The frequency of CNTFRQ_EL0 is standardized to a
frequency of 1GHz, so Arm Base System Architecture 1.0[1] has
introduced watchdog revision 1 that increases the length the
watchdog offset register to 48 bit, while other operation of
the watchdog remains the same.

The driver can determine which version of the watchdog is
implemented through the watchdog interface identification
register (W_IID). If the version is 0x1, the watchdog
offset register will be 48 bit, otherwise it will be 32 bit.

[1] https://developer.arm.com/documentation/den0094/latest

Cc: Wim Van Sebroeck <wim@linux-watchdog.org>
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Cc: Al Stone <al.stone@linaro.org>
Cc: Jianchao Hu <hujianchao@hisilicon.com>
Cc: Huiqiang Wang <wanghuiqiang@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
ChangeLog
v1-->v2:
    1. Addressed Guenter's comments
    2. Remove some dead mailboxs and rewrite comments.
    
 drivers/watchdog/sbsa_gwdt.c | 54 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c
index f0f1e3b2e463..ee9ff38929eb 100644
--- a/drivers/watchdog/sbsa_gwdt.c
+++ b/drivers/watchdog/sbsa_gwdt.c
@@ -73,16 +73,21 @@
 #define SBSA_GWDT_WCS_WS0	BIT(1)
 #define SBSA_GWDT_WCS_WS1	BIT(2)
 
+#define SBSA_GWDT_VERSION_MASK  0xF
+#define SBSA_GWDT_VERSION_SHIFT 16
+
 /**
  * struct sbsa_gwdt - Internal representation of the SBSA GWDT
  * @wdd:		kernel watchdog_device structure
  * @clk:		store the System Counter clock frequency, in Hz.
+ * @version:            store the architecture version
  * @refresh_base:	Virtual address of the watchdog refresh frame
  * @control_base:	Virtual address of the watchdog control frame
  */
 struct sbsa_gwdt {
 	struct watchdog_device	wdd;
 	u32			clk;
+	int			version;
 	void __iomem		*refresh_base;
 	void __iomem		*control_base;
 };
@@ -113,6 +118,30 @@ MODULE_PARM_DESC(nowayout,
 		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 /*
+ * Arm Base System Architecture 1.0 introduces watchdog v1 which
+ * increases the length watchdog offset register to 48 bits.
+ * - For version 0: WOR is 32 bits;
+ * - For version 1: WOR is 48 bits which comprises the register
+ * offset 0x8 and 0xC, and the bits [63:48] are reserved which are
+ * Read-As-Zero and Writes-Ignored.
+ */
+static u64 sbsa_gwdt_reg_read(struct sbsa_gwdt *gwdt)
+{
+	if (gwdt->version == 0)
+		return readl(gwdt->control_base + SBSA_GWDT_WOR);
+	else
+		return readq(gwdt->control_base + SBSA_GWDT_WOR);
+}
+
+static void sbsa_gwdt_reg_write(u64 val, struct sbsa_gwdt *gwdt)
+{
+	if (gwdt->version == 0)
+		writel((u32)val, gwdt->control_base + SBSA_GWDT_WOR);
+	else
+		writeq(val, gwdt->control_base + SBSA_GWDT_WOR);
+}
+
+/*
  * watchdog operation functions
  */
 static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
@@ -123,16 +152,14 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
 	wdd->timeout = timeout;
 
 	if (action)
-		writel(gwdt->clk * timeout,
-		       gwdt->control_base + SBSA_GWDT_WOR);
+		sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt);
 	else
 		/*
 		 * In the single stage mode, The first signal (WS0) is ignored,
 		 * the timeout is (WOR * 2), so the WOR should be configured
 		 * to half value of timeout.
 		 */
-		writel(gwdt->clk / 2 * timeout,
-		       gwdt->control_base + SBSA_GWDT_WOR);
+		sbsa_gwdt_reg_write(gwdt->clk / 2 * timeout, gwdt);
 
 	return 0;
 }
@@ -149,7 +176,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd)
 	 */
 	if (!action &&
 	    !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0))
-		timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR);
+		timeleft += sbsa_gwdt_reg_read(gwdt);
 
 	timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) -
 		    arch_timer_read_counter();
@@ -172,6 +199,17 @@ static int sbsa_gwdt_keepalive(struct watchdog_device *wdd)
 	return 0;
 }
 
+static void sbsa_gwdt_get_version(struct watchdog_device *wdd)
+{
+	struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
+	int ver;
+
+	ver = readl(gwdt->control_base + SBSA_GWDT_W_IIDR);
+	ver = (ver >> SBSA_GWDT_VERSION_SHIFT) & SBSA_GWDT_VERSION_MASK;
+
+	gwdt->version = ver;
+}
+
 static int sbsa_gwdt_start(struct watchdog_device *wdd)
 {
 	struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
@@ -252,10 +290,14 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
 	wdd->info = &sbsa_gwdt_info;
 	wdd->ops = &sbsa_gwdt_ops;
 	wdd->min_timeout = 1;
-	wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
 	wdd->timeout = DEFAULT_TIMEOUT;
 	watchdog_set_drvdata(wdd, gwdt);
 	watchdog_set_nowayout(wdd, nowayout);
+	sbsa_gwdt_get_version(wdd);
+	if (gwdt->version == 0)
+		wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
+	else
+		wdd->max_hw_heartbeat_ms = GENMASK_ULL(47, 0) / gwdt->clk * 1000;
 
 	status = readl(cf_base + SBSA_GWDT_WCS);
 	if (status & SBSA_GWDT_WCS_WS1) {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] watchdog: sbsa: Support architecture version 1
  2021-05-17 12:10 [PATCH v2] watchdog: sbsa: Support architecture version 1 Shaokun Zhang
@ 2021-05-17 13:41 ` Guenter Roeck
  0 siblings, 0 replies; 2+ messages in thread
From: Guenter Roeck @ 2021-05-17 13:41 UTC (permalink / raw)
  To: Shaokun Zhang, linux-watchdog
  Cc: Wim Van Sebroeck, Suravee Suthikulpanit, Al Stone, Jianchao Hu,
	Huiqiang Wang

On 5/17/21 5:10 AM, Shaokun Zhang wrote:
> For Armv8.6, The frequency of CNTFRQ_EL0 is standardized to a
> frequency of 1GHz, so Arm Base System Architecture 1.0[1] has
> introduced watchdog revision 1 that increases the length the
> watchdog offset register to 48 bit, while other operation of
> the watchdog remains the same.
> 
> The driver can determine which version of the watchdog is
> implemented through the watchdog interface identification
> register (W_IID). If the version is 0x1, the watchdog
> offset register will be 48 bit, otherwise it will be 32 bit.
> 
> [1] https://developer.arm.com/documentation/den0094/latest
> 
> Cc: Wim Van Sebroeck <wim@linux-watchdog.org>
> Cc: Guenter Roeck <linux@roeck-us.net>
> Cc: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
> Cc: Al Stone <al.stone@linaro.org>
> Cc: Jianchao Hu <hujianchao@hisilicon.com>
> Cc: Huiqiang Wang <wanghuiqiang@huawei.com>
> Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
> ChangeLog
> v1-->v2:
>      1. Addressed Guenter's comments
>      2. Remove some dead mailboxs and rewrite comments.
>      
>   drivers/watchdog/sbsa_gwdt.c | 54 +++++++++++++++++++++++++++++++++++++++-----
>   1 file changed, 48 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c
> index f0f1e3b2e463..ee9ff38929eb 100644
> --- a/drivers/watchdog/sbsa_gwdt.c
> +++ b/drivers/watchdog/sbsa_gwdt.c
> @@ -73,16 +73,21 @@
>   #define SBSA_GWDT_WCS_WS0	BIT(1)
>   #define SBSA_GWDT_WCS_WS1	BIT(2)
>   
> +#define SBSA_GWDT_VERSION_MASK  0xF
> +#define SBSA_GWDT_VERSION_SHIFT 16
> +
>   /**
>    * struct sbsa_gwdt - Internal representation of the SBSA GWDT
>    * @wdd:		kernel watchdog_device structure
>    * @clk:		store the System Counter clock frequency, in Hz.
> + * @version:            store the architecture version
>    * @refresh_base:	Virtual address of the watchdog refresh frame
>    * @control_base:	Virtual address of the watchdog control frame
>    */
>   struct sbsa_gwdt {
>   	struct watchdog_device	wdd;
>   	u32			clk;
> +	int			version;
>   	void __iomem		*refresh_base;
>   	void __iomem		*control_base;
>   };
> @@ -113,6 +118,30 @@ MODULE_PARM_DESC(nowayout,
>   		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
>   
>   /*
> + * Arm Base System Architecture 1.0 introduces watchdog v1 which
> + * increases the length watchdog offset register to 48 bits.
> + * - For version 0: WOR is 32 bits;
> + * - For version 1: WOR is 48 bits which comprises the register
> + * offset 0x8 and 0xC, and the bits [63:48] are reserved which are
> + * Read-As-Zero and Writes-Ignored.
> + */
> +static u64 sbsa_gwdt_reg_read(struct sbsa_gwdt *gwdt)
> +{
> +	if (gwdt->version == 0)
> +		return readl(gwdt->control_base + SBSA_GWDT_WOR);
> +	else
> +		return readq(gwdt->control_base + SBSA_GWDT_WOR);
> +}
> +
> +static void sbsa_gwdt_reg_write(u64 val, struct sbsa_gwdt *gwdt)
> +{
> +	if (gwdt->version == 0)
> +		writel((u32)val, gwdt->control_base + SBSA_GWDT_WOR);
> +	else
> +		writeq(val, gwdt->control_base + SBSA_GWDT_WOR);
> +}
> +
> +/*
>    * watchdog operation functions
>    */
>   static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
> @@ -123,16 +152,14 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
>   	wdd->timeout = timeout;
>   
>   	if (action)
> -		writel(gwdt->clk * timeout,
> -		       gwdt->control_base + SBSA_GWDT_WOR);
> +		sbsa_gwdt_reg_write(gwdt->clk * timeout, gwdt);
>   	else
>   		/*
>   		 * In the single stage mode, The first signal (WS0) is ignored,
>   		 * the timeout is (WOR * 2), so the WOR should be configured
>   		 * to half value of timeout.
>   		 */
> -		writel(gwdt->clk / 2 * timeout,
> -		       gwdt->control_base + SBSA_GWDT_WOR);
> +		sbsa_gwdt_reg_write(gwdt->clk / 2 * timeout, gwdt);
>   
>   	return 0;
>   }
> @@ -149,7 +176,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd)
>   	 */
>   	if (!action &&
>   	    !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0))
> -		timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR);
> +		timeleft += sbsa_gwdt_reg_read(gwdt);
>   
>   	timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) -
>   		    arch_timer_read_counter();
> @@ -172,6 +199,17 @@ static int sbsa_gwdt_keepalive(struct watchdog_device *wdd)
>   	return 0;
>   }
>   
> +static void sbsa_gwdt_get_version(struct watchdog_device *wdd)
> +{
> +	struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
> +	int ver;
> +
> +	ver = readl(gwdt->control_base + SBSA_GWDT_W_IIDR);
> +	ver = (ver >> SBSA_GWDT_VERSION_SHIFT) & SBSA_GWDT_VERSION_MASK;
> +
> +	gwdt->version = ver;
> +}
> +
>   static int sbsa_gwdt_start(struct watchdog_device *wdd)
>   {
>   	struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
> @@ -252,10 +290,14 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
>   	wdd->info = &sbsa_gwdt_info;
>   	wdd->ops = &sbsa_gwdt_ops;
>   	wdd->min_timeout = 1;
> -	wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
>   	wdd->timeout = DEFAULT_TIMEOUT;
>   	watchdog_set_drvdata(wdd, gwdt);
>   	watchdog_set_nowayout(wdd, nowayout);
> +	sbsa_gwdt_get_version(wdd);
> +	if (gwdt->version == 0)
> +		wdd->max_hw_heartbeat_ms = U32_MAX / gwdt->clk * 1000;
> +	else
> +		wdd->max_hw_heartbeat_ms = GENMASK_ULL(47, 0) / gwdt->clk * 1000;
>   
>   	status = readl(cf_base + SBSA_GWDT_WCS);
>   	if (status & SBSA_GWDT_WCS_WS1) {
> 


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-05-17 13:41 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-17 12:10 [PATCH v2] watchdog: sbsa: Support architecture version 1 Shaokun Zhang
2021-05-17 13:41 ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).