1 // SPDX-License-Identifier: GPL-2.0
3 * Xilinx window watchdog timer driver.
5 * Author(s): Michal Simek <michal.simek@xilinx.com>
6 * Ashok Reddy Soma <ashokred@xilinx.com>
8 * Copyright (c) 2020, Xilinx Inc.
16 #include <linux/compat.h>
19 /* Refresh Register Masks */
20 #define XWT_WWREF_GWRR_MASK BIT(0) /* Refresh and start new period */
22 /* Generic Control/Status Register Masks */
23 #define XWT_WWCSR_GWEN_MASK BIT(0) /* Enable Bit */
25 /* Register offsets for the Wdt device */
26 #define XWT_WWREF_OFFSET 0x1000 /* Refresh Register */
27 #define XWT_WWCSR_OFFSET 0x2000 /* Control/Status Register */
28 #define XWT_WWOFF_OFFSET 0x2008 /* Offset Register */
29 #define XWT_WWCMP0_OFFSET 0x2010 /* Compare Value Register0 */
30 #define XWT_WWCMP1_OFFSET 0x2014 /* Compare Value Register1 */
31 #define XWT_WWWRST_OFFSET 0x2FD0 /* Warm Reset Register */
33 struct xlnx_wwdt_priv {
39 struct xlnx_wwdt_plat {
43 static int xlnx_wwdt_reset(struct udevice *dev)
45 struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
47 regmap_write(wdt->regs, XWT_WWREF_OFFSET, XWT_WWREF_GWRR_MASK);
52 static int xlnx_wwdt_stop(struct udevice *dev)
55 struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
57 if (wdt->enable_once) {
58 dev_warn(dev, "Can't stop Xilinx watchdog.\n");
62 /* Disable the generic watchdog timer */
63 regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
64 csr &= ~(XWT_WWCSR_GWEN_MASK);
65 regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
67 clk_disable(&wdt->clk);
69 dev_dbg(dev, "Watchdog disabled!\n");
74 static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags)
79 unsigned long clock_f;
80 struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
82 clock_f = clk_get_rate(&wdt->clk);
83 if (IS_ERR_VALUE(clock_f)) {
84 dev_err(dev, "failed to get rate\n");
88 dev_dbg(dev, "%s: CLK %ld\n", __func__, clock_f);
90 /* Calculate timeout count */
91 count = timeout * clock_f;
93 /* clk_enable will return -ENOSYS when it is not implemented */
94 ret = clk_enable(&wdt->clk);
95 if (ret && ret != -ENOSYS) {
96 dev_err(dev, "failed to enable clock\n");
101 * Timeout count is half as there are two windows
102 * first window overflow is ignored (interrupt),
103 * reset is only generated at second window overflow
107 /* Disable the generic watchdog timer */
108 regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
109 csr &= ~(XWT_WWCSR_GWEN_MASK);
110 regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
112 /* Set compare and offset registers for generic watchdog timeout */
113 regmap_write(wdt->regs, XWT_WWCMP0_OFFSET, (u32)count);
114 regmap_write(wdt->regs, XWT_WWCMP1_OFFSET, 0);
115 regmap_write(wdt->regs, XWT_WWOFF_OFFSET, (u32)count);
117 /* Enable the generic watchdog timer */
118 regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
119 csr |= (XWT_WWCSR_GWEN_MASK);
120 regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
125 static int xlnx_wwdt_probe(struct udevice *dev)
128 struct xlnx_wwdt_plat *plat = dev_get_plat(dev);
129 struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
131 dev_dbg(dev, "%s: Probing wdt%u\n", __func__, dev_seq(dev));
133 ret = regmap_init_mem(dev_ofnode(dev), &wdt->regs);
135 dev_dbg(dev, "failed to get regbase of wwdt\n");
139 wdt->enable_once = plat->enable_once;
141 ret = clk_get_by_index(dev, 0, &wdt->clk);
143 dev_err(dev, "failed to get clock\n");
148 static int xlnx_wwdt_of_to_plat(struct udevice *dev)
150 struct xlnx_wwdt_plat *plat = dev_get_plat(dev);
152 plat->enable_once = dev_read_u32_default(dev, "xlnx,wdt-enable-once",
154 dev_dbg(dev, "wdt-enable-once %d\n", plat->enable_once);
159 static const struct wdt_ops xlnx_wwdt_ops = {
160 .start = xlnx_wwdt_start,
161 .reset = xlnx_wwdt_reset,
162 .stop = xlnx_wwdt_stop,
165 static const struct udevice_id xlnx_wwdt_ids[] = {
166 { .compatible = "xlnx,versal-wwdt-1.0", },
170 U_BOOT_DRIVER(xlnx_wwdt) = {
173 .of_match = xlnx_wwdt_ids,
174 .probe = xlnx_wwdt_probe,
175 .priv_auto = sizeof(struct xlnx_wwdt_priv),
176 .plat_auto = sizeof(struct xlnx_wwdt_plat),
177 .of_to_plat = xlnx_wwdt_of_to_plat,
178 .ops = &xlnx_wwdt_ops,