projects/linux·blob master · refs

520 lines · 15.6 KiB

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