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