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