lantiq_wdt.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * This program is free software; you can redistribute it and/or modify it
  3. * under the terms of the GNU General Public License version 2 as published
  4. * by the Free Software Foundation.
  5. *
  6. * Copyright (C) 2010 John Crispin <john@phrozen.org>
  7. * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
  8. * Based on EP93xx wdt driver
  9. */
  10. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11. #include <linux/module.h>
  12. #include <linux/fs.h>
  13. #include <linux/miscdevice.h>
  14. #include <linux/watchdog.h>
  15. #include <linux/of_platform.h>
  16. #include <linux/uaccess.h>
  17. #include <linux/clk.h>
  18. #include <linux/io.h>
  19. #include <linux/regmap.h>
  20. #include <linux/mfd/syscon.h>
  21. #include <lantiq_soc.h>
  22. #define LTQ_XRX_RCU_RST_STAT 0x0014
  23. #define LTQ_XRX_RCU_RST_STAT_WDT BIT(31)
  24. /* CPU0 Reset Source Register */
  25. #define LTQ_FALCON_SYS1_CPU0RS 0x0060
  26. /* reset cause mask */
  27. #define LTQ_FALCON_SYS1_CPU0RS_MASK 0x0007
  28. #define LTQ_FALCON_SYS1_CPU0RS_WDT 0x02
  29. /*
  30. * Section 3.4 of the datasheet
  31. * The password sequence protects the WDT control register from unintended
  32. * write actions, which might cause malfunction of the WDT.
  33. *
  34. * essentially the following two magic passwords need to be written to allow
  35. * IO access to the WDT core
  36. */
  37. #define LTQ_WDT_PW1 0x00BE0000
  38. #define LTQ_WDT_PW2 0x00DC0000
  39. #define LTQ_WDT_CR 0x0 /* watchdog control register */
  40. #define LTQ_WDT_SR 0x8 /* watchdog status register */
  41. #define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
  42. #define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
  43. #define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
  44. /* divider to 0x40000 */
  45. #define LTQ_WDT_DIVIDER 0x40000
  46. #define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
  47. static bool nowayout = WATCHDOG_NOWAYOUT;
  48. static void __iomem *ltq_wdt_membase;
  49. static unsigned long ltq_io_region_clk_rate;
  50. static unsigned long ltq_wdt_bootstatus;
  51. static unsigned long ltq_wdt_in_use;
  52. static int ltq_wdt_timeout = 30;
  53. static int ltq_wdt_ok_to_close;
  54. static void
  55. ltq_wdt_enable(void)
  56. {
  57. unsigned long int timeout = ltq_wdt_timeout *
  58. (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
  59. if (timeout > LTQ_MAX_TIMEOUT)
  60. timeout = LTQ_MAX_TIMEOUT;
  61. /* write the first password magic */
  62. ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
  63. /* write the second magic plus the configuration and new timeout */
  64. ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
  65. LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
  66. }
  67. static void
  68. ltq_wdt_disable(void)
  69. {
  70. /* write the first password magic */
  71. ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
  72. /*
  73. * write the second password magic with no config
  74. * this turns the watchdog off
  75. */
  76. ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
  77. }
  78. static ssize_t
  79. ltq_wdt_write(struct file *file, const char __user *data,
  80. size_t len, loff_t *ppos)
  81. {
  82. if (len) {
  83. if (!nowayout) {
  84. size_t i;
  85. ltq_wdt_ok_to_close = 0;
  86. for (i = 0; i != len; i++) {
  87. char c;
  88. if (get_user(c, data + i))
  89. return -EFAULT;
  90. if (c == 'V')
  91. ltq_wdt_ok_to_close = 1;
  92. else
  93. ltq_wdt_ok_to_close = 0;
  94. }
  95. }
  96. ltq_wdt_enable();
  97. }
  98. return len;
  99. }
  100. static struct watchdog_info ident = {
  101. .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
  102. WDIOF_CARDRESET,
  103. .identity = "ltq_wdt",
  104. };
  105. static long
  106. ltq_wdt_ioctl(struct file *file,
  107. unsigned int cmd, unsigned long arg)
  108. {
  109. int ret = -ENOTTY;
  110. switch (cmd) {
  111. case WDIOC_GETSUPPORT:
  112. ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
  113. sizeof(ident)) ? -EFAULT : 0;
  114. break;
  115. case WDIOC_GETBOOTSTATUS:
  116. ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
  117. break;
  118. case WDIOC_GETSTATUS:
  119. ret = put_user(0, (int __user *)arg);
  120. break;
  121. case WDIOC_SETTIMEOUT:
  122. ret = get_user(ltq_wdt_timeout, (int __user *)arg);
  123. if (!ret)
  124. ltq_wdt_enable();
  125. /* intentional drop through */
  126. case WDIOC_GETTIMEOUT:
  127. ret = put_user(ltq_wdt_timeout, (int __user *)arg);
  128. break;
  129. case WDIOC_KEEPALIVE:
  130. ltq_wdt_enable();
  131. ret = 0;
  132. break;
  133. }
  134. return ret;
  135. }
  136. static int
  137. ltq_wdt_open(struct inode *inode, struct file *file)
  138. {
  139. if (test_and_set_bit(0, &ltq_wdt_in_use))
  140. return -EBUSY;
  141. ltq_wdt_in_use = 1;
  142. ltq_wdt_enable();
  143. return nonseekable_open(inode, file);
  144. }
  145. static int
  146. ltq_wdt_release(struct inode *inode, struct file *file)
  147. {
  148. if (ltq_wdt_ok_to_close)
  149. ltq_wdt_disable();
  150. else
  151. pr_err("watchdog closed without warning\n");
  152. ltq_wdt_ok_to_close = 0;
  153. clear_bit(0, &ltq_wdt_in_use);
  154. return 0;
  155. }
  156. static const struct file_operations ltq_wdt_fops = {
  157. .owner = THIS_MODULE,
  158. .write = ltq_wdt_write,
  159. .unlocked_ioctl = ltq_wdt_ioctl,
  160. .open = ltq_wdt_open,
  161. .release = ltq_wdt_release,
  162. .llseek = no_llseek,
  163. };
  164. static struct miscdevice ltq_wdt_miscdev = {
  165. .minor = WATCHDOG_MINOR,
  166. .name = "watchdog",
  167. .fops = &ltq_wdt_fops,
  168. };
  169. typedef int (*ltq_wdt_bootstatus_set)(struct platform_device *pdev);
  170. static int ltq_wdt_bootstatus_xrx(struct platform_device *pdev)
  171. {
  172. struct device *dev = &pdev->dev;
  173. struct regmap *rcu_regmap;
  174. u32 val;
  175. int err;
  176. rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
  177. if (IS_ERR(rcu_regmap))
  178. return PTR_ERR(rcu_regmap);
  179. err = regmap_read(rcu_regmap, LTQ_XRX_RCU_RST_STAT, &val);
  180. if (err)
  181. return err;
  182. if (val & LTQ_XRX_RCU_RST_STAT_WDT)
  183. ltq_wdt_bootstatus = WDIOF_CARDRESET;
  184. return 0;
  185. }
  186. static int ltq_wdt_bootstatus_falcon(struct platform_device *pdev)
  187. {
  188. struct device *dev = &pdev->dev;
  189. struct regmap *rcu_regmap;
  190. u32 val;
  191. int err;
  192. rcu_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
  193. "lantiq,rcu");
  194. if (IS_ERR(rcu_regmap))
  195. return PTR_ERR(rcu_regmap);
  196. err = regmap_read(rcu_regmap, LTQ_FALCON_SYS1_CPU0RS, &val);
  197. if (err)
  198. return err;
  199. if ((val & LTQ_FALCON_SYS1_CPU0RS_MASK) == LTQ_FALCON_SYS1_CPU0RS_WDT)
  200. ltq_wdt_bootstatus = WDIOF_CARDRESET;
  201. return 0;
  202. }
  203. static int
  204. ltq_wdt_probe(struct platform_device *pdev)
  205. {
  206. struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  207. struct clk *clk;
  208. ltq_wdt_bootstatus_set ltq_wdt_bootstatus_set;
  209. int ret;
  210. ltq_wdt_membase = devm_ioremap_resource(&pdev->dev, res);
  211. if (IS_ERR(ltq_wdt_membase))
  212. return PTR_ERR(ltq_wdt_membase);
  213. ltq_wdt_bootstatus_set = of_device_get_match_data(&pdev->dev);
  214. if (ltq_wdt_bootstatus_set) {
  215. ret = ltq_wdt_bootstatus_set(pdev);
  216. if (ret)
  217. return ret;
  218. }
  219. /* we do not need to enable the clock as it is always running */
  220. clk = clk_get_io();
  221. if (IS_ERR(clk)) {
  222. dev_err(&pdev->dev, "Failed to get clock\n");
  223. return -ENOENT;
  224. }
  225. ltq_io_region_clk_rate = clk_get_rate(clk);
  226. clk_put(clk);
  227. dev_info(&pdev->dev, "Init done\n");
  228. return misc_register(&ltq_wdt_miscdev);
  229. }
  230. static int
  231. ltq_wdt_remove(struct platform_device *pdev)
  232. {
  233. misc_deregister(&ltq_wdt_miscdev);
  234. return 0;
  235. }
  236. static const struct of_device_id ltq_wdt_match[] = {
  237. { .compatible = "lantiq,wdt", .data = NULL},
  238. { .compatible = "lantiq,xrx100-wdt", .data = ltq_wdt_bootstatus_xrx },
  239. { .compatible = "lantiq,falcon-wdt", .data = ltq_wdt_bootstatus_falcon },
  240. {},
  241. };
  242. MODULE_DEVICE_TABLE(of, ltq_wdt_match);
  243. static struct platform_driver ltq_wdt_driver = {
  244. .probe = ltq_wdt_probe,
  245. .remove = ltq_wdt_remove,
  246. .driver = {
  247. .name = "wdt",
  248. .of_match_table = ltq_wdt_match,
  249. },
  250. };
  251. module_platform_driver(ltq_wdt_driver);
  252. module_param(nowayout, bool, 0);
  253. MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
  254. MODULE_AUTHOR("John Crispin <john@phrozen.org>");
  255. MODULE_DESCRIPTION("Lantiq SoC Watchdog");
  256. MODULE_LICENSE("GPL");