1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Timer HAL
9  */
10 
11 #ifndef MOD_TIMER_H
12 #define MOD_TIMER_H
13 
14 #include <fwk_id.h>
15 #include <fwk_module_idx.h>
16 
17 #include <stdbool.h>
18 #include <stdint.h>
19 
20 /*!
21  * \addtogroup GroupModules Modules
22  * \{
23  */
24 
25 /*!
26  * \defgroup GroupModuleTimer Timer HAL
27  *
28  * \brief Hardware Abstraction Layer for Timers.
29  *
30  * \details Provides functionality for setting timer events, tracking elapsed
31  *      time, and synchronously delaying execution.
32  *
33  * \{
34  */
35 
36 /*!
37  * \brief Timer module API indicies
38  */
39 enum mod_timer_api_idx {
40     /*! Timer API index */
41     MOD_TIMER_API_IDX_TIMER,
42 
43     /*! Alarm API index */
44     MOD_TIMER_API_IDX_ALARM,
45 
46     /*! Number of APIs */
47     MOD_TIMER_API_COUNT,
48 };
49 
50 /*!
51  * \brief Timer API ID
52  */
53 #define MOD_TIMER_API_ID_TIMER FWK_ID_API(FWK_MODULE_IDX_TIMER, \
54                                           MOD_TIMER_API_IDX_TIMER)
55 
56 /*!
57  * \brief Alarm API ID
58  */
59 #define MOD_TIMER_API_ID_ALARM FWK_ID_API(FWK_MODULE_IDX_TIMER, \
60                                           MOD_TIMER_API_IDX_ALARM)
61 
62 /*!
63  * \brief Alarm type.
64  */
65 enum mod_timer_alarm_type {
66     /*! Alarm that will trigger once */
67     MOD_TIMER_ALARM_TYPE_ONCE,
68 
69     /*! Alarm that will trigger at regular intervals */
70     MOD_TIMER_ALARM_TYPE_PERIODIC,
71 
72     /*! Number of alarm types */
73     MOD_TIMER_ALARM_TYPE_COUNT,
74 };
75 
76 /*!
77  * \brief Timer device descriptor
78  */
79 struct mod_timer_dev_config {
80     /*! Element identifier for the device's associated driver */
81     fwk_id_t id;
82 
83     /*! Timer device IRQ number */
84     unsigned int timer_irq;
85 };
86 
87 /*!
88  * \brief Timer driver interface.
89  */
90 struct mod_timer_driver_api {
91     /*! Name of the driver. */
92     const char *name;
93 
94     /*!
95      * Enable timer events
96      * It is expected that the driver enables the timer's interrupt
97      * source (i.e. using the timer's registers) within this function.
98      */
99     int (*enable)(fwk_id_t dev_id);
100 
101     /*!
102      * Disable timer events
103      * It is expected that the driver disables the timer's interrupt
104      * source (i.e.using the timer's registers) within this function.
105      */
106     int (*disable)(fwk_id_t dev_id);
107 
108     /*!
109      * Set timer event for a specified timestamp
110      * The timer HAL clears the interrupt via the framework interrupt interface.
111      * So it is expected from the timer driver to set the timer value only.
112      */
113     int (*set_timer)(fwk_id_t dev_id, uint64_t timestamp);
114 
115     /*! Get remaining time until the next pending timer event is due to fire */
116     int (*get_timer)(fwk_id_t dev_id, uint64_t *timestamp);
117 
118     /*! Get current counter value */
119     int (*get_counter)(fwk_id_t dev_id, uint64_t *value);
120 
121     /*! Get counter frequency */
122     int (*get_frequency)(fwk_id_t dev_id, uint32_t *value);
123 };
124 
125 /*!
126  * \brief Timer HAL interface
127  */
128 struct mod_timer_api {
129     /*!
130      * \brief Get the frequency of a given timer.
131      *
132      * \details Get the frequency in Hertz (Hz) that a timer is running at.
133      *
134      * \param dev_id Element identifier that identifies the timer device.
135      * \param[out] frequency The timer frequency.
136      *
137      * \retval ::FWK_SUCCESS Operation succeeded.
138      * \retval ::FWK_E_PARAM The frequency pointer was invalid.
139      * \retval One of the other specific error codes described by the framework.
140      */
141     int (*get_frequency)(fwk_id_t dev_id, uint32_t *frequency);
142 
143     /*!
144      * \brief Get a counter timestamp that represents a given time period in
145      *      microseconds (µS).
146      *
147      * \note The value of the resulting timestamp is only valid for the given
148      *      device, since other timer devices may operate at different rates.
149      *
150      * \param dev_id Element identifier that identifies the timer device.
151      * \param microseconds Period, in microseconds.
152      * \param[out] timestamp The resulting counter timestamp.
153      *
154      * \retval ::FWK_SUCCESS Operation succeeded.
155      * \retval ::FWK_E_PARAM The timestamp pointer was invalid.
156      * \retval One of the other specific error codes described by the framework.
157      */
158     int (*time_to_timestamp)(fwk_id_t dev_id,
159                              uint32_t microseconds,
160                              uint64_t *timestamp);
161 
162     /*!
163      * \brief Get the current counter value of a given timer.
164      *
165      * \details Directly returns the counter value of the timer at the present
166      *      moment.
167      *
168      * \param dev_id Element identifier that identifies the timer device.
169      * \param[out] counter The counter value.
170      *
171      * \retval ::FWK_SUCCESS Operation succeeded.
172      * \retval ::FWK_E_PARAM The counter pointer was invalid.
173      * \retval One of the other specific error codes described by the framework.
174      */
175     int (*get_counter)(fwk_id_t dev_id, uint64_t *counter);
176 
177     /*!
178      * \brief Delay execution by synchronously waiting for a specified amount
179      *      of time.
180      *
181      * \details Blocks the calling thread for the specified amount of time.
182      *
183      * \param dev_id Element identifier that identifies the timer device.
184      * \param microseconds The amount of time, given in microseconds, to delay.
185      *
186      * \retval ::FWK_SUCCESS Operation succeeded.
187      * \retval One of the other specific error codes described by the framework.
188      */
189     int (*delay)(fwk_id_t dev_id, uint32_t microseconds);
190 
191     /*!
192      * \brief Delay execution, waiting until a given condition is true or until
193      *      a given timeout period has been exceeded, whichever occurs first.
194      *
195      * \note The calling thread is blocked until either condition has been met.
196      *
197      * \param dev_id Element identifier that identifies the timer device.
198      * \param microseconds Maximum amount of time, in microseconds, to wait for
199      *      the given condition to be met.
200      * \param cond Pointer to the function that evaluates the condition and
201      *      which returns a boolean value indicating if it has been met or not.
202      *      The condition function is called repeatedly until it returns true,
203      *      or until the timeout period has elapsed.
204      * \param data Pointer passed to the condition function when it is called.
205      *
206      * \retval ::FWK_SUCCESS The condition was met before the timeout period
207      *      elapsed.
208      * \retval ::FWK_E_TIMEOUT The timeout period elapsed before the condition
209      *      was met.
210      * \retval One of the other specific error codes described by the framework.
211      */
212     int (*wait)(fwk_id_t dev_id,
213                 uint32_t microseconds,
214                 bool (*cond)(void*),
215                 void *data);
216 
217     /*!
218      * \brief Get the time difference, expressed in timer ticks, between the
219      *      current timer counter value and the given timestamp. This represents
220      *      the remaining number of ticks until the given timestamp is reached.
221      *
222      * \note If the given timestamp is in the past then the remaining_ticks is
223      *      set to zero.
224      *
225      * \param dev_id Element identifier that identifies the timer device.
226      * \param timestamp Timestamp to compare to the current timer value.
227      * \param[out] remaining_ticks The remaining number of ticks before
228      *      the timer value reaches the given timestamp.
229      *
230      * \retval ::FWK_SUCCESS Operation succeeded.
231      * \retval ::FWK_E_PARAM The remaining_ticks pointer was invalid.
232      * \retval One of the other specific error codes described by the framework.
233      *
234      * \note remaining_ticks is also a timestamp.
235      */
236     int (*remaining)(fwk_id_t dev_id,
237                      uint64_t timestamp,
238                      uint64_t *remaining_ticks);
239 
240     /*!
241      * \brief Get the number of ticks before the next alarm trigger of a given
242      *      timer.
243      *
244      * \warning If the timer has no active alarm, \p remaining_ticks is not
245      *      initialized.
246      *
247      * \param dev_id Element identifier that identifies the timer device.
248      * \param [out] has_alarm \c true if the timer has an active alarm,
249      *      otherwise \c false.
250      * \param [out] remaining_ticks Number of ticks between now and the next
251      *      alarm trigger of the timer identified by \p dev_id.
252      *
253      * \retval ::FWK_SUCCESS Operation succeeded.
254      * \retval ::FWK_E_PARAM One of the parameters is invalid.
255      * \retval ::FWK_E_DEVICE The timer driver failed.
256      * \return One of the other specific error codes described by the framework.
257      */
258     int (*get_next_alarm_remaining)(fwk_id_t dev_id,
259                                     bool *has_alarm,
260                                     uint64_t *remaining_ticks);
261 };
262 
263 /*!
264  * \brief Alarm interface
265  */
266 struct mod_timer_alarm_api {
267     /*!
268      * \brief Start an alarm so it will trigger after a specified time.
269      *
270      * \details When an alarm is triggered, \p callback is called.
271      *
272      *     If the alarm is periodic, it will automatically be started again
273      *     with the same time delay after it triggers.
274      *
275      *     An alarm can be started multiple times without being stopped. In this
276      *     case, internally, the alarm will be stopped then started again with
277      *     the new configuration.
278      *
279      * \warning \p callback will be called from within an interrupt service
280      *      routine.
281      *
282      * \param alarm_id Sub-element identifier of the alarm.
283      * \param milliseconds The time delay, given in milliseconds, until the
284      *     alarm should trigger.
285      * \param type ::MOD_TIMER_ALARM_TYPE_ONCE or
286      *     ::MOD_TIMER_ALARM_TYPE_PERIODIC.
287      * \param callback Pointer to the callback function.
288      * \param param Parameter given to the callback function when called.
289      *
290      * \pre \p alarm_id must be a valid sub-element alarm identifier that has
291      *     previously been bound to.
292      *
293      * \retval ::FWK_E_ACCESS The function was called from an interrupt handler
294      *      OR could not attain call context.
295      * \retval ::FWK_E_DEVICE The timer driver failed.
296      * \retval ::FWK_SUCCESS The alarm was started.
297      * \return One of the other specific error codes described by the framework.
298      */
299     int (*start)(fwk_id_t alarm_id,
300                  unsigned int milliseconds,
301                  enum mod_timer_alarm_type type,
302                  void (*callback)(uintptr_t param),
303                  uintptr_t param);
304 
305     /*!
306      * \brief Stop a previously started alarm.
307      *
308      * \details Stop an alarm that was previously started. This will prevent the
309      *     alarm from triggering. This does not undo the binding of the alarm
310      *     and it can be started again afterwards.
311      *
312      * \param alarm_id Sub-element identifier of the alarm item.
313      *
314      * \pre \p alarm_id must be a valid sub-element alarm identifier that has
315      *     previously been bound to.
316      *
317      * \retval ::FWK_SUCCESS The alarm was stopped.
318      * \retval ::FWK_E_DEVICE The timer driver failed.
319      * \retval ::FWK_E_STATE The alarm was already stopped.
320      * \retval ::FWK_E_ACCESS The function was called from an interrupt handler
321      *      different from the interrupt handler of the timer the alarm is
322      *      associated to OR could not attain call context.
323      * \retval ::FWK_E_INIT The component has not been initialized.
324      * \return One of the other specific error codes described by the framework.
325      */
326     int (*stop)(fwk_id_t alarm_id);
327 };
328 
329 /*!
330  * \}
331  */
332 
333 /*!
334  * \}
335  */
336 
337 #endif /* MOD_TIMER_H */
338