1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{ 4 io::register, 5 prelude::*, 6 sizes::{ 7 SizeConstants, 8 SZ_4K, // 9 }, // 10 }; 11 12 use crate::driver::NovaRegisters; 13 14 // PDISP 15 16 register! { 17 base: NovaRegisters; 18 19 pub(super) NV_PDISP_VGA_WORKSPACE_BASE(u32) @ 0x00625f04 { 20 /// VGA workspace base address divided by 0x10000. 21 31:8 addr; 22 /// Set if the `addr` field is valid. 23 3:3 status_valid => bool; 24 } 25 } 26 27 impl NV_PDISP_VGA_WORKSPACE_BASE { 28 /// Returns the base address of the VGA workspace, or `None` if none exists. 29 pub(super) fn vga_workspace_addr(self) -> Option<u64> { 30 if self.status_valid() { 31 Some(u64::from(self.addr()) << 16) 32 } else { 33 None 34 } 35 } 36 } 37 38 // PFB 39 40 register! { 41 base: NovaRegisters; 42 43 /// Low bits of the physical system memory address used by the GPU to perform sysmembar 44 /// operations (see [`crate::fb::SysmemFlush`]). 45 pub(super) NV_PFB_NISO_FLUSH_SYSMEM_ADDR(u32) @ 0x00100c10 { 46 31:0 adr_39_08; 47 } 48 49 /// High bits of the physical system memory address used by the GPU to perform sysmembar 50 /// operations. 51 pub(super) NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x00100c40 { 52 23:0 adr_63_40; 53 } 54 55 pub(super) NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE(u32) @ 0x00100ce0 { 56 30:30 ecc_mode_enabled => bool; 57 9:4 lower_mag; 58 3:0 lower_scale; 59 } 60 61 pub(super) NV_PFB_PRI_MMU_WPR2_ADDR_LO(u32) @ 0x001fa824 { 62 /// Bits 12..40 of the lower (inclusive) bound of the WPR2 region. 63 31:4 lo_val; 64 } 65 66 pub(super) NV_PFB_PRI_MMU_WPR2_ADDR_HI(u32) @ 0x001fa828 { 67 /// Bits 12..40 of the higher (exclusive) bound of the WPR2 region. 68 31:4 hi_val; 69 } 70 } 71 72 const HSHUB0_REGION_SIZE: usize = SZ_4K; 73 74 /// The GB10x HSHUB0 register window (Base defined as `NV_HSHUB0_PRIV_BASE` in Open RM). 75 /// 76 /// The base is provided by the GB10x framebuffer HAL. 77 #[repr(align(4))] 78 #[derive(FromBytes, IntoBytes)] 79 pub(super) struct Hshub0Registers([u8; HSHUB0_REGION_SIZE]); 80 81 register! { 82 base: Hshub0Registers; 83 84 // GB10x sysmem flush registers, relative to the HSHUB0 base. GB10x routes sysmembar 85 // through a primary and an EG (egress) pair that must both be programmed to the same 86 // address. Hardware ignores bits 7:0 of each LO register. The boot path uses a fixed 87 // HSHUB0 base, so the multiple runtime-discovered HSHUB bases are not needed here. 88 pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x00000e50 { 89 31:0 adr => u32; 90 } 91 92 pub(super) NV_PFB_HSHUB_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x00000e54 { 93 19:0 adr; 94 } 95 96 pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x000006c0 { 97 31:0 adr => u32; 98 } 99 100 pub(super) NV_PFB_HSHUB_EG_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x000006c4 { 101 19:0 adr; 102 } 103 } 104 105 register! { 106 base: NovaRegisters; 107 108 // GB20x FBHUB0 sysmem flush registers. Unlike the older 109 // NV_PFB_NISO_FLUSH_SYSMEM_ADDR registers, which encode the address with an 110 // 8-bit right-shift, these take the raw address split into lower and upper 111 // halves. Hardware ignores bits 7:0 of the LO register. 112 pub(super) NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x008a1d58 { 113 31:0 adr => u32; 114 } 115 116 pub(super) NV_PFB_FBHUB0_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x008a1d5c { 117 19:0 adr; 118 } 119 } 120 121 register! { 122 base: NovaRegisters; 123 124 /// Low bits of the physical system memory address used by the GPU to perform 125 /// sysmembar operations on Hopper. 126 /// 127 /// Like the GB20x FBHUB0 registers, and unlike the Ampere 128 /// `NV_PFB_NISO_FLUSH_SYSMEM_ADDR` registers (which encode the address with an 129 /// 8-bit right-shift), these take the raw address split into lower and upper 130 /// halves. Hardware ignores bits 7:0 of the LO register. 131 pub(super) NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_LO(u32) @ 0x00100a34 { 132 31:0 adr => u32; 133 } 134 135 /// High bits of the physical system memory address used by the GPU to perform 136 /// sysmembar operations on Hopper. 137 pub(super) NV_PFB_FBHUB_PCIE_FLUSH_SYSMEM_ADDR_HI(u32) @ 0x00100a38 { 138 19:0 adr; 139 } 140 } 141 142 impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE { 143 /// Returns the usable framebuffer size, in bytes. 144 pub(super) fn usable_fb_size(self) -> u64 { 145 let size = (u64::from(self.lower_mag()) << u64::from(self.lower_scale())) * u64::SZ_1M; 146 147 if self.ecc_mode_enabled() { 148 // Remove the amount of memory reserved for ECC (one per 16 units). 149 size / 16 * 15 150 } else { 151 size 152 } 153 } 154 } 155 156 impl NV_PFB_PRI_MMU_WPR2_ADDR_LO { 157 /// Returns the lower (inclusive) bound of the WPR2 region. 158 pub(super) fn lower_bound(self) -> u64 { 159 u64::from(self.lo_val()) << 12 160 } 161 } 162 163 impl NV_PFB_PRI_MMU_WPR2_ADDR_HI { 164 /// Returns the higher (exclusive) bound of the WPR2 region. 165 /// 166 /// A value of zero means the WPR2 region is not set. 167 pub(super) fn higher_bound(self) -> u64 { 168 u64::from(self.hi_val()) << 12 169 } 170 171 /// Returns whether the WPR2 region is currently set. 172 pub(super) fn is_wpr2_set(self) -> bool { 173 self.hi_val() != 0 174 } 175 } 176