xref: /linux/drivers/gpu/drm/tyr/gpu.rs (revision 58809f614e0e3f4e12b489bddf680bfeb31c0a20)
1*cf4fd52eSDaniel Almeida // SPDX-License-Identifier: GPL-2.0 or MIT
2*cf4fd52eSDaniel Almeida 
3*cf4fd52eSDaniel Almeida use kernel::bits::genmask_u32;
4*cf4fd52eSDaniel Almeida use kernel::device::Bound;
5*cf4fd52eSDaniel Almeida use kernel::device::Device;
6*cf4fd52eSDaniel Almeida use kernel::devres::Devres;
7*cf4fd52eSDaniel Almeida use kernel::platform;
8*cf4fd52eSDaniel Almeida use kernel::prelude::*;
9*cf4fd52eSDaniel Almeida use kernel::time;
10*cf4fd52eSDaniel Almeida use kernel::transmute::AsBytes;
11*cf4fd52eSDaniel Almeida 
12*cf4fd52eSDaniel Almeida use crate::driver::IoMem;
13*cf4fd52eSDaniel Almeida use crate::regs;
14*cf4fd52eSDaniel Almeida 
15*cf4fd52eSDaniel Almeida /// Struct containing information that can be queried by userspace. This is read from
16*cf4fd52eSDaniel Almeida /// the GPU's registers.
17*cf4fd52eSDaniel Almeida ///
18*cf4fd52eSDaniel Almeida /// # Invariants
19*cf4fd52eSDaniel Almeida ///
20*cf4fd52eSDaniel Almeida /// - The layout of this struct identical to the C `struct drm_panthor_gpu_info`.
21*cf4fd52eSDaniel Almeida #[repr(C)]
22*cf4fd52eSDaniel Almeida pub(crate) struct GpuInfo {
23*cf4fd52eSDaniel Almeida     pub(crate) gpu_id: u32,
24*cf4fd52eSDaniel Almeida     pub(crate) gpu_rev: u32,
25*cf4fd52eSDaniel Almeida     pub(crate) csf_id: u32,
26*cf4fd52eSDaniel Almeida     pub(crate) l2_features: u32,
27*cf4fd52eSDaniel Almeida     pub(crate) tiler_features: u32,
28*cf4fd52eSDaniel Almeida     pub(crate) mem_features: u32,
29*cf4fd52eSDaniel Almeida     pub(crate) mmu_features: u32,
30*cf4fd52eSDaniel Almeida     pub(crate) thread_features: u32,
31*cf4fd52eSDaniel Almeida     pub(crate) max_threads: u32,
32*cf4fd52eSDaniel Almeida     pub(crate) thread_max_workgroup_size: u32,
33*cf4fd52eSDaniel Almeida     pub(crate) thread_max_barrier_size: u32,
34*cf4fd52eSDaniel Almeida     pub(crate) coherency_features: u32,
35*cf4fd52eSDaniel Almeida     pub(crate) texture_features: [u32; 4],
36*cf4fd52eSDaniel Almeida     pub(crate) as_present: u32,
37*cf4fd52eSDaniel Almeida     pub(crate) pad0: u32,
38*cf4fd52eSDaniel Almeida     pub(crate) shader_present: u64,
39*cf4fd52eSDaniel Almeida     pub(crate) l2_present: u64,
40*cf4fd52eSDaniel Almeida     pub(crate) tiler_present: u64,
41*cf4fd52eSDaniel Almeida     pub(crate) core_features: u32,
42*cf4fd52eSDaniel Almeida     pub(crate) pad: u32,
43*cf4fd52eSDaniel Almeida }
44*cf4fd52eSDaniel Almeida 
45*cf4fd52eSDaniel Almeida impl GpuInfo {
46*cf4fd52eSDaniel Almeida     pub(crate) fn new(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result<Self> {
47*cf4fd52eSDaniel Almeida         let gpu_id = regs::GPU_ID.read(dev, iomem)?;
48*cf4fd52eSDaniel Almeida         let csf_id = regs::GPU_CSF_ID.read(dev, iomem)?;
49*cf4fd52eSDaniel Almeida         let gpu_rev = regs::GPU_REVID.read(dev, iomem)?;
50*cf4fd52eSDaniel Almeida         let core_features = regs::GPU_CORE_FEATURES.read(dev, iomem)?;
51*cf4fd52eSDaniel Almeida         let l2_features = regs::GPU_L2_FEATURES.read(dev, iomem)?;
52*cf4fd52eSDaniel Almeida         let tiler_features = regs::GPU_TILER_FEATURES.read(dev, iomem)?;
53*cf4fd52eSDaniel Almeida         let mem_features = regs::GPU_MEM_FEATURES.read(dev, iomem)?;
54*cf4fd52eSDaniel Almeida         let mmu_features = regs::GPU_MMU_FEATURES.read(dev, iomem)?;
55*cf4fd52eSDaniel Almeida         let thread_features = regs::GPU_THREAD_FEATURES.read(dev, iomem)?;
56*cf4fd52eSDaniel Almeida         let max_threads = regs::GPU_THREAD_MAX_THREADS.read(dev, iomem)?;
57*cf4fd52eSDaniel Almeida         let thread_max_workgroup_size = regs::GPU_THREAD_MAX_WORKGROUP_SIZE.read(dev, iomem)?;
58*cf4fd52eSDaniel Almeida         let thread_max_barrier_size = regs::GPU_THREAD_MAX_BARRIER_SIZE.read(dev, iomem)?;
59*cf4fd52eSDaniel Almeida         let coherency_features = regs::GPU_COHERENCY_FEATURES.read(dev, iomem)?;
60*cf4fd52eSDaniel Almeida 
61*cf4fd52eSDaniel Almeida         let texture_features = regs::GPU_TEXTURE_FEATURES0.read(dev, iomem)?;
62*cf4fd52eSDaniel Almeida 
63*cf4fd52eSDaniel Almeida         let as_present = regs::GPU_AS_PRESENT.read(dev, iomem)?;
64*cf4fd52eSDaniel Almeida 
65*cf4fd52eSDaniel Almeida         let shader_present = u64::from(regs::GPU_SHADER_PRESENT_LO.read(dev, iomem)?);
66*cf4fd52eSDaniel Almeida         let shader_present =
67*cf4fd52eSDaniel Almeida             shader_present | u64::from(regs::GPU_SHADER_PRESENT_HI.read(dev, iomem)?) << 32;
68*cf4fd52eSDaniel Almeida 
69*cf4fd52eSDaniel Almeida         let tiler_present = u64::from(regs::GPU_TILER_PRESENT_LO.read(dev, iomem)?);
70*cf4fd52eSDaniel Almeida         let tiler_present =
71*cf4fd52eSDaniel Almeida             tiler_present | u64::from(regs::GPU_TILER_PRESENT_HI.read(dev, iomem)?) << 32;
72*cf4fd52eSDaniel Almeida 
73*cf4fd52eSDaniel Almeida         let l2_present = u64::from(regs::GPU_L2_PRESENT_LO.read(dev, iomem)?);
74*cf4fd52eSDaniel Almeida         let l2_present = l2_present | u64::from(regs::GPU_L2_PRESENT_HI.read(dev, iomem)?) << 32;
75*cf4fd52eSDaniel Almeida 
76*cf4fd52eSDaniel Almeida         Ok(Self {
77*cf4fd52eSDaniel Almeida             gpu_id,
78*cf4fd52eSDaniel Almeida             gpu_rev,
79*cf4fd52eSDaniel Almeida             csf_id,
80*cf4fd52eSDaniel Almeida             l2_features,
81*cf4fd52eSDaniel Almeida             tiler_features,
82*cf4fd52eSDaniel Almeida             mem_features,
83*cf4fd52eSDaniel Almeida             mmu_features,
84*cf4fd52eSDaniel Almeida             thread_features,
85*cf4fd52eSDaniel Almeida             max_threads,
86*cf4fd52eSDaniel Almeida             thread_max_workgroup_size,
87*cf4fd52eSDaniel Almeida             thread_max_barrier_size,
88*cf4fd52eSDaniel Almeida             coherency_features,
89*cf4fd52eSDaniel Almeida             // TODO: Add texture_features_{1,2,3}.
90*cf4fd52eSDaniel Almeida             texture_features: [texture_features, 0, 0, 0],
91*cf4fd52eSDaniel Almeida             as_present,
92*cf4fd52eSDaniel Almeida             pad0: 0,
93*cf4fd52eSDaniel Almeida             shader_present,
94*cf4fd52eSDaniel Almeida             l2_present,
95*cf4fd52eSDaniel Almeida             tiler_present,
96*cf4fd52eSDaniel Almeida             core_features,
97*cf4fd52eSDaniel Almeida             pad: 0,
98*cf4fd52eSDaniel Almeida         })
99*cf4fd52eSDaniel Almeida     }
100*cf4fd52eSDaniel Almeida 
101*cf4fd52eSDaniel Almeida     pub(crate) fn log(&self, pdev: &platform::Device) {
102*cf4fd52eSDaniel Almeida         let major = (self.gpu_id >> 16) & 0xff;
103*cf4fd52eSDaniel Almeida         let minor = (self.gpu_id >> 8) & 0xff;
104*cf4fd52eSDaniel Almeida         let status = self.gpu_id & 0xff;
105*cf4fd52eSDaniel Almeida 
106*cf4fd52eSDaniel Almeida         let model_name = if let Some(model) = GPU_MODELS
107*cf4fd52eSDaniel Almeida             .iter()
108*cf4fd52eSDaniel Almeida             .find(|&f| f.major == major && f.minor == minor)
109*cf4fd52eSDaniel Almeida         {
110*cf4fd52eSDaniel Almeida             model.name
111*cf4fd52eSDaniel Almeida         } else {
112*cf4fd52eSDaniel Almeida             "unknown"
113*cf4fd52eSDaniel Almeida         };
114*cf4fd52eSDaniel Almeida 
115*cf4fd52eSDaniel Almeida         dev_info!(
116*cf4fd52eSDaniel Almeida             pdev.as_ref(),
117*cf4fd52eSDaniel Almeida             "mali-{} id 0x{:x} major 0x{:x} minor 0x{:x} status 0x{:x}",
118*cf4fd52eSDaniel Almeida             model_name,
119*cf4fd52eSDaniel Almeida             self.gpu_id >> 16,
120*cf4fd52eSDaniel Almeida             major,
121*cf4fd52eSDaniel Almeida             minor,
122*cf4fd52eSDaniel Almeida             status
123*cf4fd52eSDaniel Almeida         );
124*cf4fd52eSDaniel Almeida 
125*cf4fd52eSDaniel Almeida         dev_info!(
126*cf4fd52eSDaniel Almeida             pdev.as_ref(),
127*cf4fd52eSDaniel Almeida             "Features: L2:{:#x} Tiler:{:#x} Mem:{:#x} MMU:{:#x} AS:{:#x}",
128*cf4fd52eSDaniel Almeida             self.l2_features,
129*cf4fd52eSDaniel Almeida             self.tiler_features,
130*cf4fd52eSDaniel Almeida             self.mem_features,
131*cf4fd52eSDaniel Almeida             self.mmu_features,
132*cf4fd52eSDaniel Almeida             self.as_present
133*cf4fd52eSDaniel Almeida         );
134*cf4fd52eSDaniel Almeida 
135*cf4fd52eSDaniel Almeida         dev_info!(
136*cf4fd52eSDaniel Almeida             pdev.as_ref(),
137*cf4fd52eSDaniel Almeida             "shader_present=0x{:016x} l2_present=0x{:016x} tiler_present=0x{:016x}",
138*cf4fd52eSDaniel Almeida             self.shader_present,
139*cf4fd52eSDaniel Almeida             self.l2_present,
140*cf4fd52eSDaniel Almeida             self.tiler_present
141*cf4fd52eSDaniel Almeida         );
142*cf4fd52eSDaniel Almeida     }
143*cf4fd52eSDaniel Almeida 
144*cf4fd52eSDaniel Almeida     /// Returns the number of virtual address bits supported by the GPU.
145*cf4fd52eSDaniel Almeida     #[expect(dead_code)]
146*cf4fd52eSDaniel Almeida     pub(crate) fn va_bits(&self) -> u32 {
147*cf4fd52eSDaniel Almeida         self.mmu_features & genmask_u32(0..=7)
148*cf4fd52eSDaniel Almeida     }
149*cf4fd52eSDaniel Almeida 
150*cf4fd52eSDaniel Almeida     /// Returns the number of physical address bits supported by the GPU.
151*cf4fd52eSDaniel Almeida     #[expect(dead_code)]
152*cf4fd52eSDaniel Almeida     pub(crate) fn pa_bits(&self) -> u32 {
153*cf4fd52eSDaniel Almeida         (self.mmu_features >> 8) & genmask_u32(0..=7)
154*cf4fd52eSDaniel Almeida     }
155*cf4fd52eSDaniel Almeida }
156*cf4fd52eSDaniel Almeida 
157*cf4fd52eSDaniel Almeida // SAFETY: `GpuInfo`'s invariant guarantees that it is the same type that is
158*cf4fd52eSDaniel Almeida // already exposed to userspace by the C driver. This implies that it fulfills
159*cf4fd52eSDaniel Almeida // the requirements for `AsBytes`.
160*cf4fd52eSDaniel Almeida //
161*cf4fd52eSDaniel Almeida // This means:
162*cf4fd52eSDaniel Almeida //
163*cf4fd52eSDaniel Almeida // - No implicit padding,
164*cf4fd52eSDaniel Almeida // - No kernel pointers,
165*cf4fd52eSDaniel Almeida // - No interior mutability.
166*cf4fd52eSDaniel Almeida unsafe impl AsBytes for GpuInfo {}
167*cf4fd52eSDaniel Almeida 
168*cf4fd52eSDaniel Almeida struct GpuModels {
169*cf4fd52eSDaniel Almeida     name: &'static str,
170*cf4fd52eSDaniel Almeida     major: u32,
171*cf4fd52eSDaniel Almeida     minor: u32,
172*cf4fd52eSDaniel Almeida }
173*cf4fd52eSDaniel Almeida 
174*cf4fd52eSDaniel Almeida const GPU_MODELS: [GpuModels; 1] = [GpuModels {
175*cf4fd52eSDaniel Almeida     name: "g610",
176*cf4fd52eSDaniel Almeida     major: 10,
177*cf4fd52eSDaniel Almeida     minor: 7,
178*cf4fd52eSDaniel Almeida }];
179*cf4fd52eSDaniel Almeida 
180*cf4fd52eSDaniel Almeida #[allow(dead_code)]
181*cf4fd52eSDaniel Almeida pub(crate) struct GpuId {
182*cf4fd52eSDaniel Almeida     pub(crate) arch_major: u32,
183*cf4fd52eSDaniel Almeida     pub(crate) arch_minor: u32,
184*cf4fd52eSDaniel Almeida     pub(crate) arch_rev: u32,
185*cf4fd52eSDaniel Almeida     pub(crate) prod_major: u32,
186*cf4fd52eSDaniel Almeida     pub(crate) ver_major: u32,
187*cf4fd52eSDaniel Almeida     pub(crate) ver_minor: u32,
188*cf4fd52eSDaniel Almeida     pub(crate) ver_status: u32,
189*cf4fd52eSDaniel Almeida }
190*cf4fd52eSDaniel Almeida 
191*cf4fd52eSDaniel Almeida impl From<u32> for GpuId {
192*cf4fd52eSDaniel Almeida     fn from(value: u32) -> Self {
193*cf4fd52eSDaniel Almeida         GpuId {
194*cf4fd52eSDaniel Almeida             arch_major: (value & genmask_u32(28..=31)) >> 28,
195*cf4fd52eSDaniel Almeida             arch_minor: (value & genmask_u32(24..=27)) >> 24,
196*cf4fd52eSDaniel Almeida             arch_rev: (value & genmask_u32(20..=23)) >> 20,
197*cf4fd52eSDaniel Almeida             prod_major: (value & genmask_u32(16..=19)) >> 16,
198*cf4fd52eSDaniel Almeida             ver_major: (value & genmask_u32(12..=15)) >> 12,
199*cf4fd52eSDaniel Almeida             ver_minor: (value & genmask_u32(4..=11)) >> 4,
200*cf4fd52eSDaniel Almeida             ver_status: value & genmask_u32(0..=3),
201*cf4fd52eSDaniel Almeida         }
202*cf4fd52eSDaniel Almeida     }
203*cf4fd52eSDaniel Almeida }
204*cf4fd52eSDaniel Almeida 
205*cf4fd52eSDaniel Almeida /// Powers on the l2 block.
206*cf4fd52eSDaniel Almeida pub(crate) fn l2_power_on(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
207*cf4fd52eSDaniel Almeida     regs::L2_PWRON_LO.write(dev, iomem, 1)?;
208*cf4fd52eSDaniel Almeida 
209*cf4fd52eSDaniel Almeida     // TODO: We cannot poll, as there is no support in Rust currently, so we
210*cf4fd52eSDaniel Almeida     // sleep. Change this when read_poll_timeout() is implemented in Rust.
211*cf4fd52eSDaniel Almeida     kernel::time::delay::fsleep(time::Delta::from_millis(100));
212*cf4fd52eSDaniel Almeida 
213*cf4fd52eSDaniel Almeida     if regs::L2_READY_LO.read(dev, iomem)? != 1 {
214*cf4fd52eSDaniel Almeida         dev_err!(dev, "Failed to power on the GPU\n");
215*cf4fd52eSDaniel Almeida         return Err(EIO);
216*cf4fd52eSDaniel Almeida     }
217*cf4fd52eSDaniel Almeida 
218*cf4fd52eSDaniel Almeida     Ok(())
219*cf4fd52eSDaniel Almeida }
220