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