diff --git a/bsp/cvitek/c906_little/board/Kconfig b/bsp/cvitek/c906_little/board/Kconfig index 4944cdcc56..49c046748b 100755 --- a/bsp/cvitek/c906_little/board/Kconfig +++ b/bsp/cvitek/c906_little/board/Kconfig @@ -295,6 +295,32 @@ menu "General Drivers Configuration" default n endif + menuconfig BSP_USING_TIMER + bool "Enable TIMER" + default n + select RT_USING_HWTIMER + if BSP_USING_TIMER + config BSP_USING_TIMER4 + bool "Enable TIMER4" + default n + + config BSP_USING_TIMER5 + bool "Enable TIMER5" + default n + + config BSP_USING_TIMER6 + bool "Enable TIMER6" + default n + + config BSP_USING_TIMER7 + bool "Enable TIMER7" + default n + + config BSP_TIMER_IRQ_BASE + int + default 55 + endif + menuconfig BSP_USING_PWM bool "Using PWM" select RT_USING_PWM diff --git a/bsp/cvitek/cv18xx_risc-v/board/Kconfig b/bsp/cvitek/cv18xx_risc-v/board/Kconfig index 55dfb1078b..f971b18e2c 100755 --- a/bsp/cvitek/cv18xx_risc-v/board/Kconfig +++ b/bsp/cvitek/cv18xx_risc-v/board/Kconfig @@ -295,6 +295,48 @@ menu "General Drivers Configuration" default n endif + menuconfig BSP_USING_TIMER + bool "Enable TIMER" + default n + select RT_USING_HWTIMER + if BSP_USING_TIMER + config BSP_USING_TIMER0 + bool "Enable TIMER0" + default n + + config BSP_USING_TIMER1 + bool "Enable TIMER1" + default n + + config BSP_USING_TIMER2 + bool "Enable TIMER2" + default n + + config BSP_USING_TIMER3 + bool "Enable TIMER3" + default n + + config BSP_USING_TIMER4 + bool "Enable TIMER4" + default n + + config BSP_USING_TIMER5 + bool "Enable TIMER5" + default n + + config BSP_USING_TIMER6 + bool "Enable TIMER6" + default n + + config BSP_USING_TIMER7 + bool "Enable TIMER7" + default n + + config BSP_TIMER_IRQ_BASE + int + default 79 + 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 56bca8b136..61d65b7697 100755 --- a/bsp/cvitek/drivers/SConscript +++ b/bsp/cvitek/drivers/SConscript @@ -61,6 +61,9 @@ CPPDEFINES += ['-DCONFIG_64BIT'] if GetDepend('BSP_USING_RTC'): src += ['drv_rtc.c'] +if GetDepend('BSP_USING_TIMER'): + src += ['drv_timer.c'] + group = DefineGroup('drivers', src, depend = [''], CPPDEFINES = CPPDEFINES, CPPPATH = CPPPATH) Return('group') diff --git a/bsp/cvitek/drivers/drv_timer.c b/bsp/cvitek/drivers/drv_timer.c new file mode 100644 index 0000000000..957a643618 --- /dev/null +++ b/bsp/cvitek/drivers/drv_timer.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024/08/08 ShichengChu first version + */ +#include +#include +#include "drv_timer.h" + +#define DBG_LEVEL DBG_LOG +#include +#define LOG_TAG "DRV.TIMER" + +#include "pinctrl.h" +#include "mmio.h" +#define DW_NR_TIMERS 8 + +#define TIMER_FREQ 25000000 + +#define DW_TIMER_GET_RELOAD_VAL(_tim_, _frq_) ((_tim_ < 25000U) ? ((_frq_ * _tim_) / 1000U) : (_frq_ * (_tim_ / 1000U))) + +#define DW_TIMER0_BASE 0x030A0000UL +#define DW_TIMER0_SIZE 0x14U + +#define DW_TIMER1_BASE (DW_TIMER0_BASE+DW_TIMER0_SIZE) +#define DW_TIMER1_SIZE DW_TIMER0_SIZE + +#define DW_TIMER2_BASE (DW_TIMER1_BASE+DW_TIMER1_SIZE) +#define DW_TIMER2_SIZE DW_TIMER1_SIZE + +#define DW_TIMER3_BASE (DW_TIMER2_BASE+DW_TIMER2_SIZE) +#define DW_TIMER3_SIZE DW_TIMER2_SIZE + +#define DW_TIMER4_BASE (DW_TIMER3_BASE+DW_TIMER3_SIZE) +#define DW_TIMER4_SIZE DW_TIMER3_SIZE + +#define DW_TIMER5_BASE (DW_TIMER4_BASE+DW_TIMER4_SIZE) +#define DW_TIMER5_SIZE DW_TIMER4_SIZE + +#define DW_TIMER6_BASE (DW_TIMER5_BASE+DW_TIMER5_SIZE) +#define DW_TIMER6_SIZE DW_TIMER5_SIZE + +#define DW_TIMER7_BASE (DW_TIMER6_BASE+DW_TIMER6_SIZE) +#define DW_TIMER7_SIZE DW_TIMER6_SIZE + +#if defined(BSP_USING_CV18XX) || defined(SOC_CV18XX_AARCH64) + +#define TIMER_INTR_0 BSP_TIMER_IRQ_BASE + 0 +#define TIMER_INTR_1 BSP_TIMER_IRQ_BASE + 1 +#define TIMER_INTR_2 BSP_TIMER_IRQ_BASE + 2 +#define TIMER_INTR_3 BSP_TIMER_IRQ_BASE + 3 +#define TIMER_INTR_4 BSP_TIMER_IRQ_BASE + 4 +#define TIMER_INTR_5 BSP_TIMER_IRQ_BASE + 5 +#define TIMER_INTR_6 BSP_TIMER_IRQ_BASE + 6 +#define TIMER_INTR_7 BSP_TIMER_IRQ_BASE + 7 + +#elif defined(BSP_USING_C906_LITTLE) + +#define TIMER_INTR_4 BSP_TIMER_IRQ_BASE + 0 +#define TIMER_INTR_5 BSP_TIMER_IRQ_BASE + 1 +#define TIMER_INTR_6 BSP_TIMER_IRQ_BASE + 2 +#define TIMER_INTR_7 BSP_TIMER_IRQ_BASE + 3 + +#else + +#error "Unsupported CPU type!" + +#endif + +/*! Timer1 Control Reg, offset: 0x08 */ +#define DW_TIMER_CTL_ENABLE_SEL_Pos (0U) +#define DW_TIMER_CTL_ENABLE_SEL_Msk (0x1U << DW_TIMER_CTL_ENABLE_SEL_Pos) +#define DW_TIMER_CTL_ENABLE_SEL_EN DW_TIMER_CTL_ENABLE_SEL_Msk + +#define DW_TIMER_CTL_MODE_SEL_Pos (1U) +#define DW_TIMER_CTL_MODE_SEL_Msk (0x1U << DW_TIMER_CTL_MODE_SEL_Pos) +#define DW_TIMER_CTL_MODE_SEL_EN DW_TIMER_CTL_MODE_SEL_Msk + +#define DW_TIMER_CTL_INT_MASK_Pos (2U) +#define DW_TIMER_CTL_INT_MASK_Msk (0x1U << DW_TIMER_CTL_INT_MASK_Pos) +#define DW_TIMER_CTL_INT_MAKS_EN DW_TIMER_CTL_INT_MASK_Msk + +#define DW_TIMER_CTL_HARD_TRIG_Pos (4U) +#define DW_TIMER_CTL_HARD_TRIG_Msk (0x1U << DW_TIMER_CTL_HARD_TRIG_Pos) +#define DW_TIMER_CTL_HARD_TRIG_EN DW_TIMER_CTL_HARD_TRIG_Msk + +/*! Timer EOI, offset: 0x0c */ +#define DW_TIMER_EOI_REG_Pos (0U) +#define DW_TIMER_EOI_REG_Msk (0x1U << DW_TIMER_EOI_REG_Pos) +#define DW_TIMER_EOI_REG_EN DW_TIMER_EOI_REG_Msk + +/*! Timer Int Status, offset: 0x10 */ +#define DW_TIMER_INT_STATUS_Pos (0U) +#define DW_TIMER_INT_STATUS_Msk (0x1U << DW_TIMER_INT_STATUS_Pos) +#define DW_TIMER_INT_STATUS_EN DW_TIMER_INT_STATUS_Msk + +/*! Timers Int Status, offset: 0xa0 */ +#define DW_TIMERS_INT_STATUS_Pos (0U) +#define DW_TIMERS_INT_STATUS_Msk (0x2U << DW_TIMERS_INT_STATUS_Pos) +#define DW_TIMERS_INT_STATUS_EN DW_TIMERS_INT_STATUS_Msk + +/*! Timers EOI, offset: 0xa4 */ +#define DW_TIMERS_EOI_REG_Pos (0U) +#define DW_TIMERS_EOI_REG_Msk (0x2U << DW_TIMERS_EOI_REG_Pos) +#define DW_TIMERS_EOI_REG_EN DW_TIMERS_EOI_REG_Msk + +/*! Timers Raw Int Status,offset: 0xa8 */ +#define DW_TIMERS_RAW_INT_STA_Pos (0U) +#define DW_TIMERS_RAW_INT_STA_Msk (0x2U << DW_TIMERS_RAW_INT_STA_Pos) +#define DW_TIMERS_RAW_INT_STA_EN DW_TIMERS_RAW_INT_STA_Msk + +typedef struct { + volatile uint32_t TLC; /* Offset: 0x000 (R/W) TimerLoadCount */ + volatile const uint32_t TCV; /* Offset: 0x004 (R/ ) TimerCurrentValue */ + volatile uint32_t TCR; /* Offset: 0x008 (R/W) TimerControlReg */ + volatile const uint32_t TEOI; /* Offset: 0x00c (R/ ) TimerEOI */ + volatile const uint32_t TIS; /* Offset: 0x010 (R/ ) TimerIntStatus */ +} dw_timer_regs_t; + +typedef struct { + dw_timer_regs_t timer[DW_NR_TIMERS]; + volatile const uint32_t TSIS; /* Offset: 0x0a0 (R/ ) TimersIntStatus */ + volatile const uint32_t TSEOI; /* Offset: 0x0a4 (R/ ) TimersEOI */ + volatile const uint32_t TSRIS; /* Offset: 0x0a8 (R/ ) TimersRawIntStatus */ +} dw_timer_general_regs_t; + +typedef struct _timer +{ + char *name; + dw_timer_regs_t *base; + rt_uint32_t irqno; + rt_hwtimer_t timer; +}_timer_t; + +static void _timer_init(rt_hwtimer_t *timer, rt_uint32_t state); +static rt_err_t _timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode); +static void _timer_stop(rt_hwtimer_t *timer); +static rt_uint32_t _timer_count_get(rt_hwtimer_t *timer); +static rt_err_t _timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args); + +static const struct rt_hwtimer_ops _timer_ops = { + .init = _timer_init, + .start = _timer_start, + .stop = _timer_stop, + .count_get = _timer_count_get, + .control = _timer_control +}; + +static const struct rt_hwtimer_info _timer_info = { + .maxfreq = 25000000UL, + .minfreq = 25000000UL, + .maxcnt = 0xFFFFFFFF, + .cntmode = HWTIMER_MODE_PERIOD +}; + +static _timer_t _timer_obj[] = +{ +#ifdef BSP_USING_TIMER0 + { + .name = "timer0", + .base = (dw_timer_regs_t *)DW_TIMER0_BASE, + .irqno = TIMER_INTR_0 + }, +#endif /* BSP_USING_TIMER0 */ +#ifdef BSP_USING_TIMER1 + { + .name = "timer1", + .base = (dw_timer_regs_t *)DW_TIMER1_BASE, + .irqno = TIMER_INTR_1 + }, +#endif /* BSP_USING_TIMER1 */ +#ifdef BSP_USING_TIMER2 + { + .name = "timer2", + .base = (dw_timer_regs_t *)DW_TIMER2_BASE, + .irqno = TIMER_INTR_2 + }, +#endif /* BSP_USING_TIMER2 */ +#ifdef BSP_USING_TIMER3 + { + .name = "timer3", + .base = (dw_timer_regs_t *)DW_TIMER3_BASE, + .irqno = TIMER_INTR_3 + }, +#endif /* BSP_USING_TIMER3 */ +#ifdef BSP_USING_TIMER4 + { + .name = "timer4", + .base = (dw_timer_regs_t *)DW_TIMER4_BASE, + .irqno = TIMER_INTR_4 + }, +#endif /* BSP_USING_TIMER4 */ +#ifdef BSP_USING_TIMER5 + { + .name = "timer5", + .base = (dw_timer_regs_t *)DW_TIMER5_BASE, + .irqno = TIMER_INTR_5 + }, +#endif /* BSP_USING_TIMER5 */ +#ifdef BSP_USING_TIMER6 + { + .name = "timer6", + .base = (dw_timer_regs_t *)DW_TIMER6_BASE, + .irqno = TIMER_INTR_6 + }, +#endif /* BSP_USING_TIMER6 */ +#ifdef BSP_USING_TIMER7 + { + .name = "timer7", + .base = (dw_timer_regs_t *)DW_TIMER7_BASE, + .irqno = TIMER_INTR_7 + }, +#endif /* BSP_USING_TIMER7 */ +}; + +uint32_t hal_timer_read_load(dw_timer_regs_t *timer_base) +{ + return (timer_base->TLC); +} +void hal_timer_write_load(dw_timer_regs_t *timer_base, uint32_t value) +{ + timer_base->TLC = value; +} +uint32_t hal_timer_get_current(dw_timer_regs_t *timer_base) +{ + return (timer_base->TCV); +} +void hal_timer_set_enable(dw_timer_regs_t *timer_base) +{ + timer_base->TCR |= (DW_TIMER_CTL_ENABLE_SEL_EN); +} +void hal_timer_set_disable(dw_timer_regs_t *timer_base) +{ + timer_base->TCR &= ~(DW_TIMER_CTL_ENABLE_SEL_EN); +} +uint32_t hal_timer_get_enable(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TCR) & DW_TIMER_CTL_ENABLE_SEL_EN) ? (uint32_t)1 : (uint32_t)0); +} +void hal_timer_set_mode_free(dw_timer_regs_t *timer_base) +{ + timer_base->TCR &= ~(DW_TIMER_CTL_MODE_SEL_EN); +} +void hal_timer_set_mode_load(dw_timer_regs_t *timer_base) +{ + timer_base->TCR |= (DW_TIMER_CTL_MODE_SEL_EN); +} +uint32_t hal_timer_get_model(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TCR) & DW_TIMER_CTL_MODE_SEL_EN) ? (uint32_t)1 : (uint32_t)0); +} +void hal_timer_set_mask(dw_timer_regs_t *timer_base) +{ + timer_base->TCR |= (DW_TIMER_CTL_INT_MAKS_EN); +} +void hal_timer_set_unmask(dw_timer_regs_t *timer_base) +{ + timer_base->TCR &= ~(DW_TIMER_CTL_INT_MAKS_EN); +} +uint32_t hal_timer_get_mask(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TCR) & DW_TIMER_CTL_INT_MAKS_EN) ? (uint32_t)1 : (uint32_t)0); +} +void hal_timer_set_hardtrigger_en(dw_timer_regs_t *timer_base) +{ + timer_base->TCR |= (DW_TIMER_CTL_HARD_TRIG_EN); +} +void hal_timer_set_hardtrigger_dis(dw_timer_regs_t *timer_base) +{ + timer_base->TCR &= ~(DW_TIMER_CTL_HARD_TRIG_EN); +} +uint32_t hal_timer_get_hardtrigger(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TCR) & DW_TIMER_CTL_HARD_TRIG_EN) ? (uint32_t)1 : (uint32_t)0); +} +uint32_t hal_timer_clear_irq(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TEOI) & DW_TIMER_EOI_REG_EN) ? (uint32_t)1 : (uint32_t)0); +} +uint32_t hal_timer_get_int_status(dw_timer_regs_t *timer_base) +{ + return (((timer_base->TIS) & DW_TIMER_INT_STATUS_EN) ? (uint32_t)1 : (uint32_t)0); +} +void hal_timer_reset_register(dw_timer_regs_t *timer_base) +{ + timer_base->TCR = 0U; + timer_base->TLC = 0U; +} +uint32_t hal_timer_general_active_after_mask(dw_timer_general_regs_t *timer_base) +{ + return ((timer_base->TSIS) & DW_TIMERS_INT_STATUS_EN); +} +uint32_t hal_timer_general_clear_irq(dw_timer_general_regs_t *timer_base) +{ + return ((timer_base->TSEOI) & DW_TIMERS_EOI_REG_EN); +} +uint32_t hal_timer_general_active_prior_mask(dw_timer_general_regs_t *timer_base) +{ + return ((timer_base->TSRIS) & DW_TIMERS_RAW_INT_STA_EN); +} + +static void rt_hw_hwtmr_isr(int irqno, void *param) +{ + _timer_t *_tmr = param; + dw_timer_regs_t *timer_base = _tmr->base; + + if (hal_timer_get_int_status(timer_base)) + { + hal_timer_clear_irq(timer_base); + hal_timer_set_disable(timer_base); + + rt_device_hwtimer_isr(&_tmr->timer); + if(_tmr->timer.mode == HWTIMER_MODE_PERIOD) + { + hal_timer_set_enable(timer_base); + hal_timer_set_unmask(timer_base); + } + } +} + +static void _timer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + _timer_t *_tmr = rt_container_of(timer, _timer_t, timer); + + RT_ASSERT(_tmr!=NULL) + if(state) + { + hal_timer_reset_register(_tmr->base); + } +} + +static rt_err_t _timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + _timer_t *_tmr = rt_container_of(timer, _timer_t, timer); + uint32_t tmp_load = cnt; + + hal_timer_set_mode_load(_tmr->base); + + /*FIXME: no less than 10*/ + if (tmp_load < 10) + { + tmp_load = 10; + } + + hal_timer_set_disable(_tmr->base); + hal_timer_write_load(_tmr->base, tmp_load); + + hal_timer_set_enable(_tmr->base); + hal_timer_set_unmask(_tmr->base); + + return RT_EOK; +} + +static void _timer_stop(rt_hwtimer_t *timer) +{ + _timer_t *_tmr = rt_container_of(timer, _timer_t, timer); + + hal_timer_set_mask(_tmr->base); + hal_timer_set_disable(_tmr->base); +} + +static rt_uint32_t _timer_count_get(rt_hwtimer_t *timer) +{ + _timer_t *_tmr = rt_container_of(timer, _timer_t, timer); + rt_uint32_t cnt = hal_timer_get_current(_tmr->base); + + return cnt; +} + +static rt_err_t _timer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + _timer_t *_tmr = rt_container_of(timer, _timer_t, timer); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + err = -RT_ERROR; + break; + case HWTIMER_CTRL_INFO_GET: + *(rt_hwtimer_t*)args = _tmr->timer; + break; + case HWTIMER_CTRL_MODE_SET: + _tmr->timer.mode = *(rt_uint32_t*)args; + break; + case HWTIMER_CTRL_STOP: + _timer_stop(timer); + break; + default: + err = -RT_EINVAL; + break; + } + + return err; +} + +int rt_hw_timer_init(void) +{ + int ret = RT_EOK; + + for (uint32_t i = 0; i < sizeof(_timer_obj) / sizeof(_timer_obj[0]); i++) + { +#if defined(ARCH_ARM) + _timer_obj[i].base = (dw_timer_regs_t *)rt_ioremap((void*)_timer_obj[i].base, 0x10000); +#endif /* defined(ARCH_ARM) */ + _timer_obj[i].timer.info = &_timer_info; + _timer_obj[i].timer.ops = &_timer_ops; + ret = rt_device_hwtimer_register(&_timer_obj[i].timer, _timer_obj[i].name, &_timer_obj[i]); + if (ret != RT_EOK) + { + LOG_E("%s register failed", _timer_obj[i].name); + } + rt_hw_interrupt_install(_timer_obj[i].irqno, rt_hw_hwtmr_isr, &_timer_obj[i], _timer_obj[i].name); + rt_hw_interrupt_umask(_timer_obj[i].irqno); + } + + return ret; +} + +INIT_DEVICE_EXPORT(rt_hw_timer_init); diff --git a/bsp/cvitek/drivers/drv_timer.h b/bsp/cvitek/drivers/drv_timer.h new file mode 100644 index 0000000000..fae53df1d0 --- /dev/null +++ b/bsp/cvitek/drivers/drv_timer.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024/08/08 ShichengChu first version + */ +#ifndef __DRV_TIMER_H__ +#define __DRV_TIMER_H__ + +int rt_hw_timer_init(void); + +#endif /* __DRV_TIMER_H__ */