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