1 // SPDX-License-Identifier: GPL-2.0 or MIT 2 3 use kernel::{ 4 clk::{ 5 Clk, 6 OptionalClk, // 7 }, 8 device::{ 9 Bound, 10 Core, 11 Device, // 12 }, 13 devres::Devres, 14 dma::{ 15 Device as DmaDevice, 16 DmaMask, // 17 }, 18 drm, 19 drm::ioctl, 20 io::{ 21 poll, 22 Io, // 23 }, 24 new_mutex, 25 of, 26 platform, 27 prelude::*, 28 regulator, 29 regulator::Regulator, 30 sizes::SZ_2M, 31 sync::{ 32 aref::ARef, 33 Arc, 34 Mutex, // 35 }, 36 time, // 37 }; 38 39 use crate::{ 40 file::TyrDrmFileData, 41 gem::BoData, 42 gpu, 43 gpu::GpuInfo, 44 regs::gpu_control::*, // 45 }; 46 47 pub(crate) type IoMem = kernel::io::mem::IoMem<'static, SZ_2M>; 48 49 pub(crate) struct TyrDrmDriver; 50 51 /// Convenience type alias for the DRM device type for this driver. 52 pub(crate) type TyrDrmDevice = drm::Device<TyrDrmDriver>; 53 54 #[pin_data(PinnedDrop)] 55 pub(crate) struct TyrPlatformDriverData { 56 _device: ARef<TyrDrmDevice>, 57 } 58 59 #[pin_data] 60 pub(crate) struct TyrDrmDeviceData { 61 pub(crate) pdev: ARef<platform::Device>, 62 63 #[pin] 64 clks: Mutex<Clocks>, 65 66 #[pin] 67 regulators: Mutex<Regulators>, 68 69 /// Some information on the GPU. 70 /// 71 /// This is mainly queried by userspace, i.e.: Mesa. 72 pub(crate) gpu_info: GpuInfo, 73 } 74 75 fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result { 76 let io = (*iomem).access(dev)?; 77 io.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset)); 78 79 poll::read_poll_timeout( 80 || { 81 let io = (*iomem).access(dev)?; 82 Ok(io.read(GPU_IRQ_RAWSTAT)) 83 }, 84 |status| status.reset_completed(), 85 time::Delta::from_millis(1), 86 time::Delta::from_millis(100), 87 ) 88 .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?; 89 90 Ok(()) 91 } 92 93 kernel::of_device_table!( 94 OF_TABLE, 95 MODULE_OF_TABLE, 96 <TyrPlatformDriverData as platform::Driver>::IdInfo, 97 [ 98 (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), 99 (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) 100 ] 101 ); 102 103 impl platform::Driver for TyrPlatformDriverData { 104 type IdInfo = (); 105 type Data<'bound> = Self; 106 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 107 108 fn probe<'bound>( 109 pdev: &'bound platform::Device<Core<'_>>, 110 _info: Option<&'bound Self::IdInfo>, 111 ) -> impl PinInit<Self, Error> + 'bound { 112 let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; 113 let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; 114 let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; 115 116 core_clk.prepare_enable()?; 117 stacks_clk.prepare_enable()?; 118 coregroup_clk.prepare_enable()?; 119 120 let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?; 121 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; 122 123 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 124 let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?.into_devres()?, GFP_KERNEL)?; 125 126 issue_soft_reset(pdev.as_ref(), &iomem)?; 127 gpu::l2_power_on(pdev.as_ref(), &iomem)?; 128 129 let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?; 130 gpu_info.log(pdev.as_ref()); 131 132 let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features) 133 .pa_bits() 134 .get(); 135 // SAFETY: No concurrent DMA allocations or mappings can be made because 136 // the device is still being probed and therefore isn't being used by 137 // other threads of execution. 138 unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? }; 139 140 let platform: ARef<platform::Device> = pdev.into(); 141 142 let data = try_pin_init!(TyrDrmDeviceData { 143 pdev: platform.clone(), 144 clks <- new_mutex!(Clocks { 145 core: core_clk, 146 stacks: stacks_clk, 147 coregroup: coregroup_clk, 148 }), 149 regulators <- new_mutex!(Regulators { 150 _mali: mali_regulator, 151 _sram: sram_regulator, 152 }), 153 gpu_info, 154 }); 155 156 let ddev: ARef<TyrDrmDevice> = drm::Device::new(pdev.as_ref(), data)?; 157 drm::driver::Registration::new_foreign_owned(&ddev, pdev.as_ref(), 0)?; 158 159 let driver = TyrPlatformDriverData { _device: ddev }; 160 161 // We need this to be dev_info!() because dev_dbg!() does not work at 162 // all in Rust for now, and we need to see whether probe succeeded. 163 dev_info!(pdev, "Tyr initialized correctly.\n"); 164 Ok(driver) 165 } 166 } 167 168 #[pinned_drop] 169 impl PinnedDrop for TyrPlatformDriverData { 170 fn drop(self: Pin<&mut Self>) {} 171 } 172 173 // We need to retain the name "panthor" to achieve drop-in compatibility with 174 // the C driver in the userspace stack. 175 const INFO: drm::DriverInfo = drm::DriverInfo { 176 major: 1, 177 minor: 5, 178 patchlevel: 0, 179 name: c"panthor", 180 desc: c"ARM Mali Tyr DRM driver", 181 }; 182 183 #[vtable] 184 impl drm::Driver for TyrDrmDriver { 185 type Data = TyrDrmDeviceData; 186 type File = TyrDrmFileData; 187 type Object = drm::gem::shmem::Object<BoData>; 188 189 const INFO: drm::DriverInfo = INFO; 190 const FEAT_RENDER: bool = true; 191 192 kernel::declare_drm_ioctls! { 193 (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query), 194 } 195 } 196 197 struct Clocks { 198 core: Clk, 199 stacks: OptionalClk, 200 coregroup: OptionalClk, 201 } 202 203 impl Drop for Clocks { 204 fn drop(&mut self) { 205 self.core.disable_unprepare(); 206 self.stacks.disable_unprepare(); 207 self.coregroup.disable_unprepare(); 208 } 209 } 210 211 struct Regulators { 212 _mali: Regulator<regulator::Enabled>, 213 _sram: Regulator<regulator::Enabled>, 214 } 215