xref: /aosp_15_r20/external/pigweed/pw_clock_tree/public/pw_clock_tree/clock_tree.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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