These opcodes are used for register write, modify, poll and store (save) sequencer operations.
Signed-off-by: Joel Fernandes <[email protected]> --- drivers/gpu/nova-core/gsp/fw.rs | 4 - drivers/gpu/nova-core/gsp/sequencer.rs | 120 ++++++++++++++++++++++--- 2 files changed, 109 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 6d58042bc9e8..376c10cc8003 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -389,7 +389,6 @@ fn from(value: SeqBufOpcode) -> Self { #[derive(Copy, Clone)] pub(crate) struct RegWritePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_WRITE); -#[expect(unused)] impl RegWritePayload { /// Returns the register address. pub(crate) fn addr(&self) -> u32 { @@ -413,7 +412,6 @@ unsafe impl AsBytes for RegWritePayload {} #[derive(Copy, Clone)] pub(crate) struct RegModifyPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_MODIFY); -#[expect(unused)] impl RegModifyPayload { /// Returns the register address. pub(crate) fn addr(&self) -> u32 { @@ -442,7 +440,6 @@ unsafe impl AsBytes for RegModifyPayload {} #[derive(Copy, Clone)] pub(crate) struct RegPollPayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_POLL); -#[expect(unused)] impl RegPollPayload { /// Returns the register address. pub(crate) fn addr(&self) -> u32 { @@ -495,7 +492,6 @@ unsafe impl AsBytes for DelayUsPayload {} #[derive(Copy, Clone)] pub(crate) struct RegStorePayload(r570_144::GSP_SEQ_BUF_PAYLOAD_REG_STORE); -#[expect(unused)] impl RegStorePayload { /// Returns the register address. pub(crate) fn addr(&self) -> u32 { diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs index c5ef3a33466a..b564523b64e7 100644 --- a/drivers/gpu/nova-core/gsp/sequencer.rs +++ b/drivers/gpu/nova-core/gsp/sequencer.rs @@ -4,9 +4,13 @@ use core::{ array, - mem::size_of, // + mem::{ + size_of, + size_of_val, // + }, // }; use kernel::device; +use kernel::io::poll::read_poll_timeout; use kernel::prelude::*; use kernel::time::Delta; use kernel::transmute::FromBytes; @@ -56,18 +60,50 @@ struct GspSequencerInfo { /// GSP Sequencer Command types with payload data. /// Commands have an opcode and an opcode-dependent struct. -#[allow(dead_code)] -pub(crate) enum GspSeqCmd {} +#[allow(clippy::enum_variant_names)] +pub(crate) enum GspSeqCmd { + RegWrite(fw::RegWritePayload), + RegModify(fw::RegModifyPayload), + RegPoll(fw::RegPollPayload), + RegStore(fw::RegStorePayload), +} impl GspSeqCmd { /// Creates a new `GspSeqCmd` from raw data returning the command and its size in bytes. - pub(crate) fn new(data: &[u8], _dev: &device::Device) -> Result<(Self, usize)> { - let _fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?; - let _opcode_size = core::mem::size_of::<u32>(); + pub(crate) fn new(data: &[u8], dev: &device::Device) -> Result<(Self, usize)> { + let fw_cmd = fw::SequencerBufferCmd::from_bytes(data).ok_or(EINVAL)?; + let opcode_size = core::mem::size_of::<u32>(); + + let (cmd, size) = match fw_cmd.opcode()? { + fw::SeqBufOpcode::RegWrite => { + let payload = fw_cmd.reg_write_payload()?; + let size = opcode_size + size_of_val(&payload); + (GspSeqCmd::RegWrite(payload), size) + } + fw::SeqBufOpcode::RegModify => { + let payload = fw_cmd.reg_modify_payload()?; + let size = opcode_size + size_of_val(&payload); + (GspSeqCmd::RegModify(payload), size) + } + fw::SeqBufOpcode::RegPoll => { + let payload = fw_cmd.reg_poll_payload()?; + let size = opcode_size + size_of_val(&payload); + (GspSeqCmd::RegPoll(payload), size) + } + fw::SeqBufOpcode::RegStore => { + let payload = fw_cmd.reg_store_payload()?; + let size = opcode_size + size_of_val(&payload); + (GspSeqCmd::RegStore(payload), size) + } + _ => return Err(EINVAL), + }; + + if data.len() < size { + dev_err!(dev, "Data is not enough for command"); + return Err(EINVAL); + } - // NOTE: At this commit, NO opcodes exist yet, so just return error. - // Later commits will add match arms here. - Err(EINVAL) + Ok((cmd, size)) } } @@ -95,12 +131,74 @@ pub(crate) trait GspSeqCmdRunner { fn run(&self, sequencer: &GspSequencer<'_>) -> Result; } -impl GspSeqCmdRunner for GspSeqCmd { - fn run(&self, _seq: &GspSequencer<'_>) -> Result { +impl GspSeqCmdRunner for fw::RegWritePayload { + fn run(&self, sequencer: &GspSequencer<'_>) -> Result { + let addr = self.addr() as usize; + let val = self.val(); + let _ = sequencer.bar.try_write32(val, addr); Ok(()) } } +impl GspSeqCmdRunner for fw::RegModifyPayload { + fn run(&self, sequencer: &GspSequencer<'_>) -> Result { + let addr = self.addr() as usize; + if let Ok(temp) = sequencer.bar.try_read32(addr) { + let _ = sequencer + .bar + .try_write32((temp & !self.mask()) | self.val(), addr); + } + Ok(()) + } +} + +impl GspSeqCmdRunner for fw::RegPollPayload { + fn run(&self, sequencer: &GspSequencer<'_>) -> Result { + let addr = self.addr() as usize; + + // Default timeout to 4 seconds. + let timeout_us = if self.timeout() == 0 { + 4_000_000 + } else { + i64::from(self.timeout()) + }; + + // First read. + sequencer.bar.try_read32(addr)?; + + // Poll the requested register with requested timeout. + read_poll_timeout( + || sequencer.bar.try_read32(addr), + |current| (current & self.mask()) == self.val(), + Delta::ZERO, + Delta::from_micros(timeout_us), + ) + .map(|_| ()) + } +} + +impl GspSeqCmdRunner for fw::RegStorePayload { + fn run(&self, sequencer: &GspSequencer<'_>) -> Result { + let addr = self.addr() as usize; + let _index = self.index(); + + let _val = sequencer.bar.try_read32(addr)?; + + Ok(()) + } +} + +impl GspSeqCmdRunner for GspSeqCmd { + fn run(&self, seq: &GspSequencer<'_>) -> Result { + match self { + GspSeqCmd::RegWrite(cmd) => cmd.run(seq), + GspSeqCmd::RegModify(cmd) => cmd.run(seq), + GspSeqCmd::RegPoll(cmd) => cmd.run(seq), + GspSeqCmd::RegStore(cmd) => cmd.run(seq), + } + } +} + /// Iterator over GSP sequencer commands. pub(crate) struct GspSeqIter<'a> { /// Command data buffer. -- 2.34.1
