169f5cd67SAlexandre Courbot // SPDX-License-Identifier: GPL-2.0 269f5cd67SAlexandre Courbot 369f5cd67SAlexandre Courbot //! Falcon microprocessor base support 469f5cd67SAlexandre Courbot 569f5cd67SAlexandre Courbot use core::ops::Deref; 669f5cd67SAlexandre Courbot use hal::FalconHal; 769f5cd67SAlexandre Courbot use kernel::bindings; 869f5cd67SAlexandre Courbot use kernel::device; 969f5cd67SAlexandre Courbot use kernel::prelude::*; 10*4092e1b4SAlexandre Courbot use kernel::time::Delta; 1169f5cd67SAlexandre Courbot use kernel::types::ARef; 1269f5cd67SAlexandre Courbot 1369f5cd67SAlexandre Courbot use crate::dma::DmaObject; 1469f5cd67SAlexandre Courbot use crate::driver::Bar0; 1569f5cd67SAlexandre Courbot use crate::gpu::Chipset; 1669f5cd67SAlexandre Courbot use crate::regs; 1769f5cd67SAlexandre Courbot use crate::util; 1869f5cd67SAlexandre Courbot 1969f5cd67SAlexandre Courbot pub(crate) mod gsp; 2069f5cd67SAlexandre Courbot mod hal; 2169f5cd67SAlexandre Courbot pub(crate) mod sec2; 2269f5cd67SAlexandre Courbot 231b8233bbSDanilo Krummrich // TODO[FPRI]: Replace with `ToPrimitive`. 241b8233bbSDanilo Krummrich macro_rules! impl_from_enum_to_u32 { 251b8233bbSDanilo Krummrich ($enum_type:ty) => { 261b8233bbSDanilo Krummrich impl From<$enum_type> for u32 { 271b8233bbSDanilo Krummrich fn from(value: $enum_type) -> Self { 281b8233bbSDanilo Krummrich value as u32 291b8233bbSDanilo Krummrich } 301b8233bbSDanilo Krummrich } 311b8233bbSDanilo Krummrich }; 321b8233bbSDanilo Krummrich } 331b8233bbSDanilo Krummrich 3469f5cd67SAlexandre Courbot /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 3569f5cd67SAlexandre Courbot /// register. 3669f5cd67SAlexandre Courbot #[repr(u8)] 3769f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 3869f5cd67SAlexandre Courbot pub(crate) enum FalconCoreRev { 3969f5cd67SAlexandre Courbot #[default] 4069f5cd67SAlexandre Courbot Rev1 = 1, 4169f5cd67SAlexandre Courbot Rev2 = 2, 4269f5cd67SAlexandre Courbot Rev3 = 3, 4369f5cd67SAlexandre Courbot Rev4 = 4, 4469f5cd67SAlexandre Courbot Rev5 = 5, 4569f5cd67SAlexandre Courbot Rev6 = 6, 4669f5cd67SAlexandre Courbot Rev7 = 7, 4769f5cd67SAlexandre Courbot } 481b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconCoreRev); 4969f5cd67SAlexandre Courbot 503606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 5169f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconCoreRev { 5269f5cd67SAlexandre Courbot type Error = Error; 5369f5cd67SAlexandre Courbot 5469f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 5569f5cd67SAlexandre Courbot use FalconCoreRev::*; 5669f5cd67SAlexandre Courbot 5769f5cd67SAlexandre Courbot let rev = match value { 5869f5cd67SAlexandre Courbot 1 => Rev1, 5969f5cd67SAlexandre Courbot 2 => Rev2, 6069f5cd67SAlexandre Courbot 3 => Rev3, 6169f5cd67SAlexandre Courbot 4 => Rev4, 6269f5cd67SAlexandre Courbot 5 => Rev5, 6369f5cd67SAlexandre Courbot 6 => Rev6, 6469f5cd67SAlexandre Courbot 7 => Rev7, 6569f5cd67SAlexandre Courbot _ => return Err(EINVAL), 6669f5cd67SAlexandre Courbot }; 6769f5cd67SAlexandre Courbot 6869f5cd67SAlexandre Courbot Ok(rev) 6969f5cd67SAlexandre Courbot } 7069f5cd67SAlexandre Courbot } 7169f5cd67SAlexandre Courbot 7269f5cd67SAlexandre Courbot /// Revision subversion number of a falcon core, used in the 7369f5cd67SAlexandre Courbot /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. 7469f5cd67SAlexandre Courbot #[repr(u8)] 7569f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 7669f5cd67SAlexandre Courbot pub(crate) enum FalconCoreRevSubversion { 7769f5cd67SAlexandre Courbot #[default] 7869f5cd67SAlexandre Courbot Subversion0 = 0, 7969f5cd67SAlexandre Courbot Subversion1 = 1, 8069f5cd67SAlexandre Courbot Subversion2 = 2, 8169f5cd67SAlexandre Courbot Subversion3 = 3, 8269f5cd67SAlexandre Courbot } 831b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconCoreRevSubversion); 8469f5cd67SAlexandre Courbot 853606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 8669f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconCoreRevSubversion { 8769f5cd67SAlexandre Courbot type Error = Error; 8869f5cd67SAlexandre Courbot 8969f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 9069f5cd67SAlexandre Courbot use FalconCoreRevSubversion::*; 9169f5cd67SAlexandre Courbot 9269f5cd67SAlexandre Courbot let sub_version = match value & 0b11 { 9369f5cd67SAlexandre Courbot 0 => Subversion0, 9469f5cd67SAlexandre Courbot 1 => Subversion1, 9569f5cd67SAlexandre Courbot 2 => Subversion2, 9669f5cd67SAlexandre Courbot 3 => Subversion3, 9769f5cd67SAlexandre Courbot _ => return Err(EINVAL), 9869f5cd67SAlexandre Courbot }; 9969f5cd67SAlexandre Courbot 10069f5cd67SAlexandre Courbot Ok(sub_version) 10169f5cd67SAlexandre Courbot } 10269f5cd67SAlexandre Courbot } 10369f5cd67SAlexandre Courbot 10469f5cd67SAlexandre Courbot /// Security model of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 10569f5cd67SAlexandre Courbot /// register. 10669f5cd67SAlexandre Courbot #[repr(u8)] 10769f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone)] 10869f5cd67SAlexandre Courbot pub(crate) enum FalconSecurityModel { 10969f5cd67SAlexandre Courbot /// Non-Secure: runs unsigned code without privileges. 11069f5cd67SAlexandre Courbot #[default] 11169f5cd67SAlexandre Courbot None = 0, 11269f5cd67SAlexandre Courbot /// Low-Secure: runs code with some privileges. Can only be entered from `Heavy` mode, which 11369f5cd67SAlexandre Courbot /// will typically validate the LS code through some signature. 11469f5cd67SAlexandre Courbot Light = 2, 11569f5cd67SAlexandre Courbot /// High-Secure: runs signed code with full privileges. Signature is validated by boot ROM. 11669f5cd67SAlexandre Courbot Heavy = 3, 11769f5cd67SAlexandre Courbot } 1181b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconSecurityModel); 11969f5cd67SAlexandre Courbot 1203606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 12169f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconSecurityModel { 12269f5cd67SAlexandre Courbot type Error = Error; 12369f5cd67SAlexandre Courbot 12469f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 12569f5cd67SAlexandre Courbot use FalconSecurityModel::*; 12669f5cd67SAlexandre Courbot 12769f5cd67SAlexandre Courbot let sec_model = match value { 12869f5cd67SAlexandre Courbot 0 => None, 12969f5cd67SAlexandre Courbot 2 => Light, 13069f5cd67SAlexandre Courbot 3 => Heavy, 13169f5cd67SAlexandre Courbot _ => return Err(EINVAL), 13269f5cd67SAlexandre Courbot }; 13369f5cd67SAlexandre Courbot 13469f5cd67SAlexandre Courbot Ok(sec_model) 13569f5cd67SAlexandre Courbot } 13669f5cd67SAlexandre Courbot } 13769f5cd67SAlexandre Courbot 13869f5cd67SAlexandre Courbot /// Signing algorithm for a given firmware, used in the [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] 13969f5cd67SAlexandre Courbot /// register. 14069f5cd67SAlexandre Courbot #[repr(u8)] 14169f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 14269f5cd67SAlexandre Courbot pub(crate) enum FalconModSelAlgo { 14369f5cd67SAlexandre Courbot /// RSA3K. 14469f5cd67SAlexandre Courbot #[default] 14569f5cd67SAlexandre Courbot Rsa3k = 1, 14669f5cd67SAlexandre Courbot } 1471b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconModSelAlgo); 14869f5cd67SAlexandre Courbot 1493606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 15069f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconModSelAlgo { 15169f5cd67SAlexandre Courbot type Error = Error; 15269f5cd67SAlexandre Courbot 15369f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 15469f5cd67SAlexandre Courbot match value { 15569f5cd67SAlexandre Courbot 1 => Ok(FalconModSelAlgo::Rsa3k), 15669f5cd67SAlexandre Courbot _ => Err(EINVAL), 15769f5cd67SAlexandre Courbot } 15869f5cd67SAlexandre Courbot } 15969f5cd67SAlexandre Courbot } 16069f5cd67SAlexandre Courbot 16169f5cd67SAlexandre Courbot /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register. 16269f5cd67SAlexandre Courbot #[repr(u8)] 16369f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 16469f5cd67SAlexandre Courbot pub(crate) enum DmaTrfCmdSize { 16569f5cd67SAlexandre Courbot /// 256 bytes transfer. 16669f5cd67SAlexandre Courbot #[default] 16769f5cd67SAlexandre Courbot Size256B = 0x6, 16869f5cd67SAlexandre Courbot } 1691b8233bbSDanilo Krummrich impl_from_enum_to_u32!(DmaTrfCmdSize); 17069f5cd67SAlexandre Courbot 1713606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 17269f5cd67SAlexandre Courbot impl TryFrom<u8> for DmaTrfCmdSize { 17369f5cd67SAlexandre Courbot type Error = Error; 17469f5cd67SAlexandre Courbot 17569f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 17669f5cd67SAlexandre Courbot match value { 17769f5cd67SAlexandre Courbot 0x6 => Ok(Self::Size256B), 17869f5cd67SAlexandre Courbot _ => Err(EINVAL), 17969f5cd67SAlexandre Courbot } 18069f5cd67SAlexandre Courbot } 18169f5cd67SAlexandre Courbot } 18269f5cd67SAlexandre Courbot 18369f5cd67SAlexandre Courbot /// Currently active core on a dual falcon/riscv (Peregrine) controller. 18469f5cd67SAlexandre Courbot #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 18569f5cd67SAlexandre Courbot pub(crate) enum PeregrineCoreSelect { 18669f5cd67SAlexandre Courbot /// Falcon core is active. 18769f5cd67SAlexandre Courbot #[default] 18869f5cd67SAlexandre Courbot Falcon = 0, 18969f5cd67SAlexandre Courbot /// RISC-V core is active. 19069f5cd67SAlexandre Courbot Riscv = 1, 19169f5cd67SAlexandre Courbot } 1921b8233bbSDanilo Krummrich impl_from_enum_to_u32!(PeregrineCoreSelect); 19369f5cd67SAlexandre Courbot 19469f5cd67SAlexandre Courbot impl From<bool> for PeregrineCoreSelect { 19569f5cd67SAlexandre Courbot fn from(value: bool) -> Self { 19669f5cd67SAlexandre Courbot match value { 19769f5cd67SAlexandre Courbot false => PeregrineCoreSelect::Falcon, 19869f5cd67SAlexandre Courbot true => PeregrineCoreSelect::Riscv, 19969f5cd67SAlexandre Courbot } 20069f5cd67SAlexandre Courbot } 20169f5cd67SAlexandre Courbot } 20269f5cd67SAlexandre Courbot 20369f5cd67SAlexandre Courbot /// Different types of memory present in a falcon core. 20469f5cd67SAlexandre Courbot #[derive(Debug, Clone, Copy, PartialEq, Eq)] 20569f5cd67SAlexandre Courbot pub(crate) enum FalconMem { 20669f5cd67SAlexandre Courbot /// Instruction Memory. 20769f5cd67SAlexandre Courbot Imem, 20869f5cd67SAlexandre Courbot /// Data Memory. 20969f5cd67SAlexandre Courbot Dmem, 21069f5cd67SAlexandre Courbot } 21169f5cd67SAlexandre Courbot 21269f5cd67SAlexandre Courbot /// Target/source of a DMA transfer to/from falcon memory. 21369f5cd67SAlexandre Courbot #[derive(Debug, Clone, Default)] 21469f5cd67SAlexandre Courbot pub(crate) enum FalconFbifTarget { 21569f5cd67SAlexandre Courbot /// VRAM. 21669f5cd67SAlexandre Courbot #[default] 21769f5cd67SAlexandre Courbot LocalFb = 0, 21869f5cd67SAlexandre Courbot /// Coherent system memory. 21969f5cd67SAlexandre Courbot CoherentSysmem = 1, 22069f5cd67SAlexandre Courbot /// Non-coherent system memory. 22169f5cd67SAlexandre Courbot NoncoherentSysmem = 2, 22269f5cd67SAlexandre Courbot } 2231b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconFbifTarget); 22469f5cd67SAlexandre Courbot 2253606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 22669f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconFbifTarget { 22769f5cd67SAlexandre Courbot type Error = Error; 22869f5cd67SAlexandre Courbot 22969f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 23069f5cd67SAlexandre Courbot let res = match value { 23169f5cd67SAlexandre Courbot 0 => Self::LocalFb, 23269f5cd67SAlexandre Courbot 1 => Self::CoherentSysmem, 23369f5cd67SAlexandre Courbot 2 => Self::NoncoherentSysmem, 23469f5cd67SAlexandre Courbot _ => return Err(EINVAL), 23569f5cd67SAlexandre Courbot }; 23669f5cd67SAlexandre Courbot 23769f5cd67SAlexandre Courbot Ok(res) 23869f5cd67SAlexandre Courbot } 23969f5cd67SAlexandre Courbot } 24069f5cd67SAlexandre Courbot 24169f5cd67SAlexandre Courbot /// Type of memory addresses to use. 24269f5cd67SAlexandre Courbot #[derive(Debug, Clone, Default)] 24369f5cd67SAlexandre Courbot pub(crate) enum FalconFbifMemType { 24469f5cd67SAlexandre Courbot /// Virtual memory addresses. 24569f5cd67SAlexandre Courbot #[default] 24669f5cd67SAlexandre Courbot Virtual = 0, 24769f5cd67SAlexandre Courbot /// Physical memory addresses. 24869f5cd67SAlexandre Courbot Physical = 1, 24969f5cd67SAlexandre Courbot } 2501b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconFbifMemType); 25169f5cd67SAlexandre Courbot 25269f5cd67SAlexandre Courbot /// Conversion from a single-bit register field. 25369f5cd67SAlexandre Courbot impl From<bool> for FalconFbifMemType { 25469f5cd67SAlexandre Courbot fn from(value: bool) -> Self { 25569f5cd67SAlexandre Courbot match value { 25669f5cd67SAlexandre Courbot false => Self::Virtual, 25769f5cd67SAlexandre Courbot true => Self::Physical, 25869f5cd67SAlexandre Courbot } 25969f5cd67SAlexandre Courbot } 26069f5cd67SAlexandre Courbot } 26169f5cd67SAlexandre Courbot 26269f5cd67SAlexandre Courbot /// Trait defining the parameters of a given Falcon instance. 26369f5cd67SAlexandre Courbot pub(crate) trait FalconEngine: Sync { 26469f5cd67SAlexandre Courbot /// Base I/O address for the falcon, relative from which its registers are accessed. 26569f5cd67SAlexandre Courbot const BASE: usize; 26669f5cd67SAlexandre Courbot } 26769f5cd67SAlexandre Courbot 26869f5cd67SAlexandre Courbot /// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). 26969f5cd67SAlexandre Courbot #[derive(Debug)] 27069f5cd67SAlexandre Courbot pub(crate) struct FalconLoadTarget { 27169f5cd67SAlexandre Courbot /// Offset from the start of the source object to copy from. 27269f5cd67SAlexandre Courbot pub(crate) src_start: u32, 27369f5cd67SAlexandre Courbot /// Offset from the start of the destination memory to copy into. 27469f5cd67SAlexandre Courbot pub(crate) dst_start: u32, 27569f5cd67SAlexandre Courbot /// Number of bytes to copy. 27669f5cd67SAlexandre Courbot pub(crate) len: u32, 27769f5cd67SAlexandre Courbot } 27869f5cd67SAlexandre Courbot 27969f5cd67SAlexandre Courbot /// Parameters for the falcon boot ROM. 28069f5cd67SAlexandre Courbot #[derive(Debug)] 28169f5cd67SAlexandre Courbot pub(crate) struct FalconBromParams { 28269f5cd67SAlexandre Courbot /// Offset in `DMEM`` of the firmware's signature. 28369f5cd67SAlexandre Courbot pub(crate) pkc_data_offset: u32, 28469f5cd67SAlexandre Courbot /// Mask of engines valid for this firmware. 28569f5cd67SAlexandre Courbot pub(crate) engine_id_mask: u16, 28669f5cd67SAlexandre Courbot /// ID of the ucode used to infer a fuse register to validate the signature. 28769f5cd67SAlexandre Courbot pub(crate) ucode_id: u8, 28869f5cd67SAlexandre Courbot } 28969f5cd67SAlexandre Courbot 29069f5cd67SAlexandre Courbot /// Trait for providing load parameters of falcon firmwares. 29169f5cd67SAlexandre Courbot pub(crate) trait FalconLoadParams { 29269f5cd67SAlexandre Courbot /// Returns the load parameters for `IMEM`. 29369f5cd67SAlexandre Courbot fn imem_load_params(&self) -> FalconLoadTarget; 29469f5cd67SAlexandre Courbot 29569f5cd67SAlexandre Courbot /// Returns the load parameters for `DMEM`. 29669f5cd67SAlexandre Courbot fn dmem_load_params(&self) -> FalconLoadTarget; 29769f5cd67SAlexandre Courbot 29869f5cd67SAlexandre Courbot /// Returns the parameters to write into the BROM registers. 29969f5cd67SAlexandre Courbot fn brom_params(&self) -> FalconBromParams; 30069f5cd67SAlexandre Courbot 30169f5cd67SAlexandre Courbot /// Returns the start address of the firmware. 30269f5cd67SAlexandre Courbot fn boot_addr(&self) -> u32; 30369f5cd67SAlexandre Courbot } 30469f5cd67SAlexandre Courbot 30569f5cd67SAlexandre Courbot /// Trait for a falcon firmware. 30669f5cd67SAlexandre Courbot /// 30769f5cd67SAlexandre Courbot /// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA 30869f5cd67SAlexandre Courbot /// object. 30969f5cd67SAlexandre Courbot pub(crate) trait FalconFirmware: FalconLoadParams + Deref<Target = DmaObject> { 31069f5cd67SAlexandre Courbot /// Engine on which this firmware is to be loaded. 31169f5cd67SAlexandre Courbot type Target: FalconEngine; 31269f5cd67SAlexandre Courbot } 31369f5cd67SAlexandre Courbot 31469f5cd67SAlexandre Courbot /// Contains the base parameters common to all Falcon instances. 31569f5cd67SAlexandre Courbot pub(crate) struct Falcon<E: FalconEngine> { 31669f5cd67SAlexandre Courbot hal: KBox<dyn FalconHal<E>>, 31769f5cd67SAlexandre Courbot dev: ARef<device::Device>, 31869f5cd67SAlexandre Courbot } 31969f5cd67SAlexandre Courbot 32069f5cd67SAlexandre Courbot impl<E: FalconEngine + 'static> Falcon<E> { 32169f5cd67SAlexandre Courbot /// Create a new falcon instance. 32269f5cd67SAlexandre Courbot /// 32369f5cd67SAlexandre Courbot /// `need_riscv` is set to `true` if the caller expects the falcon to be a dual falcon/riscv 32469f5cd67SAlexandre Courbot /// controller. 32569f5cd67SAlexandre Courbot pub(crate) fn new( 32669f5cd67SAlexandre Courbot dev: &device::Device, 32769f5cd67SAlexandre Courbot chipset: Chipset, 32869f5cd67SAlexandre Courbot bar: &Bar0, 32969f5cd67SAlexandre Courbot need_riscv: bool, 33069f5cd67SAlexandre Courbot ) -> Result<Self> { 33169f5cd67SAlexandre Courbot let hwcfg1 = regs::NV_PFALCON_FALCON_HWCFG1::read(bar, E::BASE); 33269f5cd67SAlexandre Courbot // Check that the revision and security model contain valid values. 33369f5cd67SAlexandre Courbot let _ = hwcfg1.core_rev()?; 33469f5cd67SAlexandre Courbot let _ = hwcfg1.security_model()?; 33569f5cd67SAlexandre Courbot 33669f5cd67SAlexandre Courbot if need_riscv { 33769f5cd67SAlexandre Courbot let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 33869f5cd67SAlexandre Courbot if !hwcfg2.riscv() { 33969f5cd67SAlexandre Courbot dev_err!( 34069f5cd67SAlexandre Courbot dev, 34169f5cd67SAlexandre Courbot "riscv support requested on a controller that does not support it\n" 34269f5cd67SAlexandre Courbot ); 34369f5cd67SAlexandre Courbot return Err(EINVAL); 34469f5cd67SAlexandre Courbot } 34569f5cd67SAlexandre Courbot } 34669f5cd67SAlexandre Courbot 34769f5cd67SAlexandre Courbot Ok(Self { 34869f5cd67SAlexandre Courbot hal: hal::falcon_hal(chipset)?, 34969f5cd67SAlexandre Courbot dev: dev.into(), 35069f5cd67SAlexandre Courbot }) 35169f5cd67SAlexandre Courbot } 35269f5cd67SAlexandre Courbot 35369f5cd67SAlexandre Courbot /// Wait for memory scrubbing to complete. 35469f5cd67SAlexandre Courbot fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 35569f5cd67SAlexandre Courbot // TIMEOUT: memory scrubbing should complete in less than 20ms. 356*4092e1b4SAlexandre Courbot util::wait_on(Delta::from_millis(20), || { 35769f5cd67SAlexandre Courbot if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE).mem_scrubbing_done() { 35869f5cd67SAlexandre Courbot Some(()) 35969f5cd67SAlexandre Courbot } else { 36069f5cd67SAlexandre Courbot None 36169f5cd67SAlexandre Courbot } 36269f5cd67SAlexandre Courbot }) 36369f5cd67SAlexandre Courbot } 36469f5cd67SAlexandre Courbot 36569f5cd67SAlexandre Courbot /// Reset the falcon engine. 36669f5cd67SAlexandre Courbot fn reset_eng(&self, bar: &Bar0) -> Result { 36769f5cd67SAlexandre Courbot let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 36869f5cd67SAlexandre Courbot 36969f5cd67SAlexandre Courbot // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 37069f5cd67SAlexandre Courbot // RESET_READY so a non-failing timeout is used. 371*4092e1b4SAlexandre Courbot let _ = util::wait_on(Delta::from_micros(150), || { 37269f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 37369f5cd67SAlexandre Courbot if r.reset_ready() { 37469f5cd67SAlexandre Courbot Some(()) 37569f5cd67SAlexandre Courbot } else { 37669f5cd67SAlexandre Courbot None 37769f5cd67SAlexandre Courbot } 37869f5cd67SAlexandre Courbot }); 37969f5cd67SAlexandre Courbot 38069f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(true)); 38169f5cd67SAlexandre Courbot 3823606620bSAlexandre Courbot // TODO[DLAY]: replace with udelay() or equivalent once available. 38369f5cd67SAlexandre Courbot // TIMEOUT: falcon engine should not take more than 10us to reset. 384*4092e1b4SAlexandre Courbot let _: Result = util::wait_on(Delta::from_micros(10), || None); 38569f5cd67SAlexandre Courbot 38669f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(false)); 38769f5cd67SAlexandre Courbot 38869f5cd67SAlexandre Courbot self.reset_wait_mem_scrubbing(bar)?; 38969f5cd67SAlexandre Courbot 39069f5cd67SAlexandre Courbot Ok(()) 39169f5cd67SAlexandre Courbot } 39269f5cd67SAlexandre Courbot 39369f5cd67SAlexandre Courbot /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete. 39469f5cd67SAlexandre Courbot pub(crate) fn reset(&self, bar: &Bar0) -> Result { 39569f5cd67SAlexandre Courbot self.reset_eng(bar)?; 39669f5cd67SAlexandre Courbot self.hal.select_core(self, bar)?; 39769f5cd67SAlexandre Courbot self.reset_wait_mem_scrubbing(bar)?; 39869f5cd67SAlexandre Courbot 39969f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_RM::default() 40069f5cd67SAlexandre Courbot .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) 40169f5cd67SAlexandre Courbot .write(bar, E::BASE); 40269f5cd67SAlexandre Courbot 40369f5cd67SAlexandre Courbot Ok(()) 40469f5cd67SAlexandre Courbot } 40569f5cd67SAlexandre Courbot 40669f5cd67SAlexandre Courbot /// Perform a DMA write according to `load_offsets` from `dma_handle` into the falcon's 40769f5cd67SAlexandre Courbot /// `target_mem`. 40869f5cd67SAlexandre Courbot /// 40969f5cd67SAlexandre Courbot /// `sec` is set if the loaded firmware is expected to run in secure mode. 41069f5cd67SAlexandre Courbot fn dma_wr<F: FalconFirmware<Target = E>>( 41169f5cd67SAlexandre Courbot &self, 41269f5cd67SAlexandre Courbot bar: &Bar0, 41369f5cd67SAlexandre Courbot fw: &F, 41469f5cd67SAlexandre Courbot target_mem: FalconMem, 41569f5cd67SAlexandre Courbot load_offsets: FalconLoadTarget, 41669f5cd67SAlexandre Courbot sec: bool, 41769f5cd67SAlexandre Courbot ) -> Result { 41869f5cd67SAlexandre Courbot const DMA_LEN: u32 = 256; 41969f5cd67SAlexandre Courbot 42069f5cd67SAlexandre Courbot // For IMEM, we want to use the start offset as a virtual address tag for each page, since 42169f5cd67SAlexandre Courbot // code addresses in the firmware (and the boot vector) are virtual. 42269f5cd67SAlexandre Courbot // 42369f5cd67SAlexandre Courbot // For DMEM we can fold the start offset into the DMA handle. 42469f5cd67SAlexandre Courbot let (src_start, dma_start) = match target_mem { 42569f5cd67SAlexandre Courbot FalconMem::Imem => (load_offsets.src_start, fw.dma_handle()), 42669f5cd67SAlexandre Courbot FalconMem::Dmem => ( 42769f5cd67SAlexandre Courbot 0, 42869f5cd67SAlexandre Courbot fw.dma_handle_with_offset(load_offsets.src_start as usize)?, 42969f5cd67SAlexandre Courbot ), 43069f5cd67SAlexandre Courbot }; 43143ad65ecSDanilo Krummrich if dma_start % bindings::dma_addr_t::from(DMA_LEN) > 0 { 43269f5cd67SAlexandre Courbot dev_err!( 43369f5cd67SAlexandre Courbot self.dev, 43469f5cd67SAlexandre Courbot "DMA transfer start addresses must be a multiple of {}", 43569f5cd67SAlexandre Courbot DMA_LEN 43669f5cd67SAlexandre Courbot ); 43769f5cd67SAlexandre Courbot return Err(EINVAL); 43869f5cd67SAlexandre Courbot } 43969f5cd67SAlexandre Courbot if load_offsets.len % DMA_LEN > 0 { 44069f5cd67SAlexandre Courbot dev_err!( 44169f5cd67SAlexandre Courbot self.dev, 44269f5cd67SAlexandre Courbot "DMA transfer length must be a multiple of {}", 44369f5cd67SAlexandre Courbot DMA_LEN 44469f5cd67SAlexandre Courbot ); 44569f5cd67SAlexandre Courbot return Err(EINVAL); 44669f5cd67SAlexandre Courbot } 44769f5cd67SAlexandre Courbot 44869f5cd67SAlexandre Courbot // Set up the base source DMA address. 44969f5cd67SAlexandre Courbot 45069f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFBASE::default() 45169f5cd67SAlexandre Courbot .set_base((dma_start >> 8) as u32) 45269f5cd67SAlexandre Courbot .write(bar, E::BASE); 45369f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFBASE1::default() 45469f5cd67SAlexandre Courbot .set_base((dma_start >> 40) as u16) 45569f5cd67SAlexandre Courbot .write(bar, E::BASE); 45669f5cd67SAlexandre Courbot 45769f5cd67SAlexandre Courbot let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() 45869f5cd67SAlexandre Courbot .set_size(DmaTrfCmdSize::Size256B) 45969f5cd67SAlexandre Courbot .set_imem(target_mem == FalconMem::Imem) 46069f5cd67SAlexandre Courbot .set_sec(if sec { 1 } else { 0 }); 46169f5cd67SAlexandre Courbot 46269f5cd67SAlexandre Courbot for pos in (0..load_offsets.len).step_by(DMA_LEN as usize) { 46369f5cd67SAlexandre Courbot // Perform a transfer of size `DMA_LEN`. 46469f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() 46569f5cd67SAlexandre Courbot .set_offs(load_offsets.dst_start + pos) 46669f5cd67SAlexandre Courbot .write(bar, E::BASE); 46769f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() 46869f5cd67SAlexandre Courbot .set_offs(src_start + pos) 46969f5cd67SAlexandre Courbot .write(bar, E::BASE); 47069f5cd67SAlexandre Courbot cmd.write(bar, E::BASE); 47169f5cd67SAlexandre Courbot 47269f5cd67SAlexandre Courbot // Wait for the transfer to complete. 47369f5cd67SAlexandre Courbot // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories 47469f5cd67SAlexandre Courbot // should ever take that long. 475*4092e1b4SAlexandre Courbot util::wait_on(Delta::from_secs(2), || { 47669f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, E::BASE); 47769f5cd67SAlexandre Courbot if r.idle() { 47869f5cd67SAlexandre Courbot Some(()) 47969f5cd67SAlexandre Courbot } else { 48069f5cd67SAlexandre Courbot None 48169f5cd67SAlexandre Courbot } 48269f5cd67SAlexandre Courbot })?; 48369f5cd67SAlexandre Courbot } 48469f5cd67SAlexandre Courbot 48569f5cd67SAlexandre Courbot Ok(()) 48669f5cd67SAlexandre Courbot } 48769f5cd67SAlexandre Courbot 48869f5cd67SAlexandre Courbot /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. 48969f5cd67SAlexandre Courbot pub(crate) fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result { 49069f5cd67SAlexandre Courbot regs::NV_PFALCON_FBIF_CTL::alter(bar, E::BASE, |v| v.set_allow_phys_no_ctx(true)); 49169f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, E::BASE); 49269f5cd67SAlexandre Courbot regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, E::BASE, |v| { 49369f5cd67SAlexandre Courbot v.set_target(FalconFbifTarget::CoherentSysmem) 49469f5cd67SAlexandre Courbot .set_mem_type(FalconFbifMemType::Physical) 49569f5cd67SAlexandre Courbot }); 49669f5cd67SAlexandre Courbot 49769f5cd67SAlexandre Courbot self.dma_wr(bar, fw, FalconMem::Imem, fw.imem_load_params(), true)?; 49869f5cd67SAlexandre Courbot self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params(), true)?; 49969f5cd67SAlexandre Courbot 50069f5cd67SAlexandre Courbot self.hal.program_brom(self, bar, &fw.brom_params())?; 50169f5cd67SAlexandre Courbot 50269f5cd67SAlexandre Courbot // Set `BootVec` to start of non-secure code. 50369f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_BOOTVEC::default() 50469f5cd67SAlexandre Courbot .set_value(fw.boot_addr()) 50569f5cd67SAlexandre Courbot .write(bar, E::BASE); 50669f5cd67SAlexandre Courbot 50769f5cd67SAlexandre Courbot Ok(()) 50869f5cd67SAlexandre Courbot } 50969f5cd67SAlexandre Courbot 51069f5cd67SAlexandre Courbot /// Runs the loaded firmware and waits for its completion. 51169f5cd67SAlexandre Courbot /// 51269f5cd67SAlexandre Courbot /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers 51369f5cd67SAlexandre Courbot /// prior to running. 51469f5cd67SAlexandre Courbot /// 51569f5cd67SAlexandre Courbot /// Wait up to two seconds for the firmware to complete, and return its exit status read from 51669f5cd67SAlexandre Courbot /// the `MBOX0` and `MBOX1` registers. 51769f5cd67SAlexandre Courbot pub(crate) fn boot( 51869f5cd67SAlexandre Courbot &self, 51969f5cd67SAlexandre Courbot bar: &Bar0, 52069f5cd67SAlexandre Courbot mbox0: Option<u32>, 52169f5cd67SAlexandre Courbot mbox1: Option<u32>, 52269f5cd67SAlexandre Courbot ) -> Result<(u32, u32)> { 52369f5cd67SAlexandre Courbot if let Some(mbox0) = mbox0 { 52469f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX0::default() 52569f5cd67SAlexandre Courbot .set_value(mbox0) 52669f5cd67SAlexandre Courbot .write(bar, E::BASE); 52769f5cd67SAlexandre Courbot } 52869f5cd67SAlexandre Courbot 52969f5cd67SAlexandre Courbot if let Some(mbox1) = mbox1 { 53069f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX1::default() 53169f5cd67SAlexandre Courbot .set_value(mbox1) 53269f5cd67SAlexandre Courbot .write(bar, E::BASE); 53369f5cd67SAlexandre Courbot } 53469f5cd67SAlexandre Courbot 53569f5cd67SAlexandre Courbot match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE).alias_en() { 53669f5cd67SAlexandre Courbot true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() 53769f5cd67SAlexandre Courbot .set_startcpu(true) 53869f5cd67SAlexandre Courbot .write(bar, E::BASE), 53969f5cd67SAlexandre Courbot false => regs::NV_PFALCON_FALCON_CPUCTL::default() 54069f5cd67SAlexandre Courbot .set_startcpu(true) 54169f5cd67SAlexandre Courbot .write(bar, E::BASE), 54269f5cd67SAlexandre Courbot } 54369f5cd67SAlexandre Courbot 54469f5cd67SAlexandre Courbot // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. 545*4092e1b4SAlexandre Courbot util::wait_on(Delta::from_secs(2), || { 54669f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE); 54769f5cd67SAlexandre Courbot if r.halted() { 54869f5cd67SAlexandre Courbot Some(()) 54969f5cd67SAlexandre Courbot } else { 55069f5cd67SAlexandre Courbot None 55169f5cd67SAlexandre Courbot } 55269f5cd67SAlexandre Courbot })?; 55369f5cd67SAlexandre Courbot 55469f5cd67SAlexandre Courbot let (mbox0, mbox1) = ( 55569f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, E::BASE).value(), 55669f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, E::BASE).value(), 55769f5cd67SAlexandre Courbot ); 55869f5cd67SAlexandre Courbot 55969f5cd67SAlexandre Courbot Ok((mbox0, mbox1)) 56069f5cd67SAlexandre Courbot } 56169f5cd67SAlexandre Courbot 56269f5cd67SAlexandre Courbot /// Returns the fused version of the signature to use in order to run a HS firmware on this 56369f5cd67SAlexandre Courbot /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header. 56469f5cd67SAlexandre Courbot pub(crate) fn signature_reg_fuse_version( 56569f5cd67SAlexandre Courbot &self, 56669f5cd67SAlexandre Courbot bar: &Bar0, 56769f5cd67SAlexandre Courbot engine_id_mask: u16, 56869f5cd67SAlexandre Courbot ucode_id: u8, 56969f5cd67SAlexandre Courbot ) -> Result<u32> { 57069f5cd67SAlexandre Courbot self.hal 57169f5cd67SAlexandre Courbot .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id) 57269f5cd67SAlexandre Courbot } 57369f5cd67SAlexandre Courbot } 574