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<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 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 106 107 fn probe( 108 pdev: &platform::Device<Core>, 109 _info: Option<&Self::IdInfo>, 110 ) -> impl PinInit<Self, Error> { 111 let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?; 112 let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?; 113 let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?; 114 115 core_clk.prepare_enable()?; 116 stacks_clk.prepare_enable()?; 117 coregroup_clk.prepare_enable()?; 118 119 let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?; 120 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?; 121 122 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 123 let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?; 124 125 issue_soft_reset(pdev.as_ref(), &iomem)?; 126 gpu::l2_power_on(pdev.as_ref(), &iomem)?; 127 128 let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?; 129 gpu_info.log(pdev.as_ref()); 130 131 let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features) 132 .pa_bits() 133 .get(); 134 // SAFETY: No concurrent DMA allocations or mappings can be made because 135 // the device is still being probed and therefore isn't being used by 136 // other threads of execution. 137 unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? }; 138 139 let platform: ARef<platform::Device> = pdev.into(); 140 141 let data = try_pin_init!(TyrDrmDeviceData { 142 pdev: platform.clone(), 143 clks <- new_mutex!(Clocks { 144 core: core_clk, 145 stacks: stacks_clk, 146 coregroup: coregroup_clk, 147 }), 148 regulators <- new_mutex!(Regulators { 149 _mali: mali_regulator, 150 _sram: sram_regulator, 151 }), 152 gpu_info, 153 }); 154 155 let ddev: ARef<TyrDrmDevice> = drm::Device::new(pdev.as_ref(), data)?; 156 drm::driver::Registration::new_foreign_owned(&ddev, pdev.as_ref(), 0)?; 157 158 let driver = TyrPlatformDriverData { _device: ddev }; 159 160 // We need this to be dev_info!() because dev_dbg!() does not work at 161 // all in Rust for now, and we need to see whether probe succeeded. 162 dev_info!(pdev, "Tyr initialized correctly.\n"); 163 Ok(driver) 164 } 165 } 166 167 #[pinned_drop] 168 impl PinnedDrop for TyrPlatformDriverData { 169 fn drop(self: Pin<&mut Self>) {} 170 } 171 172 // We need to retain the name "panthor" to achieve drop-in compatibility with 173 // the C driver in the userspace stack. 174 const INFO: drm::DriverInfo = drm::DriverInfo { 175 major: 1, 176 minor: 5, 177 patchlevel: 0, 178 name: c"panthor", 179 desc: c"ARM Mali Tyr DRM driver", 180 }; 181 182 #[vtable] 183 impl drm::Driver for TyrDrmDriver { 184 type Data = TyrDrmDeviceData; 185 type File = TyrDrmFileData; 186 type Object = drm::gem::shmem::Object<BoData>; 187 188 const INFO: drm::DriverInfo = INFO; 189 190 kernel::declare_drm_ioctls! { 191 (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query), 192 } 193 } 194 195 struct Clocks { 196 core: Clk, 197 stacks: OptionalClk, 198 coregroup: OptionalClk, 199 } 200 201 impl Drop for Clocks { 202 fn drop(&mut self) { 203 self.core.disable_unprepare(); 204 self.stacks.disable_unprepare(); 205 self.coregroup.disable_unprepare(); 206 } 207 } 208 209 struct Regulators { 210 _mali: Regulator<regulator::Enabled>, 211 _sram: Regulator<regulator::Enabled>, 212 } 213