|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +use core::marker::PhantomData; |
| 4 | +use core::time::Duration; |
| 5 | + |
| 6 | +use kernel::device; |
| 7 | +use kernel::prelude::*; |
| 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(Duration::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: The ucode fuse versions are contained in the FUSE_OPT_FPF_<ENGINE>_UCODE<X>_VERSION |
| 46 | + // registers, which are an array. Our register definition macros do not allow us to manage them |
| 47 | + // properly, so we need to hardcode their addresses for now. Clean this up once we support |
| 48 | + // 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: 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(params.engine_id_mask as u32) |
| 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 | +} |
0 commit comments