Explorar el Código

[bsp][cvitek] add wdt driver

Z8MAN8 hace 1 año
padre
commit
5e892607fa

+ 19 - 0
bsp/cvitek/c906_little/board/Kconfig

@@ -45,6 +45,25 @@ menu "General Drivers Configuration"
         select RT_USING_ADC
         default n
 
+    menuconfig BSP_USING_WDT
+        bool "Enable Watchdog Timer"
+        select RT_USING_WDT
+        default n
+
+        if BSP_USING_WDT
+            config BSP_USING_WDT0
+                bool "Enable WDT0"
+                default n
+
+            config BSP_USING_WDT1
+                bool "Enable WDT1"
+                default n
+
+            config BSP_USING_WDT2
+                bool "Enable WDT2"
+                default n
+        endif
+
     menuconfig BSP_USING_PWM
         bool "Using PWM"
         select RT_USING_PWM

+ 3 - 0
bsp/cvitek/drivers/SConscript

@@ -18,6 +18,9 @@ if GetDepend('BSP_USING_I2C'):
 if GetDepend('BSP_USING_ADC'):
     src += ['drv_adc.c']
 
+if GetDepend('BSP_USING_WDT'):
+    src += ['drv_wdt.c']
+
 if GetDepend('BSP_USING_PWM'):
     src += ['drv_pwm.c']
     CPPPATH += [cwd + r'/cv1800b/pwm']

+ 165 - 0
bsp/cvitek/drivers/drv_wdt.c

@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author         Notes
+ * 2024/03/02     ShichengChu    first version
+ */
+#include <rtthread.h>
+#include <rtdevice.h>
+#include "drv_wdt.h"
+
+#ifdef BSP_USING_WDT
+
+#define DBG_LEVEL   DBG_LOG
+#include <rtdbg.h>
+#define LOG_TAG "DRV.WDT"
+
+#define WDT_FREQ_DEFAULT 25000000UL
+#define CVI_WDT_MAX_TOP     15
+
+struct _cvi_wdt_dev
+{
+    struct rt_watchdog_device device;
+    const char *name;
+    rt_uint32_t base;
+};
+
+static struct _cvi_wdt_dev _wdt_dev[] =
+{
+#ifdef BSP_USING_WDT0
+    {
+        .name = "wdt0",
+        .base = CVI_WDT0_BASE
+    },
+#endif /* BSP_USING_WDT0 */
+#ifdef BSP_USING_WDT1
+    {
+        .name = "wdt1",
+        .base = CVI_WDT1_BASE
+    },
+#endif /* BSP_USING_WDT1 */
+#ifdef BSP_USING_WDT2
+    {
+        .name = "wdt2",
+        .base = CVI_WDT2_BASE
+    },
+#endif /* BSP_USING_WDT2 */
+};
+struct rt_watchdog_device wdt_device;
+
+static rt_err_t _wdt_init(rt_watchdog_t *wdt_device)
+{
+    cvi_wdt_top_setting();
+
+    return RT_EOK;
+}
+
+rt_inline int wdt_top_in_ms(unsigned int top)
+{
+    /*
+     * There are 16 possible timeout values in 0..15 where the number of
+     * cycles is 2 ^ (16 + i) and the watchdog counts down.
+     */
+    // pr_debug("wdt top in seconds: %d/%d=%d\n", (1U << (16 + top)), chip->clk_hz, (1U << (16 + top)) / chip->clk_hz);
+    return (1U << (16 + top)) / (WDT_FREQ_DEFAULT / 1000);
+}
+
+static rt_err_t csi_wdt_set_timeout(unsigned long reg_base, uint32_t ms)
+{
+    rt_err_t ret = RT_EOK;
+    int i, top_val = CVI_WDT_MAX_TOP;
+
+    /*
+     * Iterate over the timeout values until we find the closest match. We
+     * always look for >=.
+     */
+    for (i = 0; i <= CVI_WDT_MAX_TOP; ++i)
+        if (wdt_top_in_ms(i) >= ms) {
+            top_val = i;
+            break;
+        }
+
+    if (i < CVI_WDT_MAX_TOP)
+    {
+        /*
+        * Set the new value in the watchdog.  Some versions of wdt_chip
+        * have TOPINIT in the TIMEOUT_RANGE register (as per
+        * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1).  On those we
+        * effectively get a pat of the watchdog right here.
+        */
+        cvi_wdt_set_timeout(reg_base, top_val);
+        cvi_wdt_start_en(reg_base);
+    }
+    else
+    {
+        ret = -RT_ERROR;
+    }
+
+    return ret;
+}
+
+
+static rt_err_t _wdt_control(rt_watchdog_t *wdt_device, int cmd, void *arg)
+{
+    RT_ASSERT(wdt_device != RT_NULL);
+
+    struct _cvi_wdt_dev *wdt = rt_container_of(wdt_device, struct _cvi_wdt_dev, device);
+    rt_uint32_t reg_base = wdt->base;
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_WDT_KEEPALIVE:
+        cvi_wdt_feed_en(reg_base);
+        break;
+    case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
+        csi_wdt_set_timeout(reg_base, *(rt_uint32_t *)arg);
+        wdt_device->parent.user_data = (rt_uint32_t)(*(rt_uint32_t *)arg);
+        break;
+    case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
+        *(rt_uint32_t *)arg = (rt_uint32_t)wdt_device->parent.user_data;
+        break;
+    case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
+        *(rt_uint32_t *)arg = (cvi_wdt_get_counter_value(reg_base) / (WDT_FREQ_DEFAULT / 1000U));
+        break;
+    case RT_DEVICE_CTRL_WDT_START:
+        cvi_wdt_set_respond_system_reset(reg_base);
+        cvi_wdt_start_en(reg_base);
+        break;
+    case RT_DEVICE_CTRL_WDT_STOP:
+        cvi_wdt_start_dis(reg_base);
+        break;
+    default:
+        LOG_W("This command is not supported.");
+        return -RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+static const struct rt_watchdog_ops _wdt_ops =
+{
+    .init = _wdt_init,
+    .control = _wdt_control
+};
+
+int rt_hw_wdt_init(void)
+{
+    rt_uint8_t i;
+    for (i = 0; i < sizeof(_wdt_dev) / sizeof(_wdt_dev[0]); i ++)
+    {
+        _wdt_dev[i].device.ops = &_wdt_ops;
+        if (rt_hw_watchdog_register(&_wdt_dev[i].device, _wdt_dev[i].name, RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
+        {
+            LOG_E("%s register failed!", _wdt_dev[i].name);
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+INIT_BOARD_EXPORT(rt_hw_wdt_init);
+
+#endif /* BSP_USING_WDT */

+ 164 - 0
bsp/cvitek/drivers/drv_wdt.h

@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author         Notes
+ * 2024/03/02     ShichengChu    first version
+ */
+#ifndef __DRV_ADC_H__
+#define __DRV_ADC_H__
+
+#include "pinctrl.h"
+#include "mmio.h"
+
+struct cvi_wdt_regs_t {
+    uint32_t CR;
+    uint32_t TORR;
+    uint32_t CCVR;
+    uint32_t CRR;
+    uint32_t STAT;
+    uint32_t EOI;
+};
+
+static struct cvi_wdt_regs_t cv182x_wdt_reg = {
+    .CR = 0x0,
+    .TORR = 0x4,
+    .CCVR = 0x8,
+    .CRR = 0xc,
+    .STAT = 0x10,
+    .EOI = 0x14,
+};
+
+static struct cvi_wdt_regs_t *cvi_wdt_reg = &cv182x_wdt_reg;
+
+#define CVI_WDT0_BASE                0x03010000
+#define CVI_WDT1_BASE                0x03011000
+#define CVI_WDT2_BASE                0x03012000
+
+#define WDT_CR(reg_base)        *((volatile uint32_t *)(reg_base + cvi_wdt_reg->CR))
+#define WDT_TORR(reg_base)      *((volatile uint32_t *)(reg_base + cvi_wdt_reg->TORR))
+#define WDT_CCVR(reg_base)      *((volatile const uint32_t *)(reg_base + cvi_wdt_reg->CCVR))
+#define WDT_CRR(reg_base)       *((volatile uint32_t *)(reg_base + cvi_wdt_reg->CRR))
+#define WDT_STAT(reg_base)      *((volatile const uint32_t *)(reg_base + cvi_wdt_reg->STAT))
+#define WDT_EOI(reg_base)       *((volatile const uint32_t *)(reg_base + cvi_wdt_reg->EOI))
+
+#define CVI_WDT_TORR_WDT_TORR_Pos                   (0U)
+#define CVI_WDT_TORR_WDT_TORR_Msk                   (0xf << CVI_WDT_TORR_WDT_TORR_Pos)
+#define CVI_WDT_TORR_WDT_ITORR_Pos                  (4U)
+#define CVI_WDT_TORR_WDT_ITORR_Msk                  (0xf << CVI_WDT_TORR_WDT_ITORR_Pos)
+
+#define CVI_WDT_CR_WDT_ENABLE_Pos                   (0U)
+#define CVI_WDT_CR_WDT_ENABLE_Msk                   (1U << CVI_WDT_CR_WDT_ENABLE_Pos)
+#define CVI_WDT_CR_WDT_ENABLE_En                    CVI_WDT_CR_WDT_ENABLE_Msk
+
+#define CVI_WDT_CR_WDT_RESPOND_Pos                   (1U)
+#define CVI_WDT_CR_WDT_RESPOND_Msk                   (1U << CVI_WDT_CR_WDT_RESPOND_Pos)
+#define CVI_WDT_CR_WDT_RESPOND_IRQ_THEN_RST          CVI_WDT_CR_WDT_RESPOND_Msk
+
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos           (2U)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Msk           (7U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_2_PCLK        (0U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_4_PCLK        (1U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_8_PCLK        (2U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_16_PCLK       (3U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_32_PCLK       (4U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_64_PCLK       (5U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_128_PCLK      (6U << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos)
+#define CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_256_PCLK      CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Msk
+
+#define CVI_WDT_CRR_FEED_Value                       0x76
+#define CVI_WDT_CRR_FEED_Pos                         (0U)
+#define CVI_WDT_CRR_FEED_Msk                         (0xff << CVI_WDT_CRR_FEED_Pos)
+#define CVI_WDT_CRR_FEED_En                          CVI_WDT_CRR_FEED_Value
+
+#define CVI_WDT_CCVR_COUNTER_Pos                     (0U)
+#define CVI_WDT_CCVR_COUNTER_Msk                     (0xffffffff << CVI_WDT_CCVR_COUNTER_Pos)
+
+#define CVI_WDT_STAT_IRQ_STAT_Pos                    (0U)
+#define CVI_WDT_STAT_IRQ_STAT_Msk                    (1U << CVI_WDT_STAT_IRQ_STAT_Pos)
+
+#define CVI_WDT_STAT_IRQ_CLR_Pos                     (0U)
+#define CVI_WDT_STAT_IRQ_CLR_Msk                     (1U << CVI_WDT_STAT_IRQ_STAT_Pos)
+#define CVI_WDT_STAT_IRQ_CLR_En                      CVI_WDT_STAT_IRQ_CLR_Msk
+
+#define CV_TOP      0x03000000
+#define CV_TOP_WDT_OFFSET   0x8
+#define CV_TOP_WDT_VAL  0x100
+#define CV_RST_REG      (CV_TOP + 0x3004)
+#define CV_RST_WDT      (1U << 16)
+
+rt_inline void cvi_wdt_top_setting()
+{
+    uint32_t val;
+
+    mmio_write_32(CV_TOP + CV_TOP_WDT_OFFSET, CV_TOP_WDT_VAL);
+
+    val = mmio_read_32(CV_RST_REG);
+    mmio_write_32(CV_RST_REG, val & ~CV_RST_WDT);
+    rt_hw_us_delay(10);
+    mmio_write_32(CV_RST_REG, val | CV_RST_WDT);
+}
+
+rt_inline void cvi_wdt_start_en(unsigned long reg_base)
+{
+    WDT_CR(reg_base) |= CVI_WDT_CR_WDT_ENABLE_En;
+}
+
+rt_inline void cvi_wdt_start_dis(unsigned long reg_base)
+{
+    WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_ENABLE_En;
+}
+
+rt_inline uint32_t cvi_wdt_get_start(unsigned long reg_base)
+{
+    return (WDT_CR(reg_base) & CVI_WDT_CR_WDT_ENABLE_Msk);
+}
+
+rt_inline void cvi_wdt_set_timeout(unsigned long reg_base, uint32_t value)
+{
+    WDT_TORR(reg_base) &= ~CVI_WDT_TORR_WDT_TORR_Pos;
+    WDT_TORR(reg_base) = ((value << CVI_WDT_TORR_WDT_ITORR_Pos) | (value << CVI_WDT_TORR_WDT_TORR_Pos));
+}
+
+rt_inline void cvi_wdt_set_respond_system_reset(unsigned long reg_base)
+{
+    WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_RESPOND_IRQ_THEN_RST;
+}
+
+rt_inline void cvi_wdt_set_respond_irq_then_reset(unsigned long reg_base)
+{
+    WDT_CR(reg_base) |= CVI_WDT_CR_WDT_RESPOND_IRQ_THEN_RST;
+}
+
+rt_inline void cvi_wdt_set_reset_pulse_width(unsigned long reg_base, uint32_t value)
+{
+    WDT_CR(reg_base) &= ~CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Msk;
+    WDT_CR(reg_base) |= (value << CVI_WDT_CR_WDT_RESET_PULSE_WIDTH_Pos);
+}
+
+rt_inline void cvi_wdt_feed_en(unsigned long reg_base)
+{
+    WDT_CRR(reg_base) = CVI_WDT_CRR_FEED_En;
+}
+
+rt_inline uint32_t cvi_wdt_get_counter_value(unsigned long reg_base)
+{
+    return (WDT_CCVR(reg_base) & CVI_WDT_CCVR_COUNTER_Msk);
+}
+
+rt_inline uint32_t cvi_wdt_get_irq_stat(unsigned long reg_base)
+{
+    return (WDT_STAT(reg_base) & CVI_WDT_STAT_IRQ_STAT_Msk);
+}
+
+rt_inline void cvi_wdt_clr_irq_en(unsigned long reg_base)
+{
+    WDT_EOI(reg_base);
+}
+
+
+int rt_hw_wdt_init(void);
+
+#endif /* __DRV_ADC_H__ */