xref: /linux/drivers/gpu/nova-core/falcon/hal/ga102.rs (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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