xref: /linux/drivers/gpu/nova-core/firmware.rs (revision 80213934d00fe09d9dcef3d6f17250be131435aa)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Contains structures and functions dedicated to the parsing, building and patching of firmwares
4 //! to be loaded into a given execution unit.
5 
6 use kernel::device;
7 use kernel::firmware;
8 use kernel::prelude::*;
9 use kernel::str::CString;
10 
11 use crate::gpu;
12 use crate::gpu::Chipset;
13 
14 pub(crate) const FIRMWARE_VERSION: &str = "535.113.01";
15 
16 /// Structure encapsulating the firmware blobs required for the GPU to operate.
17 #[expect(dead_code)]
18 pub(crate) struct Firmware {
19     booter_load: firmware::Firmware,
20     booter_unload: firmware::Firmware,
21     bootloader: firmware::Firmware,
22     gsp: firmware::Firmware,
23 }
24 
25 impl Firmware {
26     pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> {
27         let mut chip_name = CString::try_from_fmt(fmt!("{}", chipset))?;
28         chip_name.make_ascii_lowercase();
29 
30         let request = |name_| {
31             CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver))
32                 .and_then(|path| firmware::Firmware::request(&path, dev))
33         };
34 
35         Ok(Firmware {
36             booter_load: request("booter_load")?,
37             booter_unload: request("booter_unload")?,
38             bootloader: request("bootloader")?,
39             gsp: request("gsp")?,
40         })
41     }
42 }
43 
44 /// Structure used to describe some firmwares, notably FWSEC-FRTS.
45 #[repr(C)]
46 #[derive(Debug, Clone)]
47 pub(crate) struct FalconUCodeDescV3 {
48     /// Header defined by `NV_BIT_FALCON_UCODE_DESC_HEADER_VDESC*` in OpenRM.
49     hdr: u32,
50     /// Stored size of the ucode after the header.
51     stored_size: u32,
52     /// Offset in `DMEM` at which the signature is expected to be found.
53     pub(crate) pkc_data_offset: u32,
54     /// Offset after the code segment at which the app headers are located.
55     pub(crate) interface_offset: u32,
56     /// Base address at which to load the code segment into `IMEM`.
57     pub(crate) imem_phys_base: u32,
58     /// Size in bytes of the code to copy into `IMEM`.
59     pub(crate) imem_load_size: u32,
60     /// Virtual `IMEM` address (i.e. `tag`) at which the code should start.
61     pub(crate) imem_virt_base: u32,
62     /// Base address at which to load the data segment into `DMEM`.
63     pub(crate) dmem_phys_base: u32,
64     /// Size in bytes of the data to copy into `DMEM`.
65     pub(crate) dmem_load_size: u32,
66     /// Mask of the falcon engines on which this firmware can run.
67     pub(crate) engine_id_mask: u16,
68     /// ID of the ucode used to infer a fuse register to validate the signature.
69     pub(crate) ucode_id: u8,
70     /// Number of signatures in this firmware.
71     pub(crate) signature_count: u8,
72     /// Versions of the signatures, used to infer a valid signature to use.
73     pub(crate) signature_versions: u16,
74     _reserved: u16,
75 }
76 
77 impl FalconUCodeDescV3 {
78     /// Returns the size in bytes of the header.
79     pub(crate) fn size(&self) -> usize {
80         const HDR_SIZE_SHIFT: u32 = 16;
81         const HDR_SIZE_MASK: u32 = 0xffff0000;
82 
83         ((self.hdr & HDR_SIZE_MASK) >> HDR_SIZE_SHIFT) as usize
84     }
85 }
86 
87 pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>);
88 
89 impl<const N: usize> ModInfoBuilder<N> {
90     const fn make_entry_file(self, chipset: &str, fw: &str) -> Self {
91         ModInfoBuilder(
92             self.0
93                 .new_entry()
94                 .push("nvidia/")
95                 .push(chipset)
96                 .push("/gsp/")
97                 .push(fw)
98                 .push("-")
99                 .push(FIRMWARE_VERSION)
100                 .push(".bin"),
101         )
102     }
103 
104     const fn make_entry_chipset(self, chipset: &str) -> Self {
105         self.make_entry_file(chipset, "booter_load")
106             .make_entry_file(chipset, "booter_unload")
107             .make_entry_file(chipset, "bootloader")
108             .make_entry_file(chipset, "gsp")
109     }
110 
111     pub(crate) const fn create(
112         module_name: &'static kernel::str::CStr,
113     ) -> firmware::ModInfoBuilder<N> {
114         let mut this = Self(firmware::ModInfoBuilder::new(module_name));
115         let mut i = 0;
116 
117         while i < gpu::Chipset::NAMES.len() {
118             this = this.make_entry_chipset(gpu::Chipset::NAMES[i]);
119             i += 1;
120         }
121 
122         this.0
123     }
124 }
125