Skip to content

Commit 00144f4

Browse files
Wendy LiangBradley Bolen
authored andcommitted
timer: Add Xilinx ZynqMP PS ttc timer
Add Xilinx PS ttc timer for Xilinx ZynqMP platform. Signed-off-by: Wendy Liang <[email protected]>
1 parent df84594 commit 00144f4

File tree

6 files changed

+241
-0
lines changed

6 files changed

+241
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
/drivers/timer/altera_avalon_timer_hal.c @wentongwu
166166
/drivers/timer/riscv_machine_timer.c @nategraff-sifive @kgugala @pgielda
167167
/drivers/timer/litex_timer.c @mateusz-holenko @kgugala @pgielda
168+
/drivers/timer/xlnx_psttc_timer.c @wjliang
168169
/drivers/usb/ @jfischer-phytec-iot @finikorg
169170
/drivers/usb/device/usb_dc_stm32.c @ydamigos @loicpoulain
170171
/drivers/i2c/i2c_ll_stm32* @ldts @ydamigos

drivers/timer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ zephyr_sources_if_kconfig( native_posix_timer.c)
1515
zephyr_sources_if_kconfig( sam0_rtc_timer.c)
1616
zephyr_sources_if_kconfig( litex_timer.c)
1717
zephyr_sources_if_kconfig( mchp_xec_rtos_timer.c)
18+
zephyr_sources_if_kconfig( xlnx_psttc_timer.c)

drivers/timer/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,23 @@ config MCHP_XEC_RTOS_TIMER
241241
XEC series RTOS timer and provides the standard "system clock
242242
driver" interfaces.
243243

244+
config XLNX_PSTTC_TIMER
245+
bool "Xilinx PS ttc timer support"
246+
default y
247+
depends on SOC_XILINX_ZYNQMP
248+
help
249+
This module implements a kernel device driver for the Xilinx ZynqMP
250+
platform provides the standard "system clock driver" interfaces.
251+
If unchecked, no timer will be used.
252+
253+
config XLNX_PSTTC_TIMER_INDEX
254+
int "Xilinx PS ttc timer index"
255+
range 0 3
256+
default 0
257+
depends on XLNX_PSTTC_TIMER
258+
help
259+
This is the index of TTC timer picked to provide system clock.
260+
244261
config SYSTEM_CLOCK_DISABLE
245262
bool "API to disable system clock"
246263
help

drivers/timer/xlnx_psttc_timer.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2018 Xilinx, Inc.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <drivers/timer/system_timer.h>
7+
#include <sys_clock.h>
8+
#include "irq.h"
9+
#include "legacy_api.h"
10+
11+
#define TIMER_FREQ CONFIG_SYS_CLOCK_TICKS_PER_SEC
12+
13+
#if (CONFIG_XLNX_PSTTC_TIMER_INDEX == 0)
14+
#define TIMER_INPUT_CLKHZ DT_INST_0_CDNS_TTC_CLOCK_FREQUENCY
15+
#define TIMER_IRQ DT_INST_0_CDNS_TTC_IRQ_0
16+
#define TIMER_BASEADDR DT_INST_0_CDNS_TTC_BASE_ADDRESS
17+
#else
18+
#error ("No timer is specified")
19+
#endif
20+
21+
#define XTTCPS_CLK_CNTRL_OFFSET 0x00000000U /**< Clock Control Register */
22+
#define XTTCPS_CNT_CNTRL_OFFSET 0x0000000CU /**< Counter Control Register*/
23+
#define XTTCPS_COUNT_VALUE_OFFSET 0x00000018U /**< Current Counter Value */
24+
#define XTTCPS_INTERVAL_VAL_OFFSET 0x00000024U /**< Interval Count Value */
25+
#define XTTCPS_MATCH_0_OFFSET 0x00000030U /**< Match 1 value */
26+
#define XTTCPS_MATCH_1_OFFSET 0x0000003CU /**< Match 2 value */
27+
#define XTTCPS_MATCH_2_OFFSET 0x00000048U /**< Match 3 value */
28+
#define XTTCPS_ISR_OFFSET 0x00000054U /**< Interrupt Status Register */
29+
#define XTTCPS_IER_OFFSET 0x00000060U /**< Interrupt Enable Register */
30+
31+
/* Clock Control Register definitions */
32+
#define XTTCPS_CLK_CNTRL_PS_EN_MASK 0x00000001U /**< Prescale enable */
33+
#define XTTCPS_CLK_CNTRL_PS_VAL_MASK 0x0000001EU /**< Prescale value */
34+
#define XTTCPS_CLK_CNTRL_PS_VAL_SHIFT 1U /**< Prescale shift */
35+
#define XTTCPS_CLK_CNTRL_PS_DISABLE 16U /**< Prescale disable */
36+
#define XTTCPS_CLK_CNTRL_SRC_MASK 0x00000020U /**< Clock source */
37+
#define XTTCPS_CLK_CNTRL_EXT_EDGE_MASK 0x00000040U /**< External Clock edge */
38+
39+
/* Counter Control Register definitions */
40+
#define XTTCPS_CNT_CNTRL_DIS_MASK 0x00000001U /**< Disable the counter */
41+
#define XTTCPS_CNT_CNTRL_INT_MASK 0x00000002U /**< Interval mode */
42+
#define XTTCPS_CNT_CNTRL_DECR_MASK 0x00000004U /**< Decrement mode */
43+
#define XTTCPS_CNT_CNTRL_MATCH_MASK 0x00000008U /**< Match mode */
44+
#define XTTCPS_CNT_CNTRL_RST_MASK 0x00000010U /**< Reset counter */
45+
#define XTTCPS_CNT_CNTRL_EN_WAVE_MASK 0x00000020U /**< Enable waveform */
46+
#define XTTCPS_CNT_CNTRL_POL_WAVE_MASK 0x00000040U /**< Waveform polarity */
47+
#define XTTCPS_CNT_CNTRL_RESET_VALUE 0x00000021U /**< Reset value */
48+
49+
/* Interrupt register masks */
50+
#define XTTCPS_IXR_INTERVAL_MASK 0x00000001U /**< Interval Interrupt */
51+
#define XTTCPS_IXR_MATCH_0_MASK 0x00000002U /**< Match 1 Interrupt */
52+
#define XTTCPS_IXR_MATCH_1_MASK 0x00000004U /**< Match 2 Interrupt */
53+
#define XTTCPS_IXR_MATCH_2_MASK 0x00000008U /**< Match 3 Interrupt */
54+
#define XTTCPS_IXR_CNT_OVR_MASK 0x00000010U /**< Counter Overflow */
55+
#define XTTCPS_IXR_ALL_MASK 0x0000001FU /**< All valid Interrupts */
56+
57+
#define XTTC_MAX_INTERVAL_COUNT 0xFFFFFFFFU /**< Maximum value of interval counter */
58+
59+
static u32_t accumulated_cycles;
60+
static s32_t _sys_idle_elapsed_ticks = 1;
61+
62+
static int xttc_calculate_interval(u32_t *interval, u8_t *prescaler)
63+
{
64+
u32_t tmpinterval = 0;
65+
u8_t tmpprescaler = 0;
66+
unsigned int tmpval;
67+
68+
tmpval = (u32_t)(TIMER_INPUT_CLKHZ / TIMER_FREQ);
69+
70+
if (tmpval < (u32_t)65536U) {
71+
/* no prescaler is required */
72+
tmpinterval = tmpval;
73+
tmpprescaler = 0;
74+
} else {
75+
for (tmpprescaler = 1U; tmpprescaler < 16; tmpprescaler++) {
76+
tmpval = (u32_t)(TIMER_INPUT_CLKHZ /
77+
(TIMER_FREQ * (1U << tmpprescaler)));
78+
if (tmpval < (u32_t)65536U) {
79+
tmpinterval = tmpval;
80+
break;
81+
}
82+
}
83+
}
84+
85+
if (tmpinterval != 0) {
86+
*interval = tmpinterval;
87+
*prescaler = tmpprescaler;
88+
return 0;
89+
}
90+
91+
/* TBD: Is there a way to adjust the sys clock parameters such as
92+
* ticks per sec if it failed to configure the timer as specified
93+
*/
94+
return -EINVAL;
95+
}
96+
97+
/**
98+
* @brief System timer tick handler
99+
*
100+
* This routine handles the system clock tick interrupt. A TICK_EVENT event
101+
* is pushed onto the kernel stack.
102+
*
103+
* The symbol for this routine is either _timer_int_handler.
104+
*
105+
* @return N/A
106+
*/
107+
void _timer_int_handler(void *unused)
108+
{
109+
ARG_UNUSED(unused);
110+
111+
u32_t regval;
112+
113+
regval = sys_read32(TIMER_BASEADDR + XTTCPS_ISR_OFFSET);
114+
accumulated_cycles += sys_clock_hw_cycles_per_tick();
115+
z_clock_announce(_sys_idle_elapsed_ticks);
116+
}
117+
118+
/**
119+
* @brief Initialize and enable the system clock
120+
*
121+
* This routine is used to program the systick to deliver interrupts at the
122+
* rate specified via the 'sys_clock_us_per_tick' global variable.
123+
*
124+
* @return 0
125+
*/
126+
int z_clock_driver_init(struct device *device)
127+
{
128+
int ret;
129+
u32_t interval;
130+
u8_t prescaler;
131+
u32_t regval;
132+
133+
/* Stop timer */
134+
sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK,
135+
TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
136+
137+
/* Calculate prescaler */
138+
ret = xttc_calculate_interval(&interval, &prescaler);
139+
if (ret < 0) {
140+
printk("Failed to calculate prescaler.\n");
141+
return ret;
142+
}
143+
144+
/* Reset registers */
145+
sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE,
146+
TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
147+
sys_write32(0, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET);
148+
sys_write32(0, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET);
149+
sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_0_OFFSET);
150+
sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_1_OFFSET);
151+
sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_2_OFFSET);
152+
sys_write32(0, TIMER_BASEADDR + XTTCPS_IER_OFFSET);
153+
sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASEADDR + XTTCPS_ISR_OFFSET);
154+
/* Reset counter value */
155+
regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
156+
regval |= XTTCPS_CNT_CNTRL_RST_MASK;
157+
sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
158+
159+
/* Set options */
160+
regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
161+
regval |= XTTCPS_CNT_CNTRL_INT_MASK;
162+
sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
163+
164+
/* Set interval and prescaller */
165+
sys_write32(interval, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET);
166+
regval = (u32_t)((prescaler & 0xFU) << 1);
167+
sys_write32(regval, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET);
168+
169+
/* Enable timer interrupt */
170+
IRQ_CONNECT(TIMER_IRQ, 0, _timer_int_handler, 0, 0);
171+
irq_enable(TIMER_IRQ);
172+
regval = sys_read32(TIMER_BASEADDR + XTTCPS_IER_OFFSET);
173+
regval |= XTTCPS_IXR_INTERVAL_MASK;
174+
sys_write32(regval, TIMER_BASEADDR + XTTCPS_IER_OFFSET);
175+
176+
/* Start timer */
177+
regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
178+
regval &= (~XTTCPS_CNT_CNTRL_DIS_MASK);
179+
sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
180+
181+
return 0;
182+
}
183+
184+
185+
/**
186+
* @brief Read the platform's timer hardware
187+
*
188+
* This routine returns the current time in terms of timer hardware clock
189+
* cycles.
190+
*
191+
* @return up counter of elapsed clock cycles
192+
*/
193+
u32_t z_timer_cycle_get_32(void)
194+
{
195+
return accumulated_cycles;
196+
}

dts/bindings/timer/xlnx,ttcps.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
title: Xilinx ZynqMP PS TTC TIMERS
3+
4+
description: >
5+
This binding gives a base representation of the Xilinx ZynqMP PS TTC TIMERS
6+
7+
inherits:
8+
!include base.yaml
9+
10+
properties:
11+
compatible:
12+
constraint: "cdns,ttc"
13+
14+
label:
15+
category: required
16+
17+
reg:
18+
category: required
19+
20+
clock-frequency:
21+
type: int
22+
category: optional
23+
description: Clock frequency information for Timer operation
24+
...

tests/kernel/context/src/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
#define TICK_IRQ DT_LITEX_TIMER0_E0002800_IRQ_0
6868
#elif defined(CONFIG_RV32M1_LPTMR_TIMER)
6969
#define TICK_IRQ DT_OPENISA_RV32M1_LPTMR_SYSTEM_LPTMR_IRQ_0
70+
#elif defined(CONFIG_XLNX_PSTTC_TIMER)
71+
#define TICK_IRQ DT_INST_0_CDNS_TTC_IRQ_0
7072
#elif defined(CONFIG_CPU_CORTEX_M)
7173
/*
7274
* The Cortex-M use the SYSTICK exception for the system timer, which is

0 commit comments

Comments
 (0)