1 /*
2 * Copyright (c) 2020 Stephanos Ioannidis <root@stephanos.io>
3 * Copyright (c) 2018 Xilinx, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT xlnx_ttcps
9
10 #include <soc.h>
11 #include <drivers/timer/system_timer.h>
12 #include "xlnx_psttc_timer_priv.h"
13
14 #define TIMER_INDEX CONFIG_XLNX_PSTTC_TIMER_INDEX
15
16 #define TIMER_IRQ DT_INST_IRQN(0)
17 #define TIMER_BASE_ADDR DT_INST_REG_ADDR(0)
18 #define TIMER_CLOCK_FREQUECY DT_INST_PROP(0, clock_frequency)
19
20 #define TICKS_PER_SEC CONFIG_SYS_CLOCK_TICKS_PER_SEC
21 #define CYCLES_PER_SEC TIMER_CLOCK_FREQUECY
22 #define CYCLES_PER_TICK (CYCLES_PER_SEC / TICKS_PER_SEC)
23
24 /*
25 * CYCLES_NEXT_MIN must be large enough to ensure that the timer does not miss
26 * interrupts. This value was conservatively set using the trial and error
27 * method, and there is room for improvement.
28 */
29 #define CYCLES_NEXT_MIN (10000)
30 #define CYCLES_NEXT_MAX (XTTC_MAX_INTERVAL_COUNT)
31
32 BUILD_ASSERT(TIMER_CLOCK_FREQUECY ==
33 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
34 "Configured system timer frequency does not match the TTC "
35 "clock frequency in the device tree");
36
37 BUILD_ASSERT(CYCLES_PER_SEC >= TICKS_PER_SEC,
38 "Timer clock frequency must be greater than the system tick "
39 "frequency");
40
41 BUILD_ASSERT((CYCLES_PER_SEC % TICKS_PER_SEC) == 0,
42 "Timer clock frequency is not divisible by the system tick "
43 "frequency");
44
45 #ifdef CONFIG_TICKLESS_KERNEL
46 static uint32_t last_cycles;
47 #endif
48
read_count(void)49 static uint32_t read_count(void)
50 {
51 /* Read current counter value */
52 return sys_read32(TIMER_BASE_ADDR + XTTCPS_COUNT_VALUE_OFFSET);
53 }
54
update_match(uint32_t cycles,uint32_t match)55 static void update_match(uint32_t cycles, uint32_t match)
56 {
57 uint32_t delta = match - cycles;
58
59 /* Ensure that the match value meets the minimum timing requirements */
60 if (delta < CYCLES_NEXT_MIN) {
61 match += CYCLES_NEXT_MIN - delta;
62 }
63
64 /* Write counter match value for interrupt generation */
65 sys_write32(match, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
66 }
67
ttc_isr(const void * arg)68 static void ttc_isr(const void *arg)
69 {
70 uint32_t cycles;
71 uint32_t ticks;
72
73 ARG_UNUSED(arg);
74
75 /* Acknowledge interrupt */
76 sys_read32(TIMER_BASE_ADDR + XTTCPS_ISR_OFFSET);
77
78 /* Read counter value */
79 cycles = read_count();
80
81 #ifdef CONFIG_TICKLESS_KERNEL
82 /* Calculate the number of ticks since last announcement */
83 ticks = (cycles - last_cycles) / CYCLES_PER_TICK;
84
85 /* Update last cycles count */
86 last_cycles = cycles;
87 #else
88 /* Update counter match value for the next interrupt */
89 update_match(cycles, cycles + CYCLES_PER_TICK);
90
91 /* Advance tick count by 1 */
92 ticks = 1;
93 #endif
94
95 /* Announce to the kernel*/
96 sys_clock_announce(ticks);
97 }
98
sys_clock_driver_init(const struct device * dev)99 int sys_clock_driver_init(const struct device *dev)
100 {
101 uint32_t reg_val;
102 ARG_UNUSED(dev);
103
104 /* Stop timer */
105 sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK,
106 TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
107
108 #ifdef CONFIG_TICKLESS_KERNEL
109 /* Initialise internal states */
110 last_cycles = 0;
111 #endif
112
113 /* Initialise timer registers */
114 sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE,
115 TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
116 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_CLK_CNTRL_OFFSET);
117 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_INTERVAL_VAL_OFFSET);
118 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
119 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_1_OFFSET);
120 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_MATCH_2_OFFSET);
121 sys_write32(0, TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
122 sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASE_ADDR + XTTCPS_ISR_OFFSET);
123
124 /* Reset counter value */
125 reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
126 reg_val |= XTTCPS_CNT_CNTRL_RST_MASK;
127 sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
128
129 /* Set match mode */
130 reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
131 reg_val |= XTTCPS_CNT_CNTRL_MATCH_MASK;
132 sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
133
134 /* Set initial timeout */
135 reg_val = IS_ENABLED(CONFIG_TICKLESS_KERNEL) ?
136 CYCLES_NEXT_MAX : CYCLES_PER_TICK;
137 sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_MATCH_0_OFFSET);
138
139 /* Connect timer interrupt */
140 IRQ_CONNECT(TIMER_IRQ, 0, ttc_isr, 0, 0);
141 irq_enable(TIMER_IRQ);
142
143 /* Enable timer interrupt */
144 reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
145 reg_val |= XTTCPS_IXR_MATCH_0_MASK;
146 sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_IER_OFFSET);
147
148 /* Start timer */
149 reg_val = sys_read32(TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
150 reg_val &= (~XTTCPS_CNT_CNTRL_DIS_MASK);
151 sys_write32(reg_val, TIMER_BASE_ADDR + XTTCPS_CNT_CNTRL_OFFSET);
152
153 return 0;
154 }
155
sys_clock_set_timeout(int32_t ticks,bool idle)156 void sys_clock_set_timeout(int32_t ticks, bool idle)
157 {
158 #ifdef CONFIG_TICKLESS_KERNEL
159 uint32_t cycles;
160 uint32_t next_cycles;
161
162 /* Read counter value */
163 cycles = read_count();
164
165 /* Calculate timeout counter value */
166 if (ticks == K_TICKS_FOREVER) {
167 next_cycles = cycles + CYCLES_NEXT_MAX;
168 } else {
169 next_cycles = cycles + ((uint32_t)ticks * CYCLES_PER_TICK);
170 }
171
172 /* Set match value for the next interrupt */
173 update_match(cycles, next_cycles);
174 #endif
175 }
176
sys_clock_elapsed(void)177 uint32_t sys_clock_elapsed(void)
178 {
179 #ifdef CONFIG_TICKLESS_KERNEL
180 uint32_t cycles;
181
182 /* Read counter value */
183 cycles = read_count();
184
185 /* Return the number of ticks since last announcement */
186 return (cycles - last_cycles) / CYCLES_PER_TICK;
187 #else
188 /* Always return 0 for tickful operation */
189 return 0;
190 #endif
191 }
192
sys_clock_cycle_get_32(void)193 uint32_t sys_clock_cycle_get_32(void)
194 {
195 /* Return the current counter value */
196 return read_count();
197 }
198