From 80463c8b0652328e56d830ef3d579f632316b51e Mon Sep 17 00:00:00 2001 From: husong1 Date: Fri, 10 Oct 2025 15:47:11 +0800 Subject: [PATCH] arch/armv7r: Add armv7r clkdev timer driver. This commit added armv7r clkdev timer driver. Signed-off-by: husong1 --- arch/arm/src/armv7-r/Kconfig | 2 + arch/arm/src/armv7-r/arm_timer.c | 176 ++++++++----------------------- 2 files changed, 48 insertions(+), 130 deletions(-) diff --git a/arch/arm/src/armv7-r/Kconfig b/arch/arm/src/armv7-r/Kconfig index b42348de90d..b183d21f234 100644 --- a/arch/arm/src/armv7-r/Kconfig +++ b/arch/arm/src/armv7-r/Kconfig @@ -27,6 +27,8 @@ endif # ARMV7R_GIC_EOIMODE config ARMV7R_HAVE_PTM bool default n + select ONESHOT + select ONESHOT_COUNT ---help--- Selected by the configuration tool if the architecture supports the per-processor Private Timers (PTMs) diff --git a/arch/arm/src/armv7-r/arm_timer.c b/arch/arm/src/armv7-r/arm_timer.c index 23c6e07acf4..f6ed610bc10 100644 --- a/arch/arm/src/armv7-r/arm_timer.c +++ b/arch/arm/src/armv7-r/arm_timer.c @@ -49,52 +49,6 @@ # define GIC_IRQ_TIMER GIC_IRQ_PTM #endif -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure provides the private representation of the "lower-half" - * driver state structure. This structure must be cast-compatible with the - * oneshot_lowerhalf_s structure. - */ - -struct arm_timer_lowerhalf_s -{ - struct oneshot_lowerhalf_s lh; /* Lower half operations */ - uint32_t freq; /* Timer working clock frequency(Hz) */ - - /* which cpu timer is running, -1 indicate timer stoppd */ - - int running; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower, - struct timespec *ts); -static int arm_timer_start(struct oneshot_lowerhalf_s *lower, - const struct timespec *ts); -static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower, - struct timespec *ts); -static int arm_timer_current(struct oneshot_lowerhalf_s *lower, - struct timespec *ts); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const struct oneshot_operations_s g_arm_timer_ops = -{ - .max_delay = arm_timer_maxdelay, - .start = arm_timer_start, - .cancel = arm_timer_cancel, - .current = arm_timer_current, -}; - -static struct arm_timer_lowerhalf_s g_arm_timer_lowerhalf; - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -134,101 +88,42 @@ static inline void arm_timer_phy_set_irq_mask(bool mask) UP_ISB(); } -static inline uint64_t nsec_from_count(uint64_t count, uint32_t freq) +static int arm_timer_interrupt(int irq, void *regs, void *arg) { - uint64_t sec = count / freq; - uint64_t nsec = (count % freq) * NSEC_PER_SEC / freq; - return sec * NSEC_PER_SEC + nsec; + struct oneshot_lowerhalf_s *priv = (struct oneshot_lowerhalf_s *)arg; + arm_timer_phy_set_absolute(UINT64_MAX); + oneshot_process_callback(priv); + return OK; } -static inline uint64_t nsec_to_count(uint32_t nsec, uint32_t freq) +static clkcnt_t arm_oneshot_max_delay(struct oneshot_lowerhalf_s *lower) { - return (uint64_t)nsec * freq / NSEC_PER_SEC; + return UINT32_MAX; } -static inline uint64_t sec_to_count(uint32_t sec, uint32_t freq) +static clkcnt_t arm_oneshot_current(struct oneshot_lowerhalf_s *lower) { - return (uint64_t)sec * freq; + /* We do not need memory barrier here. */ + + return arm_timer_phy_count(); } -static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower_, - struct timespec *ts) +static void arm_oneshot_start_absolute(struct oneshot_lowerhalf_s *lower, + clkcnt_t expected) { - uint64_t maxnsec = nsec_from_count(UINT64_MAX, arm_timer_get_freq()); - - ts->tv_sec = maxnsec / NSEC_PER_SEC; - ts->tv_nsec = maxnsec % NSEC_PER_SEC; - - return 0; + arm_timer_phy_set_absolute(expected); } -static int arm_timer_start(struct oneshot_lowerhalf_s *lower_, - const struct timespec *ts) +static void arm_oneshot_start(struct oneshot_lowerhalf_s *lower, + clkcnt_t delta) { - struct arm_timer_lowerhalf_s *lower = - (struct arm_timer_lowerhalf_s *)lower_; - irqstate_t flags; - uint64_t count; - - flags = up_irq_save(); - - lower->running = this_cpu(); - - count = sec_to_count(ts->tv_sec, arm_timer_get_freq()) + - nsec_to_count(ts->tv_nsec, arm_timer_get_freq()); - - arm_timer_phy_set_relative(count > UINT32_MAX ? UINT32_MAX : count); - + arm_timer_phy_set_relative(delta); arm_timer_phy_set_irq_mask(false); - - up_irq_restore(flags); - - return 0; } -static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_, - struct timespec *ts) +static void arm_oneshot_cancel(struct oneshot_lowerhalf_s *lower) { - struct arm_timer_lowerhalf_s *lower = - (struct arm_timer_lowerhalf_s *)lower_; - irqstate_t flags; - - flags = up_irq_save(); - - lower->running = -1; - - arm_timer_phy_set_irq_mask(true); - - up_irq_restore(flags); - - return 0; -} - -static int arm_timer_current(struct oneshot_lowerhalf_s *lower_, - struct timespec *ts) -{ - uint64_t nsec = nsec_from_count(arm_timer_phy_count(), - arm_timer_get_freq()); - - ts->tv_sec = nsec / NSEC_PER_SEC; - ts->tv_nsec = nsec % NSEC_PER_SEC; - - return 0; -} - -static int arm_timer_interrupt(int irq, void *context, void *arg) -{ - struct arm_timer_lowerhalf_s *lower = arg; - DEBUGASSERT(lower != NULL); - - arm_timer_phy_set_irq_mask(true); - - if (lower->running == this_cpu()) - { - oneshot_process_callback(&lower->lh); - } - - return 0; + arm_timer_phy_set_absolute(UINT64_MAX); } static void arm_timer_initialize_per_cpu(unsigned int freq) @@ -240,29 +135,50 @@ static void arm_timer_initialize_per_cpu(unsigned int freq) arm_timer_set_freq(freq); } - arm_timer_phy_set_irq_mask(true); + arm_timer_phy_set_absolute(UINT64_MAX); arm_timer_phy_enable(true); + arm_timer_phy_set_irq_mask(false); up_enable_irq(GIC_IRQ_TIMER); } +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct oneshot_operations_s g_arm_oneshot_ops = +{ + .current = arm_oneshot_current, + .start = arm_oneshot_start, + .start_absolute = arm_oneshot_start_absolute, + .cancel = arm_oneshot_cancel, + .max_delay = arm_oneshot_max_delay, +}; + +static struct oneshot_lowerhalf_s g_arm_oneshot_lowerhalf = +{ + .ops = &g_arm_oneshot_ops +}; + /**************************************************************************** * Public Functions ****************************************************************************/ struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq) { - struct arm_timer_lowerhalf_s *lower = &g_arm_timer_lowerhalf; + struct oneshot_lowerhalf_s *lower = &g_arm_oneshot_lowerhalf; + + /* The init freq is for trust-zone only since CNTFRQ is only + * allowed to access in secure state. + */ arm_timer_initialize_per_cpu(freq); - lower->freq = arm_timer_get_freq(); - lower->lh.ops = &g_arm_timer_ops; - lower->running = -1; + oneshot_count_init(lower, arm_timer_get_freq()); irq_attach(GIC_IRQ_TIMER, arm_timer_interrupt, lower); - return (struct oneshot_lowerhalf_s *)lower; + return lower; } void arm_timer_secondary_init(unsigned int freq)