wdt.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #include "amt630h.h"
  2. #include "uart.h"
  3. #define WTCON 0x00
  4. #define WTPSR 0x04
  5. #define WTCNT 0x08
  6. #define WTCLRINT 0x10
  7. #define WTRCR 0x14
  8. #define WTCNT_MAXCNT 0xffff
  9. #define WTCON_MAXDIV 0x80
  10. #define WTCON_ENABLE (1 << 0)
  11. #define WTCON_RSTEN (1 << 1)
  12. #define WTCON_INTEN (1 << 2)
  13. #define WTCON_DIV16 (0 << 4)
  14. #define WTCON_DIV32 (1 << 4)
  15. #define WTCON_DIV64 (2 << 4)
  16. #define WTCON_DIV128 (3 << 4)
  17. #define WTCON_DIVMASK (0x3 << 4)
  18. #define WTCON_PRESCALE_MAX 0x10000
  19. #define WATCHDOG_DEFAULT_TIME (3)
  20. #define CLK_APB_FREQ 108000000
  21. static int wdt_timeout = WATCHDOG_DEFAULT_TIME;
  22. static int soft_noboot = 0; /* 1: not reboot when watchdog timer expired */
  23. static int wdt_count;
  24. static inline unsigned int wdt_max_timeout()
  25. {
  26. unsigned long freq = CLK_APB_FREQ;
  27. return WTCNT_MAXCNT / (freq / WTCON_PRESCALE_MAX
  28. / WTCON_MAXDIV);
  29. }
  30. int wdt_set_heartbeat(unsigned int timeout)
  31. {
  32. unsigned long freq = CLK_APB_FREQ;
  33. unsigned int count;
  34. unsigned int divisor = 1;
  35. if (timeout < 1 || timeout > wdt_max_timeout())
  36. return -EINVAL;
  37. freq = DIV_ROUND_UP(freq, 128);
  38. count = timeout * freq;
  39. /* TRACE_DEBUG("Heartbeat: count=%d, timeout=%d, freq=%lu\n",
  40. count, timeout, freq); */
  41. /* if the count is bigger than the watchdog register,
  42. then work out what we need to do (and if) we can
  43. actually make this value
  44. */
  45. if (count >= 0x10000) {
  46. divisor = DIV_ROUND_UP(count, 0xffff);
  47. if (divisor > WTCON_PRESCALE_MAX) {
  48. SendUartString("timeout too big\n");
  49. return -EINVAL;
  50. }
  51. }
  52. /* TRACE_DEBUG("Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n",
  53. timeout, divisor, count, DIV_ROUND_UP(count, divisor)); */
  54. count = DIV_ROUND_UP(count, divisor);
  55. wdt_count = count;
  56. /* update the pre-scaler */
  57. writel(divisor - 1, WDT_BASE + WTPSR);
  58. writel(count, WDT_BASE + WTCNT);
  59. wdt_timeout = timeout;
  60. return 0;
  61. }
  62. void wdt_stop(void)
  63. {
  64. unsigned long wtcon;
  65. wtcon = readl(WDT_BASE + WTCON);
  66. wtcon &= ~(WTCON_ENABLE | WTCON_RSTEN);
  67. writel(wtcon, WDT_BASE + WTCON);
  68. }
  69. void wdt_start(void)
  70. {
  71. unsigned long wtcon;
  72. wdt_stop();
  73. wtcon = readl(WDT_BASE + WTCON);
  74. wtcon &= ~WTCON_DIVMASK;
  75. wtcon |= WTCON_ENABLE | WTCON_DIV128;
  76. if (soft_noboot) {
  77. wtcon |= WTCON_INTEN;
  78. wtcon &= ~WTCON_RSTEN;
  79. } else {
  80. wtcon &= ~WTCON_INTEN;
  81. wtcon |= WTCON_RSTEN;
  82. }
  83. /* TRACE_DEBUG("Starting watchdog: count=0x%08x, wtcon=%08lx\n",
  84. wdt_count, wtcon); */
  85. writel(wdt_count, WDT_BASE + WTCNT);
  86. writel(wtcon, WDT_BASE + WTCON);
  87. }
  88. int wdt_init(void)
  89. {
  90. int ret;
  91. ret = wdt_set_heartbeat(wdt_timeout);
  92. if (ret) {
  93. SendUartString("failed to set timeout value\n");
  94. }
  95. wdt_start();
  96. return 0;
  97. }
  98. void wdt_cpu_reboot(void)
  99. {
  100. SendUartString("cpu reboot...\n");
  101. soft_noboot = 0;
  102. wdt_count = 300;
  103. wdt_start();
  104. while(1);
  105. }