xref: /linux/drivers/gpu/drm/tyr/driver.rs (revision 82b78182eacf82c1847c6f1fd93d91c15efb69cf)
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     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         aref::ARef,
33         Arc,
34         Mutex, //
35     },
36     time, //
37 };
38 
39 use crate::{
40     file::TyrDrmFileData,
41     gem::BoData,
42     gpu,
43     gpu::GpuInfo,
44     regs::gpu_control::*, //
45 };
46 
47 pub(crate) type IoMem = kernel::io::mem::IoMem<SZ_2M>;
48 
49 pub(crate) struct TyrDrmDriver;
50 
51 /// Convenience type alias for the DRM device type for this driver.
52 pub(crate) type TyrDrmDevice = drm::Device<TyrDrmDriver>;
53 
54 #[pin_data(PinnedDrop)]
55 pub(crate) struct TyrPlatformDriverData {
56     _device: ARef<TyrDrmDevice>,
57 }
58 
59 #[pin_data]
60 pub(crate) struct TyrDrmDeviceData {
61     pub(crate) pdev: ARef<platform::Device>,
62 
63     #[pin]
64     clks: Mutex<Clocks>,
65 
66     #[pin]
67     regulators: Mutex<Regulators>,
68 
69     /// Some information on the GPU.
70     ///
71     /// This is mainly queried by userspace, i.e.: Mesa.
72     pub(crate) gpu_info: GpuInfo,
73 }
74 
75 fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
76     let io = (*iomem).access(dev)?;
77     io.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
78 
79     poll::read_poll_timeout(
80         || {
81             let io = (*iomem).access(dev)?;
82             Ok(io.read(GPU_IRQ_RAWSTAT))
83         },
84         |status| status.reset_completed(),
85         time::Delta::from_millis(1),
86         time::Delta::from_millis(100),
87     )
88     .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
89 
90     Ok(())
91 }
92 
93 kernel::of_device_table!(
94     OF_TABLE,
95     MODULE_OF_TABLE,
96     <TyrPlatformDriverData as platform::Driver>::IdInfo,
97     [
98         (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
99         (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
100     ]
101 );
102 
103 impl platform::Driver for TyrPlatformDriverData {
104     type IdInfo = ();
105     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
106 
107     fn probe(
108         pdev: &platform::Device<Core>,
109         _info: Option<&Self::IdInfo>,
110     ) -> impl PinInit<Self, Error> {
111         let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
112         let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
113         let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
114 
115         core_clk.prepare_enable()?;
116         stacks_clk.prepare_enable()?;
117         coregroup_clk.prepare_enable()?;
118 
119         let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
120         let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
121 
122         let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
123         let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
124 
125         issue_soft_reset(pdev.as_ref(), &iomem)?;
126         gpu::l2_power_on(pdev.as_ref(), &iomem)?;
127 
128         let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?;
129         gpu_info.log(pdev.as_ref());
130 
131         let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features)
132             .pa_bits()
133             .get();
134         // SAFETY: No concurrent DMA allocations or mappings can be made because
135         // the device is still being probed and therefore isn't being used by
136         // other threads of execution.
137         unsafe { pdev.dma_set_mask_and_coherent(DmaMask::try_new(pa_bits)?)? };
138 
139         let platform: ARef<platform::Device> = pdev.into();
140 
141         let data = try_pin_init!(TyrDrmDeviceData {
142                 pdev: platform.clone(),
143                 clks <- new_mutex!(Clocks {
144                     core: core_clk,
145                     stacks: stacks_clk,
146                     coregroup: coregroup_clk,
147                 }),
148                 regulators <- new_mutex!(Regulators {
149                     _mali: mali_regulator,
150                     _sram: sram_regulator,
151                 }),
152                 gpu_info,
153         });
154 
155         let ddev: ARef<TyrDrmDevice> = drm::Device::new(pdev.as_ref(), data)?;
156         drm::driver::Registration::new_foreign_owned(&ddev, pdev.as_ref(), 0)?;
157 
158         let driver = TyrPlatformDriverData { _device: ddev };
159 
160         // We need this to be dev_info!() because dev_dbg!() does not work at
161         // all in Rust for now, and we need to see whether probe succeeded.
162         dev_info!(pdev, "Tyr initialized correctly.\n");
163         Ok(driver)
164     }
165 }
166 
167 #[pinned_drop]
168 impl PinnedDrop for TyrPlatformDriverData {
169     fn drop(self: Pin<&mut Self>) {}
170 }
171 
172 // We need to retain the name "panthor" to achieve drop-in compatibility with
173 // the C driver in the userspace stack.
174 const INFO: drm::DriverInfo = drm::DriverInfo {
175     major: 1,
176     minor: 5,
177     patchlevel: 0,
178     name: c"panthor",
179     desc: c"ARM Mali Tyr DRM driver",
180 };
181 
182 #[vtable]
183 impl drm::Driver for TyrDrmDriver {
184     type Data = TyrDrmDeviceData;
185     type File = TyrDrmFileData;
186     type Object = drm::gem::shmem::Object<BoData>;
187 
188     const INFO: drm::DriverInfo = INFO;
189 
190     kernel::declare_drm_ioctls! {
191         (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, TyrDrmFileData::dev_query),
192     }
193 }
194 
195 struct Clocks {
196     core: Clk,
197     stacks: OptionalClk,
198     coregroup: OptionalClk,
199 }
200 
201 impl Drop for Clocks {
202     fn drop(&mut self) {
203         self.core.disable_unprepare();
204         self.stacks.disable_unprepare();
205         self.coregroup.disable_unprepare();
206     }
207 }
208 
209 struct Regulators {
210     _mali: Regulator<regulator::Enabled>,
211     _sram: Regulator<regulator::Enabled>,
212 }
213