1 // SPDX-License-Identifier: GPL-2.0 2 3 use core::marker::PhantomData; 4 5 use kernel::{ 6 device, 7 io::{ 8 poll::read_poll_timeout, 9 register::{ 10 Array, 11 WithBase, // 12 }, 13 Io, // 14 }, 15 prelude::*, 16 time::Delta, // 17 }; 18 19 use crate::{ 20 driver::Bar0, 21 falcon::{ 22 hal::LoadMethod, 23 Falcon, 24 FalconBromParams, 25 FalconEngine, 26 FalconModSelAlgo, 27 PeregrineCoreSelect, // 28 }, 29 regs, 30 }; 31 32 use super::FalconHal; 33 34 fn select_core_ga102<E: FalconEngine>(bar: Bar0<'_>) -> Result { 35 let bcr_ctrl = bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>()); 36 if bcr_ctrl.core_select() != PeregrineCoreSelect::Falcon { 37 bar.write( 38 WithBase::of::<E>(), 39 regs::NV_PRISCV_RISCV_BCR_CTRL::zeroed().with_core_select(PeregrineCoreSelect::Falcon), 40 ); 41 42 // TIMEOUT: falcon core should take less than 10ms to report being enabled. 43 read_poll_timeout( 44 || Ok(bar.read(regs::NV_PRISCV_RISCV_BCR_CTRL::of::<E>())), 45 |r| r.valid(), 46 Delta::ZERO, 47 Delta::from_millis(10), 48 )?; 49 } 50 51 Ok(()) 52 } 53 54 fn signature_reg_fuse_version_ga102( 55 dev: &device::Device, 56 bar: Bar0<'_>, 57 engine_id_mask: u16, 58 ucode_id: u8, 59 ) -> Result<u32> { 60 // Each engine has 16 ucode version registers numbered from 1 to 16. 61 let ucode_idx = match usize::from(ucode_id) { 62 ucode_id @ 1..=regs::NV_FUSE_OPT_FPF_SIZE => ucode_id - 1, 63 _ => { 64 dev_err!(dev, "invalid ucode id {:#x}\n", ucode_id); 65 return Err(EINVAL); 66 } 67 }; 68 69 // `ucode_idx` is guaranteed to be in the range [0..15], making the `read` calls provable valid 70 // at build-time. 71 let reg_fuse_version: u16 = if engine_id_mask & 0x0001 != 0 { 72 bar.read(regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::at(ucode_idx)) 73 .data() 74 } else if engine_id_mask & 0x0004 != 0 { 75 bar.read(regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::at(ucode_idx)) 76 .data() 77 } else if engine_id_mask & 0x0400 != 0 { 78 bar.read(regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::at(ucode_idx)) 79 .data() 80 } else { 81 dev_err!(dev, "unexpected engine_id_mask {:#x}\n", engine_id_mask); 82 return Err(EINVAL); 83 }; 84 85 // TODO[NUMM]: replace with `last_set_bit` once it lands. 86 Ok(u16::BITS - reg_fuse_version.leading_zeros()) 87 } 88 89 fn program_brom_ga102<E: FalconEngine>(bar: Bar0<'_>, params: &FalconBromParams) { 90 bar.write( 91 WithBase::of::<E>().at(0), 92 regs::NV_PFALCON2_FALCON_BROM_PARAADDR::zeroed().with_value(params.pkc_data_offset), 93 ); 94 bar.write( 95 WithBase::of::<E>(), 96 regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::zeroed() 97 .with_value(u32::from(params.engine_id_mask)), 98 ); 99 bar.write( 100 WithBase::of::<E>(), 101 regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::zeroed().with_ucode_id(params.ucode_id), 102 ); 103 bar.write( 104 WithBase::of::<E>(), 105 regs::NV_PFALCON2_FALCON_MOD_SEL::zeroed().with_algo(FalconModSelAlgo::Rsa3k), 106 ); 107 } 108 109 pub(super) struct Ga102<E: FalconEngine>(PhantomData<E>); 110 111 impl<E: FalconEngine> Ga102<E> { 112 pub(super) fn new() -> Self { 113 Self(PhantomData) 114 } 115 } 116 117 impl<E: FalconEngine> FalconHal<E> for Ga102<E> { 118 fn select_core(&self, _falcon: &Falcon<E>, bar: Bar0<'_>) -> Result { 119 select_core_ga102::<E>(bar) 120 } 121 122 fn signature_reg_fuse_version( 123 &self, 124 falcon: &Falcon<E>, 125 bar: Bar0<'_>, 126 engine_id_mask: u16, 127 ucode_id: u8, 128 ) -> Result<u32> { 129 signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id) 130 } 131 132 fn program_brom(&self, _falcon: &Falcon<E>, bar: Bar0<'_>, params: &FalconBromParams) { 133 program_brom_ga102::<E>(bar, params); 134 } 135 136 fn is_riscv_active(&self, bar: Bar0<'_>) -> bool { 137 bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>()) 138 .active_stat() 139 } 140 141 fn reset_wait_mem_scrubbing(&self, bar: Bar0<'_>) -> Result { 142 // TIMEOUT: memory scrubbing should complete in less than 20ms. 143 read_poll_timeout( 144 || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 145 |r| r.mem_scrubbing_done(), 146 Delta::ZERO, 147 Delta::from_millis(20), 148 ) 149 .map(|_| ()) 150 } 151 152 fn reset_eng(&self, bar: Bar0<'_>) -> Result { 153 let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>()); 154 155 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 156 // RESET_READY so a non-failing timeout is used. 157 let _ = read_poll_timeout( 158 || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 159 |r| r.reset_ready(), 160 Delta::ZERO, 161 Delta::from_micros(150), 162 ); 163 164 regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(bar); 165 self.reset_wait_mem_scrubbing(bar)?; 166 167 Ok(()) 168 } 169 170 fn load_method(&self) -> LoadMethod { 171 LoadMethod::Dma 172 } 173 } 174