atsamd_hal/peripherals/clock/d5x/v2/
ahb.rs

1//! # Advanced high performance bus clocks
2//!
3//! ## Overview
4//!
5//! AHB clocks facilitate communication between the processor core and
6//! peripherals on the AHB bus. To communicate with a peripheral, the
7//! corresponding AHB clock must be enabled, which is done by setting a bit in
8//! the `AHBMASK` register.
9//!
10//! In this module, *enabled* AHB clocks are represented by the [`AhbClk<A>`]
11//! struct, where the type parameter `A` is a type that implements [`AhbId`] and
12//! corresponds to one of the bits in the `AHBMASK` register.
13//!
14//! While most other clocks in the `clock` module are configured through
15//! mutually exclusive registers, the [`AhbClk`]s share a single `AHBMASK`
16//! register. This presents a challenge for memory safety. Specifically, if we
17//! allowed unrestricted access to the `AHBMASK` register through each `AhbClk`,
18//! we could create data races.
19//!
20//! To solve this problem, we restrict access to the `AHBMASK` register using
21//! the [`Ahb`] type. `Ahb` was created to act as a gateway to the `AHBMASK`
22//! register, allowing us to use `&mut Ahb` as compile-time proof of exclusive
23//! access to it.
24//!
25//! ## Example
26//!
27//! Enabling and disabling the [`AhbClk`]s proceeds according to the principles
28//! outlined in the [`clock` module documentation]. It is best shown with an
29//! example.
30//!
31//! Let's start by using [`clock_system_at_reset`] to access the HAL clocking
32//! structs.
33//!
34//! ```no_run
35//! use atsamd_hal::{
36//!     clock::v2::{
37//!         clock_system_at_reset,
38//!     },
39//!     pac::Peripherals,
40//! };
41//! let mut pac = Peripherals::take().unwrap();
42//! let (mut buses, clocks, tokens) = clock_system_at_reset(
43//!     pac.oscctrl,
44//!     pac.osc32kctrl,
45//!     pac.gclk,
46//!     pac.mclk,
47//!     &mut pac.nvmctrl,
48//! );
49//! ```
50//!
51//! All AHB clocks are enabled at power-on reset. We can find them in the
52//! [`Clocks`] struct.
53//!
54//! ```no_run
55//! # use atsamd_hal::{
56//! #     clock::v2::{
57//! #         clock_system_at_reset,
58//! #     },
59//! #     pac::Peripherals,
60//! # };
61//! # let mut pac = Peripherals::take().unwrap();
62//! # let (mut buses, clocks, tokens) = clock_system_at_reset(
63//! #     pac.oscctrl,
64//! #     pac.osc32kctrl,
65//! #     pac.gclk,
66//! #     pac.mclk,
67//! #     &mut pac.nvmctrl,
68//! # );
69//! let ahb_qspi = clocks.ahbs.qspi;
70//! ```
71//!
72//! To disable an `AhbClk`, we must have access to the [`Ahb`] bus type, which
73//! is found in the [`Buses`] struct. As described above, [`Ahb`] mediates
74//! access to the shared `AHBMASK` register. We call [`Ahb::disable`] to convert
75//! an [`AhbClk`] into the corresponding [`AhbToken`].
76//!
77//! ```no_run
78//! # use atsamd_hal::{
79//! #     clock::v2::{
80//! #         clock_system_at_reset,
81//! #     },
82//! #     pac::Peripherals,
83//! # };
84//! # let mut pac = Peripherals::take().unwrap();
85//! # let (mut buses, clocks, tokens) = clock_system_at_reset(
86//! #     pac.oscctrl,
87//! #     pac.osc32kctrl,
88//! #     pac.gclk,
89//! #     pac.mclk,
90//! #     &mut pac.nvmctrl,
91//! # );
92//! # let ahb_qspi = clocks.ahbs.qspi;
93//! let ahb_qspi = buses.ahb.disable(ahb_qspi);
94//! ```
95//!
96//! To reenable an `AhbClk`, users must save the `AhbToken` and use it when
97//! calling [`Ahb::enable`].
98//!
99//! The complete example is shown below.
100//!
101//! ```no_run
102//! use atsamd_hal::{
103//!     clock::v2::{
104//!         clock_system_at_reset,
105//!     },
106//!     pac::Peripherals,
107//! };
108//! let mut pac = Peripherals::take().unwrap();
109//! let (mut buses, clocks, tokens) = clock_system_at_reset(
110//!     pac.oscctrl,
111//!     pac.osc32kctrl,
112//!     pac.gclk,
113//!     pac.mclk,
114//!     &mut pac.nvmctrl,
115//! );
116//! let ahb_qspi = clocks.ahbs.qspi;
117//! let ahb_qspi = buses.ahb.disable(ahb_qspi);
118//! ```
119//!
120//! [`clock` module documentation]: super
121//! [`clock_system_at_reset`]: super::clock_system_at_reset
122//! [`Clocks`]: super::Clocks
123//! [`Buses`]: super::Buses
124
125use atsamd_hal_macros::hal_macro_helper;
126
127use core::marker::PhantomData;
128
129use bitflags;
130use paste::paste;
131
132use crate::pac::{mclk, Mclk};
133
134use super::types::*;
135
136//==============================================================================
137// Ahb
138//==============================================================================
139
140/// AHB clock controller
141///
142/// As described in the [module-level documentation](self), this struct mediates
143/// access to the shared `AHBMASK` register. Users can convert a disabled
144/// [`AhbToken<A>`] into an enabled [`AhbClk<A>`] using [`Ahb::enable`], and
145/// vice versa with [`Ahb::disable`].
146pub struct Ahb(());
147
148impl Ahb {
149    /// Create a new instance of [`Ahb`]
150    ///
151    /// # Safety
152    ///
153    /// Because the `Ahb` mediates access to the `AHBMASK` register, it must be
154    /// a singleton. There must never be two simulatenous instances of it at a
155    /// time. See the notes on `Token` types and memory safety in the root of
156    /// the `clock` module for more details.
157    #[inline]
158    pub(super) unsafe fn new() -> Self {
159        Self(())
160    }
161
162    #[inline]
163    fn ahbmask(&mut self) -> &mclk::Ahbmask {
164        // Safety: The `Ahb` type has exclusive access to the `AHBMASK`
165        // register. See the notes on `Token` types and memory safety in the
166        // root of the `clock` module for more details.
167        unsafe { (*Mclk::PTR).ahbmask() }
168    }
169
170    #[inline]
171    fn enable_mask(&mut self, mask: AhbMask) {
172        // Safety: The mask bits are derived from a `bitflags` struct, so they
173        // are guaranteed to be valid.
174        self.ahbmask()
175            .modify(|r, w| unsafe { w.bits(r.bits() | mask.bits()) });
176    }
177
178    #[inline]
179    fn disable_mask(&mut self, mask: AhbMask) {
180        // Safety: The mask bits are derived from a `bitflags` struct, so they
181        // are guaranteed to be valid.
182        self.ahbmask()
183            .modify(|r, w| unsafe { w.bits(r.bits() & !mask.bits()) });
184    }
185
186    /// Enable the corresponding AHB clock
187    ///
188    /// Consume an [`AhbToken`], enable the corresponding AHB clock and return
189    /// an [`AhbClk`]. The `AhbClk` represents proof that the corresponding AHB
190    /// clock has been enabled.
191    #[inline]
192    pub fn enable<A: AhbId>(&mut self, token: AhbToken<A>) -> AhbClk<A> {
193        self.enable_mask(A::DYN.into());
194        AhbClk::new(token)
195    }
196
197    /// Disable the corresponding AHB clock
198    ///
199    /// Consume the [`AhbClk`], disable the corresponding AHB clock and return
200    /// the [`AhbToken`].
201    #[inline]
202    pub fn disable<A: AhbId>(&mut self, clock: AhbClk<A>) -> AhbToken<A> {
203        self.disable_mask(A::DYN.into());
204        clock.free()
205    }
206}
207
208//==============================================================================
209// AhbId
210//==============================================================================
211
212/// Type-level enum identifying one of the possible AHB clocks
213///
214/// The types implementing this trait are type-level variants of `AhbId`, and
215/// they identify one of the possible AHB clocks, which can vary by chip. Each
216/// type corresponds to a specific bit in the `AHBMASK` register.
217///
218/// `AhbId` is the type-level equivalent of [`DynAhbId`]. See the documentation
219/// on [type-level programming] and specifically [type-level enums] for more
220/// details.
221///
222/// [type-level programming]: crate::typelevel
223/// [type-level enums]: crate::typelevel#type-level-enums
224pub trait AhbId: crate::typelevel::Sealed {
225    /// Corresponding [`DynAhbId`]
226    const DYN: DynAhbId;
227}
228
229//==============================================================================
230// AhbToken
231//==============================================================================
232
233/// Singleton token that can be exchanged for an [`AhbClk`]
234///
235/// As explained in the [`clock` module documentation](super), instances of
236/// various `Token` types can be exchanged for actual clock types. They
237/// represent clocks that are disabled.
238///
239/// The type parameter `A` is an [`AhbId`] indicating which AHB clock is
240/// represented by this token. To enable the corresponding AHB clock, use the
241/// [`Ahb::enable`] method.
242pub struct AhbToken<A: AhbId> {
243    id: PhantomData<A>,
244}
245
246impl<A: AhbId> AhbToken<A> {
247    /// Create a new instance of [`AhbToken`]
248    ///
249    /// # Safety
250    ///
251    /// Each `AhbToken` is a singleton. There must never be two simulatenous
252    /// instances with the same [`AhbId`]. See the notes on `Token` types and
253    /// memory safety in the root of the `clock` module for more details.
254    #[inline]
255    unsafe fn new() -> Self {
256        AhbToken { id: PhantomData }
257    }
258}
259
260//==============================================================================
261// AhbClk
262//==============================================================================
263
264/// An enabled AHB clock
265///
266/// An [`AhbClk`] represents an enabled AHB clock. The type parameter `A` is an
267/// [`AhbId`], which corresponds to a particular bit in the `AHBMASK`
268/// register. An `AhbClk` can be disabled with the [`Ahb::disable`] method.
269pub struct AhbClk<A: AhbId> {
270    token: AhbToken<A>,
271}
272
273impl<A: AhbId> AhbClk<A> {
274    #[inline]
275    fn new(token: AhbToken<A>) -> Self {
276        AhbClk { token }
277    }
278
279    #[inline]
280    fn free(self) -> AhbToken<A> {
281        self.token
282    }
283}
284
285//==============================================================================
286// DynAhbId & AhbClks
287//==============================================================================
288
289macro_rules! define_ahb_types {
290    (
291        $(
292            $( #[$( $cfg:tt )+] )?
293            $Type:ident = $BIT:literal,
294        )+
295    ) => {
296        paste! {
297            bitflags::bitflags! {
298                /// AHB clock register mask
299                ///
300                /// This is a [`bitflags`] struct with a binary representation
301                /// exactly matching the `AHBMASK` register.
302                struct AhbMask: u32 {
303                    $(
304                        $( #[$( $cfg )+] )?
305                        const [<$Type:upper>] = 1 << $BIT;
306                    )+
307                }
308            }
309
310            /// Value-level enum identifying a single AHB clock
311            ///
312            /// Each variant of this enum corresponds to a specific bit in the
313            /// `AHBMASK` register and identifies one of the possible AHB
314            /// clocks, which can vary by chip.
315            ///
316            /// `DynAhbId` is the value-level equivalent of [`AhbId`].
317            #[repr(u8)]
318            pub enum DynAhbId {
319                $(
320                    $( #[$( $cfg )+] )?
321                    $Type = $BIT,
322                )+
323            }
324
325            impl From<DynAhbId> for AhbMask {
326                #[inline]
327                fn from(id: DynAhbId) -> AhbMask {
328                    match id {
329                        $(
330                            $( #[$( $cfg )+] )?
331                            DynAhbId::$Type => AhbMask::[<$Type:upper>],
332                        )+
333                    }
334                }
335            }
336
337            $(
338                $( #[$( $cfg )+] )?
339                impl AhbId for $Type {
340                    const DYN: DynAhbId = DynAhbId::$Type;
341                }
342            )+
343
344            /// Set of all [`AhbClk`]s
345            ///
346            /// All [`AhbClk`]s are enabled at power-on reset.
347            pub struct AhbClks {
348                $(
349                    $( #[$( $cfg )+] )?
350                    pub [<$Type:snake>]: AhbClk<$Type>,
351                )+
352            }
353            impl AhbClks {
354                /// Create the set of [`AhbClk`]s
355                ///
356                /// # Safety
357                ///
358                /// All invariants of `AhbToken::new` must be upheld here.
359                #[inline]
360                pub(super) unsafe fn new() -> Self {
361                    AhbClks {
362                        $(
363                            $( #[$( $cfg )+] )?
364                            [<$Type:snake>]: AhbClk::new(AhbToken::new()),
365                        )+
366                    }
367                }
368            }
369        }
370    };
371}
372
373#[hal_macro_helper]
374define_ahb_types!(
375    Hpb0 = 0,
376    Hpb1 = 1,
377    Hpb2 = 2,
378    Hpb3 = 3,
379    Dsu = 4,
380    NvmCtrl = 6,
381    Cmcc = 8,
382    Dmac = 9,
383    Usb = 10,
384    Pac = 12,
385    Qspi = 13,
386    #[hal_cfg("gmac")]
387    Gmac = 14,
388    Sdhc0 = 15,
389    #[hal_cfg("sdhc1")]
390    Sdhc1 = 16,
391    #[hal_cfg("can0")]
392    Can0 = 17,
393    #[hal_cfg("can1")]
394    Can1 = 18,
395    Icm = 19,
396    Pukcc = 20,
397    Qspi2x = 21,
398    NvmCtrlSmeeProm = 22,
399    NvmCtrlCache = 23,
400);