| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // SPDX-License-Identifier: GPL-2.0 or MIT
- use kernel::clk::Clk;
- use kernel::clk::OptionalClk;
- use kernel::device::Bound;
- use kernel::device::Core;
- use kernel::device::Device;
- use kernel::devres::Devres;
- use kernel::drm;
- use kernel::drm::ioctl;
- use kernel::io::poll;
- use kernel::new_mutex;
- use kernel::of;
- use kernel::platform;
- use kernel::prelude::*;
- use kernel::regulator;
- use kernel::regulator::Regulator;
- use kernel::sizes::SZ_2M;
- use kernel::sync::aref::ARef;
- use kernel::sync::Arc;
- use kernel::sync::Mutex;
- use kernel::time;
- use crate::file::File;
- use crate::gem::TyrObject;
- use crate::gpu;
- use crate::gpu::GpuInfo;
- use crate::regs;
- pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;
- /// Convenience type alias for the DRM device type for this driver.
- pub(crate) type TyrDevice = drm::Device<TyrDriver>;
- #[pin_data(PinnedDrop)]
- pub(crate) struct TyrDriver {
- _device: ARef<TyrDevice>,
- }
- #[pin_data(PinnedDrop)]
- pub(crate) struct TyrData {
- 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 TyrData {}
- // SAFETY: This will be removed in a future patch.
- unsafe impl Sync for TyrData {}
- 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,
- <TyrDriver as platform::Driver>::IdInfo,
- [
- (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
- (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
- ]
- );
- impl platform::Driver for TyrDriver {
- 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!(TyrData {
- 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: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?;
- drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?;
- let driver = TyrDriver { _device: tdev };
- // 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 TyrDriver {
- fn drop(self: Pin<&mut Self>) {}
- }
- #[pinned_drop]
- impl PinnedDrop for TyrData {
- 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 TyrDriver {
- type Data = TyrData;
- type File = File;
- 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, File::dev_query),
- }
- }
- #[pin_data]
- struct Clocks {
- core: Clk,
- stacks: OptionalClk,
- coregroup: OptionalClk,
- }
- #[pin_data]
- struct Regulators {
- _mali: Regulator<regulator::Enabled>,
- _sram: Regulator<regulator::Enabled>,
- }
|