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