From 58545dfe5da728f711b38a7f408b5d16f4c4dcf2 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Fri, 29 May 2026 17:49:04 +0300 Subject: [PATCH 1/7] add PMPv1 driver Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- arch/arm64/boot/dts/apple/t8103.dtsi | 213 +++++++++++++- drivers/pmdomain/apple/Kconfig | 14 + drivers/pmdomain/apple/Makefile | 1 + drivers/pmdomain/apple/pmp_v1_report.rs | 294 +++++++++++++++++++ drivers/soc/apple/Kconfig | 14 + drivers/soc/apple/Makefile | 2 + drivers/soc/apple/pmp_v1.rs | 358 ++++++++++++++++++++++++ rust/bindings/bindings_helper.h | 2 + rust/kernel/soc/apple/mod.rs | 4 + rust/kernel/soc/apple/pmdomain.rs | 208 ++++++++++++++ rust/kernel/soc/apple/pmp_v1_bridge.rs | 28 ++ 11 files changed, 1134 insertions(+), 4 deletions(-) create mode 100644 drivers/pmdomain/apple/pmp_v1_report.rs create mode 100644 drivers/soc/apple/pmp_v1.rs create mode 100644 rust/kernel/soc/apple/pmdomain.rs create mode 100644 rust/kernel/soc/apple/pmp_v1_bridge.rs diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 58c59075f2d2b7..72215d60868b12 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -22,6 +22,7 @@ aliases { gpu = &gpu; + pmp = &pmp; }; cpus { @@ -480,7 +481,7 @@ <0x2 0x4000000 0 0x1000000>; reg-names = "asc", "sgx"; mboxes = <&agx_mbox>; - power-domains = <&ps_gfx>; + power-domains = <&pmp_report_gfx>; memory-region = <&uat_ttbs>, <&uat_pagetables>, <&uat_handoff>, <&gpu_hw_cal_a>, <&gpu_hw_cal_b>, <&gpu_globals>; memory-region-names = "ttbs", "pagetables", "handoff", @@ -553,7 +554,7 @@ reg = <0x2 0x28200000 0x0 0xc000>, <0x2 0x28400000 0x0 0x4000>; reg-names = "be", "fe"; - power-domains = <&ps_dispdfr_fe>, <&ps_dispdfr_be>; + power-domains = <&pmp_report_dispdfr>, <&ps_dispdfr_be>; interrupt-parent = <&aic>; interrupts = , ; @@ -659,8 +660,14 @@ <0x2 0x3b3d0000 0x0 0x4000>; apple,bw-scratch = <&pmgr_dcp 0 5 0x14>; apple,bw-doorbell = <&pmgr_dcp 1 6>; +<<<<<<< HEAD apple,iomfb-surfaces = <1 1 0 0>; power-domains = <&ps_disp0_cpu0>; +||||||| parent of 7e00af94af80 (add PMPv1 driver) + power-domains = <&ps_disp0_cpu0>; +======= + power-domains = <&pmp_report_disp0>; +>>>>>>> 7e00af94af80 (add PMPv1 driver) resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -736,7 +743,7 @@ <0x2 0x2c1043f0 0x0 0x100>; interrupt-parent = <&aic>; interrupts = ; - power-domains = <&ps_isp_sys>, <&ps_isp_set0>, + power-domains = <&pmp_report_isp_sys>, <&ps_isp_set0>, <&ps_isp_set1>, <&ps_isp_set2>, <&ps_isp_fe>, <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, <&ps_isp_set7>, <&ps_isp_set8>, <&ps_isp_set9>, @@ -1061,6 +1068,205 @@ #apple,bw-doorbell-cells = <2>; }; + pmp_dart: iommu@23b300000 { + compatible = "apple,t8103-dart"; + reg = <0x2 0x3b300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_mbox: mbox@23bc08000 { + compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x3bc08000 0x0 0x4000>; + interrupt-parent = <&aic>; + + interrupts = , + , + , + ; + interrupt-names = "send-empty", "send-not-empty", + "recv-empty", "recv-not-empty"; + #mbox-cells = <0>; + power-domains = <&ps_pmp>, <&ps_pms_sram>; + }; + + pmp: pmp@23b850000 { + compatible = "apple,t8103-pmp-v1"; + reg = <0x2 0x3b850000 0x0 0x200000>, + <0x2 0x3bc00000 0x0 0x60000>; + reg-names = "pmp", "asc"; + power-domains = <&ps_pmp>; + + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + #address-cells = <1>; + #size-cells = <0>; + iommus = <&pmp_dart 0>; + + apple,init-ranges = <0x0 0x00024000 0x0 0x4000>, + <0x0 0x00064000 0x0 0x4000>, + <0x0 0x000a4000 0x0 0x4000>, + <0x0 0x000e4000 0x0 0x4000>, + <0x0 0x00158000 0x0 0x4000>, + <0x0 0x00204000 0x0 0x4000>, + <0x0 0x00244000 0x0 0x4000>, + <0x0 0x00284000 0x0 0x4000>, + <0x0 0x002c4000 0x0 0x4000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x04d10000 0x0 0x4000>, + <0x0 0x10058000 0x0 0x4000>, + <0x0 0x10158000 0x0 0x4000>, + <0x0 0x10258000 0x0 0x4000>, + <0x0 0x10358000 0x0 0x4000>, + <0x0 0x10e20000 0x0 0x60000>, + <0x0 0x10e48000 0x0 0x4000>, + <0x0 0x11058000 0x0 0x4000>, + <0x0 0x11158000 0x0 0x4000>, + <0x0 0x11258000 0x0 0x4000>, + <0x0 0x11358000 0x0 0x4000>, + <0x0 0x11e20000 0x0 0x60000>, + <0x0 0x11e48000 0x0 0x4000>, + <0x0 0x3d100000 0x0 0x14000>, + <0x0 0x3d128000 0x0 0x30000>, + <0x0 0x3d0d8000 0x0 0x4000>, + <0x0 0x6b90c000 0x0 0x4000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x00170000 0x0 0x4000>, + <0x0 0x00000000 0x0 0x0000>, + <0x0 0x3c100000 0x0 0x4000>, + <0x0 0x04e20000 0x0 0x4000>, + <0x0 0x11ee0000 0x0 0x8000>, + <0x0 0x11ee8000 0x0 0x8000>, + <0x0 0x11ef0000 0x0 0x8000>, + <0x0 0x10ee0000 0x0 0x8000>, + <0x0 0x04d80000 0x0 0x8000>; + + pmp_report_gfx: report@99 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-gfx"; + reg = <99>; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@104 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-ane-sys"; + reg = <104>; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@100 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-isp-sys"; + reg = <0x64>; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + }; + + pmp_report_disp0: report@84 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-disp0"; + reg = <84>; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext: report@85 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-dispext"; + reg = <0x55>; + #power-domain-cells = <0>; + power-domains = <&ps_dispext_cpu0>; + }; + + pmp_report_venc_sys: report@101 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-venc-sys"; + reg = <101>; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@102 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-avd-sys"; + reg = <102>; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr: report@93 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-msr"; + reg = <0x5d>; + #power-domain-cells = <0>; + power-domains = <&ps_msr>; + status = "disabled"; + }; + + pmp_report_jpg: report@92 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-jpg"; + reg = <0x5c>; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_dispdfr: report@219 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-dispdfr"; + reg = <219>; + #power-domain-cells = <0>; + power-domains = <&ps_dispdfr_fe>; + }; + + pmp_report_atc0_pcie: report@e { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-atc0_pcie"; + reg = <0xe>; + #power-domain-cells = <0>; + power-domains = <&ps_atc0_pcie>; + status = "disabled"; + }; + + pmp_report_atc1_pcie: report@62 { + compatible = "apple,t8103-pmp-v1-report-entry"; + label = "pmp-atc1_pcie"; + reg = <0x3e>; + #power-domain-cells = <0>; + power-domains = <&ps_atc1_pcie>; + status = "disabled"; + }; + + // pmp_report_atc0_pcie_v: report@10 { + // compatible = "apple,t8103-pmp-v1-report-entry"; + // label = "pmp-atc0_pcie-v"; + // #power-domain-cells = <0>; + // power-domains = <&ps_atc0_pcie_v>; + // }; + + // pmp_report_atc1_pcie_v: report@11 { + // compatible = "apple,t8103-pmp-v1-report-entry"; + // label = "pmp-atc1_pcie-v"; + // #power-domain-cells = <0>; + // power-domains = <&ps_atc1_pcie_v>; + // }; + + }; + pinctrl_ap: pinctrl@23c100000 { compatible = "apple,t8103-pinctrl", "apple,pinctrl"; reg = <0x2 0x3c100000 0x0 0x100000>; @@ -1712,7 +1918,6 @@ msi-parent = <&pcie0>; msi-ranges = <&aic AIC_IRQ 704 IRQ_TYPE_EDGE_RISING 32>; - iommu-map = <0x100 &pcie0_dart_0 1 1>, <0x200 &pcie0_dart_1 1 1>, <0x300 &pcie0_dart_2 1 1>; diff --git a/drivers/pmdomain/apple/Kconfig b/drivers/pmdomain/apple/Kconfig index 6e9deb9de0739c..72a10134e5365d 100644 --- a/drivers/pmdomain/apple/Kconfig +++ b/drivers/pmdomain/apple/Kconfig @@ -20,4 +20,18 @@ config APPLE_PMP_REPORT depends on PM select PM_GENERIC_DOMAINS +config APPLE_PMP_V1_REPORT + bool "Apple PMPv1 report control" + depends on OF + depends on PM + select PM_GENERIC_DOMAINS + + help + Enable support for the Apple PMPv1 report control driver. + + This provides power-domain support for PMPv1 report entries + described in the device tree on Apple SoCs. + + Say 'y' if you have an Apple machine with PMPv1. + endif diff --git a/drivers/pmdomain/apple/Makefile b/drivers/pmdomain/apple/Makefile index b098b204d9868a..cfc7138de30f73 100644 --- a/drivers/pmdomain/apple/Makefile +++ b/drivers/pmdomain/apple/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += pmgr-pwrstate.o obj-$(CONFIG_APPLE_PMP_REPORT) += pmp-report.o +obj-$(CONFIG_APPLE_PMP_V1_REPORT) += pmp_v1_report.o diff --git a/drivers/pmdomain/apple/pmp_v1_report.rs b/drivers/pmdomain/apple/pmp_v1_report.rs new file mode 100644 index 00000000000000..8aa9fc5e2a3e50 --- /dev/null +++ b/drivers/pmdomain/apple/pmp_v1_report.rs @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +#![recursion_limit = "2048"] + +//! Apple SoC PMPv1 power state reporting driver + +use kernel::{ + container_of, + device::{ + self, + Core, + }, + module_platform_driver, + of, + platform, + prelude::*, + soc::apple::{ + pmdomain, + pmp_v1_bridge + }, + sync::Arc, + types::{ScopeGuard, ForeignOwnable, ARef}, +}; + +#[repr(C)] +struct ReportEntry { + dev: ARef, + pub genpd: pmdomain::GenericPmDomain, + id: u32, +} + +impl ReportEntry { + fn genpd_ptr(&self) -> *mut pmdomain::GenericPmDomain { + &raw const self.genpd as *mut _ + } + + unsafe fn from_genpd<'a>(genpd: *mut pmdomain::GenericPmDomain) -> &'a mut Self { + unsafe { &mut *container_of!(genpd, ReportEntry, genpd) } + } +} + +#[pin_data] +struct PmpReportData { + #[pin] + dev: ARef, + #[pin] + node: of::Node, + #[pin] + entry: Pin>, +} + +impl PmpReportData { + fn new(pdev: &platform::Device, + node: of::Node, + entry: Pin>) -> Result> + { + Arc::pin_init( + try_pin_init!( + PmpReportData { + dev: pdev.as_ref().into(), + node, + entry + } + ), + GFP_KERNEL, + ) + } +} + +unsafe impl Send for PmpReportData {} +unsafe impl Sync for PmpReportData {} + +struct PmpV1ReportDriver(Arc); + +impl Drop for PmpV1ReportDriver { + fn drop(&mut self) { + pmdomain::of_del_provider(&self.0.node); + + let genpd = self.0.entry.genpd_ptr(); + let _ = pmdomain::genpd_remove(genpd); + } +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + (), + [(of::DeviceId::new(c"apple,t8103-pmp-v1-report-entry"), ())] +); + +unsafe extern "C" fn report_entry_set_state( + genpd: *mut pmdomain::GenericPmDomain, + enable: bool) -> c_int +{ + let ent = unsafe { ReportEntry::from_genpd(genpd) }; + + let parent = ent.dev.as_ref().parent().unwrap(); + + dev_info!(ent.dev, "Setting state '{}' for device {}", enable, ent.id); + + // SAFETY: our parent is PmpDriver, and its repr(transparent) for Arc + let pdata_ptr = unsafe { + Pin::>>::borrow(parent.get_drvdata()) + }; + let bridge = (&*pdata_ptr).clone(); + + while !bridge.ready() { + } + dev_info!(ent.dev, "Bridge ready"); + + // TODO: handle errors + bridge.send_devpwr(ent.id as u64, enable).unwrap(); + + 0 +} + +unsafe extern "C" fn report_entry_power_on(genpd: *mut pmdomain::GenericPmDomain) -> c_int { + unsafe { report_entry_set_state(genpd, true) } +} + +unsafe extern "C" fn report_entry_power_off(genpd: *mut pmdomain::GenericPmDomain) -> c_int { + unsafe { report_entry_set_state(genpd, false) } +} + +impl platform::Driver for PmpV1ReportDriver { + type IdInfo = (); + + const OF_ID_TABLE: Option> = Some(&OF_TABLE); + + fn probe( + pdev: &platform::Device, + _info: Option<&()>, + ) -> impl PinInit { + let dev: ARef = pdev.as_ref().into(); + let node = dev.of_node().ok_or(ENODEV)?; + + let id = node.get_property::(c"reg")?; + + let label_prop = node.get_property::>(c"label")?; + let label = CStr::from_bytes_with_nul(&label_prop).map_err(|_| EINVAL)?; + + let mut entry = KBox::into_pin(KBox::new( + ReportEntry { + dev, + // SAFETY: valid in C so also valid here + genpd: unsafe { core::mem::zeroed() }, + id, + }, + GFP_KERNEL, + )?); + + let entry_mut = unsafe { Pin::get_unchecked_mut(entry.as_mut()) }; + + match node.get_property::(c"apple,always-on") { + Ok(_) => {} + _ => { + entry_mut.genpd.flags |= pmdomain::GENPD_FLAG_ACTIVE_WAKEUP; + } + } + entry_mut.genpd.name = label.as_char_ptr(); + entry_mut.genpd.power_on = Some(report_entry_power_on); + entry_mut.genpd.power_off = Some(report_entry_power_off); + + let genpd = entry_mut.genpd_ptr(); + pmdomain::genpd_init(genpd, None, true)?; + pmdomain::of_add_provider_simple(&node, genpd)?; + + let remove_device = ScopeGuard::new(|| { + let _ = pmdomain::genpd_remove_device(pdev.as_ref()); + }); + + let raw_node = pmdomain::of_node_ptr(&node); + let mut it: pmdomain::OfPhandleIterator = pmdomain::of_phandle_iterator(); + + pmdomain::of_phandle_iterator_init( + &mut it, &node, c"power-domains", c"#power-domain-cells", -1)?; + + while pmdomain::of_phandle_iterator_next(&mut it)? { + let mut parent_spec = pmdomain::OfPhandleArgs { + np: it.node, + args_count: 0, + args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], + }; + + parent_spec.args_count = pmdomain::of_phandle_iterator_args( + &mut it, + parent_spec.args.as_mut_ptr(), + pmdomain::MAX_PHANDLE_ARGS.try_into().unwrap(), + ); + + let subdomain_spec = pmdomain::OfPhandleArgs { + np: raw_node, + args_count: 0, + args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], + }; + + if let Err(e) = pmdomain::of_add_subdomain(&parent_spec, &subdomain_spec) { + dev_err!(entry.dev, "failed to add to parent domain"); + pmdomain::of_node_put(parent_spec.np); + return Err(e); + } + } + + let data = PmpReportData::new(pdev, node, entry)?; + + remove_device.dismiss(); + + Ok(Self(data)) + } +} + +module_platform_driver! { + type: PmpV1ReportDriver, + name: "apple_pmp_v1_report", + license: "Dual MIT/GPL", +} + + let label_prop = node.get_property::>(c"label")?; + let label = CStr::from_bytes_with_nul(&label_prop).map_err(|_| EINVAL)?; + + let mut entry = KBox::into_pin(KBox::new( + ReportEntry { + dev, + // SAFETY: valid in C so also valid here + genpd: unsafe { core::mem::zeroed() }, + id, + }, + GFP_KERNEL, + )?); + + let entry_mut = unsafe { Pin::get_unchecked_mut(entry.as_mut()) }; + + match node.get_property::(c"apple,always-on") { + Ok(_) => {} + _ => { + entry_mut.genpd.flags |= pmdomain::GENPD_FLAG_ACTIVE_WAKEUP; + } + } + entry_mut.genpd.name = label.as_char_ptr(); + entry_mut.genpd.power_on = Some(report_entry_power_on); + entry_mut.genpd.power_off = Some(report_entry_power_off); + + let genpd = entry_mut.genpd_ptr(); + pmdomain::genpd_init(genpd, None, true)?; + pmdomain::of_add_provider_simple(&node, genpd)?; + + let remove_device = ScopeGuard::new(|| { + let _ = pmdomain::genpd_remove_device(pdev.as_ref()); + }); + + let raw_node = pmdomain::of_node_ptr(&node); + let mut it: pmdomain::OfPhandleIterator = pmdomain::of_phandle_iterator(); + + pmdomain::of_phandle_iterator_init( + &mut it, &node, c"power-domains", c"#power-domain-cells", -1)?; + + while pmdomain::of_phandle_iterator_next(&mut it)? { + let mut parent_spec = pmdomain::OfPhandleArgs { + np: it.node, + args_count: 0, + args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], + }; + + parent_spec.args_count = pmdomain::of_phandle_iterator_args( + &mut it, + parent_spec.args.as_mut_ptr(), + pmdomain::MAX_PHANDLE_ARGS.try_into().unwrap(), + ); + + let subdomain_spec = pmdomain::OfPhandleArgs { + np: raw_node, + args_count: 0, + args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], + }; + + if let Err(e) = pmdomain::of_add_subdomain(&parent_spec, &subdomain_spec) { + dev_err!(entry.dev, "failed to add to parent domain"); + pmdomain::of_node_put(parent_spec.np); + return Err(e); + } + } + + let data = PmpReportData::new(pdev, node, entry)?; + + remove_device.dismiss(); + + Ok(Self(data)) + } +} + +module_platform_driver! { + type: PmpV1ReportDriver, + name: "apple_pmp_v1_report", + license: "Dual MIT/GPL", +} diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index 41bd8fbc87aab3..c27ca6bb13a876 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -122,6 +122,20 @@ config APPLE_PMP Say 'y' here if you have an Apple SoC. +config APPLE_PMP_V1 + tristate "Apple Power Management Processor Version 1" + depends on ARCH_APPLE || COMPILE_TEST + depends on RUST + select APPLE_PMP_V1_REPORT + select RUST_APPLE_RTKIT + default y if ARCH_APPLE + help + A co-processor present on Apple M1 SoC, controlling power states of + fabric and other uncore components. + + Say 'y' here if you have an Apple M1 chip. + Say 'n' here if you don't have an Apple M1 chip. + endmenu endif diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 1baa6de9449589..c31d59e7ab815d 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -25,3 +25,5 @@ obj-$(CONFIG_APPLE_AOP) += aop.o obj-$(CONFIG_APPLE_SEP) += sep.o obj-$(CONFIG_APPLE_PMP) += pmp.o + +obj-$(CONFIG_APPLE_PMP_V1) += pmp_v1.o diff --git a/drivers/soc/apple/pmp_v1.rs b/drivers/soc/apple/pmp_v1.rs new file mode 100644 index 00000000000000..3926ed12d82494 --- /dev/null +++ b/drivers/soc/apple/pmp_v1.rs @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +#![recursion_limit = "2048"] + +//! Apple PMPv1 driver +//! +//! Copyright (C) The Asahi Linux Contributors + +use core::sync::atomic::{ + AtomicBool, + Ordering +}; + +use kernel::{ + bindings, + device::{ + self, + Core, + }, + platform, + devres::Devres, + dma, + io::mem::IoMem, + iosys_map::IoSysMapRef, + module_platform_driver, + new_mutex, + of, + prelude::*, + soc::apple::{ + rtkit, + pmp_v1_bridge + }, + sync::{ + Arc, + Mutex, + }, + types::{ + ARef, + ForeignOwnable, + }, +}; + +const CPU_CONTROL: usize = 0x44; +const CPU_RUN: u32 = 0x1 << 4; +const PMP_MMIO_SIZE: usize = 0x200000; +const ASC_MMIO_SIZE: usize = 0x60000; +const PMP_ENDPOINT: u8 = 0x20; +const OPC_STARTUP: u64 = 0; +const OPC_CONFIGURE: u64 = 0x10; +const OPC_CONFIGURE_ACK: u64 = 0x20; +const OPC_INIT1: u64 = 0x200; +const OPC_INIT1_ACK: u64 = 0x201; +const OPC_INIT2: u64 = 0x202; +const OPC_INIT2_ACK: u64 = 0x203; +const OPC_DEVPWR: u64 = 0x20e; +const OPC_SHIFT: u32 = 44; + +type ShMem = dma::CoherentAllocation; + +#[pin_data] +struct PmpData { + dev: ARef, + pmp_mmio: Pin>>>, + asc_mmio: Pin>>>, + #[pin] + rtkit: Mutex>>, + shmem: ShMem, + ready: AtomicBool, +} + +fn build_shmem(dev: &platform::Device) -> Result { + let mut shmem = + dma::CoherentAllocation::::alloc_coherent(dev.as_ref(), 0x10000, GFP_KERNEL)?; + + // SAFETY: + // Only this driver communicates with PMP. PMP waits for Configure message + // thus no r/w operations from the shared memory. + unsafe { + shmem.as_slice_mut(0, shmem.count())?.fill(0); + } + + Ok(shmem) +} + +fn send_dram_config(dev: &ARef, shmem: &mut ShMem) -> Result<()> { + let node = dev.fwnode().ok_or(EIO)?; + + let n_entries = node.property_count_elem::(c"apple,energy-model-dram-configs")?; + + let dram_config = node + .property_read_array_vec::(c"apple,energy-model-dram-configs", n_entries)? + .required_by(dev)?; + + unsafe { + shmem.write(&dram_config, 0x2000)?; + } + + Ok(()) +} + +fn send_init_config(dev: &ARef, shmem: &mut ShMem) -> Result { + send_dram_config(dev, shmem)?; + + let mut dva: usize = 0xc0000000; + let mut maps: KVec = KVec::::new(); + let node = dev.fwnode().ok_or(EIO)?; + + let n_entries = node.property_count_elem::(c"apple,init-ranges")? / 2; + let regions = node + .property_read_array_vec::(c"apple,init-ranges", n_entries * 2)? + .required_by(dev)?; + + let domain = unsafe { bindings::iommu_get_domain_for_dev(dev.as_raw()) }; + + let mut err = 0; + + let mut map_addresses = + |reg_indx_start: usize, reg_indx_end: usize, mut dva: usize| -> Result<()> + { + for i in reg_indx_start..reg_indx_end { + let addr = (1u64 << 33) + regions[i * 2]; + let size: u64 = regions[i * 2 + 1]; + if size == 0 { + maps.extend_from_slice(&[0u8; 16], GFP_KERNEL)?; + continue; + } + + dev_info!(dev, "map 0x{:x} -> 0x{:x}", addr, dva); + + unsafe { + err = bindings::iommu_map( + domain, + dva, + addr, + size as usize, + (bindings::IOMMU_READ | bindings::IOMMU_WRITE | bindings::IOMMU_MMIO) as i32, + bindings::GFP_KERNEL, + ); + + if err != 0 { + break; + } + } + + maps.extend_from_slice(&dva.to_le_bytes(), GFP_KERNEL)?; + maps.extend_from_slice(&size.to_le_bytes(), GFP_KERNEL)?; + + dva += size.next_multiple_of(0x4000) as usize; + } + + Ok(()) + }; + + // 1st region + map_addresses(0, 14, dva)?; + + // 2nd region + dva = 0xc1000000; + map_addresses(14, 15, dva)?; + + // so on... + dva = 0xc2000000; + map_addresses(15, 21, dva)?; + + dva = 0xc3000000; + map_addresses(21, 27, dva)?; + + dva = 0xc4000000; + map_addresses(27, 30, dva)?; + + dva = 0xc5000000; + map_addresses(30, 32, dva)?; + + dva = 0xc0024000; + map_addresses(32, 34, dva)?; + + dva = 0xc6000000; + map_addresses(34, 35, dva)?; + + dva = 0xc1004000; + map_addresses(35, 36, dva)?; + + dva = 0xc3074000; + map_addresses(36, 39, dva)?; + + dva = 0xc2074000; + map_addresses(39, 40, dva)?; + + dva = 0xc1008000; + map_addresses(40, 41, dva)?; + + unsafe { + shmem.write(&maps, 0xe000)?; + } + + Ok(0) +} + +impl PmpData { + fn new(pdev: &platform::Device) -> Result> { + let pmp_req = pdev.io_request_by_name(c"pmp").ok_or(EINVAL)?; + let pmp_mmio = KBox::pin_init(pmp_req.iomap_sized::(), GFP_KERNEL)?; + let asc_req = pdev.io_request_by_name(c"asc").ok_or(EINVAL)?; + let asc_mmio = KBox::pin_init(asc_req.iomap_sized::(), GFP_KERNEL)?; + + let dev = pdev.as_ref().into(); + let mut shmem = build_shmem(pdev)?; + + send_init_config(&dev, &mut shmem)?; + + Arc::pin_init( + try_pin_init!( + PmpData { + dev, + pmp_mmio, + asc_mmio, + rtkit <- new_mutex!(None), + shmem, + ready: AtomicBool::new(false), + } + ), + GFP_KERNEL, + ) + } + + fn start_cpu(&self, dev: &platform::Device) -> Result<()> { + let asc_mmio = self.asc_mmio.access(dev.as_ref())?; + let val = asc_mmio.read32_relaxed(CPU_CONTROL); + asc_mmio.write32_relaxed(val | CPU_RUN, CPU_CONTROL); + Ok(()) + } + + fn start(&self) -> Result<()> { + let mut guard = self.rtkit.lock(); + let mut rtk = guard.as_mut().as_pin_mut().unwrap(); + rtk.as_mut().wake()?; + rtk.start_endpoint(PMP_ENDPOINT) + } + + fn startup(&self) -> Result { + let configure_msg = (OPC_CONFIGURE << OPC_SHIFT) | self.shmem.dma_handle(); + + Ok(configure_msg) + } + + fn recv_message(&self, msg: u64) -> Result<()> { + let opc = msg >> OPC_SHIFT; + let reply = match opc { + OPC_STARTUP => self.startup()?, + OPC_CONFIGURE_ACK => + (OPC_INIT1 << OPC_SHIFT) | (1 << 16) + 0x3, + OPC_INIT1_ACK => + (OPC_INIT2 << OPC_SHIFT) | (1 << 16), + OPC_INIT2_ACK => { + self.ready.store(true, Ordering::Release); + 0 + }, + OPC_DEVPWR => msg, + 0x110 => 0, + _ => { + dev_err!(self.dev, "Got unknown message 0x{:x}", msg); + return Err(EIO); + } + }; + + if reply != 0 { + let mut rtk_guard = self.rtkit.lock(); + let rtk = rtk_guard.as_mut().as_pin_mut().unwrap(); + rtk.send_message(PMP_ENDPOINT, reply)?; + } + + Ok(()) + } +} + +impl pmp_v1_bridge::DevPwrBridge for PmpData { + fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()> { + let msg = (OPC_DEVPWR << OPC_SHIFT) + (dev << 16) + enable as u64; + self.recv_message(msg) + } + + fn ready(&self) -> bool { + self.ready.load(Ordering::Acquire) + } +} + +#[repr(transparent)] +struct PmpDriver(Arc); + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + (), + [(of::DeviceId::new(c"apple,t8103-pmp-v1"), ())] +); + +unsafe impl Send for PmpData {} +unsafe impl Sync for PmpData {} + +struct NoBuffer; +impl rtkit::Buffer for NoBuffer { + fn iova(&self) -> Result { + unreachable!() + } + + fn buf(&mut self) -> Result> { + unreachable!() + } +} + +#[vtable] +impl rtkit::Operations for PmpData { + type Data = Arc; + type Buffer = NoBuffer; + + fn recv_message(data: ::Borrowed<'_>, _ep: u8, msg: u64) { + let ret = data.recv_message(msg); + if let Err(e) = ret { + dev_err!(data.dev, "Failed to handle rtkit message, error: {:?}", e); + } + } + + fn crashed(data: ::Borrowed<'_>, _crashlog: Option<&[u8]>) { + dev_err!(data.dev, "PMP firmware crashed"); + } +} + +impl platform::Driver for PmpDriver { + type IdInfo = (); + + const OF_ID_TABLE: Option> = Some(&OF_TABLE); + + fn probe(pdev: &platform::Device, _info: Option<&()>) -> impl PinInit { + let dev: ARef = pdev.as_ref().into(); + + unsafe { + let err = bindings::devm_of_platform_populate(dev.as_raw()); + // TODO handle errors + } + + let data = PmpData::new(pdev)?; + + let rtkit = rtkit::RtKit::::new(&dev, None, 0, data.clone())?; + *data.rtkit.lock() = Some(rtkit); + + data.start_cpu(pdev)?; + data.start()?; + + let data = data as Arc; + + Ok(Self(data)) + } +} + +module_platform_driver! { + type: PmpDriver, + name: "apple_pmp_v1", + license: "Dual MIT/GPL", +} diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 11d83046554963..972f9ebdb17b0d 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -83,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ #include #include #include +#include #include /* diff --git a/rust/kernel/soc/apple/mod.rs b/rust/kernel/soc/apple/mod.rs index e77eba782a5867..1c92cd00c67a65 100644 --- a/rust/kernel/soc/apple/mod.rs +++ b/rust/kernel/soc/apple/mod.rs @@ -10,3 +10,7 @@ pub mod aop; #[cfg(CONFIG_RUST_APPLE_MAILBOX = "y")] pub mod mailbox; + +#[cfg(CONFIG_APPLE_PMP_V1_REPORT = "y")] +pub mod pmdomain; +pub mod pmp_v1_bridge; diff --git a/rust/kernel/soc/apple/pmdomain.rs b/rust/kernel/soc/apple/pmdomain.rs new file mode 100644 index 00000000000000..24c014bd89faf4 --- /dev/null +++ b/rust/kernel/soc/apple/pmdomain.rs @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +//! Power domain (PM domain) abstractions. + +use crate::{ + bindings, + device::Device, + error::{from_err_ptr, to_result, Result}, + prelude::*, + str::CStrExt, +}; + +use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; + +pub type DevPmDomain = bindings::dev_pm_domain; +pub type DevPmDomainAttachDataRaw = bindings::dev_pm_domain_attach_data; +pub type DevPmDomainListRaw = bindings::dev_pm_domain_list; +pub type DevPowerGovernor = bindings::dev_power_governor; +pub type GenericPmDomain = bindings::generic_pm_domain; +pub type GpdDevOps = bindings::gpd_dev_ops; +pub type GpdLink = bindings::gpd_link; +pub type GpdStatus = bindings::gpd_status; +pub type GpdTimingData = bindings::gpd_timing_data; +pub type GenpdGovernorData = bindings::genpd_governor_data; +pub type GenpdLockOps = bindings::genpd_lock_ops; +pub type GenpdNotification = bindings::genpd_notication; +pub type GenpdOnecellData = bindings::genpd_onecell_data; +pub type GenpdPowerState = bindings::genpd_power_state; +pub type GenpdSyncState = bindings::genpd_sync_state; +pub type GenpdXlate = bindings::genpd_xlate_t; +pub type GenericPmDomainData = bindings::generic_pm_domain_data; +pub type OfPhandleArgs = bindings::of_phandle_args; +pub type PmDomainData = bindings::pm_domain_data; + + +use crate::of; + +pub fn of_node_ptr(node: &of::Node) -> *mut bindings::device_node { + core::ptr::from_ref(node.node()) as *const bindings::device_node as *mut bindings::device_node +} + +pub fn genpd_remove_device(dev: &Device) -> Result { + // SAFETY: `dev` is valid. + to_result(unsafe { bindings::pm_genpd_remove_device(dev.as_raw()) }) +} + +/// Initialize a generic PM domain. +pub fn genpd_init( + genpd: *mut bindings::generic_pm_domain, + gov: Option<*mut bindings::dev_power_governor>, + is_off: bool, +) -> Result { + // SAFETY: Caller guarantees `genpd` and `gov` are valid. + to_result(unsafe { bindings::pm_genpd_init(genpd, gov.unwrap_or(core::ptr::null_mut()), is_off) }) +} + +/// Remove a generic PM domain. + +pub fn genpd_remove(genpd: *mut bindings::generic_pm_domain) -> Result { + // SAFETY: Caller guarantees `genpd` is valid. + to_result(unsafe { bindings::pm_genpd_remove(genpd) }) +} + +pub fn of_add_provider_simple(node: &of::Node, genpd: *mut bindings::generic_pm_domain) -> Result { + // SAFETY: Caller guarantees `genpd` is valid, and `node` is valid. + to_result(unsafe { bindings::of_genpd_add_provider_simple(of_node_ptr(node), genpd) }) +} + +pub fn of_del_provider(node: &of::Node) { + // SAFETY: `node` is valid. + unsafe { bindings::of_genpd_del_provider(of_node_ptr(node)) }; +} + +/// Add a subdomain from phandle args. +pub fn of_add_subdomain( + parent_spec: *const bindings::of_phandle_args, + subdomain_spec: *const bindings::of_phandle_args, +||||||| parent of 7e00af94af80 (add PMPv1 driver) +======= + +use crate::{ + bindings, + device::Device, + error::{to_result, Result}, + of, + prelude::*, + str::CStrExt, +}; + +/// Binding for `dev_power_governor` +pub type DevPowerGovernor = bindings::dev_power_governor; +/// Binding for `generic_pm_domain` +pub type GenericPmDomain = bindings::generic_pm_domain; +/// Binding for `device_node` +pub type DeviceNode = bindings::device_node; +/// Binding for `of_phandle_args` +pub type OfPhandleArgs = bindings::of_phandle_args; +/// Binding for `of_phandle_iterator` +pub type OfPhandleIterator = bindings::of_phandle_iterator; + +/// Binding for `MAX_PHANDLE_ARGS` +pub const MAX_PHANDLE_ARGS: u32 = bindings::MAX_PHANDLE_ARGS; +/// Binding for `GENPD_FLAG_ACTIVE_WAKEUP` +pub const GENPD_FLAG_ACTIVE_WAKEUP: u32 = bindings::GENPD_FLAG_ACTIVE_WAKEUP; + +/// Returns the raw device node pointer for an OF node. +pub fn of_node_ptr(node: &of::Node) -> *mut DeviceNode { + core::ptr::from_ref(node.node()) as *const DeviceNode as *mut DeviceNode +} + +/// Creates an uninitialized phandle iterator. +pub fn of_phandle_iterator() -> OfPhandleIterator { + // SAFETY: The zeroed iterator is initialized by `of_phandle_iterator_init` + // before use. + unsafe { core::mem::zeroed() } +} + +/// Initializes a phandle iterator for a node property. +pub fn of_phandle_iterator_init( + it: &mut OfPhandleIterator, + node: &of::Node, + list_name: &CStr, + cells_name: &CStr, + cell_count: c_int, +) -> Result { + to_result(unsafe { + bindings::of_phandle_iterator_init( + it, + of_node_ptr(node), + list_name.as_char_ptr(), + cells_name.as_char_ptr(), + cell_count, + ) + }) +} + +/// Advances a phandle iterator. +pub fn of_phandle_iterator_next(it: &mut OfPhandleIterator) -> Result { + let ret = unsafe { bindings::of_phandle_iterator_next(it) }; + if ret == ENOENT.to_errno() { + Ok(false) + } else if ret < 0 { + Err(Error::from_errno(ret)) + } else { + Ok(true) + } +} + +/// Reads the argument cells for the current phandle iterator entry. +pub fn of_phandle_iterator_args( + it: &mut OfPhandleIterator, + args: *mut u32, + size: c_int, +) -> c_int { + // SAFETY: Caller guarantees `args` is valid for `size` elements. + unsafe { bindings::of_phandle_iterator_args(it, args, size) } +} + +/// Drops a device node reference. +pub fn of_node_put(node: *mut DeviceNode) { + // SAFETY: `node` is either NULL or a reference owned by the caller. + unsafe { bindings::of_node_put(node) }; +} + +/// Removes a device from its generic PM domain. +pub fn genpd_remove_device(dev: &Device) -> Result { + // SAFETY: `dev` is valid. + to_result(unsafe { bindings::pm_genpd_remove_device(dev.as_raw()) }) +} + +/// Initialize a generic PM domain. +pub fn genpd_init( + genpd: *mut GenericPmDomain, + gov: Option<*mut DevPowerGovernor>, + is_off: bool, +) -> Result { + // SAFETY: caller guarantees `genpd` and `gov` are valid. + to_result( + unsafe { bindings::pm_genpd_init(genpd, gov.unwrap_or(core::ptr::null_mut()), is_off) } + ) +} + +/// Remove a generic PM domain. +pub fn genpd_remove(genpd: *mut GenericPmDomain) -> Result { + // SAFETY: Caller guarantees `genpd` is valid. + to_result(unsafe { bindings::pm_genpd_remove(genpd) }) +} + +/// Adds a simple OF generic PM domain provider. +pub fn of_add_provider_simple(node: &of::Node, genpd: *mut GenericPmDomain) -> Result { + // SAFETY: Caller guarantees `genpd` is valid, and `node` is valid. + to_result(unsafe { bindings::of_genpd_add_provider_simple(of_node_ptr(node), genpd) }) +} + +/// Removes an OF generic PM domain provider. +pub fn of_del_provider(node: &of::Node) { + // SAFETY: `node` is valid. + unsafe { bindings::of_genpd_del_provider(of_node_ptr(node)) }; +} + +/// Add a subdomain from phandle args. +pub fn of_add_subdomain( + parent_spec: &OfPhandleArgs, + subdomain_spec: &OfPhandleArgs, +) -> Result { + // SAFETY: Caller guarantees `parent_spec` and `subdomain_spec` are valid. + to_result(unsafe { bindings::of_genpd_add_subdomain(parent_spec, subdomain_spec) }) +} diff --git a/rust/kernel/soc/apple/pmp_v1_bridge.rs b/rust/kernel/soc/apple/pmp_v1_bridge.rs new file mode 100644 index 00000000000000..050b597907a5fd --- /dev/null +++ b/rust/kernel/soc/apple/pmp_v1_bridge.rs @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT + +<<<<<<< HEAD +//! Common code for PMP V1 endpoint drivers + +use kernel::prelude::*; + +// Allowing for report-entry drivers to send power on/off message +// through RTKit. +pub trait DevPwrBridge: Send + Sync { + fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()>; +} + +||||||| parent of 7e00af94af80 (add PMPv1 driver) +======= +//! Common code for PMPv1 endpoint drivers + +use kernel::prelude::*; + +/// Allows report-entry drivers to send power on/off messages through RTKit. +pub trait DevPwrBridge: Send + Sync { + /// Sends a device power state request. + fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()>; + + /// Returns whether the bridge is ready to accept requests. + fn ready(&self) -> bool; +} +>>>>>>> 7e00af94af80 (add PMPv1 driver) From 231eac629fc6b17a649986405ac2292741cbf4a1 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Sun, 23 Aug 2026 21:10:33 +0300 Subject: [PATCH 2/7] add pmp-v1 pd docs Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- .../bindings/power/apple,pmp-v1.yaml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/apple,pmp-v1.yaml diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml new file mode 100644 index 00000000000000..2a7ed011495add --- /dev/null +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/apple,pmp-v1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple PMPv1 Power Domains + +maintainers: + - dd-dreams + +description: + Apple PMPv1 power domains are controlled by the Apple Power Management + Processor (PMP). Report-entry nodes expose individual PMP-managed resources as + generic power domains. + +properties: + compatible: + enum: + - apple,t8103-pmp-v1 + - apple,t8103-pmp-v1-report-entry + +required: + - compatible + +additionalProperties: true From 3bb6ff024fc846544821f4c5a85fb18f6cf2994b Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Sun, 23 Aug 2026 21:55:14 +0300 Subject: [PATCH 3/7] remove git leftovers Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- arch/arm64/boot/dts/apple/t8103.dtsi | 6 -- rust/kernel/soc/apple/pmdomain.rs | 78 +------------------------- rust/kernel/soc/apple/pmp_v1_bridge.rs | 14 ----- 3 files changed, 1 insertion(+), 97 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 72215d60868b12..15b8d9bdcf1d2e 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -660,14 +660,8 @@ <0x2 0x3b3d0000 0x0 0x4000>; apple,bw-scratch = <&pmgr_dcp 0 5 0x14>; apple,bw-doorbell = <&pmgr_dcp 1 6>; -<<<<<<< HEAD apple,iomfb-surfaces = <1 1 0 0>; - power-domains = <&ps_disp0_cpu0>; -||||||| parent of 7e00af94af80 (add PMPv1 driver) - power-domains = <&ps_disp0_cpu0>; -======= power-domains = <&pmp_report_disp0>; ->>>>>>> 7e00af94af80 (add PMPv1 driver) resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; diff --git a/rust/kernel/soc/apple/pmdomain.rs b/rust/kernel/soc/apple/pmdomain.rs index 24c014bd89faf4..15aa87f61e52d0 100644 --- a/rust/kernel/soc/apple/pmdomain.rs +++ b/rust/kernel/soc/apple/pmdomain.rs @@ -1,82 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT -//! Power domain (PM domain) abstractions. - -use crate::{ - bindings, - device::Device, - error::{from_err_ptr, to_result, Result}, - prelude::*, - str::CStrExt, -}; - -use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; - -pub type DevPmDomain = bindings::dev_pm_domain; -pub type DevPmDomainAttachDataRaw = bindings::dev_pm_domain_attach_data; -pub type DevPmDomainListRaw = bindings::dev_pm_domain_list; -pub type DevPowerGovernor = bindings::dev_power_governor; -pub type GenericPmDomain = bindings::generic_pm_domain; -pub type GpdDevOps = bindings::gpd_dev_ops; -pub type GpdLink = bindings::gpd_link; -pub type GpdStatus = bindings::gpd_status; -pub type GpdTimingData = bindings::gpd_timing_data; -pub type GenpdGovernorData = bindings::genpd_governor_data; -pub type GenpdLockOps = bindings::genpd_lock_ops; -pub type GenpdNotification = bindings::genpd_notication; -pub type GenpdOnecellData = bindings::genpd_onecell_data; -pub type GenpdPowerState = bindings::genpd_power_state; -pub type GenpdSyncState = bindings::genpd_sync_state; -pub type GenpdXlate = bindings::genpd_xlate_t; -pub type GenericPmDomainData = bindings::generic_pm_domain_data; -pub type OfPhandleArgs = bindings::of_phandle_args; -pub type PmDomainData = bindings::pm_domain_data; - - -use crate::of; - -pub fn of_node_ptr(node: &of::Node) -> *mut bindings::device_node { - core::ptr::from_ref(node.node()) as *const bindings::device_node as *mut bindings::device_node -} - -pub fn genpd_remove_device(dev: &Device) -> Result { - // SAFETY: `dev` is valid. - to_result(unsafe { bindings::pm_genpd_remove_device(dev.as_raw()) }) -} - -/// Initialize a generic PM domain. -pub fn genpd_init( - genpd: *mut bindings::generic_pm_domain, - gov: Option<*mut bindings::dev_power_governor>, - is_off: bool, -) -> Result { - // SAFETY: Caller guarantees `genpd` and `gov` are valid. - to_result(unsafe { bindings::pm_genpd_init(genpd, gov.unwrap_or(core::ptr::null_mut()), is_off) }) -} - -/// Remove a generic PM domain. - -pub fn genpd_remove(genpd: *mut bindings::generic_pm_domain) -> Result { - // SAFETY: Caller guarantees `genpd` is valid. - to_result(unsafe { bindings::pm_genpd_remove(genpd) }) -} - -pub fn of_add_provider_simple(node: &of::Node, genpd: *mut bindings::generic_pm_domain) -> Result { - // SAFETY: Caller guarantees `genpd` is valid, and `node` is valid. - to_result(unsafe { bindings::of_genpd_add_provider_simple(of_node_ptr(node), genpd) }) -} - -pub fn of_del_provider(node: &of::Node) { - // SAFETY: `node` is valid. - unsafe { bindings::of_genpd_del_provider(of_node_ptr(node)) }; -} - -/// Add a subdomain from phandle args. -pub fn of_add_subdomain( - parent_spec: *const bindings::of_phandle_args, - subdomain_spec: *const bindings::of_phandle_args, -||||||| parent of 7e00af94af80 (add PMPv1 driver) -======= +//! Power domain abstractions. use crate::{ bindings, diff --git a/rust/kernel/soc/apple/pmp_v1_bridge.rs b/rust/kernel/soc/apple/pmp_v1_bridge.rs index 050b597907a5fd..5f3e8cea56152c 100644 --- a/rust/kernel/soc/apple/pmp_v1_bridge.rs +++ b/rust/kernel/soc/apple/pmp_v1_bridge.rs @@ -1,18 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT -<<<<<<< HEAD -//! Common code for PMP V1 endpoint drivers - -use kernel::prelude::*; - -// Allowing for report-entry drivers to send power on/off message -// through RTKit. -pub trait DevPwrBridge: Send + Sync { - fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()>; -} - -||||||| parent of 7e00af94af80 (add PMPv1 driver) -======= //! Common code for PMPv1 endpoint drivers use kernel::prelude::*; @@ -25,4 +12,3 @@ pub trait DevPwrBridge: Send + Sync { /// Returns whether the bridge is ready to accept requests. fn ready(&self) -> bool; } ->>>>>>> 7e00af94af80 (add PMPv1 driver) From 4bde67e45741a6e4cd8dc50c77e56fda172448c6 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:47:32 +0300 Subject: [PATCH 4/7] fix build and address feedback Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- arch/arm64/boot/dts/apple/t8103.dtsi | 95 ++++++++------- drivers/pmdomain/apple/Kconfig | 10 +- drivers/pmdomain/apple/pmp_v1_report.rs | 105 +++-------------- drivers/soc/apple/Kconfig | 2 - drivers/soc/apple/pmp_v1.rs | 148 +++++++++--------------- rust/kernel/soc/apple/mod.rs | 1 + rust/kernel/soc/apple/pmp_v1_bridge.rs | 9 +- rust/kernel/sync/completion.rs | 18 ++- 8 files changed, 147 insertions(+), 241 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi index 15b8d9bdcf1d2e..cf414f2da8db44 100644 --- a/arch/arm64/boot/dts/apple/t8103.dtsi +++ b/arch/arm64/boot/dts/apple/t8103.dtsi @@ -1099,47 +1099,60 @@ #size-cells = <0>; iommus = <&pmp_dart 0>; - apple,init-ranges = <0x0 0x00024000 0x0 0x4000>, - <0x0 0x00064000 0x0 0x4000>, - <0x0 0x000a4000 0x0 0x4000>, - <0x0 0x000e4000 0x0 0x4000>, - <0x0 0x00158000 0x0 0x4000>, - <0x0 0x00204000 0x0 0x4000>, - <0x0 0x00244000 0x0 0x4000>, - <0x0 0x00284000 0x0 0x4000>, - <0x0 0x002c4000 0x0 0x4000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x04d10000 0x0 0x4000>, - <0x0 0x10058000 0x0 0x4000>, - <0x0 0x10158000 0x0 0x4000>, - <0x0 0x10258000 0x0 0x4000>, - <0x0 0x10358000 0x0 0x4000>, - <0x0 0x10e20000 0x0 0x60000>, - <0x0 0x10e48000 0x0 0x4000>, - <0x0 0x11058000 0x0 0x4000>, - <0x0 0x11158000 0x0 0x4000>, - <0x0 0x11258000 0x0 0x4000>, - <0x0 0x11358000 0x0 0x4000>, - <0x0 0x11e20000 0x0 0x60000>, - <0x0 0x11e48000 0x0 0x4000>, - <0x0 0x3d100000 0x0 0x14000>, - <0x0 0x3d128000 0x0 0x30000>, - <0x0 0x3d0d8000 0x0 0x4000>, - <0x0 0x6b90c000 0x0 0x4000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x00170000 0x0 0x4000>, - <0x0 0x00000000 0x0 0x0000>, - <0x0 0x3c100000 0x0 0x4000>, - <0x0 0x04e20000 0x0 0x4000>, - <0x0 0x11ee0000 0x0 0x8000>, - <0x0 0x11ee8000 0x0 0x8000>, - <0x0 0x11ef0000 0x0 0x8000>, - <0x0 0x10ee0000 0x0 0x8000>, - <0x0 0x04d80000 0x0 0x8000>; + apple,init-ranges = <0x00024000 0x4000>, + <0x00064000 0x4000>, + <0x000a4000 0x4000>, + <0x000e4000 0x4000>, + <0x00158000 0x4000>, + <0x00204000 0x4000>, + <0x00244000 0x4000>, + <0x00284000 0x4000>, + <0x002c4000 0x4000>, + <0x00000000 0x0000>, + <0x00000000 0x0000>, + <0x00000000 0x0000>, + <0x00000000 0x0000>, + <0x00000000 0x0000>, + <0x04d10000 0x4000>, + <0x10058000 0x4000>, + <0x10158000 0x4000>, + <0x10258000 0x4000>, + <0x10358000 0x4000>, + <0x10e20000 0x60000>, + <0x10e48000 0x4000>, + <0x11058000 0x4000>, + <0x11158000 0x4000>, + <0x11258000 0x4000>, + <0x11358000 0x4000>, + <0x11e20000 0x60000>, + <0x11e48000 0x4000>, + <0x3d100000 0x14000>, + <0x3d128000 0x30000>, + <0x3d0d8000 0x4000>, + <0x6b90c000 0x4000>, + <0x00000000 0x0000>, + <0x00170000 0x4000>, + <0x00000000 0x0000>, + <0x3c100000 0x4000>, + <0x04e20000 0x4000>, + <0x11ee0000 0x8000>, + <0x11ee8000 0x8000>, + <0x11ef0000 0x8000>, + <0x10ee0000 0x8000>, + <0x04d80000 0x8000>; + + apple,init-dva = <0xc0000000 0xe>, + <0xc1000000 1>, + <0xc2000000 6>, + <0xc3000000 6>, + <0xc4000000 3>, + <0xc5000000 2>, + <0xc0024000 2>, + <0xc6000000 1>, + <0xc1004000 1>, + <0xc3074000 3>, + <0xc2074000 1>, + <0xc1008000 1>; pmp_report_gfx: report@99 { compatible = "apple,t8103-pmp-v1-report-entry"; diff --git a/drivers/pmdomain/apple/Kconfig b/drivers/pmdomain/apple/Kconfig index 72a10134e5365d..66f7ab50bc48f3 100644 --- a/drivers/pmdomain/apple/Kconfig +++ b/drivers/pmdomain/apple/Kconfig @@ -21,17 +21,9 @@ config APPLE_PMP_REPORT select PM_GENERIC_DOMAINS config APPLE_PMP_V1_REPORT - bool "Apple PMPv1 report control" + bool depends on OF depends on PM select PM_GENERIC_DOMAINS - help - Enable support for the Apple PMPv1 report control driver. - - This provides power-domain support for PMPv1 report entries - described in the device tree on Apple SoCs. - - Say 'y' if you have an Apple machine with PMPv1. - endif diff --git a/drivers/pmdomain/apple/pmp_v1_report.rs b/drivers/pmdomain/apple/pmp_v1_report.rs index 8aa9fc5e2a3e50..a2aacfbea9221c 100644 --- a/drivers/pmdomain/apple/pmp_v1_report.rs +++ b/drivers/pmdomain/apple/pmp_v1_report.rs @@ -17,8 +17,8 @@ use kernel::{ pmdomain, pmp_v1_bridge }, - sync::Arc, - types::{ScopeGuard, ForeignOwnable, ARef}, + sync::{Arc, aref::ARef}, + types::{ScopeGuard, ForeignOwnable}, }; #[repr(C)] @@ -43,21 +43,17 @@ struct PmpReportData { #[pin] dev: ARef, #[pin] - node: of::Node, - #[pin] entry: Pin>, } impl PmpReportData { fn new(pdev: &platform::Device, - node: of::Node, entry: Pin>) -> Result> { Arc::pin_init( try_pin_init!( PmpReportData { dev: pdev.as_ref().into(), - node, entry } ), @@ -73,7 +69,8 @@ struct PmpV1ReportDriver(Arc); impl Drop for PmpV1ReportDriver { fn drop(&mut self) { - pmdomain::of_del_provider(&self.0.node); + let node = self.0.dev.of_node().unwrap(); + pmdomain::of_del_provider(&node); let genpd = self.0.entry.genpd_ptr(); let _ = pmdomain::genpd_remove(genpd); @@ -89,13 +86,13 @@ kernel::of_device_table!( unsafe extern "C" fn report_entry_set_state( genpd: *mut pmdomain::GenericPmDomain, - enable: bool) -> c_int -{ + enable: bool +) -> c_int { let ent = unsafe { ReportEntry::from_genpd(genpd) }; let parent = ent.dev.as_ref().parent().unwrap(); - dev_info!(ent.dev, "Setting state '{}' for device {}", enable, ent.id); + dev_dbg!(ent.dev, "Setting state '{}' for device {}", enable, ent.id); // SAFETY: our parent is PmpDriver, and its repr(transparent) for Arc let pdata_ptr = unsafe { @@ -103,9 +100,12 @@ unsafe extern "C" fn report_entry_set_state( }; let bridge = (&*pdata_ptr).clone(); - while !bridge.ready() { + if !bridge.ready() { + // TODO: put correct erro + return 1; } - dev_info!(ent.dev, "Bridge ready"); + + dev_dbg!(ent.dev, "Bridge ready"); // TODO: handle errors bridge.send_devpwr(ent.id as u64, enable).unwrap(); @@ -200,86 +200,7 @@ impl platform::Driver for PmpV1ReportDriver { } } - let data = PmpReportData::new(pdev, node, entry)?; - - remove_device.dismiss(); - - Ok(Self(data)) - } -} - -module_platform_driver! { - type: PmpV1ReportDriver, - name: "apple_pmp_v1_report", - license: "Dual MIT/GPL", -} - - let label_prop = node.get_property::>(c"label")?; - let label = CStr::from_bytes_with_nul(&label_prop).map_err(|_| EINVAL)?; - - let mut entry = KBox::into_pin(KBox::new( - ReportEntry { - dev, - // SAFETY: valid in C so also valid here - genpd: unsafe { core::mem::zeroed() }, - id, - }, - GFP_KERNEL, - )?); - - let entry_mut = unsafe { Pin::get_unchecked_mut(entry.as_mut()) }; - - match node.get_property::(c"apple,always-on") { - Ok(_) => {} - _ => { - entry_mut.genpd.flags |= pmdomain::GENPD_FLAG_ACTIVE_WAKEUP; - } - } - entry_mut.genpd.name = label.as_char_ptr(); - entry_mut.genpd.power_on = Some(report_entry_power_on); - entry_mut.genpd.power_off = Some(report_entry_power_off); - - let genpd = entry_mut.genpd_ptr(); - pmdomain::genpd_init(genpd, None, true)?; - pmdomain::of_add_provider_simple(&node, genpd)?; - - let remove_device = ScopeGuard::new(|| { - let _ = pmdomain::genpd_remove_device(pdev.as_ref()); - }); - - let raw_node = pmdomain::of_node_ptr(&node); - let mut it: pmdomain::OfPhandleIterator = pmdomain::of_phandle_iterator(); - - pmdomain::of_phandle_iterator_init( - &mut it, &node, c"power-domains", c"#power-domain-cells", -1)?; - - while pmdomain::of_phandle_iterator_next(&mut it)? { - let mut parent_spec = pmdomain::OfPhandleArgs { - np: it.node, - args_count: 0, - args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], - }; - - parent_spec.args_count = pmdomain::of_phandle_iterator_args( - &mut it, - parent_spec.args.as_mut_ptr(), - pmdomain::MAX_PHANDLE_ARGS.try_into().unwrap(), - ); - - let subdomain_spec = pmdomain::OfPhandleArgs { - np: raw_node, - args_count: 0, - args: [0; pmdomain::MAX_PHANDLE_ARGS as usize], - }; - - if let Err(e) = pmdomain::of_add_subdomain(&parent_spec, &subdomain_spec) { - dev_err!(entry.dev, "failed to add to parent domain"); - pmdomain::of_node_put(parent_spec.np); - return Err(e); - } - } - - let data = PmpReportData::new(pdev, node, entry)?; + let data = PmpReportData::new(pdev, entry)?; remove_device.dismiss(); diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index c27ca6bb13a876..b8f32f88efc183 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -128,13 +128,11 @@ config APPLE_PMP_V1 depends on RUST select APPLE_PMP_V1_REPORT select RUST_APPLE_RTKIT - default y if ARCH_APPLE help A co-processor present on Apple M1 SoC, controlling power states of fabric and other uncore components. Say 'y' here if you have an Apple M1 chip. - Say 'n' here if you don't have an Apple M1 chip. endmenu diff --git a/drivers/soc/apple/pmp_v1.rs b/drivers/soc/apple/pmp_v1.rs index 3926ed12d82494..aeeb6ee8731411 100644 --- a/drivers/soc/apple/pmp_v1.rs +++ b/drivers/soc/apple/pmp_v1.rs @@ -5,11 +5,6 @@ //! //! Copyright (C) The Asahi Linux Contributors -use core::sync::atomic::{ - AtomicBool, - Ordering -}; - use kernel::{ bindings, device::{ @@ -19,7 +14,10 @@ use kernel::{ platform, devres::Devres, dma, - io::mem::IoMem, + io::{ + mem::IoMem, + Io, + }, iosys_map::IoSysMapRef, module_platform_driver, new_mutex, @@ -31,12 +29,12 @@ use kernel::{ }, sync::{ Arc, + aref::ARef, Mutex, + Completion }, - types::{ - ARef, - ForeignOwnable, - }, + types::ForeignOwnable, + time::msecs_to_jiffies, }; const CPU_CONTROL: usize = 0x44; @@ -54,7 +52,7 @@ const OPC_INIT2_ACK: u64 = 0x203; const OPC_DEVPWR: u64 = 0x20e; const OPC_SHIFT: u32 = 44; -type ShMem = dma::CoherentAllocation; +type ShMem = dma::Coherent<[u8]>; #[pin_data] struct PmpData { @@ -64,21 +62,12 @@ struct PmpData { #[pin] rtkit: Mutex>>, shmem: ShMem, - ready: AtomicBool, + #[pin] + pub ready: Completion, } fn build_shmem(dev: &platform::Device) -> Result { - let mut shmem = - dma::CoherentAllocation::::alloc_coherent(dev.as_ref(), 0x10000, GFP_KERNEL)?; - - // SAFETY: - // Only this driver communicates with PMP. PMP waits for Configure message - // thus no r/w operations from the shared memory. - unsafe { - shmem.as_slice_mut(0, shmem.count())?.fill(0); - } - - Ok(shmem) + dma::Coherent::::zeroed_slice(dev.as_ref(), 0x10000, GFP_KERNEL) } fn send_dram_config(dev: &ARef, shmem: &mut ShMem) -> Result<()> { @@ -90,9 +79,7 @@ fn send_dram_config(dev: &ARef, shmem: &mut ShMem) -> Result<()> .property_read_array_vec::(c"apple,energy-model-dram-configs", n_entries)? .required_by(dev)?; - unsafe { - shmem.write(&dram_config, 0x2000)?; - } + unsafe { shmem.as_mut()[0x2000..][..dram_config.len()].copy_from_slice(&dram_config); } Ok(()) } @@ -100,25 +87,30 @@ fn send_dram_config(dev: &ARef, shmem: &mut ShMem) -> Result<()> fn send_init_config(dev: &ARef, shmem: &mut ShMem) -> Result { send_dram_config(dev, shmem)?; - let mut dva: usize = 0xc0000000; let mut maps: KVec = KVec::::new(); let node = dev.fwnode().ok_or(EIO)?; - let n_entries = node.property_count_elem::(c"apple,init-ranges")? / 2; + let n_entries = node.property_count_elem::(c"apple,init-ranges")?; let regions = node - .property_read_array_vec::(c"apple,init-ranges", n_entries * 2)? + .property_read_array_vec::(c"apple,init-ranges", n_entries)? .required_by(dev)?; let domain = unsafe { bindings::iommu_get_domain_for_dev(dev.as_raw()) }; - let mut err = 0; + let dva_entries = node.property_count_elem::(c"apple,init-dva")?; + let dvas = node + .property_read_array_vec::(c"apple,init-dva", dva_entries)? + .required_by(dev)?; + + let mut start = 0; + + for chunk in dvas.chunks_exact(2) { + let mut dva = chunk[0] as u64; + let count = chunk[1] as u64; - let mut map_addresses = - |reg_indx_start: usize, reg_indx_end: usize, mut dva: usize| -> Result<()> - { - for i in reg_indx_start..reg_indx_end { - let addr = (1u64 << 33) + regions[i * 2]; - let size: u64 = regions[i * 2 + 1]; + for i in start..start + count { + let addr = (1u64 << 33) + regions[2*i as usize] as u64; + let size = regions[1 + 2*i as usize] as u64; if size == 0 { maps.extend_from_slice(&[0u8; 16], GFP_KERNEL)?; continue; @@ -127,9 +119,9 @@ fn send_init_config(dev: &ARef, shmem: &mut ShMem) -> Result 0x{:x}", addr, dva); unsafe { - err = bindings::iommu_map( + let err = bindings::iommu_map( domain, - dva, + dva as usize, addr, size as usize, (bindings::IOMMU_READ | bindings::IOMMU_WRITE | bindings::IOMMU_MMIO) as i32, @@ -137,61 +129,20 @@ fn send_init_config(dev: &ARef, shmem: &mut ShMem) -> Result) -> Result<()> { let asc_mmio = self.asc_mmio.access(dev.as_ref())?; - let val = asc_mmio.read32_relaxed(CPU_CONTROL); - asc_mmio.write32_relaxed(val | CPU_RUN, CPU_CONTROL); + let asc_mmio = asc_mmio.relaxed(); + let val = asc_mmio.read32(CPU_CONTROL); + asc_mmio.write32(val | CPU_RUN, CPU_CONTROL); Ok(()) } @@ -251,10 +203,9 @@ impl PmpData { OPC_INIT1_ACK => (OPC_INIT2 << OPC_SHIFT) | (1 << 16), OPC_INIT2_ACK => { - self.ready.store(true, Ordering::Release); + self.ready.complete_all(); 0 }, - OPC_DEVPWR => msg, 0x110 => 0, _ => { dev_err!(self.dev, "Got unknown message 0x{:x}", msg); @@ -270,16 +221,25 @@ impl PmpData { Ok(()) } + + fn rtk_send_devpwr(&self, dev: u64, enable: bool) -> Result<()> { + let msg = (OPC_DEVPWR << OPC_SHIFT) + (dev << 16) + enable as u64; + + let mut rtk_guard = self.rtkit.lock(); + rtk_guard.as_mut().as_pin_mut().unwrap() + .send_message(PMP_ENDPOINT, msg)?; + + Ok(()) + } } impl pmp_v1_bridge::DevPwrBridge for PmpData { fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()> { - let msg = (OPC_DEVPWR << OPC_SHIFT) + (dev << 16) + enable as u64; - self.recv_message(msg) + self.rtk_send_devpwr(dev, enable) } fn ready(&self) -> bool { - self.ready.load(Ordering::Acquire) + self.ready.wait_for_completion_timeout(msecs_to_jiffies(50)) } } @@ -334,7 +294,9 @@ impl platform::Driver for PmpDriver { unsafe { let err = bindings::devm_of_platform_populate(dev.as_raw()); - // TODO handle errors + if err != 0 { + return Err(Error::from_errno(err)); + } } let data = PmpData::new(pdev)?; diff --git a/rust/kernel/soc/apple/mod.rs b/rust/kernel/soc/apple/mod.rs index 1c92cd00c67a65..e1b41504a9c077 100644 --- a/rust/kernel/soc/apple/mod.rs +++ b/rust/kernel/soc/apple/mod.rs @@ -13,4 +13,5 @@ pub mod mailbox; #[cfg(CONFIG_APPLE_PMP_V1_REPORT = "y")] pub mod pmdomain; +#[cfg(CONFIG_APPLE_PMP_V1_REPORT = "y")] pub mod pmp_v1_bridge; diff --git a/rust/kernel/soc/apple/pmp_v1_bridge.rs b/rust/kernel/soc/apple/pmp_v1_bridge.rs index 5f3e8cea56152c..b1d0ff5f2080c9 100644 --- a/rust/kernel/soc/apple/pmp_v1_bridge.rs +++ b/rust/kernel/soc/apple/pmp_v1_bridge.rs @@ -1,14 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only OR MIT -//! Common code for PMPv1 endpoint drivers +//! Bridge for PMPv1 drivers -use kernel::prelude::*; +use crate::{ + prelude::*, + sync::Completion +}; /// Allows report-entry drivers to send power on/off messages through RTKit. pub trait DevPwrBridge: Send + Sync { /// Sends a device power state request. fn send_devpwr(&self, dev: u64, enable: bool) -> Result<()>; - /// Returns whether the bridge is ready to accept requests. + /// Waits for the bridge to be ready to accept requests. fn ready(&self) -> bool; } diff --git a/rust/kernel/sync/completion.rs b/rust/kernel/sync/completion.rs index c50012a940a3c7..a2f46862365e04 100644 --- a/rust/kernel/sync/completion.rs +++ b/rust/kernel/sync/completion.rs @@ -6,7 +6,12 @@ //! //! C header: [`include/linux/completion.h`](srctree/include/linux/completion.h) -use crate::{bindings, prelude::*, types::Opaque}; +use crate::{ + bindings, + prelude::*, + time::Jiffies, + types::Opaque, // +}; /// Synchronization primitive to signal when a certain task has been completed. /// @@ -109,4 +114,15 @@ impl Completion { // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`. unsafe { bindings::wait_for_completion(self.as_raw()) }; } + + /// Wait for completion of a task with a timeout. + /// + /// This method waits for the completion of a task; it is not interruptible but has a timeout. + /// Returns `true` if the task completed before the timeout, `false` if the timeout elapsed. + /// + /// The timeout is specified in jiffies. See also [`Completion::complete_all`]. + pub fn wait_for_completion_timeout(&self, timeout: Jiffies) -> bool { + // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`. + unsafe { bindings::wait_for_completion_timeout(self.as_raw(), timeout) != 0 } + } } From 93c9296710b3f4b5fd311e968f442b1e6de40094 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Tue, 25 Aug 2026 23:26:55 +0300 Subject: [PATCH 5/7] update dt-bindings for pmp v1 Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- .../bindings/power/apple,pmp-v1.yaml | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml index 2a7ed011495add..8668e71d3b4b59 100644 --- a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml @@ -20,7 +20,101 @@ properties: - apple,t8103-pmp-v1 - apple,t8103-pmp-v1-report-entry + reg: + maxItems: 2 + + reg-names: + items: + - const: pmp + - const: asc + + mboxes: + maxItems: 1 + + mbox-names: + items: + - const: mbox + + iommus: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#power-domain-cells": + const: 0 + + power-domains: + maxItems: 1 + + label: + description: + Specifies the name of the SoC domain being controlled. This is used to + name the power domains. + + apple,always-on: + description: + Forces this power domain to always be powered up. + type: boolean + + apple,init-ranges: + description: + List of PMP memory regions, represented as address and size pairs for + initializing PMP. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + items: + minimum: 0 + + apple,init-dva: + description: + List of device virtual address with count pairs for initializing PMP. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + items: + minimum: 0 + required: - compatible -additionalProperties: true +allOf: + - if: + properties: + compatible: + const: apple,t8103-pmp-v1 + then: + required: + - reg + - reg-names + - mboxes + - mbox-names + - "#address-cells" + - "#size-cells" + - iommus + - apple,init-ranges + - apple,init-dva + + patternProperties: + "^report@[0-9a-f]+$": + $ref: "#" + + - if: + properties: + compatible: + const: apple,t8103-pmp-v1-report-entry + then: + $ref: power-domain.yaml# + + required: + - reg + - label + - power-domains + + properties: + reg: + maxItems: 1 + +additionalProperties: false From 4df058eb1e9749159be3bcc174296857ee68ac68 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Tue, 25 Aug 2026 23:40:25 +0300 Subject: [PATCH 6/7] split dt-binding for pmp-v1 Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- .../power/apple,pmp-v1-report-entry.yaml | 48 +++++++++++++ .../bindings/power/apple,pmp-v1.yaml | 69 ++++--------------- 2 files changed, 63 insertions(+), 54 deletions(-) create mode 100644 Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml new file mode 100644 index 00000000000000..ed82f52d51cb6b --- /dev/null +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/apple,pmp-v1-report-entry.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple PMPv1 Report Entry Power Domains + +maintainers: + - Didi Nuk + +description: + Apple PMPv1 report-entry nodes expose individual PMP-managed resources as + generic power domains. The PMP driver requires a report-entry node for each + SoC-specific PMP-managed resource. + +properties: + compatible: + enum: + - apple,t8103-pmp-v1-report-entry + + reg: + maxItems: 1 + + "#power-domain-cells": + const: 0 + + power-domains: + maxItems: 1 + + label: + description: + Specifies the name of the SoC report entry domain. This is used to + name the report entry domains. + + apple,always-on: + description: + Forces this power domain to always be powered up. + type: boolean + +required: + - compatible + - reg + - label + - "#power-domain-cells" + - power-domains + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml index 8668e71d3b4b59..38e208ca18d6c1 100644 --- a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml @@ -7,18 +7,16 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Apple PMPv1 Power Domains maintainers: - - dd-dreams + - Didi Nuk description: Apple PMPv1 power domains are controlled by the Apple Power Management - Processor (PMP). Report-entry nodes expose individual PMP-managed resources as - generic power domains. + Processor (PMP). properties: compatible: enum: - apple,t8103-pmp-v1 - - apple,t8103-pmp-v1-report-entry reg: maxItems: 2 @@ -44,22 +42,9 @@ properties: "#size-cells": const: 0 - "#power-domain-cells": - const: 0 - power-domains: maxItems: 1 - label: - description: - Specifies the name of the SoC domain being controlled. This is used to - name the power domains. - - apple,always-on: - description: - Forces this power domain to always be powered up. - type: boolean - apple,init-ranges: description: List of PMP memory regions, represented as address and size pairs for @@ -79,42 +64,18 @@ properties: required: - compatible - -allOf: - - if: - properties: - compatible: - const: apple,t8103-pmp-v1 - then: - required: - - reg - - reg-names - - mboxes - - mbox-names - - "#address-cells" - - "#size-cells" - - iommus - - apple,init-ranges - - apple,init-dva - - patternProperties: - "^report@[0-9a-f]+$": - $ref: "#" - - - if: - properties: - compatible: - const: apple,t8103-pmp-v1-report-entry - then: - $ref: power-domain.yaml# - - required: - - reg - - label - - power-domains - - properties: - reg: - maxItems: 1 + - reg + - reg-names + - mboxes + - mbox-names + - "#address-cells" + - "#size-cells" + - iommus + - apple,init-ranges + - apple,init-dva + +patternProperties: + "^report@[0-9a-f]+$": + $ref: apple,pmp-v1-report-entry.yaml# additionalProperties: false From 9b607338163b577a8e9d5f38423daa0846574e66 Mon Sep 17 00:00:00 2001 From: dd-dreams <80887265+dd-dreams@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:20:51 +0300 Subject: [PATCH 7/7] change to const and remove redundant lines Signed-off-by: dd-dreams <80887265+dd-dreams@users.noreply.github.com> --- .../bindings/power/apple,pmp-v1-report-entry.yaml | 3 +-- Documentation/devicetree/bindings/power/apple,pmp-v1.yaml | 7 +------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml index ed82f52d51cb6b..d78236e8e5edd9 100644 --- a/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1-report-entry.yaml @@ -16,8 +16,7 @@ description: properties: compatible: - enum: - - apple,t8103-pmp-v1-report-entry + const: apple,t8103-pmp-v1-report-entry reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml index 38e208ca18d6c1..9ff8da301938fc 100644 --- a/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmp-v1.yaml @@ -15,8 +15,7 @@ description: properties: compatible: - enum: - - apple,t8103-pmp-v1 + const: apple,t8103-pmp-v1 reg: maxItems: 2 @@ -51,16 +50,12 @@ properties: initializing PMP. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 2 - items: - minimum: 0 apple,init-dva: description: List of device virtual address with count pairs for initializing PMP. $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 2 - items: - minimum: 0 required: - compatible