From 362844f9b19894dfdf57c4bdec749d0ec621bd5d Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 17:52:13 +0100 Subject: [PATCH 1/4] rust: bindings: WIP(?): Export various bits for PMP driver Signed-off-by: Sasha Finkelstein --- rust/bindings/bindings_helper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index a5407b5746fc4f..025dae9fc05534 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include From 9cd555775395f5a3290f63a4e8dd3850a9beb7f8 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 17:53:50 +0100 Subject: [PATCH 2/4] soc: apple: Add support for the PMP co-processor This is the core part of a power management co-processor present on certain Apple SoCs. This driver starts the firmware, and uploads the configuration and calibration data by pretending to be IOKit. Signed-off-by: Sasha Finkelstein --- drivers/soc/apple/Kconfig | 12 + drivers/soc/apple/Makefile | 2 + drivers/soc/apple/pmp.rs | 436 +++++++++++++++++++++++++++++++++++++ 3 files changed, 450 insertions(+) create mode 100644 drivers/soc/apple/pmp.rs diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index c926f7705be671..2882d913ce46bf 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -109,6 +109,18 @@ config APPLE_SEP Say 'y' here if you have an Apple SoC. +config APPLE_PMP + tristate "Apple Power Management Processor" + depends on ARCH_APPLE || COMPILE_TEST + depends on RUST + select RUST_APPLE_RTKIT + default y if ARCH_APPLE + help + A co-processor present on Apple SoCs, controlling power states of + fabric and other uncore compoents. + + Say 'y' here if you have an Apple SoC. + endmenu endif diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 47f66719ee8a90..f9ab2a1ff53f42 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -23,3 +23,5 @@ apple-sart-y = sart.o obj-$(CONFIG_APPLE_AOP) += aop.o obj-$(CONFIG_APPLE_SEP) += sep.o + +obj-$(CONFIG_APPLE_PMP) += pmp.o diff --git a/drivers/soc/apple/pmp.rs b/drivers/soc/apple/pmp.rs new file mode 100644 index 00000000000000..1742d8207b9461 --- /dev/null +++ b/drivers/soc/apple/pmp.rs @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +#![recursion_limit = "2048"] + +//! Apple PMP driver +//! +//! Copyright (C) The Asahi Linux Contributors + +use core::{ + mem, + slice, // +}; + +use kernel::{ + bindings, + device::{ + self, + Core, // + }, + devres::Devres, + dma::CoherentAllocation, + io::mem::IoMem, + iosys_map::IoSysMapRef, + module_platform_driver, + new_mutex, + of, + platform, + prelude::*, + soc::apple::rtkit, + sync::{ + Arc, + Mutex, // + }, + types::{ + ARef, + ForeignOwnable, // + }, // +}; + +const PMP_MMIO_SIZE: usize = 0x100000; +const ASC_MMIO_SIZE: usize = 0x4000; +const BOOTARGS_OFFSET: usize = 0x22c; +const BOOTARGS_SIZE: usize = 0x230; +const CPU_CONTROL: usize = 0x44; +const CPU_RUN: u32 = 0x1 << 4; +const PMP_ENDPOINT: u8 = 0x20; +const OPC_GET_IOVA_TABLE: u64 = 0x10; +const OPC_MALLOC: u64 = 0x12; +const OPC_FREE: u64 = 0x14; +const OPC_SET_BUF: u64 = 0x30; +const OPC_REGISTER_IOREG: u64 = 0x32; +const OPC_SET_IOREG: u64 = 0x34; +const OPC_ACK_MASK: u64 = 0x1; +const OPC_SHIFT: u32 = 48; +const MALLOC_SIZE_MASK: u64 = 0xFFFFFF; +const MSG_IOVA_MASK: u64 = 0xFFFFFFFFFFFF; +const SET_IOREG_INDEX_MASK: u64 = 0xFFFF; +const PIO_VM_BASE: u64 = 0xc0000000; +const PIO_GRANULARITY: u64 = 0x1000000; + +const fn from_fourcc(b: &[u8; 4]) -> u32 { + b[3] as u32 | (b[2] as u32) << 8 | (b[1] as u32) << 16 | (b[0] as u32) << 24 +} + +struct PmpAllocation { + addr: u64, + alloc: CoherentAllocation, +} + +struct PmpState { + iova_table: Option>, + allocs: KVec, + value_buf: Option, + ioreg_entries: KVec, +} + +impl PmpState { + fn new() -> Result { + Ok(PmpState { + iova_table: None, + allocs: KVec::with_capacity(10, GFP_KERNEL)?, + value_buf: None, + ioreg_entries: KVec::with_capacity(340, GFP_KERNEL)?, + }) + } + fn find_alloc(&self, addr: u64) -> Option { + // Due to how pmp manages memory, iterating in reverse will + // usually result in us getting the right one on the first try + for (i, e) in self.allocs.iter().enumerate().rev() { + if e.addr == addr { + return Some(i); + } + } + None + } + fn get_buf(&mut self, addr: u64) -> Option<&mut CoherentAllocation> { + let idx = self.find_alloc(addr)?; + Some(&mut self.allocs[idx].alloc) + } +} + +#[pin_data] +struct PmpData { + dev: ARef, + pmp_mmio: Pin>>>, + asc_mmio: Pin>>>, + #[pin] + rtkit: Mutex>>, + #[pin] + state: Mutex, +} + +impl PmpData { + fn new(dev: &platform::Device) -> Result> { + let pmp_req = dev.io_request_by_name(c"pmp").ok_or(EINVAL)?; + let pmp_mmio = KBox::pin_init(pmp_req.iomap_sized::(), GFP_KERNEL)?; + let asc_req = dev.io_request_by_name(c"asc").ok_or(EINVAL)?; + let asc_mmio = KBox::pin_init(asc_req.iomap_sized::(), GFP_KERNEL)?; + Arc::pin_init( + try_pin_init!( + PmpData { + dev: dev.as_ref().into(), + pmp_mmio, + asc_mmio, + rtkit <- new_mutex!(None), + state <- new_mutex!(PmpState::new()?) + } + ), + GFP_KERNEL, + ) + } + fn start_cpu(&self) -> Result<()> { + let asc_mmio = self.asc_mmio.try_access().ok_or(ENXIO)?; + 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 pmp_read32(&self, off: usize) -> u32 { + if let Some(pmp_mmio) = self.pmp_mmio.try_access() { + pmp_mmio.read32_relaxed(off) + } else { + 0 + } + } + fn patch_bootargs(&self, patches: &[(u32, u32)]) -> Result<()> { + let offset = self.pmp_read32(BOOTARGS_OFFSET) as usize; + let size = self.pmp_read32(BOOTARGS_SIZE) as usize; + let mut arg_bytes = KVec::with_capacity(size, GFP_KERNEL)?; + for _ in 0..size { + arg_bytes.push(0, GFP_KERNEL).unwrap(); + } + { + let pmp_mmio = self.pmp_mmio.try_access().ok_or(ENXIO)?; + pmp_mmio.try_memcpy_fromio(&mut arg_bytes, offset)?; + } + let mut idx = 0; + while idx < size { + let key = u32::from_le_bytes(arg_bytes[idx..idx + 4].try_into().unwrap()); + let size = u32::from_le_bytes(arg_bytes[idx + 4..idx + 8].try_into().unwrap()) as usize; + idx += 8; + for (k, v) in patches.iter() { + if *k != key { + continue; + } + arg_bytes[idx..idx + size].copy_from_slice(&(*v as u64).to_le_bytes()[..size]); + break; + } + idx += size; + } + { + let pmp_mmio = self.pmp_mmio.try_access().ok_or(ENXIO)?; + pmp_mmio.try_memcpy_toio(offset, &arg_bytes) + } + } + fn get_iova_table(&self) -> Result { + let mut state = self.state.lock(); + if state.iova_table.is_some() { + dev_err!(self.dev, "Asked for iova table with existing buffer"); + return Err(EIO); + } + let node = self.dev.fwnode().ok_or(EIO)?; + let mut pio_base = PIO_VM_BASE; + let prop_name = c"apple,pio-ranges"; + let n_entries = node.property_count_elem::(prop_name)? / 2; + let ranges = node + .property_read_array_vec::(prop_name, n_entries * 2)? + .required_by(&self.dev)?; + let mut table = self.dev.while_bound_with(|bound_dev| { + CoherentAllocation::alloc_coherent(bound_dev, 512, GFP_KERNEL) + })?; + for i in 0..table.count() { + unsafe { table.write(&[0], i)? }; + } + + let domain = unsafe { bindings::iommu_get_domain_for_dev(self.dev.as_raw()) }; + for i in 0..n_entries { + let host_addr = ranges[i * 2]; + let size = ranges[i * 2 + 1]; + unsafe { + let err = bindings::iommu_map( + domain, + pio_base as usize, + host_addr, + size as usize, + (bindings::IOMMU_READ | bindings::IOMMU_WRITE | bindings::IOMMU_MMIO) as i32, + bindings::GFP_KERNEL, + ); + if err != 0 { + return Err(Error::from_errno(err)); + } + } + unsafe { table.write(&[host_addr, pio_base, size], i * 3)? }; + pio_base += PIO_GRANULARITY; + } + let msg = (OPC_GET_IOVA_TABLE | OPC_ACK_MASK) << OPC_SHIFT | table.dma_handle(); + state.iova_table = Some(table); + Ok(msg) + } + fn malloc(&self, size: u64) -> Result { + let iomem = self.dev.while_bound_with(|bound_dev| { + CoherentAllocation::alloc_coherent(bound_dev, size as usize, GFP_KERNEL) + })?; + let mut state = self.state.lock(); + let addr = iomem.dma_handle(); + let msg = (OPC_MALLOC | OPC_ACK_MASK) << OPC_SHIFT | addr; + state.allocs.push( + PmpAllocation { + addr: addr, + alloc: iomem, + }, + GFP_KERNEL, + )?; + Ok(msg) + } + fn free(&self, addr: u64) -> Result { + let mut state = self.state.lock(); + if let Some(idx) = state.find_alloc(addr) { + state.allocs.swap_remove(idx); + } else { + dev_err!( + self.dev, + "Attempted to free memory that was not allocated {}", + addr + ); + return Err(EIO); + } + let msg = (OPC_FREE | OPC_ACK_MASK) << OPC_SHIFT; + Ok(msg) + } + fn set_buf(&self, addr: u64) -> Result { + let mut state = self.state.lock(); + if state.value_buf.is_some() { + dev_err!(self.dev, "Setting a buffer when one exists"); + return Err(EIO); + } + let ptr_buf = if let Some(s) = state.get_buf(addr) { + s + } else { + dev_err!(self.dev, "Unable to find buffer"); + return Err(EIO); + }; + if ptr_buf.count() < mem::size_of::() { + dev_err!(self.dev, "Buffer too small"); + return Err(EIO); + } + let ptr = unsafe { *(ptr_buf.start_ptr() as *const u64) }; + state.value_buf = Some(ptr); + let msg = (OPC_SET_BUF | OPC_ACK_MASK) << OPC_SHIFT; + Ok(msg) + } + fn register_ioreg(&self, addr: u64) -> Result { + let mut state = self.state.lock(); + let msg_buf = if let Some(s) = state.get_buf(addr) { + s + } else { + dev_err!(self.dev, "Unable to find buffer"); + return Err(EIO); + }; + if msg_buf.count() < 0x44 { + dev_err!(self.dev, "Buffer too small"); + return Err(EIO); + } + let mut size = unsafe { *(msg_buf.start_ptr().offset(0x40) as *const u32) }; + if size == 0 { + let mut name_vec = KVec::with_capacity(0x31, GFP_KERNEL)?; + name_vec + .extend_from_slice( + unsafe { slice::from_raw_parts(msg_buf.start_ptr(), 0x30) }, + GFP_KERNEL, + ) + .unwrap(); + name_vec.push(0, GFP_KERNEL).unwrap(); + let name_str = CStr::from_bytes_until_nul(&name_vec).unwrap(); + let node = self.dev.fwnode().ok_or(EIO)?; + let tunables = node.get_child_by_name(c"tunables").ok_or(EIO)?; + if state.value_buf.is_none() { + dev_err!(self.dev, "Value buf not set"); + return Err(EIO); + } + let val_buf_addr = state.value_buf.unwrap(); + let val_buf = if let Some(s) = state.get_buf(val_buf_addr) { + s + } else { + dev_err!(self.dev, "Unable to find value buffer"); + return Err(EIO); + }; + if tunables.property_present(name_str) { + let len = tunables.property_count_elem::(name_str)?; + let data = tunables + .property_read_array_vec::(name_str, len)? + .required_by(&self.dev)?; + unsafe { + slice::from_raw_parts_mut(val_buf.start_ptr_mut(), len).copy_from_slice(&data); + } + size = len as u32; + } else { + dev_info!(self.dev, "unknown property {:?}", name_str); + } + } + state.ioreg_entries.push(size, GFP_KERNEL)?; + let index = state.ioreg_entries.len() as u64; + let msg = (OPC_REGISTER_IOREG | OPC_ACK_MASK) << OPC_SHIFT | (index << 32) | size as u64; + Ok(msg) + } + fn set_ioreg(&self, index: u64) -> Result { + let len = *self + .state + .lock() + .ioreg_entries + .get(index as usize) + .ok_or(EIO)? as u64; + let msg = (OPC_SET_IOREG | OPC_ACK_MASK) << OPC_SHIFT | len; + Ok(msg) + } + fn recv_message(&self, msg: u64) -> Result<()> { + let opc = (msg >> OPC_SHIFT) & 0xFF; + let reply = match opc { + OPC_GET_IOVA_TABLE => self.get_iova_table()?, + OPC_MALLOC => self.malloc(msg & MALLOC_SIZE_MASK)?, + OPC_FREE => self.free(msg & MSG_IOVA_MASK)?, + OPC_SET_BUF => self.set_buf(msg & MSG_IOVA_MASK)?, + OPC_REGISTER_IOREG => self.register_ioreg(msg & MSG_IOVA_MASK)?, + OPC_SET_IOREG => self.set_ioreg(msg & SET_IOREG_INDEX_MASK)?, + _ => { + dev_err!(self.dev, "Got unknown message {}", msg); + return Err(EIO); + } + }; + let mut rtk_guard = self.rtkit.lock(); + let rtk = rtk_guard.as_mut().as_pin_mut().unwrap(); + rtk.send_message(PMP_ENDPOINT, reply)?; + Ok(()) + } +} + +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"); + } +} + +#[allow(dead_code)] +struct PmpDriver(Arc); + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + (), + [(of::DeviceId::new(c"apple,t6000-pmp-v2"), ())] +); + +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(); + let data = PmpData::new(pdev)?; + let node = dev.fwnode().ok_or(EIO)?; + let dvid = node + .property_read(c"apple,dram-vendor-id") + .required_by(&dev)?; + let dcap = node + .property_read(c"apple,dram-capacity") + .required_by(&dev)?; + let bdid = node + .property_read(c"apple,board-id") + .required_by(&dev)?; + data.patch_bootargs(&[ + (from_fourcc(b"BDID"), bdid), + (from_fourcc(b"DCAP"), dcap), + (from_fourcc(b"DVID"), dvid), + ])?; + let rtkit = rtkit::RtKit::::new(&dev, None, 0, data.clone())?; + *data.rtkit.lock() = Some(rtkit); + data.start_cpu()?; + data.start()?; + Ok(PmpDriver(data)) + } +} + +module_platform_driver! { + type: PmpDriver, + name: "apple_pmp", + license: "Dual MIT/GPL", +} From 3bda44d084e4288221b52fbfcf08f9d349a57f15 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 17:59:08 +0100 Subject: [PATCH 3/4] pmdomain: apple: Add PMP reporting interface This driver manages a shared SRAM area that is used to communicate desired power states of devices that PMP manages. Signed-off-by: Sasha Finkelstein --- drivers/pmdomain/apple/Makefile | 1 + drivers/pmdomain/apple/pmp-report.c | 235 ++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 drivers/pmdomain/apple/pmp-report.c diff --git a/drivers/pmdomain/apple/Makefile b/drivers/pmdomain/apple/Makefile index 53665af630be22..006d4c0071ab89 100644 --- a/drivers/pmdomain/apple/Makefile +++ b/drivers/pmdomain/apple/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += pmgr-pwrstate.o +obj-$(CONFIG_APPLE_PMP) += pmp-report.o diff --git a/drivers/pmdomain/apple/pmp-report.c b/drivers/pmdomain/apple/pmp-report.c new file mode 100644 index 00000000000000..af894adb7829f4 --- /dev/null +++ b/drivers/pmdomain/apple/pmp-report.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC PMP power state reporting driver + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PMP_REPORT_READY 0x1 + +struct apple_pmp_report_offsets { + u32 tgt_read; + u32 tgt_write; + u32 actual; + u32 status; +}; + +struct apple_pmp_report { + struct device *dev; + const struct apple_pmp_report_offsets *offsets; + void __iomem *base; + spinlock_t lock; +}; + +static int apple_pmp_report_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct apple_pmp_report *rep; + int ret; + + rep = devm_kzalloc(dev, sizeof(*rep), GFP_KERNEL); + if (!rep) + return -ENOMEM; + + rep->dev = dev; + rep->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rep->base)) + return PTR_ERR(rep->base); + rep->offsets = of_device_get_match_data(dev); + dev_set_drvdata(dev, rep); + ret = of_platform_populate(np, NULL, NULL, dev); + if (ret) + return dev_err_probe(dev, ret, "failed to create child devices\n"); + + return 0; +} + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t600x = { + .tgt_read = 0xf80, + .tgt_write = 0x107c0, + .actual = 0x1000, + .status = 0x10, +}; + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t602x = { + .tgt_read = 0x2000, + .tgt_write = 0x11000, + .actual = 0x2080, + .status = 0x10, +}; + +static const struct apple_pmp_report_offsets apple_pmp_offsets_t8112 = { + .tgt_read = 0xa00, + .tgt_write = 0x10500, + .actual = 0xa40, + .status = 0x10, +}; + +static const struct of_device_id apple_pmp_report_of_match[] = { + { .compatible = "apple,t6000-pmp-v2-report", .data = &apple_pmp_offsets_t600x }, + { .compatible = "apple,t6020-pmp-v2-report", .data = &apple_pmp_offsets_t602x }, + { .compatible = "apple,t8112-pmp-v2-report", .data = &apple_pmp_offsets_t8112 }, + {} +}; + +static struct platform_driver apple_pmp_report_driver = { + .probe = apple_pmp_report_probe, + .driver = { + .name = "apple-pmp-report", + .of_match_table = apple_pmp_report_of_match, + }, +}; + +struct apple_pmp_report_entry { + struct device *dev; + struct generic_pm_domain genpd; + u32 id; +}; + +#define genpd_to_apple_pmp_report_entry(_genpd) \ + container_of(_genpd, struct apple_pmp_report_entry, genpd) + +static int apple_pmp_report_set_state(struct generic_pm_domain *genpd, bool enable) +{ + struct apple_pmp_report_entry *ent = genpd_to_apple_pmp_report_entry(genpd); + struct apple_pmp_report *rep = dev_get_drvdata(ent->dev->parent); + u64 bit_val = 1 << ent->id; + u64 val; + unsigned long flags; + + spin_lock_irqsave(&rep->lock, flags); + val = readq(rep->base + rep->offsets->tgt_read); + val &= ~bit_val; + if (enable) + val |= bit_val; + writeq(val, rep->base + rep->offsets->tgt_write); + spin_unlock_irqrestore(&rep->lock, flags); + val = readq(rep->base + rep->offsets->status); + if ((val & PMP_REPORT_READY) == 0) + return 0; + return readq_poll_timeout_atomic( + rep->base + rep->offsets->actual, + val, + !!(val & bit_val) == !!enable, + 100, + 50000); +} + +static int apple_pmp_report_entry_power_on(struct generic_pm_domain *genpd) +{ + return apple_pmp_report_set_state(genpd, true); +} + +static int apple_pmp_report_entry_power_off(struct generic_pm_domain *genpd) +{ + return apple_pmp_report_set_state(genpd, false); +} + +static int apple_pmp_report_entry_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct apple_pmp_report_entry *ent; + int ret; + const char *name; + struct of_phandle_iterator it; + + ent = devm_kzalloc(dev, sizeof(*ent), GFP_KERNEL); + if (!ent) + return -ENOMEM; + + ent->dev = dev; + + ret = of_property_read_u32(node, "reg", &ent->id); + if (ret) + return dev_err_probe(dev, ret, "missing reg property\n"); + + ret = of_property_read_string(node, "label", &name); + if (ret < 0) + return dev_err_probe(dev, ret, "missing label property\n"); + + if (of_property_read_bool(node, "apple,always-on")) + ent->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; + ent->genpd.name = name; + ent->genpd.power_on = apple_pmp_report_entry_power_on; + ent->genpd.power_off = apple_pmp_report_entry_power_off; + + ret = pm_genpd_init(&ent->genpd, NULL, true); + if (ret) + return dev_err_probe(dev, ret, "pm_genpd_init failed\n"); + + ret = of_genpd_add_provider_simple(node, &ent->genpd); + if (ret) + return dev_err_probe(dev, ret, "of_genpd_add_provider_simple failed\n"); + + of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) { + struct of_phandle_args parent, child; + + parent.np = it.node; + parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS); + child.np = node; + child.args_count = 0; + ret = of_genpd_add_subdomain(&parent, &child); + + if (ret == -EPROBE_DEFER) { + of_node_put(parent.np); + goto err_remove; + } else if (ret < 0) { + dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n", + ret, it.node->name, node->name); + of_node_put(parent.np); + goto err_remove; + } + } + + pm_genpd_remove_device(dev); + + return 0; +err_remove: + of_genpd_del_provider(node); + pm_genpd_remove(&ent->genpd); + return ret; +} + +static const struct of_device_id apple_pmp_report_entry_of_match[] = { + { .compatible = "apple,t6000-pmp-v2-report-entry" }, + {} +}; + +static struct platform_driver apple_pmp_report_entry_driver = { + .probe = apple_pmp_report_entry_probe, + .driver = { + .name = "apple-pmp-report-entry", + .of_match_table = apple_pmp_report_entry_of_match, + }, +}; + +MODULE_DEVICE_TABLE(of, apple_pmp_report_of_match); +MODULE_DEVICE_TABLE(of, apple_pmp_report_entry_of_match); + +static int __init apple_pmp_report_init(void) +{ + platform_driver_register(&apple_pmp_report_entry_driver); + platform_driver_register(&apple_pmp_report_driver); + return 0; +} + +static void __exit apple_pmp_report_exit(void) +{ + platform_driver_unregister(&apple_pmp_report_entry_driver); + platform_driver_unregister(&apple_pmp_report_driver); +} + +module_init(apple_pmp_report_init); +module_exit(apple_pmp_report_exit); + +MODULE_DESCRIPTION("PMP power state reporting driver for Apple SoCs"); From 7c135f2823bc8059a81006229821e520e7f01ee3 Mon Sep 17 00:00:00 2001 From: Sasha Finkelstein Date: Thu, 26 Feb 2026 18:15:38 +0100 Subject: [PATCH 4/4] arm64: dts: apple: Add PMP nodes and hook up power reporting Add the PMP device and set it as the power-domain for devices that need to report their power states to it. Signed-off-by: Sasha Finkelstein --- arch/arm64/boot/dts/apple/t6000.dtsi | 15 ++ arch/arm64/boot/dts/apple/t6001.dtsi | 12 + arch/arm64/boot/dts/apple/t6002.dtsi | 57 +++++ arch/arm64/boot/dts/apple/t600x-common.dtsi | 1 + arch/arm64/boot/dts/apple/t600x-die0.dtsi | 190 +++++++++++++++- arch/arm64/boot/dts/apple/t600x-dieX.dtsi | 4 +- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 2 +- arch/arm64/boot/dts/apple/t6020.dtsi | 16 ++ arch/arm64/boot/dts/apple/t6021.dtsi | 13 ++ arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi | 1 + arch/arm64/boot/dts/apple/t6022.dtsi | 43 ++++ arch/arm64/boot/dts/apple/t602x-common.dtsi | 1 + arch/arm64/boot/dts/apple/t602x-die0.dtsi | 206 +++++++++++++++++- arch/arm64/boot/dts/apple/t602x-dieX.dtsi | 4 +- arch/arm64/boot/dts/apple/t8112.dtsi | 160 +++++++++++++- 15 files changed, 710 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/apple/t6000.dtsi b/arch/arm64/boot/dts/apple/t6000.dtsi index c9e4e52d9aac92..9b97b2325ec503 100644 --- a/arch/arm64/boot/dts/apple/t6000.dtsi +++ b/arch/arm64/boot/dts/apple/t6000.dtsi @@ -18,6 +18,21 @@ }; /delete-node/ &pmgr_south; +/delete-node/ &pmp_report_dispext2; +/delete-node/ &pmp_report_dispext3; +/delete-node/ &pmp_report_venc1; +/delete-node/ &pmp_report_msr1; +/delete-node/ &pmp_report_prores; + +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>; +}; &gpu { compatible = "apple,agx-t6000", "apple,agx-g13x"; diff --git a/arch/arm64/boot/dts/apple/t6001.dtsi b/arch/arm64/boot/dts/apple/t6001.dtsi index 3ac838c9b803b6..73053599d71d81 100644 --- a/arch/arm64/boot/dts/apple/t6001.dtsi +++ b/arch/arm64/boot/dts/apple/t6001.dtsi @@ -70,6 +70,18 @@ }; }; +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x82000000 0x0 0x1000000>, + <0x5 0x2000000 0x0 0x1000000>; +}; + &gpu { compatible = "apple,agx-t6001", "apple,agx-g13c", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t6002.dtsi b/arch/arm64/boot/dts/apple/t6002.dtsi index 9bf333e0cf2d66..b5f175d71ee69a 100644 --- a/arch/arm64/boot/dts/apple/t6002.dtsi +++ b/arch/arm64/boot/dts/apple/t6002.dtsi @@ -320,6 +320,63 @@ power-domains = <&ps_afr>, <&ps_afr_die1>; }; +&pmp { + apple,pio-ranges = <0x2 0x82000000 0x0 0x1000000>, + <0x3 0x4000000 0x0 0x1000000>, + <0x3 0x83000000 0x0 0x1000000>, + <0x4 0x2000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x82000000 0x0 0x1000000>, + <0x5 0x2000000 0x0 0x1000000>, + <0x22 0x82000000 0x0 0x1000000>, + <0x23 0x4000000 0x0 0x1000000>, + <0x23 0x83000000 0x0 0x1000000>, + <0x24 0x2000000 0x0 0x1000000>, + <0x24 0x82000000 0x0 0x1000000>, + <0x25 0x2000000 0x0 0x1000000>, + <0x22 0x10e70000 0x0 0x90000>, + <0x22 0x11e70000 0x0 0x90000>, + <0x22 0x12e70000 0x0 0x90000>; +}; + +&pmp_report { + pmp_report_dispext0_die1: report@33 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x33>; + label = "pmp-dispext0_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0_die1>; + }; + + pmp_report_dispext1_die1: report@34 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x34>; + label = "pmp-dispext1_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + }; + + pmp_report_dispext2_die1: report@35 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x35>; + label = "pmp-dispext2_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + status = "disabled"; + }; + + pmp_report_dispext3_die1: report@36 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x36>; + label = "pmp-dispext3_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + status = "disabled"; + }; +}; + &gpu { compatible = "apple,agx-t6002", "apple,agx-g13d", "apple,agx-g13s"; }; diff --git a/arch/arm64/boot/dts/apple/t600x-common.dtsi b/arch/arm64/boot/dts/apple/t600x-common.dtsi index f37feaea4c2191..318914dffef856 100644 --- a/arch/arm64/boot/dts/apple/t600x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-common.dtsi @@ -13,6 +13,7 @@ aliases { gpu = &gpu; + pmp = &pmp; }; cpus { diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi index f00550a680e131..fad3b908ed8d00 100644 --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi @@ -40,6 +40,190 @@ #apple,bw-scratch-cells = <3>; }; + pmp_dart: iommu@28e300000 { + compatible = "apple,t6000-dart"; + reg = <0x2 0x8e300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@28e3c0000 { + compatible = "apple,t6000-pmp-v2-report"; + reg = <0x2 0x8e3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_gfx: report@9 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x9>; + label = "pmp-gfx"; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@a { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@b { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + }; + + pmp_report_disp0: report@c { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext0: report@d { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-dispext0"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0>; + }; + + pmp_report_dispext1: report@e { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0>; + }; + + pmp_report_venc_sys: report@10 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x10>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@11 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr0: report@12 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x12>; + label = "pmp-msr0"; + #power-domain-cells = <0>; + power-domains = <&ps_msr0>; + status = "disabled"; + }; + + pmp_report_jpg: report@13 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x13>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@14 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x14>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_dispext2: report@20 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext2"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext2_cpu0>; + status = "disabled"; + }; + + pmp_report_dispext3: report@21 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x21>; + label = "pmp-dispext3"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext3_cpu0>; + status = "disabled"; + }; + + pmp_report_venc1: report@22 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x22>; + label = "pmp-venc1"; + #power-domain-cells = <0>; + power-domains = <&ps_venc1_sys>; + status = "disabled"; + }; + + pmp_report_msr1: report@23 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x23>; + label = "pmp-msr1"; + #power-domain-cells = <0>; + power-domains = <&ps_msr1>; + status = "disabled"; + }; + + pmp_report_prores: report@24 { + compatible = "apple,t6000-pmp-v2-report-entry"; + reg = <0x24>; + label = "pmp-prores"; + #power-domain-cells = <0>; + power-domains = <&ps_prores>; + status = "disabled"; + }; + }; + + pmp: pmp@28e700000 { + compatible = "apple,t6000-pmp-v2"; + reg = <0x2 0x8e700000 0x0 0x100000>, + <0x2 0x8ec00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + tunables { + }; + }; + + pmp_mbox: mbox@28ec08000 { + compatible = "apple,t6000-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x8ec08000 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>; + }; + smc: smc@290400000 { compatible = "apple,t6000-smc", "apple,smc"; reg = <0x2 0x90400000 0x0 0x4000>, @@ -333,7 +517,7 @@ <0x3 0x8b344000 0x0 0x4000>, <0x3 0x8b800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x988>; - power-domains = <&ps_disp0_cpu0>; + power-domains = <&pmp_report_disp0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -545,7 +729,7 @@ <0x4 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", @@ -644,7 +828,7 @@ <0x3 0x861043f0 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_fe>, <&ps_isp_set3>, <&ps_isp_set4>, <&ps_isp_set5>, <&ps_isp_set6>, <&ps_isp_set7>, <&ps_isp_set8>; diff --git a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi index 1671299411e0e6..bde7c93c3b4814 100644 --- a/arch/arm64/boot/dts/apple/t600x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-dieX.dtsi @@ -75,7 +75,7 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x990>; - power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + power-domains = <&DIE_NODE(pmp_report_dispext0)>; resets = <&DIE_NODE(ps_dispext0_cpu0)>; clocks = <&DIE_NODE(clk_dispext0)>; phandle = <&DIE_NODE(dcpext0)>; @@ -152,7 +152,7 @@ <0x2 0x8c344000 0x0 0x4000>, <0x2 0x8c800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x998>; - power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + power-domains = <&DIE_NODE(pmp_report_dispext1)>; resets = <&DIE_NODE(ps_dispext1_cpu0)>; clocks = <&DIE_NODE(clk_dispext1)>; phandle = <&DIE_NODE(dcpext1)>; diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi index 8d030df13bf5f8..c6e33954c03067 100644 --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi @@ -124,7 +124,7 @@ /* remove once m1n1 enables sio nodes after setup */ &sio { - status = "okay"; + status = "okay"; }; &dpaudio1 { diff --git a/arch/arm64/boot/dts/apple/t6020.dtsi b/arch/arm64/boot/dts/apple/t6020.dtsi index 482a1e5f53d0a6..82c38593873386 100644 --- a/arch/arm64/boot/dts/apple/t6020.dtsi +++ b/arch/arm64/boot/dts/apple/t6020.dtsi @@ -18,6 +18,22 @@ }; /delete-node/ &pmgr_south; +/delete-node/ &pmp_report_dispext2; +/delete-node/ &pmp_report_dispext3; +/delete-node/ &pmp_report_venc1; +/delete-node/ &pmp_report_msr1; +/delete-node/ &pmp_report_prores; + +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>; +}; &gpu { compatible = "apple,agx-t6020", "apple,agx-g14x", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6021.dtsi b/arch/arm64/boot/dts/apple/t6021.dtsi index bb0e66851f1b59..44c3b09ad46c51 100644 --- a/arch/arm64/boot/dts/apple/t6021.dtsi +++ b/arch/arm64/boot/dts/apple/t6021.dtsi @@ -73,6 +73,19 @@ }; }; +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x80000000 0x0 0x1000000>, + <0x5 0x0 0x0 0x1000000>; +}; + &gpu { compatible = "apple,agx-t6021", "apple,agx-g14x", "apple,agx-g14c", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi index f11b017dc0496f..fa0183441d791b 100644 --- a/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi +++ b/arch/arm64/boot/dts/apple/t6022-jxxxd.dtsi @@ -68,6 +68,7 @@ /* delete power-domains for missing disp0 / disp0_die1 */ /delete-node/ &ps_disp0_cpu0; /delete-node/ &ps_disp0_fe; +/delete-node/ &pmp_report_disp0; /delete-node/ &ps_disp0_cpu0_die1; /delete-node/ &ps_disp0_fe_die1; diff --git a/arch/arm64/boot/dts/apple/t6022.dtsi b/arch/arm64/boot/dts/apple/t6022.dtsi index f17c9a4f59e482..788bbf078f3894 100644 --- a/arch/arm64/boot/dts/apple/t6022.dtsi +++ b/arch/arm64/boot/dts/apple/t6022.dtsi @@ -359,6 +359,49 @@ power-domains = <&ps_afr>, <&ps_afr_die1>; }; +&pmp { + apple,pio-ranges = <0x2 0x80000000 0x0 0x1000000>, + <0x3 0x0 0x0 0x1000000>, + <0x3 0x80000000 0x0 0x1000000>, + <0x4 0x0 0x0 0x1000000>, + <0x3 0x40000000 0x0 0x1000000>, + <0x2 0x10e70000 0x0 0x90000>, + <0x2 0x11e70000 0x0 0x90000>, + <0x2 0x12e70000 0x0 0x90000>, + <0x4 0x80000000 0x0 0x1000000>, + <0x5 0x0 0x0 0x1000000>, + <0x22 0x80000000 0x0 0x1000000>, + <0x23 0x0 0x0 0x1000000>, + <0x23 0x80000000 0x0 0x1000000>, + <0x24 0x0 0x0 0x1000000>, + <0x23 0x40000000 0x0 0x1000000>, + <0x24 0x80000000 0x0 0x1000000>, + <0x25 0x0 0x0 0x1000000>, + <0x22 0x10e70000 0x0 0x90000>, + <0x22 0x11e70000 0x0 0x90000>, + <0x22 0x12e70000 0x0 0x90000>; +}; + +&pmp_report { + pmp_report_dispext0_die1: report@1f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1f>; + label = "pmp-dispext0_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0_die1>; + }; + + pmp_report_dispext1_die1: report@20 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext1_die1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0_die1>; + }; +}; + &gpu { compatible = "apple,agx-t6022", "apple,agx-g14x", "apple,agx-g14d", "apple,agx-g14s"; diff --git a/arch/arm64/boot/dts/apple/t602x-common.dtsi b/arch/arm64/boot/dts/apple/t602x-common.dtsi index 2905234ad6d40b..317f913bf13a12 100644 --- a/arch/arm64/boot/dts/apple/t602x-common.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-common.dtsi @@ -13,6 +13,7 @@ aliases { gpu = &gpu; + pmp = &pmp; }; cpus { diff --git a/arch/arm64/boot/dts/apple/t602x-die0.dtsi b/arch/arm64/boot/dts/apple/t602x-die0.dtsi index 6803254a38af5e..ff5664bbe0542d 100644 --- a/arch/arm64/boot/dts/apple/t602x-die0.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-die0.dtsi @@ -23,6 +23,206 @@ power-domains = <&ps_aic>; }; + pmp_dart: iommu@28e300000 { + compatible = "apple,t6020-dart", "apple,t8110-dart"; + reg = <0x2 0x8e300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@28e3c0000 { + compatible = "apple,t6020-pmp-v2-report"; + reg = <0x2 0x8e3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_gfx: report@a { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-gfx"; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@b { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@c { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + }; + + pmp_report_disp0: report@d { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext0: report@e { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext0"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext0_cpu0>; + }; + + pmp_report_dispext1: report@f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xe>; + label = "pmp-dispext1"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext1_cpu0>; + }; + + pmp_report_venc_sys: report@10 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x10>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@11 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr0: report@12 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x12>; + label = "pmp-msr0"; + #power-domain-cells = <0>; + power-domains = <&ps_msr0>; + status = "disabled"; + }; + + pmp_report_jpg: report@13 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x13>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@14 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x14>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_dispext2: report@1f { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x1f>; + label = "pmp-dispext2"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext2_cpu0>; + status = "disabled"; + }; + + pmp_report_dispext3: report@20 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x20>; + label = "pmp-dispext3"; + #power-domain-cells = <0>; + power-domains = <&ps_dispext3_cpu0>; + status = "disabled"; + }; + + pmp_report_venc1: report@21 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x21>; + label = "pmp-venc1"; + #power-domain-cells = <0>; + power-domains = <&ps_venc1_sys>; + status = "disabled"; + }; + + pmp_report_msr1: report@22 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x22>; + label = "pmp-msr1"; + #power-domain-cells = <0>; + power-domains = <&ps_msr1>; + status = "disabled"; + }; + + pmp_report_prores: report@23 { + compatible = "apple,t6020-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x23>; + label = "pmp-prores"; + #power-domain-cells = <0>; + power-domains = <&ps_prores>; + status = "disabled"; + }; + }; + + pmp: pmp@28e700000 { + compatible = "apple,t6020-pmp-v2", "apple,t6000-pmp-v2"; + reg = <0x2 0x8e700000 0x0 0x100000>, + <0x2 0x8ec00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + tunables { + }; + }; + + pmp_mbox: mbox@28ec08000 { + compatible = "apple,t6020-asc-mailbox", "apple,asc-mailbox-v4"; + reg = <0x2 0x8ec08000 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>; + }; + pmgr_misc: power-management@28e20c000 { compatible = "apple,t6020-pmgr-misc", "apple,t6000-pmgr-misc"; #address-cells = <1>; @@ -338,7 +538,7 @@ #iommu-cells = <1>; interrupt-parent = <&aic>; interrupts = ; - power-domains = <&ps_isp_sys>; + power-domains = <&pmp_report_isp_sys>; apple,dma-range = <0x100 0x0 0x1 0x0>; status = "disabled"; @@ -410,7 +610,7 @@ <0x3 0x89344000 0x0 0x4000>, <0x3 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1208>; - power-domains = <&ps_disp0_cpu0>; + power-domains = <&pmp_report_disp0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -739,7 +939,7 @@ , ; 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", diff --git a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi index 30fe15fe0ac393..b3fafb91348fc0 100644 --- a/arch/arm64/boot/dts/apple/t602x-dieX.dtsi +++ b/arch/arm64/boot/dts/apple/t602x-dieX.dtsi @@ -74,7 +74,7 @@ <0x2 0x89344000 0x0 0x4000>, <0x2 0x89800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1210>; - power-domains = <&DIE_NODE(ps_dispext0_cpu0)>; + power-domains = <&DIE_NODE(pmp_report_dispext0)>; resets = <&DIE_NODE(ps_dispext0_cpu0)>; clocks = <&DIE_NODE(clk_dispext0)>; phandle = <&DIE_NODE(dcpext0)>; @@ -222,7 +222,7 @@ <0x3 0x15344000 0x0 0x4000>, <0x3 0x15800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x1218>; - power-domains = <&DIE_NODE(ps_dispext1_cpu0)>; + power-domains = <&DIE_NODE(pmp_report_dispext1)>; resets = <&DIE_NODE(ps_dispext1_cpu0)>; clocks = <&DIE_NODE(clk_dispext1)>; phandle = <&DIE_NODE(dcpext1)>; diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi index 13847d4fd37fc5..c05d10a47b25fa 100644 --- a/arch/arm64/boot/dts/apple/t8112.dtsi +++ b/arch/arm64/boot/dts/apple/t8112.dtsi @@ -22,6 +22,7 @@ aliases { gpu = &gpu; + pmp = &pmp; }; cpus { @@ -508,7 +509,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", @@ -578,7 +579,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 = , ; @@ -672,7 +673,7 @@ <0x2 0x2c4c4430 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>, @@ -733,7 +734,7 @@ <0x2 0x31344000 0x0 0x4000>, <0x2 0x31800000 0x0 0x800000>; apple,bw-scratch = <&pmgr_dcp 0 4 0x5d8>; - power-domains = <&ps_disp0_cpu0>; + power-domains = <&pmp_report_disp0>; resets = <&ps_disp0_cpu0>; clocks = <&clk_disp0>; phandle = <&dcp>; @@ -1063,6 +1064,157 @@ /* child nodes are added in t8103-pmgr.dtsi */ }; + pmp_dart: iommu@23b300000 { + compatible = "apple,t8110-dart"; + reg = <0x2 0x3b300000 0x0 0x4000>; + #iommu-cells = <1>; + interrupt-parent = <&aic>; + interrupts = ; + power-domains = <&ps_pmp>; + }; + + pmp_report: pmp_report@23b3c0000 { + compatible = "apple,t8112-pmp-v2-report"; + reg = <0x2 0x3b3c0000 0x0 0x20000>; + power-domains = <&ps_pms_sram>; + #address-cells = <1>; + #size-cells = <0>; + + pmp_report_gfx: report@4 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x4>; + label = "pmp-gfx"; + #power-domain-cells = <0>; + power-domains = <&ps_gfx>; + }; + + pmp_report_ane_sys: report@5 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x5>; + label = "pmp-ane-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_ane_sys>; + status = "disabled"; + }; + + pmp_report_isp_sys: report@6 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x6>; + label = "pmp-isp-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_isp_sys>; + }; + + pmp_report_disp0: report@7 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x7>; + label = "pmp-disp0"; + #power-domain-cells = <0>; + power-domains = <&ps_disp0_cpu0>; + apple,always-on; + }; + + pmp_report_dispext: report@8 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x8>; + label = "pmp-dispext"; + #power-domain-cells = <0>; + power-domains = <&pmp_report_dispext>; + }; + + pmp_report_venc_sys: report@9 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x9>; + label = "pmp-venc-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_venc_sys>; + status = "disabled"; + }; + + pmp_report_avd_sys: report@a { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xa>; + label = "pmp-avd-sys"; + #power-domain-cells = <0>; + power-domains = <&ps_avd_sys>; + status = "disabled"; + }; + + pmp_report_msr: report@b { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xb>; + label = "pmp-msr"; + #power-domain-cells = <0>; + power-domains = <&ps_msr>; + status = "disabled"; + }; + + pmp_report_jpg: report@c { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xc>; + label = "pmp-jpg"; + #power-domain-cells = <0>; + power-domains = <&ps_jpg>; + status = "disabled"; + }; + + pmp_report_scodec: report@d { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0xd>; + label = "pmp-scodec"; + #power-domain-cells = <0>; + power-domains = <&ps_scodec>; + status = "disabled"; + }; + + pmp_report_dispdfr: report@11 { + compatible = "apple,t8112-pmp-v2-report-entry", + "apple,t6000-pmp-v2-report-entry"; + reg = <0x11>; + label = "pmp-dispdfr"; + #power-domain-cells = <0>; + power-domains = <&ps_dispdfr_fe>; + }; + }; + + pmp: pmp@23b500000 { + compatible = "apple,t8112-pmp-v2", "apple,t6000-pmp-v2"; + reg = <0x2 0x3b500000 0x0 0x80000>, + <0x2 0x3bc00000 0x0 0x4000>; + reg-names = "pmp", "asc"; + mboxes = <&pmp_mbox>; + mbox-names = "mbox"; + iommus = <&pmp_dart 0>; + power-domains = <&ps_pmp>; + tunables { + }; + }; + + pmp_mbox: mbox@23bc08000 { + compatible = "apple,t8112-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>; + }; + + pmgr_dcp: power-management@23b3d0000 { reg = <0x2 0x3b3d0000 0x0 0x4000>; reg-names = "dcp-bw-scratch";