.. | .. |
---|
34 | 34 | #define KR_KEY_EWA 0x5555 /* write access enable */ |
---|
35 | 35 | #define KR_KEY_DWA 0x0000 /* write access disable */ |
---|
36 | 36 | |
---|
37 | | -/* IWDG_PR register bit values */ |
---|
38 | | -#define PR_4 0x00 /* prescaler set to 4 */ |
---|
39 | | -#define PR_8 0x01 /* prescaler set to 8 */ |
---|
40 | | -#define PR_16 0x02 /* prescaler set to 16 */ |
---|
41 | | -#define PR_32 0x03 /* prescaler set to 32 */ |
---|
42 | | -#define PR_64 0x04 /* prescaler set to 64 */ |
---|
43 | | -#define PR_128 0x05 /* prescaler set to 128 */ |
---|
44 | | -#define PR_256 0x06 /* prescaler set to 256 */ |
---|
| 37 | +/* IWDG_PR register */ |
---|
| 38 | +#define PR_SHIFT 2 |
---|
| 39 | +#define PR_MIN BIT(PR_SHIFT) |
---|
45 | 40 | |
---|
46 | 41 | /* IWDG_RLR register values */ |
---|
47 | | -#define RLR_MIN 0x07C /* min value supported by reload register */ |
---|
48 | | -#define RLR_MAX 0xFFF /* max value supported by reload register */ |
---|
| 42 | +#define RLR_MIN 0x2 /* min value recommended */ |
---|
| 43 | +#define RLR_MAX GENMASK(11, 0) /* max value of reload register */ |
---|
49 | 44 | |
---|
50 | 45 | /* IWDG_SR register bit mask */ |
---|
51 | | -#define FLAG_PVU BIT(0) /* Watchdog prescaler value update */ |
---|
52 | | -#define FLAG_RVU BIT(1) /* Watchdog counter reload value update */ |
---|
| 46 | +#define SR_PVU BIT(0) /* Watchdog prescaler value update */ |
---|
| 47 | +#define SR_RVU BIT(1) /* Watchdog counter reload value update */ |
---|
53 | 48 | |
---|
54 | 49 | /* set timeout to 100000 us */ |
---|
55 | 50 | #define TIMEOUT_US 100000 |
---|
56 | 51 | #define SLEEP_US 1000 |
---|
57 | 52 | |
---|
58 | | -#define HAS_PCLK true |
---|
| 53 | +struct stm32_iwdg_data { |
---|
| 54 | + bool has_pclk; |
---|
| 55 | + u32 max_prescaler; |
---|
| 56 | +}; |
---|
| 57 | + |
---|
| 58 | +static const struct stm32_iwdg_data stm32_iwdg_data = { |
---|
| 59 | + .has_pclk = false, |
---|
| 60 | + .max_prescaler = 256, |
---|
| 61 | +}; |
---|
| 62 | + |
---|
| 63 | +static const struct stm32_iwdg_data stm32mp1_iwdg_data = { |
---|
| 64 | + .has_pclk = true, |
---|
| 65 | + .max_prescaler = 1024, |
---|
| 66 | +}; |
---|
59 | 67 | |
---|
60 | 68 | struct stm32_iwdg { |
---|
61 | 69 | struct watchdog_device wdd; |
---|
| 70 | + const struct stm32_iwdg_data *data; |
---|
62 | 71 | void __iomem *regs; |
---|
63 | 72 | struct clk *clk_lsi; |
---|
64 | 73 | struct clk *clk_pclk; |
---|
65 | 74 | unsigned int rate; |
---|
66 | | - bool has_pclk; |
---|
67 | 75 | }; |
---|
68 | 76 | |
---|
69 | 77 | static inline u32 reg_read(void __iomem *base, u32 reg) |
---|
.. | .. |
---|
79 | 87 | static int stm32_iwdg_start(struct watchdog_device *wdd) |
---|
80 | 88 | { |
---|
81 | 89 | struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); |
---|
82 | | - u32 val = FLAG_PVU | FLAG_RVU; |
---|
83 | | - u32 reload; |
---|
| 90 | + u32 tout, presc, iwdg_rlr, iwdg_pr, iwdg_sr; |
---|
84 | 91 | int ret; |
---|
85 | 92 | |
---|
86 | 93 | dev_dbg(wdd->parent, "%s\n", __func__); |
---|
87 | 94 | |
---|
88 | | - /* prescaler fixed to 256 */ |
---|
89 | | - reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1, |
---|
90 | | - RLR_MIN, RLR_MAX); |
---|
| 95 | + tout = clamp_t(unsigned int, wdd->timeout, |
---|
| 96 | + wdd->min_timeout, wdd->max_hw_heartbeat_ms / 1000); |
---|
| 97 | + |
---|
| 98 | + presc = DIV_ROUND_UP(tout * wdt->rate, RLR_MAX + 1); |
---|
| 99 | + |
---|
| 100 | + /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */ |
---|
| 101 | + presc = roundup_pow_of_two(presc); |
---|
| 102 | + iwdg_pr = presc <= 1 << PR_SHIFT ? 0 : ilog2(presc) - PR_SHIFT; |
---|
| 103 | + iwdg_rlr = ((tout * wdt->rate) / presc) - 1; |
---|
91 | 104 | |
---|
92 | 105 | /* enable write access */ |
---|
93 | 106 | reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA); |
---|
94 | 107 | |
---|
95 | 108 | /* set prescaler & reload registers */ |
---|
96 | | - reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */ |
---|
97 | | - reg_write(wdt->regs, IWDG_RLR, reload); |
---|
| 109 | + reg_write(wdt->regs, IWDG_PR, iwdg_pr); |
---|
| 110 | + reg_write(wdt->regs, IWDG_RLR, iwdg_rlr); |
---|
98 | 111 | reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); |
---|
99 | 112 | |
---|
100 | 113 | /* wait for the registers to be updated (max 100ms) */ |
---|
101 | | - ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, val, |
---|
102 | | - !(val & (FLAG_PVU | FLAG_RVU)), |
---|
| 114 | + ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, iwdg_sr, |
---|
| 115 | + !(iwdg_sr & (SR_PVU | SR_RVU)), |
---|
103 | 116 | SLEEP_US, TIMEOUT_US); |
---|
104 | 117 | if (ret) { |
---|
105 | | - dev_err(wdd->parent, |
---|
106 | | - "Fail to set prescaler or reload registers\n"); |
---|
| 118 | + dev_err(wdd->parent, "Fail to set prescaler, reload regs\n"); |
---|
107 | 119 | return ret; |
---|
108 | 120 | } |
---|
109 | 121 | |
---|
.. | .. |
---|
138 | 150 | return 0; |
---|
139 | 151 | } |
---|
140 | 152 | |
---|
| 153 | +static void stm32_clk_disable_unprepare(void *data) |
---|
| 154 | +{ |
---|
| 155 | + clk_disable_unprepare(data); |
---|
| 156 | +} |
---|
| 157 | + |
---|
141 | 158 | static int stm32_iwdg_clk_init(struct platform_device *pdev, |
---|
142 | 159 | struct stm32_iwdg *wdt) |
---|
143 | 160 | { |
---|
| 161 | + struct device *dev = &pdev->dev; |
---|
144 | 162 | u32 ret; |
---|
145 | 163 | |
---|
146 | | - wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); |
---|
| 164 | + wdt->clk_lsi = devm_clk_get(dev, "lsi"); |
---|
147 | 165 | if (IS_ERR(wdt->clk_lsi)) { |
---|
148 | | - dev_err(&pdev->dev, "Unable to get lsi clock\n"); |
---|
| 166 | + dev_err(dev, "Unable to get lsi clock\n"); |
---|
149 | 167 | return PTR_ERR(wdt->clk_lsi); |
---|
150 | 168 | } |
---|
151 | 169 | |
---|
152 | 170 | /* optional peripheral clock */ |
---|
153 | | - if (wdt->has_pclk) { |
---|
154 | | - wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); |
---|
| 171 | + if (wdt->data->has_pclk) { |
---|
| 172 | + wdt->clk_pclk = devm_clk_get(dev, "pclk"); |
---|
155 | 173 | if (IS_ERR(wdt->clk_pclk)) { |
---|
156 | | - dev_err(&pdev->dev, "Unable to get pclk clock\n"); |
---|
| 174 | + dev_err(dev, "Unable to get pclk clock\n"); |
---|
157 | 175 | return PTR_ERR(wdt->clk_pclk); |
---|
158 | 176 | } |
---|
159 | 177 | |
---|
160 | 178 | ret = clk_prepare_enable(wdt->clk_pclk); |
---|
161 | 179 | if (ret) { |
---|
162 | | - dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); |
---|
| 180 | + dev_err(dev, "Unable to prepare pclk clock\n"); |
---|
163 | 181 | return ret; |
---|
164 | 182 | } |
---|
| 183 | + ret = devm_add_action_or_reset(dev, |
---|
| 184 | + stm32_clk_disable_unprepare, |
---|
| 185 | + wdt->clk_pclk); |
---|
| 186 | + if (ret) |
---|
| 187 | + return ret; |
---|
165 | 188 | } |
---|
166 | 189 | |
---|
167 | 190 | ret = clk_prepare_enable(wdt->clk_lsi); |
---|
168 | 191 | if (ret) { |
---|
169 | | - dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); |
---|
170 | | - clk_disable_unprepare(wdt->clk_pclk); |
---|
| 192 | + dev_err(dev, "Unable to prepare lsi clock\n"); |
---|
171 | 193 | return ret; |
---|
172 | 194 | } |
---|
| 195 | + ret = devm_add_action_or_reset(dev, stm32_clk_disable_unprepare, |
---|
| 196 | + wdt->clk_lsi); |
---|
| 197 | + if (ret) |
---|
| 198 | + return ret; |
---|
173 | 199 | |
---|
174 | 200 | wdt->rate = clk_get_rate(wdt->clk_lsi); |
---|
175 | 201 | |
---|
.. | .. |
---|
191 | 217 | }; |
---|
192 | 218 | |
---|
193 | 219 | static const struct of_device_id stm32_iwdg_of_match[] = { |
---|
194 | | - { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, |
---|
195 | | - { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, |
---|
| 220 | + { .compatible = "st,stm32-iwdg", .data = &stm32_iwdg_data }, |
---|
| 221 | + { .compatible = "st,stm32mp1-iwdg", .data = &stm32mp1_iwdg_data }, |
---|
196 | 222 | { /* end node */ } |
---|
197 | 223 | }; |
---|
198 | 224 | MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); |
---|
199 | 225 | |
---|
200 | 226 | static int stm32_iwdg_probe(struct platform_device *pdev) |
---|
201 | 227 | { |
---|
| 228 | + struct device *dev = &pdev->dev; |
---|
202 | 229 | struct watchdog_device *wdd; |
---|
203 | | - const struct of_device_id *match; |
---|
204 | 230 | struct stm32_iwdg *wdt; |
---|
205 | | - struct resource *res; |
---|
206 | 231 | int ret; |
---|
207 | 232 | |
---|
208 | | - match = of_match_device(stm32_iwdg_of_match, &pdev->dev); |
---|
209 | | - if (!match) |
---|
210 | | - return -ENODEV; |
---|
211 | | - |
---|
212 | | - wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); |
---|
| 233 | + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); |
---|
213 | 234 | if (!wdt) |
---|
214 | 235 | return -ENOMEM; |
---|
215 | 236 | |
---|
216 | | - wdt->has_pclk = match->data; |
---|
| 237 | + wdt->data = of_device_get_match_data(&pdev->dev); |
---|
| 238 | + if (!wdt->data) |
---|
| 239 | + return -ENODEV; |
---|
217 | 240 | |
---|
218 | 241 | /* This is the timer base. */ |
---|
219 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
220 | | - wdt->regs = devm_ioremap_resource(&pdev->dev, res); |
---|
| 242 | + wdt->regs = devm_platform_ioremap_resource(pdev, 0); |
---|
221 | 243 | if (IS_ERR(wdt->regs)) { |
---|
222 | | - dev_err(&pdev->dev, "Could not get resource\n"); |
---|
| 244 | + dev_err(dev, "Could not get resource\n"); |
---|
223 | 245 | return PTR_ERR(wdt->regs); |
---|
224 | 246 | } |
---|
225 | 247 | |
---|
.. | .. |
---|
229 | 251 | |
---|
230 | 252 | /* Initialize struct watchdog_device. */ |
---|
231 | 253 | wdd = &wdt->wdd; |
---|
| 254 | + wdd->parent = dev; |
---|
232 | 255 | wdd->info = &stm32_iwdg_info; |
---|
233 | 256 | wdd->ops = &stm32_iwdg_ops; |
---|
234 | | - wdd->min_timeout = ((RLR_MIN + 1) * 256) / wdt->rate; |
---|
235 | | - wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 256 * 1000) / wdt->rate; |
---|
236 | | - wdd->parent = &pdev->dev; |
---|
| 257 | + wdd->min_timeout = DIV_ROUND_UP((RLR_MIN + 1) * PR_MIN, wdt->rate); |
---|
| 258 | + wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * wdt->data->max_prescaler * |
---|
| 259 | + 1000) / wdt->rate; |
---|
237 | 260 | |
---|
238 | 261 | watchdog_set_drvdata(wdd, wdt); |
---|
239 | 262 | watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); |
---|
| 263 | + watchdog_init_timeout(wdd, 0, dev); |
---|
240 | 264 | |
---|
241 | | - ret = watchdog_init_timeout(wdd, 0, &pdev->dev); |
---|
242 | | - if (ret) |
---|
243 | | - dev_warn(&pdev->dev, |
---|
244 | | - "unable to set timeout value, using default\n"); |
---|
| 265 | + /* |
---|
| 266 | + * In case of CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set |
---|
| 267 | + * (Means U-Boot/bootloaders leaves the watchdog running) |
---|
| 268 | + * When we get here we should make a decision to prevent |
---|
| 269 | + * any side effects before user space daemon will take care of it. |
---|
| 270 | + * The best option, taking into consideration that there is no |
---|
| 271 | + * way to read values back from hardware, is to enforce watchdog |
---|
| 272 | + * being run with deterministic values. |
---|
| 273 | + */ |
---|
| 274 | + if (IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) { |
---|
| 275 | + ret = stm32_iwdg_start(wdd); |
---|
| 276 | + if (ret) |
---|
| 277 | + return ret; |
---|
245 | 278 | |
---|
246 | | - ret = watchdog_register_device(wdd); |
---|
247 | | - if (ret) { |
---|
248 | | - dev_err(&pdev->dev, "failed to register watchdog device\n"); |
---|
249 | | - goto err; |
---|
| 279 | + /* Make sure the watchdog is serviced */ |
---|
| 280 | + set_bit(WDOG_HW_RUNNING, &wdd->status); |
---|
250 | 281 | } |
---|
251 | 282 | |
---|
| 283 | + ret = devm_watchdog_register_device(dev, wdd); |
---|
| 284 | + if (ret) |
---|
| 285 | + return ret; |
---|
| 286 | + |
---|
252 | 287 | platform_set_drvdata(pdev, wdt); |
---|
253 | | - |
---|
254 | | - return 0; |
---|
255 | | -err: |
---|
256 | | - clk_disable_unprepare(wdt->clk_lsi); |
---|
257 | | - clk_disable_unprepare(wdt->clk_pclk); |
---|
258 | | - |
---|
259 | | - return ret; |
---|
260 | | -} |
---|
261 | | - |
---|
262 | | -static int stm32_iwdg_remove(struct platform_device *pdev) |
---|
263 | | -{ |
---|
264 | | - struct stm32_iwdg *wdt = platform_get_drvdata(pdev); |
---|
265 | | - |
---|
266 | | - watchdog_unregister_device(&wdt->wdd); |
---|
267 | | - clk_disable_unprepare(wdt->clk_lsi); |
---|
268 | | - clk_disable_unprepare(wdt->clk_pclk); |
---|
269 | 288 | |
---|
270 | 289 | return 0; |
---|
271 | 290 | } |
---|
272 | 291 | |
---|
273 | 292 | static struct platform_driver stm32_iwdg_driver = { |
---|
274 | 293 | .probe = stm32_iwdg_probe, |
---|
275 | | - .remove = stm32_iwdg_remove, |
---|
276 | 294 | .driver = { |
---|
277 | 295 | .name = "iwdg", |
---|
278 | 296 | .of_match_table = of_match_ptr(stm32_iwdg_of_match), |
---|