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