drv_wdt.c 6.1 KB

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