cdns_wdt.c 6.8 KB

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