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 u32 wdog_clock_rate; 59 }; 60 61 struct imx7ulp_wdt_device { 62 struct watchdog_device wdd; 63 void __iomem *base; 64 struct clk *clk; 65 bool post_rcs_wait; 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->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 do { 294 ret = _imx7ulp_wdt_init(wdt, timeout, val); 295 toval = readl(wdt->base + WDOG_TOVAL); 296 cs = readl(wdt->base + WDOG_CS); 297 cs &= ~(WDOG_CS_FLG | WDOG_CS_ULK | WDOG_CS_RCS); 298 } while (--loop > 0 && (cs != val || toval != timeout || ret)); 299 300 if (loop == 0) 301 return -EBUSY; 302 303 return ret; 304 } 305 306 static int imx7ulp_wdt_probe(struct platform_device *pdev) 307 { 308 struct imx7ulp_wdt_device *imx7ulp_wdt; 309 struct device *dev = &pdev->dev; 310 struct watchdog_device *wdog; 311 int ret; 312 313 imx7ulp_wdt = devm_kzalloc(dev, sizeof(*imx7ulp_wdt), GFP_KERNEL); 314 if (!imx7ulp_wdt) 315 return -ENOMEM; 316 317 platform_set_drvdata(pdev, imx7ulp_wdt); 318 319 imx7ulp_wdt->base = devm_platform_ioremap_resource(pdev, 0); 320 if (IS_ERR(imx7ulp_wdt->base)) 321 return PTR_ERR(imx7ulp_wdt->base); 322 323 imx7ulp_wdt->clk = devm_clk_get_enabled(dev, NULL); 324 if (IS_ERR(imx7ulp_wdt->clk)) { 325 dev_err(dev, "Failed to get watchdog clock\n"); 326 return PTR_ERR(imx7ulp_wdt->clk); 327 } 328 329 /* The WDOG may need to do external reset through dedicated pin */ 330 imx7ulp_wdt->ext_reset = of_property_read_bool(dev->of_node, "fsl,ext-reset-output"); 331 332 imx7ulp_wdt->post_rcs_wait = true; 333 if (of_device_is_compatible(dev->of_node, 334 "fsl,imx8ulp-wdt")) { 335 dev_info(dev, "imx8ulp wdt probe\n"); 336 imx7ulp_wdt->post_rcs_wait = false; 337 } else { 338 dev_info(dev, "imx7ulp wdt probe\n"); 339 } 340 341 wdog = &imx7ulp_wdt->wdd; 342 wdog->info = &imx7ulp_wdt_info; 343 wdog->ops = &imx7ulp_wdt_ops; 344 wdog->min_timeout = 1; 345 wdog->max_timeout = MAX_TIMEOUT; 346 wdog->parent = dev; 347 wdog->timeout = DEFAULT_TIMEOUT; 348 349 watchdog_init_timeout(wdog, 0, dev); 350 watchdog_stop_on_reboot(wdog); 351 watchdog_stop_on_unregister(wdog); 352 watchdog_set_drvdata(wdog, imx7ulp_wdt); 353 354 imx7ulp_wdt->hw = of_device_get_match_data(dev); 355 ret = imx7ulp_wdt_init(imx7ulp_wdt, wdog->timeout * imx7ulp_wdt->hw->wdog_clock_rate); 356 if (ret) 357 return ret; 358 359 return devm_watchdog_register_device(dev, wdog); 360 } 361 362 static int __maybe_unused imx7ulp_wdt_suspend_noirq(struct device *dev) 363 { 364 struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev); 365 366 if (watchdog_active(&imx7ulp_wdt->wdd)) 367 imx7ulp_wdt_stop(&imx7ulp_wdt->wdd); 368 369 clk_disable_unprepare(imx7ulp_wdt->clk); 370 371 return 0; 372 } 373 374 static int __maybe_unused imx7ulp_wdt_resume_noirq(struct device *dev) 375 { 376 struct imx7ulp_wdt_device *imx7ulp_wdt = dev_get_drvdata(dev); 377 u32 timeout = imx7ulp_wdt->wdd.timeout * imx7ulp_wdt->hw->wdog_clock_rate; 378 int ret; 379 380 ret = clk_prepare_enable(imx7ulp_wdt->clk); 381 if (ret) 382 return ret; 383 384 if (watchdog_active(&imx7ulp_wdt->wdd)) { 385 imx7ulp_wdt_init(imx7ulp_wdt, timeout); 386 imx7ulp_wdt_start(&imx7ulp_wdt->wdd); 387 imx7ulp_wdt_ping(&imx7ulp_wdt->wdd); 388 } 389 390 return 0; 391 } 392 393 static const struct dev_pm_ops imx7ulp_wdt_pm_ops = { 394 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx7ulp_wdt_suspend_noirq, 395 imx7ulp_wdt_resume_noirq) 396 }; 397 398 static const struct imx_wdt_hw_feature imx7ulp_wdt_hw = { 399 .prescaler_enable = false, 400 .wdog_clock_rate = 1000, 401 }; 402 403 static const struct imx_wdt_hw_feature imx93_wdt_hw = { 404 .prescaler_enable = true, 405 .wdog_clock_rate = 125, 406 }; 407 408 static const struct of_device_id imx7ulp_wdt_dt_ids[] = { 409 { .compatible = "fsl,imx8ulp-wdt", .data = &imx7ulp_wdt_hw, }, 410 { .compatible = "fsl,imx7ulp-wdt", .data = &imx7ulp_wdt_hw, }, 411 { .compatible = "fsl,imx93-wdt", .data = &imx93_wdt_hw, }, 412 { /* sentinel */ } 413 }; 414 MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids); 415 416 static struct platform_driver imx7ulp_wdt_driver = { 417 .probe = imx7ulp_wdt_probe, 418 .driver = { 419 .name = "imx7ulp-wdt", 420 .pm = &imx7ulp_wdt_pm_ops, 421 .of_match_table = imx7ulp_wdt_dt_ids, 422 }, 423 }; 424 module_platform_driver(imx7ulp_wdt_driver); 425 426 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); 427 MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver"); 428 MODULE_LICENSE("GPL v2"); 429