From 5ffce32376558753a7c85c5de9d8c79ca5ded287 Mon Sep 17 00:00:00 2001 From: Maciej Sobkowski Date: Mon, 19 Jun 2023 14:18:25 +0200 Subject: [PATCH] drivers: timer: Add driver for Ambiq system timer (STIMER) This commit addst support for the system timer peripheral which can be found in Apollo4 SoCs. Signed-off-by: Maciej Sobkowski --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.ambiq | 13 +++ drivers/timer/ambiq_stimer.c | 150 +++++++++++++++++++++++++++ dts/arm/ambiq/ambiq_apollo4p.dtsi | 7 ++ dts/bindings/timer/ambiq,stimer.yaml | 15 +++ 6 files changed, 187 insertions(+) create mode 100644 drivers/timer/Kconfig.ambiq create mode 100644 drivers/timer/ambiq_stimer.c create mode 100644 dts/bindings/timer/ambiq,stimer.yaml diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index ced74f9559..47a10b358c 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_library() zephyr_library_sources(sys_clock_init.c) zephyr_library_sources_ifdef(CONFIG_ALTERA_AVALON_TIMER altera_avalon_timer_hal.c) +zephyr_library_sources_ifdef(CONFIG_AMBIQ_STIMER_TIMER ambiq_stimer.c) zephyr_library_sources_ifdef(CONFIG_APIC_TIMER apic_timer.c) zephyr_library_sources_ifdef(CONFIG_APIC_TSC_DEADLINE_TIMER apic_tsc.c) zephyr_library_sources_ifdef(CONFIG_ARCV2_TIMER arcv2_timer0.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 3631c55e49..fb615c2b7c 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -64,6 +64,7 @@ config SYSTEM_CLOCK_LOCK_FREE_COUNT hold times. source "drivers/timer/Kconfig.altera_avalon" +source "drivers/timer/Kconfig.ambiq" source "drivers/timer/Kconfig.apic" source "drivers/timer/Kconfig.arcv2" source "drivers/timer/Kconfig.arm_arch" diff --git a/drivers/timer/Kconfig.ambiq b/drivers/timer/Kconfig.ambiq new file mode 100644 index 0000000000..4d804a7699 --- /dev/null +++ b/drivers/timer/Kconfig.ambiq @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2023 Antmicro + +config AMBIQ_STIMER_TIMER + bool "Ambiq STIMER system clock driver" + default y + depends on DT_HAS_AMBIQ_STIMER_ENABLED + select AMBIQ_HAL + select TICKLESS_CAPABLE + select AMBIQ_HAL_USE_STIMER + help + Ambiq Apollo4 stimer driver diff --git a/drivers/timer/ambiq_stimer.c b/drivers/timer/ambiq_stimer.c new file mode 100644 index 0000000000..5db803fb12 --- /dev/null +++ b/drivers/timer/ambiq_stimer.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_stimer + +/** + * @file + * @brief Ambiq Apollo STIMER-based sys_clock driver + * + */ + +#include +#include +#include +#include +#include +#include + +/* ambiq-sdk includes */ +#include + +#define COUNTER_MAX UINT32_MAX + +#define CYC_PER_TICK (sys_clock_hw_cycles_per_sec() \ + / CONFIG_SYS_CLOCK_TICKS_PER_SEC) +#define MAX_TICKS ((k_ticks_t)(COUNTER_MAX / CYC_PER_TICK) - 1) +#define MAX_CYCLES (MAX_TICKS * CYC_PER_TICK) +#define MIN_DELAY 1 + +#define TIMER_IRQ (DT_INST_IRQN(0)) + +#if defined(CONFIG_TEST) +const int32_t z_sys_timer_irq_for_test = TIMER_IRQ; +#endif + +/* Value of STIMER counter when the previous kernel tick was announced */ +static atomic_t g_last_count; + +/* Spinlock to sync between Compare ISR and update of Compare register */ +static struct k_spinlock g_lock; + +static void stimer_isr(const void *arg) +{ + ARG_UNUSED(arg); + + uint32_t irq_status = am_hal_stimer_int_status_get(false); + + if (irq_status & AM_HAL_STIMER_INT_COMPAREA) { + am_hal_stimer_int_clear(AM_HAL_STIMER_INT_COMPAREA); + + k_spinlock_key_t key = k_spin_lock(&g_lock); + + uint32_t now = am_hal_stimer_counter_get(); + uint32_t dticks = (uint32_t)((now - g_last_count) / CYC_PER_TICK); + + g_last_count += dticks * CYC_PER_TICK; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + uint32_t next = g_last_count + CYC_PER_TICK; + + if ((int32_t)(next - now) < MIN_DELAY) { + next += CYC_PER_TICK; + } + am_hal_stimer_compare_delta_set(0, next - g_last_count); + } + + k_spin_unlock(&g_lock, key); + sys_clock_announce(dticks); + } +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; + } + + k_spinlock_key_t key = k_spin_lock(&g_lock); + + uint64_t now = am_hal_stimer_counter_get(); + uint32_t adj, cyc = ticks * CYC_PER_TICK; + + /* Round up to next tick boundary. */ + adj = (uint32_t)(now - g_last_count) + (CYC_PER_TICK - 1); + if (cyc <= MAX_CYCLES - adj) { + cyc += adj; + } else { + cyc = MAX_CYCLES; + } + cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK; + + if ((int32_t)(cyc + g_last_count - now) < MIN_DELAY) { + cyc += CYC_PER_TICK; + } + + am_hal_stimer_compare_delta_set(0, cyc); + + k_spin_unlock(&g_lock, key); +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + k_spinlock_key_t key = k_spin_lock(&g_lock); + uint32_t ret = (am_hal_stimer_counter_get() + - g_last_count) / CYC_PER_TICK; + + k_spin_unlock(&g_lock, key); + return ret; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return am_hal_stimer_counter_get(); +} + +static int stimer_init(void) +{ + uint32_t oldCfg; + k_spinlock_key_t key = k_spin_lock(&g_lock); + + oldCfg = am_hal_stimer_config(AM_HAL_STIMER_CFG_FREEZE); + + am_hal_stimer_config((oldCfg & ~(AM_HAL_STIMER_CFG_FREEZE | STIMER_STCFG_CLKSEL_Msk)) + | AM_HAL_STIMER_XTAL_32KHZ + | AM_HAL_STIMER_CFG_COMPARE_A_ENABLE); + + g_last_count = am_hal_stimer_counter_get(); + + k_spin_unlock(&g_lock, key); + + NVIC_ClearPendingIRQ(TIMER_IRQ); + IRQ_CONNECT(TIMER_IRQ, 0, stimer_isr, 0, 0); + irq_enable(TIMER_IRQ); + + am_hal_stimer_int_enable(AM_HAL_STIMER_INT_COMPAREA); + + return 0; +} + +SYS_INIT(stimer_init, PRE_KERNEL_2, + CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/arm/ambiq/ambiq_apollo4p.dtsi b/dts/arm/ambiq/ambiq_apollo4p.dtsi index 0a0116224d..3be926ad13 100644 --- a/dts/arm/ambiq/ambiq_apollo4p.dtsi +++ b/dts/arm/ambiq/ambiq_apollo4p.dtsi @@ -41,6 +41,13 @@ #pwrcfg-cells = <2>; }; + stimer0: stimer@40008800 { + compatible = "ambiq,stimer"; + reg = <0x40008800 0x80>; + interrupts = <32 0>; + status = "okay"; + }; + uart0: uart@4001c000 { compatible = "ambiq,uart", "arm,pl011"; reg = <0x4001c000 0x1000>; diff --git a/dts/bindings/timer/ambiq,stimer.yaml b/dts/bindings/timer/ambiq,stimer.yaml new file mode 100644 index 0000000000..f7bfa196f3 --- /dev/null +++ b/dts/bindings/timer/ambiq,stimer.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq STIMER + +compatible: "ambiq,stimer" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true