Files
linux/drivers/gpu/drm/tyr/gpu.rs
Deborah Brouwer ef2964f11e drm/tyr: Use vertical style for imports
Currently Tyr uses rustfmt style for imports, but the kernel uses a
vertical layout that makes it easier to resolve conflicts and rebase.

Import guidelines are documented here:
	https://docs.kernel.org/rust/coding-guidelines.html#imports

Change all of Tyr's imports to use the vertical layout. This will
ease the introduction of additional Tyr patches upstream.

There should be no functional changes in this patch.

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Deborah Brouwer <deborah.brouwer@collabora.com>
Link: https://patch.msgid.link/20260223203833.207955-1-deborah.brouwer@collabora.com
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
2026-02-24 07:21:26 +00:00

224 lines
6.6 KiB
Rust

// SPDX-License-Identifier: GPL-2.0 or MIT
use core::ops::{
Deref,
DerefMut, //
};
use kernel::{
bits::genmask_u32,
device::{
Bound,
Device, //
},
devres::Devres,
io::poll,
platform,
prelude::*,
time::Delta,
transmute::AsBytes,
uapi, //
};
use crate::{
driver::IoMem,
regs, //
};
/// Struct containing information that can be queried by userspace. This is read from
/// the GPU's registers.
///
/// # Invariants
///
/// - The layout of this struct 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(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result<Self> {
let gpu_id = regs::GPU_ID.read(dev, iomem)?;
let csf_id = regs::GPU_CSF_ID.read(dev, iomem)?;
let gpu_rev = regs::GPU_REVID.read(dev, iomem)?;
let core_features = regs::GPU_CORE_FEATURES.read(dev, iomem)?;
let l2_features = regs::GPU_L2_FEATURES.read(dev, iomem)?;
let tiler_features = regs::GPU_TILER_FEATURES.read(dev, iomem)?;
let mem_features = regs::GPU_MEM_FEATURES.read(dev, iomem)?;
let mmu_features = regs::GPU_MMU_FEATURES.read(dev, iomem)?;
let thread_features = regs::GPU_THREAD_FEATURES.read(dev, iomem)?;
let max_threads = regs::GPU_THREAD_MAX_THREADS.read(dev, iomem)?;
let thread_max_workgroup_size = regs::GPU_THREAD_MAX_WORKGROUP_SIZE.read(dev, iomem)?;
let thread_max_barrier_size = regs::GPU_THREAD_MAX_BARRIER_SIZE.read(dev, iomem)?;
let coherency_features = regs::GPU_COHERENCY_FEATURES.read(dev, iomem)?;
let texture_features = regs::GPU_TEXTURE_FEATURES0.read(dev, iomem)?;
let as_present = regs::GPU_AS_PRESENT.read(dev, iomem)?;
let shader_present = u64::from(regs::GPU_SHADER_PRESENT_LO.read(dev, iomem)?);
let shader_present =
shader_present | u64::from(regs::GPU_SHADER_PRESENT_HI.read(dev, iomem)?) << 32;
let tiler_present = u64::from(regs::GPU_TILER_PRESENT_LO.read(dev, iomem)?);
let tiler_present =
tiler_present | u64::from(regs::GPU_TILER_PRESENT_HI.read(dev, iomem)?) << 32;
let l2_present = u64::from(regs::GPU_L2_PRESENT_LO.read(dev, iomem)?);
let l2_present = l2_present | u64::from(regs::GPU_L2_PRESENT_HI.read(dev, iomem)?) << 32;
Ok(Self(uapi::drm_panthor_gpu_info {
gpu_id,
gpu_rev,
csf_id,
l2_features,
tiler_features,
mem_features,
mmu_features,
thread_features,
max_threads,
thread_max_workgroup_size,
thread_max_barrier_size,
coherency_features,
// TODO: Add texture_features_{1,2,3}.
texture_features: [texture_features, 0, 0, 0],
as_present,
selected_coherency: uapi::drm_panthor_gpu_coherency_DRM_PANTHOR_GPU_COHERENCY_NONE,
shader_present,
l2_present,
tiler_present,
core_features,
pad: 0,
gpu_features: 0,
}))
}
pub(crate) fn log(&self, pdev: &platform::Device) {
let gpu_id = GpuId::from(self.gpu_id);
let model_name = if let Some(model) = GPU_MODELS
.iter()
.find(|&f| f.arch_major == gpu_id.arch_major && f.prod_major == gpu_id.prod_major)
{
model.name
} else {
"unknown"
};
dev_info!(
pdev,
"mali-{} id 0x{:x} major 0x{:x} minor 0x{:x} status 0x{:x}",
model_name,
self.gpu_id >> 16,
gpu_id.ver_major,
gpu_id.ver_minor,
gpu_id.ver_status
);
dev_info!(
pdev,
"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!(
pdev,
"shader_present=0x{:016x} l2_present=0x{:016x} tiler_present=0x{:016x}",
self.shader_present,
self.l2_present,
self.tiler_present
);
}
/// Returns the number of virtual address bits supported by the GPU.
#[expect(dead_code)]
pub(crate) fn va_bits(&self) -> u32 {
self.mmu_features & genmask_u32(0..=7)
}
/// Returns the number of physical address bits supported by the GPU.
#[expect(dead_code)]
pub(crate) fn pa_bits(&self) -> u32 {
(self.mmu_features >> 8) & genmask_u32(0..=7)
}
}
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,
}];
#[allow(dead_code)]
pub(crate) struct GpuId {
pub(crate) arch_major: u32,
pub(crate) arch_minor: u32,
pub(crate) arch_rev: u32,
pub(crate) prod_major: u32,
pub(crate) ver_major: u32,
pub(crate) ver_minor: u32,
pub(crate) ver_status: u32,
}
impl From<u32> for GpuId {
fn from(value: u32) -> Self {
GpuId {
arch_major: (value & genmask_u32(28..=31)) >> 28,
arch_minor: (value & genmask_u32(24..=27)) >> 24,
arch_rev: (value & genmask_u32(20..=23)) >> 20,
prod_major: (value & genmask_u32(16..=19)) >> 16,
ver_major: (value & genmask_u32(12..=15)) >> 12,
ver_minor: (value & genmask_u32(4..=11)) >> 4,
ver_status: value & genmask_u32(0..=3),
}
}
}
/// Powers on the l2 block.
pub(crate) fn l2_power_on(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
regs::L2_PWRON_LO.write(dev, iomem, 1)?;
poll::read_poll_timeout(
|| regs::L2_READY_LO.read(dev, iomem),
|status| *status == 1,
Delta::from_millis(1),
Delta::from_millis(100),
)
.inspect_err(|_| dev_err!(dev, "Failed to power on the GPU."))?;
Ok(())
}