xref: /linux/drivers/gpu/nova-core/regs.rs (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
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 // Actually known as `NV_PSEC_FALCON_ENGINE` and `NV_PGSP_FALCON_ENGINE` depending on the falcon
368 // instance.
369 register!(NV_PFALCON_FALCON_ENGINE @ PFalconBase[0x000003c0] {
370     0:0     reset as bool;
371 });
372 
373 impl NV_PFALCON_FALCON_ENGINE {
374     /// Resets the falcon
375     pub(crate) fn reset_engine<E: FalconEngine>(bar: &Bar0) {
376         Self::read(bar, &E::ID).set_reset(true).write(bar, &E::ID);
377 
378         // TIMEOUT: falcon engine should not take more than 10us to reset.
379         time::delay::fsleep(time::Delta::from_micros(10));
380 
381         Self::read(bar, &E::ID).set_reset(false).write(bar, &E::ID);
382     }
383 }
384 
385 register!(NV_PFALCON_FBIF_TRANSCFG @ PFalconBase[0x00000600[8]] {
386     1:0     target as u8 ?=> FalconFbifTarget;
387     2:2     mem_type as bool => FalconFbifMemType;
388 });
389 
390 register!(NV_PFALCON_FBIF_CTL @ PFalconBase[0x00000624] {
391     7:7     allow_phys_no_ctx as bool;
392 });
393 
394 /* PFALCON2 */
395 
396 register!(NV_PFALCON2_FALCON_MOD_SEL @ PFalcon2Base[0x00000180] {
397     7:0     algo as u8 ?=> FalconModSelAlgo;
398 });
399 
400 register!(NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID @ PFalcon2Base[0x00000198] {
401     7:0    ucode_id as u8;
402 });
403 
404 register!(NV_PFALCON2_FALCON_BROM_ENGIDMASK @ PFalcon2Base[0x0000019c] {
405     31:0    value as u32;
406 });
407 
408 // OpenRM defines this as a register array, but doesn't specify its size and only uses its first
409 // element. Be conservative until we know the actual size or need to use more registers.
410 register!(NV_PFALCON2_FALCON_BROM_PARAADDR @ PFalcon2Base[0x00000210[1]] {
411     31:0    value as u32;
412 });
413 
414 // PRISCV
415 
416 // RISC-V status register for debug (Turing and GA100 only).
417 // Reflects current RISC-V core status.
418 register!(NV_PRISCV_RISCV_CORE_SWITCH_RISCV_STATUS @ PFalcon2Base[0x00000240] {
419     0:0     active_stat as bool, "RISC-V core active/inactive status";
420 });
421 
422 // GA102 and later
423 register!(NV_PRISCV_RISCV_CPUCTL @ PFalcon2Base[0x00000388] {
424     0:0     halted as bool;
425     7:7     active_stat as bool;
426 });
427 
428 register!(NV_PRISCV_RISCV_BCR_CTRL @ PFalcon2Base[0x00000668] {
429     0:0     valid as bool;
430     4:4     core_select as bool => PeregrineCoreSelect;
431     8:8     br_fetch as bool;
432 });
433 
434 // The modules below provide registers that are not identical on all supported chips. They should
435 // only be used in HAL modules.
436 
437 pub(crate) mod gm107 {
438     // FUSE
439 
440     register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00021c04 {
441         0:0     display_disabled as bool;
442     });
443 }
444 
445 pub(crate) mod ga100 {
446     // FUSE
447 
448     register!(NV_FUSE_STATUS_OPT_DISPLAY @ 0x00820c04 {
449         0:0     display_disabled as bool;
450     });
451 }
452