1 // SPDX-License-Identifier: GPL-2.0
3 * Window watchdog device driver for Xilinx Versal WWDT
5 * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
9 #include <linux/interrupt.h>
11 #include <linux/ioport.h>
12 #include <linux/math64.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/watchdog.h>
18 /* Max timeout is calculated at 100MHz source clock */
19 #define XWWDT_DEFAULT_TIMEOUT 42
20 #define XWWDT_MIN_TIMEOUT 1
22 /* Register offsets for the WWDT device */
23 #define XWWDT_MWR_OFFSET 0x00
24 #define XWWDT_ESR_OFFSET 0x04
25 #define XWWDT_FCR_OFFSET 0x08
26 #define XWWDT_FWR_OFFSET 0x0c
27 #define XWWDT_SWR_OFFSET 0x10
29 /* Master Write Control Register Masks */
30 #define XWWDT_MWR_MASK BIT(0)
32 /* Enable and Status Register Masks */
33 #define XWWDT_ESR_WINT_MASK BIT(16)
34 #define XWWDT_ESR_WSW_MASK BIT(8)
35 #define XWWDT_ESR_WEN_MASK BIT(0)
37 #define XWWDT_CLOSE_WINDOW_PERCENT 50
39 static int wwdt_timeout
;
40 static int closed_window_percent
;
42 module_param(wwdt_timeout
, int, 0);
43 MODULE_PARM_DESC(wwdt_timeout
,
44 "Watchdog time in seconds. (default="
45 __MODULE_STRING(XWWDT_DEFAULT_TIMEOUT
) ")");
46 module_param(closed_window_percent
, int, 0);
47 MODULE_PARM_DESC(closed_window_percent
,
48 "Watchdog closed window percentage. (default="
49 __MODULE_STRING(XWWDT_CLOSE_WINDOW_PERCENT
) ")");
51 * struct xwwdt_device - Watchdog device structure
52 * @base: base io address of WDT device
53 * @spinlock: spinlock for IO register access
54 * @xilinx_wwdt_wdd: watchdog device structure
55 * @freq: source clock frequency of WWDT
56 * @close_percent: Closed window percent
60 spinlock_t spinlock
; /* spinlock for register handling */
61 struct watchdog_device xilinx_wwdt_wdd
;
66 static int xilinx_wwdt_start(struct watchdog_device
*wdd
)
68 struct xwwdt_device
*xdev
= watchdog_get_drvdata(wdd
);
69 struct watchdog_device
*xilinx_wwdt_wdd
= &xdev
->xilinx_wwdt_wdd
;
70 u64 time_out
, closed_timeout
, open_timeout
;
71 u32 control_status_reg
;
73 /* Calculate timeout count */
74 time_out
= xdev
->freq
* wdd
->timeout
;
75 closed_timeout
= div_u64(time_out
* xdev
->close_percent
, 100);
76 open_timeout
= time_out
- closed_timeout
;
77 wdd
->min_hw_heartbeat_ms
= xdev
->close_percent
* 10 * wdd
->timeout
;
79 spin_lock(&xdev
->spinlock
);
81 iowrite32(XWWDT_MWR_MASK
, xdev
->base
+ XWWDT_MWR_OFFSET
);
82 iowrite32(~(u32
)XWWDT_ESR_WEN_MASK
, xdev
->base
+ XWWDT_ESR_OFFSET
);
83 iowrite32((u32
)closed_timeout
, xdev
->base
+ XWWDT_FWR_OFFSET
);
84 iowrite32((u32
)open_timeout
, xdev
->base
+ XWWDT_SWR_OFFSET
);
86 /* Enable the window watchdog timer */
87 control_status_reg
= ioread32(xdev
->base
+ XWWDT_ESR_OFFSET
);
88 control_status_reg
|= XWWDT_ESR_WEN_MASK
;
89 iowrite32(control_status_reg
, xdev
->base
+ XWWDT_ESR_OFFSET
);
91 spin_unlock(&xdev
->spinlock
);
93 dev_dbg(xilinx_wwdt_wdd
->parent
, "Watchdog Started!\n");
98 static int xilinx_wwdt_keepalive(struct watchdog_device
*wdd
)
100 struct xwwdt_device
*xdev
= watchdog_get_drvdata(wdd
);
101 u32 control_status_reg
;
103 spin_lock(&xdev
->spinlock
);
105 /* Enable write access control bit for the window watchdog */
106 iowrite32(XWWDT_MWR_MASK
, xdev
->base
+ XWWDT_MWR_OFFSET
);
108 /* Trigger restart kick to watchdog */
109 control_status_reg
= ioread32(xdev
->base
+ XWWDT_ESR_OFFSET
);
110 control_status_reg
|= XWWDT_ESR_WSW_MASK
;
111 iowrite32(control_status_reg
, xdev
->base
+ XWWDT_ESR_OFFSET
);
113 spin_unlock(&xdev
->spinlock
);
118 static const struct watchdog_info xilinx_wwdt_ident
= {
119 .options
= WDIOF_KEEPALIVEPING
|
121 .firmware_version
= 1,
122 .identity
= "xlnx_window watchdog",
125 static const struct watchdog_ops xilinx_wwdt_ops
= {
126 .owner
= THIS_MODULE
,
127 .start
= xilinx_wwdt_start
,
128 .ping
= xilinx_wwdt_keepalive
,
131 static int xwwdt_probe(struct platform_device
*pdev
)
133 struct watchdog_device
*xilinx_wwdt_wdd
;
134 struct device
*dev
= &pdev
->dev
;
135 struct xwwdt_device
*xdev
;
139 xdev
= devm_kzalloc(dev
, sizeof(*xdev
), GFP_KERNEL
);
143 xilinx_wwdt_wdd
= &xdev
->xilinx_wwdt_wdd
;
144 xilinx_wwdt_wdd
->info
= &xilinx_wwdt_ident
;
145 xilinx_wwdt_wdd
->ops
= &xilinx_wwdt_ops
;
146 xilinx_wwdt_wdd
->parent
= dev
;
148 xdev
->base
= devm_platform_ioremap_resource(pdev
, 0);
149 if (IS_ERR(xdev
->base
))
150 return PTR_ERR(xdev
->base
);
152 clk
= devm_clk_get_enabled(dev
, NULL
);
156 xdev
->freq
= clk_get_rate(clk
);
160 xilinx_wwdt_wdd
->min_timeout
= XWWDT_MIN_TIMEOUT
;
161 xilinx_wwdt_wdd
->timeout
= XWWDT_DEFAULT_TIMEOUT
;
162 xilinx_wwdt_wdd
->max_hw_heartbeat_ms
= 1000 * xilinx_wwdt_wdd
->timeout
;
164 if (closed_window_percent
== 0 || closed_window_percent
>= 100)
165 xdev
->close_percent
= XWWDT_CLOSE_WINDOW_PERCENT
;
167 xdev
->close_percent
= closed_window_percent
;
169 watchdog_init_timeout(xilinx_wwdt_wdd
, wwdt_timeout
, &pdev
->dev
);
170 spin_lock_init(&xdev
->spinlock
);
171 watchdog_set_drvdata(xilinx_wwdt_wdd
, xdev
);
172 watchdog_set_nowayout(xilinx_wwdt_wdd
, 1);
174 ret
= devm_watchdog_register_device(dev
, xilinx_wwdt_wdd
);
178 dev_info(dev
, "Xilinx window watchdog Timer with timeout %ds\n",
179 xilinx_wwdt_wdd
->timeout
);
184 static const struct of_device_id xwwdt_of_match
[] = {
185 { .compatible
= "xlnx,versal-wwdt", },
188 MODULE_DEVICE_TABLE(of
, xwwdt_of_match
);
190 static struct platform_driver xwwdt_driver
= {
191 .probe
= xwwdt_probe
,
193 .name
= "Xilinx window watchdog",
194 .of_match_table
= xwwdt_of_match
,
198 module_platform_driver(xwwdt_driver
);
200 MODULE_AUTHOR("Neeli Srinivas <srinivas.neeli@amd.com>");
201 MODULE_DESCRIPTION("Xilinx window watchdog driver");
202 MODULE_LICENSE("GPL");