xref: /linux/drivers/gpu/nova-core/gsp/sequencer.rs (revision 320608e5bc887b03a67c26396bc698f556906db0)
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         GspBootContext, //
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 #[derive(Debug)]
71 pub(crate) enum GspSeqCmd {
72     RegWrite(fw::RegWritePayload),
73     RegModify(fw::RegModifyPayload),
74     RegPoll(fw::RegPollPayload),
75     DelayUs(fw::DelayUsPayload),
76     RegStore(fw::RegStorePayload),
77     CoreReset,
78     CoreStart,
79     CoreWaitForHalt,
80     CoreResume,
81 }
82 
83 impl GspSeqCmd {
84     /// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes.
85     pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> {
86         let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;
87         let opcode_size = core::mem::size_of::<u32>();
88 
89         let (cmd, size) = match fw_cmd.opcode()? {
90             fw::SeqBufOpcode::RegWrite => {
91                 let payload = fw_cmd.reg_write_payload()?;
92                 let size = opcode_size + size_of_val(&payload);
93                 (GspSeqCmd::RegWrite(payload), size)
94             }
95             fw::SeqBufOpcode::RegModify => {
96                 let payload = fw_cmd.reg_modify_payload()?;
97                 let size = opcode_size + size_of_val(&payload);
98                 (GspSeqCmd::RegModify(payload), size)
99             }
100             fw::SeqBufOpcode::RegPoll => {
101                 let payload = fw_cmd.reg_poll_payload()?;
102                 let size = opcode_size + size_of_val(&payload);
103                 (GspSeqCmd::RegPoll(payload), size)
104             }
105             fw::SeqBufOpcode::DelayUs => {
106                 let payload = fw_cmd.delay_us_payload()?;
107                 let size = opcode_size + size_of_val(&payload);
108                 (GspSeqCmd::DelayUs(payload), size)
109             }
110             fw::SeqBufOpcode::RegStore => {
111                 let payload = fw_cmd.reg_store_payload()?;
112                 let size = opcode_size + size_of_val(&payload);
113                 (GspSeqCmd::RegStore(payload), size)
114             }
115             fw::SeqBufOpcode::CoreReset => (GspSeqCmd::CoreReset, opcode_size),
116             fw::SeqBufOpcode::CoreStart => (GspSeqCmd::CoreStart, opcode_size),
117             fw::SeqBufOpcode::CoreWaitForHalt => (GspSeqCmd::CoreWaitForHalt, opcode_size),
118             fw::SeqBufOpcode::CoreResume => (GspSeqCmd::CoreResume, opcode_size),
119         };
120 
121         if data.len() < size {
122             dev_err!(dev, "Data is not enough for command\n");
123             return Err(EINVAL);
124         }
125 
126         Ok((cmd, size))
127     }
128 }
129 
130 /// GSP Sequencer for executing firmware commands during boot.
131 pub(crate) struct GspSequencer<'a> {
132     /// `Bar0` for register access.
133     bar: Bar0<'a>,
134     /// SEC2 falcon for core operations.
135     sec2_falcon: &'a Falcon<'a, Sec2>,
136     /// GSP falcon for core operations.
137     gsp_falcon: &'a Falcon<'a, Gsp>,
138     /// LibOS DMA handle address.
139     libos_dma_handle: u64,
140     /// Bootloader application version.
141     bootloader_app_version: u32,
142     /// Device for logging.
143     dev: &'a device::Device,
144 }
145 
146 impl fw::RegWritePayload {
147     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
148         let addr = usize::from_safe_cast(self.addr());
149 
150         sequencer.bar.try_write32(self.val(), addr)
151     }
152 }
153 
154 impl fw::RegModifyPayload {
155     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
156         let addr = usize::from_safe_cast(self.addr());
157 
158         sequencer.bar.try_read32(addr).and_then(|val| {
159             sequencer
160                 .bar
161                 .try_write32((val & !self.mask()) | self.val(), addr)
162         })
163     }
164 }
165 
166 impl fw::RegPollPayload {
167     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
168         let addr = usize::from_safe_cast(self.addr());
169 
170         // Default timeout to 4 seconds.
171         let timeout_us = if self.timeout() == 0 {
172             4_000_000
173         } else {
174             i64::from(self.timeout())
175         };
176 
177         // First read.
178         sequencer.bar.try_read32(addr)?;
179 
180         // Poll the requested register with requested timeout.
181         read_poll_timeout(
182             || sequencer.bar.try_read32(addr),
183             |current| (current & self.mask()) == self.val(),
184             Delta::ZERO,
185             Delta::from_micros(timeout_us),
186         )
187         .map(|_| ())
188     }
189 }
190 
191 impl fw::DelayUsPayload {
192     fn run(&self, _sequencer: &GspSequencer<'_>) -> Result {
193         fsleep(Delta::from_micros(i64::from(self.val())));
194         Ok(())
195     }
196 }
197 
198 impl fw::RegStorePayload {
199     fn run(&self, sequencer: &GspSequencer<'_>) -> Result {
200         let addr = usize::from_safe_cast(self.addr());
201 
202         sequencer.bar.try_read32(addr).map(|_| ())
203     }
204 }
205 
206 impl GspSeqCmd {
207     fn run(&self, seq: &GspSequencer<'_>) -> Result {
208         match self {
209             GspSeqCmd::RegWrite(cmd) => cmd.run(seq),
210             GspSeqCmd::RegModify(cmd) => cmd.run(seq),
211             GspSeqCmd::RegPoll(cmd) => cmd.run(seq),
212             GspSeqCmd::DelayUs(cmd) => cmd.run(seq),
213             GspSeqCmd::RegStore(cmd) => cmd.run(seq),
214             GspSeqCmd::CoreReset => {
215                 seq.gsp_falcon.reset()?;
216                 seq.gsp_falcon.dma_reset();
217                 Ok(())
218             }
219             GspSeqCmd::CoreStart => {
220                 seq.gsp_falcon.start()?;
221                 Ok(())
222             }
223             GspSeqCmd::CoreWaitForHalt => {
224                 seq.gsp_falcon.wait_till_halted()?;
225                 Ok(())
226             }
227             GspSeqCmd::CoreResume => {
228                 // At this point, 'SEC2-RTOS' has been loaded into SEC2 by the sequencer
229                 // but neither SEC2-RTOS nor GSP-RM is running yet. This part of the
230                 // sequencer will start both.
231 
232                 // Reset the GSP to prepare it for resuming.
233                 seq.gsp_falcon.reset()?;
234 
235                 // Write the libOS DMA handle to GSP mailboxes.
236                 seq.gsp_falcon.write_mailboxes(
237                     Some(seq.libos_dma_handle as u32),
238                     Some((seq.libos_dma_handle >> 32) as u32),
239                 );
240 
241                 // Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.
242                 seq.sec2_falcon.start()?;
243 
244                 // Poll until GSP-RM reload/resume has completed (up to 2 seconds).
245                 seq.gsp_falcon.check_reload_completed(Delta::from_secs(2))?;
246 
247                 // Verify SEC2 completed successfully by checking its mailbox for errors.
248                 let mbox0 = seq.sec2_falcon.read_mailbox0();
249                 if mbox0 != 0 {
250                     dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);
251                     return Err(EIO);
252                 }
253 
254                 // Configure GSP with the bootloader version.
255                 seq.gsp_falcon.write_os_version(seq.bootloader_app_version);
256 
257                 // Verify the GSP's RISC-V core is active indicating successful GSP boot.
258                 if !seq.gsp_falcon.is_riscv_active() {
259                     dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");
260                     return Err(EIO);
261                 }
262                 Ok(())
263             }
264         }
265     }
266 }
267 
268 /// Iterator over GSP sequencer commands.
269 struct GspSeqIter<'a> {
270     /// Command data buffer.
271     cmd_data: &'a [u8],
272     /// Current position in the buffer.
273     current_offset: usize,
274     /// Total number of commands to process.
275     total_cmds: u32,
276     /// Number of commands processed so far.
277     cmds_processed: u32,
278     /// Device for logging.
279     dev: &'a device::Device,
280 }
281 
282 impl<'a> GspSeqIter<'a> {
283     fn new(seq: &'a GspSequence, dev: &'a device::Device) -> Self {
284         Self {
285             cmd_data: &seq.cmd_data,
286             current_offset: 0,
287             total_cmds: seq.cmd_index,
288             cmds_processed: 0,
289             dev,
290         }
291     }
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 {}\n", 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     pub(crate) fn run(
337         cmdq: &Cmdq,
338         ctx: &'a GspBootContext<'_, '_>,
339         libos_dma_handle: u64,
340         bootloader_app_version: u32,
341     ) -> Result {
342         let seq_info = loop {
343             match cmdq.receive_msg::<GspSequence>(Cmdq::RECEIVE_TIMEOUT) {
344                 Ok(seq_info) => break seq_info,
345                 Err(ERANGE) => continue,
346                 Err(e) => return Err(e),
347             }
348         };
349 
350         let sequencer = GspSequencer {
351             bar: ctx.bar,
352             sec2_falcon: ctx.sec2_falcon,
353             gsp_falcon: ctx.gsp_falcon,
354             libos_dma_handle,
355             bootloader_app_version,
356             dev: ctx.dev(),
357         };
358 
359         dev_dbg!(sequencer.dev, "Running CPU Sequencer commands\n");
360 
361         for cmd_result in GspSeqIter::new(&seq_info, sequencer.dev) {
362             match cmd_result {
363                 Ok(cmd) => cmd.run(&sequencer)?,
364                 Err(e) => {
365                     dev_err!(
366                         sequencer.dev,
367                         "Error running command at index {}\n",
368                         seq_info.cmd_index
369                     );
370                     return Err(e);
371                 }
372             }
373         }
374 
375         dev_dbg!(
376             sequencer.dev,
377             "CPU Sequencer commands completed successfully\n"
378         );
379         Ok(())
380     }
381 }
382