drv_wdt.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024/03/02 ShichengChu first version
  9. */
  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include "drv_wdt.h"
  13. #define DBG_LEVEL DBG_LOG
  14. #include <rtdbg.h>
  15. #define LOG_TAG "DRV.WDT"
  16. #define WDT_FREQ_DEFAULT 25000000UL
  17. #define CVI_WDT_MAX_TOP 15
  18. rt_inline void cvi_wdt_top_setting()
  19. {
  20. uint32_t val;
  21. mmio_write_32(CV_TOP + CV_TOP_WDT_OFFSET, CV_TOP_WDT_VAL);
  22. val = mmio_read_32(CV_RST_REG);
  23. mmio_write_32(CV_RST_REG, val & ~CV_RST_WDT);
  24. rt_hw_us_delay(10);
  25. mmio_write_32(CV_RST_REG, val | CV_RST_WDT);
  26. }
  27. rt_inline void cvi_wdt_start_en(unsigned long reg_base)
  28. {
  29. WDT_CR(reg_base) |= CVI_WDT_CR_WDT_ENABLE_En;
  30. }
  31. rt_inline void cvi_wdt_start_dis(unsigned long reg_base)
  32. {
  33. WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_ENABLE_En;
  34. }
  35. rt_inline uint32_t cvi_wdt_get_start(unsigned long reg_base)
  36. {
  37. return (WDT_CR(reg_base) & CVI_WDT_CR_WDT_ENABLE_Msk);
  38. }
  39. rt_inline void cvi_wdt_set_timeout(unsigned long reg_base, uint32_t value)
  40. {
  41. WDT_TORR(reg_base) &= ~CVI_WDT_TORR_WDT_TORR_Pos;
  42. WDT_TORR(reg_base) = ((value << CVI_WDT_TORR_WDT_ITORR_Pos) | (value << CVI_WDT_TORR_WDT_TORR_Pos));
  43. }
  44. rt_inline void cvi_wdt_set_respond_system_reset(unsigned long reg_base)
  45. {
  46. WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_RESPOND_IRQ_THEN_RST;
  47. }
  48. rt_inline void cvi_wdt_set_respond_irq_then_reset(unsigned long reg_base)
  49. {
  50. WDT_CR(reg_base) |= CVI_WDT_CR_WDT_RESPOND_IRQ_THEN_RST;
  51. }
  52. rt_inline void cvi_wdt_set_reset_pulse_width(unsigned long reg_base, uint32_t value)
  53. {
  54. WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Msk;
  55. WDT_CR(reg_base) |= (value << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos);
  56. }
  57. rt_inline void cvi_wdt_feed_en(unsigned long reg_base)
  58. {
  59. WDT_CRR(reg_base) = CVI_WDT_CRR_FEED_En;
  60. }
  61. rt_inline uint32_t cvi_wdt_get_counter_value(unsigned long reg_base)
  62. {
  63. return (WDT_CCVR(reg_base) & CVI_WDT_CCVR_COUNTER_Msk);
  64. }
  65. rt_inline uint32_t cvi_wdt_get_irq_stat(unsigned long reg_base)
  66. {
  67. return (WDT_STAT(reg_base) & CVI_WDT_STAT_IRQ_STAT_Msk);
  68. }
  69. rt_inline void cvi_wdt_clr_irq_en(unsigned long reg_base)
  70. {
  71. WDT_EOI(reg_base);
  72. }
  73. struct _cvi_wdt_dev
  74. {
  75. struct rt_watchdog_device device;
  76. const char *name;
  77. rt_uint32_t base;
  78. rt_uint32_t timeout;
  79. };
  80. static struct _cvi_wdt_dev _wdt_dev[] =
  81. {
  82. #ifdef BSP_USING_WDT0
  83. {
  84. .name = "wdt0",
  85. .base = CVI_WDT0_BASE
  86. },
  87. #endif /* BSP_USING_WDT0 */
  88. #ifdef BSP_USING_WDT1
  89. {
  90. .name = "wdt1",
  91. .base = CVI_WDT1_BASE
  92. },
  93. #endif /* BSP_USING_WDT1 */
  94. #ifdef BSP_USING_WDT2
  95. {
  96. .name = "wdt2",
  97. .base = CVI_WDT2_BASE
  98. },
  99. #endif /* BSP_USING_WDT2 */
  100. };
  101. struct rt_watchdog_device wdt_device;
  102. static rt_err_t _wdt_init(rt_watchdog_t *wdt_device)
  103. {
  104. cvi_wdt_top_setting();
  105. return RT_EOK;
  106. }
  107. rt_inline int wdt_top_in_ms(unsigned int top)
  108. {
  109. /*
  110. * There are 16 possible timeout values in 0..15 where the number of
  111. * cycles is 2 ^ (16 + i) and the watchdog counts down.
  112. */
  113. // pr_debug("wdt top in seconds: %d/%d=%d\n", (1U << (16 + top)), chip->clk_hz, (1U << (16 + top)) / chip->clk_hz);
  114. return (1U << (16 + top)) / (WDT_FREQ_DEFAULT / 1000);
  115. }
  116. /**
  117. * @brief set timeout period
  118. *
  119. * @param reg_base base address of the watchdog controller
  120. * @param ms timeout period (in millisecond)
  121. *
  122. * @return RT_EOK if successed.
  123. */
  124. static rt_err_t csi_wdt_set_timeout(unsigned long reg_base, uint32_t ms)
  125. {
  126. rt_err_t ret = RT_EOK;
  127. int i, top_val = CVI_WDT_MAX_TOP;
  128. /*
  129. * Iterate over the timeout values until we find the closest match. We
  130. * always look for >=.
  131. */
  132. for (i = 0; i <= CVI_WDT_MAX_TOP; ++i)
  133. if (wdt_top_in_ms(i) >= ms) {
  134. top_val = i;
  135. break;
  136. }
  137. if (i < CVI_WDT_MAX_TOP)
  138. {
  139. /*
  140. * Set the new value in the watchdog. Some versions of wdt_chip
  141. * have TOPINIT in the TIMEOUT_RANGE register (as per
  142. * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we
  143. * effectively get a pat of the watchdog right here.
  144. */
  145. cvi_wdt_set_timeout(reg_base, top_val);
  146. cvi_wdt_start_en(reg_base);
  147. }
  148. else
  149. {
  150. ret = -RT_ERROR;
  151. }
  152. return ret;
  153. }
  154. static rt_err_t _wdt_control(rt_watchdog_t *wdt_device, int cmd, void *arg)
  155. {
  156. RT_ASSERT(wdt_device != RT_NULL);
  157. struct _cvi_wdt_dev *wdt = rt_container_of(wdt_device, struct _cvi_wdt_dev, device);
  158. rt_uint32_t reg_base = wdt->base;
  159. switch (cmd)
  160. {
  161. case RT_DEVICE_CTRL_WDT_KEEPALIVE:
  162. cvi_wdt_feed_en(reg_base);
  163. break;
  164. case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
  165. wdt->timeout = *(rt_uint32_t *)arg;
  166. csi_wdt_set_timeout(reg_base, wdt->timeout * 1000);
  167. break;
  168. case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
  169. *(rt_uint32_t *)arg = wdt->timeout;
  170. break;
  171. case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
  172. *(rt_uint32_t *)arg = (cvi_wdt_get_counter_value(reg_base) / WDT_FREQ_DEFAULT);
  173. break;
  174. case RT_DEVICE_CTRL_WDT_START:
  175. cvi_wdt_set_respond_system_reset(reg_base);
  176. cvi_wdt_start_en(reg_base);
  177. break;
  178. case RT_DEVICE_CTRL_WDT_STOP:
  179. cvi_wdt_start_dis(reg_base);
  180. break;
  181. default:
  182. LOG_W("This command is not supported.");
  183. return -RT_EINVAL;
  184. }
  185. return RT_EOK;
  186. }
  187. static const struct rt_watchdog_ops _wdt_ops =
  188. {
  189. .init = _wdt_init,
  190. .control = _wdt_control
  191. };
  192. int rt_hw_wdt_init(void)
  193. {
  194. rt_uint8_t i;
  195. for (i = 0; i < sizeof(_wdt_dev) / sizeof(_wdt_dev[0]); i ++)
  196. {
  197. _wdt_dev[i].device.ops = &_wdt_ops;
  198. if (rt_hw_watchdog_register(&_wdt_dev[i].device, _wdt_dev[i].name, RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
  199. {
  200. LOG_E("%s register failed!", _wdt_dev[i].name);
  201. return -RT_ERROR;
  202. }
  203. }
  204. return RT_EOK;
  205. }
  206. INIT_DEVICE_EXPORT(rt_hw_wdt_init);