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