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