1 // Copyright 2024 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 #include <memory> 18 #include <mutex> 19 20 #include "pw_assert/assert.h" 21 #include "pw_status/status.h" 22 #include "pw_status/try.h" 23 #include "pw_sync/interrupt_spin_lock.h" 24 #include "pw_sync/mutex.h" 25 26 namespace pw::clock_tree { 27 28 /// Abstract base class for a clock tree element of a clock tree. 29 /// 30 /// Class implementations of `Element` must implement `Acquire` and `Release` 31 /// functions. For clock tree elements that only get enabled / configured, 32 /// it is sufficient to only override the `DoEnable` function, otherwise it 33 /// is required to override the `DoDisable` function to disable the respective 34 /// clock tree element. 35 /// 36 /// Note: Clock tree element classes shouldn't be directly derived from the 37 /// `Element` class, but from the `ElementBlocking`, 38 /// `ElementNonBlockingCannotFail` or `ElementNonBlockingMightFail` class. 39 class Element { 40 public: may_block_(may_block)41 constexpr Element(bool may_block = false) : may_block_(may_block) {} 42 virtual ~Element() = default; 43 44 /// Get reference count for this clock tree element. ref_count()45 uint32_t ref_count() const { return ref_count_; } 46 47 /// Check whether acquiring or releasing the element may block. may_block()48 bool may_block() const { return may_block_; } 49 50 // Not copyable or movable 51 Element(const Element&) = delete; 52 Element(const Element&&) = delete; 53 Element& operator=(const Element&) = delete; 54 Element& operator=(const Element&&) = delete; 55 56 protected: 57 /// Acquire a reference to the clock tree element. 58 /// 59 /// Acquiring a reference to a clock tree element ensures that the 60 /// clock tree element is configured and enabled. 61 /// 62 /// If the clock tree element depends on another clock tree element, 63 /// a reference to the dependent clock tree element will get 64 /// acquired when the first reference to this clock tree element 65 /// gets acquired. This ensures that all dependent clock tree 66 /// elements have been enabled before this clock tree element gets 67 /// configured and enabled. 68 virtual Status Acquire() = 0; 69 70 /// Release a reference to the clock tree element. 71 /// 72 /// Releasing the last reference to the clock tree element will disable 73 /// the clock tree element. 74 /// 75 /// When the last reference to the clock tree element gets released, 76 /// the clock tree element gets disabled if the `DoDisable` function 77 /// is overridden. 78 /// 79 /// If the clock tree element depends on another clock tree element, 80 /// a reference to the dependent clock tree element will get 81 /// released once the last reference to this clock tree element has 82 /// been released and the clock tree element has been disabled. 83 /// This ensures that the clock tree element gets disabled before 84 /// all dependent clock tree elements have been disabled. 85 virtual Status Release() = 0; 86 87 /// Increment reference count and return incremented value. IncRef()88 uint32_t IncRef() { return ++ref_count_; } 89 90 /// Decrement reference count and return decremented value. DecRef()91 uint32_t DecRef() { return --ref_count_; } 92 93 /// Function called when the clock tree element needs to get enabled. 94 virtual Status DoEnable() = 0; 95 96 /// Function called when the clock tree element can get disabled. 97 /// 98 /// Can be overridden by child class in case the clock tree element 99 /// can be disabled to save power. DoDisable()100 virtual Status DoDisable() { return OkStatus(); } 101 102 private: 103 /// Reference count for this tree element. 104 uint32_t ref_count_ = 0; 105 106 /// Whether acquiring or releasing the element may block. 107 const bool may_block_; 108 109 friend class ClockTree; 110 template <typename ElementType> 111 friend class DependentElement; 112 friend class ClockDivider; 113 }; 114 115 /// Abstract class of a clock tree element that might need to block to perform 116 /// element updates. 117 class ElementBlocking : public Element { 118 public: ElementBlocking()119 constexpr ElementBlocking() : Element(/*may_block=*/true) {} 120 }; 121 122 /// Abstract class of a clock tree element that will not block to perform 123 /// element updates and will not fail when performing clock updates. 124 class ElementNonBlockingCannotFail : public Element {}; 125 126 /// Abstract class of a clock tree element that will not block to perform 127 /// element updates and might fail when performing clock updates. 128 class ElementNonBlockingMightFail : public Element {}; 129 130 /// Abstract class template of a clock tree element that provides a clock 131 /// source. 132 /// 133 /// A `ClockSource` clock tree element does not depend on any other 134 /// clock tree element, but provides a clock to the system that is not 135 /// derived from another clock. 136 /// 137 /// Class implementations of `ClockSource` must implement 138 /// `Acquire` and `Release` functions. For clock sources that only get 139 /// enabled / configured, it is sufficient to only override the `DoEnable` 140 /// function, otherwise it is required to override the `DoDisable` function to 141 /// disable the clock source. 142 /// 143 /// Template argument `ElementType` can be of class `ElementBlocking`, 144 /// `ElementNonBlockingCannotFail` or 145 /// `ElementNonBlockingMightFail.` 146 template <typename ElementType> 147 class ClockSource : public ElementType { 148 private: 149 /// Acquire a reference to the clock source. 150 /// 151 /// When the first reference gets acquired, the clock source gets enabled. Acquire()152 Status Acquire() final { 153 if (this->IncRef() > 1) { 154 // This clock tree element is already enabled. 155 return OkStatus(); 156 } 157 158 // Enable clock source. 159 Status status = this->DoEnable(); 160 if (!status.ok()) { 161 this->DecRef(); 162 } 163 return status; 164 } 165 166 /// Release a reference to the clock source. 167 /// 168 /// When the last reference gets released, the clock source gets disabled. Release()169 Status Release() final { 170 if (this->DecRef() > 0) { 171 // The clock tree element remains enabled. 172 return OkStatus(); 173 } 174 175 // Disable the clock source. 176 Status status = this->DoDisable(); 177 if (!status.ok()) { 178 this->IncRef(); 179 } 180 return status; 181 } 182 }; 183 184 /// Class that represents a no-op clock source clock tree element that can 185 /// be used to satisfy the dependent source clock tree element dependency 186 /// for clock source classes that expect a source clock tree element. 187 class ClockSourceNoOp : public ClockSource<ElementNonBlockingCannotFail> { 188 private: DoEnable()189 pw::Status DoEnable() final { return pw::OkStatus(); } 190 DoDisable()191 pw::Status DoDisable() final { return pw::OkStatus(); } 192 }; 193 194 /// Abstract class template of a clock tree element that depends on another 195 /// clock tree element. 196 /// 197 /// A `DependentElement` clock tree element depends on another 198 /// clock tree element. 199 /// 200 /// Class implementations of `DependentElement` must override the 201 /// `DoEnable` function, the `DoDisable` function can be overridden to disable 202 /// the dependent clock tree element to save power. 203 /// 204 /// Template argument `ElementType` can be of class `ElementBlocking`, 205 /// `ElementNonBlockingCannotFail` or 206 /// `ElementNonBlockingMightFail.` 207 template <typename ElementType> 208 class DependentElement : public ElementType { 209 public: 210 /// Create a dependent clock tree element that depends on `source`. DependentElement(ElementType & source)211 constexpr DependentElement(ElementType& source) : source_(&source) {} 212 213 protected: 214 /// Update source dependency. 215 /// 216 /// It is the responsibility of the derived class to ensure that the 217 /// source dependency can only be changed when permitted, i.e. only 218 /// if reference count is zero. 219 /// If the update is permitted while the reference count is greater than 220 /// zero, the caller of this function must make sure that the `DoEnable` 221 /// method has access to the updated configuration matching the new `source` 222 /// dependency. Only if the `UpdateSource` call succeeds, the new source has 223 /// been configured as the `source_` element for this element, otherwise the 224 /// old source element is still configured as `source_` element for this 225 /// element. If the `DoEnable` call of the new source fails, the current 226 /// element will be disabled, since the previous source got already released, 227 /// and the old source remains configured as the dependent element. UpdateSource(ElementType & new_source,bool permit_change_if_in_use)228 Status UpdateSource(ElementType& new_source, bool permit_change_if_in_use) { 229 // If the element is not enabled, we can update the `source_` directly. 230 if (this->ref_count() == 0) { 231 source_ = &new_source; 232 return OkStatus(); 233 } 234 235 // The element is active, check whether we are allowed to change the source. 236 if (!permit_change_if_in_use) { 237 return Status::FailedPrecondition(); 238 } 239 240 ElementType* old_source = source_; 241 242 // Acquire the dependent sources for the new_source element. 243 PW_TRY(new_source.Acquire()); 244 245 // Disable this current element configuration. 246 if (Status status = this->DoDisable(); !status.ok()) { 247 new_source.Release().IgnoreError(); 248 return status; 249 } 250 251 // Enable the new source element configuration. 252 Status status = this->DoEnable(); 253 254 // Release the reference to the old dependent source regardless whether 255 // we have enabled the new source, since we have successfully disabled it. 256 old_source->Release().IgnoreError(); 257 258 // Check whether the `DoEnable` method succeeded for the new source. 259 if (!status.ok()) { 260 new_source.Release().IgnoreError(); 261 this->DecRef(); 262 return status; 263 } 264 265 // Everything has succeeded, change the source_ element. 266 source_ = &new_source; 267 return OkStatus(); 268 } 269 270 private: 271 /// Acquire a reference to the dependent clock tree element. 272 /// 273 /// When the first reference gets acquired, a reference to the source 274 /// element gets acquired, before the dependent clock tree element gets 275 /// enabled. Acquire()276 Status Acquire() final { 277 if (this->IncRef() > 1) { 278 // This clock tree element is already enabled. 279 return OkStatus(); 280 } 281 282 // Acquire a reference to the dependent clock tree element before 283 // enabling this clock tree element. 284 if (Status status = source_->Acquire(); !status.ok()) { 285 this->DecRef(); 286 return status; 287 } 288 289 Status status = this->DoEnable(); 290 if (!status.ok()) { 291 source_->Release().IgnoreError(); 292 this->DecRef(); 293 } 294 return status; 295 } 296 297 /// Release a reference to the dependent clock tree element. 298 /// 299 /// When the last reference gets released, the dependent clock tree 300 /// element gets disabled (if implemented), before the reference to the 301 /// `source` element gets released. Release()302 Status Release() final { 303 if (this->DecRef() > 0) { 304 // The clock tree element remains enabled. 305 return OkStatus(); 306 } 307 308 // Disable the clock tree element. 309 if (Status status = this->DoDisable(); !status.ok()) { 310 this->IncRef(); 311 return status; 312 } 313 // Even if releasing the dependent source references fails, 314 // we won't re-enable the clock source, and instead just return 315 // the error code to the caller. 316 return source_->Release(); 317 } 318 319 /// Pointer to the source clock tree element this clock tree element depends 320 /// on. 321 ElementType* source_; 322 }; 323 324 /// Abstract class of the clock divider specific interface. 325 /// 326 /// The clock divider interface allows APIs to accept a `ClockDivider` 327 /// element, if they want to use the `ClockTree`'s `SetDividerValue` method. 328 /// They can use the `element` method to call the `ClockTree`'s `Acquire` and 329 /// `Release` methods. 330 class ClockDivider { 331 public: ClockDivider(Element & element)332 constexpr ClockDivider(Element& element) : element_(element) {} 333 334 virtual ~ClockDivider() = default; 335 336 /// Set `divider` value. 337 /// 338 /// The `divider` value will get updated as part of this method if the clock 339 /// divider is currently active, otherwise the new divider value will be 340 /// configured when the clock divider gets enabled next. 341 virtual Status Set(uint32_t divider) = 0; 342 343 /// Return the element implementing this interface. element()344 Element& element() const { return element_; } 345 346 private: 347 /// Reference to element implementing this interface. 348 Element& element_; 349 }; 350 351 /// Abstract class template of a clock divider element. 352 /// 353 /// A `ClockDivider` clock tree element depends on another clock tree element 354 /// and has a divider value that gets configured when the clock divider gets 355 /// enabled. 356 /// 357 /// Class implementations of `ClockDivider` must override the `DoEnable` 358 /// function. 359 /// 360 /// Template argument `ElementType` can be of class `ElementBlocking`, 361 /// `ElementNonBlockingCannotFail` or 362 /// `ElementNonBlockingMightFail.` 363 template <typename ElementType> 364 class ClockDividerElement : public DependentElement<ElementType>, 365 public ClockDivider { 366 public: 367 /// Create a clock divider element that depends on `source` and gets 368 /// configured with `divider` value when enabled. ClockDividerElement(ElementType & source,uint32_t divider)369 constexpr ClockDividerElement(ElementType& source, uint32_t divider) 370 : DependentElement<ElementType>(source), 371 ClockDivider(static_cast<Element&>(*this)), 372 divider_(divider) {} 373 374 /// Set `divider` value. 375 /// 376 /// The `divider` value will get updated as part of this method if the clock 377 /// divider is currently active, otherwise the new divider value will be 378 /// configured when the clock divider gets enabled next. Set(uint32_t divider)379 Status Set(uint32_t divider) override { 380 uint32_t old_divider = divider_; 381 divider_ = divider; 382 if (this->ref_count() == 0) { 383 return OkStatus(); 384 } 385 386 Status status = this->DoEnable(); 387 if (!status.ok()) { 388 // Restore old divider value. 389 divider_ = old_divider; 390 } 391 return status; 392 } 393 394 protected: 395 /// Get current divider value. divider()396 uint32_t divider() const { return divider_; } 397 398 private: 399 /// Configured divider value. 400 uint32_t divider_; 401 }; 402 403 /// Alias for a blocking clock divider tree element. 404 using ClockDividerBlocking = ClockDividerElement<ElementBlocking>; 405 406 /// Alias for a non-blocking clock divider tree element where updates cannot 407 /// fail. 408 using ClockDividerNonBlockingCannotFail = 409 ClockDividerElement<ElementNonBlockingCannotFail>; 410 411 /// Alias for a non-blocking clock divider tree element where updates might 412 /// fail. 413 using ClockDividerNonBlockingMightFail = 414 ClockDividerElement<ElementNonBlockingMightFail>; 415 416 /// Clock tree class that manages the state of clock tree elements. 417 /// 418 /// The `ClockTree` provides the `Acquire` and `Release` methods to 419 /// acquire a reference to `ElementNonBlockingCannotFail`, 420 /// `ElementNonBlockingMightFail`, or `ElementBlocking` elements or 421 /// to the generic `Element` element. These functions will acquire the 422 /// proper lock to ensure that clock updates are synchronized. 423 /// 424 /// The `SetDividerValue` method allows to change the divider value for 425 /// `ClockDividerNonBlockingCannotFail`, `ClockDividerNonBlockingMightFail` 426 /// or `ClockDividerBlocking` elements, or to the generic `ClockDivider` 427 /// element. 428 class ClockTree { 429 public: 430 /// Acquire a reference to a non-blocking clock tree element. 431 /// Acquiring the clock tree element will succeed. Acquire(ElementNonBlockingCannotFail & element)432 void Acquire(ElementNonBlockingCannotFail& element) { 433 std::lock_guard lock(interrupt_spin_lock_); 434 Status status = element.Acquire(); 435 PW_DASSERT(status.ok()); 436 } 437 438 /// Acquire a reference to a non-blocking clock tree element. 439 /// Acquiring the clock tree element might fail. Acquire(ElementNonBlockingMightFail & element)440 Status Acquire(ElementNonBlockingMightFail& element) { 441 std::lock_guard lock(interrupt_spin_lock_); 442 return element.Acquire(); 443 } 444 445 /// Acquire a reference to a blocking clock tree element. 446 /// Acquiring the clock tree element might fail. Acquire(ElementBlocking & element)447 Status Acquire(ElementBlocking& element) { 448 std::lock_guard lock(mutex_); 449 return element.Acquire(); 450 } 451 452 /// Acquire a reference to a clock tree element. 453 /// Acquiring the clock tree element might fail. 454 /// 455 /// Note: May not be called from inside an interrupt context or with 456 /// interrupts disabled. Acquire(Element & element)457 Status Acquire(Element& element) { 458 if (element.may_block()) { 459 std::lock_guard lock(mutex_); 460 return element.Acquire(); 461 } 462 std::lock_guard lock(interrupt_spin_lock_); 463 return element.Acquire(); 464 } 465 466 /// Acquire a reference to clock tree element `element` while `element_with` 467 /// clock tree is enabled. 468 /// Acquiring the clock tree element might fail. 469 /// 470 /// Note: May not be called from inside an interrupt context or with 471 /// interrupts disabled. AcquireWith(Element & element,Element & element_with)472 Status AcquireWith(Element& element, Element& element_with) { 473 PW_TRY(Acquire(element_with)); 474 Status status = Acquire(element); 475 Release(element_with).IgnoreError(); 476 return status; 477 } 478 479 /// Release a reference to a non-blocking clock tree element. 480 /// Releasing the clock tree element will succeed. Release(ElementNonBlockingCannotFail & element)481 void Release(ElementNonBlockingCannotFail& element) { 482 std::lock_guard lock(interrupt_spin_lock_); 483 Status status = element.Release(); 484 PW_DASSERT(status.ok()); 485 } 486 487 /// Release a reference to a non-blocking clock tree element. 488 /// Releasing the clock tree element might fail. Release(ElementNonBlockingMightFail & element)489 Status Release(ElementNonBlockingMightFail& element) { 490 std::lock_guard lock(interrupt_spin_lock_); 491 return element.Release(); 492 } 493 494 /// Release a reference to a blocking clock tree element. 495 /// Releasing the clock tree element might fail. Release(ElementBlocking & element)496 Status Release(ElementBlocking& element) { 497 std::lock_guard lock(mutex_); 498 return element.Release(); 499 } 500 501 /// Release a reference to a clock tree element. 502 /// Releasing the clock tree element might fail. 503 /// 504 /// Note: May not be called from inside an interrupt context or with 505 /// interrupts disabled. Release(Element & element)506 Status Release(Element& element) { 507 if (element.may_block()) { 508 std::lock_guard lock(mutex_); 509 return element.Release(); 510 } 511 std::lock_guard lock(interrupt_spin_lock_); 512 return element.Release(); 513 } 514 515 /// Set divider value for a non-blocking clock divider element. 516 /// Setting the clock divider value will succeed. SetDividerValue(ClockDividerNonBlockingCannotFail & clock_divider,uint32_t divider_value)517 void SetDividerValue(ClockDividerNonBlockingCannotFail& clock_divider, 518 uint32_t divider_value) { 519 std::lock_guard lock(interrupt_spin_lock_); 520 Status status = clock_divider.Set(divider_value); 521 PW_DASSERT(status.ok()); 522 } 523 524 /// Set divider value for a non-blocking clock divider element. 525 /// Setting the clock divider value might fail. SetDividerValue(ClockDividerNonBlockingMightFail & clock_divider,uint32_t divider_value)526 Status SetDividerValue(ClockDividerNonBlockingMightFail& clock_divider, 527 uint32_t divider_value) { 528 std::lock_guard lock(interrupt_spin_lock_); 529 return clock_divider.Set(divider_value); 530 } 531 532 /// Set divider value for a blocking clock divider element. 533 /// Setting the clock divider value might fail. SetDividerValue(ClockDividerBlocking & clock_divider,uint32_t divider_value)534 Status SetDividerValue(ClockDividerBlocking& clock_divider, 535 uint32_t divider_value) { 536 std::lock_guard lock(mutex_); 537 return clock_divider.Set(divider_value); 538 } 539 540 /// Set divider value for a clock divider element. 541 /// Setting the clock divider value might fail. 542 /// 543 /// Note: May not be called from inside an interrupt context or with 544 /// interrupts disabled. SetDividerValue(ClockDivider & clock_divider,uint32_t divider_value)545 Status SetDividerValue(ClockDivider& clock_divider, uint32_t divider_value) { 546 if (clock_divider.element().may_block()) { 547 std::lock_guard lock(mutex_); 548 return clock_divider.Set(divider_value); 549 } 550 std::lock_guard lock(interrupt_spin_lock_); 551 return clock_divider.Set(divider_value); 552 } 553 554 protected: 555 /// `mutex_` protects `ElementBlocking` clock tree elements. 556 sync::Mutex mutex_; 557 558 /// `interrupt_spin_lock_` protects `ElementNonBlockingCannotFail` 559 /// and `ElementNonBlockingMightFail` clock tree elements. 560 sync::InterruptSpinLock interrupt_spin_lock_; 561 }; 562 563 /// Helper class that allows drivers to accept optional clock tree 564 /// information and streamline clock tree operations. 565 class ElementController { 566 public: 567 /// Create an element controller that accepts optional clock 568 /// tree and element information. 569 constexpr ElementController(ClockTree* clock_tree = nullptr, 570 Element* element = nullptr) clock_tree_(clock_tree)571 : clock_tree_(clock_tree), element_(element) {} 572 573 /// Acquire a reference to the optional clock tree element. 574 /// 575 /// If not both optional clock_tree and element pointers are 576 /// non-null, the function just returns `pw::OkStatus()`. Acquire()577 Status Acquire() { 578 if (clock_tree_ != nullptr && element_ != nullptr) { 579 return clock_tree_->Acquire(*element_); 580 } 581 return OkStatus(); 582 } 583 584 /// Release a reference to the optional clock tree element. 585 /// 586 /// If not both optional clock_tree and element pointers are 587 /// non-null, the function just returns `pw::OkStatus()`. Release()588 Status Release() { 589 if (clock_tree_ != nullptr && element_ != nullptr) { 590 return clock_tree_->Release(*element_); 591 } 592 return OkStatus(); 593 } 594 595 /// Pointer to optional `ClockTree` object. 596 ClockTree* clock_tree_ = nullptr; 597 598 /// Pointer to optional `Element` object. 599 Element* element_ = nullptr; 600 }; 601 } // namespace pw::clock_tree 602