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