// SPDX-License-Identifier: GPL-2.0 or MIT use core::ops::{ Deref, DerefMut, // }; use kernel::{ device::{ Bound, Device, // }, io::{ poll, register::Array, Io, // }, prelude::*, time::Delta, transmute::AsBytes, uapi, // }; use crate::{ driver::IoMem, regs::{ gpu_control::*, join_u64, // }, // }; /// Struct containing information that can be queried by userspace. This is read from /// the GPU's registers. /// /// # Invariants /// /// - The layout of this struct is identical to the C `struct drm_panthor_gpu_info`. #[repr(transparent)] #[derive(Clone, Copy)] pub(crate) struct GpuInfo(pub(crate) uapi::drm_panthor_gpu_info); impl GpuInfo { pub(crate) fn new(io: &IoMem<'_>) -> Self { Self(uapi::drm_panthor_gpu_info { gpu_id: io.read(GPU_ID).into_raw(), gpu_rev: io.read(REVIDR).into_raw(), csf_id: io.read(CSF_ID).into_raw(), l2_features: io.read(L2_FEATURES).into_raw(), tiler_features: io.read(TILER_FEATURES).into_raw(), mem_features: io.read(MEM_FEATURES).into_raw(), mmu_features: io.read(MMU_FEATURES).into_raw(), thread_features: io.read(THREAD_FEATURES).into_raw(), max_threads: io.read(THREAD_MAX_THREADS).into_raw(), thread_max_workgroup_size: io.read(THREAD_MAX_WORKGROUP_SIZE).into_raw(), thread_max_barrier_size: io.read(THREAD_MAX_BARRIER_SIZE).into_raw(), coherency_features: io.read(COHERENCY_FEATURES).into_raw(), texture_features: [ io.read(TEXTURE_FEATURES::at(0)).supported_formats().get(), io.read(TEXTURE_FEATURES::at(1)).supported_formats().get(), io.read(TEXTURE_FEATURES::at(2)).supported_formats().get(), io.read(TEXTURE_FEATURES::at(3)).supported_formats().get(), ], as_present: io.read(AS_PRESENT).into_raw(), selected_coherency: uapi::drm_panthor_gpu_coherency_DRM_PANTHOR_GPU_COHERENCY_NONE, shader_present: join_u64( io.read(SHADER_PRESENT_LO).into_raw(), io.read(SHADER_PRESENT_HI).into_raw(), ), l2_present: join_u64( io.read(L2_PRESENT_LO).into_raw(), io.read(L2_PRESENT_HI).into_raw(), ), tiler_present: join_u64( io.read(TILER_PRESENT_LO).into_raw(), io.read(TILER_PRESENT_HI).into_raw(), ), core_features: io.read(CORE_FEATURES).into_raw(), // Padding must be zero. pad: 0, //GPU_FEATURES register is not available; it was introduced in arch 11.x. gpu_features: 0, }) } pub(crate) fn log(&self, dev: &Device) { let gpu_id = GPU_ID::from_raw(self.gpu_id); let model_name = if let Some(model) = GPU_MODELS.iter().find(|&f| { f.arch_major == gpu_id.arch_major().get() && f.prod_major == gpu_id.prod_major().get() }) { model.name } else { "unknown" }; dev_info!( dev, "mali-{} GPU_ID 0x{:x} major 0x{:x} minor 0x{:x} status 0x{:x}", model_name, gpu_id.into_raw(), gpu_id.ver_major().get(), gpu_id.ver_minor().get(), gpu_id.ver_status().get() ); dev_info!( dev, "Features: L2:{:#x} Tiler:{:#x} Mem:{:#x} MMU:{:#x} AS:{:#x}", self.l2_features, self.tiler_features, self.mem_features, self.mmu_features, self.as_present, ); dev_info!( dev, "shader_present=0x{:016x} l2_present=0x{:016x} tiler_present=0x{:016x}", self.shader_present, self.l2_present, self.tiler_present, ); } } impl Deref for GpuInfo { type Target = uapi::drm_panthor_gpu_info; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for GpuInfo { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } // SAFETY: `GpuInfo`'s invariant guarantees that it is the same type that is // already exposed to userspace by the C driver. This implies that it fulfills // the requirements for `AsBytes`. // // This means: // // - No implicit padding, // - No kernel pointers, // - No interior mutability. unsafe impl AsBytes for GpuInfo {} struct GpuModels { name: &'static str, arch_major: u32, prod_major: u32, } const GPU_MODELS: [GpuModels; 1] = [GpuModels { name: "g610", arch_major: 10, prod_major: 7, }]; /// Powers on the l2 block. pub(crate) fn l2_power_on(dev: &Device, io: &IoMem<'_>) -> Result { io.write_reg(L2_PWRON_LO::zeroed().with_const_request::<1>()); poll::read_poll_timeout( || Ok(io.read(L2_READY_LO)), |status| status.ready() == 1, Delta::from_millis(1), Delta::from_millis(100), ) .inspect_err(|_| dev_err!(dev, "Failed to power on the GPU."))?; Ok(()) }