gpu: nova-core: Hopper/Blackwell: add FSP falcon EMEM operations

Add external memory (EMEM) read/write operations to the GPU's FSP falcon
engine. These operations use Falcon PIO (Programmed I/O) to communicate
with the FSP through indirect memory access.

Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Reviewed-by: Eliot Courtney <ecourtney@nvidia.com>
Link: https://patch.msgid.link/20260603-b4-blackwell-v13-1-d9f3a06939e0@nvidia.com
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
This commit is contained in:
John Hubbard 2026-06-03 16:30:18 +09:00 committed by Alexandre Courbot
parent 0023a1e8d0
commit 6d6c3189f9
2 changed files with 93 additions and 5 deletions

View File

@ -6,12 +6,26 @@
//! The FSP falcon handles secure boot and Chain of Trust operations
//! on Hopper and Blackwell architectures, replacing SEC2's role.
use kernel::io::register::RegisterBase;
use kernel::{
io::{
register::{
RegisterBase,
WithBase, //
},
Io, //
},
prelude::*,
};
use crate::falcon::{
FalconEngine,
PFalcon2Base,
PFalconBase, //
use crate::{
driver::Bar0,
falcon::{
Falcon,
FalconEngine,
PFalcon2Base,
PFalconBase, //
},
regs,
};
/// Type specifying the `Fsp` falcon engine. Cannot be instantiated.
@ -26,3 +40,59 @@ impl RegisterBase<PFalcon2Base> for Fsp {
}
impl FalconEngine for Fsp {}
impl Falcon<Fsp> {
/// Writes `data` to FSP external memory at offset `0`.
///
/// `data` is interpreted as little-endian 32-bit words. Returns `EINVAL`
/// if the `data` length is not 4-byte aligned.
#[expect(dead_code)]
fn write_emem(&mut self, bar: &Bar0, data: &[u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a write burst at offset `0`, auto-incrementing on each write.
bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincw(true),
);
for chunk in data.chunks_exact(4) {
let value = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
// Write the next 32-bit `value`; hardware advances the offset.
bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMD::zeroed().with_data(value),
);
}
Ok(())
}
/// Reads FSP external memory from offset `0` into `data`.
///
/// `data` is stored as little-endian 32-bit words. Returns `EINVAL` if
/// the `data` length is not 4-byte aligned.
#[expect(dead_code)]
fn read_emem(&mut self, bar: &Bar0, data: &mut [u8]) -> Result {
if data.len() % 4 != 0 {
return Err(EINVAL);
}
// Begin a read burst at offset `0`, auto-incrementing on each read.
bar.write(
WithBase::of::<Fsp>(),
regs::NV_PFALCON_FALCON_EMEMC::zeroed().with_aincr(true),
);
for chunk in data.chunks_exact_mut(4) {
// Read the next 32-bit word; hardware advances the offset.
let value = bar.read(regs::NV_PFALCON_FALCON_EMEMD::of::<Fsp>()).data();
chunk.copy_from_slice(&value.to_le_bytes());
}
Ok(())
}
}

View File

@ -475,6 +475,24 @@ pub(crate) fn vga_workspace_addr(self) -> Option<u64> {
pub(crate) NV_PFALCON_FBIF_CTL(u32) @ PFalconBase + 0x00000624 {
7:7 allow_phys_no_ctx => bool;
}
// Falcon EMEM PIO registers (used by FSP on Hopper/Blackwell).
// These provide the falcon external memory communication interface.
pub(crate) NV_PFALCON_FALCON_EMEMC(u32) @ PFalconBase + 0x00000ac0 {
/// EMEM byte offset (4-byte aligned) within the block.
7:2 offs;
/// EMEM block to access.
15:8 blk;
/// Auto-increment the offset after each write.
24:24 aincw => bool;
/// Auto-increment the offset after each read.
25:25 aincr => bool;
}
pub(crate) NV_PFALCON_FALCON_EMEMD(u32) @ PFalconBase + 0x00000ac4 {
31:0 data => u32;
}
}
impl NV_PFALCON_FALCON_DMACTL {