Path: blob/master/drivers/gpu/nova-core/gsp/sequencer.rs
122941 views
// SPDX-License-Identifier: GPL-2.012//! GSP Sequencer implementation for Pre-hopper GSP boot sequence.34use core::array;56use kernel::{7device,8io::{9poll::read_poll_timeout,10Io, //11},12prelude::*,13sync::aref::ARef,14time::{15delay::fsleep,16Delta, //17},18transmute::FromBytes, //19};2021use crate::{22driver::Bar0,23falcon::{24gsp::Gsp,25sec2::Sec2,26Falcon, //27},28gsp::{29cmdq::{30Cmdq,31MessageFromGsp, //32},33fw,34},35num::FromSafeCast,36sbuffer::SBufferIter,37};3839/// GSP Sequencer information containing the command sequence and data.40struct GspSequence {41/// Current command index for error reporting.42cmd_index: u32,43/// Command data buffer containing the sequence of commands.44cmd_data: KVec<u8>,45}4647impl MessageFromGsp for GspSequence {48const FUNCTION: fw::MsgFunction = fw::MsgFunction::GspRunCpuSequencer;49type InitError = Error;50type Message = fw::RunCpuSequencer;5152fn read(53msg: &Self::Message,54sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,55) -> Result<Self, Self::InitError> {56let cmd_data = sbuffer.flush_into_kvec(GFP_KERNEL)?;57Ok(GspSequence {58cmd_index: msg.cmd_index(),59cmd_data,60})61}62}6364const CMD_SIZE: usize = size_of::<fw::SequencerBufferCmd>();6566/// GSP Sequencer Command types with payload data.67/// Commands have an opcode and an opcode-dependent struct.68#[allow(clippy::enum_variant_names)]69pub(crate) enum GspSeqCmd {70RegWrite(fw::RegWritePayload),71RegModify(fw::RegModifyPayload),72RegPoll(fw::RegPollPayload),73DelayUs(fw::DelayUsPayload),74RegStore(fw::RegStorePayload),75CoreReset,76CoreStart,77CoreWaitForHalt,78CoreResume,79}8081impl GspSeqCmd {82/// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes.83pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> {84let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?;85let opcode_size = core::mem::size_of::<u32>();8687let (cmd, size) = match fw_cmd.opcode()? {88fw::SeqBufOpcode::RegWrite => {89let payload = fw_cmd.reg_write_payload()?;90let size = opcode_size + size_of_val(&payload);91(GspSeqCmd::RegWrite(payload), size)92}93fw::SeqBufOpcode::RegModify => {94let payload = fw_cmd.reg_modify_payload()?;95let size = opcode_size + size_of_val(&payload);96(GspSeqCmd::RegModify(payload), size)97}98fw::SeqBufOpcode::RegPoll => {99let payload = fw_cmd.reg_poll_payload()?;100let size = opcode_size + size_of_val(&payload);101(GspSeqCmd::RegPoll(payload), size)102}103fw::SeqBufOpcode::DelayUs => {104let payload = fw_cmd.delay_us_payload()?;105let size = opcode_size + size_of_val(&payload);106(GspSeqCmd::DelayUs(payload), size)107}108fw::SeqBufOpcode::RegStore => {109let payload = fw_cmd.reg_store_payload()?;110let size = opcode_size + size_of_val(&payload);111(GspSeqCmd::RegStore(payload), size)112}113fw::SeqBufOpcode::CoreReset => (GspSeqCmd::CoreReset, opcode_size),114fw::SeqBufOpcode::CoreStart => (GspSeqCmd::CoreStart, opcode_size),115fw::SeqBufOpcode::CoreWaitForHalt => (GspSeqCmd::CoreWaitForHalt, opcode_size),116fw::SeqBufOpcode::CoreResume => (GspSeqCmd::CoreResume, opcode_size),117};118119if data.len() < size {120dev_err!(dev, "Data is not enough for command\n");121return Err(EINVAL);122}123124Ok((cmd, size))125}126}127128/// GSP Sequencer for executing firmware commands during boot.129pub(crate) struct GspSequencer<'a> {130/// Sequencer information with command data.131seq_info: GspSequence,132/// `Bar0` for register access.133bar: &'a Bar0,134/// SEC2 falcon for core operations.135sec2_falcon: &'a Falcon<Sec2>,136/// GSP falcon for core operations.137gsp_falcon: &'a Falcon<Gsp>,138/// LibOS DMA handle address.139libos_dma_handle: u64,140/// Bootloader application version.141bootloader_app_version: u32,142/// Device for logging.143dev: ARef<device::Device>,144}145146/// Trait for running sequencer commands.147pub(crate) trait GspSeqCmdRunner {148fn run(&self, sequencer: &GspSequencer<'_>) -> Result;149}150151impl GspSeqCmdRunner for fw::RegWritePayload {152fn run(&self, sequencer: &GspSequencer<'_>) -> Result {153let addr = usize::from_safe_cast(self.addr());154155sequencer.bar.try_write32(self.val(), addr)156}157}158159impl GspSeqCmdRunner for fw::RegModifyPayload {160fn run(&self, sequencer: &GspSequencer<'_>) -> Result {161let addr = usize::from_safe_cast(self.addr());162163sequencer.bar.try_read32(addr).and_then(|val| {164sequencer165.bar166.try_write32((val & !self.mask()) | self.val(), addr)167})168}169}170171impl GspSeqCmdRunner for fw::RegPollPayload {172fn run(&self, sequencer: &GspSequencer<'_>) -> Result {173let addr = usize::from_safe_cast(self.addr());174175// Default timeout to 4 seconds.176let timeout_us = if self.timeout() == 0 {1774_000_000178} else {179i64::from(self.timeout())180};181182// First read.183sequencer.bar.try_read32(addr)?;184185// Poll the requested register with requested timeout.186read_poll_timeout(187|| sequencer.bar.try_read32(addr),188|current| (current & self.mask()) == self.val(),189Delta::ZERO,190Delta::from_micros(timeout_us),191)192.map(|_| ())193}194}195196impl GspSeqCmdRunner for fw::DelayUsPayload {197fn run(&self, _sequencer: &GspSequencer<'_>) -> Result {198fsleep(Delta::from_micros(i64::from(self.val())));199Ok(())200}201}202203impl GspSeqCmdRunner for fw::RegStorePayload {204fn run(&self, sequencer: &GspSequencer<'_>) -> Result {205let addr = usize::from_safe_cast(self.addr());206207sequencer.bar.try_read32(addr).map(|_| ())208}209}210211impl GspSeqCmdRunner for GspSeqCmd {212fn run(&self, seq: &GspSequencer<'_>) -> Result {213match self {214GspSeqCmd::RegWrite(cmd) => cmd.run(seq),215GspSeqCmd::RegModify(cmd) => cmd.run(seq),216GspSeqCmd::RegPoll(cmd) => cmd.run(seq),217GspSeqCmd::DelayUs(cmd) => cmd.run(seq),218GspSeqCmd::RegStore(cmd) => cmd.run(seq),219GspSeqCmd::CoreReset => {220seq.gsp_falcon.reset(seq.bar)?;221seq.gsp_falcon.dma_reset(seq.bar);222Ok(())223}224GspSeqCmd::CoreStart => {225seq.gsp_falcon.start(seq.bar)?;226Ok(())227}228GspSeqCmd::CoreWaitForHalt => {229seq.gsp_falcon.wait_till_halted(seq.bar)?;230Ok(())231}232GspSeqCmd::CoreResume => {233// At this point, 'SEC2-RTOS' has been loaded into SEC2 by the sequencer234// but neither SEC2-RTOS nor GSP-RM is running yet. This part of the235// sequencer will start both.236237// Reset the GSP to prepare it for resuming.238seq.gsp_falcon.reset(seq.bar)?;239240// Write the libOS DMA handle to GSP mailboxes.241seq.gsp_falcon.write_mailboxes(242seq.bar,243Some(seq.libos_dma_handle as u32),244Some((seq.libos_dma_handle >> 32) as u32),245);246247// Start the SEC2 falcon which will trigger GSP-RM to resume on the GSP.248seq.sec2_falcon.start(seq.bar)?;249250// Poll until GSP-RM reload/resume has completed (up to 2 seconds).251seq.gsp_falcon252.check_reload_completed(seq.bar, Delta::from_secs(2))?;253254// Verify SEC2 completed successfully by checking its mailbox for errors.255let mbox0 = seq.sec2_falcon.read_mailbox0(seq.bar);256if mbox0 != 0 {257dev_err!(seq.dev, "Sequencer: sec2 errors: {:?}\n", mbox0);258return Err(EIO);259}260261// Configure GSP with the bootloader version.262seq.gsp_falcon263.write_os_version(seq.bar, seq.bootloader_app_version);264265// Verify the GSP's RISC-V core is active indicating successful GSP boot.266if !seq.gsp_falcon.is_riscv_active(seq.bar) {267dev_err!(seq.dev, "Sequencer: RISC-V core is not active\n");268return Err(EIO);269}270Ok(())271}272}273}274}275276/// Iterator over GSP sequencer commands.277pub(crate) struct GspSeqIter<'a> {278/// Command data buffer.279cmd_data: &'a [u8],280/// Current position in the buffer.281current_offset: usize,282/// Total number of commands to process.283total_cmds: u32,284/// Number of commands processed so far.285cmds_processed: u32,286/// Device for logging.287dev: ARef<device::Device>,288}289290impl<'a> Iterator for GspSeqIter<'a> {291type Item = Result<GspSeqCmd>;292293fn next(&mut self) -> Option<Self::Item> {294// Stop if we've processed all commands or reached the end of data.295if self.cmds_processed >= self.total_cmds || self.current_offset >= self.cmd_data.len() {296return None;297}298299// Check if we have enough data for opcode.300if self.current_offset + core::mem::size_of::<u32>() > self.cmd_data.len() {301return Some(Err(EIO));302}303304let offset = self.current_offset;305306// Handle command creation based on available data,307// zero-pad if necessary (since last command may not be full size).308let mut buffer = [0u8; CMD_SIZE];309let copy_len = if offset + CMD_SIZE <= self.cmd_data.len() {310CMD_SIZE311} else {312self.cmd_data.len() - offset313};314buffer[..copy_len].copy_from_slice(&self.cmd_data[offset..offset + copy_len]);315let cmd_result = GspSeqCmd::new(&buffer, &self.dev);316317cmd_result.map_or_else(318|_err| {319dev_err!(self.dev, "Error parsing command at offset {}\n", offset);320None321},322|(cmd, size)| {323self.current_offset += size;324self.cmds_processed += 1;325Some(Ok(cmd))326},327)328}329}330331impl<'a> GspSequencer<'a> {332fn iter(&self) -> GspSeqIter<'_> {333let cmd_data = &self.seq_info.cmd_data[..];334335GspSeqIter {336cmd_data,337current_offset: 0,338total_cmds: self.seq_info.cmd_index,339cmds_processed: 0,340dev: self.dev.clone(),341}342}343}344345/// Parameters for running the GSP sequencer.346pub(crate) struct GspSequencerParams<'a> {347/// Bootloader application version.348pub(crate) bootloader_app_version: u32,349/// LibOS DMA handle address.350pub(crate) libos_dma_handle: u64,351/// GSP falcon for core operations.352pub(crate) gsp_falcon: &'a Falcon<Gsp>,353/// SEC2 falcon for core operations.354pub(crate) sec2_falcon: &'a Falcon<Sec2>,355/// Device for logging.356pub(crate) dev: ARef<device::Device>,357/// BAR0 for register access.358pub(crate) bar: &'a Bar0,359}360361impl<'a> GspSequencer<'a> {362pub(crate) fn run(cmdq: &mut Cmdq, params: GspSequencerParams<'a>) -> Result {363let seq_info = loop {364match cmdq.receive_msg::<GspSequence>(Delta::from_secs(10)) {365Ok(seq_info) => break seq_info,366Err(ERANGE) => continue,367Err(e) => return Err(e),368}369};370371let sequencer = GspSequencer {372seq_info,373bar: params.bar,374sec2_falcon: params.sec2_falcon,375gsp_falcon: params.gsp_falcon,376libos_dma_handle: params.libos_dma_handle,377bootloader_app_version: params.bootloader_app_version,378dev: params.dev,379};380381dev_dbg!(sequencer.dev, "Running CPU Sequencer commands\n");382383for cmd_result in sequencer.iter() {384match cmd_result {385Ok(cmd) => cmd.run(&sequencer)?,386Err(e) => {387dev_err!(388sequencer.dev,389"Error running command at index {}\n",390sequencer.seq_info.cmd_index391);392return Err(e);393}394}395}396397dev_dbg!(398sequencer.dev,399"CPU Sequencer commands completed successfully\n"400);401Ok(())402}403}404405406