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