Skip to content

Commit cf4fd52

Browse files
danielalmeida-collaboraDarksonn
authored andcommitted
rust: drm: Introduce the Tyr driver for Arm Mali GPUs
Add a Rust driver for ARM Mali CSF-based GPUs. It is a port of Panthor and therefore exposes Panthor's uAPI and name to userspace, and the product of a joint effort between Collabora, Arm and Google engineers. The aim is to incrementally develop Tyr with the abstractions that are currently available until it is consider to be in parity with Panthor feature-wise. The development of Tyr itself started in January, after a few failed attempts of converting Panthor piecewise through a mix of Rust and C code. There is a downstream branch that's much further ahead in terms of capabilities than this initial patch. The downstream code is capable of booting the MCU, doing sync VM_BINDS through the work-in-progress GPUVM abstraction and also doing (trivial) submits through Asahi's drm_scheduler and dma_fence abstractions. So basically, most of what one would expect a modern GPU driver to do, except for power management and some other very important adjacent pieces. It is not at the point where submits can correctly deal with dependencies, or at the point where it can rotate access to the GPU hardware fairly through a software scheduler, but that is simply a matter of writing more code. This first patch, however, only implements a subset of the current features available downstream, as the rest is not implementable without pulling in even more abstractions. In particular, a lot of things depend on properly mapping memory on a given VA range, which itself depends on the GPUVM abstraction that is currently work-in-progress. For this reason, we still cannot boot the MCU and thus, cannot do much for the moment. This constitutes a change in the overall strategy that we have been using to develop Tyr so far. By submitting small parts of the driver upstream iteratively, we aim to: a) evolve together with Nova and rvkms, hopefully reducing regressions due to upstream changes (that may break us because we were not there, in the first place) b) prove any work-in-progress abstractions by having them run on a real driver and hardware and, c) provide a reason to work on and review said abstractions by providing a user, which would be tyr itself. Despite its limited feature-set, we offer IGT tests. It is only tested on the rk3588, so any other SoC is probably not going to work at all for now. The skeleton is basically taken from Nova and also rust_platform_driver.rs. Lastly, the name "Tyr" is inspired by Norse mythology, reflecting ARM's tradition of naming their GPUs after Nordic mythological figures and places. Co-developed-by: Beata Michalska <beata.michalska@arm.com> Signed-off-by: Beata Michalska <beata.michalska@arm.com> Co-developed-by: Carsten Haitzler <carsten.haitzler@foss.arm.com> Signed-off-by: Carsten Haitzler <carsten.haitzler@foss.arm.com> Co-developed-by: Rob Herring <robh@kernel.org> Signed-off-by: Rob Herring <robh@kernel.org> Link: https://www.collabora.com/news-and-blog/news-and-events/introducing-tyr-a-new-rust-drm-driver.html Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com> Acked-by: Boris Brezillon <boris.brezillon@collabora.com> [aliceryhl: minor Kconfig update on apply] [aliceryhl: s/drm::device::/drm::/] Link: https://lore.kernel.org/r/20250910-tyr-v3-1-dba3bc2ae623@collabora.com Co-developed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
1 parent d4dc08c commit cf4fd52

12 files changed

Lines changed: 667 additions & 0 deletions

File tree

MAINTAINERS

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,6 +2086,19 @@ F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
20862086
F: drivers/gpu/drm/panthor/
20872087
F: include/uapi/drm/panthor_drm.h
20882088

2089+
ARM MALI TYR DRM DRIVER
2090+
M: Daniel Almeida <daniel.almeida@collabora.com>
2091+
M: Alice Ryhl <aliceryhl@google.com>
2092+
L: dri-devel@lists.freedesktop.org
2093+
S: Supported
2094+
W: https://rust-for-linux.com/tyr-gpu-driver
2095+
W https://drm.pages.freedesktop.org/maintainer-tools/drm-rust.html
2096+
B: https://gitlab.freedesktop.org/panfrost/linux/-/issues
2097+
T: git https://gitlab.freedesktop.org/drm/rust/kernel.git
2098+
F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
2099+
F: drivers/gpu/drm/tyr/
2100+
F: include/uapi/drm/panthor_drm.h
2101+
20892102
ARM MALI-DP DRM DRIVER
20902103
M: Liviu Dudau <liviu.dudau@arm.com>
20912104
S: Supported

drivers/gpu/drm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ source "drivers/gpu/drm/sprd/Kconfig"
396396

397397
source "drivers/gpu/drm/imagination/Kconfig"
398398

399+
source "drivers/gpu/drm/tyr/Kconfig"
400+
399401
config DRM_HYPERV
400402
tristate "DRM Support for Hyper-V synthetic video device"
401403
depends on DRM && PCI && HYPERV

drivers/gpu/drm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
220220
obj-$(CONFIG_DRM_LIMA) += lima/
221221
obj-$(CONFIG_DRM_PANFROST) += panfrost/
222222
obj-$(CONFIG_DRM_PANTHOR) += panthor/
223+
obj-$(CONFIG_DRM_TYR) += tyr/
223224
obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
224225
obj-$(CONFIG_DRM_MCDE) += mcde/
225226
obj-$(CONFIG_DRM_TIDSS) += tidss/

drivers/gpu/drm/tyr/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-License-Identifier: GPL-2.0 or MIT
2+
3+
config DRM_TYR
4+
tristate "Tyr (Rust DRM support for ARM Mali CSF-based GPUs)"
5+
depends on DRM=y
6+
depends on RUST
7+
depends on ARM || ARM64 || COMPILE_TEST
8+
depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE
9+
default n
10+
help
11+
Rust DRM driver for ARM Mali CSF-based GPUs.
12+
13+
This driver is for Mali (or Immortalis) Valhall Gxxx GPUs.
14+
15+
Note that the Mali-G68 and Mali-G78, while Valhall architecture, will
16+
be supported with the panfrost driver as they are not CSF GPUs.
17+
18+
if M is selected, the module will be called tyr. This driver is work
19+
in progress and may not be functional.

drivers/gpu/drm/tyr/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SPDX-License-Identifier: GPL-2.0 or MIT
2+
3+
obj-$(CONFIG_DRM_TYR) += tyr.o

drivers/gpu/drm/tyr/driver.rs

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// SPDX-License-Identifier: GPL-2.0 or MIT
2+
3+
use kernel::c_str;
4+
use kernel::clk::Clk;
5+
use kernel::clk::OptionalClk;
6+
use kernel::device::Bound;
7+
use kernel::device::Core;
8+
use kernel::device::Device;
9+
use kernel::devres::Devres;
10+
use kernel::drm;
11+
use kernel::drm::ioctl;
12+
use kernel::new_mutex;
13+
use kernel::of;
14+
use kernel::platform;
15+
use kernel::prelude::*;
16+
use kernel::regulator;
17+
use kernel::regulator::Regulator;
18+
use kernel::sizes::SZ_2M;
19+
use kernel::sync::Arc;
20+
use kernel::sync::Mutex;
21+
use kernel::time;
22+
use kernel::types::ARef;
23+
24+
use crate::file::File;
25+
use crate::gem::TyrObject;
26+
use crate::gpu;
27+
use crate::gpu::GpuInfo;
28+
use crate::regs;
29+
30+
pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;
31+
32+
/// Convenience type alias for the DRM device type for this driver.
33+
pub(crate) type TyrDevice = drm::Device<TyrDriver>;
34+
35+
#[pin_data(PinnedDrop)]
36+
pub(crate) struct TyrDriver {
37+
device: ARef<TyrDevice>,
38+
}
39+
40+
#[pin_data(PinnedDrop)]
41+
pub(crate) struct TyrData {
42+
pub(crate) pdev: ARef<platform::Device>,
43+
44+
#[pin]
45+
clks: Mutex<Clocks>,
46+
47+
#[pin]
48+
regulators: Mutex<Regulators>,
49+
50+
/// Some information on the GPU.
51+
///
52+
/// This is mainly queried by userspace, i.e.: Mesa.
53+
pub(crate) gpu_info: GpuInfo,
54+
}
55+
56+
// Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they
57+
// should. There are patches on the mailing list to address this, but they have
58+
// not landed yet.
59+
//
60+
// For now, add this workaround so that this patch compiles with the promise
61+
// that it will be removed in a future patch.
62+
//
63+
// SAFETY: This will be removed in a future patch.
64+
unsafe impl Send for TyrData {}
65+
// SAFETY: This will be removed in a future patch.
66+
unsafe impl Sync for TyrData {}
67+
68+
fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
69+
regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;
70+
71+
// TODO: We cannot poll, as there is no support in Rust currently, so we
72+
// sleep. Change this when read_poll_timeout() is implemented in Rust.
73+
kernel::time::delay::fsleep(time::Delta::from_millis(100));
74+
75+
if regs::GPU_IRQ_RAWSTAT.read(dev, iomem)? & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED == 0 {
76+
dev_err!(dev, "GPU reset failed with errno\n");
77+
dev_err!(
78+
dev,
79+
"GPU_INT_RAWSTAT is {}\n",
80+
regs::GPU_IRQ_RAWSTAT.read(dev, iomem)?
81+
);
82+
83+
return Err(EIO);
84+
}
85+
86+
Ok(())
87+
}
88+
89+
kernel::of_device_table!(
90+
OF_TABLE,
91+
MODULE_OF_TABLE,
92+
<TyrDriver as platform::Driver>::IdInfo,
93+
[
94+
(of::DeviceId::new(c_str!("rockchip,rk3588-mali")), ()),
95+
(of::DeviceId::new(c_str!("arm,mali-valhall-csf")), ())
96+
]
97+
);
98+
99+
impl platform::Driver for TyrDriver {
100+
type IdInfo = ();
101+
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
102+
103+
fn probe(
104+
pdev: &platform::Device<Core>,
105+
_info: Option<&Self::IdInfo>,
106+
) -> Result<Pin<KBox<Self>>> {
107+
let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?;
108+
let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?;
109+
let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?;
110+
111+
core_clk.prepare_enable()?;
112+
stacks_clk.prepare_enable()?;
113+
coregroup_clk.prepare_enable()?;
114+
115+
let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("mali"))?;
116+
let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("sram"))?;
117+
118+
let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
119+
let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
120+
121+
issue_soft_reset(pdev.as_ref(), &iomem)?;
122+
gpu::l2_power_on(pdev.as_ref(), &iomem)?;
123+
124+
let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?;
125+
gpu_info.log(pdev);
126+
127+
let platform: ARef<platform::Device> = pdev.into();
128+
129+
let data = try_pin_init!(TyrData {
130+
pdev: platform.clone(),
131+
clks <- new_mutex!(Clocks {
132+
core: core_clk,
133+
stacks: stacks_clk,
134+
coregroup: coregroup_clk,
135+
}),
136+
regulators <- new_mutex!(Regulators {
137+
mali: mali_regulator,
138+
sram: sram_regulator,
139+
}),
140+
gpu_info,
141+
});
142+
143+
let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?;
144+
drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?;
145+
146+
let driver = KBox::pin_init(try_pin_init!(TyrDriver { device: tdev }), GFP_KERNEL)?;
147+
148+
// We need this to be dev_info!() because dev_dbg!() does not work at
149+
// all in Rust for now, and we need to see whether probe succeeded.
150+
dev_info!(pdev.as_ref(), "Tyr initialized correctly.\n");
151+
Ok(driver)
152+
}
153+
}
154+
155+
#[pinned_drop]
156+
impl PinnedDrop for TyrDriver {
157+
fn drop(self: Pin<&mut Self>) {}
158+
}
159+
160+
#[pinned_drop]
161+
impl PinnedDrop for TyrData {
162+
fn drop(self: Pin<&mut Self>) {
163+
// TODO: the type-state pattern for Clks will fix this.
164+
let clks = self.clks.lock();
165+
clks.core.disable_unprepare();
166+
clks.stacks.disable_unprepare();
167+
clks.coregroup.disable_unprepare();
168+
}
169+
}
170+
171+
// We need to retain the name "panthor" to achieve drop-in compatibility with
172+
// the C driver in the userspace stack.
173+
const INFO: drm::DriverInfo = drm::DriverInfo {
174+
major: 1,
175+
minor: 5,
176+
patchlevel: 0,
177+
name: c_str!("panthor"),
178+
desc: c_str!("ARM Mali Tyr DRM driver"),
179+
};
180+
181+
#[vtable]
182+
impl drm::Driver for TyrDriver {
183+
type Data = TyrData;
184+
type File = File;
185+
type Object = drm::gem::Object<TyrObject>;
186+
187+
const INFO: drm::DriverInfo = INFO;
188+
189+
kernel::declare_drm_ioctls! {
190+
(PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, File::dev_query),
191+
}
192+
}
193+
194+
#[pin_data]
195+
struct Clocks {
196+
core: Clk,
197+
stacks: OptionalClk,
198+
coregroup: OptionalClk,
199+
}
200+
201+
#[pin_data]
202+
struct Regulators {
203+
mali: Regulator<regulator::Enabled>,
204+
sram: Regulator<regulator::Enabled>,
205+
}

drivers/gpu/drm/tyr/file.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: GPL-2.0 or MIT
2+
3+
use kernel::drm;
4+
use kernel::prelude::*;
5+
use kernel::uaccess::UserSlice;
6+
use kernel::uapi;
7+
8+
use crate::driver::TyrDevice;
9+
use crate::TyrDriver;
10+
11+
#[pin_data]
12+
pub(crate) struct File {}
13+
14+
/// Convenience type alias for our DRM `File` type
15+
pub(crate) type DrmFile = drm::file::File<File>;
16+
17+
impl drm::file::DriverFile for File {
18+
type Driver = TyrDriver;
19+
20+
fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> {
21+
KBox::try_pin_init(try_pin_init!(Self {}), GFP_KERNEL)
22+
}
23+
}
24+
25+
impl File {
26+
pub(crate) fn dev_query(
27+
tdev: &TyrDevice,
28+
devquery: &mut uapi::drm_panthor_dev_query,
29+
_file: &DrmFile,
30+
) -> Result<u32> {
31+
if devquery.pointer == 0 {
32+
match devquery.type_ {
33+
uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => {
34+
devquery.size = core::mem::size_of_val(&tdev.gpu_info) as u32;
35+
Ok(0)
36+
}
37+
_ => Err(EINVAL),
38+
}
39+
} else {
40+
match devquery.type_ {
41+
uapi::drm_panthor_dev_query_type_DRM_PANTHOR_DEV_QUERY_GPU_INFO => {
42+
let mut writer = UserSlice::new(
43+
UserPtr::from_addr(devquery.pointer as usize),
44+
devquery.size as usize,
45+
)
46+
.writer();
47+
48+
writer.write(&tdev.gpu_info)?;
49+
50+
Ok(0)
51+
}
52+
_ => Err(EINVAL),
53+
}
54+
}
55+
}
56+
}

drivers/gpu/drm/tyr/gem.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: GPL-2.0 or MIT
2+
3+
use crate::driver::TyrDevice;
4+
use crate::driver::TyrDriver;
5+
use kernel::drm::gem;
6+
use kernel::prelude::*;
7+
8+
/// GEM Object inner driver data
9+
#[pin_data]
10+
pub(crate) struct TyrObject {}
11+
12+
impl gem::DriverObject for TyrObject {
13+
type Driver = TyrDriver;
14+
15+
fn new(_dev: &TyrDevice, _size: usize) -> impl PinInit<Self, Error> {
16+
try_pin_init!(TyrObject {})
17+
}
18+
}

0 commit comments

Comments
 (0)