From 5e892607faa4b74b4f7aeab04ca53aff6b9b6c21 Mon Sep 17 00:00:00 2001 From: Z8MAN8 <1468559561@qq.com> Date: Mon, 4 Mar 2024 00:37:38 +0800 Subject: [PATCH] [bsp][cvitek] add wdt driver --- bsp/cvitek/c906_little/board/Kconfig | 19 +++ bsp/cvitek/drivers/SConscript | 3 + bsp/cvitek/drivers/drv_wdt.c | 165 +++++++++++++++++++++++++++ bsp/cvitek/drivers/drv_wdt.h | 164 ++++++++++++++++++++++++++ 4 files changed, 351 insertions(+) create mode 100644 bsp/cvitek/drivers/drv_wdt.c create mode 100644 bsp/cvitek/drivers/drv_wdt.h diff --git a/bsp/cvitek/c906_little/board/Kconfig b/bsp/cvitek/c906_little/board/Kconfig index 689cc4285db..03f664e89c5 100755 --- a/bsp/cvitek/c906_little/board/Kconfig +++ b/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 diff --git a/bsp/cvitek/drivers/SConscript b/bsp/cvitek/drivers/SConscript index 9f342e1385c..a32eb05378b 100755 --- a/bsp/cvitek/drivers/SConscript +++ b/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'] diff --git a/bsp/cvitek/drivers/drv_wdt.c b/bsp/cvitek/drivers/drv_wdt.c new file mode 100644 index 00000000000..09481623c52 --- /dev/null +++ b/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 +#include +#include "drv_wdt.h" + +#ifdef BSP_USING_WDT + +#define DBG_LEVEL DBG_LOG +#include +#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 */ diff --git a/bsp/cvitek/drivers/drv_wdt.h b/bsp/cvitek/drivers/drv_wdt.h new file mode 100644 index 00000000000..f779d6129b6 --- /dev/null +++ b/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__ */