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