at v6.19 205 lines 6.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 or MIT 2 3use kernel::c_str; 4use kernel::clk::Clk; 5use kernel::clk::OptionalClk; 6use kernel::device::Bound; 7use kernel::device::Core; 8use kernel::device::Device; 9use kernel::devres::Devres; 10use kernel::drm; 11use kernel::drm::ioctl; 12use kernel::new_mutex; 13use kernel::of; 14use kernel::platform; 15use kernel::prelude::*; 16use kernel::regulator; 17use kernel::regulator::Regulator; 18use kernel::sizes::SZ_2M; 19use kernel::sync::Arc; 20use kernel::sync::Mutex; 21use kernel::time; 22use kernel::types::ARef; 23 24use crate::file::File; 25use crate::gem::TyrObject; 26use crate::gpu; 27use crate::gpu::GpuInfo; 28use crate::regs; 29 30pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>; 31 32/// Convenience type alias for the DRM device type for this driver. 33pub(crate) type TyrDevice = drm::Device<TyrDriver>; 34 35#[pin_data(PinnedDrop)] 36pub(crate) struct TyrDriver { 37 device: ARef<TyrDevice>, 38} 39 40#[pin_data(PinnedDrop)] 41pub(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. 64unsafe impl Send for TyrData {} 65// SAFETY: This will be removed in a future patch. 66unsafe impl Sync for TyrData {} 67 68fn 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 89kernel::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 99impl 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 ) -> impl PinInit<Self, Error> { 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 = TyrDriver { device: tdev }; 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] 156impl PinnedDrop for TyrDriver { 157 fn drop(self: Pin<&mut Self>) {} 158} 159 160#[pinned_drop] 161impl 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. 173const 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] 182impl 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] 195struct Clocks { 196 core: Clk, 197 stacks: OptionalClk, 198 coregroup: OptionalClk, 199} 200 201#[pin_data] 202struct Regulators { 203 mali: Regulator<regulator::Enabled>, 204 sram: Regulator<regulator::Enabled>, 205}