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 12 use crate::driver::IoMem; 13 use 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)] 22 pub(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 45 impl 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. 166 unsafe impl AsBytes for GpuInfo {} 167 168 struct GpuModels { 169 name: &'static str, 170 major: u32, 171 minor: u32, 172 } 173 174 const GPU_MODELS: [GpuModels; 1] = [GpuModels { 175 name: "g610", 176 major: 10, 177 minor: 7, 178 }]; 179 180 #[allow(dead_code)] 181 pub(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 191 impl 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. 206 pub(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 } 220