1 /* 2 * Arm SCP/MCP Software 3 * Copyright (c) 2017-2021, 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 /*! 205 * \brief Range of supported rates for a clock. 206 */ 207 struct mod_clock_range { 208 /*! The type of rates the clock provides (discrete or continuous) */ 209 enum mod_clock_rate_type rate_type; 210 211 /*! Minimum rate (in Hz) */ 212 uint64_t min; 213 214 /*! Maximum rate (in Hz) */ 215 uint64_t max; 216 217 /*! 218 * \brief Number of Hertz by which the rate can be incremented at each step 219 * throughout the clock's range. 220 * 221 * \warning Valid only when rate_type is equal to 222 * ::MOD_CLOCK_RATE_TYPE_CONTINUOUS, as clocks that use 223 * ::MOD_CLOCK_RATE_TYPE_DISCRETE may not have a regular step between 224 * their rates. 225 */ 226 uint64_t step; 227 228 /*! The number of unique rates that the clock can attain */ 229 uint64_t rate_count; 230 }; 231 232 /*! 233 * \brief Clock properties exposed via the get_info() API function. 234 * 235 * \details This structure is intended to store clock information that is static 236 * and which does not change during runtime. Dynamic information, such as 237 * the current clock state, are exposed through functions in the clock and 238 * clock driver APIs. 239 */ 240 struct mod_clock_info { 241 /*! Human-friendly clock name */ 242 const char *name; 243 244 /*! Range of supported clock rates */ 245 struct mod_clock_range range; 246 247 /*! Number of discrete rates supported */ 248 uint64_t rate_count; 249 }; 250 251 /*! 252 * \brief Clock driver interface. 253 */ 254 struct mod_clock_drv_api { 255 /*! Name of the driver */ 256 const char *name; 257 258 /*! 259 * \brief Set a new clock rate by providing a frequency in Hertz (Hz). 260 * 261 * \param clock_id Clock device identifier. 262 * 263 * \param rate The desired frequency in Hertz. 264 * 265 * \param round_mode The type of rounding to perform, if required, to 266 * achieve the given rate. 267 * 268 * \retval ::FWK_PENDING The request is pending. The driver will provide the 269 * requested value later through the driver response API. 270 * \retval ::FWK_SUCCESS The operation succeeded. 271 * \return One of the standard framework error codes. 272 */ 273 int (*set_rate)(fwk_id_t clock_id, uint64_t rate, 274 enum mod_clock_round_mode round_mode); 275 276 /*! 277 * \brief Get the current rate of a clock in Hertz (Hz). 278 * 279 * \param clock_id Clock device identifier. 280 * 281 * \param[out] rate The current clock rate in Hertz. 282 * 283 * \retval ::FWK_PENDING The request is pending. The driver will provide the 284 * requested value later through the driver response API. 285 * \retval ::FWK_SUCCESS The operation succeeded. 286 * \return One of the standard framework error codes. 287 */ 288 int (*get_rate)(fwk_id_t clock_id, uint64_t *rate); 289 290 /*! 291 * \brief Get a clock rate in Hertz from an index into the clock's range. 292 * 293 * \param clock_id Clock device identifier. 294 * 295 * \param rate_index The index into the clock's range to get the rate of. 296 * 297 * \param[out] rate The rate, in Hertz, corresponding to the index. 298 * 299 * \retval ::FWK_SUCCESS The operation succeeded. 300 * \return One of the standard framework error codes. 301 */ 302 int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index, 303 uint64_t *rate); 304 305 /*! 306 * \brief Set the running state of a clock. 307 * 308 * \param clock_id Clock device identifier. 309 * 310 * \param state One of the valid clock states. 311 * 312 * \retval ::FWK_PENDING The request is pending. The driver will provide the 313 * requested value later through the driver response API. 314 * \retval ::FWK_SUCCESS The operation succeeded. 315 * \return One of the standard framework error codes. 316 */ 317 int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state); 318 319 /*! 320 * \brief Get the running state of a clock. 321 * 322 * \param clock_id Clock device identifier. 323 * 324 * \param[out] state The current clock state. 325 * 326 * \retval ::FWK_PENDING The request is pending. The driver will provide the 327 * requested value later through the driver response API. 328 * \retval ::FWK_SUCCESS The operation succeeded. 329 * \return One of the standard framework error codes. 330 */ 331 int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state); 332 333 /*! 334 * \brief Get the range of rates that the clock supports. 335 * 336 * \param clock_id Clock device identifier. 337 * 338 * \param[out] range The clock range structure. 339 * 340 * \retval ::FWK_SUCCESS The operation succeeded. 341 * \return One of the standard framework error codes. 342 */ 343 int (*get_range)(fwk_id_t clock_id, struct mod_clock_range *range); 344 345 /*! 346 * \brief Handle the condition where the state of a clock's power domain is 347 * about to change. 348 * 349 * \details This function will be called prior to the change in power 350 * state occurring so that the clock driver implementing this API is 351 * able to perform any required preparatory work beforehand. 352 * 353 * \note This function is optional. If the driver does not control any 354 * clocks that require power state awareness then the pointer may be set 355 * to NULL. 356 * 357 * \param clock_id Clock device identifier. 358 * 359 * \param current_state The current power state that the clock's power 360 * domain will transition away from. 361 * 362 * \param new_state The power state that the clock's power domain will 363 * transition to. 364 * 365 * \retval ::FWK_SUCCESS The operation succeeded. 366 * \return One of the standard framework error codes. 367 */ 368 int (*process_pending_power_transition)( 369 fwk_id_t clock_id, 370 unsigned int current_state, 371 unsigned int new_state); 372 373 /*! 374 * \brief Handle the condition where the state of a clock's power domain 375 * has changed. 376 * 377 * \details This function will be called after the change in power state 378 * has occurred. The driver can take any appropriate actions that are 379 * required to accommodate the new state. The transition can be to a 380 * deeper power state (e.g. ON->OFF) or to a shallower power state 381 * (e.g. OFF->ON). 382 * 383 * \note This function is optional. If the driver does not control any 384 * clocks that require power state awareness then the pointer may be set 385 * to NULL. 386 * 387 * \param clock_id Clock device identifier. 388 * 389 * \param state The power state that the clock's power domain transitioned 390 * to. 391 * 392 * \retval ::FWK_SUCCESS The operation succeeded. 393 * \return One of the standard framework error codes. 394 */ 395 int (*process_power_transition)(fwk_id_t clock_id, unsigned int state); 396 397 /*! 398 * \brief Update the output rate according to the specified input 399 * value. It is just to keep track of the current input/output. It 400 * should not be used to change any setting. 401 * 402 * \note This function is optional. If it is not needed, the pointer may be 403 * set to NULL. This function must be synchronous and every status 404 * return different from FWK_SUCCESS will be handle as an error. 405 * 406 * Behaviour example: 407 * In -> 300MHz 408 * Out <- 150MHz - /2 divider. 409 * 410 * New input: 411 * In -> 600MHz 412 * Out <- 300MHz (result) Preserve /2 divider. 413 * 414 * \param clock_id Clock device identifier. 415 * 416 * \param in_rate Desired input parent rate in Hertz. 417 * 418 * \param[out] out_rate The current clock rate in Hertz. 419 * 420 * \retval ::FWK_SUCCESS The operation succeeded. 421 * \return One of the standard framework error codes. 422 */ 423 int (*update_input_rate)( 424 fwk_id_t clock_id, 425 uint64_t in_rate, 426 uint64_t *out_rate); 427 }; 428 429 /*! 430 * \brief Clock interface. 431 */ 432 struct mod_clock_api { 433 /*! 434 * \brief Set a new clock rate by providing a frequency in Hertz (Hz). 435 * 436 * \param clock_id Clock device identifier. 437 * 438 * \param rate The desired frequency in Hertz. 439 * 440 * \param round_mode The type of rounding to perform, if required, to 441 * achieve the given rate. 442 * 443 * \retval ::FWK_SUCCESS The operation succeeded. 444 * \retval ::FWK_PENDING The request is pending. The result for this 445 * operation will be provided via a response event. 446 * \retval ::FWK_E_PARAM The clock identifier was invalid. 447 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 448 * supported. 449 * \return One of the standard framework error codes. 450 */ 451 int (*set_rate)(fwk_id_t clock_id, uint64_t rate, 452 enum mod_clock_round_mode round_mode); 453 454 /*! 455 * \brief Get the current rate of a clock in Hertz (Hz). 456 * 457 * \param clock_id Clock device identifier. 458 * 459 * \param[out] rate The current clock rate in Hertz. 460 * 461 * \retval ::FWK_SUCCESS The operation succeeded. 462 * \retval ::FWK_PENDING The request is pending. The requested rate will be 463 * provided via a response event. 464 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 465 * - The `clock_id` parameter was not a valid system entity identifier. 466 * - The `rate` parameter was a null pointer value. 467 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 468 * supported. 469 * \return One of the standard framework error codes. 470 */ 471 int (*get_rate)(fwk_id_t clock_id, uint64_t *rate); 472 473 /*! 474 * \brief Get a clock rate in Hertz from an index into the clock's range. 475 * 476 * \param clock_id Clock device identifier. 477 * 478 * \param rate_index The index into the clock's range to get the rate of. 479 * 480 * \param[out] rate The rate, in Hertz, corresponding to the index. 481 * 482 * \retval ::FWK_SUCCESS The operation succeeded. 483 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 484 * - The `clock_id` parameter was not a valid system entity identifier. 485 * - The `rate` parameter was a null pointer value. 486 * \return One of the standard framework error codes. 487 */ 488 int (*get_rate_from_index)(fwk_id_t clock_id, unsigned int rate_index, 489 uint64_t *rate); 490 491 /*! 492 * \brief Set the running state of a clock. 493 * 494 * \param clock_id Clock device identifier. 495 * 496 * \param state One of the valid clock states. 497 * 498 * \retval ::FWK_SUCCESS The operation succeeded. 499 * \retval ::FWK_PENDING The request is pending. The result for this 500 * operation will be provided via a response event. 501 * \retval ::FWK_E_PARAM The clock identifier was invalid. 502 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 503 * supported. 504 * \return One of the standard framework error codes. 505 */ 506 int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state); 507 508 /*! 509 * \brief Get the running state of a clock. 510 * 511 * \param clock_id Clock device identifier. 512 * 513 * \param[out] state The current clock state. 514 * 515 * \retval ::FWK_SUCCESS The operation succeeded. 516 * \retval ::FWK_PENDING The request is pending. The requested state will be 517 * provided via a response event. 518 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 519 * - The `clock_id` parameter was not a valid system entity identifier. 520 * - The `state` parameter was a null pointer value. 521 * \retval ::FWK_E_SUPPORT Deferred handling of asynchronous drivers is not 522 * supported. 523 * \return One of the standard framework error codes. 524 */ 525 int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state); 526 527 /*! 528 * \brief Get information about a clock's fixed properties. 529 * 530 * \param clock_id Clock device identifier. 531 * 532 * \param[out] info The clock device properties. 533 * 534 * \retval ::FWK_SUCCESS The operation succeeded. 535 * \retval ::FWK_E_PARAM An invalid parameter was encountered: 536 * - The `clock_id` parameter was not a valid system entity identifier. 537 * - The `info` parameter was a null pointer value. 538 * \return One of the standard framework error codes. 539 */ 540 int (*get_info)(fwk_id_t clock_id, struct mod_clock_info *info); 541 }; 542 543 /*! 544 * \brief Container for the values returned upon request completion. 545 */ 546 union mod_clock_resp_values { 547 /*! The current clock rate in Hertz */ 548 uint64_t rate; 549 550 /*! The current clock state */ 551 enum mod_clock_state state; 552 }; 553 554 /*! 555 * \brief Driver response parameters. 556 */ 557 struct mod_clock_driver_resp_params { 558 /*! Status of driver operation */ 559 int status; 560 561 /*! Values returned */ 562 union mod_clock_resp_values value; 563 }; 564 565 /*! 566 * \brief Clock driver response API. 567 * 568 * \details API used by the driver when an asynchronous request is completed. 569 * 570 */ 571 struct mod_clock_driver_response_api { 572 /*! 573 * \brief Signal the completion of a driver request. 574 * 575 * \param dev_id Specific clock device identifier. 576 * \param resp_values Pointer to the values requested. 577 */ 578 void (*request_complete)(fwk_id_t dev_id, 579 struct mod_clock_driver_resp_params *resp_values); 580 }; 581 582 /*! 583 * \brief Event response parameters. 584 */ 585 struct mod_clock_resp_params { 586 /*! Status of requested operation */ 587 int status; 588 589 /*! Values returned */ 590 union mod_clock_resp_values value; 591 }; 592 593 /*! 594 * \brief Define the event identifiers for deferred responses. 595 */ 596 enum mod_clock_event_idx { 597 MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST, 598 MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST, 599 600 MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST, 601 MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST, 602 603 MOD_CLOCK_EVENT_IDX_COUNT 604 }; 605 606 /*! 607 * \brief Request event identifiers. 608 * 609 * \details These identifiers are used by the clients that expect to receive a 610 * response event from this module when a request is deferred. 611 */ 612 static const fwk_id_t mod_clock_event_id_set_rate_request = 613 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 614 MOD_CLOCK_EVENT_IDX_SET_RATE_REQUEST); 615 616 static const fwk_id_t mod_clock_event_id_get_rate_request = 617 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 618 MOD_CLOCK_EVENT_IDX_GET_RATE_REQUEST); 619 620 static const fwk_id_t mod_clock_event_id_set_state_request = 621 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 622 MOD_CLOCK_EVENT_IDX_SET_STATE_REQUEST); 623 624 static const fwk_id_t mod_clock_event_id_get_state_request = 625 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_CLOCK, 626 MOD_CLOCK_EVENT_IDX_GET_STATE_REQUEST); 627 628 /*! 629 * \} 630 */ 631 632 /*! 633 * \} 634 */ 635 636 #endif /* MOD_CLOCK_H */ 637