From 4ef9d4b6bf6adfbca6b7c4a33e7a89e7e3186edd Mon Sep 17 00:00:00 2001 From: Wendy Liang Date: Sat, 17 Nov 2018 23:28:49 -0800 Subject: [PATCH] timer: Add Xilinx ZynqMP PS ttc timer Add Xilinx PS ttc timer for Xilinx ZynqMP platform. Signed-off-by: Wendy Liang --- CODEOWNERS | 1 + drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 17 +++ drivers/timer/xlnx_psttc_timer.c | 196 +++++++++++++++++++++++++++++ dts/bindings/timer/xlnx,ttcps.yaml | 24 ++++ tests/kernel/context/src/main.c | 2 + 6 files changed, 241 insertions(+) create mode 100644 drivers/timer/xlnx_psttc_timer.c create mode 100644 dts/bindings/timer/xlnx,ttcps.yaml diff --git a/CODEOWNERS b/CODEOWNERS index e1bf0e5d44..32fc14542b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -165,6 +165,7 @@ /drivers/timer/altera_avalon_timer_hal.c @wentongwu /drivers/timer/riscv_machine_timer.c @nategraff-sifive @kgugala @pgielda /drivers/timer/litex_timer.c @mateusz-holenko @kgugala @pgielda +/drivers/timer/xlnx_psttc_timer.c @wjliang /drivers/usb/ @jfischer-phytec-iot @finikorg /drivers/usb/device/usb_dc_stm32.c @ydamigos @loicpoulain /drivers/i2c/i2c_ll_stm32* @ldts @ydamigos diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index ef8cb2bbd0..b124c6ff66 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_sources_if_kconfig( native_posix_timer.c) zephyr_sources_if_kconfig( sam0_rtc_timer.c) zephyr_sources_if_kconfig( litex_timer.c) zephyr_sources_if_kconfig( mchp_xec_rtos_timer.c) +zephyr_sources_if_kconfig( xlnx_psttc_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 90b0a709a4..7c68071812 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -241,6 +241,23 @@ config MCHP_XEC_RTOS_TIMER XEC series RTOS timer and provides the standard "system clock driver" interfaces. +config XLNX_PSTTC_TIMER + bool "Xilinx PS ttc timer support" + default y + depends on SOC_XILINX_ZYNQMP + help + This module implements a kernel device driver for the Xilinx ZynqMP + platform provides the standard "system clock driver" interfaces. + If unchecked, no timer will be used. + +config XLNX_PSTTC_TIMER_INDEX + int "Xilinx PS ttc timer index" + range 0 3 + default 0 + depends on XLNX_PSTTC_TIMER + help + This is the index of TTC timer picked to provide system clock. + config SYSTEM_CLOCK_DISABLE bool "API to disable system clock" help diff --git a/drivers/timer/xlnx_psttc_timer.c b/drivers/timer/xlnx_psttc_timer.c new file mode 100644 index 0000000000..5ec46ab3e2 --- /dev/null +++ b/drivers/timer/xlnx_psttc_timer.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2018 Xilinx, Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "irq.h" +#include "legacy_api.h" + +#define TIMER_FREQ CONFIG_SYS_CLOCK_TICKS_PER_SEC + +#if (CONFIG_XLNX_PSTTC_TIMER_INDEX == 0) +#define TIMER_INPUT_CLKHZ DT_INST_0_CDNS_TTC_CLOCK_FREQUENCY +#define TIMER_IRQ DT_INST_0_CDNS_TTC_IRQ_0 +#define TIMER_BASEADDR DT_INST_0_CDNS_TTC_BASE_ADDRESS +#else +#error ("No timer is specified") +#endif + +#define XTTCPS_CLK_CNTRL_OFFSET 0x00000000U /**< Clock Control Register */ +#define XTTCPS_CNT_CNTRL_OFFSET 0x0000000CU /**< Counter Control Register*/ +#define XTTCPS_COUNT_VALUE_OFFSET 0x00000018U /**< Current Counter Value */ +#define XTTCPS_INTERVAL_VAL_OFFSET 0x00000024U /**< Interval Count Value */ +#define XTTCPS_MATCH_0_OFFSET 0x00000030U /**< Match 1 value */ +#define XTTCPS_MATCH_1_OFFSET 0x0000003CU /**< Match 2 value */ +#define XTTCPS_MATCH_2_OFFSET 0x00000048U /**< Match 3 value */ +#define XTTCPS_ISR_OFFSET 0x00000054U /**< Interrupt Status Register */ +#define XTTCPS_IER_OFFSET 0x00000060U /**< Interrupt Enable Register */ + +/* Clock Control Register definitions */ +#define XTTCPS_CLK_CNTRL_PS_EN_MASK 0x00000001U /**< Prescale enable */ +#define XTTCPS_CLK_CNTRL_PS_VAL_MASK 0x0000001EU /**< Prescale value */ +#define XTTCPS_CLK_CNTRL_PS_VAL_SHIFT 1U /**< Prescale shift */ +#define XTTCPS_CLK_CNTRL_PS_DISABLE 16U /**< Prescale disable */ +#define XTTCPS_CLK_CNTRL_SRC_MASK 0x00000020U /**< Clock source */ +#define XTTCPS_CLK_CNTRL_EXT_EDGE_MASK 0x00000040U /**< External Clock edge */ + +/* Counter Control Register definitions */ +#define XTTCPS_CNT_CNTRL_DIS_MASK 0x00000001U /**< Disable the counter */ +#define XTTCPS_CNT_CNTRL_INT_MASK 0x00000002U /**< Interval mode */ +#define XTTCPS_CNT_CNTRL_DECR_MASK 0x00000004U /**< Decrement mode */ +#define XTTCPS_CNT_CNTRL_MATCH_MASK 0x00000008U /**< Match mode */ +#define XTTCPS_CNT_CNTRL_RST_MASK 0x00000010U /**< Reset counter */ +#define XTTCPS_CNT_CNTRL_EN_WAVE_MASK 0x00000020U /**< Enable waveform */ +#define XTTCPS_CNT_CNTRL_POL_WAVE_MASK 0x00000040U /**< Waveform polarity */ +#define XTTCPS_CNT_CNTRL_RESET_VALUE 0x00000021U /**< Reset value */ + +/* Interrupt register masks */ +#define XTTCPS_IXR_INTERVAL_MASK 0x00000001U /**< Interval Interrupt */ +#define XTTCPS_IXR_MATCH_0_MASK 0x00000002U /**< Match 1 Interrupt */ +#define XTTCPS_IXR_MATCH_1_MASK 0x00000004U /**< Match 2 Interrupt */ +#define XTTCPS_IXR_MATCH_2_MASK 0x00000008U /**< Match 3 Interrupt */ +#define XTTCPS_IXR_CNT_OVR_MASK 0x00000010U /**< Counter Overflow */ +#define XTTCPS_IXR_ALL_MASK 0x0000001FU /**< All valid Interrupts */ + +#define XTTC_MAX_INTERVAL_COUNT 0xFFFFFFFFU /**< Maximum value of interval counter */ + +static u32_t accumulated_cycles; +static s32_t _sys_idle_elapsed_ticks = 1; + +static int xttc_calculate_interval(u32_t *interval, u8_t *prescaler) +{ + u32_t tmpinterval = 0; + u8_t tmpprescaler = 0; + unsigned int tmpval; + + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / TIMER_FREQ); + + if (tmpval < (u32_t)65536U) { + /* no prescaler is required */ + tmpinterval = tmpval; + tmpprescaler = 0; + } else { + for (tmpprescaler = 1U; tmpprescaler < 16; tmpprescaler++) { + tmpval = (u32_t)(TIMER_INPUT_CLKHZ / + (TIMER_FREQ * (1U << tmpprescaler))); + if (tmpval < (u32_t)65536U) { + tmpinterval = tmpval; + break; + } + } + } + + if (tmpinterval != 0) { + *interval = tmpinterval; + *prescaler = tmpprescaler; + return 0; + } + + /* TBD: Is there a way to adjust the sys clock parameters such as + * ticks per sec if it failed to configure the timer as specified + */ + return -EINVAL; +} + +/** + * @brief System timer tick handler + * + * This routine handles the system clock tick interrupt. A TICK_EVENT event + * is pushed onto the kernel stack. + * + * The symbol for this routine is either _timer_int_handler. + * + * @return N/A + */ +void _timer_int_handler(void *unused) +{ + ARG_UNUSED(unused); + + u32_t regval; + + regval = sys_read32(TIMER_BASEADDR + XTTCPS_ISR_OFFSET); + accumulated_cycles += sys_clock_hw_cycles_per_tick(); + z_clock_announce(_sys_idle_elapsed_ticks); +} + +/** + * @brief Initialize and enable the system clock + * + * This routine is used to program the systick to deliver interrupts at the + * rate specified via the 'sys_clock_us_per_tick' global variable. + * + * @return 0 + */ +int z_clock_driver_init(struct device *device) +{ + int ret; + u32_t interval; + u8_t prescaler; + u32_t regval; + + /* Stop timer */ + sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK, + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Calculate prescaler */ + ret = xttc_calculate_interval(&interval, &prescaler); + if (ret < 0) { + printk("Failed to calculate prescaler.\n"); + return ret; + } + + /* Reset registers */ + sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE, + TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_0_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_1_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_2_OFFSET); + sys_write32(0, TIMER_BASEADDR + XTTCPS_IER_OFFSET); + sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASEADDR + XTTCPS_ISR_OFFSET); + /* Reset counter value */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval |= XTTCPS_CNT_CNTRL_RST_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Set options */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval |= XTTCPS_CNT_CNTRL_INT_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + /* Set interval and prescaller */ + sys_write32(interval, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET); + regval = (u32_t)((prescaler & 0xFU) << 1); + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET); + + /* Enable timer interrupt */ + IRQ_CONNECT(TIMER_IRQ, 0, _timer_int_handler, 0, 0); + irq_enable(TIMER_IRQ); + regval = sys_read32(TIMER_BASEADDR + XTTCPS_IER_OFFSET); + regval |= XTTCPS_IXR_INTERVAL_MASK; + sys_write32(regval, TIMER_BASEADDR + XTTCPS_IER_OFFSET); + + /* Start timer */ + regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + regval &= (~XTTCPS_CNT_CNTRL_DIS_MASK); + sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET); + + return 0; +} + + +/** + * @brief Read the platform's timer hardware + * + * This routine returns the current time in terms of timer hardware clock + * cycles. + * + * @return up counter of elapsed clock cycles + */ +u32_t z_timer_cycle_get_32(void) +{ + return accumulated_cycles; +} diff --git a/dts/bindings/timer/xlnx,ttcps.yaml b/dts/bindings/timer/xlnx,ttcps.yaml new file mode 100644 index 0000000000..dc2d352139 --- /dev/null +++ b/dts/bindings/timer/xlnx,ttcps.yaml @@ -0,0 +1,24 @@ +--- +title: Xilinx ZynqMP PS TTC TIMERS + +description: > + This binding gives a base representation of the Xilinx ZynqMP PS TTC TIMERS + +inherits: + !include base.yaml + +properties: + compatible: + constraint: "cdns,ttc" + + label: + category: required + + reg: + category: required + + clock-frequency: + type: int + category: optional + description: Clock frequency information for Timer operation +... diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c index 14b96db44b..d4cca0f9e3 100644 --- a/tests/kernel/context/src/main.c +++ b/tests/kernel/context/src/main.c @@ -67,6 +67,8 @@ #define TICK_IRQ DT_LITEX_TIMER0_E0002800_IRQ_0 #elif defined(CONFIG_RV32M1_LPTMR_TIMER) #define TICK_IRQ DT_OPENISA_RV32M1_LPTMR_SYSTEM_LPTMR_IRQ_0 +#elif defined(CONFIG_XLNX_PSTTC_TIMER) +#define TICK_IRQ DT_INST_0_CDNS_TTC_IRQ_0 #elif defined(CONFIG_CPU_CORTEX_M) /* * The Cortex-M use the SYSTICK exception for the system timer, which is