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