1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2019 NXP. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/io.h> 8 #include <linux/iopoll.h> 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/platform_device.h> 13 #include <linux/reboot.h> 14 #include <linux/watchdog.h> 15 16 #define WDOG_CS 0x0 17 #define WDOG_CS_FLG BIT(14) 18 #define WDOG_CS_CMD32EN BIT(13) 19 #define WDOG_CS_PRES BIT(12) 20 #define WDOG_CS_ULK BIT(11) 21 #define WDOG_CS_RCS BIT(10) 22 #define LPO_CLK 0x1 23 #define LPO_CLK_SHIFT 8 24 #define WDOG_CS_CLK (LPO_CLK << LPO_CLK_SHIFT) 25 #define WDOG_CS_EN BIT(7) 26 #define WDOG_CS_INT_EN BIT(6) 27 #define WDOG_CS_UPDATE BIT(5) 28 #define WDOG_CS_WAIT BIT(1) 29 #define WDOG_CS_STOP BIT(0) 30 31 #define WDOG_CNT 0x4 32 #define WDOG_TOVAL 0x8 33 34 #define REFRESH_SEQ0 0xA602 35 #define REFRESH_SEQ1 0xB480 36 #define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0) 37 38 #define UNLOCK_SEQ0 0xC520 39 #define UNLOCK_SEQ1 0xD928 40 #define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0) 41 42 #define DEFAULT_TIMEOUT 60 43 #define MAX_TIMEOUT 128 44 #define WDOG_CLOCK_RATE 1000 45 #define WDOG_ULK_WAIT_TIMEOUT 1000 46 #define WDOG_RCS_WAIT_TIMEOUT 10000 47 #define WDOG_RCS_POST_WAIT 3000 48 49 #define RETRY_MAX 5 50 51 static bool nowayout = WATCHDOG_NOWAYOUT; 52 module_param(nowayout, bool, 0000); 53 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 54 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 55 56 struct imx_wdt_hw_feature { 57 bool prescaler_enable; 58 bool post_rcs_wait; 59 u32 wdog_clock_rate; 60 }; 61 62 struct imx7ulp_wdt_device { 63 struct watchdog_device wdd; 64 void __iomem *base; 65 struct clk *clk; 66 bool ext_reset; 67 const struct imx_wdt_hw_feature *hw; 68 }; 69 70 static int imx7ulp_wdt_wait_ulk(void __iomem *base) 71 { 72 u32 val = readl(base + WDOG_CS); 73 74 if (!(val & WDOG_CS_ULK) && 75 readl_poll_timeout_atomic(base + WDOG_CS, val, 76 val & WDOG_CS_ULK, 0, 77 WDOG_ULK_WAIT_TIMEOUT)) 78 return -ETIMEDOUT; 79 80 return 0; 81 } 82 83 static int imx7ulp_wdt_wait_rcs(struct imx7ulp_wdt_device *wdt) 84 { 85 int ret = 0; 86 u32 val = readl(wdt->base + WDOG_CS); 87 u64 timeout = (val & WDOG_CS_PRES) ? 88 WDOG_RCS_WAIT_TIMEOUT * 256 : WDOG_RCS_WAIT_TIMEOUT; 89 unsigned long wait_min = (val & WDOG_CS_PRES) ? 90 WDOG_RCS_POST_WAIT * 256 : WDOG_RCS_POST_WAIT; 91 92 if (!(val & WDOG_CS_RCS) && 93 readl_poll_timeout(wdt->base + WDOG_CS, val, val & WDOG_CS_RCS, 100, 94 timeout)) 95 ret = -ETIMEDOUT; 96 97 /* Wait 2.5 clocks after RCS done */ 98 if (wdt->hw->post_rcs_wait) 99 usleep_range(wait_min, wait_min + 2000); 100 101 return ret; 102 } 103 104 static int _imx7ulp_wdt_enable(struct imx7ulp_wdt_device *wdt, bool enable) 105 { 106 u32 val = readl(wdt->base + WDOG_CS); 107 int ret; 108 109 local_irq_disable(); 110 writel(UNLOCK, wdt->base + WDOG_CNT); 111 ret = imx7ulp_wdt_wait_ulk(wdt->base); 112 if (ret) 113 goto enable_out; 114 if (enable) 115 writel(val | WDOG_CS_EN, wdt->base + WDOG_CS); 116 else 117 writel(val & ~WDOG_CS_EN, wdt->base + WDOG_CS); 118 119 local_irq_enable(); 120 ret = imx7ulp_wdt_wait_rcs(wdt); 121 122 return ret; 123 124 enable_out: 125 local_irq_enable(); 126 return ret; 127 } 128 129 static int imx7ulp_wdt_enable(struct watchdog_device *wdog, bool enable) 130 { 131 struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog); 132 int ret; 133 u32 val; 134 u32 loop = RETRY_MAX; 135 136 do { 137 ret = _imx7ulp_wdt_enable(wdt, enable); 138 val = readl(wdt->base + WDOG_CS); 139 } while (--loop > 0 && ((!!(val & WDOG_CS_EN)) != enable || ret)); 140 141 if (loop == 0) 142 return -EBUSY; 143 144 return ret; 145 } 146 147 static int imx7ulp_wdt_ping(struct watchdog_device *wdog) 148 { 149 struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog); 150 151 writel(REFRESH, wdt->base + WDOG_CNT); 152 153 return 0; 154 } 155 156 static int imx7ulp_wdt_start(struct watchdog_device *wdog) 157 { 158 return imx7ulp_wdt_enable(wdog, true); 159 } 160 161 static int imx7ulp_wdt_stop(struct watchdog_device *wdog) 162 { 163 return imx7ulp_wdt_enable(wdog, false); 164 } 165 166 static int _imx7ulp_wdt_set_timeout(struct imx7ulp_wdt_device *wdt, 167 unsigned int toval) 168 { 169 int ret; 170 171 local_irq_disable(); 172 writel(UNLOCK, wdt->base + WDOG_CNT); 173 ret = imx7ulp_wdt_wait_ulk(wdt->base); 174 if (ret) 175 goto timeout_out; 176 writel(toval, wdt->base + WDOG_TOVAL); 177 local_irq_enable(); 178 ret = imx7ulp_wdt_wait_rcs(wdt); 179 return ret; 180 181 timeout_out: 182 local_irq_enable(); 183 return ret; 184 } 185 186 static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog, 187 unsigned int timeout) 188 { 189 struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog); 190 u32 toval = wdt->hw->wdog_clock_rate * timeout; 191 u32 val; 192 int ret; 193 u32 loop = RETRY_MAX; 194 195 do { 196 ret = _imx7ulp_wdt_set_timeout(wdt, toval); 197 val = readl(wdt->base + WDOG_TOVAL); 198 } while (--loop > 0 && (val != toval || ret)); 199 200 if (loop == 0) 201 return -EBUSY; 202 203 wdog->timeout = timeout; 204 return ret; 205 } 206 207 static int imx7ulp_wdt_restart(struct watchdog_device *wdog, 208 unsigned long action, void *data) 209 { 210 struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog); 211 int ret; 212 213 ret = imx7ulp_wdt_enable(wdog, true); 214 if (ret) 215 return ret; 216 217 ret = imx7ulp_wdt_set_timeout(&wdt->wdd, 1); 218 if (ret) 219 return ret; 220 221 /* wait for wdog to fire */ 222 while (true) 223 ; 224 225 return NOTIFY_DONE; 226 } 227 228 static const struct watchdog_ops imx7ulp_wdt_ops = { 229 .owner = THIS_MODULE, 230 .start = imx7ulp_wdt_start, 231 .stop = imx7ulp_wdt_stop, 232 .ping = imx7ulp_wdt_ping, 233 .set_timeout = imx7ulp_wdt_set_timeout, 234 .restart = imx7ulp_wdt_restart, 235 }; 236 237 static const struct watchdog_info imx7ulp_wdt_info = { 238 .identity = "i.MX7ULP watchdog timer", 239 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 240 WDIOF_MAGICCLOSE, 241 }; 242 243 static int _imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout, unsigned int cs) 244 { 245 u32 val; 246 int ret; 247 248 local_irq_disable(); 249 250 val = readl(wdt->base + WDOG_CS); 251 if (val & WDOG_CS_CMD32EN) { 252 writel(UNLOCK, wdt->base + WDOG_CNT); 253 } else { 254 mb(); 255 /* unlock the wdog for reconfiguration */ 256 writel_relaxed(UNLOCK_SEQ0, wdt->base + WDOG_CNT); 257 writel_relaxed(UNLOCK_SEQ1, wdt->base + WDOG_CNT); 258 mb(); 259 } 260 261 ret = imx7ulp_wdt_wait_ulk(wdt->base); 262 if (ret) 263 goto init_out; 264 265 /* set an initial timeout value in TOVAL */ 266 writel(timeout, wdt->base + WDOG_TOVAL); 267 writel(cs, wdt->base + WDOG_CS); 268 local_irq_enable(); 269 ret = imx7ulp_wdt_wait_rcs(wdt); 270 271 return ret; 272 273 init_out: 274 local_irq_enable(); 275 return ret; 276 } 277 278 static int imx7ulp_wdt_init(struct imx7ulp_wdt_device *wdt, unsigned int timeout) 279 { 280 /* enable 32bit command sequence and reconfigure */ 281 u32 val = WDOG_CS_CMD32EN | WDOG_CS_CLK | WDOG_CS_UPDATE | 282 WDOG_CS_WAIT | WDOG_CS_STOP; 283 u32 cs, toval; 284 int ret; 285 u32 loop = RETRY_MAX; 286 287 if (wdt->hw->prescaler_enable) 288 val |= WDOG_CS_PRES; 289 290 if (wdt->ext_reset) 291 val |= WDOG_CS_INT_EN; 292 293 if (readl(wdt->base + WDOG_CS) & WDOG_CS_EN) { 294 set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); 295 val |= WDOG_CS_EN; 296 } 297 298 do { 299 ret = _imx7ulp_wdt_init(wdt, timeout, val); 300 toval = readl(wdt->base + WDOG_TOVAL); 301 cs = readl(wdt->base + WDOG_CS); 302 cs &= ~(WDOG_CS_FLG | WDOG_CS_ULK | WDOG_CS_RCS); 303 } while (--loop > 0 && (cs != val || toval != timeout || ret)); 304 305 if (loop == 0) 306 return -EBUSY; 307 308 return ret; 309 } 310 311 static int imx7ulp_wdt_probe(struct platform_device *pdev) 312 { 313 struct imx7ulp_wdt_device *imx7ulp_wdt; 314 struct device *dev = &pdev->dev; 315 struct watchdog_device *wdog; 316 int ret; 317 318 imx7ulp_wdt = devm_kzalloc(dev, sizeof(*imx7ulp_wdt), GFP_KERNEL); 319 if (!imx7ulp_wdt) 320 return -ENOMEM; 321 322 platform_set_drvdata(pdev, imx7ulp_wdt); 323 324 imx7ulp_wdt->base = devm_platform_ioremap_resource(pdev, 0); 325 if (IS_ERR(imx7ulp_wdt->base)) 326 return PTR_ERR(imx7ulp_wdt->base); 327 328 imx7ulp_wdt->clk = devm_clk_get_enabled(dev, NULL); 329 if (IS_ERR(imx7ulp_wdt->clk)) { 330 dev_err(dev, "Failed to get watchdog clock\n"); 331 return PTR_ERR(imx7ulp_wdt->clk); 332 } 333 334 /* The WDOG may need to do external reset through dedicated pin */ 335 imx7ulp_wdt->ext_reset = of_property_read_bool(dev->of_node, "fsl,ext-reset-output"); 336 337 wdog = &imx7ulp_wdt->wdd; 338 wdog->info = &imx7ulp_wdt_info; 339 wdog->ops = &imx7ulp_wdt_ops; 340 wdog->min_timeout = 1; 341 wdog->max_timeout = MAX_TIMEOUT; 342 wdog->parent = dev; 343 wdog->timeout = DEFAULT_TIMEOUT; 344 345 watchdog_init_timeout(wdog, 0, dev); 346 watchdog_stop_on_reboot(wdog); 347 watchdog_stop_on_unregister(wdog); 348 watchdog_set_drvdata(wdog, imx7ulp_wdt); 349 350 imx7ulp_wdt->hw = of_device_get_match_data(dev); 351 ret = imx7ulp_wdt_init(imx7ulp_wdt, wdog->timeout * imx7ulp_wdt->hw->wdog_clock_rate); 352 if (ret) 353 return ret; 354 355 return devm_watchdog_register_device(dev, wdog); 356 } 357 358 static int __maybe_unused imx7ulp_wdt_suspend_noirq(struct device *dev) 359 { 360 struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev); 361 362 if (watchdog_active(&imx7ulp_wdt->wdd)) 363 imx7ulp_wdt_stop(&imx7ulp_wdt->wdd); 364 365 clk_disable_unprepare(imx7ulp_wdt->clk); 366 367 return 0; 368 } 369 370 static int __maybe_unused imx7ulp_wdt_resume_noirq(struct device *dev) 371 { 372 struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev); 373 u32 timeout = imx7ulp_wdt->wdd.timeout * imx7ulp_wdt->hw->wdog_clock_rate; 374 int ret; 375 376 ret = clk_prepare_enable(imx7ulp_wdt->clk); 377 if (ret) 378 return ret; 379 380 if (watchdog_active(&imx7ulp_wdt->wdd)) { 381 imx7ulp_wdt_init(imx7ulp_wdt, timeout); 382 imx7ulp_wdt_start(&imx7ulp_wdt->wdd); 383 imx7ulp_wdt_ping(&imx7ulp_wdt->wdd); 384 } 385 386 return 0; 387 } 388 389 static const struct dev_pm_ops imx7ulp_wdt_pm_ops = { 390 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx7ulp_wdt_suspend_noirq, 391 imx7ulp_wdt_resume_noirq) 392 }; 393 394 static const struct imx_wdt_hw_feature imx7ulp_wdt_hw = { 395 .prescaler_enable = false, 396 .wdog_clock_rate = 1000, 397 .post_rcs_wait = true, 398 }; 399 400 static const struct imx_wdt_hw_feature imx8ulp_wdt_hw = { 401 .prescaler_enable = false, 402 .wdog_clock_rate = 1000, 403 }; 404 405 static const struct imx_wdt_hw_feature imx93_wdt_hw = { 406 .prescaler_enable = true, 407 .wdog_clock_rate = 125, 408 }; 409 410 static const struct of_device_id imx7ulp_wdt_dt_ids[] = { 411 { .compatible = "fsl,imx7ulp-wdt", .data = &imx7ulp_wdt_hw, }, 412 { .compatible = "fsl,imx8ulp-wdt", .data = &imx8ulp_wdt_hw, }, 413 { .compatible = "fsl,imx93-wdt", .data = &imx93_wdt_hw, }, 414 { /* sentinel */ } 415 }; 416 MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids); 417 418 static struct platform_driver imx7ulp_wdt_driver = { 419 .probe = imx7ulp_wdt_probe, 420 .driver = { 421 .name = "imx7ulp-wdt", 422 .pm = &imx7ulp_wdt_pm_ops, 423 .of_match_table = imx7ulp_wdt_dt_ids, 424 }, 425 }; 426 module_platform_driver(imx7ulp_wdt_driver); 427 428 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); 429 MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver"); 430 MODULE_LICENSE("GPL v2"); 431