1*cf4fd52eSDaniel Almeida // SPDX-License-Identifier: GPL-2.0 or MIT 2*cf4fd52eSDaniel Almeida 3*cf4fd52eSDaniel Almeida use kernel::c_str; 4*cf4fd52eSDaniel Almeida use kernel::clk::Clk; 5*cf4fd52eSDaniel Almeida use kernel::clk::OptionalClk; 6*cf4fd52eSDaniel Almeida use kernel::device::Bound; 7*cf4fd52eSDaniel Almeida use kernel::device::Core; 8*cf4fd52eSDaniel Almeida use kernel::device::Device; 9*cf4fd52eSDaniel Almeida use kernel::devres::Devres; 10*cf4fd52eSDaniel Almeida use kernel::drm; 11*cf4fd52eSDaniel Almeida use kernel::drm::ioctl; 12*cf4fd52eSDaniel Almeida use kernel::new_mutex; 13*cf4fd52eSDaniel Almeida use kernel::of; 14*cf4fd52eSDaniel Almeida use kernel::platform; 15*cf4fd52eSDaniel Almeida use kernel::prelude::*; 16*cf4fd52eSDaniel Almeida use kernel::regulator; 17*cf4fd52eSDaniel Almeida use kernel::regulator::Regulator; 18*cf4fd52eSDaniel Almeida use kernel::sizes::SZ_2M; 19*cf4fd52eSDaniel Almeida use kernel::sync::Arc; 20*cf4fd52eSDaniel Almeida use kernel::sync::Mutex; 21*cf4fd52eSDaniel Almeida use kernel::time; 22*cf4fd52eSDaniel Almeida use kernel::types::ARef; 23*cf4fd52eSDaniel Almeida 24*cf4fd52eSDaniel Almeida use crate::file::File; 25*cf4fd52eSDaniel Almeida use crate::gem::TyrObject; 26*cf4fd52eSDaniel Almeida use crate::gpu; 27*cf4fd52eSDaniel Almeida use crate::gpu::GpuInfo; 28*cf4fd52eSDaniel Almeida use crate::regs; 29*cf4fd52eSDaniel Almeida 30*cf4fd52eSDaniel Almeida pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>; 31*cf4fd52eSDaniel Almeida 32*cf4fd52eSDaniel Almeida /// Convenience type alias for the DRM device type for this driver. 33*cf4fd52eSDaniel Almeida pub(crate) type TyrDevice = drm::Device<TyrDriver>; 34*cf4fd52eSDaniel Almeida 35*cf4fd52eSDaniel Almeida #[pin_data(PinnedDrop)] 36*cf4fd52eSDaniel Almeida pub(crate) struct TyrDriver { 37*cf4fd52eSDaniel Almeida device: ARef<TyrDevice>, 38*cf4fd52eSDaniel Almeida } 39*cf4fd52eSDaniel Almeida 40*cf4fd52eSDaniel Almeida #[pin_data(PinnedDrop)] 41*cf4fd52eSDaniel Almeida pub(crate) struct TyrData { 42*cf4fd52eSDaniel Almeida pub(crate) pdev: ARef<platform::Device>, 43*cf4fd52eSDaniel Almeida 44*cf4fd52eSDaniel Almeida #[pin] 45*cf4fd52eSDaniel Almeida clks: Mutex<Clocks>, 46*cf4fd52eSDaniel Almeida 47*cf4fd52eSDaniel Almeida #[pin] 48*cf4fd52eSDaniel Almeida regulators: Mutex<Regulators>, 49*cf4fd52eSDaniel Almeida 50*cf4fd52eSDaniel Almeida /// Some information on the GPU. 51*cf4fd52eSDaniel Almeida /// 52*cf4fd52eSDaniel Almeida /// This is mainly queried by userspace, i.e.: Mesa. 53*cf4fd52eSDaniel Almeida pub(crate) gpu_info: GpuInfo, 54*cf4fd52eSDaniel Almeida } 55*cf4fd52eSDaniel Almeida 56*cf4fd52eSDaniel Almeida // Both `Clk` and `Regulator` do not implement `Send` or `Sync`, but they 57*cf4fd52eSDaniel Almeida // should. There are patches on the mailing list to address this, but they have 58*cf4fd52eSDaniel Almeida // not landed yet. 59*cf4fd52eSDaniel Almeida // 60*cf4fd52eSDaniel Almeida // For now, add this workaround so that this patch compiles with the promise 61*cf4fd52eSDaniel Almeida // that it will be removed in a future patch. 62*cf4fd52eSDaniel Almeida // 63*cf4fd52eSDaniel Almeida // SAFETY: This will be removed in a future patch. 64*cf4fd52eSDaniel Almeida unsafe impl Send for TyrData {} 65*cf4fd52eSDaniel Almeida // SAFETY: This will be removed in a future patch. 66*cf4fd52eSDaniel Almeida unsafe impl Sync for TyrData {} 67*cf4fd52eSDaniel Almeida 68*cf4fd52eSDaniel Almeida fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result { 69*cf4fd52eSDaniel Almeida regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?; 70*cf4fd52eSDaniel Almeida 71*cf4fd52eSDaniel Almeida // TODO: We cannot poll, as there is no support in Rust currently, so we 72*cf4fd52eSDaniel Almeida // sleep. Change this when read_poll_timeout() is implemented in Rust. 73*cf4fd52eSDaniel Almeida kernel::time::delay::fsleep(time::Delta::from_millis(100)); 74*cf4fd52eSDaniel Almeida 75*cf4fd52eSDaniel Almeida if regs::GPU_IRQ_RAWSTAT.read(dev, iomem)? & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED == 0 { 76*cf4fd52eSDaniel Almeida dev_err!(dev, "GPU reset failed with errno\n"); 77*cf4fd52eSDaniel Almeida dev_err!( 78*cf4fd52eSDaniel Almeida dev, 79*cf4fd52eSDaniel Almeida "GPU_INT_RAWSTAT is {}\n", 80*cf4fd52eSDaniel Almeida regs::GPU_IRQ_RAWSTAT.read(dev, iomem)? 81*cf4fd52eSDaniel Almeida ); 82*cf4fd52eSDaniel Almeida 83*cf4fd52eSDaniel Almeida return Err(EIO); 84*cf4fd52eSDaniel Almeida } 85*cf4fd52eSDaniel Almeida 86*cf4fd52eSDaniel Almeida Ok(()) 87*cf4fd52eSDaniel Almeida } 88*cf4fd52eSDaniel Almeida 89*cf4fd52eSDaniel Almeida kernel::of_device_table!( 90*cf4fd52eSDaniel Almeida OF_TABLE, 91*cf4fd52eSDaniel Almeida MODULE_OF_TABLE, 92*cf4fd52eSDaniel Almeida <TyrDriver as platform::Driver>::IdInfo, 93*cf4fd52eSDaniel Almeida [ 94*cf4fd52eSDaniel Almeida (of::DeviceId::new(c_str!("rockchip,rk3588-mali")), ()), 95*cf4fd52eSDaniel Almeida (of::DeviceId::new(c_str!("arm,mali-valhall-csf")), ()) 96*cf4fd52eSDaniel Almeida ] 97*cf4fd52eSDaniel Almeida ); 98*cf4fd52eSDaniel Almeida 99*cf4fd52eSDaniel Almeida impl platform::Driver for TyrDriver { 100*cf4fd52eSDaniel Almeida type IdInfo = (); 101*cf4fd52eSDaniel Almeida const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE); 102*cf4fd52eSDaniel Almeida 103*cf4fd52eSDaniel Almeida fn probe( 104*cf4fd52eSDaniel Almeida pdev: &platform::Device<Core>, 105*cf4fd52eSDaniel Almeida _info: Option<&Self::IdInfo>, 106*cf4fd52eSDaniel Almeida ) -> Result<Pin<KBox<Self>>> { 107*cf4fd52eSDaniel Almeida let core_clk = Clk::get(pdev.as_ref(), Some(c_str!("core")))?; 108*cf4fd52eSDaniel Almeida let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("stacks")))?; 109*cf4fd52eSDaniel Almeida let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c_str!("coregroup")))?; 110*cf4fd52eSDaniel Almeida 111*cf4fd52eSDaniel Almeida core_clk.prepare_enable()?; 112*cf4fd52eSDaniel Almeida stacks_clk.prepare_enable()?; 113*cf4fd52eSDaniel Almeida coregroup_clk.prepare_enable()?; 114*cf4fd52eSDaniel Almeida 115*cf4fd52eSDaniel Almeida let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("mali"))?; 116*cf4fd52eSDaniel Almeida let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c_str!("sram"))?; 117*cf4fd52eSDaniel Almeida 118*cf4fd52eSDaniel Almeida let request = pdev.io_request_by_index(0).ok_or(ENODEV)?; 119*cf4fd52eSDaniel Almeida let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?; 120*cf4fd52eSDaniel Almeida 121*cf4fd52eSDaniel Almeida issue_soft_reset(pdev.as_ref(), &iomem)?; 122*cf4fd52eSDaniel Almeida gpu::l2_power_on(pdev.as_ref(), &iomem)?; 123*cf4fd52eSDaniel Almeida 124*cf4fd52eSDaniel Almeida let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?; 125*cf4fd52eSDaniel Almeida gpu_info.log(pdev); 126*cf4fd52eSDaniel Almeida 127*cf4fd52eSDaniel Almeida let platform: ARef<platform::Device> = pdev.into(); 128*cf4fd52eSDaniel Almeida 129*cf4fd52eSDaniel Almeida let data = try_pin_init!(TyrData { 130*cf4fd52eSDaniel Almeida pdev: platform.clone(), 131*cf4fd52eSDaniel Almeida clks <- new_mutex!(Clocks { 132*cf4fd52eSDaniel Almeida core: core_clk, 133*cf4fd52eSDaniel Almeida stacks: stacks_clk, 134*cf4fd52eSDaniel Almeida coregroup: coregroup_clk, 135*cf4fd52eSDaniel Almeida }), 136*cf4fd52eSDaniel Almeida regulators <- new_mutex!(Regulators { 137*cf4fd52eSDaniel Almeida mali: mali_regulator, 138*cf4fd52eSDaniel Almeida sram: sram_regulator, 139*cf4fd52eSDaniel Almeida }), 140*cf4fd52eSDaniel Almeida gpu_info, 141*cf4fd52eSDaniel Almeida }); 142*cf4fd52eSDaniel Almeida 143*cf4fd52eSDaniel Almeida let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?; 144*cf4fd52eSDaniel Almeida drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?; 145*cf4fd52eSDaniel Almeida 146*cf4fd52eSDaniel Almeida let driver = KBox::pin_init(try_pin_init!(TyrDriver { device: tdev }), GFP_KERNEL)?; 147*cf4fd52eSDaniel Almeida 148*cf4fd52eSDaniel Almeida // We need this to be dev_info!() because dev_dbg!() does not work at 149*cf4fd52eSDaniel Almeida // all in Rust for now, and we need to see whether probe succeeded. 150*cf4fd52eSDaniel Almeida dev_info!(pdev.as_ref(), "Tyr initialized correctly.\n"); 151*cf4fd52eSDaniel Almeida Ok(driver) 152*cf4fd52eSDaniel Almeida } 153*cf4fd52eSDaniel Almeida } 154*cf4fd52eSDaniel Almeida 155*cf4fd52eSDaniel Almeida #[pinned_drop] 156*cf4fd52eSDaniel Almeida impl PinnedDrop for TyrDriver { 157*cf4fd52eSDaniel Almeida fn drop(self: Pin<&mut Self>) {} 158*cf4fd52eSDaniel Almeida } 159*cf4fd52eSDaniel Almeida 160*cf4fd52eSDaniel Almeida #[pinned_drop] 161*cf4fd52eSDaniel Almeida impl PinnedDrop for TyrData { 162*cf4fd52eSDaniel Almeida fn drop(self: Pin<&mut Self>) { 163*cf4fd52eSDaniel Almeida // TODO: the type-state pattern for Clks will fix this. 164*cf4fd52eSDaniel Almeida let clks = self.clks.lock(); 165*cf4fd52eSDaniel Almeida clks.core.disable_unprepare(); 166*cf4fd52eSDaniel Almeida clks.stacks.disable_unprepare(); 167*cf4fd52eSDaniel Almeida clks.coregroup.disable_unprepare(); 168*cf4fd52eSDaniel Almeida } 169*cf4fd52eSDaniel Almeida } 170*cf4fd52eSDaniel Almeida 171*cf4fd52eSDaniel Almeida // We need to retain the name "panthor" to achieve drop-in compatibility with 172*cf4fd52eSDaniel Almeida // the C driver in the userspace stack. 173*cf4fd52eSDaniel Almeida const INFO: drm::DriverInfo = drm::DriverInfo { 174*cf4fd52eSDaniel Almeida major: 1, 175*cf4fd52eSDaniel Almeida minor: 5, 176*cf4fd52eSDaniel Almeida patchlevel: 0, 177*cf4fd52eSDaniel Almeida name: c_str!("panthor"), 178*cf4fd52eSDaniel Almeida desc: c_str!("ARM Mali Tyr DRM driver"), 179*cf4fd52eSDaniel Almeida }; 180*cf4fd52eSDaniel Almeida 181*cf4fd52eSDaniel Almeida #[vtable] 182*cf4fd52eSDaniel Almeida impl drm::Driver for TyrDriver { 183*cf4fd52eSDaniel Almeida type Data = TyrData; 184*cf4fd52eSDaniel Almeida type File = File; 185*cf4fd52eSDaniel Almeida type Object = drm::gem::Object<TyrObject>; 186*cf4fd52eSDaniel Almeida 187*cf4fd52eSDaniel Almeida const INFO: drm::DriverInfo = INFO; 188*cf4fd52eSDaniel Almeida 189*cf4fd52eSDaniel Almeida kernel::declare_drm_ioctls! { 190*cf4fd52eSDaniel Almeida (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, File::dev_query), 191*cf4fd52eSDaniel Almeida } 192*cf4fd52eSDaniel Almeida } 193*cf4fd52eSDaniel Almeida 194*cf4fd52eSDaniel Almeida #[pin_data] 195*cf4fd52eSDaniel Almeida struct Clocks { 196*cf4fd52eSDaniel Almeida core: Clk, 197*cf4fd52eSDaniel Almeida stacks: OptionalClk, 198*cf4fd52eSDaniel Almeida coregroup: OptionalClk, 199*cf4fd52eSDaniel Almeida } 200*cf4fd52eSDaniel Almeida 201*cf4fd52eSDaniel Almeida #[pin_data] 202*cf4fd52eSDaniel Almeida struct Regulators { 203*cf4fd52eSDaniel Almeida mali: Regulator<regulator::Enabled>, 204*cf4fd52eSDaniel Almeida sram: Regulator<regulator::Enabled>, 205*cf4fd52eSDaniel Almeida } 206