Files
Bernard Xiong 743b614875
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
doc_doxygen / doxygen_doc generate (push) Has been cancelled
doc_doxygen / deploy (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
ToolsCI / Tools (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
[components][clock_time] Refactor time subsystem around clock_time (#11111)
* [components][clock_time] Refactor time subsystem around clock_time

Introduce the clock_time core with clock source/event separation, high-resolution scheduling, and boot-time helpers, plus clock_timer adapters for timer peripherals.

Remove legacy ktime/cputime/hwtimer implementations and migrate arch and BSP time paths to the new subsystem while keeping POSIX time integration functional.

Update drivers, Kconfig/SConscript wiring, documentation, and tests; add clock_time overview docs and align naming to clock_boottime/clock_hrtimer/clock_timer.

* [components][clock_time] Use BSP-provided clock timer frequency on riscv64

* [risc-v] Use runtime clock timer frequency for tick and delays

* [bsp] Add clock timer frequency hooks for riscv64 boards

* [bsp] Update Renesas RA driver doc clock_timer link

* [bsp] Sync zynqmp-r5-axu4ev rtconfig after config refresh

* [bsp][rk3500] Update rk3500 clock configuration

* [bsp][hpmicro] Add rt_hw_us_delay hook and update board delays

* [bsp][stm32l496-st-nucleo] enable clock_time for hwtimer sample in ci

* [bsp][hpmicro] Fix rtconfig include scope for hpm6750evk

Move rtconfig.h include outside the ENET_MULTIPLE_PORT guard for hpm6750evk and hpm6750evk2 so configuration macros are available regardless of ENET settings.

* [bsp][raspi3] select clock time for systimer

* [bsp][hpm5300evk] Trim trailing blank line

* [bsp][hpm5301evklite] Trim trailing blank line

* [bsp][hpm5e00evk] Trim trailing blank line

* [bsp][hpm6200evk] Trim trailing blank line

* [bsp][hpm6300evk] Trim trailing blank line

* [bsp][hpm6750evk] Trim trailing blank line

* [bsp][hpm6750evk2] Trim trailing blank line

* [bsp][hpm6750evkmini] Trim trailing blank line

* [bsp][hpm6800evk] Trim trailing blank line

* [bsp][hpm6e00evk] Trim trailing blank line

* [bsp][nxp] switch lpc178x to gcc and remove mcx timer source

* [bsp][stm32] fix the CONFIG_RT_USING_CLOCK_TIME issue.

* [docs][clock_time] add clock time documentation

* [docs][clock_time] Update clock time subsystem documentation

- Update device driver index to use correct page reference
- Clarify upper layer responsibilities in architecture overview
- Update README to describe POSIX/libc, Soft RTC, and device driver usage
- Refine architecture diagram with improved layout and color scheme
- Remove obsolete clock_timer.md file

* [kernel][utest] Trim trailing space

* [clock_time] Fix hrtimer wrap handling

* [clock_time] fix the static rt_inline issue

* [clock_time] fix the rt_clock_hrtimer_control result issue
2026-01-31 17:44:27 +08:00

444 lines
14 KiB
C

/*
* 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 <rtthread.h>
#include <rtdevice.h>
#include "drv_timer.h"
#define DBG_LEVEL DBG_LOG
#include <rtdbg.h>
#define LOG_TAG "DRV.TIMER"
#include "pinctrl.h"
#include "mmio.h"
#include "drv_ioremap.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_clock_timer_t timer;
}_timer_t;
static void _timer_init(rt_clock_timer_t *timer, rt_uint32_t state);
static rt_err_t _timer_start(rt_clock_timer_t *timer, rt_uint32_t cnt, rt_clock_timer_mode_t mode);
static void _timer_stop(rt_clock_timer_t *timer);
static rt_uint32_t _timer_count_get(rt_clock_timer_t *timer);
static rt_err_t _timer_control(rt_clock_timer_t *timer, rt_uint32_t cmd, void *args);
static const struct rt_clock_timer_ops _timer_ops = {
.init = _timer_init,
.start = _timer_start,
.stop = _timer_stop,
.count_get = _timer_count_get,
.control = _timer_control
};
static const struct rt_clock_timer_info _timer_info = {
.maxfreq = 25000000UL,
.minfreq = 25000000UL,
.maxcnt = 0xFFFFFFFF,
.cntmode = CLOCK_TIMER_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)
{
if ((timer_base->TCR) & DW_TIMER_CTL_ENABLE_SEL_EN)
return 1;
return 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)
{
if ((timer_base->TCR) & DW_TIMER_CTL_MODE_SEL_EN)
return 1;
return 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)
{
if ((timer_base->TCR) & DW_TIMER_CTL_INT_MAKS_EN)
return 1;
return 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)
{
if ((timer_base->TCR) & DW_TIMER_CTL_HARD_TRIG_EN)
return 1;
return 0;
}
uint32_t hal_timer_clear_irq(dw_timer_regs_t *timer_base)
{
if ((timer_base->TEOI) & DW_TIMER_EOI_REG_EN)
return 1;
return 0;
}
uint32_t hal_timer_get_int_status(dw_timer_regs_t *timer_base)
{
if ((timer_base->TIS) & DW_TIMER_INT_STATUS_EN)
return 1;
return 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_clock_timer_isr(&_tmr->timer);
if(_tmr->timer.mode == CLOCK_TIMER_MODE_PERIOD)
{
hal_timer_set_enable(timer_base);
hal_timer_set_unmask(timer_base);
}
}
}
static void _timer_init(rt_clock_timer_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_clock_timer_t *timer, rt_uint32_t cnt, rt_clock_timer_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_clock_timer_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_clock_timer_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_clock_timer_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 CLOCK_TIMER_CTRL_FREQ_SET:
err = -RT_ERROR;
break;
case CLOCK_TIMER_CTRL_INFO_GET:
*(rt_clock_timer_t*)args = _tmr->timer;
break;
case CLOCK_TIMER_CTRL_MODE_SET:
_tmr->timer.mode = *(rt_uint32_t*)args;
break;
case CLOCK_TIMER_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++)
{
_timer_obj[i].base = (dw_timer_regs_t *)DRV_IOREMAP((void*)_timer_obj[i].base, 0x10000);
_timer_obj[i].timer.info = &_timer_info;
_timer_obj[i].timer.ops = &_timer_ops;
ret = rt_clock_timer_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);