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