| 1 | |
| 2 |
|
| 3 | use 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 |
|
| 38 | use crate::{
|
| 39 | file::TyrDrmFileData,
|
| 40 | fw::Firmware,
|
| 41 | gem::Bo,
|
| 42 | gpu,
|
| 43 | gpu::GpuInfo,
|
| 44 | mmu::Mmu,
|
| 45 | regs::gpu_control::*, |
| 46 | };
|
| 47 |
|
| 48 | pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
|
| 49 |
|
| 50 | pub(crate) struct TyrDrmDriver;
|
| 51 |
|
| 52 | |
| 53 | pub(crate) type TyrDrmDevice<Ctx = drm::Normal> = drm::Device<TyrDrmDriver, Ctx>;
|
| 54 |
|
| 55 | pub(crate) struct TyrPlatformDriver;
|
| 56 |
|
| 57 | #[pin_data(PinnedDrop)]
|
| 58 | pub(crate) struct TyrPlatformDriverData<'bound> {
|
| 59 | _reg: drm::Registration<'bound, TyrDrmDriver>,
|
| 60 | }
|
| 61 |
|
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | #[pin_data]
|
| 67 | pub(crate) struct TyrDrmRegistrationData<'drm> {
|
| 68 | |
| 69 | pub(crate) pdev: &'drm platform::Device<Bound>,
|
| 70 |
|
| 71 | |
| 72 | pub(crate) fw: Firmware<'drm>,
|
| 73 |
|
| 74 | #[pin]
|
| 75 | clks: Mutex<Clocks>,
|
| 76 |
|
| 77 | #[pin]
|
| 78 | regulators: Mutex<Regulators>,
|
| 79 |
|
| 80 | |
| 81 | pub(crate) iomem: Arc<IoMem<'drm>>,
|
| 82 |
|
| 83 | |
| 84 | pub(crate) gpu_info: GpuInfo,
|
| 85 | }
|
| 86 |
|
| 87 | fn 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 |
|
| 101 | kernel::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 |
|
| 110 | impl 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 | |
| 144 | |
| 145 | |
| 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 | |
| 179 | |
| 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]
|
| 190 | impl PinnedDrop for TyrPlatformDriverData<'_> {
|
| 191 | fn drop(self: Pin<&mut Self>) {}
|
| 192 | }
|
| 193 |
|
| 194 | |
| 195 | |
| 196 | const 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]
|
| 205 | impl 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 |
|
| 220 | struct Clocks {
|
| 221 | core: Clk,
|
| 222 | stacks: OptionalClk,
|
| 223 | coregroup: OptionalClk,
|
| 224 | }
|
| 225 |
|
| 226 | impl 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 |
|
| 234 | struct Regulators {
|
| 235 | _mali: Regulator<regulator::Enabled>,
|
| 236 | _sram: Regulator<regulator::Enabled>,
|
| 237 | }
|