1
2
3
4
5
6#define LOG_CATEGORY UCLASS_WDT
7
8#include <common.h>
9#include <clk.h>
10#include <dm.h>
11#include <log.h>
12#include <syscon.h>
13#include <wdt.h>
14#include <asm/io.h>
15#include <dm/device_compat.h>
16#include <linux/bitops.h>
17#include <linux/iopoll.h>
18
19
20#define IWDG_KR 0x00
21#define IWDG_PR 0x04
22#define IWDG_RLR 0x08
23#define IWDG_SR 0x0C
24
25
26#define KR_KEY_RELOAD 0xAAAA
27#define KR_KEY_ENABLE 0xCCCC
28#define KR_KEY_EWA 0x5555
29
30
31#define PR_256 0x06
32
33
34#define RLR_MAX 0xFFF
35
36
37#define SR_PVU BIT(0)
38#define SR_RVU BIT(1)
39
40struct stm32mp_wdt_priv {
41 fdt_addr_t base;
42 unsigned long wdt_clk_rate;
43};
44
45static int stm32mp_wdt_reset(struct udevice *dev)
46{
47 struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
48
49 writel(KR_KEY_RELOAD, priv->base + IWDG_KR);
50
51 return 0;
52}
53
54static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
55{
56 struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
57 int reload;
58 u32 val;
59 int ret;
60
61
62 reload = timeout_ms * priv->wdt_clk_rate / 256;
63 if (reload > RLR_MAX + 1)
64
65 reload = RLR_MAX + 1;
66 else if (!reload)
67
68 reload = priv->wdt_clk_rate / 256;
69
70
71 writel(KR_KEY_EWA, priv->base + IWDG_KR);
72 writel(PR_256, priv->base + IWDG_PR);
73 writel(reload - 1, priv->base + IWDG_RLR);
74
75
76 writel(KR_KEY_ENABLE, priv->base + IWDG_KR);
77
78
79 ret = readl_poll_timeout(priv->base + IWDG_SR, val,
80 val & (SR_PVU | SR_RVU), CONFIG_SYS_HZ);
81
82 if (ret < 0) {
83 dev_err(dev, "Updating IWDG registers timeout");
84 return -ETIMEDOUT;
85 }
86
87 return 0;
88}
89
90static int stm32mp_wdt_probe(struct udevice *dev)
91{
92 struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
93 struct clk clk;
94 int ret;
95
96 dev_dbg(dev, "IWDG init\n");
97
98 priv->base = dev_read_addr(dev);
99 if (priv->base == FDT_ADDR_T_NONE)
100 return -EINVAL;
101
102
103 ret = clk_get_by_name(dev, "pclk", &clk);
104 if (ret)
105 return ret;
106
107 ret = clk_enable(&clk);
108 if (ret)
109 return ret;
110
111
112 ret = clk_get_by_name(dev, "lsi", &clk);
113 if (ret)
114 return ret;
115
116 priv->wdt_clk_rate = clk_get_rate(&clk);
117
118 dev_dbg(dev, "IWDG init done\n");
119
120 return 0;
121}
122
123static const struct wdt_ops stm32mp_wdt_ops = {
124 .start = stm32mp_wdt_start,
125 .reset = stm32mp_wdt_reset,
126};
127
128static const struct udevice_id stm32mp_wdt_match[] = {
129 { .compatible = "st,stm32mp1-iwdg" },
130 { }
131};
132
133U_BOOT_DRIVER(stm32mp_wdt) = {
134 .name = "stm32mp-wdt",
135 .id = UCLASS_WDT,
136 .of_match = stm32mp_wdt_match,
137 .priv_auto = sizeof(struct stm32mp_wdt_priv),
138 .probe = stm32mp_wdt_probe,
139 .ops = &stm32mp_wdt_ops,
140};
141