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
issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result68 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
probe( pdev: &platform::Device<Core>, _info: Option<&Self::IdInfo>, ) -> impl PinInit<Self, Error>103 fn probe(
104 pdev: &platform::Device<Core>,
105 _info: Option<&Self::IdInfo>,
106 ) -> impl PinInit<Self, Error> {
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 = TyrDriver { device: tdev };
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 {
drop(self: Pin<&mut Self>)157 fn drop(self: Pin<&mut Self>) {}
158 }
159
160 #[pinned_drop]
161 impl PinnedDrop for TyrData {
drop(self: Pin<&mut Self>)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