Commit df12804da9664932179d3322c085b1d10fadce33
Committed by
Priyanka Jain
1 parent
a2c60b6733
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
Watchdog: introduce ARM SBSA watchdog driver
According to Server Base System Architecture (SBSA) specification, the SBSA Generic Watchdog has two stage timeouts: the first signal (WS0) is for alerting the system by interrupt, the second one (WS1) is a real hardware reset. More details about the hardware specification of this device: ARM DEN0029B - Server Base System Architecture (SBSA) This driver can operate ARM SBSA Generic Watchdog as a single stage In the single stage mode, when the timeout is reached, your system will be reset by WS1. The first signal (WS0) is ignored. Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com> Signed-off-by: Biwen Li <biwen.li@nxp.com> Reviewed-by: Stefan Roese <sr@denx.de>
Showing 4 changed files with 142 additions and 0 deletions Side-by-side Diff
MAINTAINERS
drivers/watchdog/Kconfig
... | ... | @@ -162,6 +162,15 @@ |
162 | 162 | can be probed and supports all of the methods of WDT, but does not |
163 | 163 | really do anything. |
164 | 164 | |
165 | +config WDT_SBSA | |
166 | + bool "SBSA watchdog timer support" | |
167 | + depends on WDT | |
168 | + help | |
169 | + Select this to enable SBSA watchdog timer. | |
170 | + This driver can operate ARM SBSA Generic Watchdog as a single stage. | |
171 | + In the single stage mode, when the timeout is reached, your system | |
172 | + will be reset by WS1. The first signal (WS0) is ignored. | |
173 | + | |
165 | 174 | config WDT_SP805 |
166 | 175 | bool "SP805 watchdog timer support" |
167 | 176 | depends on WDT |
drivers/watchdog/Makefile
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o |
28 | 28 | obj-$(CONFIG_WDT_MTK) += mtk_wdt.o |
29 | 29 | obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o |
30 | +obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o | |
30 | 31 | obj-$(CONFIG_WDT_SP805) += sp805_wdt.o |
31 | 32 | obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o |
32 | 33 | obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o |
drivers/watchdog/sbsa_gwdt.c
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * Watchdog driver for SBSA | |
4 | + * | |
5 | + * Copyright 2020 NXP | |
6 | + */ | |
7 | + | |
8 | +#include <asm/io.h> | |
9 | +#include <common.h> | |
10 | +#include <dm/device.h> | |
11 | +#include <dm/fdtaddr.h> | |
12 | +#include <dm/read.h> | |
13 | +#include <linux/bitops.h> | |
14 | +#include <linux/err.h> | |
15 | +#include <watchdog.h> | |
16 | +#include <wdt.h> | |
17 | + | |
18 | +DECLARE_GLOBAL_DATA_PTR; | |
19 | + | |
20 | +/* SBSA Generic Watchdog register definitions */ | |
21 | +/* refresh frame */ | |
22 | +#define SBSA_GWDT_WRR 0x000 | |
23 | + | |
24 | +/* control frame */ | |
25 | +#define SBSA_GWDT_WCS 0x000 | |
26 | +#define SBSA_GWDT_WOR 0x008 | |
27 | +#define SBSA_GWDT_WCV 0x010 | |
28 | + | |
29 | +/* refresh/control frame */ | |
30 | +#define SBSA_GWDT_W_IIDR 0xfcc | |
31 | +#define SBSA_GWDT_IDR 0xfd0 | |
32 | + | |
33 | +/* Watchdog Control and Status Register */ | |
34 | +#define SBSA_GWDT_WCS_EN BIT(0) | |
35 | +#define SBSA_GWDT_WCS_WS0 BIT(1) | |
36 | +#define SBSA_GWDT_WCS_WS1 BIT(2) | |
37 | + | |
38 | +struct sbsa_gwdt_priv { | |
39 | + void __iomem *reg_refresh; | |
40 | + void __iomem *reg_control; | |
41 | +}; | |
42 | + | |
43 | +static int sbsa_gwdt_reset(struct udevice *dev) | |
44 | +{ | |
45 | + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); | |
46 | + | |
47 | + writel(0, priv->reg_refresh + SBSA_GWDT_WRR); | |
48 | + | |
49 | + return 0; | |
50 | +} | |
51 | + | |
52 | +static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) | |
53 | +{ | |
54 | + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); | |
55 | + u32 clk; | |
56 | + | |
57 | + /* | |
58 | + * it work in the single stage mode in u-boot, | |
59 | + * The first signal (WS0) is ignored, | |
60 | + * the timeout is (WOR * 2), so the WOR should be configured | |
61 | + * to half value of timeout. | |
62 | + */ | |
63 | + clk = get_tbclk(); | |
64 | + writel(clk / 2 * timeout, | |
65 | + priv->reg_control + SBSA_GWDT_WOR); | |
66 | + | |
67 | + /* writing WCS will cause an explicit watchdog refresh */ | |
68 | + writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); | |
69 | + | |
70 | + return 0; | |
71 | +} | |
72 | + | |
73 | +static int sbsa_gwdt_stop(struct udevice *dev) | |
74 | +{ | |
75 | + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); | |
76 | + | |
77 | + writel(0, priv->reg_control + SBSA_GWDT_WCS); | |
78 | + | |
79 | + return 0; | |
80 | +} | |
81 | + | |
82 | +static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags) | |
83 | +{ | |
84 | + sbsa_gwdt_start(dev, 0, flags); | |
85 | + | |
86 | + return 0; | |
87 | +} | |
88 | + | |
89 | +static int sbsa_gwdt_probe(struct udevice *dev) | |
90 | +{ | |
91 | + debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev->seq); | |
92 | + | |
93 | + return 0; | |
94 | +} | |
95 | + | |
96 | +static int sbsa_gwdt_ofdata_to_platdata(struct udevice *dev) | |
97 | +{ | |
98 | + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); | |
99 | + | |
100 | + priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0); | |
101 | + if (IS_ERR(priv->reg_control)) | |
102 | + return PTR_ERR(priv->reg_control); | |
103 | + | |
104 | + priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1); | |
105 | + if (IS_ERR(priv->reg_refresh)) | |
106 | + return PTR_ERR(priv->reg_refresh); | |
107 | + | |
108 | + return 0; | |
109 | +} | |
110 | + | |
111 | +static const struct wdt_ops sbsa_gwdt_ops = { | |
112 | + .start = sbsa_gwdt_start, | |
113 | + .reset = sbsa_gwdt_reset, | |
114 | + .stop = sbsa_gwdt_stop, | |
115 | + .expire_now = sbsa_gwdt_expire_now, | |
116 | +}; | |
117 | + | |
118 | +static const struct udevice_id sbsa_gwdt_ids[] = { | |
119 | + { .compatible = "arm,sbsa-gwdt" }, | |
120 | + {} | |
121 | +}; | |
122 | + | |
123 | +U_BOOT_DRIVER(sbsa_gwdt) = { | |
124 | + .name = "sbsa_gwdt", | |
125 | + .id = UCLASS_WDT, | |
126 | + .of_match = sbsa_gwdt_ids, | |
127 | + .probe = sbsa_gwdt_probe, | |
128 | + .priv_auto_alloc_size = sizeof(struct sbsa_gwdt_priv), | |
129 | + .ofdata_to_platdata = sbsa_gwdt_ofdata_to_platdata, | |
130 | + .ops = &sbsa_gwdt_ops, | |
131 | +}; |