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