xref: /linux/drivers/gpu/drm/tyr/driver.rs (revision 6fa6b5cb60490db2591bb93872b95f72315e5f53)
1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 
3 use kernel::clk::Clk;
4 use kernel::clk::OptionalClk;
5 use kernel::device::Bound;
6 use kernel::device::Core;
7 use kernel::device::Device;
8 use kernel::devres::Devres;
9 use kernel::drm;
10 use kernel::drm::ioctl;
11 use kernel::io::poll;
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::aref::ARef;
20 use kernel::sync::Arc;
21 use kernel::sync::Mutex;
22 use kernel::time;
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 fn issue_soft_reset(dev: &Device<Bound>, iomem: &Devres<IoMem>) -> Result {
57     regs::GPU_CMD.write(dev, iomem, regs::GPU_CMD_SOFT_RESET)?;
58 
59     poll::read_poll_timeout(
60         || regs::GPU_IRQ_RAWSTAT.read(dev, iomem),
61         |status| *status & regs::GPU_IRQ_RAWSTAT_RESET_COMPLETED != 0,
62         time::Delta::from_millis(1),
63         time::Delta::from_millis(100),
64     )
65     .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
66 
67     Ok(())
68 }
69 
70 kernel::of_device_table!(
71     OF_TABLE,
72     MODULE_OF_TABLE,
73     <TyrDriver as platform::Driver>::IdInfo,
74     [
75         (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
76         (of::DeviceId::new(c"arm,mali-valhall-csf"), ())
77     ]
78 );
79 
80 impl platform::Driver for TyrDriver {
81     type IdInfo = ();
82     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
83 
84     fn probe(
85         pdev: &platform::Device<Core>,
86         _info: Option<&Self::IdInfo>,
87     ) -> impl PinInit<Self, Error> {
88         let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
89         let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
90         let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
91 
92         core_clk.prepare_enable()?;
93         stacks_clk.prepare_enable()?;
94         coregroup_clk.prepare_enable()?;
95 
96         let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
97         let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
98 
99         let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
100         let iomem = Arc::pin_init(request.iomap_sized::<SZ_2M>(), GFP_KERNEL)?;
101 
102         issue_soft_reset(pdev.as_ref(), &iomem)?;
103         gpu::l2_power_on(pdev.as_ref(), &iomem)?;
104 
105         let gpu_info = GpuInfo::new(pdev.as_ref(), &iomem)?;
106         gpu_info.log(pdev);
107 
108         let platform: ARef<platform::Device> = pdev.into();
109 
110         let data = try_pin_init!(TyrData {
111                 pdev: platform.clone(),
112                 clks <- new_mutex!(Clocks {
113                     core: core_clk,
114                     stacks: stacks_clk,
115                     coregroup: coregroup_clk,
116                 }),
117                 regulators <- new_mutex!(Regulators {
118                     _mali: mali_regulator,
119                     _sram: sram_regulator,
120                 }),
121                 gpu_info,
122         });
123 
124         let tdev: ARef<TyrDevice> = drm::Device::new(pdev.as_ref(), data)?;
125         drm::driver::Registration::new_foreign_owned(&tdev, pdev.as_ref(), 0)?;
126 
127         let driver = TyrDriver { _device: tdev };
128 
129         // We need this to be dev_info!() because dev_dbg!() does not work at
130         // all in Rust for now, and we need to see whether probe succeeded.
131         dev_info!(pdev, "Tyr initialized correctly.\n");
132         Ok(driver)
133     }
134 }
135 
136 #[pinned_drop]
137 impl PinnedDrop for TyrDriver {
138     fn drop(self: Pin<&mut Self>) {}
139 }
140 
141 #[pinned_drop]
142 impl PinnedDrop for TyrData {
143     fn drop(self: Pin<&mut Self>) {
144         // TODO: the type-state pattern for Clks will fix this.
145         let clks = self.clks.lock();
146         clks.core.disable_unprepare();
147         clks.stacks.disable_unprepare();
148         clks.coregroup.disable_unprepare();
149     }
150 }
151 
152 // We need to retain the name "panthor" to achieve drop-in compatibility with
153 // the C driver in the userspace stack.
154 const INFO: drm::DriverInfo = drm::DriverInfo {
155     major: 1,
156     minor: 5,
157     patchlevel: 0,
158     name: c"panthor",
159     desc: c"ARM Mali Tyr DRM driver",
160 };
161 
162 #[vtable]
163 impl drm::Driver for TyrDriver {
164     type Data = TyrData;
165     type File = File;
166     type Object = drm::gem::Object<TyrObject>;
167 
168     const INFO: drm::DriverInfo = INFO;
169 
170     kernel::declare_drm_ioctls! {
171         (PANTHOR_DEV_QUERY, drm_panthor_dev_query, ioctl::RENDER_ALLOW, File::dev_query),
172     }
173 }
174 
175 #[pin_data]
176 struct Clocks {
177     core: Clk,
178     stacks: OptionalClk,
179     coregroup: OptionalClk,
180 }
181 
182 #[pin_data]
183 struct Regulators {
184     _mali: Regulator<regulator::Enabled>,
185     _sram: Regulator<regulator::Enabled>,
186 }
187