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);