cadence_wdt.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Cadence WDT driver - Used by Xilinx Zynq
  4. *
  5. * Copyright (C) 2010 - 2014 Xilinx, Inc.
  6. *
  7. */
  8. #include <linux/clk.h>
  9. #include <linux/init.h>
  10. #include <linux/interrupt.h>
  11. #include <linux/io.h>
  12. #include <linux/irq.h>
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/of.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/watchdog.h>
  18. #define CDNS_WDT_DEFAULT_TIMEOUT 10
  19. /* Supports 1 - 516 sec */
  20. #define CDNS_WDT_MIN_TIMEOUT 1
  21. #define CDNS_WDT_MAX_TIMEOUT 516
  22. /* Restart key */
  23. #define CDNS_WDT_RESTART_KEY 0x00001999
  24. /* Counter register access key */
  25. #define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
  26. /* Counter value divisor */
  27. #define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
  28. /* Clock prescaler value and selection */
  29. #define CDNS_WDT_PRESCALE_64 64
  30. #define CDNS_WDT_PRESCALE_512 512
  31. #define CDNS_WDT_PRESCALE_4096 4096
  32. #define CDNS_WDT_PRESCALE_SELECT_64 1
  33. #define CDNS_WDT_PRESCALE_SELECT_512 2
  34. #define CDNS_WDT_PRESCALE_SELECT_4096 3
  35. /* Input clock frequency */
  36. #define CDNS_WDT_CLK_10MHZ 10000000
  37. #define CDNS_WDT_CLK_75MHZ 75000000
  38. /* Counter maximum value */
  39. #define CDNS_WDT_COUNTER_MAX 0xFFF
  40. static int wdt_timeout;
  41. static int nowayout = WATCHDOG_NOWAYOUT;
  42. module_param(wdt_timeout, int, 0644);
  43. MODULE_PARM_DESC(wdt_timeout,
  44. "Watchdog time in seconds. (default="
  45. __MODULE_STRING(CDNS_WDT_DEFAULT_TIMEOUT) ")");
  46. module_param(nowayout, int, 0644);
  47. MODULE_PARM_DESC(nowayout,
  48. "Watchdog cannot be stopped once started (default="
  49. __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  50. /**
  51. * struct cdns_wdt - Watchdog device structure
  52. * @regs: baseaddress of device
  53. * @rst: reset flag
  54. * @clk: struct clk * of a clock source
  55. * @prescaler: for saving prescaler value
  56. * @ctrl_clksel: counter clock prescaler selection
  57. * @io_lock: spinlock for IO register access
  58. * @cdns_wdt_device: watchdog device structure
  59. *
  60. * Structure containing parameters specific to cadence watchdog.
  61. */
  62. struct cdns_wdt {
  63. void __iomem *regs;
  64. bool rst;
  65. struct clk *clk;
  66. u32 prescaler;
  67. u32 ctrl_clksel;
  68. spinlock_t io_lock;
  69. struct watchdog_device cdns_wdt_device;
  70. };
  71. /* Write access to Registers */
  72. static inline void cdns_wdt_writereg(struct cdns_wdt *wdt, u32 offset, u32 val)
  73. {
  74. writel_relaxed(val, wdt->regs + offset);
  75. }
  76. /*************************Register Map**************************************/
  77. /* Register Offsets for the WDT */
  78. #define CDNS_WDT_ZMR_OFFSET 0x0 /* Zero Mode Register */
  79. #define CDNS_WDT_CCR_OFFSET 0x4 /* Counter Control Register */
  80. #define CDNS_WDT_RESTART_OFFSET 0x8 /* Restart Register */
  81. #define CDNS_WDT_SR_OFFSET 0xC /* Status Register */
  82. /*
  83. * Zero Mode Register - This register controls how the time out is indicated
  84. * and also contains the access code to allow writes to the register (0xABC).
  85. */
  86. #define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
  87. #define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
  88. #define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
  89. #define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
  90. #define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
  91. /*
  92. * Counter Control register - This register controls how fast the timer runs
  93. * and the reset value and also contains the access code to allow writes to
  94. * the register.
  95. */
  96. #define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
  97. /**
  98. * cdns_wdt_stop - Stop the watchdog.
  99. *
  100. * @wdd: watchdog device
  101. *
  102. * Read the contents of the ZMR register, clear the WDEN bit
  103. * in the register and set the access key for successful write.
  104. *
  105. * Return: always 0
  106. */
  107. static int cdns_wdt_stop(struct watchdog_device *wdd)
  108. {
  109. struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
  110. spin_lock(&wdt->io_lock);
  111. cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
  112. CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
  113. spin_unlock(&wdt->io_lock);
  114. return 0;
  115. }
  116. /**
  117. * cdns_wdt_reload - Reload the watchdog timer (i.e. pat the watchdog).
  118. *
  119. * @wdd: watchdog device
  120. *
  121. * Write the restart key value (0x00001999) to the restart register.
  122. *
  123. * Return: always 0
  124. */
  125. static int cdns_wdt_reload(struct watchdog_device *wdd)
  126. {
  127. struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
  128. spin_lock(&wdt->io_lock);
  129. cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
  130. CDNS_WDT_RESTART_KEY);
  131. spin_unlock(&wdt->io_lock);
  132. return 0;
  133. }
  134. /**
  135. * cdns_wdt_start - Enable and start the watchdog.
  136. *
  137. * @wdd: watchdog device
  138. *
  139. * The counter value is calculated according to the formula:
  140. * calculated count = (timeout * clock) / prescaler + 1.
  141. * The calculated count is divided by 0x1000 to obtain the field value
  142. * to write to counter control register.
  143. * Clears the contents of prescaler and counter reset value. Sets the
  144. * prescaler to 4096 and the calculated count and access key
  145. * to write to CCR Register.
  146. * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
  147. * or Interrupt signal(IRQEN) with a specified cycles and the access
  148. * key to write to ZMR Register.
  149. *
  150. * Return: always 0
  151. */
  152. static int cdns_wdt_start(struct watchdog_device *wdd)
  153. {
  154. struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
  155. unsigned int data = 0;
  156. unsigned short count;
  157. unsigned long clock_f = clk_get_rate(wdt->clk);
  158. /*
  159. * Counter value divisor to obtain the value of
  160. * counter reset to be written to control register.
  161. */
  162. count = (wdd->timeout * (clock_f / wdt->prescaler)) /
  163. CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
  164. if (count > CDNS_WDT_COUNTER_MAX)
  165. count = CDNS_WDT_COUNTER_MAX;
  166. spin_lock(&wdt->io_lock);
  167. cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
  168. CDNS_WDT_ZMR_ZKEY_VAL);
  169. count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
  170. /* Write counter access key first to be able write to register */
  171. data = count | CDNS_WDT_REGISTER_ACCESS_KEY | wdt->ctrl_clksel;
  172. cdns_wdt_writereg(wdt, CDNS_WDT_CCR_OFFSET, data);
  173. data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
  174. CDNS_WDT_ZMR_ZKEY_VAL;
  175. /* Reset on timeout if specified in device tree. */
  176. if (wdt->rst) {
  177. data |= CDNS_WDT_ZMR_RSTEN_MASK;
  178. data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
  179. } else {
  180. data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
  181. data |= CDNS_WDT_ZMR_IRQEN_MASK;
  182. }
  183. cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, data);
  184. cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
  185. CDNS_WDT_RESTART_KEY);
  186. spin_unlock(&wdt->io_lock);
  187. return 0;
  188. }
  189. /**
  190. * cdns_wdt_settimeout - Set a new timeout value for the watchdog device.
  191. *
  192. * @wdd: watchdog device
  193. * @new_time: new timeout value that needs to be set
  194. * Return: 0 on success
  195. *
  196. * Update the watchdog_device timeout with new value which is used when
  197. * cdns_wdt_start is called.
  198. */
  199. static int cdns_wdt_settimeout(struct watchdog_device *wdd,
  200. unsigned int new_time)
  201. {
  202. wdd->timeout = new_time;
  203. return cdns_wdt_start(wdd);
  204. }
  205. /**
  206. * cdns_wdt_irq_handler - Notifies of watchdog timeout.
  207. *
  208. * @irq: interrupt number
  209. * @dev_id: pointer to a platform device structure
  210. * Return: IRQ_HANDLED
  211. *
  212. * The handler is invoked when the watchdog times out and a
  213. * reset on timeout has not been enabled.
  214. */
  215. static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id)
  216. {
  217. struct platform_device *pdev = dev_id;
  218. dev_info(&pdev->dev,
  219. "Watchdog timed out. Internal reset not enabled\n");
  220. return IRQ_HANDLED;
  221. }
  222. /*
  223. * Info structure used to indicate the features supported by the device
  224. * to the upper layers. This is defined in watchdog.h header file.
  225. */
  226. static const struct watchdog_info cdns_wdt_info = {
  227. .identity = "cdns_wdt watchdog",
  228. .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
  229. WDIOF_MAGICCLOSE,
  230. };
  231. /* Watchdog Core Ops */
  232. static const struct watchdog_ops cdns_wdt_ops = {
  233. .owner = THIS_MODULE,
  234. .start = cdns_wdt_start,
  235. .stop = cdns_wdt_stop,
  236. .ping = cdns_wdt_reload,
  237. .set_timeout = cdns_wdt_settimeout,
  238. };
  239. /************************Platform Operations*****************************/
  240. /**
  241. * cdns_wdt_probe - Probe call for the device.
  242. *
  243. * @pdev: handle to the platform device structure.
  244. * Return: 0 on success, negative error otherwise.
  245. *
  246. * It does all the memory allocation and registration for the device.
  247. */
  248. static int cdns_wdt_probe(struct platform_device *pdev)
  249. {
  250. struct resource *res;
  251. int ret, irq;
  252. unsigned long clock_f;
  253. struct cdns_wdt *wdt;
  254. struct watchdog_device *cdns_wdt_device;
  255. wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
  256. if (!wdt)
  257. return -ENOMEM;
  258. cdns_wdt_device = &wdt->cdns_wdt_device;
  259. cdns_wdt_device->info = &cdns_wdt_info;
  260. cdns_wdt_device->ops = &cdns_wdt_ops;
  261. cdns_wdt_device->timeout = CDNS_WDT_DEFAULT_TIMEOUT;
  262. cdns_wdt_device->min_timeout = CDNS_WDT_MIN_TIMEOUT;
  263. cdns_wdt_device->max_timeout = CDNS_WDT_MAX_TIMEOUT;
  264. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  265. wdt->regs = devm_ioremap_resource(&pdev->dev, res);
  266. if (IS_ERR(wdt->regs))
  267. return PTR_ERR(wdt->regs);
  268. /* Register the interrupt */
  269. wdt->rst = of_property_read_bool(pdev->dev.of_node, "reset-on-timeout");
  270. irq = platform_get_irq(pdev, 0);
  271. if (!wdt->rst && irq >= 0) {
  272. ret = devm_request_irq(&pdev->dev, irq, cdns_wdt_irq_handler, 0,
  273. pdev->name, pdev);
  274. if (ret) {
  275. dev_err(&pdev->dev,
  276. "cannot register interrupt handler err=%d\n",
  277. ret);
  278. return ret;
  279. }
  280. }
  281. /* Initialize the members of cdns_wdt structure */
  282. cdns_wdt_device->parent = &pdev->dev;
  283. ret = watchdog_init_timeout(cdns_wdt_device, wdt_timeout, &pdev->dev);
  284. if (ret) {
  285. dev_err(&pdev->dev, "unable to set timeout value\n");
  286. return ret;
  287. }
  288. watchdog_set_nowayout(cdns_wdt_device, nowayout);
  289. watchdog_stop_on_reboot(cdns_wdt_device);
  290. watchdog_set_drvdata(cdns_wdt_device, wdt);
  291. wdt->clk = devm_clk_get(&pdev->dev, NULL);
  292. if (IS_ERR(wdt->clk)) {
  293. dev_err(&pdev->dev, "input clock not found\n");
  294. ret = PTR_ERR(wdt->clk);
  295. return ret;
  296. }
  297. ret = clk_prepare_enable(wdt->clk);
  298. if (ret) {
  299. dev_err(&pdev->dev, "unable to enable clock\n");
  300. return ret;
  301. }
  302. clock_f = clk_get_rate(wdt->clk);
  303. if (clock_f <= CDNS_WDT_CLK_75MHZ) {
  304. wdt->prescaler = CDNS_WDT_PRESCALE_512;
  305. wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
  306. } else {
  307. wdt->prescaler = CDNS_WDT_PRESCALE_4096;
  308. wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
  309. }
  310. spin_lock_init(&wdt->io_lock);
  311. ret = watchdog_register_device(cdns_wdt_device);
  312. if (ret) {
  313. dev_err(&pdev->dev, "Failed to register wdt device\n");
  314. goto err_clk_disable;
  315. }
  316. platform_set_drvdata(pdev, wdt);
  317. dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n",
  318. wdt->regs, cdns_wdt_device->timeout,
  319. nowayout ? ", nowayout" : "");
  320. return 0;
  321. err_clk_disable:
  322. clk_disable_unprepare(wdt->clk);
  323. return ret;
  324. }
  325. /**
  326. * cdns_wdt_remove - Probe call for the device.
  327. *
  328. * @pdev: handle to the platform device structure.
  329. * Return: 0 on success, otherwise negative error.
  330. *
  331. * Unregister the device after releasing the resources.
  332. */
  333. static int cdns_wdt_remove(struct platform_device *pdev)
  334. {
  335. struct cdns_wdt *wdt = platform_get_drvdata(pdev);
  336. cdns_wdt_stop(&wdt->cdns_wdt_device);
  337. watchdog_unregister_device(&wdt->cdns_wdt_device);
  338. clk_disable_unprepare(wdt->clk);
  339. return 0;
  340. }
  341. /**
  342. * cdns_wdt_shutdown - Stop the device.
  343. *
  344. * @pdev: handle to the platform structure.
  345. *
  346. */
  347. static void cdns_wdt_shutdown(struct platform_device *pdev)
  348. {
  349. struct cdns_wdt *wdt = platform_get_drvdata(pdev);
  350. cdns_wdt_stop(&wdt->cdns_wdt_device);
  351. clk_disable_unprepare(wdt->clk);
  352. }
  353. /**
  354. * cdns_wdt_suspend - Stop the device.
  355. *
  356. * @dev: handle to the device structure.
  357. * Return: 0 always.
  358. */
  359. static int __maybe_unused cdns_wdt_suspend(struct device *dev)
  360. {
  361. struct cdns_wdt *wdt = dev_get_drvdata(dev);
  362. if (watchdog_active(&wdt->cdns_wdt_device)) {
  363. cdns_wdt_stop(&wdt->cdns_wdt_device);
  364. clk_disable_unprepare(wdt->clk);
  365. }
  366. return 0;
  367. }
  368. /**
  369. * cdns_wdt_resume - Resume the device.
  370. *
  371. * @dev: handle to the device structure.
  372. * Return: 0 on success, errno otherwise.
  373. */
  374. static int __maybe_unused cdns_wdt_resume(struct device *dev)
  375. {
  376. int ret;
  377. struct cdns_wdt *wdt = dev_get_drvdata(dev);
  378. if (watchdog_active(&wdt->cdns_wdt_device)) {
  379. ret = clk_prepare_enable(wdt->clk);
  380. if (ret) {
  381. dev_err(dev, "unable to enable clock\n");
  382. return ret;
  383. }
  384. cdns_wdt_start(&wdt->cdns_wdt_device);
  385. }
  386. return 0;
  387. }
  388. static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume);
  389. static const struct of_device_id cdns_wdt_of_match[] = {
  390. { .compatible = "cdns,wdt-r1p2", },
  391. { /* end of table */ }
  392. };
  393. MODULE_DEVICE_TABLE(of, cdns_wdt_of_match);
  394. /* Driver Structure */
  395. static struct platform_driver cdns_wdt_driver = {
  396. .probe = cdns_wdt_probe,
  397. .remove = cdns_wdt_remove,
  398. .shutdown = cdns_wdt_shutdown,
  399. .driver = {
  400. .name = "cdns-wdt",
  401. .of_match_table = cdns_wdt_of_match,
  402. .pm = &cdns_wdt_pm_ops,
  403. },
  404. };
  405. module_platform_driver(cdns_wdt_driver);
  406. MODULE_AUTHOR("Xilinx, Inc.");
  407. MODULE_DESCRIPTION("Watchdog driver for Cadence WDT");
  408. MODULE_LICENSE("GPL");