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