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