drv_wdt.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. #ifdef BSP_USING_WDT
  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. struct _cvi_wdt_dev
  20. {
  21. struct rt_watchdog_device device;
  22. const char *name;
  23. rt_uint32_t base;
  24. };
  25. static struct _cvi_wdt_dev _wdt_dev[] =
  26. {
  27. #ifdef BSP_USING_WDT0
  28. {
  29. .name = "wdt0",
  30. .base = CVI_WDT0_BASE
  31. },
  32. #endif /* BSP_USING_WDT0 */
  33. #ifdef BSP_USING_WDT1
  34. {
  35. .name = "wdt1",
  36. .base = CVI_WDT1_BASE
  37. },
  38. #endif /* BSP_USING_WDT1 */
  39. #ifdef BSP_USING_WDT2
  40. {
  41. .name = "wdt2",
  42. .base = CVI_WDT2_BASE
  43. },
  44. #endif /* BSP_USING_WDT2 */
  45. };
  46. struct rt_watchdog_device wdt_device;
  47. static rt_err_t _wdt_init(rt_watchdog_t *wdt_device)
  48. {
  49. cvi_wdt_top_setting();
  50. return RT_EOK;
  51. }
  52. rt_inline int wdt_top_in_ms(unsigned int top)
  53. {
  54. /*
  55. * There are 16 possible timeout values in 0..15 where the number of
  56. * cycles is 2 ^ (16 + i) and the watchdog counts down.
  57. */
  58. // pr_debug("wdt top in seconds: %d/%d=%d\n", (1U << (16 + top)), chip->clk_hz, (1U << (16 + top)) / chip->clk_hz);
  59. return (1U << (16 + top)) / (WDT_FREQ_DEFAULT / 1000);
  60. }
  61. static rt_err_t csi_wdt_set_timeout(unsigned long reg_base, uint32_t ms)
  62. {
  63. rt_err_t ret = RT_EOK;
  64. int i, top_val = CVI_WDT_MAX_TOP;
  65. /*
  66. * Iterate over the timeout values until we find the closest match. We
  67. * always look for >=.
  68. */
  69. for (i = 0; i <= CVI_WDT_MAX_TOP; ++i)
  70. if (wdt_top_in_ms(i) >= ms) {
  71. top_val = i;
  72. break;
  73. }
  74. if (i < CVI_WDT_MAX_TOP)
  75. {
  76. /*
  77. * Set the new value in the watchdog. Some versions of wdt_chip
  78. * have TOPINIT in the TIMEOUT_RANGE register (as per
  79. * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we
  80. * effectively get a pat of the watchdog right here.
  81. */
  82. cvi_wdt_set_timeout(reg_base, top_val);
  83. cvi_wdt_start_en(reg_base);
  84. }
  85. else
  86. {
  87. ret = -RT_ERROR;
  88. }
  89. return ret;
  90. }
  91. static rt_err_t _wdt_control(rt_watchdog_t *wdt_device, int cmd, void *arg)
  92. {
  93. RT_ASSERT(wdt_device != RT_NULL);
  94. struct _cvi_wdt_dev *wdt = rt_container_of(wdt_device, struct _cvi_wdt_dev, device);
  95. rt_uint32_t reg_base = wdt->base;
  96. switch (cmd)
  97. {
  98. case RT_DEVICE_CTRL_WDT_KEEPALIVE:
  99. cvi_wdt_feed_en(reg_base);
  100. break;
  101. case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
  102. csi_wdt_set_timeout(reg_base, *(rt_uint32_t *)arg);
  103. wdt_device->parent.user_data = (rt_uint32_t)(*(rt_uint32_t *)arg);
  104. break;
  105. case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
  106. *(rt_uint32_t *)arg = (rt_uint32_t)wdt_device->parent.user_data;
  107. break;
  108. case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
  109. *(rt_uint32_t *)arg = (cvi_wdt_get_counter_value(reg_base) / (WDT_FREQ_DEFAULT / 1000U));
  110. break;
  111. case RT_DEVICE_CTRL_WDT_START:
  112. cvi_wdt_set_respond_system_reset(reg_base);
  113. cvi_wdt_start_en(reg_base);
  114. break;
  115. case RT_DEVICE_CTRL_WDT_STOP:
  116. cvi_wdt_start_dis(reg_base);
  117. break;
  118. default:
  119. LOG_W("This command is not supported.");
  120. return -RT_EINVAL;
  121. }
  122. return RT_EOK;
  123. }
  124. static const struct rt_watchdog_ops _wdt_ops =
  125. {
  126. .init = _wdt_init,
  127. .control = _wdt_control
  128. };
  129. int rt_hw_wdt_init(void)
  130. {
  131. rt_uint8_t i;
  132. for (i = 0; i < sizeof(_wdt_dev) / sizeof(_wdt_dev[0]); i ++)
  133. {
  134. _wdt_dev[i].device.ops = &_wdt_ops;
  135. if (rt_hw_watchdog_register(&_wdt_dev[i].device, _wdt_dev[i].name, RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
  136. {
  137. LOG_E("%s register failed!", _wdt_dev[i].name);
  138. return -RT_ERROR;
  139. }
  140. }
  141. return RT_EOK;
  142. }
  143. INIT_BOARD_EXPORT(rt_hw_wdt_init);
  144. #endif /* BSP_USING_WDT */