cdns_wdt.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Cadence WDT driver - Used by Xilinx Zynq
  4. * Reference: Linux kernel Cadence watchdog driver.
  5. *
  6. * Author(s): Shreenidhi Shedi <yesshedi@gmail.com>
  7. */
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <log.h>
  11. #include <wdt.h>
  12. #include <clk.h>
  13. #include <div64.h>
  14. #include <dm/device_compat.h>
  15. #include <linux/err.h>
  16. #include <linux/io.h>
  17. struct cdns_regs {
  18. u32 zmr; /* WD Zero mode register, offset - 0x0 */
  19. u32 ccr; /* Counter Control Register offset - 0x4 */
  20. u32 restart; /* Restart key register, offset - 0x8 */
  21. u32 status; /* Status Register, offset - 0xC */
  22. };
  23. struct cdns_wdt_priv {
  24. bool rst;
  25. struct cdns_regs *regs;
  26. };
  27. #define CDNS_WDT_DEFAULT_TIMEOUT 10
  28. /* Supports 1 - 516 sec */
  29. #define CDNS_WDT_MIN_TIMEOUT 1
  30. #define CDNS_WDT_MAX_TIMEOUT 516
  31. /* Restart key */
  32. #define CDNS_WDT_RESTART_KEY 0x00001999
  33. /* Counter register access key */
  34. #define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
  35. /* Counter value divisor */
  36. #define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
  37. /* Clock prescaler value and selection */
  38. #define CDNS_WDT_PRESCALE_64 64
  39. #define CDNS_WDT_PRESCALE_512 512
  40. #define CDNS_WDT_PRESCALE_4096 4096
  41. #define CDNS_WDT_PRESCALE_SELECT_64 1
  42. #define CDNS_WDT_PRESCALE_SELECT_512 2
  43. #define CDNS_WDT_PRESCALE_SELECT_4096 3
  44. /* Input clock frequency */
  45. #define CDNS_WDT_CLK_75MHZ 75000000
  46. /* Counter maximum value */
  47. #define CDNS_WDT_COUNTER_MAX 0xFFF
  48. /********************* Register Map **********************************/
  49. /*
  50. * Zero Mode Register - This register controls how the time out is indicated
  51. * and also contains the access code to allow writes to the register (0xABC).
  52. */
  53. #define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
  54. #define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
  55. #define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
  56. #define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
  57. #define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
  58. /*
  59. * Counter Control register - This register controls how fast the timer runs
  60. * and the reset value and also contains the access code to allow writes to
  61. * the register.
  62. */
  63. #define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
  64. /* Write access to Registers */
  65. static inline void cdns_wdt_writereg(u32 *addr, u32 val)
  66. {
  67. writel(val, addr);
  68. }
  69. /**
  70. * cdns_wdt_reset - Reload the watchdog timer (i.e. pat the watchdog).
  71. *
  72. * @dev: Watchdog device
  73. *
  74. * Write the restart key value (0x00001999) to the restart register.
  75. *
  76. * Return: Always 0
  77. */
  78. static int cdns_wdt_reset(struct udevice *dev)
  79. {
  80. struct cdns_wdt_priv *priv = dev_get_priv(dev);
  81. debug("%s\n", __func__);
  82. cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
  83. return 0;
  84. }
  85. /**
  86. * cdns_wdt_start - Enable and start the watchdog.
  87. *
  88. * @dev: Watchdog device
  89. * @timeout: Timeout value
  90. * @flags: Driver flags
  91. *
  92. * The counter value is calculated according to the formula:
  93. * count = (timeout * clock) / prescaler + 1.
  94. *
  95. * The calculated count is divided by 0x1000 to obtain the field value
  96. * to write to counter control register.
  97. *
  98. * Clears the contents of prescaler and counter reset value. Sets the
  99. * prescaler to 4096 and the calculated count and access key
  100. * to write to CCR Register.
  101. *
  102. * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
  103. * or Interrupt signal(IRQEN) with a specified cycles and the access
  104. * key to write to ZMR Register.
  105. *
  106. * Return: Upon success 0, failure -1.
  107. */
  108. static int cdns_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
  109. {
  110. ulong clk_f;
  111. u32 count, prescaler, ctrl_clksel, data = 0;
  112. struct clk clock;
  113. struct cdns_wdt_priv *priv = dev_get_priv(dev);
  114. if (clk_get_by_index(dev, 0, &clock) < 0) {
  115. dev_err(dev, "failed to get clock\n");
  116. return -1;
  117. }
  118. clk_f = clk_get_rate(&clock);
  119. if (IS_ERR_VALUE(clk_f)) {
  120. dev_err(dev, "failed to get rate\n");
  121. return -1;
  122. }
  123. /* Calculate timeout in seconds and restrict to min and max value */
  124. do_div(timeout, 1000);
  125. timeout = max_t(u64, timeout, CDNS_WDT_MIN_TIMEOUT);
  126. timeout = min_t(u64, timeout, CDNS_WDT_MAX_TIMEOUT);
  127. debug("%s: CLK_FREQ %ld, timeout %lld\n", __func__, clk_f, timeout);
  128. if (clk_f <= CDNS_WDT_CLK_75MHZ) {
  129. prescaler = CDNS_WDT_PRESCALE_512;
  130. ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
  131. } else {
  132. prescaler = CDNS_WDT_PRESCALE_4096;
  133. ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
  134. }
  135. /*
  136. * Counter value divisor to obtain the value of
  137. * counter reset to be written to control register.
  138. */
  139. count = (timeout * (clk_f / prescaler)) /
  140. CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
  141. if (count > CDNS_WDT_COUNTER_MAX)
  142. count = CDNS_WDT_COUNTER_MAX;
  143. cdns_wdt_writereg(&priv->regs->zmr, CDNS_WDT_ZMR_ZKEY_VAL);
  144. count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
  145. /* Write counter access key first to be able write to register */
  146. data = count | CDNS_WDT_REGISTER_ACCESS_KEY | ctrl_clksel;
  147. cdns_wdt_writereg(&priv->regs->ccr, data);
  148. data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
  149. CDNS_WDT_ZMR_ZKEY_VAL;
  150. /* Reset on timeout if specified in device tree. */
  151. if (priv->rst) {
  152. data |= CDNS_WDT_ZMR_RSTEN_MASK;
  153. data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
  154. } else {
  155. data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
  156. data |= CDNS_WDT_ZMR_IRQEN_MASK;
  157. }
  158. cdns_wdt_writereg(&priv->regs->zmr, data);
  159. cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
  160. return 0;
  161. }
  162. /**
  163. * cdns_wdt_stop - Stop the watchdog.
  164. *
  165. * @dev: Watchdog device
  166. *
  167. * Read the contents of the ZMR register, clear the WDEN bit in the register
  168. * and set the access key for successful write.
  169. *
  170. * Return: Always 0
  171. */
  172. static int cdns_wdt_stop(struct udevice *dev)
  173. {
  174. struct cdns_wdt_priv *priv = dev_get_priv(dev);
  175. cdns_wdt_writereg(&priv->regs->zmr,
  176. CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
  177. return 0;
  178. }
  179. /**
  180. * cdns_wdt_expire_now - Expire the watchdog.
  181. *
  182. * @dev: Watchdog device
  183. * @flags: Driver flags
  184. *
  185. * Access WDT and configure with minimal counter value to expire ASAP.
  186. * Expiration issues system reset. When DEBUG is enabled count should be
  187. * bigger to at least see debug message.
  188. *
  189. * Return: Always 0
  190. */
  191. static int cdns_wdt_expire_now(struct udevice *dev, ulong flags)
  192. {
  193. struct cdns_wdt_priv *priv = dev_get_priv(dev);
  194. u32 data, count = 0;
  195. #if defined(DEBUG)
  196. count = 0x40; /* Increase the value if you need more time */
  197. debug("%s: Expire wdt%u\n", __func__, dev_seq(dev));
  198. #endif
  199. cdns_wdt_writereg(&priv->regs->zmr, CDNS_WDT_ZMR_ZKEY_VAL);
  200. count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
  201. /* Write counter access key first to be able write to register */
  202. data = count | CDNS_WDT_REGISTER_ACCESS_KEY;
  203. cdns_wdt_writereg(&priv->regs->ccr, data);
  204. data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTEN_MASK |
  205. CDNS_WDT_ZMR_ZKEY_VAL;
  206. cdns_wdt_writereg(&priv->regs->zmr, data);
  207. cdns_wdt_writereg(&priv->regs->restart, CDNS_WDT_RESTART_KEY);
  208. return 0;
  209. }
  210. /**
  211. * cdns_wdt_probe - Probe call for the device.
  212. *
  213. * @dev: Handle to the udevice structure.
  214. *
  215. * Return: Always 0.
  216. */
  217. static int cdns_wdt_probe(struct udevice *dev)
  218. {
  219. debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
  220. return 0;
  221. }
  222. static int cdns_wdt_of_to_plat(struct udevice *dev)
  223. {
  224. struct cdns_wdt_priv *priv = dev_get_priv(dev);
  225. priv->regs = (struct cdns_regs *)dev_read_addr(dev);
  226. if (IS_ERR(priv->regs))
  227. return PTR_ERR(priv->regs);
  228. priv->rst = dev_read_bool(dev, "reset-on-timeout");
  229. debug("%s: reset %d\n", __func__, priv->rst);
  230. return 0;
  231. }
  232. static const struct wdt_ops cdns_wdt_ops = {
  233. .start = cdns_wdt_start,
  234. .reset = cdns_wdt_reset,
  235. .stop = cdns_wdt_stop,
  236. .expire_now = cdns_wdt_expire_now,
  237. };
  238. static const struct udevice_id cdns_wdt_ids[] = {
  239. { .compatible = "cdns,wdt-r1p2" },
  240. {}
  241. };
  242. U_BOOT_DRIVER(cdns_wdt) = {
  243. .name = "cdns_wdt",
  244. .id = UCLASS_WDT,
  245. .of_match = cdns_wdt_ids,
  246. .probe = cdns_wdt_probe,
  247. .priv_auto = sizeof(struct cdns_wdt_priv),
  248. .of_to_plat = cdns_wdt_of_to_plat,
  249. .ops = &cdns_wdt_ops,
  250. };