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