// 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; pub(crate) struct TyrDrmDriver; /// Convenience type alias for the DRM device type for this driver. pub(crate) type TyrDrmDevice = drm::Device; #[pin_data(PinnedDrop)] pub(crate) struct TyrPlatformDriverData { _device: ARef, } #[pin_data(PinnedDrop)] pub(crate) struct TyrDrmDeviceData { pub(crate) pdev: ARef, #[pin] clks: Mutex, #[pin] regulators: Mutex, /// 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, iomem: &Devres) -> 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, ::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> = Some(&OF_TABLE); fn probe( pdev: &platform::Device, _info: Option<&Self::IdInfo>, ) -> impl PinInit { 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::::get(pdev.as_ref(), c"mali")?; let sram_regulator = Regulator::::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::(), 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 = 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 = 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; 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, _sram: Regulator, }