mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Currently the `TyrDriver` struct implements both `platform::Driver` and `drm::Driver`. For clarity, split up these two roles: - Introduce `TyrPlatformDriverData` to implement `platform::Driver`, and - Introduce `TyrDrmDriver` to implement `drm::Driver`. Also rename other variables to reflect their roles in the DRM context: - Rename `TyrDevice` to `TyrDrmDevice` - Rename `TyrData` to `TyrDrmDeviceData` - Rename `File` to `TyrDrmFileData` - Rename `DrmFile` to `TyrDrmFile` No functional changes are intended. Co-developed-by: Boris Brezillon <boris.brezillon@collabora.com> Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Signed-off-by: Deborah Brouwer <deborah.brouwer@collabora.com> Link: https://patch.msgid.link/20260224002314.344675-1-deborah.brouwer@collabora.com Signed-off-by: Alice Ryhl <aliceryhl@google.com>
211 lines
5.6 KiB
Rust
211 lines
5.6 KiB
Rust
// SPDX-License-Identifier: GPL-2.0 or MIT
|
|
|
|
use kernel::{
|
|
clk::{
|
|
Clk,
|
|
OptionalClk, //
|
|
},
|
|
device::{
|
|
Bound,
|
|
Core,
|
|
Device, //
|
|
},
|
|
devres::Devres,
|
|
drm,
|
|
drm::ioctl,
|
|
io::poll,
|
|
new_mutex,
|
|
of,
|
|
platform,
|
|
prelude::*,
|
|
regulator,
|
|
regulator::Regulator,
|
|
sizes::SZ_2M,
|
|
sync::{
|
|
aref::ARef,
|
|
Arc,
|
|
Mutex, //
|
|
},
|
|
time, //
|
|
};
|
|
|
|
use crate::{
|
|
file::TyrDrmFileData,
|
|
gem::TyrObject,
|
|
gpu,
|
|
gpu::GpuInfo,
|
|
regs, //
|
|
};
|
|
|
|
pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;
|
|
|
|
pub(crate) struct TyrDrmDriver;
|
|
|
|
/// Convenience type alias for the DRM device type for this driver.
|
|
pub(crate) type TyrDrmDevice = drm::Device<TyrDrmDriver>;
|
|
|
|
#[pin_data(PinnedDrop)]
|
|
pub(crate) struct TyrPlatformDriverData {
|
|
_device: ARef<TyrDrmDevice>,
|
|
}
|
|
|
|
#[pin_data(PinnedDrop)]
|
|
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,
|
|
}
|
|
|
|
// Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they
|
|
// should. There are patches on the mailing list to address this, but they have
|
|
// not landed yet.
|
|
//
|
|
// For now, add this workaround so that this patch compiles with the promise
|
|
// that it will be removed in a future patch.
|
|
//
|
|
// SAFETY: This will be removed in a future patch.
|
|
unsafe impl Send for TyrDrmDeviceData {}
|
|
// SAFETY: This will be removed in a future patch.
|
|
unsafe impl Sync for TyrDrmDeviceData {}
|
|
|
|
fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
|
|
regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;
|
|
|
|
poll::read_poll_timeout(
|
|
|| regs::GPU_IRQ_RAWSTAT.read(dev, iomem),
|
|
|status| *status & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED != 0,
|
|
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,
|
|
<TyrPlatformDriverData as platform::Driver>::IdInfo,
|
|
[
|
|
(of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
|
|
(of::DeviceId::new(c"arm,mali-valhall-csf"), ())
|
|
]
|
|
);
|
|
|
|
impl platform::Driver for TyrPlatformDriverData {
|
|
type IdInfo = ();
|
|
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
|
|
|
|
fn probe(
|
|
pdev: &platform::Device<Core>,
|
|
_info: Option<&Self::IdInfo>,
|
|
) -> impl PinInit<Self, Error> {
|
|
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 = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
|
|
|
|
issue_soft_reset(pdev.as_ref(), &iomem)?;
|
|
gpu::l2_power_on(pdev.as_ref(), &iomem)?;
|
|
|
|
let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?;
|
|
gpu_info.log(pdev);
|
|
|
|
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 ddev: ARef<TyrDrmDevice> = drm::Device::new(pdev.as_ref(), data)?;
|
|
drm::driver::Registration::new_foreign_owned(&ddev, pdev.as_ref(), 0)?;
|
|
|
|
let driver = TyrPlatformDriverData { _device: ddev };
|
|
|
|
// 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>) {}
|
|
}
|
|
|
|
#[pinned_drop]
|
|
impl PinnedDrop for TyrDrmDeviceData {
|
|
fn drop(self: Pin<&mut Self>) {
|
|
// TODO: the type-state pattern for Clks will fix this.
|
|
let clks = self.clks.lock();
|
|
clks.core.disable_unprepare();
|
|
clks.stacks.disable_unprepare();
|
|
clks.coregroup.disable_unprepare();
|
|
}
|
|
}
|
|
|
|
// 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 = drm::gem::Object<TyrObject>;
|
|
|
|
const INFO: drm::DriverInfo = INFO;
|
|
|
|
kernel::declare_drm_ioctls! {
|
|
(PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
|
|
}
|
|
}
|
|
|
|
#[pin_data]
|
|
struct Clocks {
|
|
core: Clk,
|
|
stacks: OptionalClk,
|
|
coregroup: OptionalClk,
|
|
}
|
|
|
|
#[pin_data]
|
|
struct Regulators {
|
|
_mali: Regulator<regulator::Enabled>,
|
|
_sram: Regulator<regulator::Enabled>,
|
|
}
|