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::*; 104092e1b4SAlexandre 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 try_from(value: u8) -> Result<Self>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 try_from(value: u8) -> Result<Self>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)] 108*0b980688SJoel Fernandes /// Security mode of the Falcon microprocessor. 109*0b980688SJoel Fernandes /// 110*0b980688SJoel Fernandes /// See `falcon.rst` for more details. 11169f5cd67SAlexandre Courbot pub(crate) enum FalconSecurityModel { 11269f5cd67SAlexandre Courbot /// Non-Secure: runs unsigned code without privileges. 11369f5cd67SAlexandre Courbot #[default] 11469f5cd67SAlexandre Courbot None = 0, 115*0b980688SJoel Fernandes /// Light-Secured (LS): Runs signed code with some privileges. 116*0b980688SJoel Fernandes /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the code's 117*0b980688SJoel Fernandes /// signature. 118*0b980688SJoel Fernandes /// 119*0b980688SJoel Fernandes /// Also known as Low-Secure, Privilege Level 2 or PL2. 12069f5cd67SAlexandre Courbot Light = 2, 121*0b980688SJoel Fernandes /// Heavy-Secured (HS): Runs signed code with full privileges. 122*0b980688SJoel Fernandes /// The code's signature is verified by the Falcon Boot ROM (BROM). 123*0b980688SJoel Fernandes /// 124*0b980688SJoel Fernandes /// Also known as High-Secure, Privilege Level 3 or PL3. 12569f5cd67SAlexandre Courbot Heavy = 3, 12669f5cd67SAlexandre Courbot } 1271b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconSecurityModel); 12869f5cd67SAlexandre Courbot 1293606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 13069f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconSecurityModel { 13169f5cd67SAlexandre Courbot type Error = Error; 13269f5cd67SAlexandre Courbot try_from(value: u8) -> Result<Self>13369f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 13469f5cd67SAlexandre Courbot use FalconSecurityModel::*; 13569f5cd67SAlexandre Courbot 13669f5cd67SAlexandre Courbot let sec_model = match value { 13769f5cd67SAlexandre Courbot 0 => None, 13869f5cd67SAlexandre Courbot 2 => Light, 13969f5cd67SAlexandre Courbot 3 => Heavy, 14069f5cd67SAlexandre Courbot _ => return Err(EINVAL), 14169f5cd67SAlexandre Courbot }; 14269f5cd67SAlexandre Courbot 14369f5cd67SAlexandre Courbot Ok(sec_model) 14469f5cd67SAlexandre Courbot } 14569f5cd67SAlexandre Courbot } 14669f5cd67SAlexandre Courbot 14769f5cd67SAlexandre Courbot /// Signing algorithm for a given firmware, used in the [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] 148*0b980688SJoel Fernandes /// register. It is passed to the Falcon Boot ROM (BROM) as a parameter. 14969f5cd67SAlexandre Courbot #[repr(u8)] 15069f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 15169f5cd67SAlexandre Courbot pub(crate) enum FalconModSelAlgo { 152*0b980688SJoel Fernandes /// AES. 153*0b980688SJoel Fernandes #[expect(dead_code)] 154*0b980688SJoel Fernandes Aes = 0, 15569f5cd67SAlexandre Courbot /// RSA3K. 15669f5cd67SAlexandre Courbot #[default] 15769f5cd67SAlexandre Courbot Rsa3k = 1, 15869f5cd67SAlexandre Courbot } 1591b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconModSelAlgo); 16069f5cd67SAlexandre Courbot 1613606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 16269f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconModSelAlgo { 16369f5cd67SAlexandre Courbot type Error = Error; 16469f5cd67SAlexandre Courbot try_from(value: u8) -> Result<Self>16569f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 16669f5cd67SAlexandre Courbot match value { 16769f5cd67SAlexandre Courbot 1 => Ok(FalconModSelAlgo::Rsa3k), 16869f5cd67SAlexandre Courbot _ => Err(EINVAL), 16969f5cd67SAlexandre Courbot } 17069f5cd67SAlexandre Courbot } 17169f5cd67SAlexandre Courbot } 17269f5cd67SAlexandre Courbot 17369f5cd67SAlexandre Courbot /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register. 17469f5cd67SAlexandre Courbot #[repr(u8)] 17569f5cd67SAlexandre Courbot #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 17669f5cd67SAlexandre Courbot pub(crate) enum DmaTrfCmdSize { 17769f5cd67SAlexandre Courbot /// 256 bytes transfer. 17869f5cd67SAlexandre Courbot #[default] 17969f5cd67SAlexandre Courbot Size256B = 0x6, 18069f5cd67SAlexandre Courbot } 1811b8233bbSDanilo Krummrich impl_from_enum_to_u32!(DmaTrfCmdSize); 18269f5cd67SAlexandre Courbot 1833606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 18469f5cd67SAlexandre Courbot impl TryFrom<u8> for DmaTrfCmdSize { 18569f5cd67SAlexandre Courbot type Error = Error; 18669f5cd67SAlexandre Courbot try_from(value: u8) -> Result<Self>18769f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 18869f5cd67SAlexandre Courbot match value { 18969f5cd67SAlexandre Courbot 0x6 => Ok(Self::Size256B), 19069f5cd67SAlexandre Courbot _ => Err(EINVAL), 19169f5cd67SAlexandre Courbot } 19269f5cd67SAlexandre Courbot } 19369f5cd67SAlexandre Courbot } 19469f5cd67SAlexandre Courbot 19569f5cd67SAlexandre Courbot /// Currently active core on a dual falcon/riscv (Peregrine) controller. 19669f5cd67SAlexandre Courbot #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 19769f5cd67SAlexandre Courbot pub(crate) enum PeregrineCoreSelect { 19869f5cd67SAlexandre Courbot /// Falcon core is active. 19969f5cd67SAlexandre Courbot #[default] 20069f5cd67SAlexandre Courbot Falcon = 0, 20169f5cd67SAlexandre Courbot /// RISC-V core is active. 20269f5cd67SAlexandre Courbot Riscv = 1, 20369f5cd67SAlexandre Courbot } 2041b8233bbSDanilo Krummrich impl_from_enum_to_u32!(PeregrineCoreSelect); 20569f5cd67SAlexandre Courbot 20669f5cd67SAlexandre Courbot impl From<bool> for PeregrineCoreSelect { from(value: bool) -> Self20769f5cd67SAlexandre Courbot fn from(value: bool) -> Self { 20869f5cd67SAlexandre Courbot match value { 20969f5cd67SAlexandre Courbot false => PeregrineCoreSelect::Falcon, 21069f5cd67SAlexandre Courbot true => PeregrineCoreSelect::Riscv, 21169f5cd67SAlexandre Courbot } 21269f5cd67SAlexandre Courbot } 21369f5cd67SAlexandre Courbot } 21469f5cd67SAlexandre Courbot 21569f5cd67SAlexandre Courbot /// Different types of memory present in a falcon core. 21669f5cd67SAlexandre Courbot #[derive(Debug, Clone, Copy, PartialEq, Eq)] 21769f5cd67SAlexandre Courbot pub(crate) enum FalconMem { 21869f5cd67SAlexandre Courbot /// Instruction Memory. 21969f5cd67SAlexandre Courbot Imem, 22069f5cd67SAlexandre Courbot /// Data Memory. 22169f5cd67SAlexandre Courbot Dmem, 22269f5cd67SAlexandre Courbot } 22369f5cd67SAlexandre Courbot 224*0b980688SJoel Fernandes /// Defines the Framebuffer Interface (FBIF) aperture type. 225*0b980688SJoel Fernandes /// This determines the memory type for external memory access during a DMA transfer, which is 226*0b980688SJoel Fernandes /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. 22769f5cd67SAlexandre Courbot #[derive(Debug, Clone, Default)] 22869f5cd67SAlexandre Courbot pub(crate) enum FalconFbifTarget { 22969f5cd67SAlexandre Courbot /// VRAM. 23069f5cd67SAlexandre Courbot #[default] 231*0b980688SJoel Fernandes /// Local Framebuffer (GPU's VRAM memory). 23269f5cd67SAlexandre Courbot LocalFb = 0, 233*0b980688SJoel Fernandes /// Coherent system memory (System DRAM). 23469f5cd67SAlexandre Courbot CoherentSysmem = 1, 235*0b980688SJoel Fernandes /// Non-coherent system memory (System DRAM). 23669f5cd67SAlexandre Courbot NoncoherentSysmem = 2, 23769f5cd67SAlexandre Courbot } 2381b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconFbifTarget); 23969f5cd67SAlexandre Courbot 2403606620bSAlexandre Courbot // TODO[FPRI]: replace with `FromPrimitive`. 24169f5cd67SAlexandre Courbot impl TryFrom<u8> for FalconFbifTarget { 24269f5cd67SAlexandre Courbot type Error = Error; 24369f5cd67SAlexandre Courbot try_from(value: u8) -> Result<Self>24469f5cd67SAlexandre Courbot fn try_from(value: u8) -> Result<Self> { 24569f5cd67SAlexandre Courbot let res = match value { 24669f5cd67SAlexandre Courbot 0 => Self::LocalFb, 24769f5cd67SAlexandre Courbot 1 => Self::CoherentSysmem, 24869f5cd67SAlexandre Courbot 2 => Self::NoncoherentSysmem, 24969f5cd67SAlexandre Courbot _ => return Err(EINVAL), 25069f5cd67SAlexandre Courbot }; 25169f5cd67SAlexandre Courbot 25269f5cd67SAlexandre Courbot Ok(res) 25369f5cd67SAlexandre Courbot } 25469f5cd67SAlexandre Courbot } 25569f5cd67SAlexandre Courbot 25669f5cd67SAlexandre Courbot /// Type of memory addresses to use. 25769f5cd67SAlexandre Courbot #[derive(Debug, Clone, Default)] 25869f5cd67SAlexandre Courbot pub(crate) enum FalconFbifMemType { 25969f5cd67SAlexandre Courbot /// Virtual memory addresses. 26069f5cd67SAlexandre Courbot #[default] 26169f5cd67SAlexandre Courbot Virtual = 0, 26269f5cd67SAlexandre Courbot /// Physical memory addresses. 26369f5cd67SAlexandre Courbot Physical = 1, 26469f5cd67SAlexandre Courbot } 2651b8233bbSDanilo Krummrich impl_from_enum_to_u32!(FalconFbifMemType); 26669f5cd67SAlexandre Courbot 26769f5cd67SAlexandre Courbot /// Conversion from a single-bit register field. 26869f5cd67SAlexandre Courbot impl From<bool> for FalconFbifMemType { from(value: bool) -> Self26969f5cd67SAlexandre Courbot fn from(value: bool) -> Self { 27069f5cd67SAlexandre Courbot match value { 27169f5cd67SAlexandre Courbot false => Self::Virtual, 27269f5cd67SAlexandre Courbot true => Self::Physical, 27369f5cd67SAlexandre Courbot } 27469f5cd67SAlexandre Courbot } 27569f5cd67SAlexandre Courbot } 27669f5cd67SAlexandre Courbot 27769f5cd67SAlexandre Courbot /// Trait defining the parameters of a given Falcon instance. 27869f5cd67SAlexandre Courbot pub(crate) trait FalconEngine: Sync { 27969f5cd67SAlexandre Courbot /// Base I/O address for the falcon, relative from which its registers are accessed. 28069f5cd67SAlexandre Courbot const BASE: usize; 28169f5cd67SAlexandre Courbot } 28269f5cd67SAlexandre Courbot 28369f5cd67SAlexandre Courbot /// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). 28469f5cd67SAlexandre Courbot #[derive(Debug)] 28569f5cd67SAlexandre Courbot pub(crate) struct FalconLoadTarget { 28669f5cd67SAlexandre Courbot /// Offset from the start of the source object to copy from. 28769f5cd67SAlexandre Courbot pub(crate) src_start: u32, 28869f5cd67SAlexandre Courbot /// Offset from the start of the destination memory to copy into. 28969f5cd67SAlexandre Courbot pub(crate) dst_start: u32, 29069f5cd67SAlexandre Courbot /// Number of bytes to copy. 29169f5cd67SAlexandre Courbot pub(crate) len: u32, 29269f5cd67SAlexandre Courbot } 29369f5cd67SAlexandre Courbot 29469f5cd67SAlexandre Courbot /// Parameters for the falcon boot ROM. 29569f5cd67SAlexandre Courbot #[derive(Debug)] 29669f5cd67SAlexandre Courbot pub(crate) struct FalconBromParams { 29769f5cd67SAlexandre Courbot /// Offset in `DMEM`` of the firmware's signature. 29869f5cd67SAlexandre Courbot pub(crate) pkc_data_offset: u32, 29969f5cd67SAlexandre Courbot /// Mask of engines valid for this firmware. 30069f5cd67SAlexandre Courbot pub(crate) engine_id_mask: u16, 30169f5cd67SAlexandre Courbot /// ID of the ucode used to infer a fuse register to validate the signature. 30269f5cd67SAlexandre Courbot pub(crate) ucode_id: u8, 30369f5cd67SAlexandre Courbot } 30469f5cd67SAlexandre Courbot 30569f5cd67SAlexandre Courbot /// Trait for providing load parameters of falcon firmwares. 30669f5cd67SAlexandre Courbot pub(crate) trait FalconLoadParams { 30769f5cd67SAlexandre Courbot /// Returns the load parameters for `IMEM`. imem_load_params(&self) -> FalconLoadTarget30869f5cd67SAlexandre Courbot fn imem_load_params(&self) -> FalconLoadTarget; 30969f5cd67SAlexandre Courbot 31069f5cd67SAlexandre Courbot /// Returns the load parameters for `DMEM`. dmem_load_params(&self) -> FalconLoadTarget31169f5cd67SAlexandre Courbot fn dmem_load_params(&self) -> FalconLoadTarget; 31269f5cd67SAlexandre Courbot 31369f5cd67SAlexandre Courbot /// Returns the parameters to write into the BROM registers. brom_params(&self) -> FalconBromParams31469f5cd67SAlexandre Courbot fn brom_params(&self) -> FalconBromParams; 31569f5cd67SAlexandre Courbot 31669f5cd67SAlexandre Courbot /// Returns the start address of the firmware. boot_addr(&self) -> u3231769f5cd67SAlexandre Courbot fn boot_addr(&self) -> u32; 31869f5cd67SAlexandre Courbot } 31969f5cd67SAlexandre Courbot 32069f5cd67SAlexandre Courbot /// Trait for a falcon firmware. 32169f5cd67SAlexandre Courbot /// 32269f5cd67SAlexandre Courbot /// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA 32369f5cd67SAlexandre Courbot /// object. 32469f5cd67SAlexandre Courbot pub(crate) trait FalconFirmware: FalconLoadParams + Deref<Target = DmaObject> { 32569f5cd67SAlexandre Courbot /// Engine on which this firmware is to be loaded. 32669f5cd67SAlexandre Courbot type Target: FalconEngine; 32769f5cd67SAlexandre Courbot } 32869f5cd67SAlexandre Courbot 32969f5cd67SAlexandre Courbot /// Contains the base parameters common to all Falcon instances. 33069f5cd67SAlexandre Courbot pub(crate) struct Falcon<E: FalconEngine> { 33169f5cd67SAlexandre Courbot hal: KBox<dyn FalconHal<E>>, 33269f5cd67SAlexandre Courbot dev: ARef<device::Device>, 33369f5cd67SAlexandre Courbot } 33469f5cd67SAlexandre Courbot 33569f5cd67SAlexandre Courbot impl<E: FalconEngine + 'static> Falcon<E> { 33669f5cd67SAlexandre Courbot /// Create a new falcon instance. 33769f5cd67SAlexandre Courbot /// 33869f5cd67SAlexandre Courbot /// `need_riscv` is set to `true` if the caller expects the falcon to be a dual falcon/riscv 33969f5cd67SAlexandre Courbot /// controller. new( dev: &device::Device, chipset: Chipset, bar: &Bar0, need_riscv: bool, ) -> Result<Self>34069f5cd67SAlexandre Courbot pub(crate) fn new( 34169f5cd67SAlexandre Courbot dev: &device::Device, 34269f5cd67SAlexandre Courbot chipset: Chipset, 34369f5cd67SAlexandre Courbot bar: &Bar0, 34469f5cd67SAlexandre Courbot need_riscv: bool, 34569f5cd67SAlexandre Courbot ) -> Result<Self> { 34669f5cd67SAlexandre Courbot let hwcfg1 = regs::NV_PFALCON_FALCON_HWCFG1::read(bar, E::BASE); 34769f5cd67SAlexandre Courbot // Check that the revision and security model contain valid values. 34869f5cd67SAlexandre Courbot let _ = hwcfg1.core_rev()?; 34969f5cd67SAlexandre Courbot let _ = hwcfg1.security_model()?; 35069f5cd67SAlexandre Courbot 35169f5cd67SAlexandre Courbot if need_riscv { 35269f5cd67SAlexandre Courbot let hwcfg2 = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 35369f5cd67SAlexandre Courbot if !hwcfg2.riscv() { 35469f5cd67SAlexandre Courbot dev_err!( 35569f5cd67SAlexandre Courbot dev, 35669f5cd67SAlexandre Courbot "riscv support requested on a controller that does not support it\n" 35769f5cd67SAlexandre Courbot ); 35869f5cd67SAlexandre Courbot return Err(EINVAL); 35969f5cd67SAlexandre Courbot } 36069f5cd67SAlexandre Courbot } 36169f5cd67SAlexandre Courbot 36269f5cd67SAlexandre Courbot Ok(Self { 36369f5cd67SAlexandre Courbot hal: hal::falcon_hal(chipset)?, 36469f5cd67SAlexandre Courbot dev: dev.into(), 36569f5cd67SAlexandre Courbot }) 36669f5cd67SAlexandre Courbot } 36769f5cd67SAlexandre Courbot 36869f5cd67SAlexandre Courbot /// Wait for memory scrubbing to complete. reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result36969f5cd67SAlexandre Courbot fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 37069f5cd67SAlexandre Courbot // TIMEOUT: memory scrubbing should complete in less than 20ms. 3714092e1b4SAlexandre Courbot util::wait_on(Delta::from_millis(20), || { 37269f5cd67SAlexandre Courbot if regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE).mem_scrubbing_done() { 37369f5cd67SAlexandre Courbot Some(()) 37469f5cd67SAlexandre Courbot } else { 37569f5cd67SAlexandre Courbot None 37669f5cd67SAlexandre Courbot } 37769f5cd67SAlexandre Courbot }) 37869f5cd67SAlexandre Courbot } 37969f5cd67SAlexandre Courbot 38069f5cd67SAlexandre Courbot /// Reset the falcon engine. reset_eng(&self, bar: &Bar0) -> Result38169f5cd67SAlexandre Courbot fn reset_eng(&self, bar: &Bar0) -> Result { 38269f5cd67SAlexandre Courbot let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 38369f5cd67SAlexandre Courbot 38469f5cd67SAlexandre Courbot // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 38569f5cd67SAlexandre Courbot // RESET_READY so a non-failing timeout is used. 3864092e1b4SAlexandre Courbot let _ = util::wait_on(Delta::from_micros(150), || { 38769f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, E::BASE); 38869f5cd67SAlexandre Courbot if r.reset_ready() { 38969f5cd67SAlexandre Courbot Some(()) 39069f5cd67SAlexandre Courbot } else { 39169f5cd67SAlexandre Courbot None 39269f5cd67SAlexandre Courbot } 39369f5cd67SAlexandre Courbot }); 39469f5cd67SAlexandre Courbot 39569f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(true)); 39669f5cd67SAlexandre Courbot 3973606620bSAlexandre Courbot // TODO[DLAY]: replace with udelay() or equivalent once available. 39869f5cd67SAlexandre Courbot // TIMEOUT: falcon engine should not take more than 10us to reset. 3994092e1b4SAlexandre Courbot let _: Result = util::wait_on(Delta::from_micros(10), || None); 40069f5cd67SAlexandre Courbot 40169f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_ENGINE::alter(bar, E::BASE, |v| v.set_reset(false)); 40269f5cd67SAlexandre Courbot 40369f5cd67SAlexandre Courbot self.reset_wait_mem_scrubbing(bar)?; 40469f5cd67SAlexandre Courbot 40569f5cd67SAlexandre Courbot Ok(()) 40669f5cd67SAlexandre Courbot } 40769f5cd67SAlexandre Courbot 40869f5cd67SAlexandre Courbot /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete. reset(&self, bar: &Bar0) -> Result40969f5cd67SAlexandre Courbot pub(crate) fn reset(&self, bar: &Bar0) -> Result { 41069f5cd67SAlexandre Courbot self.reset_eng(bar)?; 41169f5cd67SAlexandre Courbot self.hal.select_core(self, bar)?; 41269f5cd67SAlexandre Courbot self.reset_wait_mem_scrubbing(bar)?; 41369f5cd67SAlexandre Courbot 41469f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_RM::default() 41569f5cd67SAlexandre Courbot .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) 41669f5cd67SAlexandre Courbot .write(bar, E::BASE); 41769f5cd67SAlexandre Courbot 41869f5cd67SAlexandre Courbot Ok(()) 41969f5cd67SAlexandre Courbot } 42069f5cd67SAlexandre Courbot 42169f5cd67SAlexandre Courbot /// Perform a DMA write according to `load_offsets` from `dma_handle` into the falcon's 42269f5cd67SAlexandre Courbot /// `target_mem`. 42369f5cd67SAlexandre Courbot /// 42469f5cd67SAlexandre Courbot /// `sec` is set if the loaded firmware is expected to run in secure mode. dma_wr<F: FalconFirmware<Target = E>>( &self, bar: &Bar0, fw: &F, target_mem: FalconMem, load_offsets: FalconLoadTarget, sec: bool, ) -> Result42569f5cd67SAlexandre Courbot fn dma_wr<F: FalconFirmware<Target = E>>( 42669f5cd67SAlexandre Courbot &self, 42769f5cd67SAlexandre Courbot bar: &Bar0, 42869f5cd67SAlexandre Courbot fw: &F, 42969f5cd67SAlexandre Courbot target_mem: FalconMem, 43069f5cd67SAlexandre Courbot load_offsets: FalconLoadTarget, 43169f5cd67SAlexandre Courbot sec: bool, 43269f5cd67SAlexandre Courbot ) -> Result { 43369f5cd67SAlexandre Courbot const DMA_LEN: u32 = 256; 43469f5cd67SAlexandre Courbot 43569f5cd67SAlexandre Courbot // For IMEM, we want to use the start offset as a virtual address tag for each page, since 43669f5cd67SAlexandre Courbot // code addresses in the firmware (and the boot vector) are virtual. 43769f5cd67SAlexandre Courbot // 43869f5cd67SAlexandre Courbot // For DMEM we can fold the start offset into the DMA handle. 43969f5cd67SAlexandre Courbot let (src_start, dma_start) = match target_mem { 44069f5cd67SAlexandre Courbot FalconMem::Imem => (load_offsets.src_start, fw.dma_handle()), 44169f5cd67SAlexandre Courbot FalconMem::Dmem => ( 44269f5cd67SAlexandre Courbot 0, 44369f5cd67SAlexandre Courbot fw.dma_handle_with_offset(load_offsets.src_start as usize)?, 44469f5cd67SAlexandre Courbot ), 44569f5cd67SAlexandre Courbot }; 44643ad65ecSDanilo Krummrich if dma_start % bindings::dma_addr_t::from(DMA_LEN) > 0 { 44769f5cd67SAlexandre Courbot dev_err!( 44869f5cd67SAlexandre Courbot self.dev, 44969f5cd67SAlexandre Courbot "DMA transfer start addresses must be a multiple of {}", 45069f5cd67SAlexandre Courbot DMA_LEN 45169f5cd67SAlexandre Courbot ); 45269f5cd67SAlexandre Courbot return Err(EINVAL); 45369f5cd67SAlexandre Courbot } 45469f5cd67SAlexandre Courbot if load_offsets.len % DMA_LEN > 0 { 45569f5cd67SAlexandre Courbot dev_err!( 45669f5cd67SAlexandre Courbot self.dev, 45769f5cd67SAlexandre Courbot "DMA transfer length must be a multiple of {}", 45869f5cd67SAlexandre Courbot DMA_LEN 45969f5cd67SAlexandre Courbot ); 46069f5cd67SAlexandre Courbot return Err(EINVAL); 46169f5cd67SAlexandre Courbot } 46269f5cd67SAlexandre Courbot 46369f5cd67SAlexandre Courbot // Set up the base source DMA address. 46469f5cd67SAlexandre Courbot 46569f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFBASE::default() 46669f5cd67SAlexandre Courbot .set_base((dma_start >> 8) as u32) 46769f5cd67SAlexandre Courbot .write(bar, E::BASE); 46869f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFBASE1::default() 46969f5cd67SAlexandre Courbot .set_base((dma_start >> 40) as u16) 47069f5cd67SAlexandre Courbot .write(bar, E::BASE); 47169f5cd67SAlexandre Courbot 47269f5cd67SAlexandre Courbot let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() 47369f5cd67SAlexandre Courbot .set_size(DmaTrfCmdSize::Size256B) 47469f5cd67SAlexandre Courbot .set_imem(target_mem == FalconMem::Imem) 47569f5cd67SAlexandre Courbot .set_sec(if sec { 1 } else { 0 }); 47669f5cd67SAlexandre Courbot 47769f5cd67SAlexandre Courbot for pos in (0..load_offsets.len).step_by(DMA_LEN as usize) { 47869f5cd67SAlexandre Courbot // Perform a transfer of size `DMA_LEN`. 47969f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() 48069f5cd67SAlexandre Courbot .set_offs(load_offsets.dst_start + pos) 48169f5cd67SAlexandre Courbot .write(bar, E::BASE); 48269f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() 48369f5cd67SAlexandre Courbot .set_offs(src_start + pos) 48469f5cd67SAlexandre Courbot .write(bar, E::BASE); 48569f5cd67SAlexandre Courbot cmd.write(bar, E::BASE); 48669f5cd67SAlexandre Courbot 48769f5cd67SAlexandre Courbot // Wait for the transfer to complete. 48869f5cd67SAlexandre Courbot // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories 48969f5cd67SAlexandre Courbot // should ever take that long. 4904092e1b4SAlexandre Courbot util::wait_on(Delta::from_secs(2), || { 49169f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, E::BASE); 49269f5cd67SAlexandre Courbot if r.idle() { 49369f5cd67SAlexandre Courbot Some(()) 49469f5cd67SAlexandre Courbot } else { 49569f5cd67SAlexandre Courbot None 49669f5cd67SAlexandre Courbot } 49769f5cd67SAlexandre Courbot })?; 49869f5cd67SAlexandre Courbot } 49969f5cd67SAlexandre Courbot 50069f5cd67SAlexandre Courbot Ok(()) 50169f5cd67SAlexandre Courbot } 50269f5cd67SAlexandre Courbot 50369f5cd67SAlexandre Courbot /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result50469f5cd67SAlexandre Courbot pub(crate) fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result { 50569f5cd67SAlexandre Courbot regs::NV_PFALCON_FBIF_CTL::alter(bar, E::BASE, |v| v.set_allow_phys_no_ctx(true)); 50669f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, E::BASE); 50769f5cd67SAlexandre Courbot regs::NV_PFALCON_FBIF_TRANSCFG::alter(bar, E::BASE, |v| { 50869f5cd67SAlexandre Courbot v.set_target(FalconFbifTarget::CoherentSysmem) 50969f5cd67SAlexandre Courbot .set_mem_type(FalconFbifMemType::Physical) 51069f5cd67SAlexandre Courbot }); 51169f5cd67SAlexandre Courbot 51269f5cd67SAlexandre Courbot self.dma_wr(bar, fw, FalconMem::Imem, fw.imem_load_params(), true)?; 51369f5cd67SAlexandre Courbot self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params(), true)?; 51469f5cd67SAlexandre Courbot 51569f5cd67SAlexandre Courbot self.hal.program_brom(self, bar, &fw.brom_params())?; 51669f5cd67SAlexandre Courbot 51769f5cd67SAlexandre Courbot // Set `BootVec` to start of non-secure code. 51869f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_BOOTVEC::default() 51969f5cd67SAlexandre Courbot .set_value(fw.boot_addr()) 52069f5cd67SAlexandre Courbot .write(bar, E::BASE); 52169f5cd67SAlexandre Courbot 52269f5cd67SAlexandre Courbot Ok(()) 52369f5cd67SAlexandre Courbot } 52469f5cd67SAlexandre Courbot 52569f5cd67SAlexandre Courbot /// Runs the loaded firmware and waits for its completion. 52669f5cd67SAlexandre Courbot /// 52769f5cd67SAlexandre Courbot /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers 52869f5cd67SAlexandre Courbot /// prior to running. 52969f5cd67SAlexandre Courbot /// 53069f5cd67SAlexandre Courbot /// Wait up to two seconds for the firmware to complete, and return its exit status read from 53169f5cd67SAlexandre Courbot /// the `MBOX0` and `MBOX1` registers. boot( &self, bar: &Bar0, mbox0: Option<u32>, mbox1: Option<u32>, ) -> Result<(u32, u32)>53269f5cd67SAlexandre Courbot pub(crate) fn boot( 53369f5cd67SAlexandre Courbot &self, 53469f5cd67SAlexandre Courbot bar: &Bar0, 53569f5cd67SAlexandre Courbot mbox0: Option<u32>, 53669f5cd67SAlexandre Courbot mbox1: Option<u32>, 53769f5cd67SAlexandre Courbot ) -> Result<(u32, u32)> { 53869f5cd67SAlexandre Courbot if let Some(mbox0) = mbox0 { 53969f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX0::default() 54069f5cd67SAlexandre Courbot .set_value(mbox0) 54169f5cd67SAlexandre Courbot .write(bar, E::BASE); 54269f5cd67SAlexandre Courbot } 54369f5cd67SAlexandre Courbot 54469f5cd67SAlexandre Courbot if let Some(mbox1) = mbox1 { 54569f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX1::default() 54669f5cd67SAlexandre Courbot .set_value(mbox1) 54769f5cd67SAlexandre Courbot .write(bar, E::BASE); 54869f5cd67SAlexandre Courbot } 54969f5cd67SAlexandre Courbot 55069f5cd67SAlexandre Courbot match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE).alias_en() { 55169f5cd67SAlexandre Courbot true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() 55269f5cd67SAlexandre Courbot .set_startcpu(true) 55369f5cd67SAlexandre Courbot .write(bar, E::BASE), 55469f5cd67SAlexandre Courbot false => regs::NV_PFALCON_FALCON_CPUCTL::default() 55569f5cd67SAlexandre Courbot .set_startcpu(true) 55669f5cd67SAlexandre Courbot .write(bar, E::BASE), 55769f5cd67SAlexandre Courbot } 55869f5cd67SAlexandre Courbot 55969f5cd67SAlexandre Courbot // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. 5604092e1b4SAlexandre Courbot util::wait_on(Delta::from_secs(2), || { 56169f5cd67SAlexandre Courbot let r = regs::NV_PFALCON_FALCON_CPUCTL::read(bar, E::BASE); 56269f5cd67SAlexandre Courbot if r.halted() { 56369f5cd67SAlexandre Courbot Some(()) 56469f5cd67SAlexandre Courbot } else { 56569f5cd67SAlexandre Courbot None 56669f5cd67SAlexandre Courbot } 56769f5cd67SAlexandre Courbot })?; 56869f5cd67SAlexandre Courbot 56969f5cd67SAlexandre Courbot let (mbox0, mbox1) = ( 57069f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, E::BASE).value(), 57169f5cd67SAlexandre Courbot regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, E::BASE).value(), 57269f5cd67SAlexandre Courbot ); 57369f5cd67SAlexandre Courbot 57469f5cd67SAlexandre Courbot Ok((mbox0, mbox1)) 57569f5cd67SAlexandre Courbot } 57669f5cd67SAlexandre Courbot 57769f5cd67SAlexandre Courbot /// Returns the fused version of the signature to use in order to run a HS firmware on this 57869f5cd67SAlexandre Courbot /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header. signature_reg_fuse_version( &self, bar: &Bar0, engine_id_mask: u16, ucode_id: u8, ) -> Result<u32>57969f5cd67SAlexandre Courbot pub(crate) fn signature_reg_fuse_version( 58069f5cd67SAlexandre Courbot &self, 58169f5cd67SAlexandre Courbot bar: &Bar0, 58269f5cd67SAlexandre Courbot engine_id_mask: u16, 58369f5cd67SAlexandre Courbot ucode_id: u8, 58469f5cd67SAlexandre Courbot ) -> Result<u32> { 58569f5cd67SAlexandre Courbot self.hal 58669f5cd67SAlexandre Courbot .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id) 58769f5cd67SAlexandre Courbot } 58869f5cd67SAlexandre Courbot } 589