rti_wdt.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Watchdog driver for the K3 RTI module
  4. *
  5. * (c) Copyright 2019-2020 Texas Instruments Inc.
  6. * All rights reserved.
  7. */
  8. #include <linux/clk.h>
  9. #include <linux/device.h>
  10. #include <linux/err.h>
  11. #include <linux/io.h>
  12. #include <linux/kernel.h>
  13. #include <linux/mod_devicetable.h>
  14. #include <linux/module.h>
  15. #include <linux/moduleparam.h>
  16. #include <linux/of.h>
  17. #include <linux/of_reserved_mem.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/pm_runtime.h>
  20. #include <linux/types.h>
  21. #include <linux/watchdog.h>
  22. #define DEFAULT_HEARTBEAT 60
  23. /* Max heartbeat is calculated at 32kHz source clock */
  24. #define MAX_HEARTBEAT 1000
  25. /* Timer register set definition */
  26. #define RTIDWDCTRL 0x90
  27. #define RTIDWDPRLD 0x94
  28. #define RTIWDSTATUS 0x98
  29. #define RTIWDKEY 0x9c
  30. #define RTIDWDCNTR 0xa0
  31. #define RTIWWDRXCTRL 0xa4
  32. #define RTIWWDSIZECTRL 0xa8
  33. #define RTIWWDRX_NMI 0xa
  34. #define RTIWWDSIZE_50P 0x50
  35. #define RTIWWDSIZE_25P 0x500
  36. #define RTIWWDSIZE_12P5 0x5000
  37. #define RTIWWDSIZE_6P25 0x50000
  38. #define RTIWWDSIZE_3P125 0x500000
  39. #define WDENABLE_KEY 0xa98559da
  40. #define WDKEY_SEQ0 0xe51a
  41. #define WDKEY_SEQ1 0xa35c
  42. #define WDT_PRELOAD_SHIFT 13
  43. #define WDT_PRELOAD_MAX 0xfff
  44. #define DWDST BIT(1)
  45. #define PON_REASON_SOF_NUM 0xBBBBCCCC
  46. #define PON_REASON_MAGIC_NUM 0xDDDDDDDD
  47. #define PON_REASON_EOF_NUM 0xCCCCBBBB
  48. #define RESERVED_MEM_MIN_SIZE 12
  49. #define MAX_HW_ERROR 250
  50. static int heartbeat;
  51. /*
  52. * struct to hold data for each WDT device
  53. * @base - base io address of WD device
  54. * @freq - source clock frequency of WDT
  55. * @wdd - hold watchdog device as is in WDT core
  56. */
  57. struct rti_wdt_device {
  58. void __iomem *base;
  59. unsigned long freq;
  60. struct watchdog_device wdd;
  61. };
  62. static int rti_wdt_start(struct watchdog_device *wdd)
  63. {
  64. u32 timer_margin;
  65. struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
  66. int ret;
  67. ret = pm_runtime_resume_and_get(wdd->parent);
  68. if (ret)
  69. return ret;
  70. /* set timeout period */
  71. timer_margin = (u64)wdd->timeout * wdt->freq;
  72. timer_margin >>= WDT_PRELOAD_SHIFT;
  73. if (timer_margin > WDT_PRELOAD_MAX)
  74. timer_margin = WDT_PRELOAD_MAX;
  75. writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD);
  76. /*
  77. * RTI only supports a windowed mode, where the watchdog can only
  78. * be petted during the open window; not too early or not too late.
  79. * The HW configuration options only allow for the open window size
  80. * to be 50% or less than that; we obviouly want to configure the open
  81. * window as large as possible so we select the 50% option.
  82. */
  83. wdd->min_hw_heartbeat_ms = 520 * wdd->timeout + MAX_HW_ERROR;
  84. /* Generate NMI when wdt expires */
  85. writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL);
  86. /* Open window size 50%; this is the largest window size available */
  87. writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL);
  88. readl_relaxed(wdt->base + RTIWWDSIZECTRL);
  89. /* enable watchdog */
  90. writel_relaxed(WDENABLE_KEY, wdt->base + RTIDWDCTRL);
  91. return 0;
  92. }
  93. static int rti_wdt_ping(struct watchdog_device *wdd)
  94. {
  95. struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
  96. /* put watchdog in service state */
  97. writel_relaxed(WDKEY_SEQ0, wdt->base + RTIWDKEY);
  98. /* put watchdog in active state */
  99. writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY);
  100. return 0;
  101. }
  102. static int rti_wdt_setup_hw_hb(struct watchdog_device *wdd, u32 wsize)
  103. {
  104. /*
  105. * RTI only supports a windowed mode, where the watchdog can only
  106. * be petted during the open window; not too early or not too late.
  107. * The HW configuration options only allow for the open window size
  108. * to be 50% or less than that.
  109. * To avoid any glitches, we accommodate 2% + max hardware error
  110. * safety margin.
  111. */
  112. switch (wsize) {
  113. case RTIWWDSIZE_50P:
  114. /* 50% open window => 52% min heartbeat */
  115. wdd->min_hw_heartbeat_ms = 520 * heartbeat + MAX_HW_ERROR;
  116. break;
  117. case RTIWWDSIZE_25P:
  118. /* 25% open window => 77% min heartbeat */
  119. wdd->min_hw_heartbeat_ms = 770 * heartbeat + MAX_HW_ERROR;
  120. break;
  121. case RTIWWDSIZE_12P5:
  122. /* 12.5% open window => 89.5% min heartbeat */
  123. wdd->min_hw_heartbeat_ms = 895 * heartbeat + MAX_HW_ERROR;
  124. break;
  125. case RTIWWDSIZE_6P25:
  126. /* 6.5% open window => 95.5% min heartbeat */
  127. wdd->min_hw_heartbeat_ms = 955 * heartbeat + MAX_HW_ERROR;
  128. break;
  129. case RTIWWDSIZE_3P125:
  130. /* 3.125% open window => 98.9% min heartbeat */
  131. wdd->min_hw_heartbeat_ms = 989 * heartbeat + MAX_HW_ERROR;
  132. break;
  133. default:
  134. return -EINVAL;
  135. }
  136. return 0;
  137. }
  138. static unsigned int rti_wdt_get_timeleft_ms(struct watchdog_device *wdd)
  139. {
  140. u64 timer_counter;
  141. u32 val;
  142. struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
  143. /* if timeout has occurred then return 0 */
  144. val = readl_relaxed(wdt->base + RTIWDSTATUS);
  145. if (val & DWDST)
  146. return 0;
  147. timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR);
  148. timer_counter *= 1000;
  149. do_div(timer_counter, wdt->freq);
  150. return timer_counter;
  151. }
  152. static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
  153. {
  154. return rti_wdt_get_timeleft_ms(wdd) / 1000;
  155. }
  156. static const struct watchdog_info rti_wdt_info = {
  157. .options = WDIOF_KEEPALIVEPING,
  158. .identity = "K3 RTI Watchdog",
  159. };
  160. static const struct watchdog_ops rti_wdt_ops = {
  161. .owner = THIS_MODULE,
  162. .start = rti_wdt_start,
  163. .ping = rti_wdt_ping,
  164. .get_timeleft = rti_wdt_get_timeleft,
  165. };
  166. static int rti_wdt_probe(struct platform_device *pdev)
  167. {
  168. int ret = 0;
  169. struct device *dev = &pdev->dev;
  170. struct watchdog_device *wdd;
  171. struct rti_wdt_device *wdt;
  172. struct clk *clk;
  173. u32 last_ping = 0;
  174. u32 reserved_mem_size;
  175. struct resource res;
  176. u32 *vaddr;
  177. u64 paddr;
  178. wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
  179. if (!wdt)
  180. return -ENOMEM;
  181. clk = clk_get(dev, NULL);
  182. if (IS_ERR(clk))
  183. return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
  184. wdt->freq = clk_get_rate(clk);
  185. clk_put(clk);
  186. if (!wdt->freq) {
  187. dev_err(dev, "Failed to get fck rate.\n");
  188. return -EINVAL;
  189. }
  190. pm_runtime_enable(dev);
  191. ret = pm_runtime_resume_and_get(dev);
  192. if (ret < 0) {
  193. pm_runtime_disable(&pdev->dev);
  194. return dev_err_probe(dev, ret, "runtime pm failed\n");
  195. }
  196. platform_set_drvdata(pdev, wdt);
  197. wdd = &wdt->wdd;
  198. wdd->info = &rti_wdt_info;
  199. wdd->ops = &rti_wdt_ops;
  200. wdd->min_timeout = 1;
  201. wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
  202. wdt->freq * 1000;
  203. wdd->timeout = DEFAULT_HEARTBEAT;
  204. wdd->parent = dev;
  205. watchdog_set_drvdata(wdd, wdt);
  206. watchdog_set_nowayout(wdd, 1);
  207. watchdog_set_restart_priority(wdd, 128);
  208. wdt->base = devm_platform_ioremap_resource(pdev, 0);
  209. if (IS_ERR(wdt->base)) {
  210. ret = PTR_ERR(wdt->base);
  211. goto err_iomap;
  212. }
  213. if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) {
  214. int preset_heartbeat;
  215. u32 time_left_ms;
  216. u64 heartbeat_ms;
  217. u32 wsize;
  218. set_bit(WDOG_HW_RUNNING, &wdd->status);
  219. time_left_ms = rti_wdt_get_timeleft_ms(wdd);
  220. /* AM62x TRM: texp = (RTIDWDPRLD + 1) * (2^13) / RTICLK1 */
  221. heartbeat_ms = readl(wdt->base + RTIDWDPRLD) + 1;
  222. heartbeat_ms <<= WDT_PRELOAD_SHIFT;
  223. heartbeat_ms *= 1000;
  224. do_div(heartbeat_ms, wdt->freq);
  225. preset_heartbeat = heartbeat_ms + 500;
  226. preset_heartbeat /= 1000;
  227. if (preset_heartbeat != heartbeat)
  228. dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n");
  229. heartbeat = preset_heartbeat;
  230. wsize = readl(wdt->base + RTIWWDSIZECTRL);
  231. ret = rti_wdt_setup_hw_hb(wdd, wsize);
  232. if (ret) {
  233. dev_err(dev, "bad window size.\n");
  234. goto err_iomap;
  235. }
  236. last_ping = heartbeat_ms - time_left_ms;
  237. if (time_left_ms > heartbeat_ms) {
  238. dev_warn(dev, "time_left > heartbeat? Assuming last ping just before now.\n");
  239. last_ping = 0;
  240. }
  241. }
  242. ret = of_reserved_mem_region_to_resource(pdev->dev.of_node, 0, &res);
  243. if (!ret) {
  244. /*
  245. * If reserved memory is defined for watchdog reset cause.
  246. * Readout the Power-on(PON) reason and pass to bootstatus.
  247. */
  248. paddr = res.start;
  249. reserved_mem_size = resource_size(&res);
  250. if (reserved_mem_size < RESERVED_MEM_MIN_SIZE) {
  251. dev_err(dev, "The size of reserved memory is too small.\n");
  252. ret = -EINVAL;
  253. goto err_iomap;
  254. }
  255. vaddr = memremap(paddr, reserved_mem_size, MEMREMAP_WB);
  256. if (!vaddr) {
  257. dev_err(dev, "Failed to map memory-region.\n");
  258. ret = -ENOMEM;
  259. goto err_iomap;
  260. }
  261. if (vaddr[0] == PON_REASON_SOF_NUM &&
  262. vaddr[1] == PON_REASON_MAGIC_NUM &&
  263. vaddr[2] == PON_REASON_EOF_NUM) {
  264. wdd->bootstatus |= WDIOF_CARDRESET;
  265. }
  266. memset(vaddr, 0, reserved_mem_size);
  267. memunmap(vaddr);
  268. }
  269. watchdog_init_timeout(wdd, heartbeat, dev);
  270. ret = watchdog_register_device(wdd);
  271. if (ret)
  272. goto err_iomap;
  273. if (last_ping)
  274. watchdog_set_last_hw_keepalive(wdd, last_ping);
  275. if (!watchdog_hw_running(wdd))
  276. pm_runtime_put_sync(&pdev->dev);
  277. return 0;
  278. err_iomap:
  279. pm_runtime_put_sync(&pdev->dev);
  280. pm_runtime_disable(&pdev->dev);
  281. return ret;
  282. }
  283. static void rti_wdt_remove(struct platform_device *pdev)
  284. {
  285. struct rti_wdt_device *wdt = platform_get_drvdata(pdev);
  286. watchdog_unregister_device(&wdt->wdd);
  287. if (!pm_runtime_suspended(&pdev->dev))
  288. pm_runtime_put(&pdev->dev);
  289. pm_runtime_disable(&pdev->dev);
  290. }
  291. static const struct of_device_id rti_wdt_of_match[] = {
  292. { .compatible = "ti,j7-rti-wdt", },
  293. {},
  294. };
  295. MODULE_DEVICE_TABLE(of, rti_wdt_of_match);
  296. static struct platform_driver rti_wdt_driver = {
  297. .driver = {
  298. .name = "rti-wdt",
  299. .of_match_table = rti_wdt_of_match,
  300. },
  301. .probe = rti_wdt_probe,
  302. .remove = rti_wdt_remove,
  303. };
  304. module_platform_driver(rti_wdt_driver);
  305. MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");
  306. MODULE_DESCRIPTION("K3 RTI Watchdog Driver");
  307. module_param(heartbeat, int, 0);
  308. MODULE_PARM_DESC(heartbeat,
  309. "Watchdog heartbeat period in seconds from 1 to "
  310. __MODULE_STRING(MAX_HEARTBEAT) ", default "
  311. __MODULE_STRING(DEFAULT_HEARTBEAT));
  312. MODULE_LICENSE("GPL");
  313. MODULE_ALIAS("platform:rti-wdt");