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 } 80 81 impl GspSeqCmd { 82 /// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes. 83 pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> { 84 let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?; 85 let opcode_size = core::mem::size_of::<u32>(); 86 87 let (cmd, size) = match fw_cmd.opcode()? { 88 fw::SeqBufOpcode::RegWrite => { 89 let payload = fw_cmd.reg_write_payload()?; 90 let size = opcode_size + size_of_val(&payload); 91 (GspSeqCmd::RegWrite(payload), size) 92 } 93 fw::SeqBufOpcode::RegModify => { 94 let payload = fw_cmd.reg_modify_payload()?; 95 let size = opcode_size + size_of_val(&payload); 96 (GspSeqCmd::RegModify(payload), size) 97 } 98 fw::SeqBufOpcode::RegPoll => { 99 let payload = fw_cmd.reg_poll_payload()?; 100 let size = opcode_size + size_of_val(&payload); 101 (GspSeqCmd::RegPoll(payload), size) 102 } 103 fw::SeqBufOpcode::DelayUs => { 104 let payload = fw_cmd.delay_us_payload()?; 105 let size = opcode_size + size_of_val(&payload); 106 (GspSeqCmd::DelayUs(payload), size) 107 } 108 fw::SeqBufOpcode::RegStore => { 109 let payload = fw_cmd.reg_store_payload()?; 110 let size = opcode_size + size_of_val(&payload); 111 (GspSeqCmd::RegStore(payload), size) 112 } 113 _ => return Err(EINVAL), 114 }; 115 116 if data.len() < size { 117 dev_err!(dev, "Data is not enough for command"); 118 return Err(EINVAL); 119 } 120 121 Ok((cmd, size)) 122 } 123 } 124 125 /// GSP Sequencer for executing firmware commands during boot. 126 #[expect(dead_code)] 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 } 218 } 219 } 220 221 /// Iterator over GSP sequencer commands. 222 pub(crate) struct GspSeqIter<'a> { 223 /// Command data buffer. 224 cmd_data: &'a [u8], 225 /// Current position in the buffer. 226 current_offset: usize, 227 /// Total number of commands to process. 228 total_cmds: u32, 229 /// Number of commands processed so far. 230 cmds_processed: u32, 231 /// Device for logging. 232 dev: ARef<device::Device>, 233 } 234 235 impl<'a> Iterator for GspSeqIter<'a> { 236 type Item = Result<GspSeqCmd>; 237 238 fn next(&mut self) -> Option<Self::Item> { 239 // Stop if we've processed all commands or reached the end of data. 240 if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() { 241 return None; 242 } 243 244 // Check if we have enough data for opcode. 245 if self.current_offset + core::mem::size_of::<u32>() > self.cmd_data.len() { 246 return Some(Err(EIO)); 247 } 248 249 let offset = self.current_offset; 250 251 // Handle command creation based on available data, 252 // zero-pad if necessary (since last command may not be full size). 253 let mut buffer = [0u8; CMD_SIZE]; 254 let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() { 255 CMD_SIZE 256 } else { 257 self.cmd_data.len() - offset 258 }; 259 buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]); 260 let cmd_result = GspSeqCmd::new(&buffer, &self.dev); 261 262 cmd_result.map_or_else( 263 |_err| { 264 dev_err!(self.dev, "Error parsing command at offset {}", offset); 265 None 266 }, 267 |(cmd, size)| { 268 self.current_offset += size; 269 self.cmds_processed += 1; 270 Some(Ok(cmd)) 271 }, 272 ) 273 } 274 } 275 276 impl<'a> GspSequencer<'a> { 277 fn iter(&self) -> GspSeqIter<'_> { 278 let cmd_data = &self.seq_info.cmd_data[..]; 279 280 GspSeqIter { 281 cmd_data, 282 current_offset: 0, 283 total_cmds: self.seq_info.cmd_index, 284 cmds_processed: 0, 285 dev: self.dev.clone(), 286 } 287 } 288 } 289 290 /// Parameters for running the GSP sequencer. 291 pub(crate) struct GspSequencerParams<'a> { 292 /// Bootloader application version. 293 pub(crate) bootloader_app_version: u32, 294 /// LibOS DMA handle address. 295 pub(crate) libos_dma_handle: u64, 296 /// GSP falcon for core operations. 297 pub(crate) gsp_falcon: &'a Falcon<Gsp>, 298 /// SEC2 falcon for core operations. 299 pub(crate) sec2_falcon: &'a Falcon<Sec2>, 300 /// Device for logging. 301 pub(crate) dev: ARef<device::Device>, 302 /// BAR0 for register access. 303 pub(crate) bar: &'a Bar0, 304 } 305 306 impl<'a> GspSequencer<'a> { 307 pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result { 308 let seq_info = loop { 309 match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) { 310 Ok(seq_info) => break seq_info, 311 Err(ERANGE) => continue, 312 Err(e) => return Err(e), 313 } 314 }; 315 316 let sequencer = GspSequencer { 317 seq_info, 318 bar: params.bar, 319 sec2_falcon: params.sec2_falcon, 320 gsp_falcon: params.gsp_falcon, 321 libos_dma_handle: params.libos_dma_handle, 322 bootloader_app_version: params.bootloader_app_version, 323 dev: params.dev, 324 }; 325 326 dev_dbg!(sequencer.dev, "Running CPU Sequencer commands"); 327 328 for cmd_result in sequencer.iter() { 329 match cmd_result { 330 Ok(cmd) => cmd.run(&sequencer)?, 331 Err(e) => { 332 dev_err!( 333 sequencer.dev, 334 "Error running command at index {}", 335 sequencer.seq_info.cmd_index 336 ); 337 return Err(e); 338 } 339 } 340 } 341 342 dev_dbg!( 343 sequencer.dev, 344 "CPU Sequencer commands completed successfully" 345 ); 346 Ok(()) 347 } 348 } 349