orion_wdt.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * drivers/watchdog/orion_wdt.c
  3. *
  4. * Watchdog driver for Orion/Kirkwood processors
  5. *
  6. * Authors: Tomas Hlavacek <tmshlvck@gmail.com>
  7. * Sylver Bruneau <sylver.bruneau@googlemail.com>
  8. * Marek Behun <marek.behun@nic.cz>
  9. *
  10. * This file is licensed under the terms of the GNU General Public
  11. * License version 2. This program is licensed "as is" without any
  12. * warranty of any kind, whether express or implied.
  13. */
  14. #include <common.h>
  15. #include <dm.h>
  16. #include <clk.h>
  17. #include <log.h>
  18. #include <wdt.h>
  19. #include <asm/global_data.h>
  20. #include <linux/bitops.h>
  21. #include <linux/kernel.h>
  22. #include <asm/io.h>
  23. #include <asm/arch/cpu.h>
  24. #include <asm/arch/soc.h>
  25. DECLARE_GLOBAL_DATA_PTR;
  26. struct orion_wdt_priv {
  27. void __iomem *reg;
  28. int wdt_counter_offset;
  29. void __iomem *rstout;
  30. void __iomem *rstout_mask;
  31. u32 timeout;
  32. unsigned long clk_rate;
  33. struct clk clk;
  34. };
  35. #define RSTOUT_ENABLE_BIT BIT(8)
  36. #define RSTOUT_MASK_BIT BIT(10)
  37. #define WDT_ENABLE_BIT BIT(8)
  38. #define TIMER_CTRL 0x0000
  39. #define TIMER_A370_STATUS 0x04
  40. #define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
  41. #define WDT_A370_EXPIRED BIT(31)
  42. static int orion_wdt_reset(struct udevice *dev)
  43. {
  44. struct orion_wdt_priv *priv = dev_get_priv(dev);
  45. /* Reload watchdog duration */
  46. writel(priv->clk_rate * priv->timeout,
  47. priv->reg + priv->wdt_counter_offset);
  48. return 0;
  49. }
  50. static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
  51. {
  52. struct orion_wdt_priv *priv = dev_get_priv(dev);
  53. u32 reg;
  54. priv->timeout = DIV_ROUND_UP(timeout_ms, 1000);
  55. /* Enable the fixed watchdog clock input */
  56. reg = readl(priv->reg + TIMER_CTRL);
  57. reg |= WDT_AXP_FIXED_ENABLE_BIT;
  58. writel(reg, priv->reg + TIMER_CTRL);
  59. /* Set watchdog duration */
  60. writel(priv->clk_rate * priv->timeout,
  61. priv->reg + priv->wdt_counter_offset);
  62. /* Clear the watchdog expiration bit */
  63. reg = readl(priv->reg + TIMER_A370_STATUS);
  64. reg &= ~WDT_A370_EXPIRED;
  65. writel(reg, priv->reg + TIMER_A370_STATUS);
  66. /* Enable watchdog timer */
  67. reg = readl(priv->reg + TIMER_CTRL);
  68. reg |= WDT_ENABLE_BIT;
  69. writel(reg, priv->reg + TIMER_CTRL);
  70. /* Enable reset on watchdog */
  71. reg = readl(priv->rstout);
  72. reg |= RSTOUT_ENABLE_BIT;
  73. writel(reg, priv->rstout);
  74. reg = readl(priv->rstout_mask);
  75. reg &= ~RSTOUT_MASK_BIT;
  76. writel(reg, priv->rstout_mask);
  77. return 0;
  78. }
  79. static int orion_wdt_stop(struct udevice *dev)
  80. {
  81. struct orion_wdt_priv *priv = dev_get_priv(dev);
  82. u32 reg;
  83. /* Disable reset on watchdog */
  84. reg = readl(priv->rstout_mask);
  85. reg |= RSTOUT_MASK_BIT;
  86. writel(reg, priv->rstout_mask);
  87. reg = readl(priv->rstout);
  88. reg &= ~RSTOUT_ENABLE_BIT;
  89. writel(reg, priv->rstout);
  90. /* Disable watchdog timer */
  91. reg = readl(priv->reg + TIMER_CTRL);
  92. reg &= ~WDT_ENABLE_BIT;
  93. writel(reg, priv->reg + TIMER_CTRL);
  94. return 0;
  95. }
  96. static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
  97. void __iomem **reg, int *offset)
  98. {
  99. fdt_addr_t addr;
  100. fdt_size_t off;
  101. addr = devfdt_get_addr_size_index(dev, index, &off);
  102. if (addr == FDT_ADDR_T_NONE)
  103. return false;
  104. *reg = (void __iomem *) addr;
  105. if (offset)
  106. *offset = off;
  107. return true;
  108. }
  109. static int orion_wdt_of_to_plat(struct udevice *dev)
  110. {
  111. struct orion_wdt_priv *priv = dev_get_priv(dev);
  112. if (!save_reg_from_ofdata(dev, 0, &priv->reg,
  113. &priv->wdt_counter_offset))
  114. goto err;
  115. if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
  116. goto err;
  117. if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
  118. goto err;
  119. return 0;
  120. err:
  121. debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
  122. return -ENXIO;
  123. }
  124. static int orion_wdt_probe(struct udevice *dev)
  125. {
  126. struct orion_wdt_priv *priv = dev_get_priv(dev);
  127. int ret;
  128. debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
  129. orion_wdt_stop(dev);
  130. ret = clk_get_by_name(dev, "fixed", &priv->clk);
  131. if (!ret)
  132. priv->clk_rate = clk_get_rate(&priv->clk);
  133. else
  134. priv->clk_rate = 25000000;
  135. return 0;
  136. }
  137. static const struct wdt_ops orion_wdt_ops = {
  138. .start = orion_wdt_start,
  139. .reset = orion_wdt_reset,
  140. .stop = orion_wdt_stop,
  141. };
  142. static const struct udevice_id orion_wdt_ids[] = {
  143. { .compatible = "marvell,armada-380-wdt" },
  144. {}
  145. };
  146. U_BOOT_DRIVER(orion_wdt) = {
  147. .name = "orion_wdt",
  148. .id = UCLASS_WDT,
  149. .of_match = orion_wdt_ids,
  150. .probe = orion_wdt_probe,
  151. .priv_auto = sizeof(struct orion_wdt_priv),
  152. .of_to_plat = orion_wdt_of_to_plat,
  153. .ops = &orion_wdt_ops,
  154. };