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