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