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