1 // SPDX-License-Identifier: GPL-2.0 2 3 //! `register!` macro to define register layout and accessors. 4 //! 5 //! A single register typically includes several fields, which are accessed through a combination 6 //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because 7 //! not all possible field values are necessarily valid. 8 //! 9 //! The `register!` macro in this module provides an intuitive and readable syntax for defining a 10 //! dedicated type for each register. Each such type comes with its own field accessors that can 11 //! return an error if a field's value is invalid. 12 13 /// Trait providing a base address to be added to the offset of a relative register to obtain 14 /// its actual offset. 15 /// 16 /// The `T` generic argument is used to distinguish which base to use, in case a type provides 17 /// several bases. It is given to the `register!` macro to restrict the use of the register to 18 /// implementors of this particular variant. 19 pub(crate) trait RegisterBase<T> { 20 const BASE: usize; 21 } 22 23 /// Defines a dedicated type for a register with an absolute offset, including getter and setter 24 /// methods for its fields and methods to read and write it from an `Io` region. 25 /// 26 /// Example: 27 /// 28 /// ```no_run 29 /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { 30 /// 3:0 minor_revision as u8, "Minor revision of the chip"; 31 /// 7:4 major_revision as u8, "Major revision of the chip"; 32 /// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; 33 /// }); 34 /// ``` 35 /// 36 /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` 37 /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least 38 /// significant bits of the register. Each field can be accessed and modified using accessor 39 /// methods: 40 /// 41 /// ```no_run 42 /// // Read from the register's defined offset (0x100). 43 /// let boot0 = BOOT_0::read(&bar); 44 /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); 45 /// 46 /// // `Chipset::try_from` is called with the value of the `chipset` field and returns an 47 /// // error if it is invalid. 48 /// let chipset = boot0.chipset()?; 49 /// 50 /// // Update some fields and write the value back. 51 /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); 52 /// 53 /// // Or, just read and update the register in a single step: 54 /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); 55 /// ``` 56 /// 57 /// Fields are defined as follows: 58 /// 59 /// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or 60 /// `bool`. Note that `bool` fields must have a range of 1 bit. 61 /// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns 62 /// the result. 63 /// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation 64 /// and returns the result. This is useful with fields for which not all values are valid. 65 /// 66 /// The documentation strings are optional. If present, they will be added to the type's 67 /// definition, or the field getter and setter methods they are attached to. 68 /// 69 /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful 70 /// for cases where a register's interpretation depends on the context: 71 /// 72 /// ```no_run 73 /// register!(SCRATCH @ 0x00000200, "Scratch register" { 74 /// 31:0 value as u32, "Raw value"; 75 /// }); 76 /// 77 /// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" { 78 /// 0:0 completed as bool, "Whether the firmware has completed booting"; 79 /// }); 80 /// ``` 81 /// 82 /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also 83 /// providing its own `completed` field. 84 /// 85 /// ## Relative registers 86 /// 87 /// A register can be defined as being accessible from a fixed offset of a provided base. For 88 /// instance, imagine the following I/O space: 89 /// 90 /// ```text 91 /// +-----------------------------+ 92 /// | ... | 93 /// | | 94 /// 0x100--->+------------CPU0-------------+ 95 /// | | 96 /// 0x110--->+-----------------------------+ 97 /// | CPU_CTL | 98 /// +-----------------------------+ 99 /// | ... | 100 /// | | 101 /// | | 102 /// 0x200--->+------------CPU1-------------+ 103 /// | | 104 /// 0x210--->+-----------------------------+ 105 /// | CPU_CTL | 106 /// +-----------------------------+ 107 /// | ... | 108 /// +-----------------------------+ 109 /// ``` 110 /// 111 /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 112 /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 113 /// them twice and would prefer a way to select which one to use from a single definition 114 /// 115 /// This can be done using the `Base[Offset]` syntax when specifying the register's address. 116 /// 117 /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 118 /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 119 /// this register needs to implement `RegisterBase<Base>`. Here is the above example translated 120 /// into code: 121 /// 122 /// ```no_run 123 /// // Type used to identify the base. 124 /// pub(crate) struct CpuCtlBase; 125 /// 126 /// // ZST describing `CPU0`. 127 /// struct Cpu0; 128 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 129 /// const BASE: usize = 0x100; 130 /// } 131 /// // Singleton of `CPU0` used to identify it. 132 /// const CPU0: Cpu0 = Cpu0; 133 /// 134 /// // ZST describing `CPU1`. 135 /// struct Cpu1; 136 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 137 /// const BASE: usize = 0x200; 138 /// } 139 /// // Singleton of `CPU1` used to identify it. 140 /// const CPU1: Cpu1 = Cpu1; 141 /// 142 /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 143 /// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { 144 /// 0:0 start as bool, "Start the CPU core"; 145 /// }); 146 /// 147 /// // The `read`, `write` and `alter` methods of relative registers take an extra `base` argument 148 /// // that is used to resolve its final address by adding its `BASE` to the offset of the 149 /// // register. 150 /// 151 /// // Start `CPU0`. 152 /// CPU_CTL::alter(bar, &CPU0, |r| r.set_start(true)); 153 /// 154 /// // Start `CPU1`. 155 /// CPU_CTL::alter(bar, &CPU1, |r| r.set_start(true)); 156 /// 157 /// // Aliases can also be defined for relative register. 158 /// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { 159 /// 1:1 alias_start as bool, "Start the aliased CPU core"; 160 /// }); 161 /// 162 /// // Start the aliased `CPU0`. 163 /// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true)); 164 /// ``` 165 /// 166 /// ## Arrays of registers 167 /// 168 /// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas 169 /// can be defined as an array of identical registers, allowing them to be accessed by index with 170 /// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add 171 /// an `idx` parameter to their `read`, `write` and `alter` methods: 172 /// 173 /// ```no_run 174 /// # fn no_run() -> Result<(), Error> { 175 /// # fn get_scratch_idx() -> usize { 176 /// # 0x15 177 /// # } 178 /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 179 /// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { 180 /// 31:0 value as u32; 181 /// }); 182 /// 183 /// // Read scratch register 0, i.e. I/O address `0x80`. 184 /// let scratch_0 = SCRATCH::read(bar, 0).value(); 185 /// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 186 /// let scratch_15 = SCRATCH::read(bar, 15).value(); 187 /// 188 /// // This is out of bounds and won't build. 189 /// // let scratch_128 = SCRATCH::read(bar, 128).value(); 190 /// 191 /// // Runtime-obtained array index. 192 /// let scratch_idx = get_scratch_idx(); 193 /// // Access on a runtime index returns an error if it is out-of-bounds. 194 /// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value(); 195 /// 196 /// // Alias to a particular register in an array. 197 /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 198 /// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" { 199 /// 7:0 status as u8; 200 /// }); 201 /// 202 /// let status = FIRMWARE_STATUS::read(bar).status(); 203 /// 204 /// // Non-contiguous register arrays can be defined by adding a stride parameter. 205 /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the 206 /// // registers of the two declarations below are interleaved. 207 /// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" { 208 /// 31:0 value as u32; 209 /// }); 210 /// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" { 211 /// 31:0 value as u32; 212 /// }); 213 /// # Ok(()) 214 /// # } 215 /// ``` 216 /// 217 /// ## Relative arrays of registers 218 /// 219 /// Combining the two features described in the sections above, arrays of registers accessible from 220 /// a base can also be defined: 221 /// 222 /// ```no_run 223 /// # fn no_run() -> Result<(), Error> { 224 /// # fn get_scratch_idx() -> usize { 225 /// # 0x15 226 /// # } 227 /// // Type used as parameter of `RegisterBase` to specify the base. 228 /// pub(crate) struct CpuCtlBase; 229 /// 230 /// // ZST describing `CPU0`. 231 /// struct Cpu0; 232 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 233 /// const BASE: usize = 0x100; 234 /// } 235 /// // Singleton of `CPU0` used to identify it. 236 /// const CPU0: Cpu0 = Cpu0; 237 /// 238 /// // ZST describing `CPU1`. 239 /// struct Cpu1; 240 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 241 /// const BASE: usize = 0x200; 242 /// } 243 /// // Singleton of `CPU1` used to identify it. 244 /// const CPU1: Cpu1 = Cpu1; 245 /// 246 /// // 64 per-cpu scratch registers, arranged as an contiguous array. 247 /// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" { 248 /// 31:0 value as u32; 249 /// }); 250 /// 251 /// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value(); 252 /// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value(); 253 /// 254 /// // This won't build. 255 /// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value(); 256 /// 257 /// // Runtime-obtained array index. 258 /// let scratch_idx = get_scratch_idx(); 259 /// // Access on a runtime value returns an error if it is out-of-bounds. 260 /// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value(); 261 /// 262 /// // `SCRATCH[8]` is used to convey the firmware exit code. 263 /// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]], 264 /// "Per-CPU firmware exit status code" { 265 /// 7:0 status as u8; 266 /// }); 267 /// 268 /// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status(); 269 /// 270 /// // Non-contiguous register arrays can be defined by adding a stride parameter. 271 /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the 272 /// // registers of the two declarations below are interleaved. 273 /// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]], 274 /// "Scratch registers bank 0" { 275 /// 31:0 value as u32; 276 /// }); 277 /// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]], 278 /// "Scratch registers bank 1" { 279 /// 31:0 value as u32; 280 /// }); 281 /// # Ok(()) 282 /// # } 283 /// ``` 284 macro_rules! register { 285 // Creates a register at a fixed offset of the MMIO space. 286 ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { 287 register!(@core $name $(, $comment)? { $($fields)* } ); 288 register!(@io_fixed $name @ $offset); 289 }; 290 291 // Creates an alias register of fixed offset register `alias` with its own fields. 292 ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { 293 register!(@core $name $(, $comment)? { $($fields)* } ); 294 register!(@io_fixed $name @ $alias::OFFSET); 295 }; 296 297 // Creates a register at a relative offset from a base address provider. 298 ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { 299 register!(@core $name $(, $comment)? { $($fields)* } ); 300 register!(@io_relative $name @ $base [ $offset ]); 301 }; 302 303 // Creates an alias register of relative offset register `alias` with its own fields. 304 ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { 305 register!(@core $name $(, $comment)? { $($fields)* } ); 306 register!(@io_relative $name @ $base [ $alias::OFFSET ]); 307 }; 308 309 // Creates an array of registers at a fixed offset of the MMIO space. 310 ( 311 $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? { 312 $($fields:tt)* 313 } 314 ) => { 315 static_assert!(::core::mem::size_of::<u32>() <= $stride); 316 register!(@core $name $(, $comment)? { $($fields)* } ); 317 register!(@io_array $name @ $offset [ $size ; $stride ]); 318 }; 319 320 // Shortcut for contiguous array of registers (stride == size of element). 321 ( 322 $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? { 323 $($fields:tt)* 324 } 325 ) => { 326 register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? { 327 $($fields)* 328 } ); 329 }; 330 331 // Creates an array of registers at a relative offset from a base address provider. 332 ( 333 $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ] 334 $(, $comment:literal)? { $($fields:tt)* } 335 ) => { 336 static_assert!(::core::mem::size_of::<u32>() <= $stride); 337 register!(@core $name $(, $comment)? { $($fields)* } ); 338 register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); 339 }; 340 341 // Shortcut for contiguous array of relative registers (stride == size of element). 342 ( 343 $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? { 344 $($fields:tt)* 345 } 346 ) => { 347 register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ] 348 $(, $comment)? { $($fields)* } ); 349 }; 350 351 // Creates an alias of register `idx` of relative array of registers `alias` with its own 352 // fields. 353 ( 354 $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? { 355 $($fields:tt)* 356 } 357 ) => { 358 static_assert!($idx < $alias::SIZE); 359 register!(@core $name $(, $comment)? { $($fields)* } ); 360 register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); 361 }; 362 363 // Creates an alias of register `idx` of array of registers `alias` with its own fields. 364 // This rule belongs to the (non-relative) register arrays set, but needs to be put last 365 // to avoid it being interpreted in place of the relative register array alias rule. 366 ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { 367 static_assert!($idx < $alias::SIZE); 368 register!(@core $name $(, $comment)? { $($fields)* } ); 369 register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); 370 }; 371 372 // All rules below are helpers. 373 374 // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, 375 // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. 376 (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { 377 $( 378 #[doc=$comment] 379 )? 380 #[repr(transparent)] 381 #[derive(Clone, Copy)] 382 pub(crate) struct $name(u32); 383 384 impl ::core::ops::BitOr for $name { 385 type Output = Self; 386 387 fn bitor(self, rhs: Self) -> Self::Output { 388 Self(self.0 | rhs.0) 389 } 390 } 391 392 impl ::core::convert::From<$name> for u32 { 393 fn from(reg: $name) -> u32 { 394 reg.0 395 } 396 } 397 398 register!(@fields_dispatcher $name { $($fields)* }); 399 }; 400 401 // Captures the fields and passes them to all the implementers that require field information. 402 // 403 // Used to simplify the matching rules for implementers, so they don't need to match the entire 404 // complex fields rule even though they only make use of part of it. 405 (@fields_dispatcher $name:ident { 406 $($hi:tt:$lo:tt $field:ident as $type:tt 407 $(?=> $try_into_type:ty)? 408 $(=> $into_type:ty)? 409 $(, $comment:literal)? 410 ; 411 )* 412 } 413 ) => { 414 register!(@field_accessors $name { 415 $( 416 $hi:$lo $field as $type 417 $(?=> $try_into_type)? 418 $(=> $into_type)? 419 $(, $comment)? 420 ; 421 )* 422 }); 423 register!(@debug $name { $($field;)* }); 424 register!(@default $name { $($field;)* }); 425 }; 426 427 // Defines all the field getter/methods methods for `$name`. 428 ( 429 @field_accessors $name:ident { 430 $($hi:tt:$lo:tt $field:ident as $type:tt 431 $(?=> $try_into_type:ty)? 432 $(=> $into_type:ty)? 433 $(, $comment:literal)? 434 ; 435 )* 436 } 437 ) => { 438 $( 439 register!(@check_field_bounds $hi:$lo $field as $type); 440 )* 441 442 #[allow(dead_code)] 443 impl $name { 444 $( 445 register!(@field_accessor $name $hi:$lo $field as $type 446 $(?=> $try_into_type)? 447 $(=> $into_type)? 448 $(, $comment)? 449 ; 450 ); 451 )* 452 } 453 }; 454 455 // Boolean fields must have `$hi == $lo`. 456 (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { 457 #[allow(clippy::eq_op)] 458 const _: () = { 459 ::kernel::build_assert!( 460 $hi == $lo, 461 concat!("boolean field `", stringify!($field), "` covers more than one bit") 462 ); 463 }; 464 }; 465 466 // Non-boolean fields must have `$hi >= $lo`. 467 (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { 468 #[allow(clippy::eq_op)] 469 const _: () = { 470 ::kernel::build_assert!( 471 $hi >= $lo, 472 concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") 473 ); 474 }; 475 }; 476 477 // Catches fields defined as `bool` and convert them into a boolean value. 478 ( 479 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty 480 $(, $comment:literal)?; 481 ) => { 482 register!( 483 @leaf_accessor $name $hi:$lo $field 484 { |f| <$into_type>::from(if f != 0 { true } else { false }) } 485 $into_type => $into_type $(, $comment)?; 486 ); 487 }; 488 489 // Shortcut for fields defined as `bool` without the `=>` syntax. 490 ( 491 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; 492 ) => { 493 register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); 494 }; 495 496 // Catches the `?=>` syntax for non-boolean fields. 497 ( 498 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty 499 $(, $comment:literal)?; 500 ) => { 501 register!(@leaf_accessor $name $hi:$lo $field 502 { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => 503 ::core::result::Result< 504 $try_into_type, 505 <$try_into_type as ::core::convert::TryFrom<$type>>::Error 506 > 507 $(, $comment)?;); 508 }; 509 510 // Catches the `=>` syntax for non-boolean fields. 511 ( 512 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty 513 $(, $comment:literal)?; 514 ) => { 515 register!(@leaf_accessor $name $hi:$lo $field 516 { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); 517 }; 518 519 // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. 520 ( 521 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt 522 $(, $comment:literal)?; 523 ) => { 524 register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); 525 }; 526 527 // Generates the accessor methods for a single field. 528 ( 529 @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident 530 { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; 531 ) => { 532 ::kernel::macros::paste!( 533 const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 534 const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 535 const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); 536 ); 537 538 $( 539 #[doc="Returns the value of this field:"] 540 #[doc=$comment] 541 )? 542 #[inline(always)] 543 pub(crate) fn $field(self) -> $res_type { 544 ::kernel::macros::paste!( 545 const MASK: u32 = $name::[<$field:upper _MASK>]; 546 const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 547 ); 548 let field = ((self.0 & MASK) >> SHIFT); 549 550 $process(field) 551 } 552 553 ::kernel::macros::paste!( 554 $( 555 #[doc="Sets the value of this field:"] 556 #[doc=$comment] 557 )? 558 #[inline(always)] 559 pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { 560 const MASK: u32 = $name::[<$field:upper _MASK>]; 561 const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 562 let value = (u32::from(value) << SHIFT) & MASK; 563 self.0 = (self.0 & !MASK) | value; 564 565 self 566 } 567 ); 568 }; 569 570 // Generates the `Debug` implementation for `$name`. 571 (@debug $name:ident { $($field:ident;)* }) => { 572 impl ::kernel::fmt::Debug for $name { 573 fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { 574 f.debug_struct(stringify!($name)) 575 .field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0)) 576 $( 577 .field(stringify!($field), &self.$field()) 578 )* 579 .finish() 580 } 581 } 582 }; 583 584 // Generates the `Default` implementation for `$name`. 585 (@default $name:ident { $($field:ident;)* }) => { 586 /// Returns a value for the register where all fields are set to their default value. 587 impl ::core::default::Default for $name { 588 fn default() -> Self { 589 #[allow(unused_mut)] 590 let mut value = Self(Default::default()); 591 592 ::kernel::macros::paste!( 593 $( 594 value.[<set_ $field>](Default::default()); 595 )* 596 ); 597 598 value 599 } 600 } 601 }; 602 603 // Generates the IO accessors for a fixed offset register. 604 (@io_fixed $name:ident @ $offset:expr) => { 605 #[allow(dead_code)] 606 impl $name { 607 pub(crate) const OFFSET: usize = $offset; 608 609 /// Read the register from its address in `io`. 610 #[inline(always)] 611 pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where 612 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 613 { 614 Self(io.read32($offset)) 615 } 616 617 /// Write the value contained in `self` to the register address in `io`. 618 #[inline(always)] 619 pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where 620 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 621 { 622 io.write32(self.0, $offset) 623 } 624 625 /// Read the register from its address in `io` and run `f` on its value to obtain a new 626 /// value to write back. 627 #[inline(always)] 628 pub(crate) fn alter<const SIZE: usize, T, F>( 629 io: &T, 630 f: F, 631 ) where 632 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 633 F: ::core::ops::FnOnce(Self) -> Self, 634 { 635 let reg = f(Self::read(io)); 636 reg.write(io); 637 } 638 } 639 }; 640 641 // Generates the IO accessors for a relative offset register. 642 (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => { 643 #[allow(dead_code)] 644 impl $name { 645 pub(crate) const OFFSET: usize = $offset; 646 647 /// Read the register from `io`, using the base address provided by `base` and adding 648 /// the register's offset to it. 649 #[inline(always)] 650 pub(crate) fn read<const SIZE: usize, T, B>( 651 io: &T, 652 #[allow(unused_variables)] 653 base: &B, 654 ) -> Self where 655 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 656 B: crate::regs::macros::RegisterBase<$base>, 657 { 658 const OFFSET: usize = $name::OFFSET; 659 660 let value = io.read32( 661 <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 662 ); 663 664 Self(value) 665 } 666 667 /// Write the value contained in `self` to `io`, using the base address provided by 668 /// `base` and adding the register's offset to it. 669 #[inline(always)] 670 pub(crate) fn write<const SIZE: usize, T, B>( 671 self, 672 io: &T, 673 #[allow(unused_variables)] 674 base: &B, 675 ) where 676 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 677 B: crate::regs::macros::RegisterBase<$base>, 678 { 679 const OFFSET: usize = $name::OFFSET; 680 681 io.write32( 682 self.0, 683 <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 684 ); 685 } 686 687 /// Read the register from `io`, using the base address provided by `base` and adding 688 /// the register's offset to it, then run `f` on its value to obtain a new value to 689 /// write back. 690 #[inline(always)] 691 pub(crate) fn alter<const SIZE: usize, T, B, F>( 692 io: &T, 693 base: &B, 694 f: F, 695 ) where 696 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 697 B: crate::regs::macros::RegisterBase<$base>, 698 F: ::core::ops::FnOnce(Self) -> Self, 699 { 700 let reg = f(Self::read(io, base)); 701 reg.write(io, base); 702 } 703 } 704 }; 705 706 // Generates the IO accessors for an array of registers. 707 (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => { 708 #[allow(dead_code)] 709 impl $name { 710 pub(crate) const OFFSET: usize = $offset; 711 pub(crate) const SIZE: usize = $size; 712 pub(crate) const STRIDE: usize = $stride; 713 714 /// Read the array register at index `idx` from its address in `io`. 715 #[inline(always)] 716 pub(crate) fn read<const SIZE: usize, T>( 717 io: &T, 718 idx: usize, 719 ) -> Self where 720 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 721 { 722 build_assert!(idx < Self::SIZE); 723 724 let offset = Self::OFFSET + (idx * Self::STRIDE); 725 let value = io.read32(offset); 726 727 Self(value) 728 } 729 730 /// Write the value contained in `self` to the array register with index `idx` in `io`. 731 #[inline(always)] 732 pub(crate) fn write<const SIZE: usize, T>( 733 self, 734 io: &T, 735 idx: usize 736 ) where 737 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 738 { 739 build_assert!(idx < Self::SIZE); 740 741 let offset = Self::OFFSET + (idx * Self::STRIDE); 742 743 io.write32(self.0, offset); 744 } 745 746 /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 747 /// new value to write back. 748 #[inline(always)] 749 pub(crate) fn alter<const SIZE: usize, T, F>( 750 io: &T, 751 idx: usize, 752 f: F, 753 ) where 754 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 755 F: ::core::ops::FnOnce(Self) -> Self, 756 { 757 let reg = f(Self::read(io, idx)); 758 reg.write(io, idx); 759 } 760 761 /// Read the array register at index `idx` from its address in `io`. 762 /// 763 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 764 /// access was out-of-bounds. 765 #[inline(always)] 766 pub(crate) fn try_read<const SIZE: usize, T>( 767 io: &T, 768 idx: usize, 769 ) -> ::kernel::error::Result<Self> where 770 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 771 { 772 if idx < Self::SIZE { 773 Ok(Self::read(io, idx)) 774 } else { 775 Err(EINVAL) 776 } 777 } 778 779 /// Write the value contained in `self` to the array register with index `idx` in `io`. 780 /// 781 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 782 /// access was out-of-bounds. 783 #[inline(always)] 784 pub(crate) fn try_write<const SIZE: usize, T>( 785 self, 786 io: &T, 787 idx: usize, 788 ) -> ::kernel::error::Result where 789 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 790 { 791 if idx < Self::SIZE { 792 Ok(self.write(io, idx)) 793 } else { 794 Err(EINVAL) 795 } 796 } 797 798 /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 799 /// new value to write back. 800 /// 801 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 802 /// access was out-of-bounds. 803 #[inline(always)] 804 pub(crate) fn try_alter<const SIZE: usize, T, F>( 805 io: &T, 806 idx: usize, 807 f: F, 808 ) -> ::kernel::error::Result where 809 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 810 F: ::core::ops::FnOnce(Self) -> Self, 811 { 812 if idx < Self::SIZE { 813 Ok(Self::alter(io, idx, f)) 814 } else { 815 Err(EINVAL) 816 } 817 } 818 } 819 }; 820 821 // Generates the IO accessors for an array of relative registers. 822 ( 823 @io_relative_array $name:ident @ $base:ty 824 [ $offset:literal [ $size:expr ; $stride:expr ] ] 825 ) => { 826 #[allow(dead_code)] 827 impl $name { 828 pub(crate) const OFFSET: usize = $offset; 829 pub(crate) const SIZE: usize = $size; 830 pub(crate) const STRIDE: usize = $stride; 831 832 /// Read the array register at index `idx` from `io`, using the base address provided 833 /// by `base` and adding the register's offset to it. 834 #[inline(always)] 835 pub(crate) fn read<const SIZE: usize, T, B>( 836 io: &T, 837 #[allow(unused_variables)] 838 base: &B, 839 idx: usize, 840 ) -> Self where 841 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 842 B: crate::regs::macros::RegisterBase<$base>, 843 { 844 build_assert!(idx < Self::SIZE); 845 846 let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + 847 Self::OFFSET + (idx * Self::STRIDE); 848 let value = io.read32(offset); 849 850 Self(value) 851 } 852 853 /// Write the value contained in `self` to `io`, using the base address provided by 854 /// `base` and adding the offset of array register `idx` to it. 855 #[inline(always)] 856 pub(crate) fn write<const SIZE: usize, T, B>( 857 self, 858 io: &T, 859 #[allow(unused_variables)] 860 base: &B, 861 idx: usize 862 ) where 863 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 864 B: crate::regs::macros::RegisterBase<$base>, 865 { 866 build_assert!(idx < Self::SIZE); 867 868 let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + 869 Self::OFFSET + (idx * Self::STRIDE); 870 871 io.write32(self.0, offset); 872 } 873 874 /// Read the array register at index `idx` from `io`, using the base address provided 875 /// by `base` and adding the register's offset to it, then run `f` on its value to 876 /// obtain a new value to write back. 877 #[inline(always)] 878 pub(crate) fn alter<const SIZE: usize, T, B, F>( 879 io: &T, 880 base: &B, 881 idx: usize, 882 f: F, 883 ) where 884 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 885 B: crate::regs::macros::RegisterBase<$base>, 886 F: ::core::ops::FnOnce(Self) -> Self, 887 { 888 let reg = f(Self::read(io, base, idx)); 889 reg.write(io, base, idx); 890 } 891 892 /// Read the array register at index `idx` from `io`, using the base address provided 893 /// by `base` and adding the register's offset to it. 894 /// 895 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 896 /// access was out-of-bounds. 897 #[inline(always)] 898 pub(crate) fn try_read<const SIZE: usize, T, B>( 899 io: &T, 900 base: &B, 901 idx: usize, 902 ) -> ::kernel::error::Result<Self> where 903 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 904 B: crate::regs::macros::RegisterBase<$base>, 905 { 906 if idx < Self::SIZE { 907 Ok(Self::read(io, base, idx)) 908 } else { 909 Err(EINVAL) 910 } 911 } 912 913 /// Write the value contained in `self` to `io`, using the base address provided by 914 /// `base` and adding the offset of array register `idx` to it. 915 /// 916 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 917 /// access was out-of-bounds. 918 #[inline(always)] 919 pub(crate) fn try_write<const SIZE: usize, T, B>( 920 self, 921 io: &T, 922 base: &B, 923 idx: usize, 924 ) -> ::kernel::error::Result where 925 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 926 B: crate::regs::macros::RegisterBase<$base>, 927 { 928 if idx < Self::SIZE { 929 Ok(self.write(io, base, idx)) 930 } else { 931 Err(EINVAL) 932 } 933 } 934 935 /// Read the array register at index `idx` from `io`, using the base address provided 936 /// by `base` and adding the register's offset to it, then run `f` on its value to 937 /// obtain a new value to write back. 938 /// 939 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 940 /// access was out-of-bounds. 941 #[inline(always)] 942 pub(crate) fn try_alter<const SIZE: usize, T, B, F>( 943 io: &T, 944 base: &B, 945 idx: usize, 946 f: F, 947 ) -> ::kernel::error::Result where 948 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 949 B: crate::regs::macros::RegisterBase<$base>, 950 F: ::core::ops::FnOnce(Self) -> Self, 951 { 952 if idx < Self::SIZE { 953 Ok(Self::alter(io, base, idx, f)) 954 } else { 955 Err(EINVAL) 956 } 957 } 958 } 959 }; 960 } 961