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