3434
3535#include "IfxStm.h"
3636
37+ /****************************************************************************
38+ * Pre-processor Definitions
39+ ****************************************************************************/
40+
41+ /* Since the tricore hardware timer triggers an interrupt only when the
42+ * compare value is equal to the counter, setting a compare value that has
43+ * already timed out will not trigger an interrupt. To avoid missing
44+ * interrupts when setting the timer, we should set a minimum delay.
45+ * The minimum delay is calculated based on the CPU frequency and the timer
46+ * frequency. We assume that the worst-case execution time for setting the
47+ * timer does not exceed 40 CPU cycles, and calculate the minimum timer
48+ * delay accordingly.
49+ * 40 CPU cycles (100ns at 400Mhz) ~ 10 timer cycles (for 100 Mhz timer).
50+ */
51+
52+ #define TRICORE_SYSTIMER_MIN_DELAY \
53+ (40ull * SCU_FREQUENCY / IFX_CFG_CPU_CLOCK_FREQUENCY)
54+
3755/****************************************************************************
3856 * Private Types
3957 ****************************************************************************/
4664struct tricore_systimer_lowerhalf_s
4765{
4866 struct oneshot_lowerhalf_s lower ;
49- volatile void * tbase ;
50- uint64_t freq ;
51- uint64_t alarm ;
52- spinlock_t lock ;
53- };
54-
55- /****************************************************************************
56- * Private Function Prototypes
57- ****************************************************************************/
58-
59- static int tricore_systimer_max_delay (struct oneshot_lowerhalf_s * lower ,
60- struct timespec * ts );
61- static int tricore_systimer_start (struct oneshot_lowerhalf_s * lower ,
62- const struct timespec * ts );
63- static int tricore_systimer_cancel (struct oneshot_lowerhalf_s * lower ,
64- struct timespec * ts );
65- static int tricore_systimer_current (struct oneshot_lowerhalf_s * lower ,
66- struct timespec * ts );
67-
68- /****************************************************************************
69- * Private Data
70- ****************************************************************************/
71-
72- static const struct oneshot_operations_s g_tricore_systimer_ops =
73- {
74- .max_delay = tricore_systimer_max_delay ,
75- .start = tricore_systimer_start ,
76- .cancel = tricore_systimer_cancel ,
77- .current = tricore_systimer_current ,
78- };
79-
80- static struct tricore_systimer_lowerhalf_s g_systimer_lower =
81- {
82- .lower .ops = & g_tricore_systimer_ops ,
67+ volatile void * tbase ;
8368};
8469
8570/****************************************************************************
@@ -124,59 +109,87 @@ tricore_systimer_set_timecmp(struct tricore_systimer_lowerhalf_s *priv,
124109 * lower An instance of the lower-half oneshot state structure. This
125110 * structure must have been previously initialized via a call to
126111 * oneshot_initialize();
127- * ts The location in which to return the maximum delay.
128112 *
129113 * Returned Value:
130- * Zero (OK) is returned on success; a negated errno value is returned
131- * on failure.
114+ * The maximum delay value.
132115 *
133116 ****************************************************************************/
134117
135- static int tricore_systimer_max_delay (struct oneshot_lowerhalf_s * lower ,
136- struct timespec * ts )
118+ static clkcnt_t tricore_systimer_max_delay (struct oneshot_lowerhalf_s * lower )
137119{
138- ts -> tv_sec = UINT32_MAX ;
139- ts -> tv_nsec = NSEC_PER_SEC - 1 ;
140-
141- return 0 ;
120+ return UINT32_MAX ;
142121}
143122
144123/****************************************************************************
145124 * Name: tricore_systimer_start
146125 *
147126 * Description:
148- * Start the oneshot timer
127+ * Start the oneshot timer. Note that the tricore systimer is special, the
128+ * IRQ is only triggered when timecmp == mtime, so we should avoid the case
129+ * that we miss the timecmp.
149130 *
150131 * Input Parameters:
151132 * lower An instance of the lower-half oneshot state structure. This
152133 * structure must have been previously initialized via a call to
153134 * oneshot_initialize();
154- * handler The function to call when when the oneshot timer expires.
155- * arg An opaque argument that will accompany the callback.
156- * ts Provides the duration of the one shot timer.
135+ * delta Provides the duration of delta count.
157136 *
158137 * Returned Value:
159- * Zero (OK) is returned on success; a negated errno value is returned
160- * on failure.
138+ * None.
161139 *
162140 ****************************************************************************/
163141
164- static int tricore_systimer_start (struct oneshot_lowerhalf_s * lower ,
165- const struct timespec * ts )
142+ static void tricore_systimer_start (struct oneshot_lowerhalf_s * lower ,
143+ clkcnt_t delta )
166144{
167145 struct tricore_systimer_lowerhalf_s * priv =
168146 (struct tricore_systimer_lowerhalf_s * )lower ;
169- uint64_t mtime = tricore_systimer_get_time (priv );
147+ irqstate_t flags ;
148+ uint64_t mtime ;
149+
150+ delta = delta < TRICORE_SYSTIMER_MIN_DELAY ?
151+ TRICORE_SYSTIMER_MIN_DELAY : delta ;
152+ flags = up_irq_save ();
153+ mtime = tricore_systimer_get_time (priv );
170154
171- priv -> alarm = mtime + ts -> tv_sec * priv -> freq +
172- ts -> tv_nsec * priv -> freq / NSEC_PER_SEC ;
173- if (priv -> alarm < mtime )
174- {
175- priv -> alarm = UINT64_MAX ;
176- }
155+ tricore_systimer_set_timecmp (priv , mtime + delta );
177156
178- tricore_systimer_set_timecmp (priv , priv -> alarm );
179- return 0 ;
157+ up_irq_restore (flags );
158+ }
159+
160+ /****************************************************************************
161+ * Name: tricore_systimer_start_absolute
162+ *
163+ * Description:
164+ * Start the oneshot timer. Note that the tricore systimer is special, the
165+ * IRQ is only triggered when timecmp == mtime, so we should avoid the case
166+ * that we miss the timecmp.
167+ *
168+ * Input Parameters:
169+ * lower An instance of the lower-half oneshot state structure. This
170+ * structure must have been previously initialized via a call to
171+ * oneshot_initialize();
172+ * expected Target
173+ *
174+ * Returned Value:
175+ * None.
176+ *
177+ ****************************************************************************/
178+
179+ static void
180+ tricore_systimer_start_absolute (struct oneshot_lowerhalf_s * lower ,
181+ clkcnt_t expected )
182+ {
183+ struct tricore_systimer_lowerhalf_s * priv =
184+ (struct tricore_systimer_lowerhalf_s * )lower ;
185+
186+ irqstate_t flags = up_irq_save ();
187+ uint64_t min_expected = tricore_systimer_get_time (priv ) +
188+ TRICORE_SYSTIMER_MIN_DELAY ;
189+ expected = expected < min_expected ? min_expected : expected ;
190+ tricore_systimer_set_timecmp (priv , expected );
191+
192+ up_irq_restore (flags );
180193}
181194
182195/****************************************************************************
@@ -192,44 +205,18 @@ static int tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
192205 * lower Caller allocated instance of the oneshot state structure. This
193206 * structure must have been previously initialized via a call to
194207 * oneshot_initialize();
195- * ts The location in which to return the time remaining on the
196- * oneshot timer. A time of zero is returned if the timer is
197- * not running.
198208 *
199209 * Returned Value:
200- * Zero (OK) is returned on success. A call to up_timer_cancel() when
201- * the timer is not active should also return success; a negated errno
202- * value is returned on any failure.
210+ * None.
203211 *
204212 ****************************************************************************/
205213
206- static int tricore_systimer_cancel (struct oneshot_lowerhalf_s * lower ,
207- struct timespec * ts )
214+ static void tricore_systimer_cancel (struct oneshot_lowerhalf_s * lower )
208215{
209216 struct tricore_systimer_lowerhalf_s * priv =
210217 (struct tricore_systimer_lowerhalf_s * )lower ;
211- uint64_t mtime ;
212218
213219 tricore_systimer_set_timecmp (priv , UINT64_MAX );
214-
215- mtime = tricore_systimer_get_time (priv );
216- if (priv -> alarm > mtime )
217- {
218- uint64_t nsec = (priv -> alarm - mtime ) *
219- NSEC_PER_SEC / priv -> freq ;
220-
221- ts -> tv_sec = nsec / NSEC_PER_SEC ;
222- ts -> tv_nsec = nsec % NSEC_PER_SEC ;
223- }
224- else
225- {
226- ts -> tv_sec = 0 ;
227- ts -> tv_nsec = 0 ;
228- }
229-
230- priv -> alarm = 0 ;
231-
232- return 0 ;
233220}
234221
235222/****************************************************************************
@@ -242,27 +229,18 @@ static int tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower,
242229 * lower Caller allocated instance of the oneshot state structure. This
243230 * structure must have been previously initialized via a call to
244231 * oneshot_initialize();
245- * ts The location in which to return the current time. A time of zero
246- * is returned for the initialization moment.
247232 *
248233 * Returned Value:
249- * Zero (OK) is returned on success, a negated errno value is returned on
250- * any failure.
234+ * Current timer count.
251235 *
252236 ****************************************************************************/
253237
254- static int tricore_systimer_current (struct oneshot_lowerhalf_s * lower ,
255- struct timespec * ts )
238+ static clkcnt_t tricore_systimer_current (struct oneshot_lowerhalf_s * lower )
256239{
257240 struct tricore_systimer_lowerhalf_s * priv =
258241 (struct tricore_systimer_lowerhalf_s * )lower ;
259- uint64_t mtime = tricore_systimer_get_time (priv );
260- uint64_t nsec = mtime / (priv -> freq / USEC_PER_SEC ) * NSEC_PER_USEC ;
261242
262- ts -> tv_sec = nsec / NSEC_PER_SEC ;
263- ts -> tv_nsec = nsec % NSEC_PER_SEC ;
264-
265- return 0 ;
243+ return tricore_systimer_get_time (priv );
266244}
267245
268246/****************************************************************************
@@ -278,12 +256,31 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
278256{
279257 struct tricore_systimer_lowerhalf_s * priv = arg ;
280258
281- tricore_systimer_set_timecmp (priv , UINT64_MAX );
259+ /* We do not need to clear the compare register here. */
260+
282261 oneshot_process_callback (& priv -> lower );
283262
284263 return 0 ;
285264}
286265
266+ /****************************************************************************
267+ * Private Data
268+ ****************************************************************************/
269+
270+ static const struct oneshot_operations_s g_tricore_oneshot_ops =
271+ {
272+ .current = tricore_systimer_current ,
273+ .start = tricore_systimer_start ,
274+ .start_absolute = tricore_systimer_start_absolute ,
275+ .cancel = tricore_systimer_cancel ,
276+ .max_delay = tricore_systimer_max_delay
277+ };
278+
279+ static struct tricore_systimer_lowerhalf_s g_tricore_oneshot_lowerhalf =
280+ {
281+ .lower .ops = & g_tricore_oneshot_ops
282+ };
283+
287284/****************************************************************************
288285 * Public Functions
289286 ****************************************************************************/
@@ -300,11 +297,13 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
300297struct oneshot_lowerhalf_s *
301298tricore_systimer_initialize (volatile void * tbase , int irq , uint64_t freq )
302299{
303- struct tricore_systimer_lowerhalf_s * priv = & g_systimer_lower ;
300+ struct tricore_systimer_lowerhalf_s * priv = & g_tricore_oneshot_lowerhalf ;
304301
305302 priv -> tbase = tbase ;
306- priv -> freq = freq ;
307- spin_lock_init (& priv -> lock );
303+
304+ ASSERT (freq <= UINT32_MAX );
305+
306+ oneshot_count_init (& priv -> lower , (uint32_t )freq );
308307
309308 IfxStm_setCompareControl (tbase ,
310309 IfxStm_Comparator_0 ,
0 commit comments