From 686cbc90f6094d87b1ebe491cbd7ad5fbf3633df Mon Sep 17 00:00:00 2001 From: Sven Ginka Date: Thu, 5 Sep 2024 21:07:36 +0200 Subject: [PATCH] driver: timer: Add support for sy1xx Add sys timer driver for Sensry's RISCV32 based SY1xx. Signed-off-by: Sven Ginka --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.sy1xx_sys_timer | 11 ++ drivers/timer/sy1xx_sys_timer.c | 180 ++++++++++++++++++ .../sy1xx,event-unit.yaml | 18 ++ dts/bindings/timer/sy1xx,sys-timer.yaml | 19 ++ 6 files changed, 230 insertions(+) create mode 100644 drivers/timer/Kconfig.sy1xx_sys_timer create mode 100644 drivers/timer/sy1xx_sys_timer.c create mode 100644 dts/bindings/interrupt-controller/sy1xx,event-unit.yaml create mode 100644 dts/bindings/timer/sy1xx,sys-timer.yaml diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index ac5bac6c244..56eea917d59 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -37,3 +37,4 @@ 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) zephyr_library_sources_ifdef(CONFIG_MTK_ADSP_TIMER mtk_adsp_timer.c) +zephyr_library_sources_ifdef(CONFIG_SY1XX_SYS_TIMER sy1xx_sys_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 3343f78d79c..e0fbfa4b1af 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -96,6 +96,7 @@ source "drivers/timer/Kconfig.ti_dm_timer" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" source "drivers/timer/Kconfig.mtk_adsp" +source "drivers/timer/Kconfig.sy1xx_sys_timer" endmenu diff --git a/drivers/timer/Kconfig.sy1xx_sys_timer b/drivers/timer/Kconfig.sy1xx_sys_timer new file mode 100644 index 00000000000..6770866aca5 --- /dev/null +++ b/drivers/timer/Kconfig.sy1xx_sys_timer @@ -0,0 +1,11 @@ +# Copyright (c) 2024 sensry.io +# SPDX-License-Identifier: Apache-2.0 + +config SY1XX_SYS_TIMER + bool "Sensry ganymed system timer" + default y + depends on SOC_SERIES_SY1XX + depends on $(dt_nodelabel_enabled,systick) + help + This module implements a kernel device driver for the system timer + and provides the standard "system clock driver" interfaces. diff --git a/drivers/timer/sy1xx_sys_timer.c b/drivers/timer/sy1xx_sys_timer.c new file mode 100644 index 00000000000..524b54ae2e7 --- /dev/null +++ b/drivers/timer/sy1xx_sys_timer.c @@ -0,0 +1,180 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 sensry.io + */ + +#define DT_DRV_COMPAT sy1xx_sys_timer + +#include +#include +#include +#include +#include +#include + +#define SY1XX_SYS_TIMER_NODE DT_NODELABEL(systick) +#define SY1XX_SYS_TIMER_BASE_ADDR DT_REG_ADDR(SY1XX_SYS_TIMER_NODE) + +#define SY1XX_MINIMUM_ALLOWED_TICK 1000 + +#define REG_TIMER_CMP_LO_OFFS 0x10 + +/* config bits */ +#define PLP_TIMER_ENABLE_BIT 0 +#define PLP_TIMER_RESET_BIT 1 +#define PLP_TIMER_IRQ_ENABLE_BIT 2 +#define PLP_TIMER_IEM_BIT 3 +#define PLP_TIMER_CMP_CLR_BIT 4 +#define PLP_TIMER_ONE_SHOT_BIT 5 +#define PLP_TIMER_PRESCALER_ENABLE_BIT 6 +#define PLP_TIMER_CLOCK_SOURCE_BIT 7 +#define PLP_TIMER_PRESCALER_VALUE_BIT 8 +#define PLP_TIMER_PRESCALER_VALUE_BITS 8 +#define PLP_TIMER_64_BIT 31 + +/* config flags */ +#define PLP_TIMER_ACTIVE 1 +#define PLP_TIMER_IDLE 0 + +#define PLP_TIMER_RESET_ENABLED 1 +#define PLP_TIMER_RESET_DISABLED 0 + +#define PLP_TIMER_IRQ_ENABLED 1 +#define PLP_TIMER_IRQ_DISABLED 0 + +#define PLP_TIMER_IEM_ENABLED 1 +#define PLP_TIMER_IEM_DISABLED 0 + +#define PLP_TIMER_CMPCLR_ENABLED 1 +#define PLP_TIMER_CMPCLR_DISABLED 0 + +#define PLP_TIMER_ONE_SHOT_ENABLED 1 +#define PLP_TIMER_ONE_SHOT_DISABLED 0 + +#define PLP_TIMER_REFCLK_ENABLED 1 +#define PLP_TIMER_REFCLK_DISABLED 0 + +#define PLP_TIMER_PRESCALER_ENABLED 1 +#define PLP_TIMER_PRESCALER_DISABLED 0 + +#define PLP_TIMER_MODE_64_ENABLED 1 +#define PLP_TIMER_MODE_64_DISABLED 0 + +static volatile uint32_t current_sys_clock; + +struct timer_cfg { + uint32_t tick_us; +}; + +static inline unsigned int timer_conf_prep(int enable, int reset, int irq_enable, int event_mask, + int cmp_clr, int one_shot, int clk_source, + int prescaler_enable, int prescaler, int mode_64) +{ + return (enable << PLP_TIMER_ENABLE_BIT) | (reset << PLP_TIMER_RESET_BIT) | + (irq_enable << PLP_TIMER_IRQ_ENABLE_BIT) | (event_mask << PLP_TIMER_IEM_BIT) | + (cmp_clr << PLP_TIMER_CMP_CLR_BIT) | (one_shot << PLP_TIMER_ONE_SHOT_BIT) | + (clk_source << PLP_TIMER_CLOCK_SOURCE_BIT) | + (prescaler_enable << PLP_TIMER_PRESCALER_ENABLE_BIT) | + (prescaler << PLP_TIMER_PRESCALER_VALUE_BIT) | (mode_64 << PLP_TIMER_64_BIT); +} + +static void sy1xx_sys_timer_reload(uint32_t base, uint32_t reload_timer_ticks) +{ + sys_write32(reload_timer_ticks, (base + REG_TIMER_CMP_LO_OFFS)); +} + +static void sy1xx_sys_timer_cfg_auto_reload(uint32_t base) +{ + + uint32_t conf = + timer_conf_prep(PLP_TIMER_ACTIVE, PLP_TIMER_RESET_ENABLED, PLP_TIMER_IRQ_ENABLED, + PLP_TIMER_IEM_DISABLED, PLP_TIMER_CMPCLR_ENABLED, + PLP_TIMER_ONE_SHOT_DISABLED, PLP_TIMER_REFCLK_ENABLED, + PLP_TIMER_PRESCALER_DISABLED, 0, PLP_TIMER_MODE_64_DISABLED); + + sys_write32(conf, base); +} + +static void sy1xx_sys_timer_irq_enable(void) +{ + soc_enable_irq(DT_IRQN(SY1XX_SYS_TIMER_NODE)); +} + +static void sy1xx_sys_timer_irq_disable(void) +{ + soc_disable_irq(DT_IRQN(SY1XX_SYS_TIMER_NODE)); +} + +static int32_t sy1xx_sys_timer_config(uint32_t base, struct timer_cfg *cfg) +{ + + /* global irq disable */ + uint32_t isr_state = arch_irq_lock(); + + if (cfg->tick_us < SY1XX_MINIMUM_ALLOWED_TICK) { + cfg->tick_us = SY1XX_MINIMUM_ALLOWED_TICK; + } + + /* expect 1.0ms resolution => tick_us = 1000 */ + uint32_t us = cfg->tick_us; + volatile double ticks_f = + (((double)us / (double)1000000) * (double)soc_get_rts_clock_frequency()) + 1.0; + + volatile uint32_t timer_ticks = (uint32_t)ticks_f; + + printk("timer [%d] expected %u (%d)\n", soc_get_rts_clock_frequency(), cfg->tick_us, + timer_ticks); + + sy1xx_sys_timer_reload(base, timer_ticks); + + sy1xx_sys_timer_cfg_auto_reload(base); + + /* we always start timer irq disabled */ + sy1xx_sys_timer_irq_disable(); + + /* restore global irq */ + arch_irq_unlock(isr_state); + + return 0; +} + +uint32_t sys_clock_elapsed(void) +{ + return 0; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return current_sys_clock; +} + +void sy1xx_sys_timer_callback(const void *user_data) +{ + current_sys_clock += 1; + + sys_clock_announce(1); +} + +static int sy1xx_sys_timer_init(void) +{ + printk("starting sys_timer\n"); + + struct timer_cfg timerCfg0 = { + .tick_us = DT_PROP(SY1XX_SYS_TIMER_NODE, ticks_us), + }; + + sy1xx_sys_timer_config(SY1XX_SYS_TIMER_BASE_ADDR, &timerCfg0); + + uint32_t irq = arch_irq_lock(); + + /* register interrupt routine with zephyr */ + irq_connect_dynamic(DT_IRQN(SY1XX_SYS_TIMER_NODE), 0, sy1xx_sys_timer_callback, NULL, 0); + + sy1xx_sys_timer_irq_enable(); + + arch_irq_unlock(irq | 0x1); + + return 0; +} + +SYS_INIT(sy1xx_sys_timer_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/bindings/interrupt-controller/sy1xx,event-unit.yaml b/dts/bindings/interrupt-controller/sy1xx,event-unit.yaml new file mode 100644 index 00000000000..4dba6bbbde5 --- /dev/null +++ b/dts/bindings/interrupt-controller/sy1xx,event-unit.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 sensry.io +# SPDX-License-Identifier: Apache-2.0 + +description: Sensry sy1xx event unit + +compatible: "sensry,sy1xx-event-unit" + +include: [interrupt-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#interrupt-cells": + const: 1 + +interrupt-cells: + - irq diff --git a/dts/bindings/timer/sy1xx,sys-timer.yaml b/dts/bindings/timer/sy1xx,sys-timer.yaml new file mode 100644 index 00000000000..b87fbd77564 --- /dev/null +++ b/dts/bindings/timer/sy1xx,sys-timer.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 sensry.io +# SPDX-License-Identifier: Apache-2.0 + +description: Sensry ganymed timer peripheral + +compatible: "sensry,sy1xx-sys-timer" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true + + ticks_us: + type: int + required: true