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) -> Result { 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 Ok(()) 109 } 110 111 pub(super) struct Ga102<E: FalconEngine>(PhantomData<E>); 112 113 impl<E: FalconEngine> Ga102<E> { 114 pub(super) fn new() -> Self { 115 Self(PhantomData) 116 } 117 } 118 119 impl<E: FalconEngine> FalconHal<E> for Ga102<E> { 120 fn select_core(&self, _falcon: &Falcon<E>, bar: &Bar0) -> Result { 121 select_core_ga102::<E>(bar) 122 } 123 124 fn signature_reg_fuse_version( 125 &self, 126 falcon: &Falcon<E>, 127 bar: &Bar0, 128 engine_id_mask: u16, 129 ucode_id: u8, 130 ) -> Result<u32> { 131 signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id) 132 } 133 134 fn program_brom(&self, _falcon: &Falcon<E>, bar: &Bar0, params: &FalconBromParams) -> Result { 135 program_brom_ga102::<E>(bar, params) 136 } 137 138 fn is_riscv_active(&self, bar: &Bar0) -> bool { 139 bar.read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>()) 140 .active_stat() 141 } 142 143 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 144 // TIMEOUT: memory scrubbing should complete in less than 20ms. 145 read_poll_timeout( 146 || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 147 |r| r.mem_scrubbing_done(), 148 Delta::ZERO, 149 Delta::from_millis(20), 150 ) 151 .map(|_| ()) 152 } 153 154 fn reset_eng(&self, bar: &Bar0) -> Result { 155 let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>()); 156 157 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 158 // RESET_READY so a non-failing timeout is used. 159 let _ = read_poll_timeout( 160 || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())), 161 |r| r.reset_ready(), 162 Delta::ZERO, 163 Delta::from_micros(150), 164 ); 165 166 regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(bar); 167 self.reset_wait_mem_scrubbing(bar)?; 168 169 Ok(()) 170 } 171 172 fn load_method(&self) -> LoadMethod { 173 LoadMethod::Dma 174 } 175 } 176