xref: /linux/drivers/gpu/drm/tyr/driver.rs (revision d3cac8a343241a547445e8a651f1d4ecc276b828)
1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 
3 use kernel::{
4     clk::{
5         Clk,
6         OptionalClk, //
7     },
8     device::{
9         Core,
10         Device,
11         DeviceContext, //
12     },
13     dma::{
14         Device as DmaDevice,
15         DmaMask, //
16     },
17     drm,
18     drm::ioctl,
19     io::{
20         poll,
21         Io, //
22     },
23     new_mutex,
24     of,
25     platform,
26     prelude::*,
27     regulator,
28     regulator::Regulator,
29     sizes::SZ_2M,
30     sync::{
31         aref::ARef,
32         Mutex, //
33     },
34     time, //
35 };
36 
37 use crate::{
38     file::TyrDrmFileData,
39     gem::BoData,
40     gpu,
41     gpu::GpuInfo,
42     regs::gpu_control::*, //
43 };
44 
45 pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
46 
47 pub(crate) struct TyrDrmDriver;
48 
49 /// Convenience type alias for the DRM device type for this driver.
50 pub(crate) type TyrDrmDevice<Ctx = drm::Normal> = drm::Device<TyrDrmDriver, Ctx>;
51 
52 pub(crate) struct TyrPlatformDriver;
53 
54 #[pin_data(PinnedDrop)]
55 pub(crate) struct TyrPlatformDriverData<'bound> {
56     _device: ARef<TyrDrmDevice>,
57     _reg: drm::Registration<'bound, TyrDrmDriver>,
58 }
59 
60 #[pin_data]
61 pub(crate) struct TyrDrmDeviceData {
62     pub(crate) pdev: ARef<platform::Device>,
63 
64     #[pin]
65     clks: Mutex<Clocks>,
66 
67     #[pin]
68     regulators: Mutex<Regulators>,
69 
70     /// Some information on the GPU.
71     ///
72     /// This is mainly queried by userspace, i.e.: Mesa.
73     pub(crate) gpu_info: GpuInfo,
74 }
75 
76 fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
77     iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
78 
79     poll::read_poll_timeout(
80         || Ok(iomem.read(GPU_IRQ_RAWSTAT)),
81         |status| status.reset_completed(),
82         time::Delta::from_millis(1),
83         time::Delta::from_millis(100),
84     )
85     .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
86 
87     Ok(())
88 }
89 
90 kernel::of_device_table!(
91     OF_TABLE,
92     MODULE_OF_TABLE,
93     <TyrPlatformDriver as platform::Driver>::IdInfo,
94     [
95         (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
96         (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
97     ]
98 );
99 
100 impl platform::Driver for TyrPlatformDriver {
101     type IdInfo = ();
102     type Data<'bound> = TyrPlatformDriverData<'bound>;
103     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
104 
105     fn probe<'bound>(
106         pdev: &'bound platform::Device<Core<'_>>,
107         _info: Option<&'bound Self::IdInfo>,
108     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
109         let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
110         let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
111         let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
112 
113         core_clk.prepare_enable()?;
114         stacks_clk.prepare_enable()?;
115         coregroup_clk.prepare_enable()?;
116 
117         let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
118         let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
119 
120         let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
121         let iomem = request.iomap_sized::<SZ_2M>()?;
122 
123         issue_soft_reset(pdev.as_ref(), &iomem)?;
124         gpu::l2_power_on(pdev.as_ref(), &iomem)?;
125 
126         let gpu_info = GpuInfo::new(&iomem);
127         gpu_info.log(pdev.as_ref());
128 
129         let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features)
130             .pa_bits()
131             .get();
132         // SAFETY: No concurrent DMA allocations or mappings can be made because
133         // the device is still being probed and therefore isn't being used by
134         // other threads of execution.
135         unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? };
136 
137         let platform: ARef<platform::Device> = pdev.into();
138 
139         let data = try_pin_init!(TyrDrmDeviceData {
140                 pdev: platform.clone(),
141                 clks <- new_mutex!(Clocks {
142                     core: core_clk,
143                     stacks: stacks_clk,
144                     coregroup: coregroup_clk,
145                 }),
146                 regulators <- new_mutex!(Regulators {
147                     _mali: mali_regulator,
148                     _sram: sram_regulator,
149                 }),
150                 gpu_info,
151         });
152 
153         let tdev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, data)?;
154         // SAFETY: `reg` is stored in `TyrPlatformDriverData` and dropped when the driver is
155         // unbound; it is never forgotten.
156         let reg = unsafe { drm::Registration::new(pdev.as_ref(), tdev, (), 0)? };
157 
158         let driver = TyrPlatformDriverData {
159             _device: reg.device().into(),
160             _reg: reg,
161         };
162 
163         // We need this to be dev_info!() because dev_dbg!() does not work at
164         // all in Rust for now, and we need to see whether probe succeeded.
165         dev_info!(pdev, "Tyr initialized correctly.\n");
166         Ok(driver)
167     }
168 }
169 
170 #[pinned_drop]
171 impl PinnedDrop for TyrPlatformDriverData<'_> {
172     fn drop(self: Pin<&mut Self>) {}
173 }
174 
175 // We need to retain the name "panthor" to achieve drop-in compatibility with
176 // the C driver in the userspace stack.
177 const INFO: drm::DriverInfo = drm::DriverInfo {
178     major: 1,
179     minor: 5,
180     patchlevel: 0,
181     name: c"panthor",
182     desc: c"ARM Mali Tyr DRM driver",
183 };
184 
185 #[vtable]
186 impl drm::Driver for TyrDrmDriver {
187     type Data = TyrDrmDeviceData;
188     type RegistrationData<'a> = ();
189     type File = TyrDrmFileData;
190     type Object = drm::gem::shmem::Object<BoData>;
191     type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
192 
193     const INFO: drm::DriverInfo = INFO;
194     const FEAT_RENDER: bool = true;
195 
196     kernel::declare_drm_ioctls! {
197         (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
198     }
199 }
200 
201 struct Clocks {
202     core: Clk,
203     stacks: OptionalClk,
204     coregroup: OptionalClk,
205 }
206 
207 impl Drop for Clocks {
208     fn drop(&mut self) {
209         self.core.disable_unprepare();
210         self.stacks.disable_unprepare();
211         self.coregroup.disable_unprepare();
212     }
213 }
214 
215 struct Regulators {
216     _mali: Regulator<regulator::Enabled>,
217     _sram: Regulator<regulator::Enabled>,
218 }
219