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