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