1 // SPDX-License-Identifier: GPL-2.0 or MIT 2 3 use kernel::clk::Clk; 4 use kernel::clk::OptionalClk; 5 use kernel::device::Bound; 6 use kernel::device::Core; 7 use kernel::device::Device; 8 use kernel::devres::Devres; 9 use kernel::drm; 10 use kernel::drm::ioctl; 11 use kernel::io::poll; 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::aref::ARef; 20 use kernel::sync::Arc; 21 use kernel::sync::Mutex; 22 use kernel::time; 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 poll::read_poll_timeout( 72 || regs::GPU_IRQ_RAWSTAT.read(dev, iomem), 73 |status| *status & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED != 0, 74 time::Delta::from_millis(1), 75 time::Delta::from_millis(100), 76 ) 77 .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?; 78 79 Ok(()) 80 } 81 82 kernel::of_device_table!( 83 OF_TABLE, 84 MODULE_OF_TABLE, 85 <TyrDriver as platform::Driver>::IdInfo, 86 [ 87 (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), 88 (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) 89 ] 90 ); 91 92 impl platform::Driver for TyrDriver { 93 type IdInfo = (); 94 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 95 96 fn probe( 97 pdev: &platform::Device<Core>, 98 _info: Option<&Self::IdInfo>, 99 ) -> impl PinInit<Self, Error> { 100 let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; 101 let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; 102 let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; 103 104 core_clk.prepare_enable()?; 105 stacks_clk.prepare_enable()?; 106 coregroup_clk.prepare_enable()?; 107 108 let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?; 109 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; 110 111 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 112 let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?; 113 114 issue_soft_reset(pdev.as_ref(), &iomem)?; 115 gpu::l2_power_on(pdev.as_ref(), &iomem)?; 116 117 let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?; 118 gpu_info.log(pdev); 119 120 let platform: ARef<platform::Device> = pdev.into(); 121 122 let data = try_pin_init!(TyrData { 123 pdev: platform.clone(), 124 clks <- new_mutex!(Clocks { 125 core: core_clk, 126 stacks: stacks_clk, 127 coregroup: coregroup_clk, 128 }), 129 regulators <- new_mutex!(Regulators { 130 _mali: mali_regulator, 131 _sram: sram_regulator, 132 }), 133 gpu_info, 134 }); 135 136 let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?; 137 drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?; 138 139 let driver = TyrDriver { _device: tdev }; 140 141 // We need this to be dev_info!() because dev_dbg!() does not work at 142 // all in Rust for now, and we need to see whether probe succeeded. 143 dev_info!(pdev, "Tyr initialized correctly.\n"); 144 Ok(driver) 145 } 146 } 147 148 #[pinned_drop] 149 impl PinnedDrop for TyrDriver { 150 fn drop(self: Pin<&mut Self>) {} 151 } 152 153 #[pinned_drop] 154 impl PinnedDrop for TyrData { 155 fn drop(self: Pin<&mut Self>) { 156 // TODO: the type-state pattern for Clks will fix this. 157 let clks = self.clks.lock(); 158 clks.core.disable_unprepare(); 159 clks.stacks.disable_unprepare(); 160 clks.coregroup.disable_unprepare(); 161 } 162 } 163 164 // We need to retain the name "panthor" to achieve drop-in compatibility with 165 // the C driver in the userspace stack. 166 const INFO: drm::DriverInfo = drm::DriverInfo { 167 major: 1, 168 minor: 5, 169 patchlevel: 0, 170 name: c"panthor", 171 desc: c"ARM Mali Tyr DRM driver", 172 }; 173 174 #[vtable] 175 impl drm::Driver for TyrDriver { 176 type Data = TyrData; 177 type File = File; 178 type Object = drm::gem::Object<TyrObject>; 179 180 const INFO: drm::DriverInfo = INFO; 181 182 kernel::declare_drm_ioctls! { 183 (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, File::dev_query), 184 } 185 } 186 187 #[pin_data] 188 struct Clocks { 189 core: Clk, 190 stacks: OptionalClk, 191 coregroup: OptionalClk, 192 } 193 194 #[pin_data] 195 struct Regulators { 196 _mali: Regulator<regulator::Enabled>, 197 _sram: Regulator<regulator::Enabled>, 198 } 199