orion_wdt.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 <wdt.h>
  17. #include <asm/io.h>
  18. #include <asm/arch/cpu.h>
  19. #include <asm/arch/soc.h>
  20. DECLARE_GLOBAL_DATA_PTR;
  21. struct orion_wdt_priv {
  22. void __iomem *reg;
  23. int wdt_counter_offset;
  24. void __iomem *rstout;
  25. void __iomem *rstout_mask;
  26. u32 timeout;
  27. };
  28. #define RSTOUT_ENABLE_BIT BIT(8)
  29. #define RSTOUT_MASK_BIT BIT(10)
  30. #define WDT_ENABLE_BIT BIT(8)
  31. #define TIMER_CTRL 0x0000
  32. #define TIMER_A370_STATUS 0x04
  33. #define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
  34. #define WDT_A370_EXPIRED BIT(31)
  35. static int orion_wdt_reset(struct udevice *dev)
  36. {
  37. struct orion_wdt_priv *priv = dev_get_priv(dev);
  38. /* Reload watchdog duration */
  39. writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
  40. return 0;
  41. }
  42. static int orion_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
  43. {
  44. struct orion_wdt_priv *priv = dev_get_priv(dev);
  45. u32 reg;
  46. priv->timeout = (u32) timeout;
  47. /* Enable the fixed watchdog clock input */
  48. reg = readl(priv->reg + TIMER_CTRL);
  49. reg |= WDT_AXP_FIXED_ENABLE_BIT;
  50. writel(reg, priv->reg + TIMER_CTRL);
  51. /* Set watchdog duration */
  52. writel(priv->timeout, priv->reg + priv->wdt_counter_offset);
  53. /* Clear the watchdog expiration bit */
  54. reg = readl(priv->reg + TIMER_A370_STATUS);
  55. reg &= ~WDT_A370_EXPIRED;
  56. writel(reg, priv->reg + TIMER_A370_STATUS);
  57. /* Enable watchdog timer */
  58. reg = readl(priv->reg + TIMER_CTRL);
  59. reg |= WDT_ENABLE_BIT;
  60. writel(reg, priv->reg + TIMER_CTRL);
  61. /* Enable reset on watchdog */
  62. reg = readl(priv->rstout);
  63. reg |= RSTOUT_ENABLE_BIT;
  64. writel(reg, priv->rstout);
  65. reg = readl(priv->rstout_mask);
  66. reg &= ~RSTOUT_MASK_BIT;
  67. writel(reg, priv->rstout_mask);
  68. return 0;
  69. }
  70. static int orion_wdt_stop(struct udevice *dev)
  71. {
  72. struct orion_wdt_priv *priv = dev_get_priv(dev);
  73. u32 reg;
  74. /* Disable reset on watchdog */
  75. reg = readl(priv->rstout_mask);
  76. reg |= RSTOUT_MASK_BIT;
  77. writel(reg, priv->rstout_mask);
  78. reg = readl(priv->rstout);
  79. reg &= ~RSTOUT_ENABLE_BIT;
  80. writel(reg, priv->rstout);
  81. /* Disable watchdog timer */
  82. reg = readl(priv->reg + TIMER_CTRL);
  83. reg &= ~WDT_ENABLE_BIT;
  84. writel(reg, priv->reg + TIMER_CTRL);
  85. return 0;
  86. }
  87. static inline bool save_reg_from_ofdata(struct udevice *dev, int index,
  88. void __iomem **reg, int *offset)
  89. {
  90. fdt_addr_t addr;
  91. fdt_size_t off;
  92. addr = fdtdec_get_addr_size_auto_noparent(
  93. gd->fdt_blob, dev_of_offset(dev), "reg", index, &off, true);
  94. if (addr == FDT_ADDR_T_NONE)
  95. return false;
  96. *reg = (void __iomem *) addr;
  97. if (offset)
  98. *offset = off;
  99. return true;
  100. }
  101. static int orion_wdt_ofdata_to_platdata(struct udevice *dev)
  102. {
  103. struct orion_wdt_priv *priv = dev_get_priv(dev);
  104. if (!save_reg_from_ofdata(dev, 0, &priv->reg,
  105. &priv->wdt_counter_offset))
  106. goto err;
  107. if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL))
  108. goto err;
  109. if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL))
  110. goto err;
  111. return 0;
  112. err:
  113. debug("%s: Could not determine Orion wdt IO addresses\n", __func__);
  114. return -ENXIO;
  115. }
  116. static int orion_wdt_probe(struct udevice *dev)
  117. {
  118. debug("%s: Probing wdt%u\n", __func__, dev->seq);
  119. orion_wdt_stop(dev);
  120. return 0;
  121. }
  122. static const struct wdt_ops orion_wdt_ops = {
  123. .start = orion_wdt_start,
  124. .reset = orion_wdt_reset,
  125. .stop = orion_wdt_stop,
  126. };
  127. static const struct udevice_id orion_wdt_ids[] = {
  128. { .compatible = "marvell,armada-380-wdt" },
  129. {}
  130. };
  131. U_BOOT_DRIVER(orion_wdt) = {
  132. .name = "orion_wdt",
  133. .id = UCLASS_WDT,
  134. .of_match = orion_wdt_ids,
  135. .probe = orion_wdt_probe,
  136. .priv_auto_alloc_size = sizeof(struct orion_wdt_priv),
  137. .ofdata_to_platdata = orion_wdt_ofdata_to_platdata,
  138. .ops = &orion_wdt_ops,
  139. };