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 DeviceContext, // 13 }, 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 Arc, 33 Mutex, // 34 }, 35 time, // 36 }; 37 38 use crate::{ 39 file::TyrDrmFileData, 40 fw::Firmware, 41 gem::Bo, 42 gpu, 43 gpu::GpuInfo, 44 mmu::Mmu, 45 regs::gpu_control::*, // 46 }; 47 48 pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>; 49 50 pub(crate) struct TyrDrmDriver; 51 52 /// Convenience type alias for the DRM device type for this driver. 53 pub(crate) type TyrDrmDevice<Ctx = drm::Normal> = drm::Device<TyrDrmDriver, Ctx>; 54 55 pub(crate) struct TyrPlatformDriver; 56 57 #[pin_data(PinnedDrop)] 58 pub(crate) struct TyrPlatformDriverData<'bound> { 59 _reg: drm::Registration<'bound, TyrDrmDriver>, 60 } 61 62 /// Data owned by the DRM [`Registration`]. 63 /// 64 /// This data can have references tied to the parent platform device binding scope 65 /// and is accessible only while the DRM device is registered with userspace. 66 #[pin_data] 67 pub(crate) struct TyrDrmRegistrationData<'drm> { 68 /// Parent platform device. 69 pub(crate) pdev: &'drm platform::Device<Bound>, 70 71 /// Firmware sections. 72 pub(crate) fw: Firmware<'drm>, 73 74 #[pin] 75 clks: Mutex<Clocks>, 76 77 #[pin] 78 regulators: Mutex<Regulators>, 79 80 /// GPU MMIO register mapping. 81 pub(crate) iomem: Arc<IoMem<'drm>>, 82 83 /// GPU information read from hardware during probe. 84 pub(crate) gpu_info: GpuInfo, 85 } 86 87 fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result { 88 iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset)); 89 90 poll::read_poll_timeout( 91 || Ok(iomem.read(GPU_IRQ_RAWSTAT)), 92 |status| status.reset_completed(), 93 time::Delta::from_millis(1), 94 time::Delta::from_millis(100), 95 ) 96 .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?; 97 98 Ok(()) 99 } 100 101 kernel::of_device_table!( 102 OF_TABLE, 103 MODULE_OF_TABLE, 104 <TyrPlatformDriver as platform::Driver>::IdInfo, 105 [ 106 (of::DeviceId::new(c"rockchip,rk3588-mali"), ()), 107 (of::DeviceId::new(c"arm,mali-valhall-csf"), ()) 108 ] 109 ); 110 111 impl platform::Driver for TyrPlatformDriver { 112 type IdInfo = (); 113 type Data<'bound> = TyrPlatformDriverData<'bound>; 114 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 115 116 fn probe<'bound>( 117 pdev: &'bound platform::Device<Core<'_>>, 118 _info: Option<&'bound Self::IdInfo>, 119 ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { 120 let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; 121 let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; 122 let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; 123 124 core_clk.prepare_enable()?; 125 stacks_clk.prepare_enable()?; 126 coregroup_clk.prepare_enable()?; 127 128 let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?; 129 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; 130 131 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 132 133 let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?, GFP_KERNEL)?; 134 135 issue_soft_reset(pdev.as_ref(), &iomem)?; 136 gpu::l2_power_on(pdev.as_ref(), &iomem)?; 137 138 let gpu_info = GpuInfo::new(&iomem); 139 gpu_info.log(pdev.as_ref()); 140 141 let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features) 142 .pa_bits() 143 .get(); 144 // SAFETY: No concurrent DMA allocations or mappings can be made because 145 // the device is still being probed and therefore isn't being used by 146 // other threads of execution. 147 unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? }; 148 149 let unreg_dev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, Ok(()))?; 150 151 let mmu = Mmu::new(pdev.as_ref(), iomem.as_arc_borrow(), &gpu_info)?; 152 153 let firmware = Firmware::new( 154 pdev.as_ref(), 155 iomem.clone(), 156 &unreg_dev, 157 mmu.as_arc_borrow(), 158 &gpu_info, 159 )?; 160 161 firmware.boot()?; 162 163 let reg_data = pin_init!(TyrDrmRegistrationData { 164 pdev, 165 fw: firmware, 166 clks <- new_mutex!(Clocks { 167 core: core_clk, 168 stacks: stacks_clk, 169 coregroup: coregroup_clk, 170 }), 171 regulators <- new_mutex!(Regulators { 172 _mali: mali_regulator, 173 _sram: sram_regulator, 174 }), 175 iomem, 176 gpu_info, 177 }); 178 179 // SAFETY: `reg` is stored in `TyrPlatformDriverData` and dropped when the driver is 180 // unbound; it is never forgotten. 181 let reg = unsafe { drm::Registration::new(pdev.as_ref(), unreg_dev, reg_data, 0)? }; 182 183 let driver = TyrPlatformDriverData { _reg: reg }; 184 185 dev_dbg!(pdev, "Tyr initialized correctly."); 186 Ok(driver) 187 } 188 } 189 190 #[pinned_drop] 191 impl PinnedDrop for TyrPlatformDriverData<'_> { 192 fn drop(self: Pin<&mut Self>) {} 193 } 194 195 // We need to retain the name "panthor" to achieve drop-in compatibility with 196 // the C driver in the userspace stack. 197 const INFO: drm::DriverInfo = drm::DriverInfo { 198 major: 1, 199 minor: 5, 200 patchlevel: 0, 201 name: c"panthor", 202 desc: c"ARM Mali Tyr DRM driver", 203 }; 204 205 #[vtable] 206 impl drm::Driver for TyrDrmDriver { 207 type Data = (); 208 type RegistrationData<'drm> = TyrDrmRegistrationData<'drm>; 209 type File = TyrDrmFileData; 210 type Object = Bo; 211 type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>; 212 213 const INFO: drm::DriverInfo = INFO; 214 const FEAT_RENDER: bool = true; 215 216 kernel::declare_drm_ioctls! { 217 (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query), 218 } 219 } 220 221 struct Clocks { 222 core: Clk, 223 stacks: OptionalClk, 224 coregroup: OptionalClk, 225 } 226 227 impl Drop for Clocks { 228 fn drop(&mut self) { 229 self.core.disable_unprepare(); 230 self.stacks.disable_unprepare(); 231 self.coregroup.disable_unprepare(); 232 } 233 } 234 235 struct Regulators { 236 _mali: Regulator<regulator::Enabled>, 237 _sram: Regulator<regulator::Enabled>, 238 } 239