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