1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2024, 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      * Timer device may need to update internal status in alarm or overflow
126      * event. This handler is used to process overflow event when there is no
127      * active alarm. Optional
128      */
129     void (*overflow_handler)(fwk_id_t dev_id);
130 };
131 
132 /*!
133  * \brief Timer HAL interface
134  */
135 struct mod_timer_api {
136     /*!
137      * \brief Get the frequency of a given timer.
138      *
139      * \details Get the frequency in Hertz (Hz) that a timer is running at.
140      *
141      * \param dev_id Element identifier that identifies the timer device.
142      * \param[out] frequency The timer frequency.
143      *
144      * \retval ::FWK_SUCCESS Operation succeeded.
145      * \retval ::FWK_E_PARAM The frequency pointer was invalid.
146      * \retval One of the other specific error codes described by the framework.
147      */
148     int (*get_frequency)(fwk_id_t dev_id, uint32_t *frequency);
149 
150     /*!
151      * \brief Get a counter timestamp that represents a given time period in
152      *      microseconds (µS).
153      *
154      * \note The value of the resulting timestamp is only valid for the given
155      *      device, since other timer devices may operate at different rates.
156      *
157      * \param dev_id Element identifier that identifies the timer device.
158      * \param microseconds Period, in microseconds.
159      * \param[out] timestamp The resulting counter timestamp.
160      *
161      * \retval ::FWK_SUCCESS Operation succeeded.
162      * \retval ::FWK_E_PARAM The timestamp pointer was invalid.
163      * \retval One of the other specific error codes described by the framework.
164      */
165     int (*time_to_timestamp)(fwk_id_t dev_id,
166                              uint32_t microseconds,
167                              uint64_t *timestamp);
168 
169     /*!
170      * \brief Get the current counter value of a given timer.
171      *
172      * \details Directly returns the counter value of the timer at the present
173      *      moment.
174      *
175      * \param dev_id Element identifier that identifies the timer device.
176      * \param[out] counter The counter value.
177      *
178      * \retval ::FWK_SUCCESS Operation succeeded.
179      * \retval ::FWK_E_PARAM The counter pointer was invalid.
180      * \retval One of the other specific error codes described by the framework.
181      */
182     int (*get_counter)(fwk_id_t dev_id, uint64_t *counter);
183 
184     /*!
185      * \brief Delay execution by synchronously waiting for a specified amount
186      *      of time.
187      *
188      * \details Blocks the calling thread for the specified amount of time.
189      *
190      * \param dev_id Element identifier that identifies the timer device.
191      * \param microseconds The amount of time, given in microseconds, to delay.
192      *
193      * \retval ::FWK_SUCCESS Operation succeeded.
194      * \retval One of the other specific error codes described by the framework.
195      */
196     int (*delay)(fwk_id_t dev_id, uint32_t microseconds);
197 
198     /*!
199      * \brief Delay execution, waiting until a given condition is true or until
200      *      a given timeout period has been exceeded, whichever occurs first.
201      *
202      * \note The calling thread is blocked until either condition has been met.
203      *
204      * \param dev_id Element identifier that identifies the timer device.
205      * \param microseconds Maximum amount of time, in microseconds, to wait for
206      *      the given condition to be met.
207      * \param cond Pointer to the function that evaluates the condition and
208      *      which returns a boolean value indicating if it has been met or not.
209      *      The condition function is called repeatedly until it returns true,
210      *      or until the timeout period has elapsed.
211      * \param data Pointer passed to the condition function when it is called.
212      *
213      * \retval ::FWK_SUCCESS The condition was met before the timeout period
214      *      elapsed.
215      * \retval ::FWK_E_TIMEOUT The timeout period elapsed before the condition
216      *      was met.
217      * \retval One of the other specific error codes described by the framework.
218      */
219     int (*wait)(fwk_id_t dev_id,
220                 uint32_t microseconds,
221                 bool (*cond)(void*),
222                 void *data);
223 
224     /*!
225      * \brief Get the time difference, expressed in timer ticks, between the
226      *      current timer counter value and the given timestamp. This represents
227      *      the remaining number of ticks until the given timestamp is reached.
228      *
229      * \note If the given timestamp is in the past then the remaining_ticks is
230      *      set to zero.
231      *
232      * \param dev_id Element identifier that identifies the timer device.
233      * \param timestamp Timestamp to compare to the current timer value.
234      * \param[out] remaining_ticks The remaining number of ticks before
235      *      the timer value reaches the given timestamp.
236      *
237      * \retval ::FWK_SUCCESS Operation succeeded.
238      * \retval ::FWK_E_PARAM The remaining_ticks pointer was invalid.
239      * \retval One of the other specific error codes described by the framework.
240      *
241      * \note remaining_ticks is also a timestamp.
242      */
243     int (*remaining)(fwk_id_t dev_id,
244                      uint64_t timestamp,
245                      uint64_t *remaining_ticks);
246 
247     /*!
248      * \brief Get the number of ticks before the next alarm trigger of a given
249      *      timer.
250      *
251      * \warning If the timer has no active alarm, \p remaining_ticks is not
252      *      initialized.
253      *
254      * \param dev_id Element identifier that identifies the timer device.
255      * \param [out] has_alarm \c true if the timer has an active alarm,
256      *      otherwise \c false.
257      * \param [out] remaining_ticks Number of ticks between now and the next
258      *      alarm trigger of the timer identified by \p dev_id.
259      *
260      * \retval ::FWK_SUCCESS Operation succeeded.
261      * \retval ::FWK_E_PARAM One of the parameters is invalid.
262      * \retval ::FWK_E_DEVICE The timer driver failed.
263      * \return One of the other specific error codes described by the framework.
264      */
265     int (*get_next_alarm_remaining)(fwk_id_t dev_id,
266                                     bool *has_alarm,
267                                     uint64_t *remaining_ticks);
268 };
269 
270 /*!
271  * \brief Alarm interface
272  */
273 struct mod_timer_alarm_api {
274     /*!
275      * \brief Start an alarm so it will trigger after a specified time.
276      *
277      * \details When an alarm is triggered, \p callback is called.
278      *
279      *     If the alarm is periodic, it will automatically be started again
280      *     with the same time delay after it triggers.
281      *
282      *     An alarm can be started multiple times without being stopped. In this
283      *     case, internally, the alarm will be stopped then started again with
284      *     the new configuration.
285      *
286      * \warning \p callback will be called from within an interrupt service
287      *      routine.
288      *
289      * \param alarm_id Sub-element identifier of the alarm.
290      * \param milliseconds The time delay, given in milliseconds, until the
291      *     alarm should trigger.
292      * \param type ::MOD_TIMER_ALARM_TYPE_ONCE or
293      *     ::MOD_TIMER_ALARM_TYPE_PERIODIC.
294      * \param callback Pointer to the callback function.
295      * \param param Parameter given to the callback function when called.
296      *
297      * \pre \p alarm_id must be a valid sub-element alarm identifier that has
298      *     previously been bound to.
299      *
300      * \retval ::FWK_E_ACCESS The function was called from an interrupt handler
301      *      OR could not attain call context.
302      * \retval ::FWK_E_DEVICE The timer driver failed.
303      * \retval ::FWK_SUCCESS The alarm was started.
304      * \return One of the other specific error codes described by the framework.
305      */
306     int (*start)(fwk_id_t alarm_id,
307                  unsigned int milliseconds,
308                  enum mod_timer_alarm_type type,
309                  void (*callback)(uintptr_t param),
310                  uintptr_t param);
311 
312     /*!
313      * \brief Stop a previously started alarm.
314      *
315      * \details Stop an alarm that was previously started. This will prevent the
316      *     alarm from triggering. This does not undo the binding of the alarm
317      *     and it can be started again afterwards.
318      *
319      * \param alarm_id Sub-element identifier of the alarm item.
320      *
321      * \pre \p alarm_id must be a valid sub-element alarm identifier that has
322      *     previously been bound to.
323      *
324      * \retval ::FWK_SUCCESS The alarm was stopped.
325      * \retval ::FWK_E_DEVICE The timer driver failed.
326      * \retval ::FWK_E_STATE The alarm was already stopped.
327      * \retval ::FWK_E_ACCESS The function was called from an interrupt handler
328      *      different from the interrupt handler of the timer the alarm is
329      *      associated to OR could not attain call context.
330      * \retval ::FWK_E_INIT The component has not been initialized.
331      * \return One of the other specific error codes described by the framework.
332      */
333     int (*stop)(fwk_id_t alarm_id);
334 };
335 
336 /*!
337  * \}
338  */
339 
340 /*!
341  * \}
342  */
343 
344 #endif /* MOD_TIMER_H */
345