use kernel::device;
use kernel::pci;
use kernel::prelude::*;
use crate::driver::Bar0;
use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon};
use crate::fb::FbLayout;
use crate::firmware::{
booter::{BooterFirmware, BooterKind},
fwsec::{FwsecCommand, FwsecFirmware},
gsp::GspFirmware,
FIRMWARE_VERSION,
};
use crate::gpu::Chipset;
use crate::regs;
use crate::vbios::Vbios;
impl super::Gsp {
fn run_fwsec_frts(
dev: &device::Device<device::Bound>,
falcon: &Falcon<Gsp>,
bar: &Bar0,
bios: &Vbios,
fb_layout: &FbLayout,
) -> Result<()> {
if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 {
dev_err!(
dev,
"WPR2 region already exists - GPU needs to be reset to proceed\n"
);
return Err(EBUSY);
}
let fwsec_frts = FwsecFirmware::new(
dev,
falcon,
bar,
bios,
FwsecCommand::Frts {
frts_addr: fb_layout.frts.start,
frts_size: fb_layout.frts.end - fb_layout.frts.start,
},
)?;
fwsec_frts.run(dev, falcon, bar)?;
let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code();
if frts_status != 0 {
dev_err!(
dev,
"FWSEC-FRTS returned with error code {:#x}",
frts_status
);
return Err(EIO);
}
let (wpr2_lo, wpr2_hi) = (
regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(),
regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(),
);
match (wpr2_lo, wpr2_hi) {
(_, 0) => {
dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n");
Err(EIO)
}
(wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => {
dev_err!(
dev,
"WPR2 region created at unexpected address {:#x}; expected {:#x}\n",
wpr2_lo,
fb_layout.frts.start,
);
Err(EIO)
}
(wpr2_lo, wpr2_hi) => {
dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi);
dev_dbg!(dev, "GPU instance built\n");
Ok(())
}
}
}
pub(crate) fn boot(
self: Pin<&mut Self>,
pdev: &pci::Device<device::Bound>,
bar: &Bar0,
chipset: Chipset,
gsp_falcon: &Falcon<Gsp>,
sec2_falcon: &Falcon<Sec2>,
) -> Result {
let dev = pdev.as_ref();
let bios = Vbios::new(dev, bar)?;
let _gsp_fw = KBox::pin_init(
GspFirmware::new(dev, chipset, FIRMWARE_VERSION)?,
GFP_KERNEL,
)?;
let fb_layout = FbLayout::new(chipset, bar)?;
dev_dbg!(dev, "{:#x?}\n", fb_layout);
Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?;
let _booter_loader = BooterFirmware::new(
dev,
BooterKind::Loader,
chipset,
FIRMWARE_VERSION,
sec2_falcon,
bar,
)?;
Ok(())
}
}