diff --git a/drivers/gpu/drm/asahi/asahi_core.rs b/drivers/gpu/drm/asahi/asahi_core.rs index 84a9bff28d6d75..7edb6462b7aa4a 100644 --- a/drivers/gpu/drm/asahi/asahi_core.rs +++ b/drivers/gpu/drm/asahi/asahi_core.rs @@ -137,6 +137,10 @@ module! { default: 1, description: "G15: answer firmware halts with the halt/resume handshake (0: fail-stop)", }, + g15_sleep_hold: u32 { + default: 1, + description: "G15 (T6031): keep the GFX domain on through system sleep (0: genpd may power it off under the firmware)", + }, g15_stream_gate: u32 { default: 1, description: "G15: admit only known CDM/VDM stream records (0: bring-up only)", diff --git a/drivers/gpu/drm/asahi/g15/boot.rs b/drivers/gpu/drm/asahi/g15/boot.rs index 45e244531323d7..6255ba50d4783f 100644 --- a/drivers/gpu/drm/asahi/g15/boot.rs +++ b/drivers/gpu/drm/asahi/g15/boot.rs @@ -6,7 +6,8 @@ //! `apple_pmp_t6030_board`, or the SoC's machine compatible), the PMP supplier on a SoC with //! the PMP AGX vote (`apple_pmp_j514s_gpu_prepare`, may return EPROBE_DEFER), the GPU regions and //! segments ([`super::adt`]: the ADT export, or the GPU device tree node), exact firmware TEXT -//! identity ([`super::identity`]), MMIO windows, runtime-PM hold of the GFX domain. +//! identity ([`super::identity`]), MMIO windows, runtime-PM hold of the GFX domain (on T6031 +//! through system sleep too, the device being left out of it). //! //! Start: PMP AGX vote (`apple_pmp_j514s_gpu_get`) where the SoC takes one, hardware identity //! and core masks (one word, or two above 32 core slots), `sgx_open` @@ -46,7 +47,7 @@ use super::fw::initdata::runtime; use super::hw; use super::initdata::{self, InitData}; use super::object::Objects; -use super::{identity, regs, uat, Config, Shared}; +use super::{identity, params, regs, uat, Config, Shared}; use crate::driver::AsahiDrmDevice as AsahiDevice; use crate::mmu; @@ -59,7 +60,7 @@ pub(crate) mod glue { fn asahi_g15_sha256(data: *const u8, len: usize, out: *mut u8); fn asahi_g15_board() -> bool; fn asahi_g15_machine(compatible: *const core::ffi::c_char) -> bool; - fn asahi_g15_hold_power(dev: *mut core::ffi::c_void); + fn asahi_g15_hold_power(dev: *mut core::ffi::c_void, sleep_hold: bool); fn asahi_g15_release_power(dev: *mut core::ffi::c_void); fn asahi_g15_module_try_get() -> bool; fn asahi_g15_module_put(); @@ -105,10 +106,12 @@ pub(crate) mod glue { unsafe { asahi_g15_machine(compatible.as_char_ptr()) } } - /// Holds the GFX power domain for the retained session. - pub(crate) fn hold_power(dev: &device::Device) { - // SAFETY: `dev` is a valid device; runtime-PM accounting on it has no other requirement. - unsafe { asahi_g15_hold_power(dev.as_raw().cast()) }; + /// Holds the GFX power domain for the retained session, and with `sleep_hold` through system + /// sleep too: the device is then left out of system sleep (`asahi_g15_hold_power()`). + pub(crate) fn hold_power(dev: &device::Device, sleep_hold: bool) { + // SAFETY: `dev` is a valid device; runtime-PM accounting and its syscore flag have no + // other requirement. + unsafe { asahi_g15_hold_power(dev.as_raw().cast(), sleep_hold) }; } /// Gives the GFX power domain hold back after a start that touched nothing firmware-visible. @@ -520,9 +523,26 @@ pub(crate) fn admit( } let board_images = initdata::prepare_board(dev, cfg, &adt)?; let regs = regs::Regs::new(pdev)?; - // Keep the GFX domain powered for the whole (retained) session. - glue::hold_power(dev); - dev_info!(dev, "{} admitted, ASC={:#x}\n", cfg.name, regs.asc_control()?); + // Read before the hold: nothing after it may fail before `Gpu::new()` can give it back. The + // domain is on already, since the probe attached the device to it. + let asc = regs.asc_control()?; + // Keep the GFX domain powered for the whole (retained) session; on T6031, whose GPU that + // domain alone powers, through system sleep too, unless g15_sleep_hold=0. + let t6031 = cfg.platform == hw::Platform::DeviceTree; + let sleep_hold = t6031 && params::sleep_hold(); + glue::hold_power(dev, sleep_hold); + dev_info!(dev, "{} admitted, ASC={:#x}\n", cfg.name, asc); + if sleep_hold { + dev_info!( + dev, + "G15: the GFX domain stays on through system sleep, as nothing starts the firmware again (g15_sleep_hold=0 lets genpd power it off)\n" + ); + } else if t6031 { + dev_warn!( + dev, + "G15: g15_sleep_hold=0: system sleep may power the GFX domain off under the firmware, which nothing starts again\n" + ); + } Ok(Admitted { regs, adt, board_images }) } diff --git a/drivers/gpu/drm/asahi/g15/glue.c b/drivers/gpu/drm/asahi/g15/glue.c index 385b9fde390538..476bfb7b62d285 100644 --- a/drivers/gpu/drm/asahi/g15/glue.c +++ b/drivers/gpu/drm/asahi/g15/glue.c @@ -24,7 +24,7 @@ void asahi_g15_sha256(const u8 *data, size_t len, u8 *out); bool asahi_g15_board(void); bool asahi_g15_machine(const char *compatible); -void asahi_g15_hold_power(struct device *dev); +void asahi_g15_hold_power(struct device *dev, bool sleep_hold); void asahi_g15_release_power(struct device *dev); bool asahi_g15_module_try_get(void); void asahi_g15_module_put(void); @@ -222,12 +222,24 @@ bool asahi_g15_machine(const char *compatible) * Keep the GFX domain powered for the whole (retained) session, like the * firmware session itself; released only by a start that failed before the * firmware was touched (asahi_g15_release_power()). + * + * With @sleep_hold (T6031), through system sleep as well. In the noirq + * phase genpd counts the GPU, the only device in the domain, as suspended, + * whatever its runtime-PM state, and powers the domain off under the + * running firmware, which nothing starts again. genpd spares a device in + * the wakeup path only in a domain with GENPD_FLAG_ACTIVE_WAKEUP, which + * PMGR gives only to a domain it finds on when it probes it. As a syscore + * device the GPU is left out of system sleep instead: genpd never counts it + * as suspended, and the domain stays on, as dwc3-apple keeps its core's + * domain on and the ISP and the SEP those of their resident firmware. + * Nothing changes while the system is awake. */ -void asahi_g15_hold_power(struct device *dev) +void asahi_g15_hold_power(struct device *dev, bool sleep_hold) { pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); + dev_pm_syscore_device(dev, sleep_hold); } /* @@ -238,6 +250,7 @@ void asahi_g15_hold_power(struct device *dev) */ void asahi_g15_release_power(struct device *dev) { + dev_pm_syscore_device(dev, false); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); diff --git a/drivers/gpu/drm/asahi/g15/params.rs b/drivers/gpu/drm/asahi/g15/params.rs index 48d21e45d0acd6..f25d276a6919f3 100644 --- a/drivers/gpu/drm/asahi/g15/params.rs +++ b/drivers/gpu/drm/asahi/g15/params.rs @@ -53,6 +53,12 @@ pub(crate) fn recovery() -> bool { *module_parameters::g15_recovery.value() != 0 } +/// Whether the T6031 GFX domain is held through system sleep too, the device being left out of +/// it (else genpd may power the domain off under the firmware in the noirq phase). +pub(crate) fn sleep_hold() -> bool { + *module_parameters::g15_sleep_hold.value() != 0 +} + /// Whether the CDM/VDM stream gates are on. pub(crate) fn stream_gate() -> bool { *module_parameters::g15_stream_gate.value() != 0