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 core::ops::{
4 Deref,
5 DerefMut, //
6};
7use 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
22use 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)]
35pub(crate) struct GpuInfo(pub(crate) uapi::drm_panthor_gpu_info);
36
37impl 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
148impl Deref for GpuInfo {
149 type Target = uapi::drm_panthor_gpu_info;
150
151 fn deref(&self) -> &Self::Target {
152 &self.0
153 }
154}
155
156impl 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.
171unsafe impl AsBytes for GpuInfo {}
172
173struct GpuModels {
174 name: &'static str,
175 arch_major: u32,
176 prod_major: u32,
177}
178
179const GPU_MODELS: [GpuModels; 1] = [GpuModels {
180 name: "g610",
181 arch_major: 10,
182 prod_major: 7,
183}];
184
185#[allow(dead_code)]
186pub(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
196impl 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.
211pub(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}