xref: /linux/drivers/gpu/nova-core/gsp/boot.rs (revision 58809f614e0e3f4e12b489bddf680bfeb31c0a20)
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