Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0 or MIT
config DRM_TYR
tristate "Tyr (Rust DRM support for ARM Mali CSF-based GPUs)"
depends on DRM=y
depends on RUST
depends on ARM || ARM64 || COMPILE_TEST
depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE
depends on COMMON_CLK
default n
select RUST_DRM_GEM_SHMEM_HELPER
help
Rust DRM driver for ARM Mali CSF-based GPUs.
This driver is for Mali (or Immortalis) Valhall Gxxx GPUs.
Note that the Mali-G68 and Mali-G78, while Valhall architecture, will
be supported with the panfrost driver as they are not CSF GPUs.
if M is selected, the module will be called tyr. This driver is work
in progress and may not be functional.
+3
View File
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0 or MIT
obj-$(CONFIG_DRM_TYR) += tyr.o
+211
View File
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
use kernel::{
clk::{
Clk,
OptionalClk, //
},
device::{
Core,
Device, //
},
dma::{
Device as DmaDevice,
DmaMask, //
},
drm,
drm::ioctl,
io::{
poll,
Io, //
},
new_mutex,
of,
platform,
prelude::*,
regulator,
regulator::Regulator,
sizes::SZ_2M,
sync::{
aref::ARef,
Mutex, //
},
time, //
};
use crate::{
file::TyrDrmFileData,
gem::BoData,
gpu,
gpu::GpuInfo,
regs::gpu_control::*, //
};
pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
pub(crate) struct TyrDrmDriver;
/// Convenience type alias for the DRM device type for this driver.
pub(crate) type TyrDrmDevice<Ctx = drm::Registered> = drm::Device<TyrDrmDriver, Ctx>;
pub(crate) struct TyrPlatformDriver;
#[pin_data(PinnedDrop)]
pub(crate) struct TyrPlatformDriverData {
_device: ARef<TyrDrmDevice>,
}
#[pin_data]
pub(crate) struct TyrDrmDeviceData {
pub(crate) pdev: ARef<platform::Device>,
#[pin]
clks: Mutex<Clocks>,
#[pin]
regulators: Mutex<Regulators>,
/// Some information on the GPU.
///
/// This is mainly queried by userspace, i.e.: Mesa.
pub(crate) gpu_info: GpuInfo,
}
fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
poll::read_poll_timeout(
|| Ok(iomem.read(GPU_IRQ_RAWSTAT)),
|status| status.reset_completed(),
time::Delta::from_millis(1),
time::Delta::from_millis(100),
)
.inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
Ok(())
}
kernel::of_device_table!(
OF_TABLE,
MODULE_OF_TABLE,
<TyrPlatformDriver as platform::Driver>::IdInfo,
[
(of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
(of::DeviceId::new(c"arm,mali-valhall-csf"), ())
]
);
impl platform::Driver for TyrPlatformDriver {
type IdInfo = ();
type Data<'bound> = TyrPlatformDriverData;
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
fn probe<'bound>(
pdev: &'bound platform::Device<Core<'_>>,
_info: Option<&'bound Self::IdInfo>,
) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
core_clk.prepare_enable()?;
stacks_clk.prepare_enable()?;
coregroup_clk.prepare_enable()?;
let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
let iomem = request.iomap_sized::<SZ_2M>()?;
issue_soft_reset(pdev.as_ref(), &iomem)?;
gpu::l2_power_on(pdev.as_ref(), &iomem)?;
let gpu_info = GpuInfo::new(&iomem);
gpu_info.log(pdev.as_ref());
let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features)
.pa_bits()
.get();
// SAFETY: No concurrent DMA allocations or mappings can be made because
// the device is still being probed and therefore isn't being used by
// other threads of execution.
unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? };
let platform: ARef<platform::Device> = pdev.into();
let data = try_pin_init!(TyrDrmDeviceData {
pdev: platform.clone(),
clks <- new_mutex!(Clocks {
core: core_clk,
stacks: stacks_clk,
coregroup: coregroup_clk,
}),
regulators <- new_mutex!(Regulators {
_mali: mali_regulator,
_sram: sram_regulator,
}),
gpu_info,
});
let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev.as_ref(), data)?;
let tdev = drm::driver::Registration::new_foreign_owned(tdev, pdev.as_ref(), 0)?;
let driver = TyrPlatformDriverData {
_device: tdev.into(),
};
// We need this to be dev_info!() because dev_dbg!() does not work at
// all in Rust for now, and we need to see whether probe succeeded.
dev_info!(pdev, "Tyr initialized correctly.\n");
Ok(driver)
}
}
#[pinned_drop]
impl PinnedDrop for TyrPlatformDriverData {
fn drop(self: Pin<&mut Self>) {}
}
// We need to retain the name "panthor" to achieve drop-in compatibility with
// the C driver in the userspace stack.
const INFO: drm::DriverInfo = drm::DriverInfo {
major: 1,
minor: 5,
patchlevel: 0,
name: c"panthor",
desc: c"ARM Mali Tyr DRM driver",
};
#[vtable]
impl drm::Driver for TyrDrmDriver {
type Data = TyrDrmDeviceData;
type File = TyrDrmFileData;
type Object<R: drm::DeviceContext> = drm::gem::shmem::Object<BoData, R>;
const INFO: drm::DriverInfo = INFO;
const FEAT_RENDER: bool = true;
kernel::declare_drm_ioctls! {
(PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
}
}
struct Clocks {
core: Clk,
stacks: OptionalClk,
coregroup: OptionalClk,
}
impl Drop for Clocks {
fn drop(&mut self) {
self.core.disable_unprepare();
self.stacks.disable_unprepare();
self.coregroup.disable_unprepare();
}
}
struct Regulators {
_mali: Regulator<regulator::Enabled>,
_sram: Regulator<regulator::Enabled>,
}
+60
View File
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
use kernel::{
drm,
prelude::*,
uaccess::UserSlice,
uapi, //
};
use crate::driver::{
TyrDrmDevice,
TyrDrmDriver, //
};
#[pin_data]
pub(crate) struct TyrDrmFileData {}
/// Convenience type alias for our DRM `File` type
pub(crate) type TyrDrmFile = drm::file::File<TyrDrmFileData>;
impl drm::file::DriverFile for TyrDrmFileData {
type Driver = TyrDrmDriver;
fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> {
KBox::try_pin_init(try_pin_init!(Self {}), GFP_KERNEL)
}
}
impl TyrDrmFileData {
pub(crate) fn dev_query(
ddev: &TyrDrmDevice,
devquery: &mut uapi::drm_panthor_dev_query,
_file: &TyrDrmFile,
) -> Result<u32> {
if devquery.pointer == 0 {
match devquery.type_ {
uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => {
devquery.size = core::mem::size_of_val(&ddev.gpu_info) as u32;
Ok(0)
}
_ => Err(EINVAL),
}
} else {
match devquery.type_ {
uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => {
let mut writer = UserSlice::new(
UserPtr::from_addr(devquery.pointer as usize),
devquery.size as usize,
)
.writer();
writer.write(&ddev.gpu_info)?;
Ok(0)
}
_ => Err(EINVAL),
}
}
}
}
+43
View File
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
//! GEM buffer object management for the Tyr driver.
//!
//! This module provides buffer object (BO) management functionality using
//! DRM's GEM subsystem with shmem backing.
use kernel::{
drm::{
gem,
DeviceContext, //
},
prelude::*, //
};
use crate::driver::{
TyrDrmDevice,
TyrDrmDriver, //
};
/// Tyr's DriverObject type for GEM objects.
#[pin_data]
pub(crate) struct BoData {
flags: u32,
}
/// Provides a way to pass arguments when creating BoData
/// as required by the gem::DriverObject trait.
pub(crate) struct BoCreateArgs {
flags: u32,
}
impl gem::DriverObject for BoData {
type Driver = TyrDrmDriver;
type Args = BoCreateArgs;
fn new<Ctx: DeviceContext>(
_dev: &TyrDrmDevice<Ctx>,
_size: usize,
args: BoCreateArgs,
) -> impl PinInit<Self, Error> {
try_pin_init!(Self { flags: args.flags })
}
}
+175
View File
@@ -0,0 +1,175 @@
// 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<Bound>) {
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(())
}
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0 or MIT
//! Arm Mali Tyr DRM driver.
//!
//! The name "Tyr" is inspired by Norse mythology, reflecting Arm's tradition of
//! naming their GPUs after Nordic mythological figures and places.
use crate::driver::TyrPlatformDriver;
mod driver;
mod file;
mod gem;
mod gpu;
mod regs;
kernel::module_platform_driver! {
type: TyrPlatformDriver,
name: "tyr",
authors: ["The Tyr driver authors"],
description: "Arm Mali Tyr DRM driver",
license: "Dual MIT/GPL",
}