wdt.c 3.0 KB

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