1 // SPDX-License-Identifier: GPL-2.0 2 3 use core::marker::PhantomData; 4 5 use kernel::device; 6 use kernel::prelude::*; 7 use kernel::time::Delta; 8 9 use crate::driver::Bar0; 10 use crate::falcon::{ 11 Falcon, FalconBromParams, FalconEngine, FalconModSelAlgo, PeregrineCoreSelect, 12 }; 13 use crate::regs; 14 use crate::util; 15 16 use super::FalconHal; 17 18 fn select_core_ga102<E: FalconEngine>(bar: &Bar0) -> Result { 19 let bcr_ctrl = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); 20 if bcr_ctrl.core_select() != PeregrineCoreSelect::Falcon { 21 regs::NV_PRISCV_RISCV_BCR_CTRL::default() 22 .set_core_select(PeregrineCoreSelect::Falcon) 23 .write(bar, &E::ID); 24 25 // TIMEOUT: falcon core should take less than 10ms to report being enabled. 26 util::wait_on(Delta::from_millis(10), || { 27 let r = regs::NV_PRISCV_RISCV_BCR_CTRL::read(bar, &E::ID); 28 if r.valid() { 29 Some(()) 30 } else { 31 None 32 } 33 })?; 34 } 35 36 Ok(()) 37 } 38 39 fn signature_reg_fuse_version_ga102( 40 dev: &device::Device, 41 bar: &Bar0, 42 engine_id_mask: u16, 43 ucode_id: u8, 44 ) -> Result<u32> { 45 const NV_FUSE_OPT_FPF_SIZE: u8 = regs::NV_FUSE_OPT_FPF_SIZE as u8; 46 47 // Each engine has 16 ucode version registers numbered from 1 to 16. 48 let ucode_idx = match ucode_id { 49 1..=NV_FUSE_OPT_FPF_SIZE => (ucode_id - 1) as usize, 50 _ => { 51 dev_err!(dev, "invalid ucode id {:#x}", ucode_id); 52 return Err(EINVAL); 53 } 54 }; 55 56 // `ucode_idx` is guaranteed to be in the range [0..15], making the `read` calls provable valid 57 // at build-time. 58 let reg_fuse_version = if engine_id_mask & 0x0001 != 0 { 59 regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::read(bar, ucode_idx).data() 60 } else if engine_id_mask & 0x0004 != 0 { 61 regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::read(bar, ucode_idx).data() 62 } else if engine_id_mask & 0x0400 != 0 { 63 regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::read(bar, ucode_idx).data() 64 } else { 65 dev_err!(dev, "unexpected engine_id_mask {:#x}", engine_id_mask); 66 return Err(EINVAL); 67 }; 68 69 // TODO[NUMM]: replace with `last_set_bit` once it lands. 70 Ok(u16::BITS - reg_fuse_version.leading_zeros()) 71 } 72 73 fn program_brom_ga102<E: FalconEngine>(bar: &Bar0, params: &FalconBromParams) -> Result { 74 regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() 75 .set_value(params.pkc_data_offset) 76 .write(bar, &E::ID, 0); 77 regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() 78 .set_value(u32::from(params.engine_id_mask)) 79 .write(bar, &E::ID); 80 regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() 81 .set_ucode_id(params.ucode_id) 82 .write(bar, &E::ID); 83 regs::NV_PFALCON2_FALCON_MOD_SEL::default() 84 .set_algo(FalconModSelAlgo::Rsa3k) 85 .write(bar, &E::ID); 86 87 Ok(()) 88 } 89 90 pub(super) struct Ga102<E: FalconEngine>(PhantomData<E>); 91 92 impl<E: FalconEngine> Ga102<E> { 93 pub(super) fn new() -> Self { 94 Self(PhantomData) 95 } 96 } 97 98 impl<E: FalconEngine> FalconHal<E> for Ga102<E> { 99 fn select_core(&self, _falcon: &Falcon<E>, bar: &Bar0) -> Result { 100 select_core_ga102::<E>(bar) 101 } 102 103 fn signature_reg_fuse_version( 104 &self, 105 falcon: &Falcon<E>, 106 bar: &Bar0, 107 engine_id_mask: u16, 108 ucode_id: u8, 109 ) -> Result<u32> { 110 signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id) 111 } 112 113 fn program_brom(&self, _falcon: &Falcon<E>, bar: &Bar0, params: &FalconBromParams) -> Result { 114 program_brom_ga102::<E>(bar, params) 115 } 116 } 117