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 8 #ifndef MOD_CLOCK_H 9 #define MOD_CLOCK_H 10 11 #include <fwk_element.h> 12 #include <fwk_id.h> 13 #include <fwk_module_idx.h> 14 15 #include <stdint.h> 16 17 /*! 18 * \addtogroup GroupModules Modules 19 * \{ 20 */ 21 22 /*! 23 * \defgroup GroupClock Clock HAL 24 * 25 * \details A Hardware Abstraction Layer for configuring clock devices. 26 * 27 * \{ 28 */ 29 30 /*! 31 * \brief Clock states. 32 */ 33 enum mod_clock_state { 34 /*! The clock is stopped */ 35 MOD_CLOCK_STATE_STOPPED = 0, 36 37 /*! The clock is running */ 38 MOD_CLOCK_STATE_RUNNING, 39 40 /*! Number of defined clock states */ 41 MOD_CLOCK_STATE_COUNT 42 }; 43 44 /*! 45 * \brief Clock notification indices. 46 */ 47 enum mod_clock_notification_idx { 48 /*! The running state of a clock changed */ 49 MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED, 50 51 /*! The running state of a clock is about to change */ 52 MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING, 53 54 /*! Number of defined notifications */ 55 MOD_CLOCK_NOTIFICATION_IDX_COUNT 56 }; 57 58 #ifdef BUILD_HAS_MOD_CLOCK 59 /*! 60 * \brief Identifier for the ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED 61 * notification. 62 */ 63 static const fwk_id_t mod_clock_notification_id_state_changed = 64 FWK_ID_NOTIFICATION_INIT( 65 FWK_MODULE_IDX_CLOCK, 66 MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED); 67 68 /*! 69 * \brief Identifier for the ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING 70 * notification 71 */ 72 static const fwk_id_t mod_clock_notification_id_state_change_pending = 73 FWK_ID_NOTIFICATION_INIT( 74 FWK_MODULE_IDX_CLOCK, 75 MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING); 76 #endif 77 78 /*! 79 * \brief Event parameters shared by the 80 * ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGED and 81 * ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notifications. 82 */ 83 struct clock_notification_params { 84 /*! 85 * The state that the clock has transitioned to, or is about 86 * to transition to. 87 */ 88 enum mod_clock_state new_state; 89 }; 90 91 /*! 92 * \brief Response parameters for the 93 * ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notification. 94 */ 95 struct clock_state_change_pending_resp_params { 96 /*! 97 * The status returned by the notified subscriber on processing the 98 * ::MOD_CLOCK_NOTIFICATION_IDX_STATE_CHANGE_PENDING notification. 99 */ 100 int status; 101 }; 102 103 /*! 104 * \brief APIs that the module makes available to entities requesting binding. 105 */ 106 enum mod_clock_api_type { 107 /*! Clock HAL */ 108 MOD_CLOCK_API_TYPE_HAL, 109 110 /*! Clock driver response */ 111 MOD_CLOCK_API_TYPE_DRIVER_RESPONSE, 112 113 /*! Number of defined APIs */ 114 MOD_CLOCK_API_COUNT, 115 }; 116 117 /*! 118 * \brief Clock rate types. 119 */ 120 enum mod_clock_rate_type { 121 /*! The clock has a discrete set of rates that it can attain */ 122 MOD_CLOCK_RATE_TYPE_DISCRETE, 123 124 /*! The clock has a continuous range of rates with a constant step */ 125 MOD_CLOCK_RATE_TYPE_CONTINUOUS, 126 }; 127 128 /*! 129 * \brief Clock rounding modes. 130 */ 131 enum mod_clock_round_mode { 132 /*! 133 * Do not perform any rounding. Any rate that is not precise and attainable 134 * will be rejected. 135 */ 136 MOD_CLOCK_ROUND_MODE_NONE, 137 138 /*! Round to the closest attainable rate, whether higher or lower */ 139 MOD_CLOCK_ROUND_MODE_NEAREST, 140 141 /*! Round to the closest attainable higher rate */ 142 MOD_CLOCK_ROUND_MODE_UP, 143 144 /*! Round to the closest attainable lower rate */ 145 MOD_CLOCK_ROUND_MODE_DOWN, 146 }; 147 148 /*! 149 * \brief Clock module configuration data. 150 */ 151 struct mod_clock_config { 152 /*! 153 * \brief Identifier of a notification to subscribe clock devices to in 154 * order to receive notifications of power domain transitions that have 155 * already occurred. 156 * 157 * \note May be ::FWK_ID_NONE to disable this functionality for all 158 * elements. 159 */ 160 const fwk_id_t pd_transition_notification_id; 161 162 /*! 163 * \brief Identifier of a notification to subscribe clock devices to in 164 * order to receive notifications of power domain transitions that are 165 * about to occur. 166 * 167 * \note May be ::FWK_ID_NONE to disable this functionality for all 168 * elements. 169 */ 170 const fwk_id_t pd_pre_transition_notification_id; 171 }; 172 173 /*! 174 * \brief Clock element configuration data. 175 */ 176 struct mod_clock_dev_config { 177 /*! Reference to the device element within the associated driver module */ 178 const fwk_id_t driver_id; 179 180 /*! Reference to the API provided by the device driver module */ 181 const fwk_id_t api_id; 182 183 /*! 184 * \brief Reference to the element or module that is the source of the 185 * power domain notification. 186 * 187 * \details If the clock belongs to the always-on (AON) power domain (i.e. 188 * it is always running), or if there are no actions to be performed 189 * when the clock's power domain changes state, then this identifier 190 * must be FWK_ID_NONE. In this case the clock will not be registered 191 * to receive notifications from the power domain module. 192 */ 193 fwk_id_t pd_source_id; 194 195 /*! 196 * \brief Assigned clock parent optional identifier. 197 * 198 * \details If the clock parent is not defined, it will not be connected 199 * to the tree of clocks and it will be left as a single node. 200 */ 201 fwk_optional_id_t parent_id; 202 203 /*! 204 * Flag to allow clock to be set to initial rate during initialization. 205 */ 206 bool default_on; 207 }; 208 209 /*! 210 * \brief Range of supported rates for a clock. 211 */ 212 struct mod_clock_range { 213 /*! The type of rates the clock provides (discrete or continuous) */ 214 enum mod_clock_rate_type rate_type; 215 216 /*! Minimum rate (in Hz) */ 217 uint64_t min; 218 219 /*! Maximum rate (in Hz) */ 220 uint64_t max; 221 222 /*! 223 * \brief Number of Hertz by which the rate can be incremented at each step 224 * throughout the clock's range. 225 * 226 * \warning Valid only when rate_type is equal to 227 * ::MOD_CLOCK_RATE_TYPE_CONTINUOUS, as clocks that use 228 * ::MOD_CLOCK_RATE_TYPE_DISCRETE may not have a regular step between 229 * their rates. 230 */ 231 uint64_t step; 232 233 /*! The number of unique rates that the clock can attain */ 234 uint64_t rate_count; 235 }; 236 237 /*! 238 * \brief Clock properties exposed via the get_info() API function. 239 * 240 * \details This structure is intended to store clock information that is static 241 * and which does not change during runtime. Dynamic information, such as 242 * the current clock state, are exposed through functions in the clock and 243 * clock driver APIs. 244 */ 245 struct mod_clock_info { 246 /*! Human-friendly clock name */ 247 const char *name; 248 249 /*! Range of supported clock rates */ 250 struct mod_clock_range range; 251 252 /*! Number of discrete rates supported */ 253 uint64_t rate_count; 254 }; 255 256 /*! 257 * \brief Clock driver interface. 258 */ 259 struct mod_clock_drv_api { 260 /*! Name of the driver */ 261 const char *name; 262 263 /*! 264 * \brief Set a new clock rate by providing a frequency in Hertz (Hz). 265 * 266 * \param clock_id Clock device identifier. 267 * 268 * \param rate The desired frequency in Hertz. 269 * 270 * \param round_mode The type of rounding to perform, if required, to 271 * achieve the given rate. 272 * 273 * \retval ::FWK_PENDING The request is pending. The driver will provide the 274 * requested value later through the driver response API. 275 * \retval ::FWK_SUCCESS The operation succeeded. 276 * \return One of the standard framework error codes. 277 */ 278 int (*set_rate)(fwk_id_t clock_id, uint64_t rate, 279 enum mod_clock_round_mode round_mode); 280 281 /*! 282 * \brief Get the current rate of a clock in Hertz (Hz). 283 * 284 * \param clock_id Clock device identifier. 285 * 286 * \param[out] rate The current clock rate in Hertz. 287 * 288 * \retval ::FWK_PENDING The request is pending. The driver will provide the 289 * requested value later through the driver response API. 290 * \retval ::FWK_SUCCESS The operation succeeded. 291 * \return One of the standard framework error codes. 292 */ 293 int (*get_rate)(fwk_id_t clock_id, uint64_t *rate); 294 295 /*! 296 * \brief Get a clock rate in Hertz from an index into the clock's range. 297 * 298 * \param clock_id Clock device identifier. 299 * 300 * \param rate_index The index into the clock's range to get the rate of. 301 * 302 * \param[out] rate The rate, in Hertz, corresponding to the index. 303 * 304 * \retval ::FWK_SUCCESS The operation succeeded. 305 * \return One of the standard framework error codes. 306 */ 307 int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index, 308 uint64_t *rate); 309 310 /*! 311 * \brief Set the running state of a clock. 312 * 313 * \param clock_id Clock device identifier. 314 * 315 * \param state One of the valid clock states. 316 * 317 * \retval ::FWK_PENDING The request is pending. The driver will provide the 318 * requested value later through the driver response API. 319 * \retval ::FWK_SUCCESS The operation succeeded. 320 * \return One of the standard framework error codes. 321 */ 322 int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state); 323 324 /*! 325 * \brief Get the running state of a clock. 326 * 327 * \param clock_id Clock device identifier. 328 * 329 * \param[out] state The current clock state. 330 * 331 * \retval ::FWK_PENDING The request is pending. The driver will provide the 332 * requested value later through the driver response API. 333 * \retval ::FWK_SUCCESS The operation succeeded. 334 * \return One of the standard framework error codes. 335 */ 336 int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state); 337 338 /*! 339 * \brief Get the range of rates that the clock supports. 340 * 341 * \param clock_id Clock device identifier. 342 * 343 * \param[out] range The clock range structure. 344 * 345 * \retval ::FWK_SUCCESS The operation succeeded. 346 * \return One of the standard framework error codes. 347 */ 348 int (*get_range)(fwk_id_t clock_id, struct mod_clock_range *range); 349 350 /*! 351 * \brief Handle the condition where the state of a clock's power domain is 352 * about to change. 353 * 354 * \details This function will be called prior to the change in power 355 * state occurring so that the clock driver implementing this API is 356 * able to perform any required preparatory work beforehand. 357 * 358 * \note This function is optional. If the driver does not control any 359 * clocks that require power state awareness then the pointer may be set 360 * to NULL. 361 * 362 * \param clock_id Clock device identifier. 363 * 364 * \param current_state The current power state that the clock's power 365 * domain will transition away from. 366 * 367 * \param new_state The power state that the clock's power domain will 368 * transition to. 369 * 370 * \retval ::FWK_SUCCESS The operation succeeded. 371 * \return One of the standard framework error codes. 372 */ 373 int (*process_pending_power_transition)( 374 fwk_id_t clock_id, 375 unsigned int current_state, 376 unsigned int new_state); 377 378 /*! 379 * \brief Handle the condition where the state of a clock's power domain 380 * has changed. 381 * 382 * \details This function will be called after the change in power state 383 * has occurred. The driver can take any appropriate actions that are 384 * required to accommodate the new state. The transition can be to a 385 * deeper power state (e.g. ON->OFF) or to a shallower power state 386 * (e.g. OFF->ON). 387 * 388 * \note This function is optional. If the driver does not control any 389 * clocks that require power state awareness then the pointer may be set 390 * to NULL. 391 * 392 * \param clock_id Clock device identifier. 393 * 394 * \param state The power state that the clock's power domain transitioned 395 * to. 396 * 397 * \retval ::FWK_SUCCESS The operation succeeded. 398 * \return One of the standard framework error codes. 399 */ 400 int (*process_power_transition)(fwk_id_t clock_id, unsigned int state); 401 402 /*! 403 * \brief Update the output rate according to the specified input 404 * value. It is just to keep track of the current input/output. It 405 * should not be used to change any setting. 406 * 407 * \note This function is optional. If it is not needed, the pointer may be 408 * set to NULL. This function must be synchronous and every status 409 * return different from FWK_SUCCESS will be handle as an error. 410 * 411 * Behaviour example: 412 * In -> 300MHz 413 * Out <- 150MHz - /2 divider. 414 * 415 * New input: 416 * In -> 600MHz 417 * Out <- 300MHz (result) Preserve /2 divider. 418 * 419 * \param clock_id Clock device identifier. 420 * 421 * \param in_rate Desired input parent rate in Hertz. 422 * 423 * \param[out] out_rate The current clock rate in Hertz. 424 * 425 * \retval ::FWK_SUCCESS The operation succeeded. 426 * \return One of the standard framework error codes. 427 */ 428 int (*update_input_rate)( 429 fwk_id_t clock_id, 430 uint64_t in_rate, 431 uint64_t *out_rate); 432 }; 433 434 /*! 435 * \brief Clock interface. 436 */ 437 struct mod_clock_api { 438 /*! 439 * \brief Set a new clock rate by providing a frequency in Hertz (Hz). 440 * 441 * \param clock_id Clock device identifier. 442 * 443 * \param rate The desired frequency in Hertz. 444 * 445 * \param round_mode The type of rounding to perform, if required, to 446 * achieve the given rate. 447 * 448 * \retval ::FWK_SUCCESS The operation succeeded. 449 * \retval ::FWK_PENDING The request is pending. The result for this 450 * operation will be provided via a response event. 451 * \retval ::FWK_E_PARAM The clock identifier was invalid. 452 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 453 * supported. 454 * \return One of the standard framework error codes. 455 */ 456 int (*set_rate)(fwk_id_t clock_id, uint64_t rate, 457 enum mod_clock_round_mode round_mode); 458 459 /*! 460 * \brief Get the current rate of a clock in Hertz (Hz). 461 * 462 * \param clock_id Clock device identifier. 463 * 464 * \param[out] rate The current clock rate in Hertz. 465 * 466 * \retval ::FWK_SUCCESS The operation succeeded. 467 * \retval ::FWK_PENDING The request is pending. The requested rate will be 468 * provided via a response event. 469 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 470 * - The `clock_id` parameter was not a valid system entity identifier. 471 * - The `rate` parameter was a null pointer value. 472 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 473 * supported. 474 * \return One of the standard framework error codes. 475 */ 476 int (*get_rate)(fwk_id_t clock_id, uint64_t *rate); 477 478 /*! 479 * \brief Get a clock rate in Hertz from an index into the clock's range. 480 * 481 * \param clock_id Clock device identifier. 482 * 483 * \param rate_index The index into the clock's range to get the rate of. 484 * 485 * \param[out] rate The rate, in Hertz, corresponding to the index. 486 * 487 * \retval ::FWK_SUCCESS The operation succeeded. 488 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 489 * - The `clock_id` parameter was not a valid system entity identifier. 490 * - The `rate` parameter was a null pointer value. 491 * \return One of the standard framework error codes. 492 */ 493 int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index, 494 uint64_t *rate); 495 496 /*! 497 * \brief Set the running state of a clock. 498 * 499 * \param clock_id Clock device identifier. 500 * 501 * \param state One of the valid clock states. 502 * 503 * \retval ::FWK_SUCCESS The operation succeeded. 504 * \retval ::FWK_PENDING The request is pending. The result for this 505 * operation will be provided via a response event. 506 * \retval ::FWK_E_PARAM The clock identifier was invalid. 507 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 508 * supported. 509 * \return One of the standard framework error codes. 510 */ 511 int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state); 512 513 /*! 514 * \brief Get the running state of a clock. 515 * 516 * \param clock_id Clock device identifier. 517 * 518 * \param[out] state The current clock state. 519 * 520 * \retval ::FWK_SUCCESS The operation succeeded. 521 * \retval ::FWK_PENDING The request is pending. The requested state will be 522 * provided via a response event. 523 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 524 * - The `clock_id` parameter was not a valid system entity identifier. 525 * - The `state` parameter was a null pointer value. 526 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 527 * supported. 528 * \return One of the standard framework error codes. 529 */ 530 int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state); 531 532 /*! 533 * \brief Get information about a clock's fixed properties. 534 * 535 * \param clock_id Clock device identifier. 536 * 537 * \param[out] info The clock device properties. 538 * 539 * \retval ::FWK_SUCCESS The operation succeeded. 540 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 541 * - The `clock_id` parameter was not a valid system entity identifier. 542 * - The `info` parameter was a null pointer value. 543 * \return One of the standard framework error codes. 544 */ 545 int (*get_info)(fwk_id_t clock_id, struct mod_clock_info *info); 546 }; 547 548 /*! 549 * \brief Container for the values returned upon request completion. 550 */ 551 union mod_clock_resp_values { 552 /*! The current clock rate in Hertz */ 553 uint64_t rate; 554 555 /*! The current clock state */ 556 enum mod_clock_state state; 557 }; 558 559 /*! 560 * \brief Driver response parameters. 561 */ 562 struct mod_clock_driver_resp_params { 563 /*! Status of driver operation */ 564 int status; 565 566 /*! Values returned */ 567 union mod_clock_resp_values value; 568 }; 569 570 /*! 571 * \brief Clock driver response API. 572 * 573 * \details API used by the driver when an asynchronous request is completed. 574 * 575 */ 576 struct mod_clock_driver_response_api { 577 /*! 578 * \brief Signal the completion of a driver request. 579 * 580 * \param dev_id Specific clock device identifier. 581 * \param resp_values Pointer to the values requested. 582 */ 583 void (*request_complete)(fwk_id_t dev_id, 584 struct mod_clock_driver_resp_params *resp_values); 585 }; 586 587 /*! 588 * \brief Event response parameters. 589 */ 590 struct mod_clock_resp_params { 591 /*! Status of requested operation */ 592 int status; 593 594 /*! Values returned */ 595 union mod_clock_resp_values value; 596 }; 597 598 /*! 599 * \brief Define the event identifiers for deferred responses. 600 */ 601 enum mod_clock_event_idx { 602 MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST, 603 MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST, 604 605 MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST, 606 MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST, 607 608 MOD_CLOCK_EVENT_IDX_COUNT 609 }; 610 611 #ifdef BUILD_HAS_MOD_CLOCK 612 /*! 613 * \brief Request event identifiers. 614 * 615 * \details These identifiers are used by the clients that expect to receive a 616 * response event from this module when a request is deferred. 617 */ 618 static const fwk_id_t mod_clock_event_id_set_rate_request = 619 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 620 MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST); 621 622 static const fwk_id_t mod_clock_event_id_get_rate_request = 623 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 624 MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST); 625 626 static const fwk_id_t mod_clock_event_id_set_state_request = 627 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 628 MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST); 629 630 static const fwk_id_t mod_clock_event_id_get_state_request = 631 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 632 MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST); 633 #endif 634 635 /*! 636 * \} 637 */ 638 639 /*! 640 * \} 641 */ 642 643 #endif /* MOD_CLOCK_H */ 644