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