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