xref: /linux/drivers/gpu/nova-core/regs.rs (revision 82ed3243219d160601fdb98742633bee7dc6f360)
1 // SPDX-License-Identifier: GPL-2.0
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 use kernel::prelude::*;
11 
12 use crate::{
13     falcon::{
14         DmaTrfCmdSize,
15         FalconCoreRev,
16         FalconCoreRevSubversion,
17         FalconFbifMemType,
18         FalconFbifTarget,
19         FalconMem,
20         FalconModSelAlgo,
21         FalconSecurityModel,
22         PFalcon2Base,
23         PFalconBase,
24         PeregrineCoreSelect, //
25     },
26     gpu::{
27         Architecture,
28         Chipset, //
29     },
30     num::FromSafeCast,
31 };
32 
33 // PMC
34 
35 register!(NV_PMC_BOOT_0 @ 0x00000000, "Basic revision information about the GPU" {
36     3:0     minor_revision as u8, "Minor revision of the chip";
37     7:4     major_revision as u8, "Major revision of the chip";
38     8:8     architecture_1 as u8, "MSB of the architecture";
39     23:20   implementation as u8, "Implementation version of the architecture";
40     28:24   architecture_0 as u8, "Lower bits of the architecture";
41 });
42 
43 impl NV_PMC_BOOT_0 {
44     pub(crate) fn is_older_than_fermi(self) -> bool {
45         // From https://github.com/NVIDIA/open-gpu-doc/tree/master/manuals :
46         const NV_PMC_BOOT_0_ARCHITECTURE_GF100: u8 = 0xc;
47 
48         // Older chips left arch1 zeroed out. That, combined with an arch0 value that is less than
49         // GF100, means "older than Fermi".
50         self.architecture_1() == 0 && self.architecture_0() < NV_PMC_BOOT_0_ARCHITECTURE_GF100
51     }
52 }
53 
54 register!(NV_PMC_BOOT_42 @ 0x00000a00, "Extended architecture information" {
55     15:12   minor_revision as u8, "Minor revision of the chip";
56     19:16   major_revision as u8, "Major revision of the chip";
57     23:20   implementation as u8, "Implementation version of the architecture";
58     29:24   architecture as u8 ?=> Architecture, "Architecture value";
59 });
60 
61 impl NV_PMC_BOOT_42 {
62     /// Combines `architecture` and `implementation` to obtain a code unique to the chipset.
63     pub(crate) fn chipset(self) -> Result<Chipset> {
64         self.architecture()
65             .map(|arch| {
66                 ((arch as u32) << Self::IMPLEMENTATION_RANGE.len())
67                     | u32::from(self.implementation())
68             })
69             .and_then(Chipset::try_from)
70     }
71 
72     /// Returns the raw architecture value from the register.
73     fn architecture_raw(self) -> u8 {
74         ((self.0 >> Self::ARCHITECTURE_RANGE.start()) & ((1 << Self::ARCHITECTURE_RANGE.len()) - 1))
75             as u8
76     }
77 }
78 
79 impl kernel::fmt::Display for NV_PMC_BOOT_42 {
80     fn fmt(&self, f: &mut kernel::fmt::Formatter<'_>) -> kernel::fmt::Result {
81         write!(
82             f,
83             "boot42 = 0x{:08x} (architecture 0x{:x}, implementation 0x{:x})",
84             self.0,
85             self.architecture_raw(),
86             self.implementation()
87         )
88     }
89 }
90 
91 // PBUS
92 
93 register!(NV_PBUS_SW_SCRATCH @ 0x00001400[64]  {});
94 
95 register!(NV_PBUS_SW_SCRATCH_0E_FRTS_ERR => NV_PBUS_SW_SCRATCH[0xe],
96     "scratch register 0xe used as FRTS firmware error code" {
97     31:16   frts_err_code as u16;
98 });
99 
100 // PFB
101 
102 // The following two registers together hold the physical system memory address that is used by the
103 // GPU to perform sysmembar operations (see `fb::SysmemFlush`).
104 
105 register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR @ 0x00100c10 {
106     31:0    adr_39_08 as u32;
107 });
108 
109 register!(NV_PFB_NISO_FLUSH_SYSMEM_ADDR_HI @ 0x00100c40 {
110     23:0    adr_63_40 as u32;
111 });
112 
113 register!(NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE @ 0x00100ce0 {
114     3:0     lower_scale as u8;
115     9:4     lower_mag as u8;
116     30:30   ecc_mode_enabled as bool;
117 });
118 
119 register!(NV_PGSP_QUEUE_HEAD @ 0x00110c00 {
120     31:0    address as u32;
121 });
122 
123 impl NV_PFB_PRI_MMU_LOCAL_MEMORY_RANGE {
124     /// Returns the usable framebuffer size, in bytes.
125     pub(crate) fn usable_fb_size(self) -> u64 {
126         let size = (u64::from(self.lower_mag()) << u64::from(self.lower_scale()))
127             * u64::from_safe_cast(kernel::sizes::SZ_1M);
128 
129         if self.ecc_mode_enabled() {
130             // Remove the amount of memory reserved for ECC (one per 16 units).
131             size / 16 * 15
132         } else {
133             size
134         }
135     }
136 }
137 
138 register!(NV_PFB_PRI_MMU_WPR2_ADDR_LO@0x001fa824  {
139     31:4    lo_val as u32, "Bits 12..40 of the lower (inclusive) bound of the WPR2 region";
140 });
141 
142 impl NV_PFB_PRI_MMU_WPR2_ADDR_LO {
143     /// Returns the lower (inclusive) bound of the WPR2 region.
144     pub(crate) fn lower_bound(self) -> u64 {
145         u64::from(self.lo_val()) << 12
146     }
147 }
148 
149 register!(NV_PFB_PRI_MMU_WPR2_ADDR_HI@0x001fa828  {
150     31:4    hi_val as u32, "Bits 12..40 of the higher (exclusive) bound of the WPR2 region";
151 });
152 
153 impl NV_PFB_PRI_MMU_WPR2_ADDR_HI {
154     /// Returns the higher (exclusive) bound of the WPR2 region.
155     ///
156     /// A value of zero means the WPR2 region is not set.
157     pub(crate) fn higher_bound(self) -> u64 {
158         u64::from(self.hi_val()) << 12
159     }
160 }
161 
162 // PGC6 register space.
163 //
164 // `GC6` is a GPU low-power state where VRAM is in self-refresh and the GPU is powered down (except
165 // for power rails needed to keep self-refresh working and important registers and hardware
166 // blocks).
167 //
168 // These scratch registers remain powered on even in a low-power state and have a designated group
169 // number.
170 
171 // Boot Sequence Interface (BSI) register used to determine
172 // if GSP reload/resume has completed during the boot process.
173 register!(NV_PGC6_BSI_SECURE_SCRATCH_14 @ 0x001180f8 {
174     26:26   boot_stage_3_handoff as bool;
175 });
176 
177 // Privilege level mask register. It dictates whether the host CPU has privilege to access the
178 // `PGC6_AON_SECURE_SCRATCH_GROUP_05` register (which it needs to read GFW_BOOT).
179 register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_PRIV_LEVEL_MASK @ 0x00118128,
180           "Privilege level mask register" {
181     0:0     read_protection_level0 as bool, "Set after FWSEC lowers its protection level";
182 });
183 
184 // OpenRM defines this as a register array, but doesn't specify its size and only uses its first
185 // element. Be conservative until we know the actual size or need to use more registers.
186 register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_05 @ 0x00118234[1] {});
187 
188 register!(
189     NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT => NV_PGC6_AON_SECURE_SCRATCH_GROUP_05[0],
190     "Scratch group 05 register 0 used as GFW boot progress indicator" {
191         7:0    progress as u8, "Progress of GFW boot (0xff means completed)";
192     }
193 );
194 
195 impl NV_PGC6_AON_SECURE_SCRATCH_GROUP_05_0_GFW_BOOT {
196     /// Returns `true` if GFW boot is completed.
197     pub(crate) fn completed(self) -> bool {
198         self.progress() == 0xff
199     }
200 }
201 
202 register!(NV_PGC6_AON_SECURE_SCRATCH_GROUP_42 @ 0x001183a4 {
203     31:0    value as u32;
204 });
205 
206 register!(
207     NV_USABLE_FB_SIZE_IN_MB => NV_PGC6_AON_SECURE_SCRATCH_GROUP_42,
208     "Scratch group 42 register used as framebuffer size" {
209         31:0    value as u32, "Usable framebuffer size, in megabytes";
210     }
211 );
212 
213 impl NV_USABLE_FB_SIZE_IN_MB {
214     /// Returns the usable framebuffer size, in bytes.
215     pub(crate) fn usable_fb_size(self) -> u64 {
216         u64::from(self.value()) * u64::from_safe_cast(kernel::sizes::SZ_1M)
217     }
218 }
219 
220 // PDISP
221 
222 register!(NV_PDISP_VGA_WORKSPACE_BASE @ 0x00625f04 {
223     3:3     status_valid as bool, "Set if the `addr` field is valid";
224     31:8    addr as u32, "VGA workspace base address divided by 0x10000";
225 });
226 
227 impl NV_PDISP_VGA_WORKSPACE_BASE {
228     /// Returns the base address of the VGA workspace, or `None` if none exists.
229     pub(crate) fn vga_workspace_addr(self) -> Option<u64> {
230         if self.status_valid() {
231             Some(u64::from(self.addr()) << 16)
232         } else {
233             None
234         }
235     }
236 }
237 
238 // FUSE
239 
240 pub(crate) const NV_FUSE_OPT_FPF_SIZE: usize = 16;
241 
242 register!(NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION @ 0x00824100[NV_FUSE_OPT_FPF_SIZE] {
243     15:0    data as u16;
244 });
245 
246 register!(NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION @ 0x00824140[NV_FUSE_OPT_FPF_SIZE] {
247     15:0    data as u16;
248 });
249 
250 register!(NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION @ 0x008241c0[NV_FUSE_OPT_FPF_SIZE] {
251     15:0    data as u16;
252 });
253 
254 // PFALCON
255 
256 register!(NV_PFALCON_FALCON_IRQSCLR @ PFalconBase[0x00000004] {
257     4:4     halt as bool;
258     6:6     swgen0 as bool;
259 });
260 
261 register!(NV_PFALCON_FALCON_MAILBOX0 @ PFalconBase[0x00000040] {
262     31:0    value as u32;
263 });
264 
265 register!(NV_PFALCON_FALCON_MAILBOX1 @ PFalconBase[0x00000044] {
266     31:0    value as u32;
267 });
268 
269 // Used to store version information about the firmware running
270 // on the Falcon processor.
271 register!(NV_PFALCON_FALCON_OS @ PFalconBase[0x00000080] {
272     31:0    value as u32;
273 });
274 
275 register!(NV_PFALCON_FALCON_RM @ PFalconBase[0x00000084] {
276     31:0    value as u32;
277 });
278 
279 register!(NV_PFALCON_FALCON_HWCFG2 @ PFalconBase[0x000000f4] {
280     10:10   riscv as bool;
281     12:12   mem_scrubbing as bool, "Set to 0 after memory scrubbing is completed";
282     31:31   reset_ready as bool, "Signal indicating that reset is completed (GA102+)";
283 });
284 
285 impl NV_PFALCON_FALCON_HWCFG2 {
286     /// Returns `true` if memory scrubbing is completed.
287     pub(crate) fn mem_scrubbing_done(self) -> bool {
288         !self.mem_scrubbing()
289     }
290 }
291 
292 register!(NV_PFALCON_FALCON_CPUCTL @ PFalconBase[0x00000100] {
293     1:1     startcpu as bool;
294     4:4     halted as bool;
295     6:6     alias_en as bool;
296 });
297 
298 register!(NV_PFALCON_FALCON_BOOTVEC @ PFalconBase[0x00000104] {
299     31:0    value as u32;
300 });
301 
302 register!(NV_PFALCON_FALCON_DMACTL @ PFalconBase[0x0000010c] {
303     0:0     require_ctx as bool;
304     1:1     dmem_scrubbing as bool;
305     2:2     imem_scrubbing as bool;
306     6:3     dmaq_num as u8;
307     7:7     secure_stat as bool;
308 });
309 
310 register!(NV_PFALCON_FALCON_DMATRFBASE @ PFalconBase[0x00000110] {
311     31:0    base as u32;
312 });
313 
314 register!(NV_PFALCON_FALCON_DMATRFMOFFS @ PFalconBase[0x00000114] {
315     23:0    offs as u32;
316 });
317 
318 register!(NV_PFALCON_FALCON_DMATRFCMD @ PFalconBase[0x00000118] {
319     0:0     full as bool;
320     1:1     idle as bool;
321     3:2     sec as u8;
322     4:4     imem as bool;
323     5:5     is_write as bool;
324     10:8    size as u8 ?=> DmaTrfCmdSize;
325     14:12   ctxdma as u8;
326     16:16   set_dmtag as u8;
327 });
328 
329 impl NV_PFALCON_FALCON_DMATRFCMD {
330     /// Programs the `imem` and `sec` fields for the given FalconMem
331     pub(crate) fn with_falcon_mem(self, mem: FalconMem) -> Self {
332         self.set_imem(mem != FalconMem::Dmem)
333             .set_sec(if mem == FalconMem::ImemSecure { 1 } else { 0 })
334     }
335 }
336 
337 register!(NV_PFALCON_FALCON_DMATRFFBOFFS @ PFalconBase[0x0000011c] {
338     31:0    offs as u32;
339 });
340 
341 register!(NV_PFALCON_FALCON_DMATRFBASE1 @ PFalconBase[0x00000128] {
342     8:0     base as u16;
343 });
344 
345 register!(NV_PFALCON_FALCON_HWCFG1 @ PFalconBase[0x0000012c] {
346     3:0     core_rev as u8 ?=> FalconCoreRev, "Core revision";
347     5:4     security_model as u8 ?=> FalconSecurityModel, "Security model";
348     7:6     core_rev_subversion as u8 ?=> FalconCoreRevSubversion, "Core revision subversion";
349 });
350 
351 register!(NV_PFALCON_FALCON_CPUCTL_ALIAS @ PFalconBase[0x00000130] {
352     1:1     startcpu as bool;
353 });
354 
355 // Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the falcon
356 // instance.
357 register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] {
358     0:0     reset as bool;
359 });
360 
361 register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] {
362     1:0     target as u8 ?=> FalconFbifTarget;
363     2:2     mem_type as bool => FalconFbifMemType;
364 });
365 
366 register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] {
367     7:7     allow_phys_no_ctx as bool;
368 });
369 
370 /* PFALCON2 */
371 
372 register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] {
373     7:0     algo as u8 ?=> FalconModSelAlgo;
374 });
375 
376 register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198] {
377     7:0    ucode_id as u8;
378 });
379 
380 register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] {
381     31:0    value as u32;
382 });
383 
384 // OpenRM defines this as a register array, but doesn't specify its size and only uses its first
385 // element. Be conservative until we know the actual size or need to use more registers.
386 register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] {
387     31:0    value as u32;
388 });
389 
390 // PRISCV
391 
392 register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] {
393     0:0     halted as bool;
394     7:7     active_stat as bool;
395 });
396 
397 register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalcon2Base[0x00000668] {
398     0:0     valid as bool;
399     4:4     core_select as bool => PeregrineCoreSelect;
400     8:8     br_fetch as bool;
401 });
402 
403 // The modules below provide registers that are not identical on all supported chips. They should
404 // only be used in HAL modules.
405 
406 pub(crate) mod gm107 {
407     // FUSE
408 
409     register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 {
410         0:0     display_disabled as bool;
411     });
412 }
413 
414 pub(crate) mod ga100 {
415     // FUSE
416 
417     register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 {
418         0:0     display_disabled as bool;
419     });
420 }
421