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