wdt.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * TNETV107X: Watchdog timer implementation (for reset)
  3. *
  4. * See file CREDITS for list of people who contributed to this
  5. * project.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <common.h>
  22. #include <asm/io.h>
  23. #include <asm/arch/clock.h>
  24. #define MAX_DIV 0xFFFE0001
  25. struct wdt_regs {
  26. u32 kick_lock;
  27. #define KICK_LOCK_1 0x5555
  28. #define KICK_LOCK_2 0xaaaa
  29. u32 kick;
  30. u32 change_lock;
  31. #define CHANGE_LOCK_1 0x6666
  32. #define CHANGE_LOCK_2 0xbbbb
  33. u32 change;
  34. u32 disable_lock;
  35. #define DISABLE_LOCK_1 0x7777
  36. #define DISABLE_LOCK_2 0xcccc
  37. #define DISABLE_LOCK_3 0xdddd
  38. u32 disable;
  39. u32 prescale_lock;
  40. #define PRESCALE_LOCK_1 0x5a5a
  41. #define PRESCALE_LOCK_2 0xa5a5
  42. u32 prescale;
  43. };
  44. static struct wdt_regs* regs = (struct wdt_regs *)TNETV107X_WDT0_ARM_BASE;
  45. #define wdt_reg_read(reg) __raw_readl(&regs->reg)
  46. #define wdt_reg_write(reg, val) __raw_writel((val), &regs->reg)
  47. static int write_prescale_reg(unsigned long prescale_value)
  48. {
  49. wdt_reg_write(prescale_lock, PRESCALE_LOCK_1);
  50. if ((wdt_reg_read(prescale_lock) & 0x3) != 0x1)
  51. return -1;
  52. wdt_reg_write(prescale_lock, PRESCALE_LOCK_2);
  53. if ((wdt_reg_read(prescale_lock) & 0x3) != 0x3)
  54. return -1;
  55. wdt_reg_write(prescale, prescale_value);
  56. return 0;
  57. }
  58. static int write_change_reg(unsigned long initial_timer_value)
  59. {
  60. wdt_reg_write(change_lock, CHANGE_LOCK_1);
  61. if ((wdt_reg_read(change_lock) & 0x3) != 0x1)
  62. return -1;
  63. wdt_reg_write(change_lock, CHANGE_LOCK_2);
  64. if ((wdt_reg_read(change_lock) & 0x3) != 0x3)
  65. return -1;
  66. wdt_reg_write(change, initial_timer_value);
  67. return 0;
  68. }
  69. static int wdt_control(unsigned long disable_value)
  70. {
  71. wdt_reg_write(disable_lock, DISABLE_LOCK_1);
  72. if ((wdt_reg_read(disable_lock) & 0x3) != 0x1)
  73. return -1;
  74. wdt_reg_write(disable_lock, DISABLE_LOCK_2);
  75. if ((wdt_reg_read(disable_lock) & 0x3) != 0x2)
  76. return -1;
  77. wdt_reg_write(disable_lock, DISABLE_LOCK_3);
  78. if ((wdt_reg_read(disable_lock) & 0x3) != 0x3)
  79. return -1;
  80. wdt_reg_write(disable, disable_value);
  81. return 0;
  82. }
  83. static int wdt_set_period(unsigned long msec)
  84. {
  85. unsigned long change_value, count_value;
  86. unsigned long prescale_value = 1;
  87. unsigned long refclk_khz, maxdiv;
  88. int ret;
  89. refclk_khz = clk_get_rate(TNETV107X_LPSC_WDT_ARM);
  90. maxdiv = (MAX_DIV / refclk_khz);
  91. if ((!msec) || (msec > maxdiv))
  92. return -1;
  93. count_value = refclk_khz * msec;
  94. if (count_value > 0xffff) {
  95. change_value = count_value / 0xffff + 1;
  96. prescale_value = count_value / change_value;
  97. } else {
  98. change_value = count_value;
  99. }
  100. ret = write_prescale_reg(prescale_value - 1);
  101. if (ret)
  102. return ret;
  103. ret = write_change_reg(change_value);
  104. if (ret)
  105. return ret;
  106. return 0;
  107. }
  108. unsigned long last_wdt = -1;
  109. int wdt_start(unsigned long msecs)
  110. {
  111. int ret;
  112. ret = wdt_control(0);
  113. if (ret)
  114. return ret;
  115. ret = wdt_set_period(msecs);
  116. if (ret)
  117. return ret;
  118. ret = wdt_control(1);
  119. if (ret)
  120. return ret;
  121. ret = wdt_kick();
  122. last_wdt = msecs;
  123. return ret;
  124. }
  125. int wdt_stop(void)
  126. {
  127. last_wdt = -1;
  128. return wdt_control(0);
  129. }
  130. int wdt_kick(void)
  131. {
  132. wdt_reg_write(kick_lock, KICK_LOCK_1);
  133. if ((wdt_reg_read(kick_lock) & 0x3) != 0x1)
  134. return -1;
  135. wdt_reg_write(kick_lock, KICK_LOCK_2);
  136. if ((wdt_reg_read(kick_lock) & 0x3) != 0x3)
  137. return -1;
  138. wdt_reg_write(kick, 1);
  139. return 0;
  140. }
  141. void reset_cpu(ulong addr)
  142. {
  143. clk_enable(TNETV107X_LPSC_WDT_ARM);
  144. wdt_start(1);
  145. wdt_kick();
  146. }