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