1
2
3
4
5
6#include <common.h>
7#include <cpu_func.h>
8#include <asm/io.h>
9#include <asm/arch/imx-regs.h>
10#include <dm.h>
11#include <wdt.h>
12
13
14
15
16struct wdog_regs {
17 u32 cs;
18 u32 cnt;
19 u32 toval;
20 u32 win;
21};
22
23struct ulp_wdt_priv {
24 struct wdog_regs *wdog;
25 u32 clk_rate;
26};
27
28#define REFRESH_WORD0 0xA602
29#define REFRESH_WORD1 0xB480
30
31#define UNLOCK_WORD0 0xC520
32#define UNLOCK_WORD1 0xD928
33
34#define UNLOCK_WORD 0xD928C520
35#define REFRESH_WORD 0xB480A602
36
37#define WDGCS_WDGE BIT(7)
38#define WDGCS_WDGUPDATE BIT(5)
39
40#define WDGCS_RCS BIT(10)
41#define WDGCS_ULK BIT(11)
42#define WDOG_CS_PRES BIT(12)
43#define WDGCS_CMD32EN BIT(13)
44#define WDGCS_FLG BIT(14)
45#define WDGCS_INT BIT(6)
46
47#define WDG_BUS_CLK (0x0)
48#define WDG_LPO_CLK (0x1)
49#define WDG_32KHZ_CLK (0x2)
50#define WDG_EXT_CLK (0x3)
51
52#define CLK_RATE_1KHZ 1000
53#define CLK_RATE_32KHZ 125
54
55void hw_watchdog_set_timeout(u16 val)
56{
57
58 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
59
60 writel(val, &wdog->toval);
61}
62
63void ulp_watchdog_reset(struct wdog_regs *wdog)
64{
65 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
66 writel(REFRESH_WORD, &wdog->cnt);
67 } else {
68 dmb();
69 __raw_writel(REFRESH_WORD0, &wdog->cnt);
70 __raw_writel(REFRESH_WORD1, &wdog->cnt);
71 dmb();
72 }
73}
74
75void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout)
76{
77 u32 cmd32 = 0;
78
79 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
80 writel(UNLOCK_WORD, &wdog->cnt);
81 cmd32 = WDGCS_CMD32EN;
82 } else {
83 dmb();
84 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
85 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
86 dmb();
87 }
88
89
90 while (!(readl(&wdog->cs) & WDGCS_ULK))
91 ;
92
93 hw_watchdog_set_timeout(timeout);
94 writel(0, &wdog->win);
95
96
97 if (IS_ENABLED(CONFIG_ARCH_IMX9))
98 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
99 WDGCS_FLG | WDOG_CS_PRES | WDGCS_INT), &wdog->cs);
100 else
101 writel((cmd32 | WDGCS_WDGE | WDGCS_WDGUPDATE | (WDG_LPO_CLK << 8) |
102 WDGCS_FLG), &wdog->cs);
103
104
105 while (!(readl(&wdog->cs) & WDGCS_RCS))
106 ;
107
108 ulp_watchdog_reset(wdog);
109}
110
111void hw_watchdog_reset(void)
112{
113 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
114
115 ulp_watchdog_reset(wdog);
116}
117
118void hw_watchdog_init(void)
119{
120 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
121
122 ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS);
123}
124
125void reset_cpu(void)
126{
127 struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
128 u32 cmd32 = 0;
129
130 if (readl(&wdog->cs) & WDGCS_CMD32EN) {
131 writel(UNLOCK_WORD, &wdog->cnt);
132 cmd32 = WDGCS_CMD32EN;
133 } else {
134 dmb();
135 __raw_writel(UNLOCK_WORD0, &wdog->cnt);
136 __raw_writel(UNLOCK_WORD1, &wdog->cnt);
137 dmb();
138 }
139
140
141 while (!(readl(&wdog->cs) & WDGCS_ULK))
142 ;
143
144 hw_watchdog_set_timeout(5);
145 writel(0, &wdog->win);
146
147
148 if (IS_ENABLED(CONFIG_ARCH_IMX9))
149 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES |
150 WDGCS_INT), &wdog->cs);
151 else
152 writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs);
153
154
155 while (!(readl(&wdog->cs) & WDGCS_RCS))
156 ;
157
158 hw_watchdog_reset();
159
160 while (1);
161}
162
163static int ulp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
164{
165 struct ulp_wdt_priv *priv = dev_get_priv(dev);
166 u64 timeout = 0;
167
168 timeout = (timeout_ms * priv->clk_rate) / 1000;
169 if (timeout > U16_MAX)
170 return -EINVAL;
171
172 ulp_watchdog_init(priv->wdog, (u16)timeout);
173
174 return 0;
175}
176
177static int ulp_wdt_reset(struct udevice *dev)
178{
179 struct ulp_wdt_priv *priv = dev_get_priv(dev);
180
181 ulp_watchdog_reset(priv->wdog);
182
183 return 0;
184}
185
186static int ulp_wdt_probe(struct udevice *dev)
187{
188 struct ulp_wdt_priv *priv = dev_get_priv(dev);
189
190 priv->wdog = dev_read_addr_ptr(dev);
191 if (!priv->wdog)
192 return -EINVAL;
193
194 priv->clk_rate = (u32)dev_get_driver_data(dev);
195 if (!priv->clk_rate)
196 return -EINVAL;
197
198 return 0;
199}
200
201static const struct wdt_ops ulp_wdt_ops = {
202 .start = ulp_wdt_start,
203 .reset = ulp_wdt_reset,
204};
205
206static const struct udevice_id ulp_wdt_ids[] = {
207 { .compatible = "fsl,imx7ulp-wdt", .data = CLK_RATE_1KHZ },
208 { .compatible = "fsl,imx8ulp-wdt", .data = CLK_RATE_1KHZ },
209 { .compatible = "fsl,imx93-wdt", .data = CLK_RATE_32KHZ },
210 {}
211};
212
213U_BOOT_DRIVER(ulp_wdt) = {
214 .name = "ulp_wdt",
215 .id = UCLASS_WDT,
216 .of_match = ulp_wdt_ids,
217 .priv_auto = sizeof(struct ulp_wdt_priv),
218 .probe = ulp_wdt_probe,
219 .ops = &ulp_wdt_ops,
220};
221