1e7c96980SAlexandre Courbot // SPDX-License-Identifier: GPL-2.0 2e7c96980SAlexandre Courbot 3e7c96980SAlexandre Courbot use kernel::device; 4e7c96980SAlexandre Courbot use kernel::pci; 5e7c96980SAlexandre Courbot use kernel::prelude::*; 6e7c96980SAlexandre Courbot 7e7c96980SAlexandre Courbot use crate::driver::Bar0; 8e7c96980SAlexandre Courbot use crate::falcon::{gsp::Gsp, sec2::Sec2, Falcon}; 9e7c96980SAlexandre Courbot use crate::fb::FbLayout; 103e5c9681SAlexandre Courbot use crate::firmware::{ 113e5c9681SAlexandre Courbot booter::{BooterFirmware, BooterKind}, 123e5c9681SAlexandre Courbot fwsec::{FwsecCommand, FwsecFirmware}, 13*a841614eSAlexandre Courbot gsp::GspFirmware, 143e5c9681SAlexandre Courbot FIRMWARE_VERSION, 153e5c9681SAlexandre Courbot }; 16e7c96980SAlexandre Courbot use crate::gpu::Chipset; 17e7c96980SAlexandre Courbot use crate::regs; 18e7c96980SAlexandre Courbot use crate::vbios::Vbios; 19e7c96980SAlexandre Courbot 20e7c96980SAlexandre Courbot impl super::Gsp { 21e7c96980SAlexandre Courbot /// Helper function to load and run the FWSEC-FRTS firmware and confirm that it has properly 22e7c96980SAlexandre Courbot /// created the WPR2 region. 23e7c96980SAlexandre Courbot fn run_fwsec_frts( 24e7c96980SAlexandre Courbot dev: &device::Device<device::Bound>, 25e7c96980SAlexandre Courbot falcon: &Falcon<Gsp>, 26e7c96980SAlexandre Courbot bar: &Bar0, 27e7c96980SAlexandre Courbot bios: &Vbios, 28e7c96980SAlexandre Courbot fb_layout: &FbLayout, 29e7c96980SAlexandre Courbot ) -> Result<()> { 30e7c96980SAlexandre Courbot // Check that the WPR2 region does not already exists - if it does, we cannot run 31e7c96980SAlexandre Courbot // FWSEC-FRTS until the GPU is reset. 32e7c96980SAlexandre Courbot if regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound() != 0 { 33e7c96980SAlexandre Courbot dev_err!( 34e7c96980SAlexandre Courbot dev, 35e7c96980SAlexandre Courbot "WPR2 region already exists - GPU needs to be reset to proceed\n" 36e7c96980SAlexandre Courbot ); 37e7c96980SAlexandre Courbot return Err(EBUSY); 38e7c96980SAlexandre Courbot } 39e7c96980SAlexandre Courbot 40e7c96980SAlexandre Courbot let fwsec_frts = FwsecFirmware::new( 41e7c96980SAlexandre Courbot dev, 42e7c96980SAlexandre Courbot falcon, 43e7c96980SAlexandre Courbot bar, 44e7c96980SAlexandre Courbot bios, 45e7c96980SAlexandre Courbot FwsecCommand::Frts { 46e7c96980SAlexandre Courbot frts_addr: fb_layout.frts.start, 47e7c96980SAlexandre Courbot frts_size: fb_layout.frts.end - fb_layout.frts.start, 48e7c96980SAlexandre Courbot }, 49e7c96980SAlexandre Courbot )?; 50e7c96980SAlexandre Courbot 51e7c96980SAlexandre Courbot // Run FWSEC-FRTS to create the WPR2 region. 52e7c96980SAlexandre Courbot fwsec_frts.run(dev, falcon, bar)?; 53e7c96980SAlexandre Courbot 54e7c96980SAlexandre Courbot // SCRATCH_E contains the error code for FWSEC-FRTS. 55e7c96980SAlexandre Courbot let frts_status = regs::NV_PBUS_SW_SCRATCH_0E_FRTS_ERR::read(bar).frts_err_code(); 56e7c96980SAlexandre Courbot if frts_status != 0 { 57e7c96980SAlexandre Courbot dev_err!( 58e7c96980SAlexandre Courbot dev, 59e7c96980SAlexandre Courbot "FWSEC-FRTS returned with error code {:#x}", 60e7c96980SAlexandre Courbot frts_status 61e7c96980SAlexandre Courbot ); 62e7c96980SAlexandre Courbot 63e7c96980SAlexandre Courbot return Err(EIO); 64e7c96980SAlexandre Courbot } 65e7c96980SAlexandre Courbot 66e7c96980SAlexandre Courbot // Check that the WPR2 region has been created as we requested. 67e7c96980SAlexandre Courbot let (wpr2_lo, wpr2_hi) = ( 68e7c96980SAlexandre Courbot regs::NV_PFB_PRI_MMU_WPR2_ADDR_LO::read(bar).lower_bound(), 69e7c96980SAlexandre Courbot regs::NV_PFB_PRI_MMU_WPR2_ADDR_HI::read(bar).higher_bound(), 70e7c96980SAlexandre Courbot ); 71e7c96980SAlexandre Courbot 72e7c96980SAlexandre Courbot match (wpr2_lo, wpr2_hi) { 73e7c96980SAlexandre Courbot (_, 0) => { 74e7c96980SAlexandre Courbot dev_err!(dev, "WPR2 region not created after running FWSEC-FRTS\n"); 75e7c96980SAlexandre Courbot 76e7c96980SAlexandre Courbot Err(EIO) 77e7c96980SAlexandre Courbot } 78e7c96980SAlexandre Courbot (wpr2_lo, _) if wpr2_lo != fb_layout.frts.start => { 79e7c96980SAlexandre Courbot dev_err!( 80e7c96980SAlexandre Courbot dev, 81e7c96980SAlexandre Courbot "WPR2 region created at unexpected address {:#x}; expected {:#x}\n", 82e7c96980SAlexandre Courbot wpr2_lo, 83e7c96980SAlexandre Courbot fb_layout.frts.start, 84e7c96980SAlexandre Courbot ); 85e7c96980SAlexandre Courbot 86e7c96980SAlexandre Courbot Err(EIO) 87e7c96980SAlexandre Courbot } 88e7c96980SAlexandre Courbot (wpr2_lo, wpr2_hi) => { 89e7c96980SAlexandre Courbot dev_dbg!(dev, "WPR2: {:#x}-{:#x}\n", wpr2_lo, wpr2_hi); 90e7c96980SAlexandre Courbot dev_dbg!(dev, "GPU instance built\n"); 91e7c96980SAlexandre Courbot 92e7c96980SAlexandre Courbot Ok(()) 93e7c96980SAlexandre Courbot } 94e7c96980SAlexandre Courbot } 95e7c96980SAlexandre Courbot } 96e7c96980SAlexandre Courbot 97e7c96980SAlexandre Courbot /// Attempt to boot the GSP. 98e7c96980SAlexandre Courbot /// 99e7c96980SAlexandre Courbot /// This is a GPU-dependent and complex procedure that involves loading firmware files from 100e7c96980SAlexandre Courbot /// user-space, patching them with signatures, and building firmware-specific intricate data 101e7c96980SAlexandre Courbot /// structures that the GSP will use at runtime. 102e7c96980SAlexandre Courbot /// 103e7c96980SAlexandre Courbot /// Upon return, the GSP is up and running, and its runtime object given as return value. 104e7c96980SAlexandre Courbot pub(crate) fn boot( 105e7c96980SAlexandre Courbot self: Pin<&mut Self>, 106e7c96980SAlexandre Courbot pdev: &pci::Device<device::Bound>, 107e7c96980SAlexandre Courbot bar: &Bar0, 108e7c96980SAlexandre Courbot chipset: Chipset, 109e7c96980SAlexandre Courbot gsp_falcon: &Falcon<Gsp>, 1103e5c9681SAlexandre Courbot sec2_falcon: &Falcon<Sec2>, 111e7c96980SAlexandre Courbot ) -> Result { 112e7c96980SAlexandre Courbot let dev = pdev.as_ref(); 113e7c96980SAlexandre Courbot 114e7c96980SAlexandre Courbot let bios = Vbios::new(dev, bar)?; 115e7c96980SAlexandre Courbot 116*a841614eSAlexandre Courbot let _gsp_fw = KBox::pin_init( 117*a841614eSAlexandre Courbot GspFirmware::new(dev, chipset, FIRMWARE_VERSION)?, 118*a841614eSAlexandre Courbot GFP_KERNEL, 119*a841614eSAlexandre Courbot )?; 120*a841614eSAlexandre Courbot 121e7c96980SAlexandre Courbot let fb_layout = FbLayout::new(chipset, bar)?; 122e7c96980SAlexandre Courbot dev_dbg!(dev, "{:#x?}\n", fb_layout); 123e7c96980SAlexandre Courbot 124e7c96980SAlexandre Courbot Self::run_fwsec_frts(dev, gsp_falcon, bar, &bios, &fb_layout)?; 125e7c96980SAlexandre Courbot 1263e5c9681SAlexandre Courbot let _booter_loader = BooterFirmware::new( 1273e5c9681SAlexandre Courbot dev, 1283e5c9681SAlexandre Courbot BooterKind::Loader, 1293e5c9681SAlexandre Courbot chipset, 1303e5c9681SAlexandre Courbot FIRMWARE_VERSION, 1313e5c9681SAlexandre Courbot sec2_falcon, 1323e5c9681SAlexandre Courbot bar, 1333e5c9681SAlexandre Courbot )?; 1343e5c9681SAlexandre Courbot 135e7c96980SAlexandre Courbot Ok(()) 136e7c96980SAlexandre Courbot } 137e7c96980SAlexandre Courbot } 138