FWSEC-FRTS is run with the desired address of the FRTS region as parameter, which we need to compute depending on some hardware parameters.
Do this in a `FbLayout` structure, that will be later extended to describe more memory regions used to boot the GSP. Signed-off-by: Alexandre Courbot <acour...@nvidia.com> --- drivers/gpu/nova-core/gpu.rs | 4 ++ drivers/gpu/nova-core/gsp.rs | 3 + drivers/gpu/nova-core/gsp/fb.rs | 109 +++++++++++++++++++++++++++++++++++++ drivers/gpu/nova-core/nova_core.rs | 1 + drivers/gpu/nova-core/regs.rs | 27 +++++++++ 5 files changed, 144 insertions(+) diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs index 2344dfc69fe4246644437d70572680a4450b5bd7..b43d1fc6bba15ffd76d564eccdb9e2afe239a3a4 100644 --- a/drivers/gpu/nova-core/gpu.rs +++ b/drivers/gpu/nova-core/gpu.rs @@ -8,6 +8,7 @@ use crate::falcon::gsp::GspFalcon; use crate::falcon::sec2::Sec2Falcon; use crate::firmware::Firmware; +use crate::gsp::fb::FbLayout; use crate::regs; use crate::timer::Timer; use crate::util; @@ -241,6 +242,9 @@ pub(crate) fn new( let bios = Vbios::probe(&bar)?; + let fb_layout = FbLayout::new(spec.chipset, &bar)?; + dev_dbg!(pdev.as_ref(), "{:#x?}\n", fb_layout); + Ok(pin_init!(Self { spec, bar, diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs new file mode 100644 index 0000000000000000000000000000000000000000..27616a9d2b7069b18661fc97811fa1cac285b8f8 --- /dev/null +++ b/drivers/gpu/nova-core/gsp.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-2.0 + +pub(crate) mod fb; diff --git a/drivers/gpu/nova-core/gsp/fb.rs b/drivers/gpu/nova-core/gsp/fb.rs new file mode 100644 index 0000000000000000000000000000000000000000..63f41dfa184c434aa4eb7d4cb1f5f1e6f0552563 --- /dev/null +++ b/drivers/gpu/nova-core/gsp/fb.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 + +use core::ops::Range; + +use kernel::devres::Devres; +use kernel::prelude::*; + +use crate::driver::Bar0; +use crate::gpu::Chipset; +use crate::regs; + +fn align_down(value: u64, align: u64) -> u64 { + value & !(align - 1) +} + +/// Layout of the GPU framebuffer memory. +/// +/// Contains ranges of GPU memory reserved for a given purpose during the GSP bootup process. +#[derive(Debug)] +#[allow(dead_code)] +pub(crate) struct FbLayout { + pub fb: Range<u64>, + + pub vga_workspace: Range<u64>, + pub bios: Range<u64>, + + pub frts: Range<u64>, +} + +impl FbLayout { + pub(crate) fn new(chipset: Chipset, bar: &Devres<Bar0>) -> Result<Self> { + let fb = { + let fb_size = with_bar!(bar, |b| vidmem_size(b, chipset))?; + + 0..fb_size + }; + let fb_len = fb.end - fb.start; + + let vga_workspace = { + let vga_base = with_bar!(bar, |b| vga_workspace_addr(&b, fb_len, chipset,))?; + + vga_base..fb.end + }; + + let bios = vga_workspace.clone(); + + let frts = { + const FRTS_DOWN_ALIGN: u64 = 0x20000; + const FRTS_SIZE: u64 = 0x100000; + let frts_base = align_down(vga_workspace.start, FRTS_DOWN_ALIGN) - FRTS_SIZE; + + frts_base..frts_base + FRTS_SIZE + }; + + Ok(Self { + fb, + vga_workspace, + bios, + frts, + }) + } +} + +/// Returns `true` if the display is disabled. +fn display_disabled(bar: &Bar0, chipset: Chipset) -> bool { + if chipset >= Chipset::GA100 { + regs::FuseStatusOptDisplayAmpere::read(bar).display_disabled() + } else { + regs::FuseStatusOptDisplayMaxwell::read(bar).display_disabled() + } +} + +/// Returns the video memory size in bytes. +fn vidmem_size(bar: &Bar0, chipset: Chipset) -> u64 { + if chipset >= Chipset::GA102 { + (regs::Pgc6AonSecureScratchGroup42::read(bar).value() as u64) << 20 + } else { + let local_mem_range = regs::PfbPriMmuLocalMemoryRange::read(bar); + let size = + (local_mem_range.lower_mag() as u64) << ((local_mem_range.lower_scale() as u64) + 20); + + if local_mem_range.ecc_mode_enabled() { + size / 16 * 15 + } else { + size + } + } +} + +/// Returns the vga workspace address. +fn vga_workspace_addr(bar: &Bar0, fb_size: u64, chipset: Chipset) -> u64 { + let base = fb_size - 0x100000; + let vga_workspace_base = if display_disabled(bar, chipset) { + regs::PdispVgaWorkspaceBase::read(bar) + } else { + return base; + }; + + if !vga_workspace_base.status_valid() { + return base; + } + + let addr = (vga_workspace_base.addr() as u64) << 16; + if addr < base { + fb_size - 0x20000 + } else { + addr + } +} diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index 2858f4a0dc35eb9d6547d5cbd81de44c8fc47bae..b78a71dea6e10707dc594fdc070b71dbb663e505 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -26,6 +26,7 @@ macro_rules! with_bar { mod falcon; mod firmware; mod gpu; +mod gsp; mod regs; mod timer; mod util; diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs index c76a16dc8e7267a4eb54cb71e1cca6fb9e00188f..3954542fdd77debd8f96d111ddd231d72dbf5b5a 100644 --- a/drivers/gpu/nova-core/regs.rs +++ b/drivers/gpu/nova-core/regs.rs @@ -38,6 +38,12 @@ 23:0 adr_63_40 => as u32 ); +register!(PfbPriMmuLocalMemoryRange@0x00100ce0; + 3:0 lower_scale => as u8; + 9:4 lower_mag => as u8; + 30:30 ecc_mode_enabled => as_bit bool; +); + /* GC6 */ register!(Pgc6AonSecureScratchGroup05PrivLevelMask@0x00118128; @@ -49,6 +55,27 @@ 31:0 value => as u32 ); +register!(Pgc6AonSecureScratchGroup42@0x001183a4; + 31:0 value => as u32 +); + +/* PDISP */ + +register!(PdispVgaWorkspaceBase@0x00625f04; + 3:3 status_valid => as_bit bool; + 31:8 addr => as u32; +); + +/* FUSE */ + +register!(FuseStatusOptDisplayMaxwell@0x00021c04; + 0:0 display_disabled => as_bit bool; +); + +register!(FuseStatusOptDisplayAmpere@0x00820c04; + 0:0 display_disabled => as_bit bool; +); + /* PFALCON */ register!(FalconIrqsclr@+0x00000004; -- 2.49.0