projects/linux·blob master · refs

237 lines · 6.3 KiB

1// SPDX-License-Identifier: GPL-2.0 or MIT
2
3use kernel::{
4 clk::{
5 Clk,
6 OptionalClk, //
7 },
8 device::{
9 Bound,
10 Core,
11 Device,
12 DeviceContext, //
13 },
14 dma::{
15 Device as DmaDevice,
16 DmaMask, //
17 },
18 drm,
19 drm::ioctl,
20 io::{
21 poll,
22 Io, //
23 },
24 new_mutex,
25 of,
26 platform,
27 prelude::*,
28 regulator,
29 regulator::Regulator,
30 sizes::SZ_2M,
31 sync::{
32 Arc,
33 Mutex, //
34 },
35 time, //
36};
37
38use crate::{
39 file::TyrDrmFileData,
40 fw::Firmware,
41 gem::Bo,
42 gpu,
43 gpu::GpuInfo,
44 mmu::Mmu,
45 regs::gpu_control::*, //
46};
47
48pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
49
50pub(crate) struct TyrDrmDriver;
51
52/// Convenience type alias for the DRM device type for this driver.
53pub(crate) type TyrDrmDevice<Ctx = drm::Normal> = drm::Device<TyrDrmDriver, Ctx>;
54
55pub(crate) struct TyrPlatformDriver;
56
57#[pin_data(PinnedDrop)]
58pub(crate) struct TyrPlatformDriverData<'bound> {
59 _reg: drm::Registration<'bound, TyrDrmDriver>,
60}
61
62/// Data owned by the DRM [`Registration`].
63///
64/// This data can have references tied to the parent platform device binding scope
65/// and is accessible only while the DRM device is registered with userspace.
66#[pin_data]
67pub(crate) struct TyrDrmRegistrationData<'drm> {
68 /// Parent platform device.
69 pub(crate) pdev: &'drm platform::Device<Bound>,
70
71 /// Firmware sections.
72 pub(crate) fw: Firmware<'drm>,
73
74 #[pin]
75 clks: Mutex<Clocks>,
76
77 #[pin]
78 regulators: Mutex<Regulators>,
79
80 /// GPU MMIO register mapping.
81 pub(crate) iomem: Arc<IoMem<'drm>>,
82
83 /// GPU information read from hardware during probe.
84 pub(crate) gpu_info: GpuInfo,
85}
86
87fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
88 iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
89
90 poll::read_poll_timeout(
91 || Ok(iomem.read(GPU_IRQ_RAWSTAT)),
92 |status| status.reset_completed(),
93 time::Delta::from_millis(1),
94 time::Delta::from_millis(100),
95 )
96 .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
97
98 Ok(())
99}
100
101kernel::of_device_table!(
102 OF_TABLE,
103 <TyrPlatformDriver as platform::Driver>::IdInfo,
104 [
105 (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
106 (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
107 ]
108);
109
110impl platform::Driver for TyrPlatformDriver {
111 type IdInfo = ();
112 type Data<'bound> = TyrPlatformDriverData<'bound>;
113 const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
114
115 fn probe<'bound>(
116 pdev: &'bound platform::Device<Core<'_>>,
117 _info: Option<&'bound Self::IdInfo>,
118 ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
119 let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
120 let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
121 let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
122
123 core_clk.prepare_enable()?;
124 stacks_clk.prepare_enable()?;
125 coregroup_clk.prepare_enable()?;
126
127 let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
128 let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
129
130 let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
131
132 let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?, GFP_KERNEL)?;
133
134 issue_soft_reset(pdev.as_ref(), &iomem)?;
135 gpu::l2_power_on(pdev.as_ref(), &iomem)?;
136
137 let gpu_info = GpuInfo::new(&iomem);
138 gpu_info.log(pdev.as_ref());
139
140 let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features)
141 .pa_bits()
142 .get();
143 // SAFETY: No concurrent DMA allocations or mappings can be made because
144 // the device is still being probed and therefore isn't being used by
145 // other threads of execution.
146 unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? };
147
148 let unreg_dev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, Ok(()))?;
149
150 let mmu = Mmu::new(pdev.as_ref(), iomem.as_arc_borrow(), &gpu_info)?;
151
152 let firmware = Firmware::new(
153 pdev.as_ref(),
154 iomem.clone(),
155 &unreg_dev,
156 mmu.as_arc_borrow(),
157 &gpu_info,
158 )?;
159
160 firmware.boot()?;
161
162 let reg_data = pin_init!(TyrDrmRegistrationData {
163 pdev,
164 fw: firmware,
165 clks <- new_mutex!(Clocks {
166 core: core_clk,
167 stacks: stacks_clk,
168 coregroup: coregroup_clk,
169 }),
170 regulators <- new_mutex!(Regulators {
171 _mali: mali_regulator,
172 _sram: sram_regulator,
173 }),
174 iomem,
175 gpu_info,
176 });
177
178 // SAFETY: `reg` is stored in `TyrPlatformDriverData` and dropped when the driver is
179 // unbound; it is never forgotten.
180 let reg = unsafe { drm::Registration::new(pdev.as_ref(), unreg_dev, reg_data, 0)? };
181
182 let driver = TyrPlatformDriverData { _reg: reg };
183
184 dev_dbg!(pdev, "Tyr initialized correctly.");
185 Ok(driver)
186 }
187}
188
189#[pinned_drop]
190impl PinnedDrop for TyrPlatformDriverData<'_> {
191 fn drop(self: Pin<&mut Self>) {}
192}
193
194// We need to retain the name "panthor" to achieve drop-in compatibility with
195// the C driver in the userspace stack.
196const INFO: drm::DriverInfo = drm::DriverInfo {
197 major: 1,
198 minor: 5,
199 patchlevel: 0,
200 name: c"panthor",
201 desc: c"ARM Mali Tyr DRM driver",
202};
203
204#[vtable]
205impl drm::Driver for TyrDrmDriver {
206 type Data = ();
207 type RegistrationData<'drm> = TyrDrmRegistrationData<'drm>;
208 type File = TyrDrmFileData;
209 type Object = Bo;
210 type ParentDevice<Ctx: DeviceContext> = platform::Device<Ctx>;
211
212 const INFO: drm::DriverInfo = INFO;
213 const FEAT_RENDER: bool = true;
214
215 kernel::declare_drm_ioctls! {
216 (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
217 }
218}
219
220struct Clocks {
221 core: Clk,
222 stacks: OptionalClk,
223 coregroup: OptionalClk,
224}
225
226impl Drop for Clocks {
227 fn drop(&mut self) {
228 self.core.disable_unprepare();
229 self.stacks.disable_unprepare();
230 self.coregroup.disable_unprepare();
231 }
232}
233
234struct Regulators {
235 _mali: Regulator<regulator::Enabled>,
236 _sram: Regulator<regulator::Enabled>,
237}