xref: /linux/drivers/gpu/nova-core/falcon/hal/ga102.rs (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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>) -> Result {
119         select_core_ga102::<E>(falcon.bar)
120     }
121 
122     fn signature_reg_fuse_version(
123         &self,
124         falcon: &Falcon<'_, E>,
125         engine_id_mask: u16,
126         ucode_id: u8,
127     ) -> Result<u32> {
128         signature_reg_fuse_version_ga102(falcon.dev, falcon.bar, engine_id_mask, ucode_id)
129     }
130 
131     fn program_brom(&self, falcon: &Falcon<'_, E>, params: &FalconBromParams) {
132         program_brom_ga102::<E>(falcon.bar, params);
133     }
134 
135     fn is_riscv_active(&self, falcon: &Falcon<'_, E>) -> bool {
136         falcon
137             .bar
138             .read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>())
139             .active_stat()
140     }
141 
142     fn is_riscv_halted(&self, falcon: &Falcon<'_, E>) -> Result<bool> {
143         Ok(falcon
144             .bar
145             .read(regs::NV_PRISCV_RISCV_CPUCTL::of::<E>())
146             .halted())
147     }
148 
149     fn reset_wait_mem_scrubbing(&self, falcon: &Falcon<'_, E>) -> Result {
150         // TIMEOUT: memory scrubbing should complete in less than 20ms.
151         read_poll_timeout(
152             || Ok(falcon.bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())),
153             |r| r.mem_scrubbing_done(),
154             Delta::ZERO,
155             Delta::from_millis(20),
156         )
157         .map(|_| ())
158     }
159 
160     fn reset_eng(&self, falcon: &Falcon<'_, E>) -> Result {
161         let bar = falcon.bar;
162 
163         let _ = bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>());
164 
165         // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set
166         // RESET_READY so a non-failing timeout is used.
167         let _ = read_poll_timeout(
168             || Ok(bar.read(regs::NV_PFALCON_FALCON_HWCFG2::of::<E>())),
169             |r| r.reset_ready(),
170             Delta::ZERO,
171             Delta::from_micros(150),
172         );
173 
174         regs::NV_PFALCON_FALCON_ENGINE::reset_engine::<E>(bar);
175         self.reset_wait_mem_scrubbing(falcon)?;
176 
177         Ok(())
178     }
179 
180     fn load_method(&self) -> LoadMethod {
181         LoadMethod::Dma
182     }
183 }
184