diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 10edb91416..c44acda2ae 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -33,3 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c) zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) +zephyr_library_sources_ifdef(CONFIG_SMARTBOND_TIMER smartbond_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 317efd71d8..2ddfe321e7 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -90,6 +90,7 @@ source "drivers/timer/Kconfig.rcar_cmt" source "drivers/timer/Kconfig.riscv_machine" source "drivers/timer/Kconfig.rv32m1_lptmr" source "drivers/timer/Kconfig.sam0_rtc" +source "drivers/timer/Kconfig.smartbond" source "drivers/timer/Kconfig.stm32_lptim" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" diff --git a/drivers/timer/Kconfig.smartbond b/drivers/timer/Kconfig.smartbond new file mode 100644 index 0000000000..2b5cb3c32e --- /dev/null +++ b/drivers/timer/Kconfig.smartbond @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SMARTBOND_TIMER + bool "Renesas SmartBond(tm) timer" + default y + depends on SOC_FAMILY_RENESAS_SMARTBOND + depends on CLOCK_CONTROL + depends on !$(dt_nodelabel_enabled,timer2) + select TICKLESS_CAPABLE + help + This module implements a kernel device driver for the TIMER2 timer + and provides the standard "system clock driver" interfaces. diff --git a/drivers/timer/smartbond_timer.c b/drivers/timer/smartbond_timer.c new file mode 100644 index 0000000000..34c9a7d721 --- /dev/null +++ b/drivers/timer/smartbond_timer.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define COUNTER_SPAN BIT(24) +#define CYC_PER_TICK k_ticks_to_cyc_ceil32(1) +#define TICK_TO_CYC(tick) k_ticks_to_cyc_ceil32(tick) +#define CYC_TO_TICK(cyc) k_cyc_to_ticks_ceil32(cyc) +#define MAX_TICKS (((COUNTER_SPAN / 2) - CYC_PER_TICK) / (CYC_PER_TICK)) + +static uint32_t last_timer_val_reg; +static uint32_t timer_val_31_24; + +static uint32_t last_isr_val; +static uint32_t last_isr_val_rounded; +static uint32_t announced_ticks; + +static void set_reload(uint32_t val) +{ + TIMER2->TIMER2_RELOAD_REG = val & TIMER2_TIMER2_RELOAD_REG_TIM_RELOAD_Msk; +} + +static uint32_t timer_val_32(void) +{ + uint32_t timer_val_reg; + uint32_t val; + + timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG & + TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk; + if (timer_val_reg < last_timer_val_reg) { + timer_val_31_24 += COUNTER_SPAN; + } + last_timer_val_reg = timer_val_reg; + + val = timer_val_31_24 + timer_val_reg; + + return val; +} + +static uint32_t timer_val_32_noupdate(void) +{ + uint32_t timer_val_reg; + uint32_t val; + + timer_val_reg = TIMER2->TIMER2_TIMER_VAL_REG & + TIMER2_TIMER2_TIMER_VAL_REG_TIM_TIMER_VALUE_Msk; + val = timer_val_31_24 + timer_val_reg; + if (timer_val_reg < last_timer_val_reg) { + val += COUNTER_SPAN; + } + + return val; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + uint32_t target_val; + uint32_t timer_val; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return; + } + + if (ticks == K_TICKS_FOREVER) { + /* FIXME we could disable timer here */ + } + + ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks; + ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS); + + timer_val = timer_val_32_noupdate(); + + /* Calculate target timer value and align to full tick */ + target_val = timer_val + TICK_TO_CYC(ticks); + target_val = ((target_val + CYC_PER_TICK - 1) / CYC_PER_TICK) * CYC_PER_TICK; + + set_reload(target_val); +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + return CYC_TO_TICK(timer_val_32_noupdate() - last_isr_val); +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return timer_val_32_noupdate(); +} + +void sys_clock_idle_exit(void) +{ + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; +} + +void sys_clock_disable(void) +{ + TIMER2->TIMER2_CTRL_REG &= ~TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; +} + +static void timer2_isr(const void *arg) +{ + uint32_t val; + int32_t delta; + int32_t dticks; + + ARG_UNUSED(arg); + + TIMER2->TIMER2_CLEAR_IRQ_REG = 1; + + val = timer_val_32(); + delta = (int32_t)(val - last_isr_val_rounded); + last_isr_val = val; + dticks = CYC_TO_TICK(delta); + last_isr_val_rounded += TICK_TO_CYC(dticks); + announced_ticks += dticks; + sys_clock_announce(dticks); +} + +static int sys_clock_driver_init(void) +{ +#if CONFIG_PM + uint8_t pdc_idx; + uint8_t en_xtal; + + en_xtal = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay) ? MCU_PDC_EN_XTAL : 0; + + /* Enable wakeup by TIMER2 */ + pdc_idx = da1469x_pdc_add(MCU_PDC_TRIGGER_TIMER2, MCU_PDC_MASTER_M33, en_xtal); + __ASSERT_NO_MSG(pdc_idx >= 0); + da1469x_pdc_set(pdc_idx); + da1469x_pdc_ack(pdc_idx); +#endif + + TIMER2->TIMER2_CTRL_REG = 0; + TIMER2->TIMER2_PRESCALER_REG = 0; + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_CLK_EN_Msk; + TIMER2->TIMER2_CTRL_REG |= TIMER2_TIMER2_CTRL_REG_TIM_FREE_RUN_MODE_EN_Msk | + TIMER2_TIMER2_CTRL_REG_TIM_IRQ_EN_Msk | + TIMER2_TIMER2_CTRL_REG_TIM_EN_Msk; + + IRQ_CONNECT(TIMER2_IRQn, _IRQ_PRIO_OFFSET, timer2_isr, 0, 0); + irq_enable(TIMER2_IRQn); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/soc/renesas/smartbond/da1469x/Kconfig.defconfig b/soc/renesas/smartbond/da1469x/Kconfig.defconfig index fedbde9f19..97d364a87e 100644 --- a/soc/renesas/smartbond/da1469x/Kconfig.defconfig +++ b/soc/renesas/smartbond/da1469x/Kconfig.defconfig @@ -3,11 +3,21 @@ if SOC_SERIES_DA1469X +config SMARTBOND_TIMER + default y if PM + +config CORTEX_M_SYSTICK + default n if SMARTBOND_TIMER + config NUM_IRQS default 40 config SYS_CLOCK_HW_CYCLES_PER_SEC - default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) if CORTEX_M_SYSTICK + default 32768 if SMARTBOND_TIMER + +config SYS_CLOCK_TICKS_PER_SEC + default 32768 if SMARTBOND_TIMER config SRAM_VECTOR_TABLE default y