[bsp][cvitek] add wdt driver
This commit is contained in:
parent
c95ffcc494
commit
5e892607fa
|
@ -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
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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 */
|
|
@ -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__ */
|
Loading…
Reference in New Issue