xref: /linux/drivers/gpu/nova-core/regs/macros.rs (revision 352af6a011d586ff042db4b2d1f7421875eb8a14)
1c3f22262SAlexandre Courbot // SPDX-License-Identifier: GPL-2.0
2c3f22262SAlexandre Courbot 
3c3f22262SAlexandre Courbot //! Macro to define register layout and accessors.
4c3f22262SAlexandre Courbot //!
5c3f22262SAlexandre Courbot //! A single register typically includes several fields, which are accessed through a combination
6c3f22262SAlexandre Courbot //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because
7c3f22262SAlexandre Courbot //! not all possible field values are necessarily valid.
8c3f22262SAlexandre Courbot //!
9c3f22262SAlexandre Courbot //! The macro in this module allow to define, using an intruitive and readable syntax, a dedicated
10c3f22262SAlexandre Courbot //! type for each register with its own field accessors that can return an error is a field's value
11c3f22262SAlexandre Courbot //! is invalid.
12c3f22262SAlexandre Courbot 
13c3f22262SAlexandre Courbot /// Defines a dedicated type for a register with an absolute offset, alongside with getter and
14c3f22262SAlexandre Courbot /// setter methods for its fields and methods to read and write it from an `Io` region.
15c3f22262SAlexandre Courbot ///
16c3f22262SAlexandre Courbot /// Example:
17c3f22262SAlexandre Courbot ///
18c3f22262SAlexandre Courbot /// ```no_run
19c3f22262SAlexandre Courbot /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" {
20c3f22262SAlexandre Courbot ///    3:0     minor_revision as u8, "Minor revision of the chip";
21c3f22262SAlexandre Courbot ///    7:4     major_revision as u8, "Major revision of the chip";
22c3f22262SAlexandre Courbot ///    28:20   chipset as u32 ?=> Chipset, "Chipset model";
23c3f22262SAlexandre Courbot /// });
24c3f22262SAlexandre Courbot /// ```
25c3f22262SAlexandre Courbot ///
26c3f22262SAlexandre Courbot /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io`
27c3f22262SAlexandre Courbot /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 less
28c3f22262SAlexandre Courbot /// significant bits of the register. Each field can be accessed and modified using accessor
29c3f22262SAlexandre Courbot /// methods:
30c3f22262SAlexandre Courbot ///
31c3f22262SAlexandre Courbot /// ```no_run
32c3f22262SAlexandre Courbot /// // Read from the register's defined offset (0x100).
33c3f22262SAlexandre Courbot /// let boot0 = BOOT_0::read(&bar);
34c3f22262SAlexandre Courbot /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision());
35c3f22262SAlexandre Courbot ///
36c3f22262SAlexandre Courbot /// // `Chipset::try_from` will be called with the value of the field and returns an error if the
37c3f22262SAlexandre Courbot /// // value is invalid.
38c3f22262SAlexandre Courbot /// let chipset = boot0.chipset()?;
39c3f22262SAlexandre Courbot ///
40c3f22262SAlexandre Courbot /// // Update some fields and write the value back.
41c3f22262SAlexandre Courbot /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar);
42c3f22262SAlexandre Courbot ///
43c3f22262SAlexandre Courbot /// // Or just read and update the register in a single step:
44c3f22262SAlexandre Courbot /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10));
45c3f22262SAlexandre Courbot /// ```
46c3f22262SAlexandre Courbot ///
47c3f22262SAlexandre Courbot /// Fields can be defined as follows:
48c3f22262SAlexandre Courbot ///
49c3f22262SAlexandre Courbot /// - `as <type>` simply returns the field value casted as the requested integer type, typically
50c3f22262SAlexandre Courbot ///   `u32`, `u16`, `u8` or `bool`. Note that `bool` fields must have a range of 1 bit.
51c3f22262SAlexandre Courbot /// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns
52c3f22262SAlexandre Courbot ///   the result.
53c3f22262SAlexandre Courbot /// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation
54c3f22262SAlexandre Courbot ///   and returns the result. This is useful on fields for which not all values are value.
55c3f22262SAlexandre Courbot ///
56c3f22262SAlexandre Courbot /// The documentation strings are optional. If present, they will be added to the type's
57c3f22262SAlexandre Courbot /// definition, or the field getter and setter methods they are attached to.
58c3f22262SAlexandre Courbot ///
59c3f22262SAlexandre Courbot /// Putting a `+` before the address of the register makes it relative to a base: the `read` and
60c3f22262SAlexandre Courbot /// `write` methods take a `base` argument that is added to the specified address before access,
61c3f22262SAlexandre Courbot /// and `try_read` and `try_write` methods are also created, allowing access with offsets unknown
62c3f22262SAlexandre Courbot /// at compile-time:
63c3f22262SAlexandre Courbot ///
64c3f22262SAlexandre Courbot /// ```no_run
65c3f22262SAlexandre Courbot /// register!(CPU_CTL @ +0x0000010, "CPU core control" {
66c3f22262SAlexandre Courbot ///    0:0     start as bool, "Start the CPU core";
67c3f22262SAlexandre Courbot /// });
68c3f22262SAlexandre Courbot ///
69c3f22262SAlexandre Courbot /// // Flip the `start` switch for the CPU core which base address is at `CPU_BASE`.
70c3f22262SAlexandre Courbot /// let cpuctl = CPU_CTL::read(&bar, CPU_BASE);
71c3f22262SAlexandre Courbot /// pr_info!("CPU CTL: {:#x}", cpuctl);
72c3f22262SAlexandre Courbot /// cpuctl.set_start(true).write(&bar, CPU_BASE);
73c3f22262SAlexandre Courbot /// ```
74e66aaaffSAlexandre Courbot ///
75e66aaaffSAlexandre Courbot /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful
76e66aaaffSAlexandre Courbot /// for cases where a register's interpretation depends on the context:
77e66aaaffSAlexandre Courbot ///
78e66aaaffSAlexandre Courbot /// ```no_run
79e66aaaffSAlexandre Courbot /// register!(SCRATCH_0 @ 0x0000100, "Scratch register 0" {
80e66aaaffSAlexandre Courbot ///    31:0     value as u32, "Raw value";
81e66aaaffSAlexandre Courbot ///
82e66aaaffSAlexandre Courbot /// register!(SCRATCH_0_BOOT_STATUS => SCRATCH_0, "Boot status of the firmware" {
83e66aaaffSAlexandre Courbot ///     0:0     completed as bool, "Whether the firmware has completed booting";
84e66aaaffSAlexandre Courbot /// ```
85e66aaaffSAlexandre Courbot ///
86e66aaaffSAlexandre Courbot /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH_0`, while also
87e66aaaffSAlexandre Courbot /// providing its own `completed` method.
88c3f22262SAlexandre Courbot macro_rules! register {
89c3f22262SAlexandre Courbot     // Creates a register at a fixed offset of the MMIO space.
90c3f22262SAlexandre Courbot     (
91c3f22262SAlexandre Courbot         $name:ident @ $offset:literal $(, $comment:literal)? {
92c3f22262SAlexandre Courbot             $($fields:tt)*
93c3f22262SAlexandre Courbot         }
94c3f22262SAlexandre Courbot     ) => {
95cdfe233eSAlexandre Courbot         register!(@common $name @ $offset $(, $comment)?);
96c3f22262SAlexandre Courbot         register!(@field_accessors $name { $($fields)* });
97c3f22262SAlexandre Courbot         register!(@io $name @ $offset);
98c3f22262SAlexandre Courbot     };
99c3f22262SAlexandre Courbot 
100e66aaaffSAlexandre Courbot     // Creates a alias register of fixed offset register `alias` with its own fields.
101e66aaaffSAlexandre Courbot     (
102e66aaaffSAlexandre Courbot         $name:ident => $alias:ident $(, $comment:literal)? {
103e66aaaffSAlexandre Courbot             $($fields:tt)*
104e66aaaffSAlexandre Courbot         }
105e66aaaffSAlexandre Courbot     ) => {
106e66aaaffSAlexandre Courbot         register!(@common $name @ $alias::OFFSET $(, $comment)?);
107e66aaaffSAlexandre Courbot         register!(@field_accessors $name { $($fields)* });
108e66aaaffSAlexandre Courbot         register!(@io $name @ $alias::OFFSET);
109e66aaaffSAlexandre Courbot     };
110e66aaaffSAlexandre Courbot 
111c3f22262SAlexandre Courbot     // Creates a register at a relative offset from a base address.
112c3f22262SAlexandre Courbot     (
113c3f22262SAlexandre Courbot         $name:ident @ + $offset:literal $(, $comment:literal)? {
114c3f22262SAlexandre Courbot             $($fields:tt)*
115c3f22262SAlexandre Courbot         }
116c3f22262SAlexandre Courbot     ) => {
117cdfe233eSAlexandre Courbot         register!(@common $name @ $offset $(, $comment)?);
118c3f22262SAlexandre Courbot         register!(@field_accessors $name { $($fields)* });
119c3f22262SAlexandre Courbot         register!(@io$name @ + $offset);
120c3f22262SAlexandre Courbot     };
121c3f22262SAlexandre Courbot 
122e66aaaffSAlexandre Courbot     // Creates a alias register of relative offset register `alias` with its own fields.
123e66aaaffSAlexandre Courbot     (
124e66aaaffSAlexandre Courbot         $name:ident => + $alias:ident $(, $comment:literal)? {
125e66aaaffSAlexandre Courbot             $($fields:tt)*
126e66aaaffSAlexandre Courbot         }
127e66aaaffSAlexandre Courbot     ) => {
128e66aaaffSAlexandre Courbot         register!(@common $name @ $alias::OFFSET $(, $comment)?);
129e66aaaffSAlexandre Courbot         register!(@field_accessors $name { $($fields)* });
130e66aaaffSAlexandre Courbot         register!(@io $name @ + $alias::OFFSET);
131e66aaaffSAlexandre Courbot     };
132e66aaaffSAlexandre Courbot 
1338dd1433dSAlexandre Courbot     // All rules below are helpers.
1348dd1433dSAlexandre Courbot 
135c3f22262SAlexandre Courbot     // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`,
136c3f22262SAlexandre Courbot     // and conversion to regular `u32`).
137e66aaaffSAlexandre Courbot     (@common $name:ident @ $offset:expr $(, $comment:literal)?) => {
138c3f22262SAlexandre Courbot         $(
139c3f22262SAlexandre Courbot         #[doc=$comment]
140c3f22262SAlexandre Courbot         )?
141c3f22262SAlexandre Courbot         #[repr(transparent)]
142c3f22262SAlexandre Courbot         #[derive(Clone, Copy, Default)]
143c3f22262SAlexandre Courbot         pub(crate) struct $name(u32);
144c3f22262SAlexandre Courbot 
145cdfe233eSAlexandre Courbot         #[allow(dead_code)]
146cdfe233eSAlexandre Courbot         impl $name {
147cdfe233eSAlexandre Courbot             pub(crate) const OFFSET: usize = $offset;
148cdfe233eSAlexandre Courbot         }
149cdfe233eSAlexandre Courbot 
1503606620bSAlexandre Courbot         // TODO[REGA]: display the raw hex value, then the value of all the fields. This requires
151c3f22262SAlexandre Courbot         // matching the fields, which will complexify the syntax considerably...
152c3f22262SAlexandre Courbot         impl ::core::fmt::Debug for $name {
153c3f22262SAlexandre Courbot             fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
154c3f22262SAlexandre Courbot                 f.debug_tuple(stringify!($name))
155c3f22262SAlexandre Courbot                     .field(&format_args!("0x{0:x}", &self.0))
156c3f22262SAlexandre Courbot                     .finish()
157c3f22262SAlexandre Courbot             }
158c3f22262SAlexandre Courbot         }
159c3f22262SAlexandre Courbot 
1608d5fbb8dSAlexandre Courbot         impl ::core::ops::BitOr for $name {
161c3f22262SAlexandre Courbot             type Output = Self;
162c3f22262SAlexandre Courbot 
163c3f22262SAlexandre Courbot             fn bitor(self, rhs: Self) -> Self::Output {
164c3f22262SAlexandre Courbot                 Self(self.0 | rhs.0)
165c3f22262SAlexandre Courbot             }
166c3f22262SAlexandre Courbot         }
167c3f22262SAlexandre Courbot 
168c3f22262SAlexandre Courbot         impl ::core::convert::From<$name> for u32 {
169c3f22262SAlexandre Courbot             fn from(reg: $name) -> u32 {
170c3f22262SAlexandre Courbot                 reg.0
171c3f22262SAlexandre Courbot             }
172c3f22262SAlexandre Courbot         }
173c3f22262SAlexandre Courbot     };
174c3f22262SAlexandre Courbot 
175c3f22262SAlexandre Courbot     // Defines all the field getter/methods methods for `$name`.
176c3f22262SAlexandre Courbot     (
177c3f22262SAlexandre Courbot         @field_accessors $name:ident {
178c3f22262SAlexandre Courbot         $($hi:tt:$lo:tt $field:ident as $type:tt
179c3f22262SAlexandre Courbot             $(?=> $try_into_type:ty)?
180c3f22262SAlexandre Courbot             $(=> $into_type:ty)?
181c3f22262SAlexandre Courbot             $(, $comment:literal)?
182c3f22262SAlexandre Courbot         ;
183c3f22262SAlexandre Courbot         )*
184c3f22262SAlexandre Courbot         }
185c3f22262SAlexandre Courbot     ) => {
186c3f22262SAlexandre Courbot         $(
187c3f22262SAlexandre Courbot             register!(@check_field_bounds $hi:$lo $field as $type);
188c3f22262SAlexandre Courbot         )*
189c3f22262SAlexandre Courbot 
190c3f22262SAlexandre Courbot         #[allow(dead_code)]
191c3f22262SAlexandre Courbot         impl $name {
192c3f22262SAlexandre Courbot             $(
193c3f22262SAlexandre Courbot             register!(@field_accessor $name $hi:$lo $field as $type
194c3f22262SAlexandre Courbot                 $(?=> $try_into_type)?
195c3f22262SAlexandre Courbot                 $(=> $into_type)?
196c3f22262SAlexandre Courbot                 $(, $comment)?
197c3f22262SAlexandre Courbot                 ;
198c3f22262SAlexandre Courbot             );
199c3f22262SAlexandre Courbot             )*
200c3f22262SAlexandre Courbot         }
201c3f22262SAlexandre Courbot     };
202c3f22262SAlexandre Courbot 
203c3f22262SAlexandre Courbot     // Boolean fields must have `$hi == $lo`.
204c3f22262SAlexandre Courbot     (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {
205c3f22262SAlexandre Courbot         #[allow(clippy::eq_op)]
206c3f22262SAlexandre Courbot         const _: () = {
2078d5fbb8dSAlexandre Courbot             ::kernel::build_assert!(
208c3f22262SAlexandre Courbot                 $hi == $lo,
209c3f22262SAlexandre Courbot                 concat!("boolean field `", stringify!($field), "` covers more than one bit")
210c3f22262SAlexandre Courbot             );
211c3f22262SAlexandre Courbot         };
212c3f22262SAlexandre Courbot     };
213c3f22262SAlexandre Courbot 
214c3f22262SAlexandre Courbot     // Non-boolean fields must have `$hi >= $lo`.
215c3f22262SAlexandre Courbot     (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {
216c3f22262SAlexandre Courbot         #[allow(clippy::eq_op)]
217c3f22262SAlexandre Courbot         const _: () = {
2188d5fbb8dSAlexandre Courbot             ::kernel::build_assert!(
219c3f22262SAlexandre Courbot                 $hi >= $lo,
220c3f22262SAlexandre Courbot                 concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")
221c3f22262SAlexandre Courbot             );
222c3f22262SAlexandre Courbot         };
223c3f22262SAlexandre Courbot     };
224c3f22262SAlexandre Courbot 
225c3f22262SAlexandre Courbot     // Catches fields defined as `bool` and convert them into a boolean value.
226c3f22262SAlexandre Courbot     (
227c3f22262SAlexandre Courbot         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty
228c3f22262SAlexandre Courbot             $(, $comment:literal)?;
229c3f22262SAlexandre Courbot     ) => {
230c3f22262SAlexandre Courbot         register!(
231c3f22262SAlexandre Courbot             @leaf_accessor $name $hi:$lo $field as bool
232c3f22262SAlexandre Courbot             { |f| <$into_type>::from(if f != 0 { true } else { false }) }
233c3f22262SAlexandre Courbot             $into_type => $into_type $(, $comment)?;
234c3f22262SAlexandre Courbot         );
235c3f22262SAlexandre Courbot     };
236c3f22262SAlexandre Courbot 
237c3f22262SAlexandre Courbot     // Shortcut for fields defined as `bool` without the `=>` syntax.
238c3f22262SAlexandre Courbot     (
239c3f22262SAlexandre Courbot         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?;
240c3f22262SAlexandre Courbot     ) => {
241c3f22262SAlexandre Courbot         register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;);
242c3f22262SAlexandre Courbot     };
243c3f22262SAlexandre Courbot 
244c3f22262SAlexandre Courbot     // Catches the `?=>` syntax for non-boolean fields.
245c3f22262SAlexandre Courbot     (
246c3f22262SAlexandre Courbot         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty
247c3f22262SAlexandre Courbot             $(, $comment:literal)?;
248c3f22262SAlexandre Courbot     ) => {
249c3f22262SAlexandre Courbot         register!(@leaf_accessor $name $hi:$lo $field as $type
250c3f22262SAlexandre Courbot             { |f| <$try_into_type>::try_from(f as $type) } $try_into_type =>
251c3f22262SAlexandre Courbot             ::core::result::Result<
252c3f22262SAlexandre Courbot                 $try_into_type,
253c3f22262SAlexandre Courbot                 <$try_into_type as ::core::convert::TryFrom<$type>>::Error
254c3f22262SAlexandre Courbot             >
255c3f22262SAlexandre Courbot             $(, $comment)?;);
256c3f22262SAlexandre Courbot     };
257c3f22262SAlexandre Courbot 
258c3f22262SAlexandre Courbot     // Catches the `=>` syntax for non-boolean fields.
259c3f22262SAlexandre Courbot     (
260c3f22262SAlexandre Courbot         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty
261c3f22262SAlexandre Courbot             $(, $comment:literal)?;
262c3f22262SAlexandre Courbot     ) => {
263c3f22262SAlexandre Courbot         register!(@leaf_accessor $name $hi:$lo $field as $type
264c3f22262SAlexandre Courbot             { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;);
265c3f22262SAlexandre Courbot     };
266c3f22262SAlexandre Courbot 
267c3f22262SAlexandre Courbot     // Shortcut for fields defined as non-`bool` without the `=>` or `?=>` syntax.
268c3f22262SAlexandre Courbot     (
269c3f22262SAlexandre Courbot         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt
270c3f22262SAlexandre Courbot             $(, $comment:literal)?;
271c3f22262SAlexandre Courbot     ) => {
272c3f22262SAlexandre Courbot         register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;);
273c3f22262SAlexandre Courbot     };
274c3f22262SAlexandre Courbot 
275c3f22262SAlexandre Courbot     // Generates the accessor methods for a single field.
276c3f22262SAlexandre Courbot     (
277c3f22262SAlexandre Courbot         @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:ty
278c3f22262SAlexandre Courbot             { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?;
279c3f22262SAlexandre Courbot     ) => {
2808d5fbb8dSAlexandre Courbot         ::kernel::macros::paste!(
281c3f22262SAlexandre Courbot         const [<$field:upper>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
282c3f22262SAlexandre Courbot         const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
283c3f22262SAlexandre Courbot         const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros();
284c3f22262SAlexandre Courbot         );
285c3f22262SAlexandre Courbot 
286c3f22262SAlexandre Courbot         $(
287c3f22262SAlexandre Courbot         #[doc="Returns the value of this field:"]
288c3f22262SAlexandre Courbot         #[doc=$comment]
289c3f22262SAlexandre Courbot         )?
290c3f22262SAlexandre Courbot         #[inline]
291c3f22262SAlexandre Courbot         pub(crate) fn $field(self) -> $res_type {
2928d5fbb8dSAlexandre Courbot             ::kernel::macros::paste!(
293c3f22262SAlexandre Courbot             const MASK: u32 = $name::[<$field:upper _MASK>];
294c3f22262SAlexandre Courbot             const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
295c3f22262SAlexandre Courbot             );
296c3f22262SAlexandre Courbot             let field = ((self.0 & MASK) >> SHIFT);
297c3f22262SAlexandre Courbot 
298c3f22262SAlexandre Courbot             $process(field)
299c3f22262SAlexandre Courbot         }
300c3f22262SAlexandre Courbot 
3018d5fbb8dSAlexandre Courbot         ::kernel::macros::paste!(
302c3f22262SAlexandre Courbot         $(
303c3f22262SAlexandre Courbot         #[doc="Sets the value of this field:"]
304c3f22262SAlexandre Courbot         #[doc=$comment]
305c3f22262SAlexandre Courbot         )?
306c3f22262SAlexandre Courbot         #[inline]
307c3f22262SAlexandre Courbot         pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self {
308c3f22262SAlexandre Courbot             const MASK: u32 = $name::[<$field:upper _MASK>];
309c3f22262SAlexandre Courbot             const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
310*b7c8d7a8STamir Duberstein             let value = (u32::from(value) << SHIFT) & MASK;
311c3f22262SAlexandre Courbot             self.0 = (self.0 & !MASK) | value;
312c3f22262SAlexandre Courbot 
313c3f22262SAlexandre Courbot             self
314c3f22262SAlexandre Courbot         }
315c3f22262SAlexandre Courbot         );
316c3f22262SAlexandre Courbot     };
317c3f22262SAlexandre Courbot 
318c3f22262SAlexandre Courbot     // Creates the IO accessors for a fixed offset register.
319e66aaaffSAlexandre Courbot     (@io $name:ident @ $offset:expr) => {
320c3f22262SAlexandre Courbot         #[allow(dead_code)]
321c3f22262SAlexandre Courbot         impl $name {
322c3f22262SAlexandre Courbot             #[inline]
323c3f22262SAlexandre Courbot             pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where
324c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
325c3f22262SAlexandre Courbot             {
326c3f22262SAlexandre Courbot                 Self(io.read32($offset))
327c3f22262SAlexandre Courbot             }
328c3f22262SAlexandre Courbot 
329c3f22262SAlexandre Courbot             #[inline]
330c3f22262SAlexandre Courbot             pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where
331c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
332c3f22262SAlexandre Courbot             {
333c3f22262SAlexandre Courbot                 io.write32(self.0, $offset)
334c3f22262SAlexandre Courbot             }
335c3f22262SAlexandre Courbot 
336c3f22262SAlexandre Courbot             #[inline]
337c3f22262SAlexandre Courbot             pub(crate) fn alter<const SIZE: usize, T, F>(
338c3f22262SAlexandre Courbot                 io: &T,
339c3f22262SAlexandre Courbot                 f: F,
340c3f22262SAlexandre Courbot             ) where
341c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
342c3f22262SAlexandre Courbot                 F: ::core::ops::FnOnce(Self) -> Self,
343c3f22262SAlexandre Courbot             {
344c3f22262SAlexandre Courbot                 let reg = f(Self::read(io));
345c3f22262SAlexandre Courbot                 reg.write(io);
346c3f22262SAlexandre Courbot             }
347c3f22262SAlexandre Courbot         }
348c3f22262SAlexandre Courbot     };
349c3f22262SAlexandre Courbot 
350c3f22262SAlexandre Courbot     // Create the IO accessors for a relative offset register.
351c3f22262SAlexandre Courbot     (@io $name:ident @ + $offset:literal) => {
352c3f22262SAlexandre Courbot         #[allow(dead_code)]
353c3f22262SAlexandre Courbot         impl $name {
354c3f22262SAlexandre Courbot             #[inline]
355c3f22262SAlexandre Courbot             pub(crate) fn read<const SIZE: usize, T>(
356c3f22262SAlexandre Courbot                 io: &T,
357c3f22262SAlexandre Courbot                 base: usize,
358c3f22262SAlexandre Courbot             ) -> Self where
359c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
360c3f22262SAlexandre Courbot             {
361c3f22262SAlexandre Courbot                 Self(io.read32(base + $offset))
362c3f22262SAlexandre Courbot             }
363c3f22262SAlexandre Courbot 
364c3f22262SAlexandre Courbot             #[inline]
365c3f22262SAlexandre Courbot             pub(crate) fn write<const SIZE: usize, T>(
366c3f22262SAlexandre Courbot                 self,
367c3f22262SAlexandre Courbot                 io: &T,
368c3f22262SAlexandre Courbot                 base: usize,
369c3f22262SAlexandre Courbot             ) where
370c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
371c3f22262SAlexandre Courbot             {
372c3f22262SAlexandre Courbot                 io.write32(self.0, base + $offset)
373c3f22262SAlexandre Courbot             }
374c3f22262SAlexandre Courbot 
375c3f22262SAlexandre Courbot             #[inline]
376c3f22262SAlexandre Courbot             pub(crate) fn alter<const SIZE: usize, T, F>(
377c3f22262SAlexandre Courbot                 io: &T,
378c3f22262SAlexandre Courbot                 base: usize,
379c3f22262SAlexandre Courbot                 f: F,
380c3f22262SAlexandre Courbot             ) where
381c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
382c3f22262SAlexandre Courbot                 F: ::core::ops::FnOnce(Self) -> Self,
383c3f22262SAlexandre Courbot             {
384c3f22262SAlexandre Courbot                 let reg = f(Self::read(io, base));
385c3f22262SAlexandre Courbot                 reg.write(io, base);
386c3f22262SAlexandre Courbot             }
387c3f22262SAlexandre Courbot 
388c3f22262SAlexandre Courbot             #[inline]
389c3f22262SAlexandre Courbot             pub(crate) fn try_read<const SIZE: usize, T>(
390c3f22262SAlexandre Courbot                 io: &T,
391c3f22262SAlexandre Courbot                 base: usize,
392c3f22262SAlexandre Courbot             ) -> ::kernel::error::Result<Self> where
393c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
394c3f22262SAlexandre Courbot             {
395c3f22262SAlexandre Courbot                 io.try_read32(base + $offset).map(Self)
396c3f22262SAlexandre Courbot             }
397c3f22262SAlexandre Courbot 
398c3f22262SAlexandre Courbot             #[inline]
399c3f22262SAlexandre Courbot             pub(crate) fn try_write<const SIZE: usize, T>(
400c3f22262SAlexandre Courbot                 self,
401c3f22262SAlexandre Courbot                 io: &T,
402c3f22262SAlexandre Courbot                 base: usize,
403c3f22262SAlexandre Courbot             ) -> ::kernel::error::Result<()> where
404c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
405c3f22262SAlexandre Courbot             {
406c3f22262SAlexandre Courbot                 io.try_write32(self.0, base + $offset)
407c3f22262SAlexandre Courbot             }
408c3f22262SAlexandre Courbot 
409c3f22262SAlexandre Courbot             #[inline]
410c3f22262SAlexandre Courbot             pub(crate) fn try_alter<const SIZE: usize, T, F>(
411c3f22262SAlexandre Courbot                 io: &T,
412c3f22262SAlexandre Courbot                 base: usize,
413c3f22262SAlexandre Courbot                 f: F,
414c3f22262SAlexandre Courbot             ) -> ::kernel::error::Result<()> where
415c3f22262SAlexandre Courbot                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
416c3f22262SAlexandre Courbot                 F: ::core::ops::FnOnce(Self) -> Self,
417c3f22262SAlexandre Courbot             {
418c3f22262SAlexandre Courbot                 let reg = f(Self::try_read(io, base)?);
419c3f22262SAlexandre Courbot                 reg.try_write(io, base)
420c3f22262SAlexandre Courbot             }
421c3f22262SAlexandre Courbot         }
422c3f22262SAlexandre Courbot     };
423c3f22262SAlexandre Courbot }
424