Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/nova-core/regs/macros.rs
29281 views
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
962