0025-watchdog-rti_wdt-Backport-mainline-driver.patch 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. From 4823856642a29f81c2310a05b4687588c62633fb Mon Sep 17 00:00:00 2001
  2. From: Jan Kiszka <jan.kiszka@siemens.com>
  3. Date: Fri, 30 Jul 2021 13:53:20 +0200
  4. Subject: [PATCH 25/26] watchdog: rti_wdt: Backport mainline driver
  5. Corresponds to 8711071e9700b67045fe5518161d63f7a03e3c9e upstream.
  6. This comes with a lot of improvements, specifically for picking up a
  7. watchdog already started by the firmware.
  8. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
  9. ---
  10. drivers/watchdog/rti_wdt.c | 194 ++++++++++++++++++++++++++++---------
  11. 1 file changed, 146 insertions(+), 48 deletions(-)
  12. diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
  13. index b0933b090f53..e3c90e617c7a 100644
  14. --- a/drivers/watchdog/rti_wdt.c
  15. +++ b/drivers/watchdog/rti_wdt.c
  16. @@ -2,26 +2,27 @@
  17. /*
  18. * Watchdog driver for the K3 RTI module
  19. *
  20. - * (c) Copyright 2019 Texas Instruments Inc.
  21. + * (c) Copyright 2019-2020 Texas Instruments Inc.
  22. * All rights reserved.
  23. */
  24. +#include <linux/clk.h>
  25. +#include <linux/device.h>
  26. +#include <linux/err.h>
  27. +#include <linux/io.h>
  28. +#include <linux/kernel.h>
  29. +#include <linux/mod_devicetable.h>
  30. #include <linux/module.h>
  31. #include <linux/moduleparam.h>
  32. -#include <linux/mod_devicetable.h>
  33. -#include <linux/types.h>
  34. -#include <linux/kernel.h>
  35. -#include <linux/watchdog.h>
  36. #include <linux/platform_device.h>
  37. -#include <linux/io.h>
  38. -#include <linux/device.h>
  39. -#include <linux/clk.h>
  40. -#include <linux/err.h>
  41. #include <linux/pm_runtime.h>
  42. +#include <linux/types.h>
  43. +#include <linux/watchdog.h>
  44. -#define MODULE_NAME "rti-wdt"
  45. #define DEFAULT_HEARTBEAT 60
  46. -#define MAX_HEARTBEAT 1000
  47. +
  48. +/* Max heartbeat is calculated at 32kHz source clock */
  49. +#define MAX_HEARTBEAT 1000
  50. /* Timer register set definition */
  51. #define RTIDWDCTRL 0x90
  52. @@ -34,7 +35,11 @@
  53. #define RTIWWDRX_NMI 0xa
  54. -#define RTIWWDSIZE_50P 0x50
  55. +#define RTIWWDSIZE_50P 0x50
  56. +#define RTIWWDSIZE_25P 0x500
  57. +#define RTIWWDSIZE_12P5 0x5000
  58. +#define RTIWWDSIZE_6P25 0x50000
  59. +#define RTIWWDSIZE_3P125 0x500000
  60. #define WDENABLE_KEY 0xa98559da
  61. @@ -47,42 +52,45 @@
  62. #define DWDST BIT(1)
  63. -static int heartbeat;
  64. +static int heartbeat = DEFAULT_HEARTBEAT;
  65. /*
  66. * struct to hold data for each WDT device
  67. * @base - base io address of WD device
  68. - * @clk - source clock of WDT
  69. - * @wdd - hold watchdog device as is in WDT core
  70. + * @freq - source clock frequency of WDT
  71. + * @wdd - hold watchdog device as is in WDT core
  72. */
  73. struct rti_wdt_device {
  74. void __iomem *base;
  75. - struct clk *clk;
  76. + unsigned long freq;
  77. struct watchdog_device wdd;
  78. };
  79. static int rti_wdt_start(struct watchdog_device *wdd)
  80. {
  81. u32 timer_margin;
  82. - unsigned long freq;
  83. struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
  84. - freq = clk_get_rate(wdt->clk);
  85. -
  86. /* set timeout period */
  87. - timer_margin = (u64)wdd->timeout * freq;
  88. + timer_margin = (u64)wdd->timeout * wdt->freq;
  89. timer_margin >>= WDT_PRELOAD_SHIFT;
  90. if (timer_margin > WDT_PRELOAD_MAX)
  91. timer_margin = WDT_PRELOAD_MAX;
  92. writel_relaxed(timer_margin, wdt->base + RTIDWDPRLD);
  93. - /* Set min heartbeat to 1.1x window size */
  94. - wdd->min_hw_heartbeat_ms = 11 * wdd->timeout * 1000 / 20;
  95. + /*
  96. + * RTI only supports a windowed mode, where the watchdog can only
  97. + * be petted during the open window; not too early or not too late.
  98. + * The HW configuration options only allow for the open window size
  99. + * to be 50% or less than that; we obviouly want to configure the open
  100. + * window as large as possible so we select the 50% option.
  101. + */
  102. + wdd->min_hw_heartbeat_ms = 500 * wdd->timeout;
  103. /* Generate NMI when wdt expires */
  104. writel_relaxed(RTIWWDRX_NMI, wdt->base + RTIWWDRXCTRL);
  105. - /* Window size 50% */
  106. + /* Open window size 50%; this is the largest window size available */
  107. writel_relaxed(RTIWWDSIZE_50P, wdt->base + RTIWWDSIZECTRL);
  108. readl_relaxed(wdt->base + RTIWWDSIZECTRL);
  109. @@ -101,16 +109,53 @@ static int rti_wdt_ping(struct watchdog_device *wdd)
  110. /* put watchdog in active state */
  111. writel_relaxed(WDKEY_SEQ1, wdt->base + RTIWDKEY);
  112. - if (readl_relaxed(wdt->base + RTIWDSTATUS))
  113. - WARN_ON_ONCE(1);
  114. + return 0;
  115. +}
  116. +
  117. +static int rti_wdt_setup_hw_hb(struct watchdog_device *wdd, u32 wsize)
  118. +{
  119. + /*
  120. + * RTI only supports a windowed mode, where the watchdog can only
  121. + * be petted during the open window; not too early or not too late.
  122. + * The HW configuration options only allow for the open window size
  123. + * to be 50% or less than that.
  124. + */
  125. + switch (wsize) {
  126. + case RTIWWDSIZE_50P:
  127. + /* 50% open window => 50% min heartbeat */
  128. + wdd->min_hw_heartbeat_ms = 500 * heartbeat;
  129. + break;
  130. +
  131. + case RTIWWDSIZE_25P:
  132. + /* 25% open window => 75% min heartbeat */
  133. + wdd->min_hw_heartbeat_ms = 750 * heartbeat;
  134. + break;
  135. +
  136. + case RTIWWDSIZE_12P5:
  137. + /* 12.5% open window => 87.5% min heartbeat */
  138. + wdd->min_hw_heartbeat_ms = 875 * heartbeat;
  139. + break;
  140. +
  141. + case RTIWWDSIZE_6P25:
  142. + /* 6.5% open window => 93.5% min heartbeat */
  143. + wdd->min_hw_heartbeat_ms = 935 * heartbeat;
  144. + break;
  145. +
  146. + case RTIWWDSIZE_3P125:
  147. + /* 3.125% open window => 96.9% min heartbeat */
  148. + wdd->min_hw_heartbeat_ms = 969 * heartbeat;
  149. + break;
  150. +
  151. + default:
  152. + return -EINVAL;
  153. + }
  154. return 0;
  155. }
  156. -static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
  157. +static unsigned int rti_wdt_get_timeleft_ms(struct watchdog_device *wdd)
  158. {
  159. u64 timer_counter;
  160. - unsigned long freq;
  161. u32 val;
  162. struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
  163. @@ -119,17 +164,20 @@ static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
  164. if (val & DWDST)
  165. return 0;
  166. - freq = clk_get_rate(wdt->clk);
  167. - if (!freq)
  168. - return 0;
  169. -
  170. timer_counter = readl_relaxed(wdt->base + RTIDWDCNTR);
  171. - do_div(timer_counter, freq);
  172. + timer_counter *= 1000;
  173. +
  174. + do_div(timer_counter, wdt->freq);
  175. return timer_counter;
  176. }
  177. +static unsigned int rti_wdt_get_timeleft(struct watchdog_device *wdd)
  178. +{
  179. + return rti_wdt_get_timeleft_ms(wdd) / 1000;
  180. +}
  181. +
  182. static const struct watchdog_info rti_wdt_info = {
  183. .options = WDIOF_KEEPALIVEPING,
  184. .identity = "K3 RTI Watchdog",
  185. @@ -149,23 +197,43 @@ static int rti_wdt_probe(struct platform_device *pdev)
  186. struct resource *wdt_mem;
  187. struct watchdog_device *wdd;
  188. struct rti_wdt_device *wdt;
  189. + struct clk *clk;
  190. + u32 last_ping = 0;
  191. wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
  192. if (!wdt)
  193. return -ENOMEM;
  194. - wdt->clk = devm_clk_get(dev, NULL);
  195. - if (IS_ERR(wdt->clk)) {
  196. - if (PTR_ERR(wdt->clk) != -EPROBE_DEFER)
  197. + clk = clk_get(dev, NULL);
  198. + if (IS_ERR(clk)) {
  199. + if (PTR_ERR(clk) != -EPROBE_DEFER)
  200. dev_err(dev, "failed to get clock\n");
  201. - return PTR_ERR(wdt->clk);
  202. + return PTR_ERR(clk);
  203. + }
  204. +
  205. + wdt->freq = clk_get_rate(clk);
  206. +
  207. + clk_put(clk);
  208. +
  209. + if (!wdt->freq) {
  210. + dev_err(dev, "Failed to get fck rate.\n");
  211. + return -EINVAL;
  212. }
  213. + /*
  214. + * If watchdog is running at 32k clock, it is not accurate.
  215. + * Adjust frequency down in this case so that we don't pet
  216. + * the watchdog too often.
  217. + */
  218. + if (wdt->freq < 32768)
  219. + wdt->freq = wdt->freq * 9 / 10;
  220. +
  221. pm_runtime_enable(dev);
  222. ret = pm_runtime_get_sync(dev);
  223. if (ret) {
  224. + pm_runtime_put_noidle(dev);
  225. if (ret != -EPROBE_DEFER)
  226. - dev_err(&pdev->dev, "runtime pm failed\n");
  227. + dev_err(dev, "runtime pm failed\n");
  228. return ret;
  229. }
  230. @@ -175,18 +243,10 @@ static int rti_wdt_probe(struct platform_device *pdev)
  231. wdd->info = &rti_wdt_info;
  232. wdd->ops = &rti_wdt_ops;
  233. wdd->min_timeout = 1;
  234. - /* Set min heartbeat to 1.1x window size */
  235. - wdd->min_hw_heartbeat_ms = 11 * DEFAULT_HEARTBEAT * 1000 / 20;
  236. - wdd->max_hw_heartbeat_ms = MAX_HEARTBEAT * 1000;
  237. - wdd->timeout = DEFAULT_HEARTBEAT;
  238. + wdd->max_hw_heartbeat_ms = (WDT_PRELOAD_MAX << WDT_PRELOAD_SHIFT) /
  239. + wdt->freq * 1000;
  240. wdd->parent = dev;
  241. - set_bit(WDOG_RESET_KEEPALIVE, &wdd->status);
  242. -
  243. - watchdog_init_timeout(wdd, heartbeat, dev);
  244. -
  245. - dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
  246. -
  247. watchdog_set_drvdata(wdd, wdt);
  248. watchdog_set_nowayout(wdd, 1);
  249. watchdog_set_restart_priority(wdd, 128);
  250. @@ -198,16 +258,53 @@ static int rti_wdt_probe(struct platform_device *pdev)
  251. goto err_iomap;
  252. }
  253. + if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) {
  254. + u32 time_left_ms;
  255. + u64 heartbeat_ms;
  256. + u32 wsize;
  257. +
  258. + set_bit(WDOG_HW_RUNNING, &wdd->status);
  259. + time_left_ms = rti_wdt_get_timeleft_ms(wdd);
  260. + heartbeat_ms = readl(wdt->base + RTIDWDPRLD);
  261. + heartbeat_ms <<= WDT_PRELOAD_SHIFT;
  262. + heartbeat_ms *= 1000;
  263. + do_div(heartbeat_ms, wdt->freq);
  264. + if (heartbeat_ms != heartbeat * 1000)
  265. + dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n");
  266. +
  267. + heartbeat = heartbeat_ms;
  268. + heartbeat /= 1000;
  269. +
  270. + wsize = readl(wdt->base + RTIWWDSIZECTRL);
  271. + ret = rti_wdt_setup_hw_hb(wdd, wsize);
  272. + if (ret) {
  273. + dev_err(dev, "bad window size.\n");
  274. + goto err_iomap;
  275. + }
  276. +
  277. + last_ping = heartbeat_ms - time_left_ms;
  278. + if (time_left_ms > heartbeat_ms) {
  279. + dev_warn(dev, "time_left > heartbeat? Assuming last ping just before now.\n");
  280. + last_ping = 0;
  281. + }
  282. + }
  283. +
  284. + watchdog_init_timeout(wdd, heartbeat, dev);
  285. +
  286. ret = watchdog_register_device(wdd);
  287. if (ret) {
  288. dev_err(dev, "cannot register watchdog device\n");
  289. goto err_iomap;
  290. }
  291. + if (last_ping)
  292. + watchdog_set_last_hw_keepalive(wdd, last_ping);
  293. +
  294. return 0;
  295. err_iomap:
  296. pm_runtime_put_sync(&pdev->dev);
  297. + pm_runtime_disable(&pdev->dev);
  298. return ret;
  299. }
  300. @@ -218,12 +315,13 @@ static int rti_wdt_remove(struct platform_device *pdev)
  301. watchdog_unregister_device(&wdt->wdd);
  302. pm_runtime_put(&pdev->dev);
  303. + pm_runtime_disable(&pdev->dev);
  304. return 0;
  305. }
  306. static const struct of_device_id rti_wdt_of_match[] = {
  307. - { .compatible = "ti,rti-wdt", },
  308. + { .compatible = "ti,j7-rti-wdt", },
  309. {},
  310. };
  311. MODULE_DEVICE_TABLE(of, rti_wdt_of_match);
  312. --
  313. 2.31.1