xref: /linux/drivers/gpu/nova-core/gsp/sequencer.rs (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! GSP Sequencer implementation for Pre-hopper GSP boot sequence.
4 
5 use core::array;
6 
7 use kernel::{
8     device,
9     io::poll::read_poll_timeout,
10     prelude::*,
11     time::{
12         delay::fsleep,
13         Delta, //
14     },
15     transmute::FromBytes,
16     types::ARef, //
17 };
18 
19 use crate::{
20     driver::Bar0,
21     falcon::{
22         gsp::Gsp,
23         sec2::Sec2,
24         Falcon, //
25     },
26     gsp::{
27         cmdq::{
28             Cmdq,
29             MessageFromGsp, //
30         },
31         fw,
32     },
33     num::FromSafeCast,
34     sbuffer::SBufferIter,
35 };
36 
37 /// GSP Sequencer information containing the command sequence and data.
38 struct GspSequence {
39     /// Current command index for error reporting.
40     cmd_index: u32,
41     /// Command data buffer containing the sequence of commands.
42     cmd_data: KVec<u8>,
43 }
44 
45 impl MessageFromGsp for GspSequence {
46     const FUNCTION: fw::MsgFunction = fw::MsgFunction::GspRunCpuSequencer;
47     type InitError = Error;
48     type Message = fw::RunCpuSequencer;
49 
50     fn read(
51         msg: &Self::Message,
52         sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
53     ) -> Result<Self, Self::InitError> {
54         let cmd_data = sbuffer.flush_into_kvec(GFP_KERNEL)?;
55         Ok(GspSequence {
56             cmd_index: msg.cmd_index(),
57             cmd_data,
58         })
59     }
60 }
61 
62 const CMD_SIZE: usize = size_of::<fw::SequencerBufferCmd>();
63 
64 /// GSP Sequencer Command types with payload data.
65 /// Commands have an opcode and an opcode-dependent struct.
66 #[allow(clippy::enum_variant_names)]
67 pub(crate) enum GspSeqCmd {
68     RegWrite(fw::RegWritePayload),
69     RegModify(fw::RegModifyPayload),
70     RegPoll(fw::RegPollPayload),
71     DelayUs(fw::DelayUsPayload),
72     RegStore(fw::RegStorePayload),
73     CoreReset,
74     CoreStart,
75     CoreWaitForHalt,
76     CoreResume,
77 }
78 
79 impl GspSeqCmd {
80     /// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes.
81     pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> {
82         let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;
83         let opcode_size = core::mem::size_of::<u32>();
84 
85         let (cmd, size) = match fw_cmd.opcode()? {
86             fw::SeqBufOpcode::RegWrite => {
87                 let payload = fw_cmd.reg_write_payload()?;
88                 let size = opcode_size + size_of_val(&payload);
89                 (GspSeqCmd::RegWrite(payload), size)
90             }
91             fw::SeqBufOpcode::RegModify => {
92                 let payload = fw_cmd.reg_modify_payload()?;
93                 let size = opcode_size + size_of_val(&payload);
94                 (GspSeqCmd::RegModify(payload), size)
95             }
96             fw::SeqBufOpcode::RegPoll => {
97                 let payload = fw_cmd.reg_poll_payload()?;
98                 let size = opcode_size + size_of_val(&payload);
99                 (GspSeqCmd::RegPoll(payload), size)
100             }
101             fw::SeqBufOpcode::DelayUs => {
102                 let payload = fw_cmd.delay_us_payload()?;
103                 let size = opcode_size + size_of_val(&payload);
104                 (GspSeqCmd::DelayUs(payload), size)
105             }
106             fw::SeqBufOpcode::RegStore => {
107                 let payload = fw_cmd.reg_store_payload()?;
108                 let size = opcode_size + size_of_val(&payload);
109                 (GspSeqCmd::RegStore(payload), size)
110             }
111             fw::SeqBufOpcode::CoreReset => (GspSeqCmd::CoreReset, opcode_size),
112             fw::SeqBufOpcode::CoreStart => (GspSeqCmd::CoreStart, opcode_size),
113             fw::SeqBufOpcode::CoreWaitForHalt => (GspSeqCmd::CoreWaitForHalt, opcode_size),
114             fw::SeqBufOpcode::CoreResume => (GspSeqCmd::CoreResume, opcode_size),
115         };
116 
117         if data.len() < size {
118             dev_err!(dev, "Data is not enough for command");
119             return Err(EINVAL);
120         }
121 
122         Ok((cmd, size))
123     }
124 }
125 
126 /// GSP Sequencer for executing firmware commands during boot.
127 pub(crate) struct GspSequencer<'a> {
128     /// Sequencer information with command data.
129     seq_info: GspSequence,
130     /// `Bar0` for register access.
131     bar: &'a Bar0,
132     /// SEC2 falcon for core operations.
133     sec2_falcon: &'a Falcon<Sec2>,
134     /// GSP falcon for core operations.
135     gsp_falcon: &'a Falcon<Gsp>,
136     /// LibOS DMA handle address.
137     libos_dma_handle: u64,
138     /// Bootloader application version.
139     bootloader_app_version: u32,
140     /// Device for logging.
141     dev: ARef<device::Device>,
142 }
143 
144 /// Trait for running sequencer commands.
145 pub(crate) trait GspSeqCmdRunner {
146     fn run(&self, sequencer: &GspSequencer<'_>) -> Result;
147 }
148 
149 impl GspSeqCmdRunner for fw::RegWritePayload {
150     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
151         let addr = usize::from_safe_cast(self.addr());
152 
153         sequencer.bar.try_write32(self.val(), addr)
154     }
155 }
156 
157 impl GspSeqCmdRunner for fw::RegModifyPayload {
158     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
159         let addr = usize::from_safe_cast(self.addr());
160 
161         sequencer.bar.try_read32(addr).and_then(|val| {
162             sequencer
163                 .bar
164                 .try_write32((val & !self.mask()) | self.val(), addr)
165         })
166     }
167 }
168 
169 impl GspSeqCmdRunner for fw::RegPollPayload {
170     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
171         let addr = usize::from_safe_cast(self.addr());
172 
173         // Default timeout to 4 seconds.
174         let timeout_us = if self.timeout() == 0 {
175             4_000_000
176         } else {
177             i64::from(self.timeout())
178         };
179 
180         // First read.
181         sequencer.bar.try_read32(addr)?;
182 
183         // Poll the requested register with requested timeout.
184         read_poll_timeout(
185             || sequencer.bar.try_read32(addr),
186             |current| (current & self.mask()) == self.val(),
187             Delta::ZERO,
188             Delta::from_micros(timeout_us),
189         )
190         .map(|_| ())
191     }
192 }
193 
194 impl GspSeqCmdRunner for fw::DelayUsPayload {
195     fn run(&self, _sequencer: &GspSequencer<'_>) -> Result {
196         fsleep(Delta::from_micros(i64::from(self.val())));
197         Ok(())
198     }
199 }
200 
201 impl GspSeqCmdRunner for fw::RegStorePayload {
202     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
203         let addr = usize::from_safe_cast(self.addr());
204 
205         sequencer.bar.try_read32(addr).map(|_| ())
206     }
207 }
208 
209 impl GspSeqCmdRunner for GspSeqCmd {
210     fn run(&self, seq: &GspSequencer<'_>) -> Result {
211         match self {
212             GspSeqCmd::RegWrite(cmd) => cmd.run(seq),
213             GspSeqCmd::RegModify(cmd) => cmd.run(seq),
214             GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
215             GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
216             GspSeqCmd::RegStore(cmd) => cmd.run(seq),
217             GspSeqCmd::CoreReset => {
218                 seq.gsp_falcon.reset(seq.bar)?;
219                 seq.gsp_falcon.dma_reset(seq.bar);
220                 Ok(())
221             }
222             GspSeqCmd::CoreStart => {
223                 seq.gsp_falcon.start(seq.bar)?;
224                 Ok(())
225             }
226             GspSeqCmd::CoreWaitForHalt => {
227                 seq.gsp_falcon.wait_till_halted(seq.bar)?;
228                 Ok(())
229             }
230             GspSeqCmd::CoreResume => {
231                 // At this point, 'SEC2-RTOS' has been loaded into SEC2 by the sequencer
232                 // but neither SEC2-RTOS nor GSP-RM is running yet. This part of the
233                 // sequencer will start both.
234 
235                 // Reset the GSP to prepare it for resuming.
236                 seq.gsp_falcon.reset(seq.bar)?;
237 
238                 // Write the libOS DMA handle to GSP mailboxes.
239                 seq.gsp_falcon.write_mailboxes(
240                     seq.bar,
241                     Some(seq.libos_dma_handle as u32),
242                     Some((seq.libos_dma_handle >> 32) as u32),
243                 );
244 
245                 // Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
246                 seq.sec2_falcon.start(seq.bar)?;
247 
248                 // Poll until GSP-RM reload/resume has completed (up to 2 seconds).
249                 seq.gsp_falcon
250                     .check_reload_completed(seq.bar, Delta::from_secs(2))?;
251 
252                 // Verify SEC2 completed successfully by checking its mailbox for errors.
253                 let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);
254                 if mbox0 != 0 {
255                     dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
256                     return Err(EIO);
257                 }
258 
259                 // Configure GSP with the bootloader version.
260                 seq.gsp_falcon
261                     .write_os_version(seq.bar, seq.bootloader_app_version);
262 
263                 // Verify the GSP's RISC-V core is active indicating successful GSP boot.
264                 if !seq.gsp_falcon.is_riscv_active(seq.bar) {
265                     dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
266                     return Err(EIO);
267                 }
268                 Ok(())
269             }
270         }
271     }
272 }
273 
274 /// Iterator over GSP sequencer commands.
275 pub(crate) struct GspSeqIter<'a> {
276     /// Command data buffer.
277     cmd_data: &'a [u8],
278     /// Current position in the buffer.
279     current_offset: usize,
280     /// Total number of commands to process.
281     total_cmds: u32,
282     /// Number of commands processed so far.
283     cmds_processed: u32,
284     /// Device for logging.
285     dev: ARef<device::Device>,
286 }
287 
288 impl<'a> Iterator for GspSeqIter<'a> {
289     type Item = Result<GspSeqCmd>;
290 
291     fn next(&mut self) -> Option<Self::Item> {
292         // Stop if we've processed all commands or reached the end of data.
293         if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() {
294             return None;
295         }
296 
297         // Check if we have enough data for opcode.
298         if self.current_offset + core::mem::size_of::<u32>() > self.cmd_data.len() {
299             return Some(Err(EIO));
300         }
301 
302         let offset = self.current_offset;
303 
304         // Handle command creation based on available data,
305         // zero-pad if necessary (since last command may not be full size).
306         let mut buffer = [0u8; CMD_SIZE];
307         let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() {
308             CMD_SIZE
309         } else {
310             self.cmd_data.len() - offset
311         };
312         buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]);
313         let cmd_result = GspSeqCmd::new(&buffer, &self.dev);
314 
315         cmd_result.map_or_else(
316             |_err| {
317                 dev_err!(self.dev, "Error parsing command at offset {}", offset);
318                 None
319             },
320             |(cmd, size)| {
321                 self.current_offset += size;
322                 self.cmds_processed += 1;
323                 Some(Ok(cmd))
324             },
325         )
326     }
327 }
328 
329 impl<'a> GspSequencer<'a> {
330     fn iter(&self) -> GspSeqIter<'_> {
331         let cmd_data = &self.seq_info.cmd_data[..];
332 
333         GspSeqIter {
334             cmd_data,
335             current_offset: 0,
336             total_cmds: self.seq_info.cmd_index,
337             cmds_processed: 0,
338             dev: self.dev.clone(),
339         }
340     }
341 }
342 
343 /// Parameters for running the GSP sequencer.
344 pub(crate) struct GspSequencerParams<'a> {
345     /// Bootloader application version.
346     pub(crate) bootloader_app_version: u32,
347     /// LibOS DMA handle address.
348     pub(crate) libos_dma_handle: u64,
349     /// GSP falcon for core operations.
350     pub(crate) gsp_falcon: &'a Falcon<Gsp>,
351     /// SEC2 falcon for core operations.
352     pub(crate) sec2_falcon: &'a Falcon<Sec2>,
353     /// Device for logging.
354     pub(crate) dev: ARef<device::Device>,
355     /// BAR0 for register access.
356     pub(crate) bar: &'a Bar0,
357 }
358 
359 impl<'a> GspSequencer<'a> {
360     pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result {
361         let seq_info = loop {
362             match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) {
363                 Ok(seq_info) => break seq_info,
364                 Err(ERANGE) => continue,
365                 Err(e) => return Err(e),
366             }
367         };
368 
369         let sequencer = GspSequencer {
370             seq_info,
371             bar: params.bar,
372             sec2_falcon: params.sec2_falcon,
373             gsp_falcon: params.gsp_falcon,
374             libos_dma_handle: params.libos_dma_handle,
375             bootloader_app_version: params.bootloader_app_version,
376             dev: params.dev,
377         };
378 
379         dev_dbg!(sequencer.dev, "Running CPU Sequencer commands");
380 
381         for cmd_result in sequencer.iter() {
382             match cmd_result {
383                 Ok(cmd) => cmd.run(&sequencer)?,
384                 Err(e) => {
385                     dev_err!(
386                         sequencer.dev,
387                         "Error running command at index {}",
388                         sequencer.seq_info.cmd_index
389                     );
390                     return Err(e);
391                 }
392             }
393         }
394 
395         dev_dbg!(
396             sequencer.dev,
397             "CPU Sequencer commands completed successfully"
398         );
399         Ok(())
400     }
401 }
402