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