1 /* 2 * Copyright (c) 2019-2023 Arm Limited 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** 18 * \file syscounter_armv8-m_cntrl_drv.h 19 * 20 * \brief Driver for Armv8-M System Counter Control, covering CNTControlBase 21 * Frame 22 * 23 * This System Counter is a 64-bit up-counter, generating the physical 24 * count for System Timer. 25 * 26 * Main features: 27 * - Enable/disable and Set/Get the 64-bit upcounter 28 * - 2 scaling registers for the 2 clock sources 29 * - These registers are used to pre-program the scaling values so 30 * that when hardware based clock switching is implemented there is no 31 * need to program the scaling increment value each time when clock is 32 * switched. 33 * - When counter scaling is enabled, ScaleVal is the value added to the 34 * Counter Count Value for every period of the counter as determined 35 * by 1/Frequency from the current operating frequency of the system 36 * counter (the "counter tick"). 37 * - ScaleVal is expressed as an unsigned fixed-point number with 38 * a 8 bit integer value and a 24-bit fractional value 39 * - Interrupt for error detection 40 * There are 2 possible reasons for error notification generation from 41 * the Counter: 42 * 1. Security attribute mismatch between register access and security 43 * attribute of the CONTROL frame 44 * 2. Address decode error within a given frame 45 * 46 */ 47 48 #ifndef __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__ 49 #define __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__ 50 51 #include <stdbool.h> 52 #include <stdint.h> 53 54 #ifdef __cplusplus 55 extern "C" { 56 #endif 57 58 #define SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH 32u 59 /*!< Armv8-M System Counter Control registers bit width */ 60 61 #define SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL 0u 62 /*!< Armv8-M System Counter Control default counter init value */ 63 64 /** 65 * \brief Armv8-M System Counter Control scaling value 66 */ 67 struct syscounter_armv8_m_cntrl_scale_val_t { 68 uint32_t integer; /* 8 bit */ 69 uint32_t fixed_point_fraction; /* 24 bit */ 70 }; 71 72 /** 73 * \brief Armv8-M System Counter Control scaling value macros * 74 * 8 bit integer and 24 bit fixed point fractional value 75 */ 76 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_MAX UINT8_MAX 77 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF 24u 78 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX \ 79 ((1u << SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF) - 1u) 80 81 /** 82 * \brief Armv8-M System Counter Control device configuration structure 83 */ 84 struct syscounter_armv8_m_cntrl_dev_cfg_t { 85 const uint32_t base; 86 /*!< Armv8-M System Counter Control device base address */ 87 struct syscounter_armv8_m_cntrl_scale_val_t scale0; 88 /*!< Default clock scaling value for Clock source 0 */ 89 struct syscounter_armv8_m_cntrl_scale_val_t scale1; 90 /*!< Default clock scaling value for Clock source 1 */ 91 }; 92 93 /** 94 * \brief Armv8-M System Counter Control device data structure 95 */ 96 struct syscounter_armv8_m_cntrl_dev_data_t { 97 bool is_initialized; 98 }; 99 100 /** 101 * \brief Armv8-M System Counter Control device structure 102 */ 103 struct syscounter_armv8_m_cntrl_dev_t { 104 const struct syscounter_armv8_m_cntrl_dev_cfg_t* const cfg; 105 /*!< Armv8-M System Counter Control configuration structure */ 106 struct syscounter_armv8_m_cntrl_dev_data_t* const data; 107 /*!< Armv8-M System Counter Control data structure */ 108 }; 109 110 /** 111 * \brief Armv8-M System Counter Control error enumeration types 112 */ 113 enum syscounter_armv8_m_cntrl_error_t { 114 SYSCOUNTER_ARMV8_M_ERR_NONE = 0u, 115 SYSCOUNTER_ARMV8_M_ERR_INVALID = 1u, 116 SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG = 2u 117 }; 118 119 /** 120 * \brief Armv8-M System Counter Control scaling number for each clock sources 121 */ 122 enum syscounter_armv8_m_cntrl_scale_nr_t { 123 SYSCOUNTER_ARMV8_M_SCALE_NR_0 = 0u, 124 /*!< Scaling for \ref SYSCOUNTER_ARMV8_M_SELCLK_CLK0 */ 125 SYSCOUNTER_ARMV8_M_SCALE_NR_1 = 1u 126 /*!< Scaling for \ref SYSCOUNTER_ARMV8_M_SELCLK_CLK1 */ 127 }; 128 129 /** 130 * \brief Clock select values 131 */ 132 enum syscounter_armv8_m_cntrl_selclk_t { 133 SYSCOUNTER_ARMV8_M_SELCLK_CLK_INVALID0 = 0u, 134 /*!< Clock select invalid value */ 135 SYSCOUNTER_ARMV8_M_SELCLK_CLK0 = 1u, 136 /*!< Clock select clock source 0 */ 137 SYSCOUNTER_ARMV8_M_SELCLK_CLK1 = 2u, 138 /*!< Clock select clock source 1 */ 139 SYSCOUNTER_ARMV8_M_SELCLK_CLK_INVALID1 = 3u 140 /*!< Clock select invalid value */ 141 }; 142 143 /** 144 * \brief Override counter enable condition for writing to CNTSCR registers 145 * 146 */ 147 enum syscounter_armv8_m_cntrl_cntscr_ovr_t { 148 SYSCOUNTER_ARMV8_M_CNTSCR_IF_DISABLED = 0u, 149 /*!< Scaling registers can be written only when counter is disabled */ 150 SYSCOUNTER_ARMV8_M_CNTSCR_ALWAYS = 1u 151 /*!< CNTSCR can be written regardless of counter enabled or disabled */ 152 }; 153 154 /** 155 * \brief Initializes counter to a known default state, which is: 156 * - counter is enabled, so starts counting 157 * - interrupt is disabled 158 * - counter reset to default reset value 159 * \ref SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL 160 * - scaling is disabled 161 * - scaling registers are set to the set values: 162 * \ref struct syscounter_armv8_m_cntrl_dev_cfg_t 163 * Init should be called prior to any other process and 164 * it's the caller's responsibility to follow proper call order. 165 * More than one call results fall through. 166 * 167 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 168 * 169 * \return Error status \ref enum syscounter_armv8_m_cntrl_error_t 170 * 171 * \note This function doesn't check if dev is NULL. 172 */ 173 enum syscounter_armv8_m_cntrl_error_t syscounter_armv8_m_cntrl_init( 174 struct syscounter_armv8_m_cntrl_dev_t* dev); 175 176 /** 177 * \brief Uninitializes counter to a known default state, which is: 178 * - counter is disabled, so stops counting 179 * - interrupt is disabled 180 * - counter reset to default reset value 181 * \ref SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL 182 * - scaling is disabled 183 * Init should be called prior to any other process and 184 * it's the caller's responsibility to follow proper call order. 185 * 186 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 187 * 188 * \note This function doesn't check if dev is NULL. 189 */ 190 void syscounter_armv8_m_cntrl_uninit( 191 struct syscounter_armv8_m_cntrl_dev_t* dev); 192 193 /** 194 * \brief Enables the counter, so counter starts counting 195 * 196 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 197 * 198 * \note This function doesn't check if dev is NULL. 199 */ 200 void syscounter_armv8_m_cntrl_enable_counter( 201 struct syscounter_armv8_m_cntrl_dev_t* dev); 202 203 /** 204 * \brief Disables the counter, so counter stops counting 205 * 206 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 207 * 208 * \note This function doesn't check if dev is NULL. 209 */ 210 void syscounter_armv8_m_cntrl_disable_counter( 211 struct syscounter_armv8_m_cntrl_dev_t* dev); 212 213 /** 214 * \brief Polls counter enable status 215 * 216 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 217 * 218 * \return true if enabled, false otherwise 219 * 220 * \note This function doesn't check if dev is NULL. 221 */ 222 bool syscounter_armv8_m_cntrl_is_counter_enabled( 223 struct syscounter_armv8_m_cntrl_dev_t* dev); 224 225 /** 226 * \brief Enables Halt-On-Debug feature 227 * 228 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 229 * 230 * \note This function doesn't check if dev is NULL. 231 */ 232 void syscounter_armv8_m_cntrl_enable_halt_on_debug( 233 struct syscounter_armv8_m_cntrl_dev_t* dev); 234 235 /** 236 * \brief Disables Halt-On-Debug feature 237 * 238 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 239 * 240 * \note This function doesn't check if dev is NULL. 241 */ 242 void syscounter_armv8_m_cntrl_disable_halt_on_debug( 243 struct syscounter_armv8_m_cntrl_dev_t* dev); 244 245 /** 246 * \brief Polls Halt-On-Debug enablement status 247 * 248 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 249 250 * \return true if enabled, false otherwise 251 * 252 * \note This function doesn't check if dev is NULL. 253 */ 254 bool syscounter_armv8_m_cntrl_is_halt_on_debug_enabled( 255 struct syscounter_armv8_m_cntrl_dev_t* dev); 256 257 /** 258 * \brief Enables scaling 259 * The used scaling register is depending on the used HW clock source. 260 * 261 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 262 * 263 * \note This function doesn't check if dev is NULL. 264 */ 265 void syscounter_armv8_m_cntrl_enable_scale( 266 struct syscounter_armv8_m_cntrl_dev_t* dev); 267 268 /** 269 * \brief Disables scaling 270 * Counter count will be incremented by default 1 for each ticks. 271 * 272 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 273 * 274 * \note This function doesn't check if dev is NULL. 275 */ 276 void syscounter_armv8_m_cntrl_disable_scale( 277 struct syscounter_armv8_m_cntrl_dev_t* dev); 278 279 /** 280 * \brief Polls scaling enablement status 281 * 282 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 283 * 284 * \return true if enabled, false otherwise 285 * 286 * \note This function doesn't check if dev is NULL. 287 */ 288 bool syscounter_armv8_m_cntrl_is_scale_enabled( 289 struct syscounter_armv8_m_cntrl_dev_t* dev); 290 291 /** 292 * \brief Enables interrupt 293 * 294 * There are 2 possible reasons for error notification generation from 295 * the Counter: 296 * 1. Security attribute mismatch between register access and security 297 * attribute of the CONTROL frame 298 * 2. Address decode error within a given frame 299 * 300 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 301 * 302 * \note This function doesn't check if dev is NULL. 303 */ 304 void syscounter_armv8_m_cntrl_enable_interrupt( 305 struct syscounter_armv8_m_cntrl_dev_t* dev); 306 307 /** 308 * \brief Disables interrupt 309 * 310 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 311 * 312 * \note This function doesn't check if dev is NULL. 313 */ 314 void syscounter_armv8_m_cntrl_disable_interrupt( 315 struct syscounter_armv8_m_cntrl_dev_t* dev); 316 317 /** 318 * \brief Polls interrupt enablement status 319 * 320 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 321 * 322 * \return true if enabled, false otherwise 323 * 324 * \note This function doesn't check if dev is NULL. 325 */ 326 bool syscounter_armv8_m_cntrl_is_interrupt_enabled( 327 struct syscounter_armv8_m_cntrl_dev_t* dev); 328 329 /** 330 * \brief Enables PSLVERR output 331 * 332 * PSLVERR output signal on APB bus dynamically generated for the 333 * following error: 334 * For security attribute mismatch between register access and security 335 * attribute of the CONTROL frame 336 * 337 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 338 * 339 * \note This function doesn't check if dev is NULL. 340 */ 341 void syscounter_armv8_m_cntrl_enable_pslverr( 342 struct syscounter_armv8_m_cntrl_dev_t* dev); 343 344 /** 345 * \brief Disables PSLVERR output 346 * 347 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 348 * 349 * \note This function doesn't check if dev is NULL. 350 */ 351 void syscounter_armv8_m_cntrl_disable_pslverr( 352 struct syscounter_armv8_m_cntrl_dev_t* dev); 353 354 /** 355 * \brief Polls PSLVERR output enablement status 356 * 357 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 358 * 359 * \return true if enabled, false otherwise 360 * 361 * \note This function doesn't check if dev is NULL. 362 */ 363 bool syscounter_armv8_m_cntrl_is_pslverr_enabled( 364 struct syscounter_armv8_m_cntrl_dev_t* dev); 365 366 /** 367 * \brief Clears interrupt pending flag 368 * 369 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 370 * 371 * \note This function doesn't check if dev is NULL. 372 */ 373 void syscounter_armv8_m_cntrl_clear_interrupt( 374 struct syscounter_armv8_m_cntrl_dev_t* dev); 375 376 /** 377 * \brief Polls Halt-On-Debug status 378 * 379 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 380 * 381 * \return true if counter is halted, false otherwise 382 * 383 * \note This function doesn't check if dev is NULL. 384 */ 385 bool syscounter_armv8_m_cntrl_is_counter_halted_on_debug( 386 struct syscounter_armv8_m_cntrl_dev_t* dev); 387 388 /** 389 * \brief Read counter value 390 * 391 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 392 * 393 * \return 64 bit counter value 394 * 395 * \note This function doesn't check if dev is NULL. 396 */ 397 uint64_t syscounter_armv8_m_cntrl_get_counter_value( 398 struct syscounter_armv8_m_cntrl_dev_t* dev); 399 400 /** 401 * \brief Writes counter value 402 * 403 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 404 * \param[in] value 64 bit counter value 405 * 406 * \note This function doesn't check if dev is NULL. 407 */ 408 void syscounter_armv8_m_cntrl_set_counter_value( 409 struct syscounter_armv8_m_cntrl_dev_t* dev, 410 uint64_t value); 411 412 /** 413 * \brief Polls whether scaling is implemented 414 * 415 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 416 * 417 * \return true if implemented, false otherwise 418 * 419 * \note This function doesn't check if dev is NULL. 420 */ 421 bool syscounter_armv8_m_cntrl_is_counter_scaling_implemented( 422 struct syscounter_armv8_m_cntrl_dev_t* dev); 423 424 /** 425 * \brief Polls whether HW based clock switching is implemented 426 * 427 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 428 * 429 * \return true if implemented, false otherwise 430 * 431 * \note This function doesn't check if dev is NULL. 432 */ 433 bool syscounter_armv8_m_cntrl_is_clock_switching_implemented( 434 struct syscounter_armv8_m_cntrl_dev_t* dev); 435 436 /** 437 * \brief Reads which clock source is being used 438 * 439 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 440 * 441 * \return Clock source \ref enum syscounter_armv8_m_cntrl_selclk_t 442 * 443 * \note This function doesn't check if dev is NULL. 444 */ 445 enum syscounter_armv8_m_cntrl_selclk_t 446 syscounter_armv8_m_cntrl_get_clock_source( 447 struct syscounter_armv8_m_cntrl_dev_t* dev); 448 449 /** 450 * \brief Reads scaling register can be overriden anytime 451 * 452 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 453 * 454 * \return Override condition \ref enum syscounter_armv8_m_cntrl_cntscr_ovr_t 455 * 456 * \note This function doesn't check if dev is NULL. 457 */ 458 enum syscounter_armv8_m_cntrl_cntscr_ovr_t 459 syscounter_armv8_m_cntrl_get_override_cntscr( 460 struct syscounter_armv8_m_cntrl_dev_t* dev); 461 462 /** 463 * \brief Reads scaling register 464 * 465 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 466 * \param[in] nr Index of scaling register to read 467 * \ref enum syscounter_armv8_m_cntrl_scale_nr_t 468 * \param[out] nr Pointer to structure to read the scale value 469 * \ref struct syscounter_armv8_m_cntrl_scale_val_t 470 * 471 * \return Override condition \ref enum syscounter_armv8_m_cntrl_cntscr_ovr_t 472 * 473 * \note This function doesn't check if dev is NULL. 474 */ 475 enum syscounter_armv8_m_cntrl_error_t 476 syscounter_armv8_m_cntrl_get_counter_scale_value( 477 struct syscounter_armv8_m_cntrl_dev_t* dev, 478 enum syscounter_armv8_m_cntrl_scale_nr_t nr, 479 struct syscounter_armv8_m_cntrl_scale_val_t *val); 480 481 /** 482 * \brief Writes scaling register 483 * 484 * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t 485 * \param[in] nr Index of scaling register to write 486 * \ref enum syscounter_armv8_m_cntrl_scale_nr_t 487 * \param[in] Scale value structure 488 * \ref struct syscounter_armv8_m_cntrl_scale_val_t 489 * 490 * \return Error status \ref enum syscounter_armv8_m_cntrl_error_t 491 * 492 * \note This function doesn't check if dev is NULL. 493 */ 494 enum syscounter_armv8_m_cntrl_error_t 495 syscounter_armv8_m_cntrl_set_counter_scale_value( 496 struct syscounter_armv8_m_cntrl_dev_t* dev, 497 enum syscounter_armv8_m_cntrl_scale_nr_t nr, 498 struct syscounter_armv8_m_cntrl_scale_val_t val); 499 500 #ifdef __cplusplus 501 } 502 #endif 503 #endif /* __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__ */ 504