Skip to content
Permalink
Browse files

timer: Add Xilinx ZynqMP PS ttc timer

Add Xilinx PS ttc timer for Xilinx ZynqMP platform.

Signed-off-by: Wendy Liang <wendy.liang@xilinx.com>
  • Loading branch information...
Wendy Liang authored and ioannisg committed Nov 18, 2018
1 parent 5364a38 commit 4ef9d4b6bf6adfbca6b7c4a33e7a89e7e3186edd
@@ -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
@@ -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)
@@ -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
@@ -0,0 +1,196 @@
/*
* Copyright (c) 2018 Xilinx, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

#include <drivers/timer/system_timer.h>
#include <sys_clock.h>
#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;
}
@@ -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
...
@@ -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

0 comments on commit 4ef9d4b

Please sign in to comment.
You can’t perform that action at this time.