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::size_of, // 8 }; 9 10 use kernel::{ 11 device, 12 prelude::*, 13 time::Delta, 14 transmute::FromBytes, 15 types::ARef, // 16 }; 17 18 use crate::{ 19 driver::Bar0, 20 falcon::{ 21 gsp::Gsp, 22 sec2::Sec2, 23 Falcon, // 24 }, 25 gsp::{ 26 cmdq::{ 27 Cmdq, 28 MessageFromGsp, // 29 }, 30 fw, 31 }, 32 sbuffer::SBufferIter, 33 }; 34 35 /// GSP Sequencer information containing the command sequence and data. 36 struct GspSequence { 37 /// Current command index for error reporting. 38 cmd_index: u32, 39 /// Command data buffer containing the sequence of commands. 40 cmd_data: KVec<u8>, 41 } 42 43 impl MessageFromGsp for GspSequence { 44 const FUNCTION: fw::MsgFunction = fw::MsgFunction::GspRunCpuSequencer; 45 type InitError = Error; 46 type Message = fw::RunCpuSequencer; 47 48 fn read( 49 msg: &Self::Message, 50 sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>, 51 ) -> Result<Self, Self::InitError> { 52 let cmd_data = sbuffer.flush_into_kvec(GFP_KERNEL)?; 53 Ok(GspSequence { 54 cmd_index: msg.cmd_index(), 55 cmd_data, 56 }) 57 } 58 } 59 60 const CMD_SIZE: usize = size_of::<fw::SequencerBufferCmd>(); 61 62 /// GSP Sequencer Command types with payload data. 63 /// Commands have an opcode and an opcode-dependent struct. 64 #[allow(dead_code)] 65 pub(crate) enum GspSeqCmd {} 66 67 impl GspSeqCmd { 68 /// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes. 69 pub(crate) fn new(data: &[u8], _dev: &device::Device) -> Result<(Self, usize)> { 70 let _fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?; 71 let _opcode_size = core::mem::size_of::<u32>(); 72 73 // NOTE: At this commit, NO opcodes exist yet, so just return error. 74 // Later commits will add match arms here. 75 Err(EINVAL) 76 } 77 } 78 79 /// GSP Sequencer for executing firmware commands during boot. 80 #[expect(dead_code)] 81 pub(crate) struct GspSequencer<'a> { 82 /// Sequencer information with command data. 83 seq_info: GspSequence, 84 /// `Bar0` for register access. 85 bar: &'a Bar0, 86 /// SEC2 falcon for core operations. 87 sec2_falcon: &'a Falcon<Sec2>, 88 /// GSP falcon for core operations. 89 gsp_falcon: &'a Falcon<Gsp>, 90 /// LibOS DMA handle address. 91 libos_dma_handle: u64, 92 /// Bootloader application version. 93 bootloader_app_version: u32, 94 /// Device for logging. 95 dev: ARef<device::Device>, 96 } 97 98 /// Trait for running sequencer commands. 99 pub(crate) trait GspSeqCmdRunner { 100 fn run(&self, sequencer: &GspSequencer<'_>) -> Result; 101 } 102 103 impl GspSeqCmdRunner for GspSeqCmd { 104 fn run(&self, _seq: &GspSequencer<'_>) -> Result { 105 Ok(()) 106 } 107 } 108 109 /// Iterator over GSP sequencer commands. 110 pub(crate) struct GspSeqIter<'a> { 111 /// Command data buffer. 112 cmd_data: &'a [u8], 113 /// Current position in the buffer. 114 current_offset: usize, 115 /// Total number of commands to process. 116 total_cmds: u32, 117 /// Number of commands processed so far. 118 cmds_processed: u32, 119 /// Device for logging. 120 dev: ARef<device::Device>, 121 } 122 123 impl<'a> Iterator for GspSeqIter<'a> { 124 type Item = Result<GspSeqCmd>; 125 126 fn next(&mut self) -> Option<Self::Item> { 127 // Stop if we've processed all commands or reached the end of data. 128 if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() { 129 return None; 130 } 131 132 // Check if we have enough data for opcode. 133 if self.current_offset + core::mem::size_of::<u32>() > self.cmd_data.len() { 134 return Some(Err(EIO)); 135 } 136 137 let offset = self.current_offset; 138 139 // Handle command creation based on available data, 140 // zero-pad if necessary (since last command may not be full size). 141 let mut buffer = [0u8; CMD_SIZE]; 142 let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() { 143 CMD_SIZE 144 } else { 145 self.cmd_data.len() - offset 146 }; 147 buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]); 148 let cmd_result = GspSeqCmd::new(&buffer, &self.dev); 149 150 cmd_result.map_or_else( 151 |_err| { 152 dev_err!(self.dev, "Error parsing command at offset {}", offset); 153 None 154 }, 155 |(cmd, size)| { 156 self.current_offset += size; 157 self.cmds_processed += 1; 158 Some(Ok(cmd)) 159 }, 160 ) 161 } 162 } 163 164 impl<'a> GspSequencer<'a> { 165 fn iter(&self) -> GspSeqIter<'_> { 166 let cmd_data = &self.seq_info.cmd_data[..]; 167 168 GspSeqIter { 169 cmd_data, 170 current_offset: 0, 171 total_cmds: self.seq_info.cmd_index, 172 cmds_processed: 0, 173 dev: self.dev.clone(), 174 } 175 } 176 } 177 178 /// Parameters for running the GSP sequencer. 179 pub(crate) struct GspSequencerParams<'a> { 180 /// Bootloader application version. 181 pub(crate) bootloader_app_version: u32, 182 /// LibOS DMA handle address. 183 pub(crate) libos_dma_handle: u64, 184 /// GSP falcon for core operations. 185 pub(crate) gsp_falcon: &'a Falcon<Gsp>, 186 /// SEC2 falcon for core operations. 187 pub(crate) sec2_falcon: &'a Falcon<Sec2>, 188 /// Device for logging. 189 pub(crate) dev: ARef<device::Device>, 190 /// BAR0 for register access. 191 pub(crate) bar: &'a Bar0, 192 } 193 194 impl<'a> GspSequencer<'a> { 195 pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result { 196 let seq_info = loop { 197 match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) { 198 Ok(seq_info) => break seq_info, 199 Err(ERANGE) => continue, 200 Err(e) => return Err(e), 201 } 202 }; 203 204 let sequencer = GspSequencer { 205 seq_info, 206 bar: params.bar, 207 sec2_falcon: params.sec2_falcon, 208 gsp_falcon: params.gsp_falcon, 209 libos_dma_handle: params.libos_dma_handle, 210 bootloader_app_version: params.bootloader_app_version, 211 dev: params.dev, 212 }; 213 214 dev_dbg!(sequencer.dev, "Running CPU Sequencer commands"); 215 216 for cmd_result in sequencer.iter() { 217 match cmd_result { 218 Ok(cmd) => cmd.run(&sequencer)?, 219 Err(e) => { 220 dev_err!( 221 sequencer.dev, 222 "Error running command at index {}", 223 sequencer.seq_info.cmd_index 224 ); 225 return Err(e); 226 } 227 } 228 } 229 230 dev_dbg!( 231 sequencer.dev, 232 "CPU Sequencer commands completed successfully" 233 ); 234 Ok(()) 235 } 236 } 237