Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

gpu: nova-core: convert falcon registers to kernel register macro

Convert all PFALCON, PFALCON2 and PRISCV registers to use the kernel's
register macro and update the code accordingly.

Because they rely on the same types to implement relative registers,
they need to be updated in lockstep.

nova-core's local register macro is now unused, so remove it.

Reviewed-by: Gary Guo <gary@garyguo.net>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260325-b4-nova-register-v4-8-bdf172f0f6ca@nvidia.com
[acourbot@nvidia.com: remove unused import.]
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>

+456 -1281
+201 -319
drivers/gpu/nova-core/falcon.rs
··· 15 15 }, 16 16 io::{ 17 17 poll::read_poll_timeout, 18 - Io, // 18 + register::{ 19 + RegisterBase, 20 + WithBase, // 21 + }, 22 + Io, 19 23 }, 20 24 prelude::*, 21 25 sync::aref::ARef, ··· 27 23 }; 28 24 29 25 use crate::{ 26 + bounded_enum, 30 27 dma::DmaObject, 31 28 driver::Bar0, 32 29 falcon::hal::LoadMethod, ··· 37 32 FromSafeCast, // 38 33 }, 39 34 regs, 40 - regs::macros::RegisterBase, // 41 35 }; 42 36 43 37 pub(crate) mod gsp; ··· 46 42 /// Alignment (in bytes) of falcon memory blocks. 47 43 pub(crate) const MEM_BLOCK_ALIGNMENT: usize = 256; 48 44 49 - // TODO[FPRI]: Replace with `ToPrimitive`. 50 - macro_rules! impl_from_enum_to_u8 { 51 - ($enum_type:ty) => { 52 - impl From<$enum_type> for u8 { 53 - fn from(value: $enum_type) -> Self { 54 - value as u8 55 - } 56 - } 57 - }; 58 - } 59 - 60 - /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 61 - /// register. 62 - #[repr(u8)] 63 - #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 64 - pub(crate) enum FalconCoreRev { 65 - #[default] 66 - Rev1 = 1, 67 - Rev2 = 2, 68 - Rev3 = 3, 69 - Rev4 = 4, 70 - Rev5 = 5, 71 - Rev6 = 6, 72 - Rev7 = 7, 73 - } 74 - impl_from_enum_to_u8!(FalconCoreRev); 75 - 76 - // TODO[FPRI]: replace with `FromPrimitive`. 77 - impl TryFrom<u8> for FalconCoreRev { 78 - type Error = Error; 79 - 80 - fn try_from(value: u8) -> Result<Self> { 81 - use FalconCoreRev::*; 82 - 83 - let rev = match value { 84 - 1 => Rev1, 85 - 2 => Rev2, 86 - 3 => Rev3, 87 - 4 => Rev4, 88 - 5 => Rev5, 89 - 6 => Rev6, 90 - 7 => Rev7, 91 - _ => return Err(EINVAL), 92 - }; 93 - 94 - Ok(rev) 45 + bounded_enum! { 46 + /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 47 + /// register. 48 + #[derive(Debug, Copy, Clone)] 49 + pub(crate) enum FalconCoreRev with TryFrom<Bounded<u32, 4>> { 50 + Rev1 = 1, 51 + Rev2 = 2, 52 + Rev3 = 3, 53 + Rev4 = 4, 54 + Rev5 = 5, 55 + Rev6 = 6, 56 + Rev7 = 7, 95 57 } 96 58 } 97 59 98 - /// Revision subversion number of a falcon core, used in the 99 - /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. 100 - #[repr(u8)] 101 - #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 102 - pub(crate) enum FalconCoreRevSubversion { 103 - #[default] 104 - Subversion0 = 0, 105 - Subversion1 = 1, 106 - Subversion2 = 2, 107 - Subversion3 = 3, 108 - } 109 - impl_from_enum_to_u8!(FalconCoreRevSubversion); 110 - 111 - // TODO[FPRI]: replace with `FromPrimitive`. 112 - impl TryFrom<u8> for FalconCoreRevSubversion { 113 - type Error = Error; 114 - 115 - fn try_from(value: u8) -> Result<Self> { 116 - use FalconCoreRevSubversion::*; 117 - 118 - let sub_version = match value & 0b11 { 119 - 0 => Subversion0, 120 - 1 => Subversion1, 121 - 2 => Subversion2, 122 - 3 => Subversion3, 123 - _ => return Err(EINVAL), 124 - }; 125 - 126 - Ok(sub_version) 60 + bounded_enum! { 61 + /// Revision subversion number of a falcon core, used in the 62 + /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. 63 + #[derive(Debug, Copy, Clone)] 64 + pub(crate) enum FalconCoreRevSubversion with From<Bounded<u32, 2>> { 65 + Subversion0 = 0, 66 + Subversion1 = 1, 67 + Subversion2 = 2, 68 + Subversion3 = 3, 127 69 } 128 70 } 129 71 130 - /// Security model of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 131 - /// register. 132 - #[repr(u8)] 133 - #[derive(Debug, Default, Copy, Clone)] 134 - /// Security mode of the Falcon microprocessor. 135 - /// 136 - /// See `falcon.rst` for more details. 137 - pub(crate) enum FalconSecurityModel { 138 - /// Non-Secure: runs unsigned code without privileges. 139 - #[default] 140 - None = 0, 141 - /// Light-Secured (LS): Runs signed code with some privileges. 142 - /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the code's 143 - /// signature. 72 + bounded_enum! { 73 + /// Security mode of the Falcon microprocessor. 144 74 /// 145 - /// Also known as Low-Secure, Privilege Level 2 or PL2. 146 - Light = 2, 147 - /// Heavy-Secured (HS): Runs signed code with full privileges. 148 - /// The code's signature is verified by the Falcon Boot ROM (BROM). 149 - /// 150 - /// Also known as High-Secure, Privilege Level 3 or PL3. 151 - Heavy = 3, 152 - } 153 - impl_from_enum_to_u8!(FalconSecurityModel); 154 - 155 - // TODO[FPRI]: replace with `FromPrimitive`. 156 - impl TryFrom<u8> for FalconSecurityModel { 157 - type Error = Error; 158 - 159 - fn try_from(value: u8) -> Result<Self> { 160 - use FalconSecurityModel::*; 161 - 162 - let sec_model = match value { 163 - 0 => None, 164 - 2 => Light, 165 - 3 => Heavy, 166 - _ => return Err(EINVAL), 167 - }; 168 - 169 - Ok(sec_model) 75 + /// See `falcon.rst` for more details. 76 + #[derive(Debug, Copy, Clone)] 77 + pub(crate) enum FalconSecurityModel with TryFrom<Bounded<u32, 2>> { 78 + /// Non-Secure: runs unsigned code without privileges. 79 + None = 0, 80 + /// Light-Secured (LS): Runs signed code with some privileges. 81 + /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the 82 + /// code's signature. 83 + /// 84 + /// Also known as Low-Secure, Privilege Level 2 or PL2. 85 + Light = 2, 86 + /// Heavy-Secured (HS): Runs signed code with full privileges. 87 + /// The code's signature is verified by the Falcon Boot ROM (BROM). 88 + /// 89 + /// Also known as High-Secure, Privilege Level 3 or PL3. 90 + Heavy = 3, 170 91 } 171 92 } 172 93 173 - /// Signing algorithm for a given firmware, used in the [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] 174 - /// register. It is passed to the Falcon Boot ROM (BROM) as a parameter. 175 - #[repr(u8)] 176 - #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 177 - pub(crate) enum FalconModSelAlgo { 178 - /// AES. 179 - #[expect(dead_code)] 180 - Aes = 0, 181 - /// RSA3K. 182 - #[default] 183 - Rsa3k = 1, 184 - } 185 - impl_from_enum_to_u8!(FalconModSelAlgo); 186 - 187 - // TODO[FPRI]: replace with `FromPrimitive`. 188 - impl TryFrom<u8> for FalconModSelAlgo { 189 - type Error = Error; 190 - 191 - fn try_from(value: u8) -> Result<Self> { 192 - match value { 193 - 1 => Ok(FalconModSelAlgo::Rsa3k), 194 - _ => Err(EINVAL), 195 - } 94 + bounded_enum! { 95 + /// Signing algorithm for a given firmware, used in the 96 + /// [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] register. It is passed to the Falcon Boot ROM 97 + /// (BROM) as a parameter. 98 + #[derive(Debug, Copy, Clone)] 99 + pub(crate) enum FalconModSelAlgo with TryFrom<Bounded<u32, 8>> { 100 + /// AES. 101 + Aes = 0, 102 + /// RSA3K. 103 + Rsa3k = 1, 196 104 } 197 105 } 198 106 199 - /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register. 200 - #[repr(u8)] 201 - #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 202 - pub(crate) enum DmaTrfCmdSize { 203 - /// 256 bytes transfer. 204 - #[default] 205 - Size256B = 0x6, 206 - } 207 - impl_from_enum_to_u8!(DmaTrfCmdSize); 208 - 209 - // TODO[FPRI]: replace with `FromPrimitive`. 210 - impl TryFrom<u8> for DmaTrfCmdSize { 211 - type Error = Error; 212 - 213 - fn try_from(value: u8) -> Result<Self> { 214 - match value { 215 - 0x6 => Ok(Self::Size256B), 216 - _ => Err(EINVAL), 217 - } 107 + bounded_enum! { 108 + /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] 109 + /// register. 110 + #[derive(Debug, Copy, Clone)] 111 + pub(crate) enum DmaTrfCmdSize with TryFrom<Bounded<u32, 3>> { 112 + /// 256 bytes transfer. 113 + Size256B = 0x6, 218 114 } 219 115 } 220 116 221 - /// Currently active core on a dual falcon/riscv (Peregrine) controller. 222 - #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 223 - pub(crate) enum PeregrineCoreSelect { 224 - /// Falcon core is active. 225 - #[default] 226 - Falcon = 0, 227 - /// RISC-V core is active. 228 - Riscv = 1, 229 - } 230 - 231 - impl From<bool> for PeregrineCoreSelect { 232 - fn from(value: bool) -> Self { 233 - match value { 234 - false => PeregrineCoreSelect::Falcon, 235 - true => PeregrineCoreSelect::Riscv, 236 - } 237 - } 238 - } 239 - 240 - impl From<PeregrineCoreSelect> for bool { 241 - fn from(value: PeregrineCoreSelect) -> Self { 242 - match value { 243 - PeregrineCoreSelect::Falcon => false, 244 - PeregrineCoreSelect::Riscv => true, 245 - } 117 + bounded_enum! { 118 + /// Currently active core on a dual falcon/riscv (Peregrine) controller. 119 + #[derive(Debug, Copy, Clone, PartialEq, Eq)] 120 + pub(crate) enum PeregrineCoreSelect with From<Bounded<u32, 1>> { 121 + /// Falcon core is active. 122 + Falcon = 0, 123 + /// RISC-V core is active. 124 + Riscv = 1, 246 125 } 247 126 } 248 127 249 128 /// Different types of memory present in a falcon core. 250 - #[derive(Debug, Clone, Copy, PartialEq, Eq)] 129 + #[derive(Debug, Copy, Clone, PartialEq, Eq)] 251 130 pub(crate) enum FalconMem { 252 131 /// Secure Instruction Memory. 253 132 ImemSecure, ··· 141 254 Dmem, 142 255 } 143 256 144 - /// Defines the Framebuffer Interface (FBIF) aperture type. 145 - /// This determines the memory type for external memory access during a DMA transfer, which is 146 - /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. 147 - #[derive(Debug, Clone, Default)] 148 - pub(crate) enum FalconFbifTarget { 149 - /// VRAM. 150 - #[default] 151 - /// Local Framebuffer (GPU's VRAM memory). 152 - LocalFb = 0, 153 - /// Coherent system memory (System DRAM). 154 - CoherentSysmem = 1, 155 - /// Non-coherent system memory (System DRAM). 156 - NoncoherentSysmem = 2, 157 - } 158 - impl_from_enum_to_u8!(FalconFbifTarget); 159 - 160 - // TODO[FPRI]: replace with `FromPrimitive`. 161 - impl TryFrom<u8> for FalconFbifTarget { 162 - type Error = Error; 163 - 164 - fn try_from(value: u8) -> Result<Self> { 165 - let res = match value { 166 - 0 => Self::LocalFb, 167 - 1 => Self::CoherentSysmem, 168 - 2 => Self::NoncoherentSysmem, 169 - _ => return Err(EINVAL), 170 - }; 171 - 172 - Ok(res) 257 + bounded_enum! { 258 + /// Defines the Framebuffer Interface (FBIF) aperture type. 259 + /// This determines the memory type for external memory access during a DMA transfer, which is 260 + /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. 261 + #[derive(Debug, Copy, Clone)] 262 + pub(crate) enum FalconFbifTarget with TryFrom<Bounded<u32, 2>> { 263 + /// Local Framebuffer (GPU's VRAM memory). 264 + LocalFb = 0, 265 + /// Coherent system memory (System DRAM). 266 + CoherentSysmem = 1, 267 + /// Non-coherent system memory (System DRAM). 268 + NoncoherentSysmem = 2, 173 269 } 174 270 } 175 271 176 - /// Type of memory addresses to use. 177 - #[derive(Debug, Clone, Default)] 178 - pub(crate) enum FalconFbifMemType { 179 - /// Virtual memory addresses. 180 - #[default] 181 - Virtual = 0, 182 - /// Physical memory addresses. 183 - Physical = 1, 184 - } 185 - 186 - /// Conversion from a single-bit register field. 187 - impl From<bool> for FalconFbifMemType { 188 - fn from(value: bool) -> Self { 189 - match value { 190 - false => Self::Virtual, 191 - true => Self::Physical, 192 - } 193 - } 194 - } 195 - 196 - impl From<FalconFbifMemType> for bool { 197 - fn from(value: FalconFbifMemType) -> Self { 198 - match value { 199 - FalconFbifMemType::Virtual => false, 200 - FalconFbifMemType::Physical => true, 201 - } 272 + bounded_enum! { 273 + /// Type of memory addresses to use. 274 + #[derive(Debug, Copy, Clone)] 275 + pub(crate) enum FalconFbifMemType with From<Bounded<u32, 1>> { 276 + /// Virtual memory addresses. 277 + Virtual = 0, 278 + /// Physical memory addresses. 279 + Physical = 1, 202 280 } 203 281 } 204 282 ··· 175 323 176 324 /// Trait defining the parameters of a given Falcon engine. 177 325 /// 178 - /// Each engine provides one base for `PFALCON` and `PFALCON2` registers. The `ID` constant is used 179 - /// to identify a given Falcon instance with register I/O methods. 326 + /// Each engine provides one base for `PFALCON` and `PFALCON2` registers. 180 327 pub(crate) trait FalconEngine: 181 328 Send + Sync + RegisterBase<PFalconBase> + RegisterBase<PFalcon2Base> + Sized 182 329 { 183 - /// Singleton of the engine, used to identify it with register I/O methods. 184 - const ID: Self; 185 330 } 186 331 187 332 /// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM) ··· 372 523 373 524 /// Resets DMA-related registers. 374 525 pub(crate) fn dma_reset(&self, bar: &Bar0) { 375 - regs::NV_PFALCON_FBIF_CTL::update(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true)); 376 - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); 526 + bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| { 527 + v.with_allow_phys_no_ctx(true) 528 + }); 529 + 530 + bar.write( 531 + WithBase::of::<E>(), 532 + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), 533 + ); 377 534 } 378 535 379 536 /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete. ··· 388 533 self.hal.select_core(self, bar)?; 389 534 self.hal.reset_wait_mem_scrubbing(bar)?; 390 535 391 - regs::NV_PFALCON_FALCON_RM::default() 392 - .set_value(bar.read(regs::NV_PMC_BOOT_0).into()) 393 - .write(bar, &E::ID); 536 + bar.write( 537 + WithBase::of::<E>(), 538 + regs::NV_PFALCON_FALCON_RM::from(bar.read(regs::NV_PMC_BOOT_0).into_raw()), 539 + ); 394 540 395 541 Ok(()) 396 542 } ··· 409 553 return Err(EINVAL); 410 554 } 411 555 412 - regs::NV_PFALCON_FALCON_IMEMC::default() 413 - .set_secure(load_offsets.secure) 414 - .set_aincw(true) 415 - .set_offs(load_offsets.dst_start) 416 - .write(bar, &E::ID, Self::PIO_PORT); 556 + bar.write( 557 + WithBase::of::<E>().at(Self::PIO_PORT), 558 + regs::NV_PFALCON_FALCON_IMEMC::zeroed() 559 + .with_secure(load_offsets.secure) 560 + .with_aincw(true) 561 + .with_offs(load_offsets.dst_start), 562 + ); 417 563 418 564 for (n, block) in load_offsets.data.chunks(MEM_BLOCK_ALIGNMENT).enumerate() { 419 565 let n = u16::try_from(n)?; 420 566 let tag: u16 = load_offsets.start_tag.checked_add(n).ok_or(ERANGE)?; 421 - regs::NV_PFALCON_FALCON_IMEMT::default().set_tag(tag).write( 422 - bar, 423 - &E::ID, 424 - Self::PIO_PORT, 567 + bar.write( 568 + WithBase::of::<E>().at(Self::PIO_PORT), 569 + regs::NV_PFALCON_FALCON_IMEMT::zeroed().with_tag(tag), 425 570 ); 426 571 for word in block.chunks_exact(4) { 427 572 let w = [word[0], word[1], word[2], word[3]]; 428 - regs::NV_PFALCON_FALCON_IMEMD::default() 429 - .set_data(u32::from_le_bytes(w)) 430 - .write(bar, &E::ID, Self::PIO_PORT); 573 + bar.write( 574 + WithBase::of::<E>().at(Self::PIO_PORT), 575 + regs::NV_PFALCON_FALCON_IMEMD::zeroed().with_data(u32::from_le_bytes(w)), 576 + ); 431 577 } 432 578 } 433 579 ··· 446 588 return Err(EINVAL); 447 589 } 448 590 449 - regs::NV_PFALCON_FALCON_DMEMC::default() 450 - .set_aincw(true) 451 - .set_offs(load_offsets.dst_start) 452 - .write(bar, &E::ID, Self::PIO_PORT); 591 + bar.write( 592 + WithBase::of::<E>().at(Self::PIO_PORT), 593 + regs::NV_PFALCON_FALCON_DMEMC::zeroed() 594 + .with_aincw(true) 595 + .with_offs(load_offsets.dst_start), 596 + ); 453 597 454 598 for word in load_offsets.data.chunks_exact(4) { 455 599 let w = [word[0], word[1], word[2], word[3]]; 456 - regs::NV_PFALCON_FALCON_DMEMD::default() 457 - .set_data(u32::from_le_bytes(w)) 458 - .write(bar, &E::ID, Self::PIO_PORT); 600 + bar.write( 601 + WithBase::of::<E>().at(Self::PIO_PORT), 602 + regs::NV_PFALCON_FALCON_DMEMD::zeroed().with_data(u32::from_le_bytes(w)), 603 + ); 459 604 } 460 605 461 606 Ok(()) ··· 470 609 bar: &Bar0, 471 610 fw: &F, 472 611 ) -> Result { 473 - regs::NV_PFALCON_FBIF_CTL::read(bar, &E::ID) 474 - .set_allow_phys_no_ctx(true) 475 - .write(bar, &E::ID); 612 + bar.update(regs::NV_PFALCON_FBIF_CTL::of::<E>(), |v| { 613 + v.with_allow_phys_no_ctx(true) 614 + }); 476 615 477 - regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); 616 + bar.write( 617 + WithBase::of::<E>(), 618 + regs::NV_PFALCON_FALCON_DMACTL::zeroed(), 619 + ); 478 620 479 621 if let Some(imem_ns) = fw.imem_ns_load_params() { 480 622 self.pio_wr_imem_slice(bar, imem_ns)?; ··· 489 625 490 626 self.hal.program_brom(self, bar, &fw.brom_params())?; 491 627 492 - regs::NV_PFALCON_FALCON_BOOTVEC::default() 493 - .set_value(fw.boot_addr()) 494 - .write(bar, &E::ID); 628 + bar.write( 629 + WithBase::of::<E>(), 630 + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()), 631 + ); 495 632 496 633 Ok(()) 497 634 } ··· 561 696 562 697 // Set up the base source DMA address. 563 698 564 - regs::NV_PFALCON_FALCON_DMATRFBASE::default() 565 - // CAST: `as u32` is used on purpose since we do want to strip the upper bits, which 566 - // will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. 567 - .set_base((dma_start >> 8) as u32) 568 - .write(bar, &E::ID); 569 - regs::NV_PFALCON_FALCON_DMATRFBASE1::default() 570 - // CAST: `as u16` is used on purpose since the remaining bits are guaranteed to fit 571 - // within a `u16`. 572 - .set_base((dma_start >> 40) as u16) 573 - .write(bar, &E::ID); 699 + bar.write( 700 + WithBase::of::<E>(), 701 + regs::NV_PFALCON_FALCON_DMATRFBASE::zeroed().with_base( 702 + // CAST: `as u32` is used on purpose since we do want to strip the upper bits, 703 + // which will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. 704 + (dma_start >> 8) as u32, 705 + ), 706 + ); 707 + bar.write( 708 + WithBase::of::<E>(), 709 + regs::NV_PFALCON_FALCON_DMATRFBASE1::zeroed().try_with_base(dma_start >> 40)?, 710 + ); 574 711 575 - let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() 576 - .set_size(DmaTrfCmdSize::Size256B) 712 + let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::zeroed() 713 + .with_size(DmaTrfCmdSize::Size256B) 577 714 .with_falcon_mem(target_mem); 578 715 579 716 for pos in (0..num_transfers).map(|i| i * DMA_LEN) { 580 717 // Perform a transfer of size `DMA_LEN`. 581 - regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() 582 - .set_offs(load_offsets.dst_start + pos) 583 - .write(bar, &E::ID); 584 - regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() 585 - .set_offs(src_start + pos) 586 - .write(bar, &E::ID); 587 - cmd.write(bar, &E::ID); 718 + bar.write( 719 + WithBase::of::<E>(), 720 + regs::NV_PFALCON_FALCON_DMATRFMOFFS::zeroed() 721 + .try_with_offs(load_offsets.dst_start + pos)?, 722 + ); 723 + bar.write( 724 + WithBase::of::<E>(), 725 + regs::NV_PFALCON_FALCON_DMATRFFBOFFS::zeroed().with_offs(src_start + pos), 726 + ); 727 + 728 + bar.write(WithBase::of::<E>(), cmd); 588 729 589 730 // Wait for the transfer to complete. 590 731 // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories 591 732 // should ever take that long. 592 733 read_poll_timeout( 593 - || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)), 734 + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMATRFCMD::of::<E>())), 594 735 |r| r.idle(), 595 736 Delta::ZERO, 596 737 Delta::from_secs(2), ··· 617 746 let dma_obj = DmaObject::from_data(dev, fw.as_slice())?; 618 747 619 748 self.dma_reset(bar); 620 - regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| { 621 - v.set_target(FalconFbifTarget::CoherentSysmem) 622 - .set_mem_type(FalconFbifMemType::Physical) 749 + bar.update(regs::NV_PFALCON_FBIF_TRANSCFG::of::<E>().at(0), |v| { 750 + v.with_target(FalconFbifTarget::CoherentSysmem) 751 + .with_mem_type(FalconFbifMemType::Physical) 623 752 }); 624 753 625 754 self.dma_wr( ··· 633 762 self.hal.program_brom(self, bar, &fw.brom_params())?; 634 763 635 764 // Set `BootVec` to start of non-secure code. 636 - regs::NV_PFALCON_FALCON_BOOTVEC::default() 637 - .set_value(fw.boot_addr()) 638 - .write(bar, &E::ID); 765 + bar.write( 766 + WithBase::of::<E>(), 767 + regs::NV_PFALCON_FALCON_BOOTVEC::zeroed().with_value(fw.boot_addr()), 768 + ); 639 769 640 770 Ok(()) 641 771 } ··· 645 773 pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> { 646 774 // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. 647 775 read_poll_timeout( 648 - || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)), 776 + || Ok(bar.read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>())), 649 777 |r| r.halted(), 650 778 Delta::ZERO, 651 779 Delta::from_secs(2), ··· 656 784 657 785 /// Start the falcon CPU. 658 786 pub(crate) fn start(&self, bar: &Bar0) -> Result<()> { 659 - match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() { 660 - true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() 661 - .set_startcpu(true) 662 - .write(bar, &E::ID), 663 - false => regs::NV_PFALCON_FALCON_CPUCTL::default() 664 - .set_startcpu(true) 665 - .write(bar, &E::ID), 787 + match bar 788 + .read(regs::NV_PFALCON_FALCON_CPUCTL::of::<E>()) 789 + .alias_en() 790 + { 791 + true => bar.write( 792 + WithBase::of::<E>(), 793 + regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::zeroed().with_startcpu(true), 794 + ), 795 + false => bar.write( 796 + WithBase::of::<E>(), 797 + regs::NV_PFALCON_FALCON_CPUCTL::zeroed().with_startcpu(true), 798 + ), 666 799 } 667 800 668 801 Ok(()) ··· 676 799 /// Writes values to the mailbox registers if provided. 677 800 pub(crate) fn write_mailboxes(&self, bar: &Bar0, mbox0: Option<u32>, mbox1: Option<u32>) { 678 801 if let Some(mbox0) = mbox0 { 679 - regs::NV_PFALCON_FALCON_MAILBOX0::default() 680 - .set_value(mbox0) 681 - .write(bar, &E::ID); 802 + bar.write( 803 + WithBase::of::<E>(), 804 + regs::NV_PFALCON_FALCON_MAILBOX0::zeroed().with_value(mbox0), 805 + ); 682 806 } 683 807 684 808 if let Some(mbox1) = mbox1 { 685 - regs::NV_PFALCON_FALCON_MAILBOX1::default() 686 - .set_value(mbox1) 687 - .write(bar, &E::ID); 809 + bar.write( 810 + WithBase::of::<E>(), 811 + regs::NV_PFALCON_FALCON_MAILBOX1::zeroed().with_value(mbox1), 812 + ); 688 813 } 689 814 } 690 815 691 816 /// Reads the value from `mbox0` register. 692 817 pub(crate) fn read_mailbox0(&self, bar: &Bar0) -> u32 { 693 - regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value() 818 + bar.read(regs::NV_PFALCON_FALCON_MAILBOX0::of::<E>()) 819 + .value() 694 820 } 695 821 696 822 /// Reads the value from `mbox1` register. 697 823 pub(crate) fn read_mailbox1(&self, bar: &Bar0) -> u32 { 698 - regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value() 824 + bar.read(regs::NV_PFALCON_FALCON_MAILBOX1::of::<E>()) 825 + .value() 699 826 } 700 827 701 828 /// Reads values from both mailbox registers. ··· 764 883 765 884 /// Write the application version to the OS register. 766 885 pub(crate) fn write_os_version(&self, bar: &Bar0, app_version: u32) { 767 - regs::NV_PFALCON_FALCON_OS::default() 768 - .set_value(app_version) 769 - .write(bar, &E::ID); 886 + bar.write( 887 + WithBase::of::<E>(), 888 + regs::NV_PFALCON_FALCON_OS::zeroed().with_value(app_version), 889 + ); 770 890 } 771 891 }
+11 -11
drivers/gpu/nova-core/falcon/gsp.rs
··· 3 3 use kernel::{ 4 4 io::{ 5 5 poll::read_poll_timeout, 6 - Io, // 6 + register::{ 7 + RegisterBase, 8 + WithBase, // 9 + }, 10 + Io, 7 11 }, 8 12 prelude::*, 9 13 time::Delta, // ··· 21 17 PFalcon2Base, 22 18 PFalconBase, // 23 19 }, 24 - regs::{ 25 - self, 26 - macros::RegisterBase, // 27 - }, 20 + regs, 28 21 }; 29 22 30 23 /// Type specifying the `Gsp` falcon engine. Cannot be instantiated. ··· 35 34 const BASE: usize = 0x00111000; 36 35 } 37 36 38 - impl FalconEngine for Gsp { 39 - const ID: Self = Gsp(()); 40 - } 37 + impl FalconEngine for Gsp {} 41 38 42 39 impl Falcon<Gsp> { 43 40 /// Clears the SWGEN0 bit in the Falcon's IRQ status clear register to 44 41 /// allow GSP to signal CPU for processing new messages in message queue. 45 42 pub(crate) fn clear_swgen0_intr(&self, bar: &Bar0) { 46 - regs::NV_PFALCON_FALCON_IRQSCLR::default() 47 - .set_swgen0(true) 48 - .write(bar, &Gsp::ID); 43 + bar.write( 44 + WithBase::of::<Gsp>(), 45 + regs::NV_PFALCON_FALCON_IRQSCLR::zeroed().with_swgen0(true), 46 + ); 49 47 } 50 48 51 49 /// Checks if GSP reload/resume has completed during the boot process.
+32 -23
drivers/gpu/nova-core/falcon/hal/ga102.rs
··· 6 6 device, 7 7 io::{ 8 8 poll::read_poll_timeout, 9 - register::Array, 9 + register::{ 10 + Array, 11 + WithBase, // 12 + }, 10 13 Io, // 11 14 }, 12 15 prelude::*, ··· 32 29 use super::FalconHal; 33 30 34 31 fn select_core_ga102<E: FalconEngine>(bar: &Bar0) -> Result { 35 - let bcr_ctrl = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); 32 + let bcr_ctrl = bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>()); 36 33 if bcr_ctrl.core_select() != PeregrineCoreSelect::Falcon { 37 - regs::NV_PRISCV_RISCV_BCR_CTRL::default() 38 - .set_core_select(PeregrineCoreSelect::Falcon) 39 - .write(bar, &E::ID); 34 + bar.write( 35 + WithBase::of::<E>(), 36 + regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed().with_core_select(PeregrineCoreSelect::Falcon), 37 + ); 40 38 41 39 // TIMEOUT: falcon core should take less than 10ms to report being enabled. 42 40 read_poll_timeout( 43 - || Ok(regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID)), 41 + || Ok(bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>())), 44 42 |r| r.valid(), 45 43 Delta::ZERO, 46 44 Delta::from_millis(10), ··· 87 83 } 88 84 89 85 fn program_brom_ga102<E: FalconEngine>(bar: &Bar0, params: &FalconBromParams) -> Result { 90 - regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() 91 - .set_value(params.pkc_data_offset) 92 - .write(bar, &E::ID, 0); 93 - regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() 94 - .set_value(u32::from(params.engine_id_mask)) 95 - .write(bar, &E::ID); 96 - regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() 97 - .set_ucode_id(params.ucode_id) 98 - .write(bar, &E::ID); 99 - regs::NV_PFALCON2_FALCON_MOD_SEL::default() 100 - .set_algo(FalconModSelAlgo::Rsa3k) 101 - .write(bar, &E::ID); 86 + bar.write( 87 + WithBase::of::<E>().at(0), 88 + regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed().with_value(params.pkc_data_offset), 89 + ); 90 + bar.write( 91 + WithBase::of::<E>(), 92 + regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() 93 + .with_value(u32::from(params.engine_id_mask)), 94 + ); 95 + bar.write( 96 + WithBase::of::<E>(), 97 + regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed().with_ucode_id(params.ucode_id), 98 + ); 99 + bar.write( 100 + WithBase::of::<E>(), 101 + regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(FalconModSelAlgo::Rsa3k), 102 + ); 102 103 103 104 Ok(()) 104 105 } ··· 136 127 } 137 128 138 129 fn is_riscv_active(&self, bar: &Bar0) -> bool { 139 - let cpuctl = regs::NV_PRISCV_RISCV_CPUCTL::read(bar, &E::ID); 140 - cpuctl.active_stat() 130 + bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>()) 131 + .active_stat() 141 132 } 142 133 143 134 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 144 135 // TIMEOUT: memory scrubbing should complete in less than 20ms. 145 136 read_poll_timeout( 146 - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), 137 + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 147 138 |r| r.mem_scrubbing_done(), 148 139 Delta::ZERO, 149 140 Delta::from_millis(20), ··· 152 143 } 153 144 154 145 fn reset_eng(&self, bar: &Bar0) -> Result { 155 - let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); 146 + let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>()); 156 147 157 148 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 158 149 // RESET_READY so a non-failing timeout is used. 159 150 let _ = read_poll_timeout( 160 - || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), 151 + || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 161 152 |r| r.reset_ready(), 162 153 Delta::ZERO, 163 154 Delta::from_micros(150),
+8 -4
drivers/gpu/nova-core/falcon/hal/tu102.rs
··· 3 3 use core::marker::PhantomData; 4 4 5 5 use kernel::{ 6 - io::poll::read_poll_timeout, 6 + io::{ 7 + poll::read_poll_timeout, 8 + register::WithBase, 9 + Io, // 10 + }, 7 11 prelude::*, 8 12 time::Delta, // 9 13 }; ··· 53 49 } 54 50 55 51 fn is_riscv_active(&self, bar: &Bar0) -> bool { 56 - let cpuctl = regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::read(bar, &E::ID); 57 - cpuctl.active_stat() 52 + bar.read(regs::NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS::of::<E>()) 53 + .active_stat() 58 54 } 59 55 60 56 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 61 57 // TIMEOUT: memory scrubbing should complete in less than 10ms. 62 58 read_poll_timeout( 63 - || Ok(regs::NV_PFALCON_FALCON_DMACTL::read(bar, &E::ID)), 59 + || Ok(bar.read(regs::NV_PFALCON_FALCON_DMACTL::of::<E>())), 64 60 |r| r.mem_scrubbing_done(), 65 61 Delta::ZERO, 66 62 Delta::from_millis(10),
+7 -10
drivers/gpu/nova-core/falcon/sec2.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - use crate::{ 4 - falcon::{ 5 - FalconEngine, 6 - PFalcon2Base, 7 - PFalconBase, // 8 - }, 9 - regs::macros::RegisterBase, 3 + use kernel::io::register::RegisterBase; 4 + 5 + use crate::falcon::{ 6 + FalconEngine, 7 + PFalcon2Base, 8 + PFalconBase, // 10 9 }; 11 10 12 11 /// Type specifying the `Sec2` falcon engine. Cannot be instantiated. ··· 19 20 const BASE: usize = 0x00841000; 20 21 } 21 22 22 - impl FalconEngine for Sec2 { 23 - const ID: Self = Sec2(()); 24 - } 23 + impl FalconEngine for Sec2 {}
+11 -8
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
··· 12 12 self, 13 13 Device, // 14 14 }, 15 + io::{ 16 + register::WithBase, // 17 + Io, 18 + }, 15 19 prelude::*, 16 20 ptr::{ 17 21 Alignable, ··· 37 33 Falcon, 38 34 FalconBromParams, 39 35 FalconDmaLoadable, 40 - FalconEngine, 41 36 FalconFbifMemType, 42 37 FalconFbifTarget, 43 38 FalconFirmware, ··· 291 288 .inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?; 292 289 293 290 // Configure DMA index for the bootloader to fetch the FWSEC firmware from system memory. 294 - regs::NV_PFALCON_FBIF_TRANSCFG::try_update( 295 - bar, 296 - &Gsp::ID, 297 - usize::from_safe_cast(self.dmem_desc.ctx_dma), 291 + bar.update( 292 + regs::NV_PFALCON_FBIF_TRANSCFG::of::<Gsp>() 293 + .try_at(usize::from_safe_cast(self.dmem_desc.ctx_dma)) 294 + .ok_or(EINVAL)?, 298 295 |v| { 299 - v.set_target(FalconFbifTarget::CoherentSysmem) 300 - .set_mem_type(FalconFbifMemType::Physical) 296 + v.with_target(FalconFbifTarget::CoherentSysmem) 297 + .with_mem_type(FalconFbifMemType::Physical) 301 298 }, 302 - )?; 299 + ); 303 300 304 301 let (mbox0, _) = falcon 305 302 .boot(bar, Some(0), None)
+186 -167
drivers/gpu/nova-core/regs.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 - // Required to retain the original register names used by OpenRM, which are all capital snake case 4 - // but are mapped to types. 5 - #![allow(non_camel_case_types)] 6 - 7 - #[macro_use] 8 - pub(crate) mod macros; 9 - 10 3 use kernel::{ 11 - io, 4 + io::{ 5 + self, 6 + register::WithBase, 7 + Io, // 8 + }, 12 9 prelude::*, 13 10 time, // 14 11 }; ··· 287 290 288 291 // PFALCON 289 292 290 - register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] { 291 - 4:4 halt as bool; 292 - 6:6 swgen0 as bool; 293 - }); 293 + io::register! { 294 + pub(crate) NV_PFALCON_FALCON_IRQSCLR(u32) @ PFalconBase + 0x00000004 { 295 + 6:6 swgen0 => bool; 296 + 4:4 halt => bool; 297 + } 294 298 295 - register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] { 296 - 31:0 value as u32; 297 - }); 299 + pub(crate) NV_PFALCON_FALCON_MAILBOX0(u32) @ PFalconBase + 0x00000040 { 300 + 31:0 value => u32; 301 + } 298 302 299 - register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] { 300 - 31:0 value as u32; 301 - }); 303 + pub(crate) NV_PFALCON_FALCON_MAILBOX1(u32) @ PFalconBase + 0x00000044 { 304 + 31:0 value => u32; 305 + } 302 306 303 - // Used to store version information about the firmware running 304 - // on the Falcon processor. 305 - register!(NV_PFALCON_FALCON_OS @ PFalconBase[0x00000080] { 306 - 31:0 value as u32; 307 - }); 307 + /// Used to store version information about the firmware running 308 + /// on the Falcon processor. 309 + pub(crate) NV_PFALCON_FALCON_OS(u32) @ PFalconBase + 0x00000080 { 310 + 31:0 value => u32; 311 + } 308 312 309 - register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] { 310 - 31:0 value as u32; 311 - }); 313 + pub(crate) NV_PFALCON_FALCON_RM(u32) @ PFalconBase + 0x00000084 { 314 + 31:0 value => u32; 315 + } 312 316 313 - register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] { 314 - 10:10 riscv as bool; 315 - 12:12 mem_scrubbing as bool, "Set to 0 after memory scrubbing is completed"; 316 - 31:31 reset_ready as bool, "Signal indicating that reset is completed (GA102+)"; 317 - }); 317 + pub(crate) NV_PFALCON_FALCON_HWCFG2(u32) @ PFalconBase + 0x000000f4 { 318 + /// Signal indicating that reset is completed (GA102+). 319 + 31:31 reset_ready => bool; 320 + /// Set to 0 after memory scrubbing is completed. 321 + 12:12 mem_scrubbing => bool; 322 + 10:10 riscv => bool; 323 + } 318 324 319 - impl NV_PFALCON_FALCON_HWCFG2 { 320 - /// Returns `true` if memory scrubbing is completed. 321 - pub(crate) fn mem_scrubbing_done(self) -> bool { 322 - !self.mem_scrubbing() 325 + pub(crate) NV_PFALCON_FALCON_CPUCTL(u32) @ PFalconBase + 0x00000100 { 326 + 6:6 alias_en => bool; 327 + 4:4 halted => bool; 328 + 1:1 startcpu => bool; 329 + } 330 + 331 + pub(crate) NV_PFALCON_FALCON_BOOTVEC(u32) @ PFalconBase + 0x00000104 { 332 + 31:0 value => u32; 333 + } 334 + 335 + pub(crate) NV_PFALCON_FALCON_DMACTL(u32) @ PFalconBase + 0x0000010c { 336 + 7:7 secure_stat => bool; 337 + 6:3 dmaq_num; 338 + 2:2 imem_scrubbing => bool; 339 + 1:1 dmem_scrubbing => bool; 340 + 0:0 require_ctx => bool; 341 + } 342 + 343 + pub(crate) NV_PFALCON_FALCON_DMATRFBASE(u32) @ PFalconBase + 0x00000110 { 344 + 31:0 base => u32; 345 + } 346 + 347 + pub(crate) NV_PFALCON_FALCON_DMATRFMOFFS(u32) @ PFalconBase + 0x00000114 { 348 + 23:0 offs; 349 + } 350 + 351 + pub(crate) NV_PFALCON_FALCON_DMATRFCMD(u32) @ PFalconBase + 0x00000118 { 352 + 16:16 set_dmtag; 353 + 14:12 ctxdma; 354 + 10:8 size ?=> DmaTrfCmdSize; 355 + 5:5 is_write => bool; 356 + 4:4 imem => bool; 357 + 3:2 sec; 358 + 1:1 idle => bool; 359 + 0:0 full => bool; 360 + } 361 + 362 + pub(crate) NV_PFALCON_FALCON_DMATRFFBOFFS(u32) @ PFalconBase + 0x0000011c { 363 + 31:0 offs => u32; 364 + } 365 + 366 + pub(crate) NV_PFALCON_FALCON_DMATRFBASE1(u32) @ PFalconBase + 0x00000128 { 367 + 8:0 base; 368 + } 369 + 370 + pub(crate) NV_PFALCON_FALCON_HWCFG1(u32) @ PFalconBase + 0x0000012c { 371 + /// Core revision subversion. 372 + 7:6 core_rev_subversion => FalconCoreRevSubversion; 373 + /// Security model. 374 + 5:4 security_model ?=> FalconSecurityModel; 375 + /// Core revision. 376 + 3:0 core_rev ?=> FalconCoreRev; 377 + } 378 + 379 + pub(crate) NV_PFALCON_FALCON_CPUCTL_ALIAS(u32) @ PFalconBase + 0x00000130 { 380 + 1:1 startcpu => bool; 381 + } 382 + 383 + /// IMEM access control register. Up to 4 ports are available for IMEM access. 384 + pub(crate) NV_PFALCON_FALCON_IMEMC(u32)[4, stride = 16] @ PFalconBase + 0x00000180 { 385 + /// Access secure IMEM. 386 + 28:28 secure => bool; 387 + /// Auto-increment on write. 388 + 24:24 aincw => bool; 389 + /// IMEM block and word offset. 390 + 15:0 offs; 391 + } 392 + 393 + /// IMEM data register. Reading/writing this register accesses IMEM at the address 394 + /// specified by the corresponding IMEMC register. 395 + pub(crate) NV_PFALCON_FALCON_IMEMD(u32)[4, stride = 16] @ PFalconBase + 0x00000184 { 396 + 31:0 data; 397 + } 398 + 399 + /// IMEM tag register. Used to set the tag for the current IMEM block. 400 + pub(crate) NV_PFALCON_FALCON_IMEMT(u32)[4, stride = 16] @ PFalconBase + 0x00000188 { 401 + 15:0 tag; 402 + } 403 + 404 + /// DMEM access control register. Up to 8 ports are available for DMEM access. 405 + pub(crate) NV_PFALCON_FALCON_DMEMC(u32)[8, stride = 8] @ PFalconBase + 0x000001c0 { 406 + /// Auto-increment on write. 407 + 24:24 aincw => bool; 408 + /// DMEM block and word offset. 409 + 15:0 offs; 410 + } 411 + 412 + /// DMEM data register. Reading/writing this register accesses DMEM at the address 413 + /// specified by the corresponding DMEMC register. 414 + pub(crate) NV_PFALCON_FALCON_DMEMD(u32)[8, stride = 8] @ PFalconBase + 0x000001c4 { 415 + 31:0 data; 416 + } 417 + 418 + /// Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the 419 + /// falcon instance. 420 + pub(crate) NV_PFALCON_FALCON_ENGINE(u32) @ PFalconBase + 0x000003c0 { 421 + 0:0 reset => bool; 422 + } 423 + 424 + pub(crate) NV_PFALCON_FBIF_TRANSCFG(u32)[8] @ PFalconBase + 0x00000600 { 425 + 2:2 mem_type => FalconFbifMemType; 426 + 1:0 target ?=> FalconFbifTarget; 427 + } 428 + 429 + pub(crate) NV_PFALCON_FBIF_CTL(u32) @ PFalconBase + 0x00000624 { 430 + 7:7 allow_phys_no_ctx => bool; 323 431 } 324 432 } 325 - 326 - register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] { 327 - 1:1 startcpu as bool; 328 - 4:4 halted as bool; 329 - 6:6 alias_en as bool; 330 - }); 331 - 332 - register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] { 333 - 31:0 value as u32; 334 - }); 335 - 336 - register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] { 337 - 0:0 require_ctx as bool; 338 - 1:1 dmem_scrubbing as bool; 339 - 2:2 imem_scrubbing as bool; 340 - 6:3 dmaq_num as u8; 341 - 7:7 secure_stat as bool; 342 - }); 343 433 344 434 impl NV_PFALCON_FALCON_DMACTL { 345 435 /// Returns `true` if memory scrubbing is completed. ··· 435 351 } 436 352 } 437 353 438 - register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] { 439 - 31:0 base as u32; 440 - }); 441 - 442 - register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] { 443 - 23:0 offs as u32; 444 - }); 445 - 446 - register!(NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase[0x00000118] { 447 - 0:0 full as bool; 448 - 1:1 idle as bool; 449 - 3:2 sec as u8; 450 - 4:4 imem as bool; 451 - 5:5 is_write as bool; 452 - 10:8 size as u8 ?=> DmaTrfCmdSize; 453 - 14:12 ctxdma as u8; 454 - 16:16 set_dmtag as u8; 455 - }); 456 - 457 354 impl NV_PFALCON_FALCON_DMATRFCMD { 458 355 /// Programs the `imem` and `sec` fields for the given FalconMem 459 356 pub(crate) fn with_falcon_mem(self, mem: FalconMem) -> Self { 460 - self.set_imem(mem != FalconMem::Dmem) 461 - .set_sec(if mem == FalconMem::ImemSecure { 1 } else { 0 }) 357 + let this = self.with_imem(mem != FalconMem::Dmem); 358 + 359 + match mem { 360 + FalconMem::ImemSecure => this.with_const_sec::<1>(), 361 + _ => this.with_const_sec::<0>(), 362 + } 462 363 } 463 364 } 464 - 465 - register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] { 466 - 31:0 offs as u32; 467 - }); 468 - 469 - register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] { 470 - 8:0 base as u16; 471 - }); 472 - 473 - register!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] { 474 - 3:0 core_rev as u8 ?=> FalconCoreRev, "Core revision"; 475 - 5:4 security_model as u8 ?=> FalconSecurityModel, "Security model"; 476 - 7:6 core_rev_subversion as u8 ?=> FalconCoreRevSubversion, "Core revision subversion"; 477 - }); 478 - 479 - register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] { 480 - 1:1 startcpu as bool; 481 - }); 482 - 483 - // IMEM access control register. Up to 4 ports are available for IMEM access. 484 - register!(NV_PFALCON_FALCON_IMEMC @ PFalconBase[0x00000180[4; 16]] { 485 - 15:0 offs as u16, "IMEM block and word offset"; 486 - 24:24 aincw as bool, "Auto-increment on write"; 487 - 28:28 secure as bool, "Access secure IMEM"; 488 - }); 489 - 490 - // IMEM data register. Reading/writing this register accesses IMEM at the address 491 - // specified by the corresponding IMEMC register. 492 - register!(NV_PFALCON_FALCON_IMEMD @ PFalconBase[0x00000184[4; 16]] { 493 - 31:0 data as u32; 494 - }); 495 - 496 - // IMEM tag register. Used to set the tag for the current IMEM block. 497 - register!(NV_PFALCON_FALCON_IMEMT @ PFalconBase[0x00000188[4; 16]] { 498 - 15:0 tag as u16; 499 - }); 500 - 501 - // DMEM access control register. Up to 8 ports are available for DMEM access. 502 - register!(NV_PFALCON_FALCON_DMEMC @ PFalconBase[0x000001c0[8; 8]] { 503 - 15:0 offs as u16, "DMEM block and word offset"; 504 - 24:24 aincw as bool, "Auto-increment on write"; 505 - }); 506 - 507 - // DMEM data register. Reading/writing this register accesses DMEM at the address 508 - // specified by the corresponding DMEMC register. 509 - register!(NV_PFALCON_FALCON_DMEMD @ PFalconBase[0x000001c4[8; 8]] { 510 - 31:0 data as u32; 511 - }); 512 - 513 - // Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the falcon 514 - // instance. 515 - register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] { 516 - 0:0 reset as bool; 517 - }); 518 365 519 366 impl NV_PFALCON_FALCON_ENGINE { 520 367 /// Resets the falcon 521 368 pub(crate) fn reset_engine<E: FalconEngine>(bar: &Bar0) { 522 - Self::read(bar, &E::ID).set_reset(true).write(bar, &E::ID); 369 + bar.update(Self::of::<E>(), |r| r.with_reset(true)); 523 370 524 371 // TIMEOUT: falcon engine should not take more than 10us to reset. 525 372 time::delay::fsleep(time::Delta::from_micros(10)); 526 373 527 - Self::read(bar, &E::ID).set_reset(false).write(bar, &E::ID); 374 + bar.update(Self::of::<E>(), |r| r.with_reset(false)); 528 375 } 529 376 } 530 377 531 - register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] { 532 - 1:0 target as u8 ?=> FalconFbifTarget; 533 - 2:2 mem_type as bool => FalconFbifMemType; 534 - }); 535 - 536 - register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] { 537 - 7:7 allow_phys_no_ctx as bool; 538 - }); 378 + impl NV_PFALCON_FALCON_HWCFG2 { 379 + /// Returns `true` if memory scrubbing is completed. 380 + pub(crate) fn mem_scrubbing_done(self) -> bool { 381 + !self.mem_scrubbing() 382 + } 383 + } 539 384 540 385 /* PFALCON2 */ 541 386 542 - register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] { 543 - 7:0 algo as u8 ?=> FalconModSelAlgo; 544 - }); 387 + io::register! { 388 + pub(crate) NV_PFALCON2_FALCON_MOD_SEL(u32) @ PFalcon2Base + 0x00000180 { 389 + 7:0 algo ?=> FalconModSelAlgo; 390 + } 545 391 546 - register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198] { 547 - 7:0 ucode_id as u8; 548 - }); 392 + pub(crate) NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID(u32) @ PFalcon2Base + 0x00000198 { 393 + 7:0 ucode_id => u8; 394 + } 549 395 550 - register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] { 551 - 31:0 value as u32; 552 - }); 396 + pub(crate) NV_PFALCON2_FALCON_BROM_ENGIDMASK(u32) @ PFalcon2Base + 0x0000019c { 397 + 31:0 value => u32; 398 + } 553 399 554 - // OpenRM defines this as a register array, but doesn't specify its size and only uses its first 555 - // element. Be conservative until we know the actual size or need to use more registers. 556 - register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] { 557 - 31:0 value as u32; 558 - }); 400 + /// OpenRM defines this as a register array, but doesn't specify its size and only uses its 401 + /// first element. Be conservative until we know the actual size or need to use more registers. 402 + pub(crate) NV_PFALCON2_FALCON_BROM_PARAADDR(u32)[1] @ PFalcon2Base + 0x00000210 { 403 + 31:0 value => u32; 404 + } 405 + } 559 406 560 407 // PRISCV 561 408 562 - // RISC-V status register for debug (Turing and GA100 only). 563 - // Reflects current RISC-V core status. 564 - register!(NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS @ PFalcon2Base[0x00000240] { 565 - 0:0 active_stat as bool, "RISC-V core active/inactive status"; 566 - }); 409 + io::register! { 410 + /// RISC-V status register for debug (Turing and GA100 only). 411 + /// Reflects current RISC-V core status. 412 + pub(crate) NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS(u32) @ PFalcon2Base + 0x00000240 { 413 + /// RISC-V core active/inactive status. 414 + 0:0 active_stat => bool; 415 + } 567 416 568 - // GA102 and later 569 - register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] { 570 - 0:0 halted as bool; 571 - 7:7 active_stat as bool; 572 - }); 417 + /// GA102 and later. 418 + pub(crate) NV_PRISCV_RISCV_CPUCTL(u32) @ PFalcon2Base + 0x00000388 { 419 + 7:7 active_stat => bool; 420 + 0:0 halted => bool; 421 + } 573 422 574 - register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalcon2Base[0x00000668] { 575 - 0:0 valid as bool; 576 - 4:4 core_select as bool => PeregrineCoreSelect; 577 - 8:8 br_fetch as bool; 578 - }); 423 + /// GA102 and later. 424 + pub(crate) NV_PRISCV_RISCV_BCR_CTRL(u32) @ PFalcon2Base + 0x00000668 { 425 + 8:8 br_fetch => bool; 426 + 4:4 core_select => PeregrineCoreSelect; 427 + 0:0 valid => bool; 428 + } 429 + } 579 430 580 431 // The modules below provide registers that are not identical on all supported chips. They should 581 432 // only be used in HAL modules.
-739
drivers/gpu/nova-core/regs/macros.rs
··· 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. Please look at the [`bitfield`] macro for the 12 - //! complete syntax of fields definitions. 13 - 14 - /// Trait providing a base address to be added to the offset of a relative register to obtain 15 - /// its actual offset. 16 - /// 17 - /// The `T` generic argument is used to distinguish which base to use, in case a type provides 18 - /// several bases. It is given to the `register!` macro to restrict the use of the register to 19 - /// implementors of this particular variant. 20 - pub(crate) trait RegisterBase<T> { 21 - const BASE: usize; 22 - } 23 - 24 - /// Defines a dedicated type for a register with an absolute offset, including getter and setter 25 - /// methods for its fields and methods to read and write it from an `Io` region. 26 - /// 27 - /// Example: 28 - /// 29 - /// ```no_run 30 - /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { 31 - /// 3:0 minor_revision as u8, "Minor revision of the chip"; 32 - /// 7:4 major_revision as u8, "Major revision of the chip"; 33 - /// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; 34 - /// }); 35 - /// ``` 36 - /// 37 - /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` 38 - /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least 39 - /// significant bits of the register. Each field can be accessed and modified using accessor 40 - /// methods: 41 - /// 42 - /// ```no_run 43 - /// // Read from the register's defined offset (0x100). 44 - /// let boot0 = BOOT_0::read(&bar); 45 - /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); 46 - /// 47 - /// // `Chipset::try_from` is called with the value of the `chipset` field and returns an 48 - /// // error if it is invalid. 49 - /// let chipset = boot0.chipset()?; 50 - /// 51 - /// // Update some fields and write the value back. 52 - /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); 53 - /// 54 - /// // Or, just read and update the register in a single step: 55 - /// BOOT_0::update(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); 56 - /// ``` 57 - /// 58 - /// The documentation strings are optional. If present, they will be added to the type's 59 - /// definition, or the field getter and setter methods they are attached to. 60 - /// 61 - /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful 62 - /// for cases where a register's interpretation depends on the context: 63 - /// 64 - /// ```no_run 65 - /// register!(SCRATCH @ 0x00000200, "Scratch register" { 66 - /// 31:0 value as u32, "Raw value"; 67 - /// }); 68 - /// 69 - /// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" { 70 - /// 0:0 completed as bool, "Whether the firmware has completed booting"; 71 - /// }); 72 - /// ``` 73 - /// 74 - /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also 75 - /// providing its own `completed` field. 76 - /// 77 - /// ## Relative registers 78 - /// 79 - /// A register can be defined as being accessible from a fixed offset of a provided base. For 80 - /// instance, imagine the following I/O space: 81 - /// 82 - /// ```text 83 - /// +-----------------------------+ 84 - /// | ... | 85 - /// | | 86 - /// 0x100--->+------------CPU0-------------+ 87 - /// | | 88 - /// 0x110--->+-----------------------------+ 89 - /// | CPU_CTL | 90 - /// +-----------------------------+ 91 - /// | ... | 92 - /// | | 93 - /// | | 94 - /// 0x200--->+------------CPU1-------------+ 95 - /// | | 96 - /// 0x210--->+-----------------------------+ 97 - /// | CPU_CTL | 98 - /// +-----------------------------+ 99 - /// | ... | 100 - /// +-----------------------------+ 101 - /// ``` 102 - /// 103 - /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 104 - /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 105 - /// them twice and would prefer a way to select which one to use from a single definition 106 - /// 107 - /// This can be done using the `Base[Offset]` syntax when specifying the register's address. 108 - /// 109 - /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 110 - /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 111 - /// this register needs to implement `RegisterBase<Base>`. Here is the above example translated 112 - /// into code: 113 - /// 114 - /// ```no_run 115 - /// // Type used to identify the base. 116 - /// pub(crate) struct CpuCtlBase; 117 - /// 118 - /// // ZST describing `CPU0`. 119 - /// struct Cpu0; 120 - /// impl RegisterBase<CpuCtlBase> for Cpu0 { 121 - /// const BASE: usize = 0x100; 122 - /// } 123 - /// // Singleton of `CPU0` used to identify it. 124 - /// const CPU0: Cpu0 = Cpu0; 125 - /// 126 - /// // ZST describing `CPU1`. 127 - /// struct Cpu1; 128 - /// impl RegisterBase<CpuCtlBase> for Cpu1 { 129 - /// const BASE: usize = 0x200; 130 - /// } 131 - /// // Singleton of `CPU1` used to identify it. 132 - /// const CPU1: Cpu1 = Cpu1; 133 - /// 134 - /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 135 - /// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { 136 - /// 0:0 start as bool, "Start the CPU core"; 137 - /// }); 138 - /// 139 - /// // The `read`, `write` and `update` methods of relative registers take an extra `base` argument 140 - /// // that is used to resolve its final address by adding its `BASE` to the offset of the 141 - /// // register. 142 - /// 143 - /// // Start `CPU0`. 144 - /// CPU_CTL::update(bar, &CPU0, |r| r.set_start(true)); 145 - /// 146 - /// // Start `CPU1`. 147 - /// CPU_CTL::update(bar, &CPU1, |r| r.set_start(true)); 148 - /// 149 - /// // Aliases can also be defined for relative register. 150 - /// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { 151 - /// 1:1 alias_start as bool, "Start the aliased CPU core"; 152 - /// }); 153 - /// 154 - /// // Start the aliased `CPU0`. 155 - /// CPU_CTL_ALIAS::update(bar, &CPU0, |r| r.set_alias_start(true)); 156 - /// ``` 157 - /// 158 - /// ## Arrays of registers 159 - /// 160 - /// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas 161 - /// can be defined as an array of identical registers, allowing them to be accessed by index with 162 - /// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add 163 - /// an `idx` parameter to their `read`, `write` and `update` methods: 164 - /// 165 - /// ```no_run 166 - /// # fn no_run() -> Result<(), Error> { 167 - /// # fn get_scratch_idx() -> usize { 168 - /// # 0x15 169 - /// # } 170 - /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 171 - /// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { 172 - /// 31:0 value as u32; 173 - /// }); 174 - /// 175 - /// // Read scratch register 0, i.e. I/O address `0x80`. 176 - /// let scratch_0 = SCRATCH::read(bar, 0).value(); 177 - /// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 178 - /// let scratch_15 = SCRATCH::read(bar, 15).value(); 179 - /// 180 - /// // This is out of bounds and won't build. 181 - /// // let scratch_128 = SCRATCH::read(bar, 128).value(); 182 - /// 183 - /// // Runtime-obtained array index. 184 - /// let scratch_idx = get_scratch_idx(); 185 - /// // Access on a runtime index returns an error if it is out-of-bounds. 186 - /// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value(); 187 - /// 188 - /// // Alias to a particular register in an array. 189 - /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 190 - /// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" { 191 - /// 7:0 status as u8; 192 - /// }); 193 - /// 194 - /// let status = FIRMWARE_STATUS::read(bar).status(); 195 - /// 196 - /// // Non-contiguous register arrays can be defined by adding a stride parameter. 197 - /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the 198 - /// // registers of the two declarations below are interleaved. 199 - /// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" { 200 - /// 31:0 value as u32; 201 - /// }); 202 - /// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" { 203 - /// 31:0 value as u32; 204 - /// }); 205 - /// # Ok(()) 206 - /// # } 207 - /// ``` 208 - /// 209 - /// ## Relative arrays of registers 210 - /// 211 - /// Combining the two features described in the sections above, arrays of registers accessible from 212 - /// a base can also be defined: 213 - /// 214 - /// ```no_run 215 - /// # fn no_run() -> Result<(), Error> { 216 - /// # fn get_scratch_idx() -> usize { 217 - /// # 0x15 218 - /// # } 219 - /// // Type used as parameter of `RegisterBase` to specify the base. 220 - /// pub(crate) struct CpuCtlBase; 221 - /// 222 - /// // ZST describing `CPU0`. 223 - /// struct Cpu0; 224 - /// impl RegisterBase<CpuCtlBase> for Cpu0 { 225 - /// const BASE: usize = 0x100; 226 - /// } 227 - /// // Singleton of `CPU0` used to identify it. 228 - /// const CPU0: Cpu0 = Cpu0; 229 - /// 230 - /// // ZST describing `CPU1`. 231 - /// struct Cpu1; 232 - /// impl RegisterBase<CpuCtlBase> for Cpu1 { 233 - /// const BASE: usize = 0x200; 234 - /// } 235 - /// // Singleton of `CPU1` used to identify it. 236 - /// const CPU1: Cpu1 = Cpu1; 237 - /// 238 - /// // 64 per-cpu scratch registers, arranged as an contiguous array. 239 - /// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" { 240 - /// 31:0 value as u32; 241 - /// }); 242 - /// 243 - /// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value(); 244 - /// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value(); 245 - /// 246 - /// // This won't build. 247 - /// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value(); 248 - /// 249 - /// // Runtime-obtained array index. 250 - /// let scratch_idx = get_scratch_idx(); 251 - /// // Access on a runtime value returns an error if it is out-of-bounds. 252 - /// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value(); 253 - /// 254 - /// // `SCRATCH[8]` is used to convey the firmware exit code. 255 - /// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]], 256 - /// "Per-CPU firmware exit status code" { 257 - /// 7:0 status as u8; 258 - /// }); 259 - /// 260 - /// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status(); 261 - /// 262 - /// // Non-contiguous register arrays can be defined by adding a stride parameter. 263 - /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the 264 - /// // registers of the two declarations below are interleaved. 265 - /// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]], 266 - /// "Scratch registers bank 0" { 267 - /// 31:0 value as u32; 268 - /// }); 269 - /// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]], 270 - /// "Scratch registers bank 1" { 271 - /// 31:0 value as u32; 272 - /// }); 273 - /// # Ok(()) 274 - /// # } 275 - /// ``` 276 - macro_rules! register { 277 - // Creates a register at a fixed offset of the MMIO space. 278 - ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { 279 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 280 - register!(@io_fixed $name @ $offset); 281 - }; 282 - 283 - // Creates an alias register of fixed offset register `alias` with its own fields. 284 - ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { 285 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 286 - register!(@io_fixed $name @ $alias::OFFSET); 287 - }; 288 - 289 - // Creates a register at a relative offset from a base address provider. 290 - ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { 291 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 292 - register!(@io_relative $name @ $base [ $offset ]); 293 - }; 294 - 295 - // Creates an alias register of relative offset register `alias` with its own fields. 296 - ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { 297 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 298 - register!(@io_relative $name @ $base [ $alias::OFFSET ]); 299 - }; 300 - 301 - // Creates an array of registers at a fixed offset of the MMIO space. 302 - ( 303 - $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? { 304 - $($fields:tt)* 305 - } 306 - ) => { 307 - static_assert!(::core::mem::size_of::<u32>() <= $stride); 308 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 309 - register!(@io_array $name @ $offset [ $size ; $stride ]); 310 - }; 311 - 312 - // Shortcut for contiguous array of registers (stride == size of element). 313 - ( 314 - $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? { 315 - $($fields:tt)* 316 - } 317 - ) => { 318 - register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? { 319 - $($fields)* 320 - } ); 321 - }; 322 - 323 - // Creates an array of registers at a relative offset from a base address provider. 324 - ( 325 - $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ] 326 - $(, $comment:literal)? { $($fields:tt)* } 327 - ) => { 328 - static_assert!(::core::mem::size_of::<u32>() <= $stride); 329 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 330 - register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]); 331 - }; 332 - 333 - // Shortcut for contiguous array of relative registers (stride == size of element). 334 - ( 335 - $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? { 336 - $($fields:tt)* 337 - } 338 - ) => { 339 - register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ] 340 - $(, $comment)? { $($fields)* } ); 341 - }; 342 - 343 - // Creates an alias of register `idx` of relative array of registers `alias` with its own 344 - // fields. 345 - ( 346 - $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? { 347 - $($fields:tt)* 348 - } 349 - ) => { 350 - static_assert!($idx < $alias::SIZE); 351 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 352 - register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] ); 353 - }; 354 - 355 - // Creates an alias of register `idx` of array of registers `alias` with its own fields. 356 - // This rule belongs to the (non-relative) register arrays set, but needs to be put last 357 - // to avoid it being interpreted in place of the relative register array alias rule. 358 - ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { 359 - static_assert!($idx < $alias::SIZE); 360 - bitfield!(pub(crate) struct $name(u32) $(, $comment)? { $($fields)* } ); 361 - register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); 362 - }; 363 - 364 - // Generates the IO accessors for a fixed offset register. 365 - (@io_fixed $name:ident @ $offset:expr) => { 366 - #[allow(dead_code)] 367 - impl $name { 368 - pub(crate) const OFFSET: usize = $offset; 369 - 370 - /// Read the register from its address in `io`. 371 - #[inline(always)] 372 - pub(crate) fn read<T, I>(io: &T) -> Self where 373 - T: ::core::ops::Deref<Target = I>, 374 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 375 - { 376 - Self(io.read32($offset)) 377 - } 378 - 379 - /// Write the value contained in `self` to the register address in `io`. 380 - #[inline(always)] 381 - pub(crate) fn write<T, I>(self, io: &T) where 382 - T: ::core::ops::Deref<Target = I>, 383 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 384 - { 385 - io.write32(self.0, $offset) 386 - } 387 - 388 - /// Read the register from its address in `io` and run `f` on its value to obtain a new 389 - /// value to write back. 390 - #[inline(always)] 391 - pub(crate) fn update<T, I, F>( 392 - io: &T, 393 - f: F, 394 - ) where 395 - T: ::core::ops::Deref<Target = I>, 396 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 397 - F: ::core::ops::FnOnce(Self) -> Self, 398 - { 399 - let reg = f(Self::read(io)); 400 - reg.write(io); 401 - } 402 - } 403 - }; 404 - 405 - // Generates the IO accessors for a relative offset register. 406 - (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => { 407 - #[allow(dead_code)] 408 - impl $name { 409 - pub(crate) const OFFSET: usize = $offset; 410 - 411 - /// Read the register from `io`, using the base address provided by `base` and adding 412 - /// the register's offset to it. 413 - #[inline(always)] 414 - pub(crate) fn read<T, I, B>( 415 - io: &T, 416 - #[allow(unused_variables)] 417 - base: &B, 418 - ) -> Self where 419 - T: ::core::ops::Deref<Target = I>, 420 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 421 - B: crate::regs::macros::RegisterBase<$base>, 422 - { 423 - const OFFSET: usize = $name::OFFSET; 424 - 425 - let value = io.read32( 426 - <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 427 - ); 428 - 429 - Self(value) 430 - } 431 - 432 - /// Write the value contained in `self` to `io`, using the base address provided by 433 - /// `base` and adding the register's offset to it. 434 - #[inline(always)] 435 - pub(crate) fn write<T, I, B>( 436 - self, 437 - io: &T, 438 - #[allow(unused_variables)] 439 - base: &B, 440 - ) where 441 - T: ::core::ops::Deref<Target = I>, 442 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 443 - B: crate::regs::macros::RegisterBase<$base>, 444 - { 445 - const OFFSET: usize = $name::OFFSET; 446 - 447 - io.write32( 448 - self.0, 449 - <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 450 - ); 451 - } 452 - 453 - /// Read the register from `io`, using the base address provided by `base` and adding 454 - /// the register's offset to it, then run `f` on its value to obtain a new value to 455 - /// write back. 456 - #[inline(always)] 457 - pub(crate) fn update<T, I, B, F>( 458 - io: &T, 459 - base: &B, 460 - f: F, 461 - ) where 462 - T: ::core::ops::Deref<Target = I>, 463 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 464 - B: crate::regs::macros::RegisterBase<$base>, 465 - F: ::core::ops::FnOnce(Self) -> Self, 466 - { 467 - let reg = f(Self::read(io, base)); 468 - reg.write(io, base); 469 - } 470 - } 471 - }; 472 - 473 - // Generates the IO accessors for an array of registers. 474 - (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => { 475 - #[allow(dead_code)] 476 - impl $name { 477 - pub(crate) const OFFSET: usize = $offset; 478 - pub(crate) const SIZE: usize = $size; 479 - pub(crate) const STRIDE: usize = $stride; 480 - 481 - /// Read the array register at index `idx` from its address in `io`. 482 - #[inline(always)] 483 - pub(crate) fn read<T, I>( 484 - io: &T, 485 - idx: usize, 486 - ) -> Self where 487 - T: ::core::ops::Deref<Target = I>, 488 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 489 - { 490 - build_assert!(idx < Self::SIZE); 491 - 492 - let offset = Self::OFFSET + (idx * Self::STRIDE); 493 - let value = io.read32(offset); 494 - 495 - Self(value) 496 - } 497 - 498 - /// Write the value contained in `self` to the array register with index `idx` in `io`. 499 - #[inline(always)] 500 - pub(crate) fn write<T, I>( 501 - self, 502 - io: &T, 503 - idx: usize 504 - ) where 505 - T: ::core::ops::Deref<Target = I>, 506 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 507 - { 508 - build_assert!(idx < Self::SIZE); 509 - 510 - let offset = Self::OFFSET + (idx * Self::STRIDE); 511 - 512 - io.write32(self.0, offset); 513 - } 514 - 515 - /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 516 - /// new value to write back. 517 - #[inline(always)] 518 - pub(crate) fn update<T, I, F>( 519 - io: &T, 520 - idx: usize, 521 - f: F, 522 - ) where 523 - T: ::core::ops::Deref<Target = I>, 524 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 525 - F: ::core::ops::FnOnce(Self) -> Self, 526 - { 527 - let reg = f(Self::read(io, idx)); 528 - reg.write(io, idx); 529 - } 530 - 531 - /// Read the array register at index `idx` from its address in `io`. 532 - /// 533 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 534 - /// access was out-of-bounds. 535 - #[inline(always)] 536 - pub(crate) fn try_read<T, I>( 537 - io: &T, 538 - idx: usize, 539 - ) -> ::kernel::error::Result<Self> where 540 - T: ::core::ops::Deref<Target = I>, 541 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 542 - { 543 - if idx < Self::SIZE { 544 - Ok(Self::read(io, idx)) 545 - } else { 546 - Err(EINVAL) 547 - } 548 - } 549 - 550 - /// Write the value contained in `self` to the array register with index `idx` in `io`. 551 - /// 552 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 553 - /// access was out-of-bounds. 554 - #[inline(always)] 555 - pub(crate) fn try_write<T, I>( 556 - self, 557 - io: &T, 558 - idx: usize, 559 - ) -> ::kernel::error::Result where 560 - T: ::core::ops::Deref<Target = I>, 561 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 562 - { 563 - if idx < Self::SIZE { 564 - Ok(self.write(io, idx)) 565 - } else { 566 - Err(EINVAL) 567 - } 568 - } 569 - 570 - /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 571 - /// new value to write back. 572 - /// 573 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 574 - /// access was out-of-bounds. 575 - #[inline(always)] 576 - pub(crate) fn try_update<T, I, F>( 577 - io: &T, 578 - idx: usize, 579 - f: F, 580 - ) -> ::kernel::error::Result where 581 - T: ::core::ops::Deref<Target = I>, 582 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 583 - F: ::core::ops::FnOnce(Self) -> Self, 584 - { 585 - if idx < Self::SIZE { 586 - Ok(Self::update(io, idx, f)) 587 - } else { 588 - Err(EINVAL) 589 - } 590 - } 591 - } 592 - }; 593 - 594 - // Generates the IO accessors for an array of relative registers. 595 - ( 596 - @io_relative_array $name:ident @ $base:ty 597 - [ $offset:literal [ $size:expr ; $stride:expr ] ] 598 - ) => { 599 - #[allow(dead_code)] 600 - impl $name { 601 - pub(crate) const OFFSET: usize = $offset; 602 - pub(crate) const SIZE: usize = $size; 603 - pub(crate) const STRIDE: usize = $stride; 604 - 605 - /// Read the array register at index `idx` from `io`, using the base address provided 606 - /// by `base` and adding the register's offset to it. 607 - #[inline(always)] 608 - pub(crate) fn read<T, I, B>( 609 - io: &T, 610 - #[allow(unused_variables)] 611 - base: &B, 612 - idx: usize, 613 - ) -> Self where 614 - T: ::core::ops::Deref<Target = I>, 615 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 616 - B: crate::regs::macros::RegisterBase<$base>, 617 - { 618 - build_assert!(idx < Self::SIZE); 619 - 620 - let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + 621 - Self::OFFSET + (idx * Self::STRIDE); 622 - let value = io.read32(offset); 623 - 624 - Self(value) 625 - } 626 - 627 - /// Write the value contained in `self` to `io`, using the base address provided by 628 - /// `base` and adding the offset of array register `idx` to it. 629 - #[inline(always)] 630 - pub(crate) fn write<T, I, B>( 631 - self, 632 - io: &T, 633 - #[allow(unused_variables)] 634 - base: &B, 635 - idx: usize 636 - ) where 637 - T: ::core::ops::Deref<Target = I>, 638 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 639 - B: crate::regs::macros::RegisterBase<$base>, 640 - { 641 - build_assert!(idx < Self::SIZE); 642 - 643 - let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE + 644 - Self::OFFSET + (idx * Self::STRIDE); 645 - 646 - io.write32(self.0, offset); 647 - } 648 - 649 - /// Read the array register at index `idx` from `io`, using the base address provided 650 - /// by `base` and adding the register's offset to it, then run `f` on its value to 651 - /// obtain a new value to write back. 652 - #[inline(always)] 653 - pub(crate) fn update<T, I, B, F>( 654 - io: &T, 655 - base: &B, 656 - idx: usize, 657 - f: F, 658 - ) where 659 - T: ::core::ops::Deref<Target = I>, 660 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 661 - B: crate::regs::macros::RegisterBase<$base>, 662 - F: ::core::ops::FnOnce(Self) -> Self, 663 - { 664 - let reg = f(Self::read(io, base, idx)); 665 - reg.write(io, base, idx); 666 - } 667 - 668 - /// Read the array register at index `idx` from `io`, using the base address provided 669 - /// by `base` and adding the register's offset to it. 670 - /// 671 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 672 - /// access was out-of-bounds. 673 - #[inline(always)] 674 - pub(crate) fn try_read<T, I, B>( 675 - io: &T, 676 - base: &B, 677 - idx: usize, 678 - ) -> ::kernel::error::Result<Self> where 679 - T: ::core::ops::Deref<Target = I>, 680 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 681 - B: crate::regs::macros::RegisterBase<$base>, 682 - { 683 - if idx < Self::SIZE { 684 - Ok(Self::read(io, base, idx)) 685 - } else { 686 - Err(EINVAL) 687 - } 688 - } 689 - 690 - /// Write the value contained in `self` to `io`, using the base address provided by 691 - /// `base` and adding the offset of array register `idx` to it. 692 - /// 693 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 694 - /// access was out-of-bounds. 695 - #[inline(always)] 696 - pub(crate) fn try_write<T, I, B>( 697 - self, 698 - io: &T, 699 - base: &B, 700 - idx: usize, 701 - ) -> ::kernel::error::Result where 702 - T: ::core::ops::Deref<Target = I>, 703 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 704 - B: crate::regs::macros::RegisterBase<$base>, 705 - { 706 - if idx < Self::SIZE { 707 - Ok(self.write(io, base, idx)) 708 - } else { 709 - Err(EINVAL) 710 - } 711 - } 712 - 713 - /// Read the array register at index `idx` from `io`, using the base address provided 714 - /// by `base` and adding the register's offset to it, then run `f` on its value to 715 - /// obtain a new value to write back. 716 - /// 717 - /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 718 - /// access was out-of-bounds. 719 - #[inline(always)] 720 - pub(crate) fn try_update<T, I, B, F>( 721 - io: &T, 722 - base: &B, 723 - idx: usize, 724 - f: F, 725 - ) -> ::kernel::error::Result where 726 - T: ::core::ops::Deref<Target = I>, 727 - I: ::kernel::io::IoKnownSize + ::kernel::io::IoCapable<u32>, 728 - B: crate::regs::macros::RegisterBase<$base>, 729 - F: ::core::ops::FnOnce(Self) -> Self, 730 - { 731 - if idx < Self::SIZE { 732 - Ok(Self::update(io, base, idx, f)) 733 - } else { 734 - Err(EINVAL) 735 - } 736 - } 737 - } 738 - }; 739 - }