xref: /linux/rust/kernel/io/register.rs (revision 4793dae01f47754e288cdbb3a22581cac2317f2b)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Macro to define register layout and accessors.
4 //!
5 //! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for
6 //! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such
7 //! type comes with its own field accessors that can return an error if a field's value is invalid.
8 //!
9 //! Note: most of the items in this module are public so they can be referenced by the macro, but
10 //! most are not to be used directly by users. Outside of the `register!` macro itself, the only
11 //! items you might want to import from this module are [`WithBase`] and [`Array`].
12 //!
13 //! # Simple example
14 //!
15 //! ```no_run
16 //! use kernel::io::register;
17 //!
18 //! register! {
19 //!     /// Basic information about the chip.
20 //!     pub BOOT_0(u32) @ 0x00000100 {
21 //!         /// Vendor ID.
22 //!         15:8 vendor_id;
23 //!         /// Major revision of the chip.
24 //!         7:4 major_revision;
25 //!         /// Minor revision of the chip.
26 //!         3:0 minor_revision;
27 //!     }
28 //! }
29 //! ```
30 //!
31 //! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an
32 //! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 4
33 //! least significant bits of the type.
34 //!
35 //! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their
36 //! getter method, which is named after them. They also have setter methods prefixed with `with_`
37 //! for runtime values and `with_const_` for constant values. All setters return the updated
38 //! register value.
39 //!
40 //! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and
41 //! `?=>` syntaxes.
42 //!
43 //! If present, doc comments above register or fields definitions are added to the relevant item
44 //! they document (the register type itself, or the field's setter and getter methods).
45 //!
46 //! Note that multiple registers can be defined in a single `register!` invocation. This can be
47 //! useful to group related registers together.
48 //!
49 //! Here is how the register defined above can be used in code:
50 //!
51 //!
52 //! ```no_run
53 //! use kernel::{
54 //!     io::{
55 //!         register,
56 //!         Io,
57 //!         IoLoc,
58 //!     },
59 //!     num::Bounded,
60 //! };
61 //! # use kernel::io::Mmio;
62 //! # register! {
63 //! #     pub BOOT_0(u32) @ 0x00000100 {
64 //! #         15:8 vendor_id;
65 //! #         7:4 major_revision;
66 //! #         3:0 minor_revision;
67 //! #     }
68 //! # }
69 //! # fn test(io: &Mmio<0x1000>) {
70 //! # fn obtain_vendor_id() -> u8 { 0xff }
71 //!
72 //! // Read from the register's defined offset (0x100).
73 //! let boot0 = io.read(BOOT_0);
74 //! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get());
75 //!
76 //! // Update some fields and write the new value back.
77 //! let new_boot0 = boot0
78 //!     // Constant values.
79 //!     .with_const_major_revision::<3>()
80 //!     .with_const_minor_revision::<10>()
81 //!     // Runtime value.
82 //!     .with_vendor_id(obtain_vendor_id());
83 //! io.write_reg(new_boot0);
84 //!
85 //! // Or, build a new value from zero and write it:
86 //! io.write_reg(BOOT_0::zeroed()
87 //!     .with_const_major_revision::<3>()
88 //!     .with_const_minor_revision::<10>()
89 //!     .with_vendor_id(obtain_vendor_id())
90 //! );
91 //!
92 //! // Or, read and update the register in a single step.
93 //! io.update(BOOT_0, |r| r
94 //!     .with_const_major_revision::<3>()
95 //!     .with_const_minor_revision::<10>()
96 //!     .with_vendor_id(obtain_vendor_id())
97 //! );
98 //!
99 //! // Constant values can also be built using the const setters.
100 //! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>()
101 //!     .with_const_major_revision::<3>()
102 //!     .with_const_minor_revision::<10>();
103 //! # }
104 //! ```
105 //!
106 //! For more extensive documentation about how to define registers, see the
107 //! [`register!`](kernel::io::register!) macro.
108 
109 use core::marker::PhantomData;
110 
111 use crate::io::IoLoc;
112 
113 use kernel::build_assert;
114 
115 /// Trait implemented by all registers.
116 pub trait Register: Sized {
117     /// Backing primitive type of the register.
118     type Storage: Into<Self> + From<Self>;
119 
120     /// Start offset of the register.
121     ///
122     /// The interpretation of this offset depends on the type of the register.
123     const OFFSET: usize;
124 }
125 
126 /// Trait implemented by registers with a fixed offset.
127 pub trait FixedRegister: Register {}
128 
129 /// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when
130 /// passing a [`FixedRegister`] value.
131 impl<T> IoLoc<T> for ()
132 where
133     T: FixedRegister,
134 {
135     type IoType = T::Storage;
136 
137     #[inline(always)]
offset(self) -> usize138     fn offset(self) -> usize {
139         T::OFFSET
140     }
141 }
142 
143 /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used
144 /// as an [`IoLoc`].
145 impl<T> IoLoc<T> for T
146 where
147     T: FixedRegister,
148 {
149     type IoType = T::Storage;
150 
151     #[inline(always)]
offset(self) -> usize152     fn offset(self) -> usize {
153         T::OFFSET
154     }
155 }
156 
157 /// Location of a fixed register.
158 pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>);
159 
160 impl<T: FixedRegister> FixedRegisterLoc<T> {
161     /// Returns the location of `T`.
162     #[inline(always)]
163     // We do not implement `Default` so we can be const.
164     #[expect(clippy::new_without_default)]
new() -> Self165     pub const fn new() -> Self {
166         Self(PhantomData)
167     }
168 }
169 
170 impl<T> IoLoc<T> for FixedRegisterLoc<T>
171 where
172     T: FixedRegister,
173 {
174     type IoType = T::Storage;
175 
176     #[inline(always)]
offset(self) -> usize177     fn offset(self) -> usize {
178         T::OFFSET
179     }
180 }
181 
182 /// Trait providing a base address to be added to the offset of a relative register to obtain
183 /// its actual offset.
184 ///
185 /// The `T` generic argument is used to distinguish which base to use, in case a type provides
186 /// several bases. It is given to the `register!` macro to restrict the use of the register to
187 /// implementors of this particular variant.
188 pub trait RegisterBase<T> {
189     /// Base address to which register offsets are added.
190     const BASE: usize;
191 }
192 
193 /// Trait implemented by all registers that are relative to a base.
194 pub trait WithBase {
195     /// Family of bases applicable to this register.
196     type BaseFamily;
197 
198     /// Returns the absolute location of this type when using `B` as its base.
199     #[inline(always)]
of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B> where Self: Register,200     fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B>
201     where
202         Self: Register,
203     {
204         RelativeRegisterLoc::new()
205     }
206 }
207 
208 /// Trait implemented by relative registers.
209 pub trait RelativeRegister: Register + WithBase {}
210 
211 /// Location of a relative register.
212 ///
213 /// This can either be an immediately accessible regular [`RelativeRegister`], or a
214 /// [`RelativeRegisterArray`] that needs one additional resolution through
215 /// [`RelativeRegisterLoc::at`].
216 pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>);
217 
218 impl<T, B> RelativeRegisterLoc<T, B>
219 where
220     T: Register + WithBase,
221     B: RegisterBase<T::BaseFamily> + ?Sized,
222 {
223     /// Returns the location of a relative register or register array.
224     #[inline(always)]
225     // We do not implement `Default` so we can be const.
226     #[expect(clippy::new_without_default)]
new() -> Self227     pub const fn new() -> Self {
228         Self(PhantomData, PhantomData)
229     }
230 
231     // Returns the absolute offset of the relative register using base `B`.
232     //
233     // This is implemented as a private const method so it can be reused by the [`IoLoc`]
234     // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`].
235     #[inline]
offset(self) -> usize236     const fn offset(self) -> usize {
237         B::BASE + T::OFFSET
238     }
239 }
240 
241 impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B>
242 where
243     T: RelativeRegister,
244     B: RegisterBase<T::BaseFamily> + ?Sized,
245 {
246     type IoType = T::Storage;
247 
248     #[inline(always)]
offset(self) -> usize249     fn offset(self) -> usize {
250         RelativeRegisterLoc::offset(self)
251     }
252 }
253 
254 /// Trait implemented by arrays of registers.
255 pub trait RegisterArray: Register {
256     /// Number of elements in the registers array.
257     const SIZE: usize;
258     /// Number of bytes between the start of elements in the registers array.
259     const STRIDE: usize;
260 }
261 
262 /// Location of an array register.
263 pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>);
264 
265 impl<T: RegisterArray> RegisterArrayLoc<T> {
266     /// Returns the location of register `T` at position `idx`, with build-time validation.
267     #[inline(always)]
new(idx: usize) -> Self268     pub fn new(idx: usize) -> Self {
269         build_assert!(idx < T::SIZE);
270 
271         Self(idx, PhantomData)
272     }
273 
274     /// Attempts to return the location of register `T` at position `idx`, with runtime validation.
275     #[inline(always)]
try_new(idx: usize) -> Option<Self>276     pub fn try_new(idx: usize) -> Option<Self> {
277         if idx < T::SIZE {
278             Some(Self(idx, PhantomData))
279         } else {
280             None
281         }
282     }
283 }
284 
285 impl<T> IoLoc<T> for RegisterArrayLoc<T>
286 where
287     T: RegisterArray,
288 {
289     type IoType = T::Storage;
290 
291     #[inline(always)]
offset(self) -> usize292     fn offset(self) -> usize {
293         T::OFFSET + self.0 * T::STRIDE
294     }
295 }
296 
297 /// Trait providing location builders for [`RegisterArray`]s.
298 pub trait Array {
299     /// Returns the location of the register at position `idx`, with build-time validation.
300     #[inline(always)]
at(idx: usize) -> RegisterArrayLoc<Self> where Self: RegisterArray,301     fn at(idx: usize) -> RegisterArrayLoc<Self>
302     where
303         Self: RegisterArray,
304     {
305         RegisterArrayLoc::new(idx)
306     }
307 
308     /// Returns the location of the register at position `idx`, with runtime validation.
309     #[inline(always)]
try_at(idx: usize) -> Option<RegisterArrayLoc<Self>> where Self: RegisterArray,310     fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>>
311     where
312         Self: RegisterArray,
313     {
314         RegisterArrayLoc::try_new(idx)
315     }
316 }
317 
318 /// Trait implemented by arrays of relative registers.
319 pub trait RelativeRegisterArray: RegisterArray + WithBase {}
320 
321 /// Location of a relative array register.
322 pub struct RelativeRegisterArrayLoc<
323     T: RelativeRegisterArray,
324     B: RegisterBase<T::BaseFamily> + ?Sized,
325 >(RelativeRegisterLoc<T, B>, usize);
326 
327 impl<T, B> RelativeRegisterArrayLoc<T, B>
328 where
329     T: RelativeRegisterArray,
330     B: RegisterBase<T::BaseFamily> + ?Sized,
331 {
332     /// Returns the location of register `T` from the base `B` at index `idx`, with build-time
333     /// validation.
334     #[inline(always)]
new(idx: usize) -> Self335     pub fn new(idx: usize) -> Self {
336         build_assert!(idx < T::SIZE);
337 
338         Self(RelativeRegisterLoc::new(), idx)
339     }
340 
341     /// Attempts to return the location of register `T` from the base `B` at index `idx`, with
342     /// runtime validation.
343     #[inline(always)]
try_new(idx: usize) -> Option<Self>344     pub fn try_new(idx: usize) -> Option<Self> {
345         if idx < T::SIZE {
346             Some(Self(RelativeRegisterLoc::new(), idx))
347         } else {
348             None
349         }
350     }
351 }
352 
353 /// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`].
354 impl<T, B> RelativeRegisterLoc<T, B>
355 where
356     T: RelativeRegisterArray,
357     B: RegisterBase<T::BaseFamily> + ?Sized,
358 {
359     /// Returns the location of the register at position `idx`, with build-time validation.
360     #[inline(always)]
at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B>361     pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> {
362         RelativeRegisterArrayLoc::new(idx)
363     }
364 
365     /// Returns the location of the register at position `idx`, with runtime validation.
366     #[inline(always)]
try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>>367     pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> {
368         RelativeRegisterArrayLoc::try_new(idx)
369     }
370 }
371 
372 impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B>
373 where
374     T: RelativeRegisterArray,
375     B: RegisterBase<T::BaseFamily> + ?Sized,
376 {
377     type IoType = T::Storage;
378 
379     #[inline(always)]
offset(self) -> usize380     fn offset(self) -> usize {
381         self.0.offset() + self.1 * T::STRIDE
382     }
383 }
384 
385 /// Trait implemented by items that contain both a register value and the absolute I/O location at
386 /// which to write it.
387 ///
388 /// Implementors can be used with [`Io::write_reg`](super::Io::write_reg).
389 pub trait LocatedRegister {
390     /// Register value to write.
391     type Value: Register;
392     /// Full location information at which to write the value.
393     type Location: IoLoc<Self::Value>;
394 
395     /// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write
396     /// operation.
into_io_op(self) -> (Self::Location, Self::Value)397     fn into_io_op(self) -> (Self::Location, Self::Value);
398 }
399 
400 impl<T> LocatedRegister for T
401 where
402     T: FixedRegister,
403 {
404     type Location = FixedRegisterLoc<Self::Value>;
405     type Value = T;
406 
407     #[inline(always)]
into_io_op(self) -> (FixedRegisterLoc<T>, T)408     fn into_io_op(self) -> (FixedRegisterLoc<T>, T) {
409         (FixedRegisterLoc::new(), self)
410     }
411 }
412 
413 /// Defines a dedicated type for a register, including getter and setter methods for its fields and
414 /// methods to read and write it from an [`Io`](kernel::io::Io) region.
415 ///
416 /// This documentation focuses on how to declare registers. See the [module-level
417 /// documentation](mod@kernel::io::register) for examples of how to access them.
418 ///
419 /// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of
420 /// registers, and relative arrays of registers.
421 ///
422 /// ## Fixed offset registers
423 ///
424 /// These are the simplest kind of registers. Their location is simply an offset inside the I/O
425 /// region. For instance:
426 ///
427 /// ```ignore
428 /// register! {
429 ///     pub FIXED_REG(u16) @ 0x80 {
430 ///         ...
431 ///     }
432 /// }
433 /// ```
434 ///
435 /// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region.
436 ///
437 /// These registers' location can be built simply by referencing their name:
438 ///
439 /// ```no_run
440 /// use kernel::{
441 ///     io::{
442 ///         register,
443 ///         Io,
444 ///     },
445 /// };
446 /// # use kernel::io::Mmio;
447 ///
448 /// register! {
449 ///     FIXED_REG(u32) @ 0x100 {
450 ///         16:8 high_byte;
451 ///         7:0  low_byte;
452 ///     }
453 /// }
454 ///
455 /// # fn test(io: &Mmio<0x1000>) {
456 /// let val = io.read(FIXED_REG);
457 ///
458 /// // Write from an already-existing value.
459 /// io.write(FIXED_REG, val.with_low_byte(0xff));
460 ///
461 /// // Create a register value from scratch.
462 /// let val2 = FIXED_REG::zeroed().with_high_byte(0x80);
463 ///
464 /// // The location of fixed offset registers is already contained in their type. Thus, the
465 /// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`.
466 /// io.write((), val2);
467 ///
468 /// // Or, the single-argument `Io::write_reg` can be used.
469 /// io.write_reg(val2);
470 /// # }
471 ///
472 /// ```
473 ///
474 /// It is possible to create an alias of an existing register with new field definitions by using
475 /// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on
476 /// the context:
477 ///
478 /// ```no_run
479 /// use kernel::io::register;
480 ///
481 /// register! {
482 ///     /// Scratch register.
483 ///     pub SCRATCH(u32) @ 0x00000200 {
484 ///         31:0 value;
485 ///     }
486 ///
487 ///     /// Boot status of the firmware.
488 ///     pub SCRATCH_BOOT_STATUS(u32) => SCRATCH {
489 ///         0:0 completed;
490 ///     }
491 /// }
492 /// ```
493 ///
494 /// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing
495 /// its own `completed` field.
496 ///
497 /// ## Relative registers
498 ///
499 /// Relative registers can be instantiated several times at a relative offset of a group of bases.
500 /// For instance, imagine the following I/O space:
501 ///
502 /// ```text
503 ///           +-----------------------------+
504 ///           |             ...             |
505 ///           |                             |
506 ///  0x100--->+------------CPU0-------------+
507 ///           |                             |
508 ///  0x110--->+-----------------------------+
509 ///           |           CPU_CTL           |
510 ///           +-----------------------------+
511 ///           |             ...             |
512 ///           |                             |
513 ///           |                             |
514 ///  0x200--->+------------CPU1-------------+
515 ///           |                             |
516 ///  0x210--->+-----------------------------+
517 ///           |           CPU_CTL           |
518 ///           +-----------------------------+
519 ///           |             ...             |
520 ///           +-----------------------------+
521 /// ```
522 ///
523 /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O
524 /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define
525 /// them twice and would prefer a way to select which one to use from a single definition.
526 ///
527 /// This can be done using the `Base + Offset` syntax when specifying the register's address:
528 ///
529 /// ```ignore
530 /// register! {
531 ///     pub RELATIVE_REG(u32) @ Base + 0x80 {
532 ///         ...
533 ///     }
534 /// }
535 /// ```
536 ///
537 /// This creates a register with an offset of `0x80` from a given base.
538 ///
539 /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the
540 /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for
541 /// this register needs to implement `RegisterBase<Base>`.
542 ///
543 /// The location of relative registers can be built using the [`WithBase::of`] method to specify
544 /// its base. All relative registers implement [`WithBase`].
545 ///
546 /// Here is the above layout translated into code:
547 ///
548 /// ```no_run
549 /// use kernel::{
550 ///     io::{
551 ///         register,
552 ///         register::{
553 ///             RegisterBase,
554 ///             WithBase,
555 ///         },
556 ///         Io,
557 ///     },
558 /// };
559 /// # use kernel::io::Mmio;
560 ///
561 /// // Type used to identify the base.
562 /// pub struct CpuCtlBase;
563 ///
564 /// // ZST describing `CPU0`.
565 /// struct Cpu0;
566 /// impl RegisterBase<CpuCtlBase> for Cpu0 {
567 ///     const BASE: usize = 0x100;
568 /// }
569 ///
570 /// // ZST describing `CPU1`.
571 /// struct Cpu1;
572 /// impl RegisterBase<CpuCtlBase> for Cpu1 {
573 ///     const BASE: usize = 0x200;
574 /// }
575 ///
576 /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`.
577 /// register! {
578 ///     /// CPU core control.
579 ///     pub CPU_CTL(u32) @ CpuCtlBase + 0x10 {
580 ///         0:0 start;
581 ///     }
582 /// }
583 ///
584 /// # fn test(io: Mmio<0x1000>) {
585 /// // Read the status of `Cpu0`.
586 /// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>());
587 ///
588 /// // Stop `Cpu0`.
589 /// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed());
590 /// # }
591 ///
592 /// // Aliases can also be defined for relative register.
593 /// register! {
594 ///     /// Alias to CPU core control.
595 ///     pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL {
596 ///         /// Start the aliased CPU core.
597 ///         1:1 alias_start;
598 ///     }
599 /// }
600 ///
601 /// # fn test2(io: Mmio<0x1000>) {
602 /// // Start the aliased `CPU0`, leaving its other fields untouched.
603 /// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true));
604 /// # }
605 /// ```
606 ///
607 /// ## Arrays of registers
608 ///
609 /// Some I/O areas contain consecutive registers that share the same field layout. These areas can
610 /// be defined as an array of identical registers, allowing them to be accessed by index with
611 /// compile-time or runtime bound checking:
612 ///
613 /// ```ignore
614 /// register! {
615 ///     pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 {
616 ///         ...
617 ///     }
618 /// }
619 /// ```
620 ///
621 /// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each
622 /// register is separated from its neighbor by 4 bytes.
623 ///
624 /// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from
625 /// each other.
626 ///
627 /// A location for a register in a register array is built using the [`Array::at`] trait method.
628 /// All arrays of registers implement [`Array`].
629 ///
630 /// ```no_run
631 /// use kernel::{
632 ///     io::{
633 ///         register,
634 ///         register::Array,
635 ///         Io,
636 ///     },
637 /// };
638 /// # use kernel::io::Mmio;
639 /// # fn get_scratch_idx() -> usize {
640 /// #   0x15
641 /// # }
642 ///
643 /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`.
644 /// register! {
645 ///     /// Scratch registers.
646 ///     pub SCRATCH(u32)[64] @ 0x00000080 {
647 ///         31:0 value;
648 ///     }
649 /// }
650 ///
651 /// # fn test(io: &Mmio<0x1000>)
652 /// #     -> Result<(), Error>{
653 /// // Read scratch register 0, i.e. I/O address `0x80`.
654 /// let scratch_0 = io.read(SCRATCH::at(0)).value();
655 ///
656 /// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`.
657 /// io.write(Array::at(15), SCRATCH::from(0xffeeaabb));
658 ///
659 /// // This is out of bounds and won't build.
660 /// // let scratch_128 = io.read(SCRATCH::at(128)).value();
661 ///
662 /// // Runtime-obtained array index.
663 /// let idx = get_scratch_idx();
664 /// // Access on a runtime index returns an error if it is out-of-bounds.
665 /// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value();
666 ///
667 /// // Alias to a specific register in an array.
668 /// // Here `SCRATCH[8]` is used to convey the firmware exit code.
669 /// register! {
670 ///     /// Firmware exit status code.
671 ///     pub FIRMWARE_STATUS(u32) => SCRATCH[8] {
672 ///         7:0 status;
673 ///     }
674 /// }
675 ///
676 /// let status = io.read(FIRMWARE_STATUS).status();
677 ///
678 /// // Non-contiguous register arrays can be defined by adding a stride parameter.
679 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the
680 /// // registers of the two declarations below are interleaved.
681 /// register! {
682 ///     /// Scratch registers bank 0.
683 ///     pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 {
684 ///         31:0 value;
685 ///     }
686 ///
687 ///     /// Scratch registers bank 1.
688 ///     pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 {
689 ///         31:0 value;
690 ///     }
691 /// }
692 /// # Ok(())
693 /// # }
694 /// ```
695 ///
696 /// ## Relative arrays of registers
697 ///
698 /// Combining the two features described in the sections above, arrays of registers accessible from
699 /// a base can also be defined:
700 ///
701 /// ```ignore
702 /// register! {
703 ///     pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 {
704 ///         ...
705 ///     }
706 /// }
707 /// ```
708 ///
709 /// Like relative registers, they implement the [`WithBase`] trait. However the return value of
710 /// [`WithBase::of`] cannot be used directly as a location and must be further specified using the
711 /// [`at`](RelativeRegisterLoc::at) method.
712 ///
713 /// ```no_run
714 /// use kernel::{
715 ///     io::{
716 ///         register,
717 ///         register::{
718 ///             RegisterBase,
719 ///             WithBase,
720 ///         },
721 ///         Io,
722 ///     },
723 /// };
724 /// # use kernel::io::Mmio;
725 /// # fn get_scratch_idx() -> usize {
726 /// #   0x15
727 /// # }
728 ///
729 /// // Type used as parameter of `RegisterBase` to specify the base.
730 /// pub struct CpuCtlBase;
731 ///
732 /// // ZST describing `CPU0`.
733 /// struct Cpu0;
734 /// impl RegisterBase<CpuCtlBase> for Cpu0 {
735 ///     const BASE: usize = 0x100;
736 /// }
737 ///
738 /// // ZST describing `CPU1`.
739 /// struct Cpu1;
740 /// impl RegisterBase<CpuCtlBase> for Cpu1 {
741 ///     const BASE: usize = 0x200;
742 /// }
743 ///
744 /// // 64 per-cpu scratch registers, arranged as a contiguous array.
745 /// register! {
746 ///     /// Per-CPU scratch registers.
747 ///     pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 {
748 ///         31:0 value;
749 ///     }
750 /// }
751 ///
752 /// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> {
753 /// // Read scratch register 0 of CPU0.
754 /// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0));
755 ///
756 /// // Write the retrieved value into scratch register 15 of CPU1.
757 /// io.write(WithBase::of::<Cpu1>().at(15), scratch);
758 ///
759 /// // This won't build.
760 /// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value();
761 ///
762 /// // Runtime-obtained array index.
763 /// let scratch_idx = get_scratch_idx();
764 /// // Access on a runtime index returns an error if it is out-of-bounds.
765 /// let cpu0_scratch = io.read(
766 ///     CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)?
767 /// ).value();
768 /// # Ok(())
769 /// # }
770 ///
771 /// // Alias to `SCRATCH[8]` used to convey the firmware exit code.
772 /// register! {
773 ///     /// Per-CPU firmware exit status code.
774 ///     pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] {
775 ///         7:0 status;
776 ///     }
777 /// }
778 ///
779 /// // Non-contiguous relative register arrays can be defined by adding a stride parameter.
780 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the
781 /// // registers of the two declarations below are interleaved.
782 /// register! {
783 ///     /// Scratch registers bank 0.
784 ///     pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 {
785 ///         31:0 value;
786 ///     }
787 ///
788 ///     /// Scratch registers bank 1.
789 ///     pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 {
790 ///         31:0 value;
791 ///     }
792 /// }
793 ///
794 /// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> {
795 /// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status();
796 /// # Ok(())
797 /// # }
798 /// ```
799 #[macro_export]
800 macro_rules! register {
801     // Entry point for the macro, allowing multiple registers to be defined in one call.
802     // It matches all possible register declaration patterns to dispatch them to corresponding
803     // `@reg` rule that defines a single register.
804     (
805         $(
806             $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
807                 $([ $size:expr $(, stride = $stride:expr)? ])?
808                 $(@ $($base:ident +)? $offset:literal)?
809                 $(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )?
810             { $($fields:tt)* }
811         )*
812     ) => {
813         $(
814         $crate::register!(
815             @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])?
816                 $(@ $($base +)? $offset)?
817                 $(=> $alias $(+ $alias_offset)? $([$alias_idx])? )?
818             { $($fields)* }
819         );
820         )*
821     };
822 
823     // All the rules below are private helpers.
824 
825     // Creates a register at a fixed offset of the MMIO space.
826     (
827         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal
828             { $($fields:tt)* }
829     ) => {
830         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
831         $crate::register!(@io_base $name($storage) @ $offset);
832         $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
833     };
834 
835     // Creates an alias register of fixed offset register `alias` with its own fields.
836     (
837         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident
838             { $($fields:tt)* }
839     ) => {
840         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
841         $crate::register!(
842             @io_base $name($storage) @
843             <$alias as $crate::io::register::Register>::OFFSET
844         );
845         $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
846     };
847 
848     // Creates a register at a relative offset from a base address provider.
849     (
850         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal
851             { $($fields:tt)* }
852     ) => {
853         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
854         $crate::register!(@io_base $name($storage) @ $offset);
855         $crate::register!(@io_relative $vis $name($storage) @ $base);
856     };
857 
858     // Creates an alias register of relative offset register `alias` with its own fields.
859     (
860         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident
861             { $($fields:tt)* }
862     ) => {
863         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
864         $crate::register!(
865             @io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET
866         );
867         $crate::register!(@io_relative $vis $name($storage) @ $base);
868     };
869 
870     // Creates an array of registers at a fixed offset of the MMIO space.
871     (
872         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
873             [ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* }
874     ) => {
875         ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);
876 
877         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
878         $crate::register!(@io_base $name($storage) @ $offset);
879         $crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]);
880     };
881 
882     // Shortcut for contiguous array of registers (stride == size of element).
883     (
884         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal
885             { $($fields:tt)* }
886     ) => {
887         $crate::register!(
888             $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]
889                 @ $offset { $($fields)* }
890         );
891     };
892 
893     // Creates an alias of register `idx` of array of registers `alias` with its own fields.
894     (
895         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ]
896             { $($fields:tt)* }
897     ) => {
898         ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);
899 
900         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
901         $crate::register!(
902             @io_base $name($storage) @
903             <$alias as $crate::io::register::Register>::OFFSET
904                 + $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE
905         );
906         $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));
907     };
908 
909     // Creates an array of registers at a relative offset from a base address provider.
910     (
911         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
912             [ $size:expr, stride = $stride:expr ]
913             @ $base:ident + $offset:literal { $($fields:tt)* }
914     ) => {
915         ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);
916 
917         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
918         $crate::register!(@io_base $name($storage) @ $offset);
919         $crate::register!(
920             @io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset
921         );
922     };
923 
924     // Shortcut for contiguous array of relative registers (stride == size of element).
925     (
926         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ]
927             @ $base:ident + $offset:literal { $($fields:tt)* }
928     ) => {
929         $crate::register!(
930             $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]
931                 @ $base + $offset { $($fields)* }
932         );
933     };
934 
935     // Creates an alias of register `idx` of relative array of registers `alias` with its own
936     // fields.
937     (
938         @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)
939             => $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* }
940     ) => {
941         ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);
942 
943         $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });
944         $crate::register!(
945             @io_base $name($storage) @
946                 <$alias as $crate::io::register::Register>::OFFSET +
947                 $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE
948         );
949         $crate::register!(@io_relative $vis $name($storage) @ $base);
950     };
951 
952     // Generates the bitfield for the register.
953     //
954     // `#[allow(non_camel_case_types)]` is added since register names typically use
955     // `SCREAMING_CASE`.
956     (
957         @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }
958     ) => {
959         $crate::register!(@bitfield_core
960             #[allow(non_camel_case_types)]
961             $(#[$attr])* $vis $name $storage
962         );
963         $crate::register!(@bitfield_fields $vis $name $storage { $($fields)* });
964     };
965 
966     // Implementations shared by all registers types.
967     (@io_base $name:ident($storage:ty) @ $offset:expr) => {
968         impl $crate::io::register::Register for $name {
969             type Storage = $storage;
970 
971             const OFFSET: usize = $offset;
972         }
973     };
974 
975     // Implementations of fixed registers.
976     (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => {
977         impl $crate::io::register::FixedRegister for $name {}
978 
979         $(#[$attr])*
980         $vis const $name: $crate::io::register::FixedRegisterLoc<$name> =
981             $crate::io::register::FixedRegisterLoc::<$name>::new();
982     };
983 
984     // Implementations of relative registers.
985     (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => {
986         impl $crate::io::register::WithBase for $name {
987             type BaseFamily = $base;
988         }
989 
990         impl $crate::io::register::RelativeRegister for $name {}
991     };
992 
993     // Implementations of register arrays.
994     (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => {
995         impl $crate::io::register::Array for $name {}
996 
997         impl $crate::io::register::RegisterArray for $name {
998             const SIZE: usize = $size;
999             const STRIDE: usize = $stride;
1000         }
1001     };
1002 
1003     // Implementations of relative array registers.
1004     (
1005         @io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]
1006             @ $base:ident + $offset:literal
1007     ) => {
1008         impl $crate::io::register::WithBase for $name {
1009             type BaseFamily = $base;
1010         }
1011 
1012         impl $crate::io::register::RegisterArray for $name {
1013             const SIZE: usize = $size;
1014             const STRIDE: usize = $stride;
1015         }
1016 
1017         impl $crate::io::register::RelativeRegisterArray for $name {}
1018     };
1019 
1020     // Defines the wrapper `$name` type and its conversions from/to the storage type.
1021     (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {
1022         $(#[$attr])*
1023         #[repr(transparent)]
1024         #[derive(Clone, Copy, PartialEq, Eq)]
1025         $vis struct $name {
1026             inner: $storage,
1027         }
1028 
1029         #[allow(dead_code)]
1030         impl $name {
1031             /// Creates a bitfield from a raw value.
1032             #[inline(always)]
1033             $vis const fn from_raw(value: $storage) -> Self {
1034                 Self{ inner: value }
1035             }
1036 
1037             /// Turns this bitfield into its raw value.
1038             ///
1039             /// This is similar to the [`From`] implementation, but is shorter to invoke in
1040             /// most cases.
1041             #[inline(always)]
1042             $vis const fn into_raw(self) -> $storage {
1043                 self.inner
1044             }
1045         }
1046 
1047         // SAFETY: `$storage` is `Zeroable` and `$name` is transparent.
1048         unsafe impl ::pin_init::Zeroable for $name {}
1049 
1050         impl ::core::convert::From<$name> for $storage {
1051             #[inline(always)]
1052             fn from(val: $name) -> $storage {
1053                 val.into_raw()
1054             }
1055         }
1056 
1057         impl ::core::convert::From<$storage> for $name {
1058             #[inline(always)]
1059             fn from(val: $storage) -> $name {
1060                 Self::from_raw(val)
1061             }
1062         }
1063     };
1064 
1065     // Definitions requiring knowledge of individual fields: private and public field accessors,
1066     // and `Debug` implementation.
1067     (@bitfield_fields $vis:vis $name:ident $storage:ty {
1068         $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident
1069             $(?=> $try_into_type:ty)?
1070             $(=> $into_type:ty)?
1071         ;
1072         )*
1073     }
1074     ) => {
1075         #[allow(dead_code)]
1076         impl $name {
1077         $(
1078         $crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field);
1079         $crate::register!(
1080             @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field
1081             $(?=> $try_into_type)?
1082             $(=> $into_type)?
1083         );
1084         )*
1085         }
1086 
1087         $crate::register!(@debug $name { $($field;)* });
1088     };
1089 
1090     // Private field accessors working with the exact `Bounded` type for the field.
1091     (
1092         @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident
1093     ) => {
1094         ::kernel::macros::paste!(
1095         $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
1096         $vis const [<$field:upper _MASK>]: $storage =
1097             ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
1098         $vis const [<$field:upper _SHIFT>]: u32 = $lo;
1099         );
1100 
1101         ::kernel::macros::paste!(
1102         fn [<__ $field>](self) ->
1103             ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {
1104             // Left shift to align the field's MSB with the storage MSB.
1105             const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);
1106             // Right shift to move the top-aligned field to bit 0 of the storage.
1107             const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;
1108 
1109             // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized
1110             // output type.
1111             let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(
1112                 self.inner << ALIGN_TOP
1113             );
1114             val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()
1115         }
1116 
1117         const fn [<__with_ $field>](
1118             mut self,
1119             value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,
1120         ) -> Self
1121         {
1122             const MASK: $storage = <$name>::[<$field:upper _MASK>];
1123             const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];
1124 
1125             let value = value.get() << SHIFT;
1126             self.inner = (self.inner & !MASK) | value;
1127 
1128             self
1129         }
1130         );
1131     };
1132 
1133     // Public accessors for fields infallibly (`=>`) converted to a type.
1134     (
1135         @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1136             $hi:literal:$lo:literal $field:ident => $into_type:ty
1137     ) => {
1138         ::kernel::macros::paste!(
1139 
1140         $(#[doc = $doc])*
1141         #[doc = "Returns the value of this field."]
1142         #[inline(always)]
1143         $vis fn $field(self) -> $into_type
1144         {
1145             self.[<__ $field>]().into()
1146         }
1147 
1148         $(#[doc = $doc])*
1149         #[doc = "Sets this field to the given `value`."]
1150         #[inline(always)]
1151         $vis fn [<with_ $field>](self, value: $into_type) -> Self
1152         {
1153             self.[<__with_ $field>](value.into())
1154         }
1155 
1156         );
1157     };
1158 
1159     // Public accessors for fields fallibly (`?=>`) converted to a type.
1160     (
1161         @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1162             $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty
1163     ) => {
1164         ::kernel::macros::paste!(
1165 
1166         $(#[doc = $doc])*
1167         #[doc = "Returns the value of this field."]
1168         #[inline(always)]
1169         $vis fn $field(self) ->
1170             Result<
1171                 $try_into_type,
1172                 <$try_into_type as ::core::convert::TryFrom<
1173                     ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
1174                 >>::Error
1175             >
1176         {
1177             self.[<__ $field>]().try_into()
1178         }
1179 
1180         $(#[doc = $doc])*
1181         #[doc = "Sets this field to the given `value`."]
1182         #[inline(always)]
1183         $vis fn [<with_ $field>](self, value: $try_into_type) -> Self
1184         {
1185             self.[<__with_ $field>](value.into())
1186         }
1187 
1188         );
1189     };
1190 
1191     // Public accessors for fields not converted to a type.
1192     (
1193         @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :
1194             $hi:tt:$lo:tt $field:ident
1195     ) => {
1196         ::kernel::macros::paste!(
1197 
1198         $(#[doc = $doc])*
1199         #[doc = "Returns the value of this field."]
1200         #[inline(always)]
1201         $vis fn $field(self) ->
1202             ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>
1203         {
1204             self.[<__ $field>]()
1205         }
1206 
1207         $(#[doc = $doc])*
1208         #[doc = "Sets this field to the compile-time constant `VALUE`."]
1209         #[inline(always)]
1210         $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {
1211             self.[<__with_ $field>](
1212                 ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()
1213             )
1214         }
1215 
1216         $(#[doc = $doc])*
1217         #[doc = "Sets this field to the given `value`."]
1218         #[inline(always)]
1219         $vis fn [<with_ $field>]<T>(
1220             self,
1221             value: T,
1222         ) -> Self
1223             where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,
1224         {
1225             self.[<__with_ $field>](value.into())
1226         }
1227 
1228         $(#[doc = $doc])*
1229         #[doc = "Tries to set this field to `value`, returning an error if it is out of range."]
1230         #[inline(always)]
1231         $vis fn [<try_with_ $field>]<T>(
1232             self,
1233             value: T,
1234         ) -> ::kernel::error::Result<Self>
1235             where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,
1236         {
1237             Ok(
1238                 self.[<__with_ $field>](
1239                     value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?
1240                 )
1241             )
1242         }
1243 
1244         );
1245     };
1246 
1247     // `Debug` implementation.
1248     (@debug $name:ident { $($field:ident;)* }) => {
1249         impl ::kernel::fmt::Debug for $name {
1250             fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
1251                 f.debug_struct(stringify!($name))
1252                     .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))
1253                 $(
1254                     .field(stringify!($field), &self.$field())
1255                 )*
1256                     .finish()
1257             }
1258         }
1259     };
1260 }
1261