14
14
#include <linux/watchdog.h>
15
15
16
16
#define WDOG_CS 0x0
17
+ #define WDOG_CS_FLG BIT(14)
17
18
#define WDOG_CS_CMD32EN BIT(13)
19
+ #define WDOG_CS_PRES BIT(12)
18
20
#define WDOG_CS_ULK BIT(11)
19
21
#define WDOG_CS_RCS BIT(10)
20
22
#define LPO_CLK 0x1
39
41
#define DEFAULT_TIMEOUT 60
40
42
#define MAX_TIMEOUT 128
41
43
#define WDOG_CLOCK_RATE 1000
42
- #define WDOG_WAIT_TIMEOUT 10000
44
+ #define WDOG_ULK_WAIT_TIMEOUT 1000
45
+ #define WDOG_RCS_WAIT_TIMEOUT 10000
46
+ #define WDOG_RCS_POST_WAIT 3000
47
+
48
+ #define RETRY_MAX 5
43
49
44
50
static bool nowayout = WATCHDOG_NOWAYOUT ;
45
51
module_param (nowayout , bool , 0000 );
@@ -50,40 +56,82 @@ struct imx7ulp_wdt_device {
50
56
struct watchdog_device wdd ;
51
57
void __iomem * base ;
52
58
struct clk * clk ;
59
+ bool post_rcs_wait ;
53
60
};
54
61
55
- static int imx7ulp_wdt_wait (void __iomem * base , u32 mask )
62
+ static int imx7ulp_wdt_wait_ulk (void __iomem * base )
56
63
{
57
64
u32 val = readl (base + WDOG_CS );
58
65
59
- if (!(val & mask ) && readl_poll_timeout_atomic (base + WDOG_CS , val ,
60
- val & mask , 0 ,
61
- WDOG_WAIT_TIMEOUT ))
66
+ if (!(val & WDOG_CS_ULK ) &&
67
+ readl_poll_timeout_atomic (base + WDOG_CS , val ,
68
+ val & WDOG_CS_ULK , 0 ,
69
+ WDOG_ULK_WAIT_TIMEOUT ))
62
70
return - ETIMEDOUT ;
63
71
64
72
return 0 ;
65
73
}
66
74
67
- static int imx7ulp_wdt_enable (struct watchdog_device * wdog , bool enable )
75
+ static int imx7ulp_wdt_wait_rcs (struct imx7ulp_wdt_device * wdt )
68
76
{
69
- struct imx7ulp_wdt_device * wdt = watchdog_get_drvdata (wdog );
77
+ int ret = 0 ;
78
+ u32 val = readl (wdt -> base + WDOG_CS );
79
+ u64 timeout = (val & WDOG_CS_PRES ) ?
80
+ WDOG_RCS_WAIT_TIMEOUT * 256 : WDOG_RCS_WAIT_TIMEOUT ;
81
+ unsigned long wait_min = (val & WDOG_CS_PRES ) ?
82
+ WDOG_RCS_POST_WAIT * 256 : WDOG_RCS_POST_WAIT ;
70
83
84
+ if (!(val & WDOG_CS_RCS ) &&
85
+ readl_poll_timeout (wdt -> base + WDOG_CS , val , val & WDOG_CS_RCS , 100 ,
86
+ timeout ))
87
+ ret = - ETIMEDOUT ;
88
+
89
+ /* Wait 2.5 clocks after RCS done */
90
+ if (wdt -> post_rcs_wait )
91
+ usleep_range (wait_min , wait_min + 2000 );
92
+
93
+ return ret ;
94
+ }
95
+
96
+ static int _imx7ulp_wdt_enable (struct imx7ulp_wdt_device * wdt , bool enable )
97
+ {
71
98
u32 val = readl (wdt -> base + WDOG_CS );
72
99
int ret ;
73
100
74
101
local_irq_disable ();
75
102
writel (UNLOCK , wdt -> base + WDOG_CNT );
76
- ret = imx7ulp_wdt_wait (wdt -> base , WDOG_CS_ULK );
103
+ ret = imx7ulp_wdt_wait_ulk (wdt -> base );
77
104
if (ret )
78
105
goto enable_out ;
79
106
if (enable )
80
107
writel (val | WDOG_CS_EN , wdt -> base + WDOG_CS );
81
108
else
82
109
writel (val & ~WDOG_CS_EN , wdt -> base + WDOG_CS );
83
- ret = imx7ulp_wdt_wait (wdt -> base , WDOG_CS_RCS );
110
+
111
+ local_irq_enable ();
112
+ ret = imx7ulp_wdt_wait_rcs (wdt );
113
+
114
+ return ret ;
84
115
85
116
enable_out :
86
117
local_irq_enable ();
118
+ return ret ;
119
+ }
120
+
121
+ static int imx7ulp_wdt_enable (struct watchdog_device * wdog , bool enable )
122
+ {
123
+ struct imx7ulp_wdt_device * wdt = watchdog_get_drvdata (wdog );
124
+ int ret ;
125
+ u32 val ;
126
+ u32 loop = RETRY_MAX ;
127
+
128
+ do {
129
+ ret = _imx7ulp_wdt_enable (wdt , enable );
130
+ val = readl (wdt -> base + WDOG_CS );
131
+ } while (-- loop > 0 && ((!!(val & WDOG_CS_EN )) != enable || ret ));
132
+
133
+ if (loop == 0 )
134
+ return - EBUSY ;
87
135
88
136
return ret ;
89
137
}
@@ -114,28 +162,44 @@ static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
114
162
return imx7ulp_wdt_enable (wdog , false);
115
163
}
116
164
117
- static int imx7ulp_wdt_set_timeout (struct watchdog_device * wdog ,
118
- unsigned int timeout )
165
+ static int _imx7ulp_wdt_set_timeout (struct imx7ulp_wdt_device * wdt ,
166
+ unsigned int toval )
119
167
{
120
- struct imx7ulp_wdt_device * wdt = watchdog_get_drvdata (wdog );
121
- u32 val = WDOG_CLOCK_RATE * timeout ;
122
168
int ret ;
123
169
124
170
local_irq_disable ();
125
171
writel (UNLOCK , wdt -> base + WDOG_CNT );
126
- ret = imx7ulp_wdt_wait (wdt -> base , WDOG_CS_ULK );
172
+ ret = imx7ulp_wdt_wait_ulk (wdt -> base );
127
173
if (ret )
128
174
goto timeout_out ;
129
- writel (val , wdt -> base + WDOG_TOVAL );
130
- ret = imx7ulp_wdt_wait (wdt -> base , WDOG_CS_RCS );
131
- if (ret )
132
- goto timeout_out ;
133
-
134
- wdog -> timeout = timeout ;
175
+ writel (toval , wdt -> base + WDOG_TOVAL );
176
+ local_irq_enable ();
177
+ ret = imx7ulp_wdt_wait_rcs (wdt );
178
+ return ret ;
135
179
136
180
timeout_out :
137
181
local_irq_enable ();
182
+ return ret ;
183
+ }
138
184
185
+ static int imx7ulp_wdt_set_timeout (struct watchdog_device * wdog ,
186
+ unsigned int timeout )
187
+ {
188
+ struct imx7ulp_wdt_device * wdt = watchdog_get_drvdata (wdog );
189
+ u32 toval = WDOG_CLOCK_RATE * timeout ;
190
+ u32 val ;
191
+ int ret ;
192
+ u32 loop = RETRY_MAX ;
193
+
194
+ do {
195
+ ret = _imx7ulp_wdt_set_timeout (wdt , toval );
196
+ val = readl (wdt -> base + WDOG_TOVAL );
197
+ } while (-- loop > 0 && (val != toval || ret ));
198
+
199
+ if (loop == 0 )
200
+ return - EBUSY ;
201
+
202
+ wdog -> timeout = timeout ;
139
203
return ret ;
140
204
}
141
205
@@ -175,38 +239,59 @@ static const struct watchdog_info imx7ulp_wdt_info = {
175
239
WDIOF_MAGICCLOSE ,
176
240
};
177
241
178
- static int imx7ulp_wdt_init ( void __iomem * base , unsigned int timeout )
242
+ static int _imx7ulp_wdt_init ( struct imx7ulp_wdt_device * wdt , unsigned int timeout , unsigned int cs )
179
243
{
180
244
u32 val ;
181
245
int ret ;
182
246
183
247
local_irq_disable ();
184
248
185
- val = readl (base + WDOG_CS );
249
+ val = readl (wdt -> base + WDOG_CS );
186
250
if (val & WDOG_CS_CMD32EN ) {
187
- writel (UNLOCK , base + WDOG_CNT );
251
+ writel (UNLOCK , wdt -> base + WDOG_CNT );
188
252
} else {
189
253
mb ();
190
254
/* unlock the wdog for reconfiguration */
191
- writel_relaxed (UNLOCK_SEQ0 , base + WDOG_CNT );
192
- writel_relaxed (UNLOCK_SEQ1 , base + WDOG_CNT );
255
+ writel_relaxed (UNLOCK_SEQ0 , wdt -> base + WDOG_CNT );
256
+ writel_relaxed (UNLOCK_SEQ1 , wdt -> base + WDOG_CNT );
193
257
mb ();
194
258
}
195
259
196
- ret = imx7ulp_wdt_wait ( base , WDOG_CS_ULK );
260
+ ret = imx7ulp_wdt_wait_ulk ( wdt -> base );
197
261
if (ret )
198
262
goto init_out ;
199
263
200
264
/* set an initial timeout value in TOVAL */
201
- writel (timeout , base + WDOG_TOVAL );
202
- /* enable 32bit command sequence and reconfigure */
203
- val = WDOG_CS_CMD32EN | WDOG_CS_CLK | WDOG_CS_UPDATE |
204
- WDOG_CS_WAIT | WDOG_CS_STOP ;
205
- writel ( val , base + WDOG_CS );
206
- imx7ulp_wdt_wait ( base , WDOG_CS_RCS ) ;
265
+ writel (timeout , wdt -> base + WDOG_TOVAL );
266
+ writel ( cs , wdt -> base + WDOG_CS );
267
+ local_irq_enable ();
268
+ ret = imx7ulp_wdt_wait_rcs ( wdt ) ;
269
+
270
+ return ret ;
207
271
208
272
init_out :
209
273
local_irq_enable ();
274
+ return ret ;
275
+ }
276
+
277
+ static int imx7ulp_wdt_init (struct imx7ulp_wdt_device * wdt , unsigned int timeout )
278
+ {
279
+ /* enable 32bit command sequence and reconfigure */
280
+ u32 val = WDOG_CS_CMD32EN | WDOG_CS_CLK | WDOG_CS_UPDATE |
281
+ WDOG_CS_WAIT | WDOG_CS_STOP ;
282
+ u32 cs , toval ;
283
+ int ret ;
284
+ u32 loop = RETRY_MAX ;
285
+
286
+ do {
287
+ ret = _imx7ulp_wdt_init (wdt , timeout , val );
288
+ toval = readl (wdt -> base + WDOG_TOVAL );
289
+ cs = readl (wdt -> base + WDOG_CS );
290
+ cs &= ~(WDOG_CS_FLG | WDOG_CS_ULK | WDOG_CS_RCS );
291
+ } while (-- loop > 0 && (cs != val || toval != timeout || ret ));
292
+
293
+ if (loop == 0 )
294
+ return - EBUSY ;
210
295
211
296
return ret ;
212
297
}
@@ -239,6 +324,15 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
239
324
return PTR_ERR (imx7ulp_wdt -> clk );
240
325
}
241
326
327
+ imx7ulp_wdt -> post_rcs_wait = true;
328
+ if (of_device_is_compatible (dev -> of_node ,
329
+ "fsl,imx8ulp-wdt" )) {
330
+ dev_info (dev , "imx8ulp wdt probe\n" );
331
+ imx7ulp_wdt -> post_rcs_wait = false;
332
+ } else {
333
+ dev_info (dev , "imx7ulp wdt probe\n" );
334
+ }
335
+
242
336
ret = clk_prepare_enable (imx7ulp_wdt -> clk );
243
337
if (ret )
244
338
return ret ;
@@ -259,7 +353,7 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
259
353
watchdog_stop_on_reboot (wdog );
260
354
watchdog_stop_on_unregister (wdog );
261
355
watchdog_set_drvdata (wdog , imx7ulp_wdt );
262
- ret = imx7ulp_wdt_init (imx7ulp_wdt -> base , wdog -> timeout * WDOG_CLOCK_RATE );
356
+ ret = imx7ulp_wdt_init (imx7ulp_wdt , wdog -> timeout * WDOG_CLOCK_RATE );
263
357
if (ret )
264
358
return ret ;
265
359
@@ -289,7 +383,7 @@ static int __maybe_unused imx7ulp_wdt_resume_noirq(struct device *dev)
289
383
return ret ;
290
384
291
385
if (imx7ulp_wdt_is_enabled (imx7ulp_wdt -> base ))
292
- imx7ulp_wdt_init (imx7ulp_wdt -> base , timeout );
386
+ imx7ulp_wdt_init (imx7ulp_wdt , timeout );
293
387
294
388
if (watchdog_active (& imx7ulp_wdt -> wdd ))
295
389
imx7ulp_wdt_start (& imx7ulp_wdt -> wdd );
@@ -303,6 +397,7 @@ static const struct dev_pm_ops imx7ulp_wdt_pm_ops = {
303
397
};
304
398
305
399
static const struct of_device_id imx7ulp_wdt_dt_ids [] = {
400
+ { .compatible = "fsl,imx8ulp-wdt" , },
306
401
{ .compatible = "fsl,imx7ulp-wdt" , },
307
402
{ /* sentinel */ }
308
403
};
0 commit comments