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