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