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