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