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