[PATCH v10 16/28] gpu: nova-core: Hopper/Blackwell: add FMC firmware image, in support of FSP

John Hubbard
2026-04-11T02:50:25Z

FSP is the Falcon that runs FMC firmware on Hopper and Blackwell.
Load the FMC ELF in two forms: the image section that FSP boots from,
and the full Firmware object for later signature extraction during
Chain of Trust verification.

Co-developed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
drivers/gpu/nova-core/firmware.rs | 1 +
drivers/gpu/nova-core/firmware/fsp.rs | 45 +++++++++++++++++++++++++++
drivers/gpu/nova-core/gsp/boot.rs | 3 ++
3 files changed, 49 insertions(+)
create mode 100644 drivers/gpu/nova-core/firmware/fsp.rs

diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index bc217bfc225f..bc26807116e4 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -27,6 +27,7 @@
};

pub(crate) mod booter;
+pub(crate) mod fsp;
pub(crate) mod fwsec;
pub(crate) mod gsp;
pub(crate) mod riscv;
diff --git a/drivers/gpu/nova-core/firmware/fsp.rs b/drivers/gpu/nova-core/firmware/fsp.rs
new file mode 100644
index 000000000000..3968bacb7e61
--- /dev/null
+++ b/drivers/gpu/nova-core/firmware/fsp.rs
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! FSP is a hardware unit that runs FMC firmware.
+
+use kernel::{
+ device,
+ dma::Coherent,
+ firmware::Firmware,
+ prelude::*, //
+};
+
+use crate::{
+ firmware::elf,
+ gpu::Chipset, //
+};
+
+#[expect(dead_code)]
+pub(crate) struct FspFirmware {
+ /// FMC firmware image data (only the "image" ELF section).
+ pub(crate) fmc_image: Coherent<[u8]>,
+ /// Full FMC ELF for signature extraction.
+ pub(crate) fmc_elf: Firmware,
+}
+
+impl FspFirmware {
+ pub(crate) fn new(
+ dev: &device::Device<device::Bound>,
+ chipset: Chipset,
+ ver: &str,
+ ) -> Result<Self> {
+ let fw = super::request_firmware(dev, chipset, "fmc", ver)?;
+
+ // FSP expects only the "image" section, not the entire ELF file.
+ let fmc_image_data = elf::elf_section(fw.data(), "image").ok_or_else(|| {
+ dev_err!(dev, "FMC ELF file missing 'image' section\n");
+ EINVAL
+ })?;
+ let fmc_image = Coherent::from_slice(dev, fmc_image_data, GFP_KERNEL)?;
+
+ Ok(Self {
+ fmc_image,
+ fmc_elf: fw,
+ })
+ }
+}
diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
index 84943beee9ca..1998bd230185 100644
--- a/drivers/gpu/nova-core/gsp/boot.rs
+++ b/drivers/gpu/nova-core/gsp/boot.rs
@@ -24,6 +24,7 @@
BooterFirmware,
BooterKind, //
},
+ fsp::FspFirmware,
fwsec::{
bootloader::FwsecFirmwareWithBl,
FwsecCommand,
@@ -206,6 +207,8 @@ fn boot_via_fsp(
) -> Result {
let _fsp_falcon = Falcon::<FspEngine>::new(dev, chipset)?;

+ let _fsp_fw = FspFirmware::new(dev, chipset, FIRMWARE_VERSION)?;
+
Err(ENOTSUPP)
}

--
2.53.0