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