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::BASE); 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::BASE); 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::BASE); 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 // TODO[REGA]: The ucode fuse versions are contained in the 46 // FUSE_OPT_FPF_<ENGINE>_UCODE<X>_VERSION registers, which are an array. Our register 47 // definition macros do not allow us to manage them properly, so we need to hardcode their 48 // addresses for now. Clean this up once we support register arrays. 49 50 // Each engine has 16 ucode version registers numbered from 1 to 16. 51 if ucode_id == 0 || ucode_id > 16 { 52 dev_err!(dev, "invalid ucode id {:#x}", ucode_id); 53 return Err(EINVAL); 54 } 55 56 // Base address of the FUSE registers array corresponding to the engine. 57 let reg_fuse_base = if engine_id_mask & 0x0001 != 0 { 58 regs::NV_FUSE_OPT_FPF_SEC2_UCODE1_VERSION::OFFSET 59 } else if engine_id_mask & 0x0004 != 0 { 60 regs::NV_FUSE_OPT_FPF_NVDEC_UCODE1_VERSION::OFFSET 61 } else if engine_id_mask & 0x0400 != 0 { 62 regs::NV_FUSE_OPT_FPF_GSP_UCODE1_VERSION::OFFSET 63 } else { 64 dev_err!(dev, "unexpected engine_id_mask {:#x}", engine_id_mask); 65 return Err(EINVAL); 66 }; 67 68 // Read `reg_fuse_base[ucode_id - 1]`. 69 let reg_fuse_version = 70 bar.read32(reg_fuse_base + ((ucode_id - 1) as usize * core::mem::size_of::<u32>())); 71 72 // TODO[NUMM]: replace with `last_set_bit` once it lands. 73 Ok(u32::BITS - reg_fuse_version.leading_zeros()) 74 } 75 76 fn program_brom_ga102<E: FalconEngine>(bar: &Bar0, params: &FalconBromParams) -> Result { 77 regs::NV_PFALCON2_FALCON_BROM_PARAADDR::default() 78 .set_value(params.pkc_data_offset) 79 .write(bar, E::BASE); 80 regs::NV_PFALCON2_FALCON_BROM_ENGIDMASK::default() 81 .set_value(u32::from(params.engine_id_mask)) 82 .write(bar, E::BASE); 83 regs::NV_PFALCON2_FALCON_BROM_CURR_UCODE_ID::default() 84 .set_ucode_id(params.ucode_id) 85 .write(bar, E::BASE); 86 regs::NV_PFALCON2_FALCON_MOD_SEL::default() 87 .set_algo(FalconModSelAlgo::Rsa3k) 88 .write(bar, E::BASE); 89 90 Ok(()) 91 } 92 93 pub(super) struct Ga102<E: FalconEngine>(PhantomData<E>); 94 95 impl<E: FalconEngine> Ga102<E> { 96 pub(super) fn new() -> Self { 97 Self(PhantomData) 98 } 99 } 100 101 impl<E: FalconEngine> FalconHal<E> for Ga102<E> { 102 fn select_core(&self, _falcon: &Falcon<E>, bar: &Bar0) -> Result { 103 select_core_ga102::<E>(bar) 104 } 105 106 fn signature_reg_fuse_version( 107 &self, 108 falcon: &Falcon<E>, 109 bar: &Bar0, 110 engine_id_mask: u16, 111 ucode_id: u8, 112 ) -> Result<u32> { 113 signature_reg_fuse_version_ga102(&falcon.dev, bar, engine_id_mask, ucode_id) 114 } 115 116 fn program_brom(&self, _falcon: &Falcon<E>, bar: &Bar0, params: &FalconBromParams) -> Result { 117 program_brom_ga102::<E>(bar, params) 118 } 119 } 120