Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 00/13] Add support for SCMIv4.0 Powercap Extensions
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford

Hi all,

I will be taking over this series from Cristian and in doing so I have
addressed a couple of issues raised by the first version and added six
additional patches since Cristian's original series:

[1/13] addresses an omission from the original powercap functionality. The
ABI documentation describes allowing enabling and disabling power capping
for a control type via /sys/class/powercap/<control type>/enabled. This
first patch implements this functionality but as stated before, this was an
omission rather than a bug that requires fixing. Disabling the control type
disables any immediate children of the control type.

The logic for this patch is based on the logic I was using for enabling and
disabling the synthetic node in the final patch of this series. As a result,
the synthetic node enable/disable patch has now been significantly reduced.

[7/13] exposes the measurement averaging interval (MAI) value when the
agent has registered to receive power measurement change notifications
for the power capping domain.

[10/13] adds MAI get and set support for the powercap protocol.

[11/13] introduces a synthetic root zone to act as a common parent for all
top-level domains.

[12/13] adds get_power_uw to synthetic root zone, summing the per-zone
power of immediate child zones.

[13/13] adds enable/disable functionality to synthetic root zone to
enable/disable immediate children.

The original series was based on v6.17-rc1 whereas this version has been
based on v7.2-rc1.

The rest of Cristian's series is explained below;

SCMIv4.0 [1] introduces some new features and commands into the Powercap
protocol. In a nutshell, such protocol changes add support for:

 - setting multiple powercap limit/interval constraints for each SCMI
   powercap domain which supports multiple Concurrent Power Limit
 - enabling more Powercap commands to use Fastchannels mechanism
 - adding multiple constraints support to the existing notifications

After a bit of needed updates in the SCMI core this series adds:

- support for the idea of optional multiple Concurrent Power Limit (CPLs)
- support for the new FCs
- support for extended notifications
- enable usage of such multiple constraint in the ARM SCMI Powercap driver

Note that the public SCMIv4.0 spec at [1] is currently still BETA0, so
this series could anyway need some minor rework along the way and
definitely will need to wait for a final public release before being
possibly merged.

Tested on a single and multi-instance scenario on an emulated setup
implementing the new protocol extensions.

Based on v7.2-rc1.

Thanks,
Phil
---
V7->V8
- Rebased on v7.2-rc1
- Fixed conflict due to updates to v7.2
V6->V7
- Added control type enable/disable patch
- Refactored Synthetic zone enable disable patch
- Corrected naming of define V2/V3 payload sizes
- Prevent possible cpli[0] out-of-bounds access
- Added cleanup for zones during scmi_powercap_probe
- Prevent instance_root_get_enable reporting a stale state
- Rebased on v7.1-rc7
V5->V6
- Re-worded existing comment for POWERCAP_MEASUREMENTS_NOTIFY
- Added define for V2/V3 payload sizes
- Used new definitions for payload sizes
- Fixed comment length
- Changed warning message warning
- Fixed line lengths and alignment
- Updated docs for new fields
- Amended omission of spz initialization when unregistering powercap zones
- Tested unloading and loading powercap module
- Re-wrote commit message
- Added use of to_scmi_powercap_root macro
- Changed instance_root_set_enable_state to bail out on any error
V4->V5
- Added enable/disable functionality to synthetic node
- Rebased on v7.1-rc1
V3->V4
- Rebased on v7.0-rc4
- Added sythentic parent node and functionality
- Moved fastchannel inits outside of loop
- Renamed arguments for consistency
V2->V3
- Added powercap MAI get/set support
V1->V2
- Rebased on sudeep/for-next/scmi/updates
- Amended Copyright to include 2026
- Added patch to extend powercap report to include MAI
- Removed creation of pi powercap_info struct due to legacy code change
- Amended references to pi->version and similar, which were based on
  legacy code
- Wrapped two variables in le32_to_cpu() to appease Sparse warnings
- Amended comparing operator value in response to feedback

Cristian Marussi (7):
  firmware: arm_scmi: Add an optional custom parameter to fastchannel
    helpers
  firmware: arm_scmi: Refactor powercap domain layout
  firmware: arm_scmi: Add SCMIv4.0 Powercap basic support
  firmware: arm_scmi: Add SCMIv4.0 Powercap FCs support
  firmware: arm_scmi: Add SCMIV4.0 Powercap notifications support
  include: trace: Add new parameter to trace_scmi_fc_call
  powercap: arm_scmi: Enable multiple constraints support

Philip Radford (6):
  powercap: Add enable disable control-type
  firmware: arm_scmi: Extend powercap report to include MAI
  firmware: arm_scmi: add Powercap MAI get/set support
  powercap: arm_scmi: Create synthetic parent node for multi-instance
  powercap: arm_scmi: Add get_power_uw to synthetic node
  powercap: arm_scmi: Synthetic zone enable/disable

 drivers/firmware/arm_scmi/driver.c    |   12 +-
 drivers/firmware/arm_scmi/perf.c      |   16 +-
 drivers/firmware/arm_scmi/powercap.c  | 1001 ++++++++++++++++++++-----
 drivers/firmware/arm_scmi/protocols.h |    2 +-
 drivers/powercap/arm_scmi_powercap.c  |  355 ++++++++-
 include/linux/scmi_protocol.h         |   97 ++-
 include/trace/events/scmi.h           |   12 +-
 7 files changed, 1214 insertions(+), 281 deletions(-)

--
2.25.1



^ permalink raw reply

* [PATCH v8 02/13] firmware: arm_scmi: Add an optional custom parameter to fastchannel helpers
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Starting from SCMIv4.0 the protocols DESCRIBE_FASTCHANNEL commands allow
to specify one additional per-protocol custom field in the outgoing message
request in order to, optionally, further narrow down the scope of the
fastchannel discovery request; the related message-reply format is instead
unchanged.

Add an optional custom protocol parameter to the common fastchannel helper
so as to enable the caller to choose the kind of message to send based on
the detected protocol version.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/driver.c    | 12 ++++++++++--
 drivers/firmware/arm_scmi/perf.c      |  8 ++++----
 drivers/firmware/arm_scmi/powercap.c  |  8 ++++----
 drivers/firmware/arm_scmi/protocols.h |  2 +-
 4 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 3e0d975ec94c..81cb8eec14bc 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1902,6 +1902,11 @@ static int scmi_iterator_run_bound(void *iter, unsigned int *start,
 struct scmi_msg_get_fc_info {
 	__le32 domain;
 	__le32 message_id;
+	__le32 custom;
+#define MSG_FC_INFO_SZ_EXTENDED	\
+	(sizeof(struct scmi_msg_get_fc_info))
+#define MSG_FC_INFO_SZ		\
+	(sizeof(struct scmi_msg_get_fc_info) - sizeof(__le32))
 };
 
 struct scmi_msg_resp_desc_fc {
@@ -1930,7 +1935,7 @@ struct scmi_msg_resp_desc_fc {
 static void
 scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
 			     u8 describe_id, u32 message_id, u32 valid_size,
-			     u32 domain, void __iomem **p_addr,
+			     u32 domain, u32 *custom, void __iomem **p_addr,
 			     struct scmi_fc_db_info **p_db, u32 *rate_limit)
 {
 	int ret;
@@ -1961,13 +1966,16 @@ scmi_common_fastchannel_init(const struct scmi_protocol_handle *ph,
 	}
 
 	ret = ph->xops->xfer_get_init(ph, describe_id,
-				      sizeof(*info), sizeof(*resp), &t);
+				      custom ? MSG_FC_INFO_SZ_EXTENDED :
+				      MSG_FC_INFO_SZ, sizeof(*resp), &t);
 	if (ret)
 		goto err_out;
 
 	info = t->tx.buf;
 	info->domain = cpu_to_le32(domain);
 	info->message_id = cpu_to_le32(message_id);
+	if (custom)
+		info->custom = cpu_to_le32(*custom);
 
 	/*
 	 * Bail out on error leaving fc_info addresses zeroed; this includes
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 4583d02bee1c..7f283f457e02 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -835,25 +835,25 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
 		return;
 
 	ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
-				   PERF_LEVEL_GET, 4, dom->id,
+				   PERF_LEVEL_GET, 4, dom->id, NULL,
 				   &fc[PERF_FC_LEVEL].get_addr, NULL,
 				   &fc[PERF_FC_LEVEL].rate_limit);
 
 	ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
-				   PERF_LIMITS_GET, 8, dom->id,
+				   PERF_LIMITS_GET, 8, dom->id, NULL,
 				   &fc[PERF_FC_LIMIT].get_addr, NULL,
 				   &fc[PERF_FC_LIMIT].rate_limit);
 
 	if (dom->info.set_perf)
 		ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
-					   PERF_LEVEL_SET, 4, dom->id,
+					   PERF_LEVEL_SET, 4, dom->id, NULL,
 					   &fc[PERF_FC_LEVEL].set_addr,
 					   &fc[PERF_FC_LEVEL].set_db,
 					   &fc[PERF_FC_LEVEL].rate_limit);
 
 	if (dom->set_limits)
 		ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
-					   PERF_LIMITS_SET, 8, dom->id,
+					   PERF_LIMITS_SET, 8, dom->id, NULL,
 					   &fc[PERF_FC_LIMIT].set_addr,
 					   &fc[PERF_FC_LIMIT].set_db,
 					   &fc[PERF_FC_LIMIT].rate_limit);
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 27e3c805e927..31b19967452f 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -726,24 +726,24 @@ static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
 		return;
 
 	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_CAP_SET, 4, domain,
+				   POWERCAP_CAP_SET, 4, domain, NULL,
 				   &fc[POWERCAP_FC_CAP].set_addr,
 				   &fc[POWERCAP_FC_CAP].set_db,
 				   &fc[POWERCAP_FC_CAP].rate_limit);
 
 	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_CAP_GET, 4, domain,
+				   POWERCAP_CAP_GET, 4, domain, NULL,
 				   &fc[POWERCAP_FC_CAP].get_addr, NULL,
 				   &fc[POWERCAP_FC_CAP].rate_limit);
 
 	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_PAI_SET, 4, domain,
+				   POWERCAP_PAI_SET, 4, domain, NULL,
 				   &fc[POWERCAP_FC_PAI].set_addr,
 				   &fc[POWERCAP_FC_PAI].set_db,
 				   &fc[POWERCAP_FC_PAI].rate_limit);
 
 	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_PAI_GET, 4, domain,
+				   POWERCAP_PAI_GET, 4, domain, NULL,
 				   &fc[POWERCAP_FC_PAI].get_addr, NULL,
 				   &fc[POWERCAP_FC_PAI].rate_limit);
 
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index 15ad5162e37a..6b27e1b531a1 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -291,7 +291,7 @@ struct scmi_proto_helpers_ops {
 				  u32 message_id, u32 *attributes);
 	void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
 				 u8 describe_id, u32 message_id,
-				 u32 valid_size, u32 domain,
+				 u32 valid_size, u32 domain, u32 *custom,
 				 void __iomem **p_addr,
 				 struct scmi_fc_db_info **p_db,
 				 u32 *rate_limit);
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 01/13] powercap: Add enable disable control-type
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

Add functionality to disable or enable the Powercap control-type by writing
directly into sys/class/powercap/arm-scmi/enabled.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/powercap/arm_scmi_powercap.c | 155 ++++++++++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index ab66e9a3b1e2..e33829d5c551 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -33,13 +33,151 @@ struct scmi_powercap_zone {
 
 struct scmi_powercap_root {
 	unsigned int num_zones;
+	bool enabled;
+	struct list_head node;
 	struct scmi_powercap_zone *spzones;
 	struct list_head *registered_zones;
 	struct list_head scmi_zones;
 };
 
+static LIST_HEAD(scmi_powercap_roots);
+static DEFINE_MUTEX(scmi_powercap_roots_lock);
+
 static struct powercap_control_type *scmi_top_pcntrl;
 
+static bool scmi_powercap_is_control_type_child(const struct scmi_powercap_zone *spz)
+{
+	return spz->registered && !spz->invalid &&
+	       spz->info->parent_id == SCMI_POWERCAP_ROOT_ZONE_ID;
+}
+
+static int
+scmi_powercap_read_root_children_enable_state(struct scmi_powercap_root *pr, bool *mode)
+{
+	struct scmi_powercap_zone *spz;
+	bool enabled;
+	int i, ret;
+
+	*mode = true;
+
+	for (i = 0; i < pr->num_zones; i++) {
+		spz = &pr->spzones[i];
+
+		if (!scmi_powercap_is_control_type_child(spz))
+			continue;
+
+		ret = powercap_ops->cap_enable_get(spz->ph, spz->info->id, &enabled);
+		if (ret)
+			return ret;
+
+		if (!enabled) {
+			*mode = false;
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int
+scmi_powercap_set_root_children_enable_state(struct scmi_powercap_root *pr, bool enable)
+{
+	struct scmi_powercap_zone *spz;
+	bool *prev_state;
+	int i, ret;
+
+	prev_state = kcalloc(pr->num_zones, sizeof(*prev_state), GFP_KERNEL);
+	if (!prev_state)
+		return -ENOMEM;
+
+	for (i = 0; i < pr->num_zones; i++) {
+		spz = &pr->spzones[i];
+
+		if (!scmi_powercap_is_control_type_child(spz))
+			continue;
+
+		ret = powercap_ops->cap_enable_get(spz->ph, spz->info->id,
+						   &prev_state[i]);
+
+		if (ret)
+			goto revert;
+
+		if (prev_state[i] == enable)
+			continue;
+
+		ret = powercap_ops->cap_enable_set(spz->ph, spz->info->id, enable);
+		if (ret)
+			goto revert;
+	}
+
+	pr->enabled = enable;
+	kfree(prev_state);
+	return 0;
+
+revert:
+	while (--i >= 0) {
+		spz = &pr->spzones[i];
+
+		if (!scmi_powercap_is_control_type_child(spz))
+			continue;
+		if (!spz->info->powercap_cap_config)
+			continue;
+		if (prev_state[i] == enable)
+			continue;
+
+		powercap_ops->cap_enable_set(spz->ph, spz->info->id, prev_state[i]);
+	}
+
+	kfree(prev_state);
+	return ret;
+}
+
+static int
+scmi_powercap_control_type_set_enable(struct powercap_control_type *pct, bool mode)
+{
+	struct scmi_powercap_root *pr;
+	int ret = 0;
+
+	mutex_lock(&scmi_powercap_roots_lock);
+	list_for_each_entry(pr, &scmi_powercap_roots, node) {
+		ret = scmi_powercap_set_root_children_enable_state(pr, mode);
+		if (ret)
+			break;
+	}
+	mutex_unlock(&scmi_powercap_roots_lock);
+
+	return ret;
+}
+
+static int
+scmi_powercap_control_type_get_enable(struct powercap_control_type *pct, bool *mode)
+{
+	struct scmi_powercap_root *pr;
+	int ret = 0;
+
+	*mode = true;
+
+	mutex_lock(&scmi_powercap_roots_lock);
+	list_for_each_entry(pr, &scmi_powercap_roots, node) {
+		ret = scmi_powercap_read_root_children_enable_state(pr, &pr->enabled);
+
+		if (ret)
+			break;
+		if (!pr->enabled) {
+			*mode = false;
+			break;
+		}
+	}
+	mutex_unlock(&scmi_powercap_roots_lock);
+
+	return ret;
+}
+
+static const struct powercap_control_type_ops scmi_powercap_control_type_ops = {
+	.set_enable = scmi_powercap_control_type_set_enable,
+	.get_enable = scmi_powercap_control_type_get_enable,
+};
+
 static int scmi_powercap_zone_release(struct powercap_zone *pz)
 {
 	return 0;
@@ -495,6 +633,16 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 	if (ret)
 		return ret;
 
+	INIT_LIST_HEAD(&pr->node);
+
+	ret = scmi_powercap_read_root_children_enable_state(pr, &pr->enabled);
+	if (ret)
+		return ret;
+
+	mutex_lock(&scmi_powercap_roots_lock);
+	list_add_tail(&pr->node, &scmi_powercap_roots);
+	mutex_unlock(&scmi_powercap_roots_lock);
+
 	dev_set_drvdata(dev, pr);
 
 	return ret;
@@ -505,6 +653,10 @@ static void scmi_powercap_remove(struct scmi_device *sdev)
 	struct device *dev = &sdev->dev;
 	struct scmi_powercap_root *pr = dev_get_drvdata(dev);
 
+	mutex_lock(&scmi_powercap_roots_lock);
+	list_del(&pr->node);
+	mutex_unlock(&scmi_powercap_roots_lock);
+
 	scmi_powercap_unregister_all_zones(pr);
 }
 
@@ -525,7 +677,8 @@ static int __init scmi_powercap_init(void)
 {
 	int ret;
 
-	scmi_top_pcntrl = powercap_register_control_type(NULL, "arm-scmi", NULL);
+	scmi_top_pcntrl = powercap_register_control_type(NULL, "arm-scmi",
+							 &scmi_powercap_control_type_ops);
 	if (IS_ERR(scmi_top_pcntrl))
 		return PTR_ERR(scmi_top_pcntrl);
 
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 03/13] firmware: arm_scmi: Refactor powercap domain layout
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

SCMIv4.0 introduces the idea of an optional Concurrent Power Limit (CPL)
for each powercap domain, where CPL0 coincides with the one and only
per-domain constraint limit that was available in pre-v4.0 SCMI Powercap.

Refactor the powercap domain descriptors and powercap operations to allow
future v4.0 extensions to cope with multiple CPLs.

While at that generalize the powercap protocol API to drop PAI references
in favour of a more generic avg_ivl naming, since from v4.0 the number and
types of averaging intervals will change in a non-backward compatible way,
so let's bury these changes within the protocol layer.

Last but not least, make the necessary changes to the ARM SCMI Powwercap
driver in order to support all of these new capabilities.

No functional change.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
[Philip: Adjusted domain_id comparitor in scmi_powercap_pai_get]
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
V7->V8
- Fixed conflict due to changes in 7.2-rc1
---
 drivers/firmware/arm_scmi/powercap.c | 182 +++++++++++++++++----------
 drivers/powercap/arm_scmi_powercap.c |  52 ++++----
 include/linux/scmi_protocol.h        |  74 +++++++----
 3 files changed, 189 insertions(+), 119 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 31b19967452f..4666030176c3 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -2,7 +2,7 @@
 /*
  * System Control and Management Interface (SCMI) Powercap Protocol
  *
- * Copyright (C) 2022 ARM Ltd.
+ * Copyright (C) 2022-2026 ARM Ltd.
  */
 
 #define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
@@ -20,6 +20,8 @@
 /* Updated only after ALL the mandatory features for that version are merged */
 #define SCMI_PROTOCOL_SUPPORTED_VERSION		0x20000
 
+#define CPL0	0
+
 enum scmi_powercap_protocol_cmd {
 	POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
 	POWERCAP_CAP_GET = 0x4,
@@ -192,27 +194,26 @@ scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
 
 static int
 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
-				    struct powercap_info *pinfo, u32 domain)
+				    struct powercap_info *pinfo,
+				    struct scmi_powercap_info *dom_info)
 {
 	int ret;
 	u32 flags;
 	struct scmi_xfer *t;
-	struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
 	struct scmi_msg_resp_powercap_domain_attributes *resp;
 
 	ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
-				      sizeof(domain), sizeof(*resp), &t);
+				      sizeof(dom_info->id), sizeof(*resp), &t);
 	if (ret)
 		return ret;
 
-	put_unaligned_le32(domain, t->tx.buf);
+	put_unaligned_le32(dom_info->id, t->tx.buf);
 	resp = t->rx.buf;
 
 	ret = ph->xops->do_xfer(ph, t);
 	if (!ret) {
 		flags = le32_to_cpu(resp->attributes);
 
-		dom_info->id = domain;
 		if (pinfo->notify_cap_cmd)
 			dom_info->notify_powercap_cap_change =
 				SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
@@ -221,12 +222,9 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 				SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
 		dom_info->async_powercap_cap_set =
 			SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
-		dom_info->powercap_cap_config =
-			SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
+
 		dom_info->powercap_monitoring =
 			SUPPORTS_POWERCAP_MONITORING(flags);
-		dom_info->powercap_pai_config =
-			SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
 		dom_info->powercap_scale_mw =
 			SUPPORTS_POWER_UNITS_MW(flags);
 		dom_info->powercap_scale_uw =
@@ -236,13 +234,29 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 
 		strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
 
-		dom_info->min_pai = le32_to_cpu(resp->min_pai);
-		dom_info->max_pai = le32_to_cpu(resp->max_pai);
-		dom_info->pai_step = le32_to_cpu(resp->pai_step);
-		ret = scmi_powercap_validate(dom_info->min_pai,
-					     dom_info->max_pai,
-					     dom_info->pai_step,
-					     dom_info->powercap_pai_config);
+		dom_info->sustainable_power =
+			le32_to_cpu(resp->sustainable_power);
+		dom_info->accuracy = le32_to_cpu(resp->accuracy);
+
+		dom_info->parent_id = le32_to_cpu(resp->parent_id);
+		if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
+		    (dom_info->parent_id >= pinfo->num_domains ||
+		     dom_info->parent_id == dom_info->id)) {
+			dev_err(ph->dev,
+				"Platform reported inconsistent parent ID for domain %d - %s\n",
+				dom_info->id, dom_info->name);
+			ret = -ENODEV;
+		}
+
+		dom_info->cpli[0].avg_ivl_config =
+			SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
+		dom_info->cpli[0].min_avg_ivl = le32_to_cpu(resp->min_pai);
+		dom_info->cpli[0].max_avg_ivl = le32_to_cpu(resp->max_pai);
+		dom_info->cpli[0].avg_ivl_step = le32_to_cpu(resp->pai_step);
+		ret = scmi_powercap_validate(dom_info->cpli[0].min_avg_ivl,
+					     dom_info->cpli[0].max_avg_ivl,
+					     dom_info->cpli[0].avg_ivl_step,
+					     dom_info->cpli[0].avg_ivl_config);
 		if (ret) {
 			dev_err(ph->dev,
 				"Platform reported inconsistent PAI config for domain %d - %s\n",
@@ -250,13 +264,15 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 			goto clean;
 		}
 
-		dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
-		dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
-		dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
-		ret = scmi_powercap_validate(dom_info->min_power_cap,
-					     dom_info->max_power_cap,
-					     dom_info->power_cap_step,
-					     dom_info->powercap_cap_config);
+		dom_info->cpli[0].cap_config =
+			SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
+		dom_info->cpli[0].min_power_cap = le32_to_cpu(resp->min_power_cap);
+		dom_info->cpli[0].max_power_cap = le32_to_cpu(resp->max_power_cap);
+		dom_info->cpli[0].power_cap_step = le32_to_cpu(resp->power_cap_step);
+		ret = scmi_powercap_validate(dom_info->cpli[0].min_power_cap,
+					     dom_info->cpli[0].max_power_cap,
+					     dom_info->cpli[0].power_cap_step,
+					     dom_info->cpli[0].cap_config);
 		if (ret) {
 			dev_err(ph->dev,
 				"Platform reported inconsistent CAP config for domain %d - %s\n",
@@ -264,19 +280,9 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 			goto clean;
 		}
 
-		dom_info->sustainable_power =
-			le32_to_cpu(resp->sustainable_power);
-		dom_info->accuracy = le32_to_cpu(resp->accuracy);
-
-		dom_info->parent_id = le32_to_cpu(resp->parent_id);
-		if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
-		    (dom_info->parent_id >= pinfo->num_domains ||
-		     dom_info->parent_id == dom_info->id)) {
-			dev_err(ph->dev,
-				"Platform reported inconsistent parent ID for domain %d - %s\n",
-				dom_info->id, dom_info->name);
-			ret = -ENODEV;
-		}
+		/* Just using same short name */
+		strscpy(dom_info->cpli[0].name, dom_info->name,
+			SCMI_SHORT_NAME_MAX_SIZE);
 	}
 
 clean:
@@ -288,12 +294,30 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 	 */
 	if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
 		ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
-					    domain, NULL, dom_info->name,
+					    dom_info->id, NULL, dom_info->name,
 					    SCMI_MAX_STR_SIZE);
 
 	return ret;
 }
 
+static int
+scmi_powercap_domain_initialize(const struct scmi_protocol_handle *ph,
+				struct powercap_info *pinfo, u32 domain)
+{
+	struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
+
+	dom_info->num_cpli = 1;
+	dom_info->cpli = devm_kcalloc(ph->dev, dom_info->num_cpli,
+				      sizeof(*dom_info->cpli), GFP_KERNEL);
+	if (!dom_info->cpli)
+		return -ENOMEM;
+
+	dom_info->id = domain;
+	dom_info->cpli[0].id = CPL0;
+
+	return scmi_powercap_domain_attributes_get(ph, pinfo, dom_info);
+}
+
 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
 {
 	struct powercap_info *pi = ph->get_priv(ph);
@@ -335,10 +359,11 @@ static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
 
 static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 				   const struct scmi_powercap_info *dom,
-				   u32 *power_cap)
+				   u32 cpl_id, u32 *power_cap)
 {
-	if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
-		*power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
+	if (dom->cpli[cpl_id].fc_info &&
+	    dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr) {
+		*power_cap = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
 				   dom->id, *power_cap, 0);
 		return 0;
@@ -348,7 +373,7 @@ static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 *power_cap)
+				 u32 domain_id, u32 cpl_id, u32 *power_cap)
 {
 	const struct scmi_powercap_info *dom;
 
@@ -359,12 +384,13 @@ static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 	if (!dom)
 		return -EINVAL;
 
-	return __scmi_powercap_cap_get(ph, dom, power_cap);
+	return __scmi_powercap_cap_get(ph, dom, cpl_id, power_cap);
 }
 
 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 				      const struct scmi_powercap_info *pc,
-				      u32 power_cap, bool ignore_dresp)
+				      u32 cpl_id, u32 power_cap,
+				      bool ignore_dresp)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -406,21 +432,23 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 
 static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 				   struct powercap_info *pi, u32 domain_id,
-				   u32 power_cap, bool ignore_dresp)
+				   u32 cpl_id, u32 power_cap, bool ignore_dresp)
 {
 	int ret = -EINVAL;
 	const struct scmi_powercap_info *pc;
 
 	pc = scmi_powercap_dom_info_get(ph, domain_id);
-	if (!pc || !pc->powercap_cap_config)
+	if (!pc || !pc->cpli[cpl_id].cap_config)
 		return ret;
 
 	if (power_cap &&
-	    (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
+	    (power_cap < pc->cpli[cpl_id].min_power_cap ||
+	     power_cap > pc->cpli[cpl_id].max_power_cap))
 		return ret;
 
-	if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
-		struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
+	if (pc->cpli[cpl_id].fc_info &&
+	    pc->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].set_addr) {
+		struct scmi_fc_info *fci = &pc->cpli[cpl_id].fc_info[POWERCAP_FC_CAP];
 
 		iowrite32(power_cap, fci->set_addr);
 		ph->hops->fastchannel_db_ring(fci->set_db);
@@ -428,7 +456,7 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 				   domain_id, power_cap, 0);
 		ret = 0;
 	} else {
-		ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
+		ret = scmi_powercap_xfer_cap_set(ph, pc, cpl_id, power_cap,
 						 ignore_dresp);
 	}
 
@@ -440,7 +468,7 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 power_cap,
+				 u32 domain_id, u32 cpl_id, u32 power_cap,
 				 bool ignore_dresp)
 {
 	struct powercap_info *pi = ph->get_priv(ph);
@@ -463,7 +491,7 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 		}
 	}
 
-	return __scmi_powercap_cap_set(ph, pi, domain_id,
+	return __scmi_powercap_cap_set(ph, pi, domain_id, cpl_id,
 				       power_cap, ignore_dresp);
 }
 
@@ -489,7 +517,7 @@ static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 *pai)
+				 u32 domain_id, u32 cpl_id, u32 *pai)
 {
 	struct scmi_powercap_info *dom;
 	struct powercap_info *pi = ph->get_priv(ph);
@@ -498,8 +526,11 @@ static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
 		return -EINVAL;
 
 	dom = pi->powercaps + domain_id;
-	if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
-		*pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
+	if (cpl_id >= dom->num_cpli)
+		return -EINVAL;
+
+	if (dom->cpli[cpl_id].fc_info && dom->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].get_addr) {
+		*pai = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].get_addr);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
 				   domain_id, *pai, 0);
 		return 0;
@@ -508,6 +539,12 @@ static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
 	return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
 }
 
+static int scmi_powercap_avg_interval_get(const struct scmi_protocol_handle *ph,
+					  u32 domain_id, u32 cpl_id, u32 *val)
+{
+	return scmi_powercap_pai_get(ph, domain_id, cpl_id, val);
+}
+
 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
 				      u32 domain_id, u32 pai)
 {
@@ -532,17 +569,18 @@ static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
 }
 
 static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 pai)
+				 u32 domain_id, u32 cpl_id, u32 pai)
 {
 	const struct scmi_powercap_info *pc;
 
 	pc = scmi_powercap_dom_info_get(ph, domain_id);
-	if (!pc || !pc->powercap_pai_config || !pai ||
-	    pai < pc->min_pai || pai > pc->max_pai)
+	if (!pc || cpl_id >= pc->num_cpli || !pc->cpli[cpl_id].avg_ivl_config ||
+	    !pai || pai < pc->cpli[cpl_id].min_avg_ivl ||
+	    pai > pc->cpli[cpl_id].max_avg_ivl)
 		return -EINVAL;
 
-	if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
-		struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
+	if (pc->cpli[cpl_id].fc_info && pc->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].set_addr) {
+		struct scmi_fc_info *fci = &pc->cpli[cpl_id].fc_info[POWERCAP_FC_PAI];
 
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
 				   domain_id, pai, 0);
@@ -554,6 +592,12 @@ static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
 	return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
 }
 
+static int scmi_powercap_avg_interval_set(const struct scmi_protocol_handle *ph,
+					  u32 domain_id, u32 cpl_id, u32 val)
+{
+	return scmi_powercap_pai_set(ph, domain_id, cpl_id, val);
+}
+
 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
 					  u32 domain_id, u32 *average_power,
 					  u32 *pai)
@@ -652,11 +696,11 @@ static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
 		if (!pi->states[domain_id].last_pcap)
 			return -EINVAL;
 
-		ret = __scmi_powercap_cap_set(ph, pi, domain_id,
+		ret = __scmi_powercap_cap_set(ph, pi, domain_id, CPL0,
 					      pi->states[domain_id].last_pcap,
 					      true);
 	} else {
-		ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
+		ret = __scmi_powercap_cap_set(ph, pi, domain_id, CPL0, 0, true);
 	}
 
 	if (ret)
@@ -667,7 +711,7 @@ static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
 	 * server could have ignored a disable request and kept enforcing some
 	 * powercap limit requested by other agents.
 	 */
-	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
+	ret = scmi_powercap_cap_get(ph, domain_id, CPL0, &power_cap);
 	if (!ret)
 		pi->states[domain_id].enabled = !!power_cap;
 
@@ -692,7 +736,7 @@ static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
 	 * Report always real platform state; platform could have ignored
 	 * a previous disable request. Default true on any error.
 	 */
-	ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
+	ret = scmi_powercap_cap_get(ph, domain_id, CPL0, &power_cap);
 	if (!ret)
 		*enable = !!power_cap;
 
@@ -709,8 +753,8 @@ static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 	.cap_set = scmi_powercap_cap_set,
 	.cap_enable_set = scmi_powercap_cap_enable_set,
 	.cap_enable_get = scmi_powercap_cap_enable_get,
-	.pai_get = scmi_powercap_pai_get,
-	.pai_set = scmi_powercap_pai_set,
+	.avg_interval_get = scmi_powercap_avg_interval_get,
+	.avg_interval_set = scmi_powercap_avg_interval_set,
 	.measurements_get = scmi_powercap_measurements_get,
 	.measurements_threshold_set = scmi_powercap_measurements_threshold_set,
 	.measurements_threshold_get = scmi_powercap_measurements_threshold_get,
@@ -1001,18 +1045,18 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 	 * formed and correlated by sane parent-child relationship (if any).
 	 */
 	for (domain = 0; domain < pinfo->num_domains; domain++) {
-		ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
+		ret = scmi_powercap_domain_initialize(ph, pinfo, domain);
 		if (ret)
 			return ret;
 
 		if (pinfo->powercaps[domain].fastchannels)
 			scmi_powercap_domain_init_fc(ph, domain,
-						     &pinfo->powercaps[domain].fc_info);
+						     &pinfo->powercaps[domain].cpli[CPL0].fc_info);
 
 		/* Grab initial state when disable is supported. */
 		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
 			ret = __scmi_powercap_cap_get(ph,
-						      &pinfo->powercaps[domain],
+						      &pinfo->powercaps[domain], CPL0,
 						      &pinfo->states[domain].last_pcap);
 			if (ret)
 				return ret;
diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index e33829d5c551..90d1fa70b1d4 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -120,7 +120,7 @@ scmi_powercap_set_root_children_enable_state(struct scmi_powercap_root *pr, bool
 
 		if (!scmi_powercap_is_control_type_child(spz))
 			continue;
-		if (!spz->info->powercap_cap_config)
+		if (!spz->info->cpli[0].cap_config)
 			continue;
 		if (prev_state[i] == enable)
 			continue;
@@ -235,7 +235,7 @@ static const struct powercap_zone_ops zone_ops = {
 };
 
 static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz,
-					u64 power_limit_uw, u32 *norm)
+					u64 power_limit_uw, int cid, u32 *norm)
 {
 	bool scale_mw = spz->info->powercap_scale_mw;
 	u64 val;
@@ -246,9 +246,9 @@ static void scmi_powercap_normalize_cap(const struct scmi_powercap_zone *spz,
 	 * the range [min_power_cap, max_power_cap] whose bounds are assured to
 	 * be two unsigned 32bits quantities.
 	 */
-	*norm = clamp_t(u32, val, spz->info->min_power_cap,
-			spz->info->max_power_cap);
-	*norm = rounddown(*norm, spz->info->power_cap_step);
+	*norm = clamp_t(u32, val, spz->info->cpli[cid].min_power_cap,
+			spz->info->cpli[cid].max_power_cap);
+	*norm = rounddown(*norm, spz->info->cpli[cid].power_cap_step);
 
 	val = (scale_mw) ? *norm * 1000 : *norm;
 	if (power_limit_uw != val)
@@ -263,12 +263,12 @@ static int scmi_powercap_set_power_limit_uw(struct powercap_zone *pz, int cid,
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 	u32 norm_power;
 
-	if (!spz->info->powercap_cap_config)
+	if (!spz->info->cpli[cid].cap_config)
 		return -EINVAL;
 
-	scmi_powercap_normalize_cap(spz, power_uw, &norm_power);
+	scmi_powercap_normalize_cap(spz, power_uw, cid, &norm_power);
 
-	return powercap_ops->cap_set(spz->ph, spz->info->id, norm_power, false);
+	return powercap_ops->cap_set(spz->ph, spz->info->id, cid, norm_power, false);
 }
 
 static int scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid,
@@ -278,7 +278,7 @@ static int scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid,
 	u32 power;
 	int ret;
 
-	ret = powercap_ops->cap_get(spz->ph, spz->info->id, &power);
+	ret = powercap_ops->cap_get(spz->ph, spz->info->id, cid, &power);
 	if (ret)
 		return ret;
 
@@ -290,19 +290,20 @@ static int scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid,
 }
 
 static void scmi_powercap_normalize_time(const struct scmi_powercap_zone *spz,
-					 u64 time_us, u32 *norm)
+					 u64 time_us, int cid, u32 *norm)
 {
 	/*
 	 * This cast is lossless since here @time_us is certain to be within the
-	 * range [min_pai, max_pai] whose bounds are assured to be two unsigned
-	 * 32bits quantities.
+	 * range [min_avg_ivl, max_avg_ivl] whose bounds are assured to be two
+	 * unsigned 32bits quantities.
 	 */
-	*norm = clamp_t(u32, time_us, spz->info->min_pai, spz->info->max_pai);
-	*norm = rounddown(*norm, spz->info->pai_step);
+	*norm = clamp_t(u32, time_us, spz->info->cpli[cid].min_avg_ivl,
+			spz->info->cpli[cid].max_avg_ivl);
+	*norm = rounddown(*norm, spz->info->cpli[cid].avg_ivl_step);
 
 	if (time_us != *norm)
 		dev_dbg(spz->dev,
-			"Normalized %s:PAI - requested:%llu - normalized:%u\n",
+			"Normalized %s:AVG_IVL - requested:%llu - normalized:%u\n",
 			spz->info->name, time_us, *norm);
 }
 
@@ -312,12 +313,13 @@ static int scmi_powercap_set_time_window_us(struct powercap_zone *pz, int cid,
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 	u32 norm_pai;
 
-	if (!spz->info->powercap_pai_config)
+	if (!spz->info->cpli[cid].avg_ivl_config)
 		return -EINVAL;
 
-	scmi_powercap_normalize_time(spz, time_window_us, &norm_pai);
+	scmi_powercap_normalize_time(spz, time_window_us, cid, &norm_pai);
 
-	return powercap_ops->pai_set(spz->ph, spz->info->id, norm_pai);
+	return powercap_ops->avg_interval_set(spz->ph, spz->info->id,
+					      cid, norm_pai);
 }
 
 static int scmi_powercap_get_time_window_us(struct powercap_zone *pz, int cid,
@@ -327,7 +329,7 @@ static int scmi_powercap_get_time_window_us(struct powercap_zone *pz, int cid,
 	int ret;
 	u32 pai;
 
-	ret = powercap_ops->pai_get(spz->ph, spz->info->id, &pai);
+	ret = powercap_ops->avg_interval_get(spz->ph, spz->info->id, cid, &pai);
 	if (ret)
 		return ret;
 
@@ -341,7 +343,7 @@ static int scmi_powercap_get_max_power_uw(struct powercap_zone *pz, int cid,
 {
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 
-	*max_power_uw = spz->info->max_power_cap;
+	*max_power_uw = spz->info->cpli[cid].max_power_cap;
 	if (spz->info->powercap_scale_mw)
 		*max_power_uw *= 1000;
 
@@ -353,7 +355,7 @@ static int scmi_powercap_get_min_power_uw(struct powercap_zone *pz, int cid,
 {
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 
-	*min_power_uw = spz->info->min_power_cap;
+	*min_power_uw = spz->info->cpli[cid].min_power_cap;
 	if (spz->info->powercap_scale_mw)
 		*min_power_uw *= 1000;
 
@@ -365,7 +367,7 @@ static int scmi_powercap_get_max_time_window_us(struct powercap_zone *pz,
 {
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 
-	*time_window_us = spz->info->max_pai;
+	*time_window_us = spz->info->cpli[cid].max_avg_ivl;
 
 	return 0;
 }
@@ -375,14 +377,16 @@ static int scmi_powercap_get_min_time_window_us(struct powercap_zone *pz,
 {
 	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
 
-	*time_window_us = (u64)spz->info->min_pai;
+	*time_window_us = (u64)spz->info->cpli[cid].min_avg_ivl;
 
 	return 0;
 }
 
 static const char *scmi_powercap_get_name(struct powercap_zone *pz, int cid)
 {
-	return "SCMI power-cap";
+	struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
+
+	return spz->info->cpli[cid].name;
 }
 
 static const struct powercap_zone_constraint_ops constraint_ops  = {
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 5ab73b1ab9aa..ecd99b24ae92 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -2,7 +2,7 @@
 /*
  * SCMI Message Protocol driver header
  *
- * Copyright (C) 2018-2021 ARM Ltd.
+ * Copyright (C) 2018-2026 ARM Ltd.
  */
 
 #ifndef _LINUX_SCMI_PROTOCOL_H
@@ -613,6 +613,35 @@ struct scmi_voltage_proto_ops {
 			 s32 *volt_uV);
 };
 
+/**
+ * struct scmi_powercap_cpl_info  - Describe one CPL - Concurrent Powercap Limit
+ *
+ * @id: CPL ID as advertised by the platform.
+ * @cap_config: CAP configuration support for this CPL.
+ * @min_power_cap: Minimum configurable CAP.
+ * @max_power_cap: Maximum configurable CAP.
+ * @power_cap_step: Step size between two consecutive CAP values.
+ * @avg_ivl_config: Powercap averaging interval configuration support.
+ * @min_avg_ivl: Minimum configurable powercap averaging interval.
+ * @max_avg_ivl: Maximum configurable powercap averaging interval.
+ * @avg_ivl_step: Step size between two consecutive averaging intervals.
+ * @name: name assigned to the Powercap Domain by platform.
+ * @fc_info: Reference to the FastChannels descriptors supported by this CPL
+ */
+struct scmi_powercap_cpl_info {
+	unsigned int id;
+	bool cap_config;
+	unsigned int min_power_cap;
+	unsigned int max_power_cap;
+	unsigned int power_cap_step;
+	bool avg_ivl_config;
+	unsigned int min_avg_ivl;
+	unsigned int max_avg_ivl;
+	unsigned int avg_ivl_step;
+	char name[SCMI_SHORT_NAME_MAX_SIZE];
+	struct scmi_fc_info *fc_info;
+};
+
 /**
  * struct scmi_powercap_info  - Describe one available Powercap domain
  *
@@ -621,21 +650,15 @@ struct scmi_voltage_proto_ops {
  * @notify_powercap_measurement_change: MEASUREMENTS change notifications
  *				       support.
  * @async_powercap_cap_set: Asynchronous CAP set support.
- * @powercap_cap_config: CAP configuration support.
  * @powercap_monitoring: Monitoring (measurements) support.
- * @powercap_pai_config: PAI configuration support.
  * @powercap_scale_mw: Domain reports power data in milliwatt units.
  * @powercap_scale_uw: Domain reports power data in microwatt units.
  *		       Note that, when both @powercap_scale_mw and
  *		       @powercap_scale_uw are set to false, the domain
  *		       reports power data on an abstract linear scale.
+ * @extended_names: Support for long names.
+ * @fastchannels: Support for at least one fastchannel,
  * @name: name assigned to the Powercap Domain by platform.
- * @min_pai: Minimum configurable PAI.
- * @max_pai: Maximum configurable PAI.
- * @pai_step: Step size between two consecutive PAI values.
- * @min_power_cap: Minimum configurable CAP.
- * @max_power_cap: Maximum configurable CAP.
- * @power_cap_step: Step size between two consecutive CAP values.
  * @sustainable_power: Maximum sustainable power consumption for this domain
  *		       under normal conditions.
  * @accuracy: The accuracy with which the power is measured and reported in
@@ -643,30 +666,25 @@ struct scmi_voltage_proto_ops {
  * @parent_id: Identifier of the containing parent power capping domain, or the
  *	       value 0xFFFFFFFF if this powercap domain is a root domain not
  *	       contained in any other domain.
+ * @num_cpli: Number of discovered CPLs.
+ * @cpli: Reference to an array holding descriptors to all the discovered CPLs.
  */
 struct scmi_powercap_info {
 	unsigned int id;
 	bool notify_powercap_cap_change;
 	bool notify_powercap_measurement_change;
 	bool async_powercap_cap_set;
-	bool powercap_cap_config;
 	bool powercap_monitoring;
-	bool powercap_pai_config;
 	bool powercap_scale_mw;
 	bool powercap_scale_uw;
 	bool fastchannels;
 	char name[SCMI_MAX_STR_SIZE];
-	unsigned int min_pai;
-	unsigned int max_pai;
-	unsigned int pai_step;
-	unsigned int min_power_cap;
-	unsigned int max_power_cap;
-	unsigned int power_cap_step;
 	unsigned int sustainable_power;
 	unsigned int accuracy;
 #define SCMI_POWERCAP_ROOT_ZONE_ID     0xFFFFFFFFUL
 	unsigned int parent_id;
-	struct scmi_fc_info *fc_info;
+	unsigned int num_cpli;
+	struct scmi_powercap_cpl_info *cpli;
 };
 
 /**
@@ -695,8 +713,12 @@ struct scmi_powercap_info {
  *		    on the system: for this reason @cap_get and @cap_enable_get
  *		    will always report the final platform view of the powercaps.
  * @cap_enable_get: get the current CAP enable status for the specified domain.
- * @pai_get: get the current PAI value for the specified domain.
- * @pai_set: set the PAI value for the specified domain to the provided value.
+ * @avg_interval_get: get the current averaging interval value for the specified
+ *		      domain. This will get the PAI or CAI depending on the used
+ *		      protocol version.
+ * @avg_interval_set: set the current averaging interval value for the specified
+ *		      domain. This will set the PAI or CAI depending on the used
+ *		      protocol version.
  * @measurements_get: retrieve the current average power measurements for the
  *		      specified domain and the related PAI upon which is
  *		      calculated.
@@ -720,17 +742,17 @@ struct scmi_powercap_proto_ops {
 	const struct scmi_powercap_info __must_check *(*info_get)
 		(const struct scmi_protocol_handle *ph, u32 domain_id);
 	int (*cap_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
-		       u32 *power_cap);
+		       u32 cpl_id, u32 *power_cap);
 	int (*cap_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
-		       u32 power_cap, bool ignore_dresp);
+		       u32 cpl_id, u32 power_cap, bool ignore_dresp);
 	int (*cap_enable_set)(const struct scmi_protocol_handle *ph,
 			      u32 domain_id, bool enable);
 	int (*cap_enable_get)(const struct scmi_protocol_handle *ph,
 			      u32 domain_id, bool *enable);
-	int (*pai_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
-		       u32 *pai);
-	int (*pai_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
-		       u32 pai);
+	int (*avg_interval_get)(const struct scmi_protocol_handle *ph,
+				u32 domain_id, u32 cpl_id, u32 *val);
+	int (*avg_interval_set)(const struct scmi_protocol_handle *ph,
+				u32 domain_id, u32 cpl_id, u32 val);
 	int (*measurements_get)(const struct scmi_protocol_handle *ph,
 				u32 domain_id, u32 *average_power, u32 *pai);
 	int (*measurements_threshold_set)(const struct scmi_protocol_handle *ph,
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 04/13] firmware: arm_scmi: Add SCMIv4.0 Powercap basic support
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Add SCMIv4.0 Powercap support for enumerating multiple CPLs of a domain
when available.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
[Philip: Fixed sparse issues where int was expected]
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/powercap.c | 474 +++++++++++++++++++++------
 include/linux/scmi_protocol.h        |   1 +
 2 files changed, 379 insertions(+), 96 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 4666030176c3..8707417230f5 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -33,6 +33,7 @@ enum scmi_powercap_protocol_cmd {
 	POWERCAP_CAP_NOTIFY = 0xa,
 	POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
 	POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
+	POWERCAP_CPC_ATTRIBUTES = 0xd,
 };
 
 enum {
@@ -69,19 +70,58 @@ struct scmi_msg_resp_powercap_domain_attributes {
 	__le32 parent_id;
 };
 
+struct scmi_msg_resp_powercap_domain_attributes_v3 {
+	__le32 attributes;
+#define SUPPORTS_POWERCAP_MAI_CONFIGURATION(x)		((x) & BIT(25))
+#define SUPPORTS_POWERCAP_FASTCHANNELS(x)		((x) & BIT(22))
+#define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY_V3(x)	((x) & BIT(21))
+#define SUPPORTS_POWERCAP_CAI_CONFIGURATION(x)		((x) & BIT(20))
+	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
+	__le32 min_mai;
+	__le32 max_mai;
+	__le32 mai_step;
+	__le32 min_power_cap;
+	__le32 max_power_cap;
+	__le32 power_cap_step;
+	__le32 sustainable_power;
+	__le32 accuracy;
+	__le32 parent_id;
+	__le32 min_cai;
+	__le32 max_cai;
+	__le32 cai_step;
+};
+
+struct scmi_msg_powercap_get_v3 {
+	__le32 domain_id;
+	__le32 cpli;
+};
+
 struct scmi_msg_powercap_set_cap_or_pai {
-	__le32 domain;
+	__le32 domain_id;
 	__le32 flags;
 #define CAP_SET_ASYNC		BIT(1)
 #define CAP_SET_IGNORE_DRESP	BIT(0)
 	__le32 value;
 };
 
+struct scmi_msg_powercap_set_cap_v3 {
+	__le32 domain_id;
+	__le32 cpli;
+	__le32 flags;
+	__le32 power_cap;
+};
+
 struct scmi_msg_resp_powercap_cap_set_complete {
-	__le32 domain;
+	__le32 domain_id;
 	__le32 power_cap;
 };
 
+struct scmi_msg_resp_powercap_cap_set_complete_v3 {
+	__le32 domain_id;
+	__le32 power_cap;
+	__le32 cpli;
+};
+
 struct scmi_msg_resp_powercap_meas_get {
 	__le32 power;
 	__le32 pai;
@@ -112,6 +152,33 @@ struct scmi_powercap_meas_changed_notify_payld {
 	__le32 power;
 };
 
+struct scmi_msg_powercap_cpc {
+	__le32 domain_id;
+	__le32 desc_index;
+};
+
+struct scmi_msg_resp_powercap_cpc {
+	__le32 num_cpl;
+#define NUM_RETURNED(n)		(le32_get_bits((n), GENMASK(15, 0)))
+#define NUM_REMAINING(n)	(le32_get_bits((n), GENMASK(31, 16)))
+	struct {
+		__le32 cpli;
+		__le32 flags;
+		__le32 min_power_cap;
+		__le32 max_power_cap;
+		__le32 power_cap_step;
+		__le32 min_cai;
+		__le32 max_cai;
+		__le32 cai_step;
+		u8 name[SCMI_SHORT_NAME_MAX_SIZE];
+	} desc[];
+};
+
+struct scmi_cpls_priv {
+	u32 domain_id;
+	struct scmi_powercap_cpl_info *cpli;
+};
+
 struct scmi_powercap_state {
 	bool enabled;
 	u32 last_pcap;
@@ -129,6 +196,11 @@ struct powercap_info {
 	bool notify_measurements_cmd;
 	struct scmi_powercap_state *states;
 	struct scmi_powercap_info *powercaps;
+	int (*xfer_cap_get)(const struct scmi_protocol_handle *ph,
+			    u32 domain_id, u32 cpl_id, u32 *power_cap);
+	int (*xfer_cap_set)(const struct scmi_protocol_handle *ph,
+			    const struct scmi_powercap_info *pc,
+			    u32 cpl_id, u32 power_cap, bool ignore_dresp);
 };
 
 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
@@ -192,111 +264,244 @@ scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
 	return 0;
 }
 
+static void iter_powercap_cpls_prepare_message(void *message,
+					       unsigned int desc_index,
+					       const void *priv)
+{
+	struct scmi_msg_powercap_cpc *msg = message;
+	const struct scmi_cpls_priv *p = priv;
+
+	msg->domain_id = cpu_to_le32(p->domain_id);
+	msg->desc_index = cpu_to_le32(desc_index);
+}
+
+static int iter_powercap_cpls_update_state(struct scmi_iterator_state *st,
+					   const void *response, void *priv)
+{
+	const struct scmi_msg_resp_powercap_cpc *r = response;
+
+	st->num_returned = NUM_RETURNED(r->num_cpl);
+	st->num_remaining = NUM_REMAINING(r->num_cpl);
+
+	return 0;
+}
+
 static int
-scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
-				    struct powercap_info *pinfo,
-				    struct scmi_powercap_info *dom_info)
+iter_powercap_cpls_process_response(const struct scmi_protocol_handle *ph,
+				    const void *response,
+				    struct scmi_iterator_state *st, void *priv)
 {
+	const struct scmi_msg_resp_powercap_cpc *r = response;
+	struct scmi_cpls_priv *p = priv;
+	struct scmi_powercap_cpl_info *cpl;
+
+	cpl = &p->cpli[st->desc_index + st->loop_idx];
+
+	cpl->id = le32_to_cpu(r->desc[st->loop_idx].cpli);
+	cpl->cap_config = le32_to_cpu(r->desc[st->loop_idx].flags) & BIT(0);
+
+	cpl->min_power_cap = le32_to_cpu(r->desc[st->loop_idx].min_power_cap);
+	cpl->max_power_cap = le32_to_cpu(r->desc[st->loop_idx].max_power_cap);
+	cpl->power_cap_step = le32_to_cpu(r->desc[st->loop_idx].power_cap_step);
+	if (!cpl->power_cap_step && cpl->min_power_cap != cpl->max_power_cap)
+		return -EINVAL;
+
+	cpl->min_avg_ivl = le32_to_cpu(r->desc[st->loop_idx].min_cai);
+	cpl->max_avg_ivl = le32_to_cpu(r->desc[st->loop_idx].max_cai);
+	cpl->avg_ivl_step = le32_to_cpu(r->desc[st->loop_idx].cai_step);
+	if (!cpl->avg_ivl_step && cpl->min_avg_ivl != cpl->max_avg_ivl)
+		return -EINVAL;
+
+	cpl->avg_ivl_config = cpl->min_avg_ivl != cpl->max_avg_ivl;
+
+	strscpy(cpl->name, r->desc[st->loop_idx].name, SCMI_SHORT_NAME_MAX_SIZE);
+
+	return 0;
+}
+
+static int scmi_powercap_cpls_enumerate(const struct scmi_protocol_handle *ph,
+					struct scmi_powercap_info *dom_info)
+{
+	void *iter;
+	struct scmi_iterator_ops ops = {
+		.prepare_message = iter_powercap_cpls_prepare_message,
+		.update_state = iter_powercap_cpls_update_state,
+		.process_response = iter_powercap_cpls_process_response,
+	};
+	struct scmi_cpls_priv cpriv = {
+		.domain_id = dom_info->id,
+		.cpli = dom_info->cpli,
+	};
+
+	iter = ph->hops->iter_response_init(ph, &ops, dom_info->num_cpli,
+					    POWERCAP_CPC_ATTRIBUTES,
+					    sizeof(struct scmi_msg_powercap_cpc),
+					    &cpriv);
+	if (IS_ERR(iter))
+		return PTR_ERR(iter);
+
+	return ph->hops->iter_response_run(iter);
+}
+
+static int
+scmi_powercap_domain_attrs_process(const struct scmi_protocol_handle *ph,
+				   struct powercap_info *pinfo,
+				   struct scmi_powercap_info *dom_info, void *r)
+{
+	struct scmi_msg_resp_powercap_domain_attributes *resp = r;
+	u32 flags = le32_to_cpu(resp->attributes);
+	bool cap_config;
 	int ret;
-	u32 flags;
-	struct scmi_xfer *t;
-	struct scmi_msg_resp_powercap_domain_attributes *resp;
 
-	ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
-				      sizeof(dom_info->id), sizeof(*resp), &t);
-	if (ret)
-		return ret;
+	cap_config = SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3) {
+		dom_info->num_cpli = 1;
+	} else {
+		dom_info->num_cpli = le32_get_bits(resp->attributes,
+						   GENMASK(18, 15));
 
-	put_unaligned_le32(dom_info->id, t->tx.buf);
-	resp = t->rx.buf;
+		if (!dom_info->num_cpli)
+			dom_info->num_cpli = 1;
 
-	ret = ph->xops->do_xfer(ph, t);
-	if (!ret) {
-		flags = le32_to_cpu(resp->attributes);
+		if (cap_config && !dom_info->num_cpli)
+			return -EINVAL;
+	}
+
+	dom_info->cpli = devm_kcalloc(ph->dev, dom_info->num_cpli,
+				      sizeof(*dom_info->cpli), GFP_KERNEL);
+	if (!dom_info->cpli)
+		return -ENOMEM;
 
-		if (pinfo->notify_cap_cmd)
+	if (pinfo->notify_cap_cmd) {
+		if (PROTOCOL_REV_MAJOR(ph->version) < 0x3)
 			dom_info->notify_powercap_cap_change =
 				SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
-		if (pinfo->notify_measurements_cmd)
-			dom_info->notify_powercap_measurement_change =
-				SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
-		dom_info->async_powercap_cap_set =
-			SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
-
-		dom_info->powercap_monitoring =
-			SUPPORTS_POWERCAP_MONITORING(flags);
-		dom_info->powercap_scale_mw =
-			SUPPORTS_POWER_UNITS_MW(flags);
-		dom_info->powercap_scale_uw =
-			SUPPORTS_POWER_UNITS_UW(flags);
-		dom_info->fastchannels =
-			SUPPORTS_POWERCAP_FASTCHANNELS(flags);
-
-		strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
-
-		dom_info->sustainable_power =
-			le32_to_cpu(resp->sustainable_power);
-		dom_info->accuracy = le32_to_cpu(resp->accuracy);
-
-		dom_info->parent_id = le32_to_cpu(resp->parent_id);
-		if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
-		    (dom_info->parent_id >= pinfo->num_domains ||
-		     dom_info->parent_id == dom_info->id)) {
-			dev_err(ph->dev,
-				"Platform reported inconsistent parent ID for domain %d - %s\n",
-				dom_info->id, dom_info->name);
-			ret = -ENODEV;
-		}
+		else
+			dom_info->notify_powercap_cap_change =
+				SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY_V3(flags);
+	}
+
+	if (pinfo->notify_measurements_cmd)
+		dom_info->notify_powercap_measurement_change =
+			SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
+
+	dom_info->extended_names = SUPPORTS_EXTENDED_NAMES(flags);
+
+	dom_info->async_powercap_cap_set =
+		SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
+
+	dom_info->powercap_monitoring =
+		SUPPORTS_POWERCAP_MONITORING(flags);
+	dom_info->powercap_scale_mw =
+		SUPPORTS_POWER_UNITS_MW(flags);
+	dom_info->powercap_scale_uw =
+		SUPPORTS_POWER_UNITS_UW(flags);
+	dom_info->fastchannels =
+		SUPPORTS_POWERCAP_FASTCHANNELS(flags);
+
+	strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
+
+	dom_info->sustainable_power =
+		le32_to_cpu(resp->sustainable_power);
+	dom_info->accuracy = le32_to_cpu(resp->accuracy);
+
+	dom_info->parent_id = le32_to_cpu(resp->parent_id);
+	if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
+	    (dom_info->parent_id >= pinfo->num_domains ||
+	     dom_info->parent_id == dom_info->id)) {
+		dev_err(ph->dev,
+			"Platform reported inconsistent parent ID for domain %d - %s\n",
+			dom_info->id, dom_info->name);
+		return -ENODEV;
+	}
 
+	dom_info->cpli[0].id = CPL0;
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3)
 		dom_info->cpli[0].avg_ivl_config =
 			SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
+	else
+		dom_info->cpli[0].avg_ivl_config =
+			SUPPORTS_POWERCAP_CAI_CONFIGURATION(flags);
+
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3) {
 		dom_info->cpli[0].min_avg_ivl = le32_to_cpu(resp->min_pai);
 		dom_info->cpli[0].max_avg_ivl = le32_to_cpu(resp->max_pai);
 		dom_info->cpli[0].avg_ivl_step = le32_to_cpu(resp->pai_step);
-		ret = scmi_powercap_validate(dom_info->cpli[0].min_avg_ivl,
-					     dom_info->cpli[0].max_avg_ivl,
-					     dom_info->cpli[0].avg_ivl_step,
-					     dom_info->cpli[0].avg_ivl_config);
-		if (ret) {
-			dev_err(ph->dev,
-				"Platform reported inconsistent PAI config for domain %d - %s\n",
-				dom_info->id, dom_info->name);
-			goto clean;
-		}
+	} else {
+		struct scmi_msg_resp_powercap_domain_attributes_v3 *resp = r;
 
-		dom_info->cpli[0].cap_config =
-			SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
-		dom_info->cpli[0].min_power_cap = le32_to_cpu(resp->min_power_cap);
-		dom_info->cpli[0].max_power_cap = le32_to_cpu(resp->max_power_cap);
-		dom_info->cpli[0].power_cap_step = le32_to_cpu(resp->power_cap_step);
-		ret = scmi_powercap_validate(dom_info->cpli[0].min_power_cap,
-					     dom_info->cpli[0].max_power_cap,
-					     dom_info->cpli[0].power_cap_step,
-					     dom_info->cpli[0].cap_config);
-		if (ret) {
-			dev_err(ph->dev,
-				"Platform reported inconsistent CAP config for domain %d - %s\n",
-				dom_info->id, dom_info->name);
-			goto clean;
-		}
+		dom_info->cpli[0].min_avg_ivl = le32_to_cpu(resp->min_cai);
+		dom_info->cpli[0].max_avg_ivl = le32_to_cpu(resp->max_cai);
+		dom_info->cpli[0].avg_ivl_step = le32_to_cpu(resp->cai_step);
+	}
+
+	ret = scmi_powercap_validate(dom_info->cpli[0].min_avg_ivl,
+				     dom_info->cpli[0].max_avg_ivl,
+				     dom_info->cpli[0].avg_ivl_step,
+				     dom_info->cpli[0].avg_ivl_config);
+	if (ret) {
+		dev_err(ph->dev,
+			"Platform reported inconsistent PAI config for domain %d - %s\n",
+			dom_info->id, dom_info->name);
+		return ret;
+	}
 
-		/* Just using same short name */
-		strscpy(dom_info->cpli[0].name, dom_info->name,
-			SCMI_SHORT_NAME_MAX_SIZE);
+	dom_info->cpli[0].cap_config = cap_config;
+	dom_info->cpli[0].min_power_cap = le32_to_cpu(resp->min_power_cap);
+	dom_info->cpli[0].max_power_cap = le32_to_cpu(resp->max_power_cap);
+	dom_info->cpli[0].power_cap_step = le32_to_cpu(resp->power_cap_step);
+	ret = scmi_powercap_validate(dom_info->cpli[0].min_power_cap,
+				     dom_info->cpli[0].max_power_cap,
+				     dom_info->cpli[0].power_cap_step,
+				     dom_info->cpli[0].cap_config);
+	if (ret) {
+		dev_err(ph->dev,
+			"Platform reported inconsistent CAP config for domain %d - %s\n",
+			dom_info->id, dom_info->name);
+		return ret;
 	}
+	/* Just using same short name */
+	strscpy(dom_info->cpli[0].name, dom_info->name, SCMI_SHORT_NAME_MAX_SIZE);
+
+	return 0;
+}
+
+static int
+scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
+				    struct powercap_info *pinfo,
+				    struct scmi_powercap_info *dom_info)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_resp_powercap_domain_attributes *resp;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
+				      sizeof(dom_info->id), 0, &t);
+	if (ret)
+		return ret;
+
+	put_unaligned_le32(dom_info->id, t->tx.buf);
+	resp = t->rx.buf;
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret)
+		ret = scmi_powercap_domain_attrs_process(ph, pinfo, dom_info, resp);
 
-clean:
 	ph->xops->xfer_put(ph, t);
 
 	/*
 	 * If supported overwrite short name with the extended one;
 	 * on error just carry on and use already provided short name.
 	 */
-	if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
+	if (!ret && dom_info->extended_names)
 		ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
 					    dom_info->id, NULL, dom_info->name,
 					    SCMI_MAX_STR_SIZE);
 
+	/* When protocol version > 0x3 there can possibly be more than 1 CPLs */
+	if (!ret && dom_info->num_cpli > 1)
+		ret = scmi_powercap_cpls_enumerate(ph, dom_info);
+
 	return ret;
 }
 
@@ -306,14 +511,7 @@ scmi_powercap_domain_initialize(const struct scmi_protocol_handle *ph,
 {
 	struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
 
-	dom_info->num_cpli = 1;
-	dom_info->cpli = devm_kcalloc(ph->dev, dom_info->num_cpli,
-				      sizeof(*dom_info->cpli), GFP_KERNEL);
-	if (!dom_info->cpli)
-		return -ENOMEM;
-
 	dom_info->id = domain;
-	dom_info->cpli[0].id = CPL0;
 
 	return scmi_powercap_domain_attributes_get(ph, pinfo, dom_info);
 }
@@ -337,7 +535,7 @@ scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
 }
 
 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
-				      u32 domain_id, u32 *power_cap)
+				      u32 domain_id, u32 cpl_id, u32 *power_cap)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -348,6 +546,33 @@ static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
 		return ret;
 
 	put_unaligned_le32(domain_id, t->tx.buf);
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret)
+		*power_cap = get_unaligned_le32(t->rx.buf);
+
+	ph->xops->xfer_put(ph, t);
+
+	return ret;
+}
+
+static int scmi_powercap_xfer_cap_get_v3(const struct scmi_protocol_handle *ph,
+					 u32 domain_id, u32 cpl_id,
+					 u32 *power_cap)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_powercap_get_v3 *msg;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(*msg),
+				      sizeof(u32), &t);
+	if (ret)
+		return ret;
+
+	msg = t->tx.buf;
+	msg->domain_id = cpu_to_le32(domain_id);
+	msg->cpli = cpu_to_le32(cpl_id);
+
 	ret = ph->xops->do_xfer(ph, t);
 	if (!ret)
 		*power_cap = get_unaligned_le32(t->rx.buf);
@@ -361,6 +586,8 @@ static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 				   const struct scmi_powercap_info *dom,
 				   u32 cpl_id, u32 *power_cap)
 {
+	struct powercap_info *pi = ph->get_priv(ph);
+
 	if (dom->cpli[cpl_id].fc_info &&
 	    dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr) {
 		*power_cap = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr);
@@ -369,7 +596,7 @@ static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 		return 0;
 	}
 
-	return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
+	return pi->xfer_cap_get(ph, dom->id, cpl_id, power_cap);
 }
 
 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
@@ -402,7 +629,7 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 		return ret;
 
 	msg = t->tx.buf;
-	msg->domain = cpu_to_le32(pc->id);
+	msg->domain_id = cpu_to_le32(pc->id);
 	msg->flags =
 		cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
 			    FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
@@ -416,7 +643,7 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 			struct scmi_msg_resp_powercap_cap_set_complete *resp;
 
 			resp = t->rx.buf;
-			if (le32_to_cpu(resp->domain) == pc->id)
+			if (le32_to_cpu(resp->domain_id) == pc->id)
 				dev_dbg(ph->dev,
 					"Powercap ID %d CAP set async to %u\n",
 					pc->id,
@@ -430,6 +657,51 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
+static int scmi_powercap_xfer_cap_set_v3(const struct scmi_protocol_handle *ph,
+					 const struct scmi_powercap_info *pc,
+					 u32 cpl_id, u32 power_cap,
+					 bool ignore_dresp)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_powercap_set_cap_v3 *msg;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
+				      sizeof(*msg), 0, &t);
+	if (ret)
+		return ret;
+
+	msg = t->tx.buf;
+	msg->domain_id = cpu_to_le32(pc->id);
+	msg->cpli = cpu_to_le32(cpl_id);
+	msg->flags =
+		cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
+			    FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
+	msg->power_cap = cpu_to_le32(power_cap);
+
+	if (!pc->async_powercap_cap_set || ignore_dresp) {
+		ret = ph->xops->do_xfer(ph, t);
+	} else {
+		ret = ph->xops->do_xfer_with_response(ph, t);
+		if (!ret) {
+			struct scmi_msg_resp_powercap_cap_set_complete_v3 *resp;
+
+			resp = t->rx.buf;
+			if (le32_to_cpu(resp->domain_id) == pc->id &&
+			    le32_to_cpu(resp->cpli) == pc->cpli[cpl_id].id)
+				dev_dbg(ph->dev,
+					"Powercap ID:%d/CPLI:%d CAP set async to %u\n",
+					pc->id, cpl_id,
+					get_unaligned_le32(&resp->power_cap));
+			else
+				ret = -EPROTO;
+		}
+	}
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
 static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 				   struct powercap_info *pi, u32 domain_id,
 				   u32 cpl_id, u32 power_cap, bool ignore_dresp)
@@ -456,12 +728,12 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 				   domain_id, power_cap, 0);
 		ret = 0;
 	} else {
-		ret = scmi_powercap_xfer_cap_set(ph, pc, cpl_id, power_cap,
-						 ignore_dresp);
+		ret = pi->xfer_cap_set(ph, pc, cpl_id, power_cap, ignore_dresp);
 	}
 
-	/* Save the last explicitly set non-zero powercap value */
-	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 && !ret && power_cap)
+	/* Save the last explicitly set non-zero powercap value for CPL0 */
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 && !ret &&
+	    cpl_id == CPL0 && power_cap)
 		pi->states[domain_id].last_pcap = power_cap;
 
 	return ret;
@@ -480,8 +752,8 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 	if (!power_cap)
 		return -EINVAL;
 
-	/* Just log the last set request if acting on a disabled domain */
-	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
+	/* Just log the last set request on CPL0 if acting on a disabled domain */
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 && cpl_id == CPL0) {
 		if (!scmi_powercap_dom_info_get(ph, domain_id))
 			return -EINVAL;
 
@@ -558,7 +830,7 @@ static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
 		return ret;
 
 	msg = t->tx.buf;
-	msg->domain = cpu_to_le32(domain_id);
+	msg->domain_id = cpu_to_le32(domain_id);
 	msg->flags = cpu_to_le32(0);
 	msg->value = cpu_to_le32(pai);
 
@@ -1023,6 +1295,16 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 	if (!pinfo)
 		return -ENOMEM;
 
+	ph->set_priv(ph, pinfo);
+
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3) {
+		pinfo->xfer_cap_get = scmi_powercap_xfer_cap_get;
+		pinfo->xfer_cap_set = scmi_powercap_xfer_cap_set;
+	} else {
+		pinfo->xfer_cap_get = scmi_powercap_xfer_cap_get_v3;
+		pinfo->xfer_cap_set = scmi_powercap_xfer_cap_set_v3;
+	}
+
 	ret = scmi_powercap_attributes_get(ph, pinfo);
 	if (ret)
 		return ret;
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index ecd99b24ae92..8b539bfcf482 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -677,6 +677,7 @@ struct scmi_powercap_info {
 	bool powercap_monitoring;
 	bool powercap_scale_mw;
 	bool powercap_scale_uw;
+	bool extended_names;
 	bool fastchannels;
 	char name[SCMI_MAX_STR_SIZE];
 	unsigned int sustainable_power;
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 05/13] firmware: arm_scmi: Add SCMIv4.0 Powercap FCs support
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Add support for new SCMIv4.0 Powercap Fastchannels.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
[Philip: removed reference to old versioning logic]
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/powercap.c | 331 ++++++++++++++++++---------
 1 file changed, 229 insertions(+), 102 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 8707417230f5..cfa1dde71ff4 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -27,19 +27,25 @@ enum scmi_powercap_protocol_cmd {
 	POWERCAP_CAP_GET = 0x4,
 	POWERCAP_CAP_SET = 0x5,
 	POWERCAP_PAI_GET = 0x6,
+	POWERCAP_MAI_GET = POWERCAP_PAI_GET,
 	POWERCAP_PAI_SET = 0x7,
+	POWERCAP_MAI_SET = POWERCAP_PAI_SET,
 	POWERCAP_DOMAIN_NAME_GET = 0x8,
 	POWERCAP_MEASUREMENTS_GET = 0x9,
 	POWERCAP_CAP_NOTIFY = 0xa,
 	POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
 	POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
 	POWERCAP_CPC_ATTRIBUTES = 0xd,
+	POWERCAP_CAI_GET = 0xe,
+	POWERCAP_CAI_SET = 0xf,
 };
 
 enum {
 	POWERCAP_FC_CAP,
-	POWERCAP_FC_PAI,
-	POWERCAP_FC_MAX,
+	POWERCAP_FC_XAI,
+	POWERCAP_FC_MAI,
+	POWERCAP_FC_MEASUREMENT,
+	POWERCAP_FC_MAX
 };
 
 struct scmi_msg_resp_powercap_domain_attributes {
@@ -91,12 +97,12 @@ struct scmi_msg_resp_powercap_domain_attributes_v3 {
 	__le32 cai_step;
 };
 
-struct scmi_msg_powercap_get_v3 {
+struct scmi_msg_powercap_cap_or_cai_get_v3 {
 	__le32 domain_id;
 	__le32 cpli;
 };
 
-struct scmi_msg_powercap_set_cap_or_pai {
+struct scmi_msg_powercap_cap_or_pai_set {
 	__le32 domain_id;
 	__le32 flags;
 #define CAP_SET_ASYNC		BIT(1)
@@ -104,13 +110,20 @@ struct scmi_msg_powercap_set_cap_or_pai {
 	__le32 value;
 };
 
-struct scmi_msg_powercap_set_cap_v3 {
+struct scmi_msg_powercap_cap_set_v3 {
 	__le32 domain_id;
 	__le32 cpli;
 	__le32 flags;
 	__le32 power_cap;
 };
 
+struct scmi_msg_powercap_cai_set {
+	__le32 domain_id;
+	__le32 flags;
+	__le32 cai;
+	__le32 cpli;
+};
+
 struct scmi_msg_resp_powercap_cap_set_complete {
 	__le32 domain_id;
 	__le32 power_cap;
@@ -201,6 +214,10 @@ struct powercap_info {
 	int (*xfer_cap_set)(const struct scmi_protocol_handle *ph,
 			    const struct scmi_powercap_info *pc,
 			    u32 cpl_id, u32 power_cap, bool ignore_dresp);
+	int (*xfer_avg_ivl_get)(const struct scmi_protocol_handle *ph,
+				u32 domain_id, u32 cpl_id, u32 *ivl);
+	int (*xfer_avg_ivl_set)(const struct scmi_protocol_handle *ph,
+				u32 domain_id, u32 cpl_id, u32 ivl);
 };
 
 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
@@ -505,17 +522,6 @@ scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
-static int
-scmi_powercap_domain_initialize(const struct scmi_protocol_handle *ph,
-				struct powercap_info *pinfo, u32 domain)
-{
-	struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
-
-	dom_info->id = domain;
-
-	return scmi_powercap_domain_attributes_get(ph, pinfo, dom_info);
-}
-
 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
 {
 	struct powercap_info *pi = ph->get_priv(ph);
@@ -562,7 +568,7 @@ static int scmi_powercap_xfer_cap_get_v3(const struct scmi_protocol_handle *ph,
 {
 	int ret;
 	struct scmi_xfer *t;
-	struct scmi_msg_powercap_get_v3 *msg;
+	struct scmi_msg_powercap_cap_or_cai_get_v3 *msg;
 
 	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(*msg),
 				      sizeof(u32), &t);
@@ -621,7 +627,7 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
 {
 	int ret;
 	struct scmi_xfer *t;
-	struct scmi_msg_powercap_set_cap_or_pai *msg;
+	struct scmi_msg_powercap_cap_or_pai_set *msg;
 
 	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
 				      sizeof(*msg), 0, &t);
@@ -664,7 +670,7 @@ static int scmi_powercap_xfer_cap_set_v3(const struct scmi_protocol_handle *ph,
 {
 	int ret;
 	struct scmi_xfer *t;
-	struct scmi_msg_powercap_set_cap_v3 *msg;
+	struct scmi_msg_powercap_cap_set_v3 *msg;
 
 	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
 				      sizeof(*msg), 0, &t);
@@ -767,8 +773,9 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 				       power_cap, ignore_dresp);
 }
 
-static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
-				      u32 domain_id, u32 *pai)
+static int
+scmi_powercap_xfer_avg_interval_get(const struct scmi_protocol_handle *ph,
+				    u32 domain_id, u32 cpl_id, u32 *ivl)
 {
 	int ret;
 	struct scmi_xfer *t;
@@ -781,58 +788,105 @@ static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
 	put_unaligned_le32(domain_id, t->tx.buf);
 	ret = ph->xops->do_xfer(ph, t);
 	if (!ret)
-		*pai = get_unaligned_le32(t->rx.buf);
+		*ivl = get_unaligned_le32(t->rx.buf);
+
+	ph->xops->xfer_put(ph, t);
+
+	return ret;
+}
+
+static int
+scmi_powercap_xfer_avg_interval_get_v3(const struct scmi_protocol_handle *ph,
+				       u32 domain_id, u32 cpl_id, u32 *ivl)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_powercap_cap_or_cai_get_v3 *msg;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAI_GET, sizeof(*msg),
+				      sizeof(u32), &t);
+	if (ret)
+		return ret;
+
+	msg = t->tx.buf;
+	msg->domain_id = cpu_to_le32(domain_id);
+	msg->cpli = cpu_to_le32(cpl_id);
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret)
+		*ivl = get_unaligned_le32(t->rx.buf);
 
 	ph->xops->xfer_put(ph, t);
 
 	return ret;
 }
 
-static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 cpl_id, u32 *pai)
+static int scmi_powercap_avg_interval_get(const struct scmi_protocol_handle *ph,
+					  u32 domain_id, u32 cpl_id, u32 *val)
 {
 	struct scmi_powercap_info *dom;
 	struct powercap_info *pi = ph->get_priv(ph);
 
-	if (!pai || domain_id >= pi->num_domains)
+	if (!val || domain_id >= pi->num_domains)
 		return -EINVAL;
 
 	dom = pi->powercaps + domain_id;
 	if (cpl_id >= dom->num_cpli)
 		return -EINVAL;
 
-	if (dom->cpli[cpl_id].fc_info && dom->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].get_addr) {
-		*pai = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].get_addr);
-		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
-				   domain_id, *pai, 0);
+	if (dom->cpli[cpl_id].fc_info &&
+	    dom->cpli[cpl_id].fc_info[POWERCAP_FC_XAI].get_addr) {
+		int trace_cmd = (PROTOCOL_REV_MAJOR(ph->version) < 0x3) ?
+			POWERCAP_PAI_GET : POWERCAP_CAI_GET;
+
+		*val = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_XAI].get_addr);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id, *val, 0);
 		return 0;
 	}
 
-	return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
+	return pi->xfer_avg_ivl_get(ph, domain_id, cpl_id, val);
 }
 
-static int scmi_powercap_avg_interval_get(const struct scmi_protocol_handle *ph,
-					  u32 domain_id, u32 cpl_id, u32 *val)
+static int
+scmi_powercap_xfer_avg_interval_set(const struct scmi_protocol_handle *ph,
+				    u32 domain_id, u32 cpl_id, u32 ivl)
 {
-	return scmi_powercap_pai_get(ph, domain_id, cpl_id, val);
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_powercap_cap_or_pai_set *msg;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET, sizeof(*msg), 0, &t);
+	if (ret)
+		return ret;
+
+	msg = t->tx.buf;
+	msg->domain_id = cpu_to_le32(domain_id);
+	msg->flags = cpu_to_le32(0);
+	msg->value = cpu_to_le32(ivl);
+
+	ret = ph->xops->do_xfer(ph, t);
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
 }
 
-static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
-				      u32 domain_id, u32 pai)
+static int
+scmi_powercap_xfer_avg_interval_set_v3(const struct scmi_protocol_handle *ph,
+				       u32 domain_id, u32 cpl_id, u32 ivl)
 {
 	int ret;
 	struct scmi_xfer *t;
-	struct scmi_msg_powercap_set_cap_or_pai *msg;
+	struct scmi_msg_powercap_cai_set *msg;
 
-	ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
-				      sizeof(*msg), 0, &t);
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_CAI_SET, sizeof(*msg), 0, &t);
 	if (ret)
 		return ret;
 
 	msg = t->tx.buf;
 	msg->domain_id = cpu_to_le32(domain_id);
 	msg->flags = cpu_to_le32(0);
-	msg->value = cpu_to_le32(pai);
+	msg->cai = cpu_to_le32(ivl);
+	msg->cpli = cpu_to_le32(cpl_id);
 
 	ret = ph->xops->do_xfer(ph, t);
 
@@ -840,48 +894,42 @@ static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
 	return ret;
 }
 
-static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
-				 u32 domain_id, u32 cpl_id, u32 pai)
+static int scmi_powercap_avg_interval_set(const struct scmi_protocol_handle *ph,
+					  u32 domain_id, u32 cpl_id, u32 ivl)
 {
 	const struct scmi_powercap_info *pc;
+	struct powercap_info *pi = ph->get_priv(ph);
 
 	pc = scmi_powercap_dom_info_get(ph, domain_id);
 	if (!pc || cpl_id >= pc->num_cpli || !pc->cpli[cpl_id].avg_ivl_config ||
-	    !pai || pai < pc->cpli[cpl_id].min_avg_ivl ||
-	    pai > pc->cpli[cpl_id].max_avg_ivl)
+	    !ivl || ivl < pc->cpli[cpl_id].min_avg_ivl ||
+	    ivl > pc->cpli[cpl_id].max_avg_ivl)
 		return -EINVAL;
 
-	if (pc->cpli[cpl_id].fc_info && pc->cpli[cpl_id].fc_info[POWERCAP_FC_PAI].set_addr) {
-		struct scmi_fc_info *fci = &pc->cpli[cpl_id].fc_info[POWERCAP_FC_PAI];
+	/* Note that fc_info descriptors for any unsupported FC will be NULL */
+	if (pc->cpli[cpl_id].fc_info &&
+	    pc->cpli[cpl_id].fc_info[POWERCAP_FC_XAI].set_addr) {
+		int trace_cmd = (PROTOCOL_REV_MAJOR(ph->version) < 0x3) ?
+			POWERCAP_PAI_SET : POWERCAP_CAI_SET;
+		struct scmi_fc_info *fci = &pc->cpli[cpl_id].fc_info[POWERCAP_FC_XAI];
 
-		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
-				   domain_id, pai, 0);
-		iowrite32(pai, fci->set_addr);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id, ivl, 0);
+		iowrite32(ivl, fci->set_addr);
 		ph->hops->fastchannel_db_ring(fci->set_db);
 		return 0;
 	}
 
-	return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
-}
-
-static int scmi_powercap_avg_interval_set(const struct scmi_protocol_handle *ph,
-					  u32 domain_id, u32 cpl_id, u32 val)
-{
-	return scmi_powercap_pai_set(ph, domain_id, cpl_id, val);
+	return pi->xfer_avg_ivl_set(ph, domain_id, cpl_id, ivl);
 }
 
-static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
-					  u32 domain_id, u32 *average_power,
-					  u32 *pai)
+static int
+scmi_powercap_xfer_measurements_get(const struct scmi_protocol_handle *ph,
+				    const struct scmi_powercap_info *pc,
+				    u32 *avg_power, u32 *avg_ivl)
 {
 	int ret;
 	struct scmi_xfer *t;
 	struct scmi_msg_resp_powercap_meas_get *resp;
-	const struct scmi_powercap_info *pc;
-
-	pc = scmi_powercap_dom_info_get(ph, domain_id);
-	if (!pc || !pc->powercap_monitoring || !pai || !average_power)
-		return -EINVAL;
 
 	ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
 				      sizeof(u32), sizeof(*resp), &t);
@@ -889,17 +937,42 @@ static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
 		return ret;
 
 	resp = t->rx.buf;
-	put_unaligned_le32(domain_id, t->tx.buf);
+	put_unaligned_le32(pc->id, t->tx.buf);
 	ret = ph->xops->do_xfer(ph, t);
 	if (!ret) {
-		*average_power = le32_to_cpu(resp->power);
-		*pai = le32_to_cpu(resp->pai);
+		*avg_power = le32_to_cpu(resp->power);
+		*avg_ivl = le32_to_cpu(resp->pai);
 	}
 
 	ph->xops->xfer_put(ph, t);
 	return ret;
 }
 
+static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
+					  u32 domain_id, u32 *avg_power,
+					  u32 *avg_ivl)
+{
+	const struct scmi_powercap_info *pc;
+	struct scmi_fc_info *fci;
+
+	pc = scmi_powercap_dom_info_get(ph, domain_id);
+	if (!pc || !pc->powercap_monitoring || !avg_ivl || !avg_power)
+		return -EINVAL;
+
+	/* Note that fc_info descriptors for any unsupported FC will be NULL */
+	fci = pc->cpli[CPL0].fc_info;
+	if (fci && fci[POWERCAP_FC_MEASUREMENT].get_addr) {
+		*avg_power = ioread32(fci[POWERCAP_FC_MEASUREMENT].get_addr);
+		/* See SCMIv4.0 3.10.2 - Payload is 32bit ONLY avg_power */
+		*avg_ivl = 0;
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_MEASUREMENTS_GET,
+				   pc->id, *avg_power, *avg_ivl);
+		return 0;
+	}
+
+	return scmi_powercap_xfer_measurements_get(ph, pc, avg_power, avg_ivl);
+}
+
 static int
 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
 					 u32 domain_id, u32 *power_thresh_low,
@@ -1033,37 +1106,85 @@ static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 };
 
 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
-					 u32 domain, struct scmi_fc_info **p_fc)
+					 struct scmi_powercap_info *dom_info)
 {
-	struct scmi_fc_info *fc;
-
-	fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
-	if (!fc)
-		return;
-
-	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_CAP_SET, 4, domain, NULL,
-				   &fc[POWERCAP_FC_CAP].set_addr,
-				   &fc[POWERCAP_FC_CAP].set_db,
-				   &fc[POWERCAP_FC_CAP].rate_limit);
-
-	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_CAP_GET, 4, domain, NULL,
-				   &fc[POWERCAP_FC_CAP].get_addr, NULL,
-				   &fc[POWERCAP_FC_CAP].rate_limit);
-
-	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_PAI_SET, 4, domain, NULL,
-				   &fc[POWERCAP_FC_PAI].set_addr,
-				   &fc[POWERCAP_FC_PAI].set_db,
-				   &fc[POWERCAP_FC_PAI].rate_limit);
-
-	ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
-				   POWERCAP_PAI_GET, 4, domain, NULL,
-				   &fc[POWERCAP_FC_PAI].get_addr, NULL,
-				   &fc[POWERCAP_FC_PAI].rate_limit);
-
-	*p_fc = fc;
+	struct scmi_fc_info *fc_cpl0;
+
+	for (int id = 0; id < dom_info->num_cpli; id++) {
+		struct scmi_fc_info *fc;
+		u32 *cpl_id, zero_cpl_id = 0;
+
+		fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
+		if (!fc)
+			return;
+
+		/* NOTE THAT when num_cpli == 1 the arg *cpl_id is 0 */
+		cpl_id = (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) ? &id : NULL;
+
+		ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+					   POWERCAP_CAP_SET, 4, dom_info->id,
+					   cpl_id,
+					   &fc[POWERCAP_FC_CAP].set_addr,
+					   &fc[POWERCAP_FC_CAP].set_db,
+					   &fc[POWERCAP_FC_CAP].rate_limit);
+
+		ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+					   POWERCAP_CAP_GET, 4, dom_info->id,
+					   cpl_id,
+					   &fc[POWERCAP_FC_CAP].get_addr, NULL,
+					   &fc[POWERCAP_FC_CAP].rate_limit);
+
+		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
+			ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+						POWERCAP_CAI_SET, 4,
+						dom_info->id, cpl_id,
+						&fc[POWERCAP_FC_XAI].set_addr,
+						&fc[POWERCAP_FC_XAI].set_db,
+						&fc[POWERCAP_FC_XAI].rate_limit);
+			ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+						POWERCAP_CAI_GET, 4,
+						dom_info->id, cpl_id,
+						&fc[POWERCAP_FC_XAI].get_addr, NULL,
+						&fc[POWERCAP_FC_XAI].rate_limit);
+			ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+							POWERCAP_MAI_SET, 4,
+							dom_info->id, &zero_cpl_id,
+							&fc[POWERCAP_FC_MAI].set_addr,
+							&fc[POWERCAP_FC_MAI].set_db,
+							&fc[POWERCAP_FC_MAI].rate_limit);
+
+			ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+							POWERCAP_MAI_GET, 4,
+							dom_info->id, &zero_cpl_id,
+							&fc[POWERCAP_FC_MAI].get_addr, NULL,
+							&fc[POWERCAP_FC_MAI].rate_limit);
+
+			ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+							POWERCAP_MEASUREMENTS_GET, 4,
+							dom_info->id, &zero_cpl_id,
+							&fc[POWERCAP_FC_MEASUREMENT].get_addr, NULL,
+							&fc[POWERCAP_FC_MEASUREMENT].rate_limit);
+		}
+
+		dom_info->cpli[id].fc_info = fc;
+	}
+
+	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3) {
+		fc_cpl0 = dom_info->cpli[CPL0].fc_info;
+		ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+						POWERCAP_PAI_SET, 4,
+						dom_info->id, NULL,
+						&fc_cpl0[POWERCAP_FC_XAI].set_addr,
+						&fc_cpl0[POWERCAP_FC_XAI].set_db,
+						&fc_cpl0[POWERCAP_FC_XAI].rate_limit);
+
+		ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
+						POWERCAP_PAI_GET, 4,
+						dom_info->id, NULL,
+						&fc_cpl0[POWERCAP_FC_XAI].get_addr, NULL,
+						&fc_cpl0[POWERCAP_FC_XAI].rate_limit);
+		}
+
 }
 
 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
@@ -1300,9 +1421,14 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 	if (PROTOCOL_REV_MAJOR(ph->version) < 0x3) {
 		pinfo->xfer_cap_get = scmi_powercap_xfer_cap_get;
 		pinfo->xfer_cap_set = scmi_powercap_xfer_cap_set;
+		pinfo->xfer_avg_ivl_get = scmi_powercap_xfer_avg_interval_get;
+		pinfo->xfer_avg_ivl_set = scmi_powercap_xfer_avg_interval_set;
+
 	} else {
 		pinfo->xfer_cap_get = scmi_powercap_xfer_cap_get_v3;
 		pinfo->xfer_cap_set = scmi_powercap_xfer_cap_set_v3;
+		pinfo->xfer_avg_ivl_get = scmi_powercap_xfer_avg_interval_get_v3;
+		pinfo->xfer_avg_ivl_set = scmi_powercap_xfer_avg_interval_set_v3;
 	}
 
 	ret = scmi_powercap_attributes_get(ph, pinfo);
@@ -1327,18 +1453,19 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
 	 * formed and correlated by sane parent-child relationship (if any).
 	 */
 	for (domain = 0; domain < pinfo->num_domains; domain++) {
-		ret = scmi_powercap_domain_initialize(ph, pinfo, domain);
+		struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
+
+		dom_info->id = domain;
+		ret = scmi_powercap_domain_attributes_get(ph, pinfo, dom_info);
 		if (ret)
 			return ret;
 
-		if (pinfo->powercaps[domain].fastchannels)
-			scmi_powercap_domain_init_fc(ph, domain,
-						     &pinfo->powercaps[domain].cpli[CPL0].fc_info);
+		if (dom_info->fastchannels)
+			scmi_powercap_domain_init_fc(ph, dom_info);
 
 		/* Grab initial state when disable is supported. */
 		if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
-			ret = __scmi_powercap_cap_get(ph,
-						      &pinfo->powercaps[domain], CPL0,
+			ret = __scmi_powercap_cap_get(ph, dom_info, CPL0,
 						      &pinfo->states[domain].last_pcap);
 			if (ret)
 				return ret;
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 06/13] firmware: arm_scmi: Add SCMIV4.0 Powercap notifications support
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Extend notification support to the new SCMIv4.0 Powercap format that carry
also a CPL identifier where specified.

Since this addition completes SCMIv4.0 Powercap support bump also the
protocol version define.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/powercap.c | 13 +++++++++----
 include/linux/scmi_protocol.h        |  3 ++-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index cfa1dde71ff4..65fac7fc6169 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -18,7 +18,7 @@
 #include "notify.h"
 
 /* Updated only after ALL the mandatory features for that version are merged */
-#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x20000
+#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x30000
 
 #define CPL0	0
 
@@ -156,7 +156,8 @@ struct scmi_powercap_cap_changed_notify_payld {
 	__le32 agent_id;
 	__le32 domain_id;
 	__le32 power_cap;
-	__le32 pai;
+	__le32 avg_ivl;
+	__le32 cpli;
 };
 
 struct scmi_powercap_meas_changed_notify_payld {
@@ -1326,14 +1327,18 @@ scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
 		const struct scmi_powercap_cap_changed_notify_payld *p = payld;
 		struct scmi_powercap_cap_changed_report *r = report;
 
-		if (sizeof(*p) != payld_sz)
+		if (sizeof(*p) > payld_sz)
 			break;
 
 		r->timestamp = timestamp;
 		r->agent_id = le32_to_cpu(p->agent_id);
 		r->domain_id = le32_to_cpu(p->domain_id);
 		r->power_cap = le32_to_cpu(p->power_cap);
-		r->pai = le32_to_cpu(p->pai);
+		r->avg_ivl = le32_to_cpu(p->avg_ivl);
+		if (sizeof(*p) == payld_sz)
+			r->cpli = le32_to_cpu(p->cpli);
+		else
+			r->cpli = 0;
 		*src_id = r->domain_id;
 		rep = r;
 		break;
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 8b539bfcf482..ce00106d2b65 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -1129,7 +1129,8 @@ struct scmi_powercap_cap_changed_report {
 	unsigned int	agent_id;
 	unsigned int	domain_id;
 	unsigned int	power_cap;
-	unsigned int	pai;
+	unsigned int	avg_ivl;
+	unsigned int	cpli;
 };
 
 struct scmi_powercap_meas_changed_report {
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 07/13] firmware: arm_scmi: Extend powercap report to include MAI
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

Extend scmi_powercap_meas_changed_report to include MAI change
notifications.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/powercap.c | 28 +++++++++++++++-------------
 include/linux/scmi_protocol.h        |  1 +
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 65fac7fc6169..653b0656a9bd 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/scmi_protocol.h>
+#include <linux/stddef.h>
 
 #include <trace/events/scmi.h>
 
@@ -21,6 +22,8 @@
 #define SCMI_PROTOCOL_SUPPORTED_VERSION		0x30000
 
 #define CPL0	0
+#define SZ_V3 (sizeof(struct scmi_powercap_meas_changed_notify_payld))
+#define SZ_V2 (SZ_V3 - sizeof(__le32))
 
 enum scmi_powercap_protocol_cmd {
 	POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
@@ -164,6 +167,7 @@ struct scmi_powercap_meas_changed_notify_payld {
 	__le32 agent_id;
 	__le32 domain_id;
 	__le32 power;
+	__le32 mai;
 };
 
 struct scmi_msg_powercap_cpc {
@@ -1215,24 +1219,18 @@ static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
 		struct scmi_msg_powercap_notify_thresh *notify;
 
 		/*
-		 * Note that we have to pick the most recently configured
-		 * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
-		 * enable request and we fail, complaining, if no thresholds
-		 * were ever set, since this is an indication the API has been
-		 * used wrongly.
+		 * Build the POWERCAP_MEASUREMENTS_NOTIFY enable request using the
+		 * most recently configured thresholds.
+		 *
+		 * The absence of thresholds is not considered an error:
+		 * notifications can still be generated to report MAI changes, even
+		 * when low and high are set to zero.
 		 */
 		ret = scmi_powercap_measurements_threshold_get(ph, domain,
 							       &low, &high);
 		if (ret)
 			return ret;
 
-		if (enable && !low && !high) {
-			dev_err(ph->dev,
-				"Invalid Measurements Notify thresholds: %u/%u\n",
-				low, high);
-			return -EINVAL;
-		}
-
 		ret = ph->xops->xfer_get_init(ph, message_id,
 					      sizeof(*notify), 0, &t);
 		if (ret)
@@ -1348,13 +1346,17 @@ scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
 		const struct scmi_powercap_meas_changed_notify_payld *p = payld;
 		struct scmi_powercap_meas_changed_report *r = report;
 
-		if (sizeof(*p) != payld_sz)
+		if (payld_sz != SZ_V2 && payld_sz != SZ_V3)
 			break;
 
 		r->timestamp = timestamp;
 		r->agent_id = le32_to_cpu(p->agent_id);
 		r->domain_id = le32_to_cpu(p->domain_id);
 		r->power = le32_to_cpu(p->power);
+		r->mai = 0;
+		if (payld_sz == SZ_V3 && PROTOCOL_REV_MAJOR(ph->version) >= 0x3)
+			r->mai = le32_to_cpu(p->mai);
+
 		*src_id = r->domain_id;
 		rep = r;
 		break;
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index ce00106d2b65..583122037bf6 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -1138,5 +1138,6 @@ struct scmi_powercap_meas_changed_report {
 	unsigned int	agent_id;
 	unsigned int	domain_id;
 	unsigned int	power;
+	unsigned int	mai;
 };
 #endif /* _LINUX_SCMI_PROTOCOL_H */
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 09/13] powercap: arm_scmi: Enable multiple constraints support
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Rafael J. Wysocki, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Initialize the domains with all the discovered available constraints,
making available multiple per-domain constraints when the platform has
advertised support for multiple concurrent power limits.

CC: "Rafael J. Wysocki" <rafael@kernel.org>
CC: linux-pm@vger.kernel.org
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
[Philip: Amended Copyright]
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/powercap/arm_scmi_powercap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index 90d1fa70b1d4..2f8a1e0ecccf 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -2,7 +2,7 @@
 /*
  * SCMI Powercap support.
  *
- * Copyright (C) 2022 ARM Ltd.
+ * Copyright (C) 2022-2026 ARM Ltd.
  */
 
 #include <linux/device.h>
@@ -449,7 +449,7 @@ static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
 
 	z = powercap_register_zone(&spz->zone, scmi_top_pcntrl, spz->info->name,
 				   parent ? &parent->zone : NULL,
-				   &zone_ops, 1, &constraint_ops);
+				   &zone_ops, spz->info->num_cpli, &constraint_ops);
 	if (!IS_ERR(z)) {
 		spz->height = scmi_powercap_get_zone_height(spz);
 		spz->registered = true;
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 08/13] include: trace: Add new parameter to trace_scmi_fc_call
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Cristian Marussi,
	Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

From: Cristian Marussi <cristian.marussi@arm.com>

Since SCMIv4.0 some of the supported Fastchannels can be configured using
an additional parameter like CPL_ID or Capability_ID.

Add equivalent support in the SCMI fastchannel traces to printout also such
parameter and fix all the existent call sites.

When such parameter is not used, it will simply show up as zero.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/perf.c     |  8 ++++----
 drivers/firmware/arm_scmi/powercap.c | 12 +++++++-----
 include/trace/events/scmi.h          | 12 +++++++-----
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 7f283f457e02..88d614e3184b 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -552,7 +552,7 @@ static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
 		struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT];
 
 		trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_SET,
-				   dom->id, min_perf, max_perf);
+				   dom->id, 0, min_perf, max_perf);
 		iowrite32(max_perf, fci->set_addr);
 		iowrite32(min_perf, fci->set_addr + 4);
 		ph->hops->fastchannel_db_ring(fci->set_db);
@@ -636,7 +636,7 @@ static int __scmi_perf_limits_get(const struct scmi_protocol_handle *ph,
 		*max_perf = ioread32(fci->get_addr);
 		*min_perf = ioread32(fci->get_addr + 4);
 		trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_GET,
-				   dom->id, *min_perf, *max_perf);
+				   dom->id, 0, *min_perf, *max_perf);
 		return 0;
 	}
 
@@ -706,7 +706,7 @@ static int __scmi_perf_level_set(const struct scmi_protocol_handle *ph,
 		struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL];
 
 		trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_SET,
-				   dom->id, level, 0);
+				   dom->id, 0, level, 0);
 		iowrite32(level, fci->set_addr);
 		ph->hops->fastchannel_db_ring(fci->set_db);
 		return 0;
@@ -769,7 +769,7 @@ static int __scmi_perf_level_get(const struct scmi_protocol_handle *ph,
 	if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) {
 		*level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr);
 		trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_GET,
-				   dom->id, *level, 0);
+				   dom->id, 0, *level, 0);
 		return 0;
 	}
 
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 653b0656a9bd..32371018bf1d 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -603,7 +603,7 @@ static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
 	    dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr) {
 		*power_cap = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_CAP].get_addr);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
-				   dom->id, *power_cap, 0);
+				   dom->id, cpl_id, *power_cap, 0);
 		return 0;
 	}
 
@@ -736,7 +736,7 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
 		iowrite32(power_cap, fci->set_addr);
 		ph->hops->fastchannel_db_ring(fci->set_db);
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
-				   domain_id, power_cap, 0);
+				   domain_id, cpl_id, power_cap, 0);
 		ret = 0;
 	} else {
 		ret = pi->xfer_cap_set(ph, pc, cpl_id, power_cap, ignore_dresp);
@@ -845,7 +845,8 @@ static int scmi_powercap_avg_interval_get(const struct scmi_protocol_handle *ph,
 			POWERCAP_PAI_GET : POWERCAP_CAI_GET;
 
 		*val = ioread32(dom->cpli[cpl_id].fc_info[POWERCAP_FC_XAI].get_addr);
-		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id, *val, 0);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id,
+				   cpl_id, *val, 0);
 		return 0;
 	}
 
@@ -918,7 +919,8 @@ static int scmi_powercap_avg_interval_set(const struct scmi_protocol_handle *ph,
 			POWERCAP_PAI_SET : POWERCAP_CAI_SET;
 		struct scmi_fc_info *fci = &pc->cpli[cpl_id].fc_info[POWERCAP_FC_XAI];
 
-		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id, ivl, 0);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, trace_cmd, domain_id,
+				   cpl_id, ivl, 0);
 		iowrite32(ivl, fci->set_addr);
 		ph->hops->fastchannel_db_ring(fci->set_db);
 		return 0;
@@ -971,7 +973,7 @@ static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
 		/* See SCMIv4.0 3.10.2 - Payload is 32bit ONLY avg_power */
 		*avg_ivl = 0;
 		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_MEASUREMENTS_GET,
-				   pc->id, *avg_power, *avg_ivl);
+				   pc->id, 0, *avg_power, *avg_ivl);
 		return 0;
 	}
 
diff --git a/include/trace/events/scmi.h b/include/trace/events/scmi.h
index 703b7bb68e44..b03da7323d04 100644
--- a/include/trace/events/scmi.h
+++ b/include/trace/events/scmi.h
@@ -10,13 +10,14 @@
 #define TRACE_SCMI_MAX_TAG_LEN	6
 
 TRACE_EVENT(scmi_fc_call,
-	TP_PROTO(u8 protocol_id, u8 msg_id, u32 res_id, u32 val1, u32 val2),
-	TP_ARGS(protocol_id, msg_id, res_id, val1, val2),
+	TP_PROTO(u8 protocol_id, u8 msg_id, u32 res_id, u32 sub_id, u32 val1, u32 val2),
+	TP_ARGS(protocol_id, msg_id, res_id, sub_id, val1, val2),
 
 	TP_STRUCT__entry(
 		__field(u8, protocol_id)
 		__field(u8, msg_id)
 		__field(u32, res_id)
+		__field(u32, sub_id)
 		__field(u32, val1)
 		__field(u32, val2)
 	),
@@ -25,13 +26,14 @@ TRACE_EVENT(scmi_fc_call,
 		__entry->protocol_id = protocol_id;
 		__entry->msg_id = msg_id;
 		__entry->res_id = res_id;
+		__entry->sub_id = sub_id;
 		__entry->val1 = val1;
 		__entry->val2 = val2;
 	),
 
-	TP_printk("pt=%02X msg_id=%02X res_id:%u vals=%u:%u",
-		__entry->protocol_id, __entry->msg_id,
-		__entry->res_id, __entry->val1, __entry->val2)
+	TP_printk("pt=%02X msg_id=%02X res_id:%u sub_id:%u vals=%u:%u",
+		  __entry->protocol_id, __entry->msg_id,
+		  __entry->res_id, __entry->sub_id, __entry->val1, __entry->val2)
 );
 
 TRACE_EVENT(scmi_xfer_begin,
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 10/13] firmware: arm_scmi: add Powercap MAI get/set support
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

Add support for Power Measurement Averaging Interval (MAI) get and set
operations to the SCMI powercap protocol driver. Extends scmi_powercap_info
to store MAI configuration and implement MAI get/set via xfer and optional
fast-channel support.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/firmware/arm_scmi/powercap.c | 127 +++++++++++++++++++++++++++
 include/linux/scmi_protocol.h        |  18 ++++
 2 files changed, 145 insertions(+)

diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 32371018bf1d..0d75a754f8bb 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -407,6 +407,34 @@ scmi_powercap_domain_attrs_process(const struct scmi_protocol_handle *ph,
 		dom_info->notify_powercap_measurement_change =
 			SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
 
+	if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
+		struct scmi_msg_resp_powercap_domain_attributes_v3 *resp_v3 = r;
+
+		flags = le32_to_cpu(resp_v3->attributes);
+		if (pinfo->notify_measurements_cmd)
+			dom_info->notify_powercap_measurement_change =
+			       SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
+
+		dom_info->mai_config = SUPPORTS_POWERCAP_MAI_CONFIGURATION(flags);
+		dom_info->min_mai = le32_to_cpu(resp_v3->min_mai);
+		dom_info->max_mai = le32_to_cpu(resp_v3->max_mai);
+		dom_info->mai_step = le32_to_cpu(resp_v3->mai_step);
+
+		if (dom_info->mai_config) {
+			ret = scmi_powercap_validate(dom_info->min_mai,
+						     dom_info->max_mai,
+						     dom_info->mai_step,
+						     dom_info->mai_config);
+
+			if (ret) {
+				dev_warn(ph->dev, "Platform reported invalid MAI config for domain %d - %s\n",
+					 dom_info->id, dom_info->name);
+
+				return ret;
+			}
+		}
+	}
+
 	dom_info->extended_names = SUPPORTS_EXTENDED_NAMES(flags);
 
 	dom_info->async_powercap_cap_set =
@@ -1098,6 +1126,103 @@ static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
 	return 0;
 }
 
+static int scmi_powercap_xfer_mai_get(const struct scmi_protocol_handle *ph,
+				      u32 domain_id, u32 *mai)
+{
+	int ret;
+	struct scmi_xfer *t;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_MAI_GET, sizeof(u32),
+				      sizeof(u32), &t);
+
+	if (ret)
+		return ret;
+
+	put_unaligned_le32(domain_id, t->tx.buf);
+
+	ret = ph->xops->do_xfer(ph, t);
+	if (!ret)
+		*mai = get_unaligned_le32(t->rx.buf);
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
+static int scmi_powercap_xfer_mai_set(const struct scmi_protocol_handle *ph,
+				      u32 domain_id, u32 mai)
+{
+	int ret;
+	struct scmi_xfer *t;
+	struct scmi_msg_powercap_cap_or_pai_set *msg;
+
+	ret = ph->xops->xfer_get_init(ph, POWERCAP_MAI_SET, sizeof(*msg),
+				      0, &t);
+	if (ret)
+		return ret;
+
+	msg = t->tx.buf;
+	msg->domain_id = cpu_to_le32(domain_id);
+	msg->flags = cpu_to_le32(0);
+	msg->value = cpu_to_le32(mai);
+
+	ret = ph->xops->do_xfer(ph, t);
+
+	ph->xops->xfer_put(ph, t);
+	return ret;
+}
+
+static int
+scmi_powercap_measurements_interval_get(const struct scmi_protocol_handle *ph,
+					u32 domain_id,
+					u32 *val)
+{
+	const struct scmi_powercap_info *pc;
+	struct scmi_fc_info *fci;
+
+	if (!val)
+		return -EINVAL;
+
+	pc = scmi_powercap_dom_info_get(ph, domain_id);
+	if (!pc)
+		return -EINVAL;
+
+	fci = pc->cpli[CPL0].fc_info;
+	if (fci && fci[POWERCAP_FC_MAI].get_addr) {
+		*val = ioread32(fci[POWERCAP_FC_MAI].get_addr);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_MAI_GET,
+				   domain_id, 0, *val, 0);
+		return 0;
+	}
+
+	return scmi_powercap_xfer_mai_get(ph, domain_id, val);
+}
+
+static int
+scmi_powercap_measurements_interval_set(const struct scmi_protocol_handle *ph,
+					u32 domain_id,
+					u32 val)
+{
+	const struct scmi_powercap_info *pc;
+	struct scmi_fc_info *fci;
+
+	pc = scmi_powercap_dom_info_get(ph, domain_id);
+	if (!pc)
+		return -EINVAL;
+
+	if (!pc->mai_config || !val || val < pc->min_mai || val > pc->max_mai)
+		return -EINVAL;
+
+	fci = pc->cpli[CPL0].fc_info;
+	if (fci && fci[POWERCAP_FC_MAI].set_addr) {
+		iowrite32(val, fci[POWERCAP_FC_MAI].set_addr);
+		ph->hops->fastchannel_db_ring(fci[POWERCAP_FC_MAI].set_db);
+		trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_MAI_SET, domain_id, 0, val, 0);
+		return 0;
+	}
+
+	return scmi_powercap_xfer_mai_set(ph, domain_id, val);
+}
+
 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 	.num_domains_get = scmi_powercap_num_domains_get,
 	.info_get = scmi_powercap_dom_info_get,
@@ -1110,6 +1235,8 @@ static const struct scmi_powercap_proto_ops powercap_proto_ops = {
 	.measurements_get = scmi_powercap_measurements_get,
 	.measurements_threshold_set = scmi_powercap_measurements_threshold_set,
 	.measurements_threshold_get = scmi_powercap_measurements_threshold_get,
+	.measurements_interval_get = scmi_powercap_measurements_interval_get,
+	.measurements_interval_set = scmi_powercap_measurements_interval_set,
 };
 
 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 583122037bf6..eeb5e609e782 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -658,6 +658,12 @@ struct scmi_powercap_cpl_info {
  *		       reports power data on an abstract linear scale.
  * @extended_names: Support for long names.
  * @fastchannels: Support for at least one fastchannel,
+ * @mai_config: MAI configuration support.
+ * @min_mai: Minimum supported Power Measurement Averaging Interval in
+ *			microseconds.
+ * @max_mai: Maximum supporte Power Measurement Averaging Interval in
+			microseconds.
+ * @mai_step: Step size between supported MAI values in microseconds.
  * @name: name assigned to the Powercap Domain by platform.
  * @sustainable_power: Maximum sustainable power consumption for this domain
  *		       under normal conditions.
@@ -679,6 +685,10 @@ struct scmi_powercap_info {
 	bool powercap_scale_uw;
 	bool extended_names;
 	bool fastchannels;
+	bool mai_config;
+	u32 min_mai;
+	u32 max_mai;
+	u32 mai_step;
 	char name[SCMI_MAX_STR_SIZE];
 	unsigned int sustainable_power;
 	unsigned int accuracy;
@@ -737,6 +747,10 @@ struct scmi_powercap_info {
  * @measurements_threshold_get: get the currently configured low and high power
  *				thresholds used when registering callbacks for
  *				notification POWERCAP_MEASUREMENTS_NOTIFY.
+ * @measurements_interval_get: get the current Power Measurement Averaging
+ *				Interval (MAI) value for the specified domain.
+ * @measurements_interval_set: set the Power Measurement Averaging Interval
+ *				(MAI) value for the specified domain.
  */
 struct scmi_powercap_proto_ops {
 	int (*num_domains_get)(const struct scmi_protocol_handle *ph);
@@ -762,6 +776,10 @@ struct scmi_powercap_proto_ops {
 	int (*measurements_threshold_get)(const struct scmi_protocol_handle *ph,
 					  u32 domain_id, u32 *power_thresh_low,
 					  u32 *power_thresh_high);
+	int (*measurements_interval_get)(const struct scmi_protocol_handle *ph,
+					 u32 domain_id, u32 *val);
+	int (*measurements_interval_set)(const struct scmi_protocol_handle *ph,
+					 u32 domain_id, u32 val);
 };
 
 enum scmi_pinctrl_selector_type {
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 11/13] powercap: arm_scmi: Create synthetic parent node for multi-instance
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

An SCMI powercap instance may expose a hierarchy of domains, or even a
forest of multiple domain trees rooted at SCMI_POWERCAP_ROOT_ZONE_ID.
Those hierarchies are valid within the namespace of a single SCMI instance.

Currently, the powercap framework has no notion of SCMI instances. If root
domains from multiple SCMI instances are registered directly under the same
Linux powercap control type, the per-instance boundaries are lost and the
resulting Linux hierarchy becomes a merge of otherwise independent SCMI
topologies.

Add a synthetic top-level powercap zone per SCMI instance and register that
instance's SCMI root domains beneath it. This keeps each instance's SCMI
hierarchy grouped together.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/powercap/arm_scmi_powercap.c | 93 +++++++++++++++++++++++++---
 1 file changed, 86 insertions(+), 7 deletions(-)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index 2f8a1e0ecccf..d45e4af0cdc7 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -38,6 +38,7 @@ struct scmi_powercap_root {
 	struct scmi_powercap_zone *spzones;
 	struct list_head *registered_zones;
 	struct list_head scmi_zones;
+	struct scmi_powercap_zone instance_root;
 };
 
 static LIST_HEAD(scmi_powercap_roots);
@@ -401,18 +402,61 @@ static const struct powercap_zone_constraint_ops constraint_ops  = {
 	.get_name = scmi_powercap_get_name,
 };
 
+/*
+ * Multi-instance constraints to meet driver requrements due to the fact
+ * that full zone semantics aren't available for the synthetic zone.
+ */
+static int instance_root_release(struct powercap_zone *pz)
+{
+	return 0;
+}
+
+static int instance_root_get_power_uw(struct powercap_zone *pz, u64 *v)
+{
+	*v = 0;
+	return 0;
+}
+
+static int instance_root_set_constraint(struct powercap_zone *pz, int cid, u64 v)
+{
+	return -EOPNOTSUPP;
+}
+
+static int instance_root_get_constraint(struct powercap_zone *pz, int cid, u64 *v)
+{
+	return -EOPNOTSUPP;
+}
+
+static const struct powercap_zone_ops instance_root_ops = {
+	.get_max_power_range_uw = scmi_powercap_get_max_power_range_uw,
+	.get_power_uw = instance_root_get_power_uw,
+	.release = instance_root_release,
+};
+
+static const struct powercap_zone_constraint_ops instance_root_const_ops = {
+	.set_power_limit_uw = instance_root_set_constraint,
+	.get_power_limit_uw = instance_root_get_constraint,
+	.set_time_window_us = instance_root_set_constraint,
+	.get_time_window_us = instance_root_get_constraint,
+};
+
 static void scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr)
 {
 	int i;
 
 	/* Un-register children zones first starting from the leaves */
-	for (i = pr->num_zones - 1; i >= 0; i--) {
+	for (i = pr->num_zones; i >= 0; i--) {
 		if (!list_empty(&pr->registered_zones[i])) {
 			struct scmi_powercap_zone *spz;
 
-			list_for_each_entry(spz, &pr->registered_zones[i], node)
+			list_for_each_entry(spz, &pr->registered_zones[i], node) {
+				if (!spz->registered)
+					continue;
+
+				spz->registered = false;
 				powercap_unregister_zone(scmi_top_pcntrl,
 							 &spz->zone);
+			}
 		}
 	}
 }
@@ -451,7 +495,10 @@ static int scmi_powercap_register_zone(struct scmi_powercap_root *pr,
 				   parent ? &parent->zone : NULL,
 				   &zone_ops, spz->info->num_cpli, &constraint_ops);
 	if (!IS_ERR(z)) {
-		spz->height = scmi_powercap_get_zone_height(spz);
+		if (parent)
+			spz->height = parent->height + 1;
+		else
+			spz->height = 0;
 		spz->registered = true;
 		list_move(&spz->node, &pr->registered_zones[spz->height]);
 		dev_dbg(spz->dev, "Registered node %s - parent %s - height:%d\n",
@@ -522,6 +569,8 @@ static int scmi_zones_register(struct device *dev,
 		struct scmi_powercap_zone *parent;
 
 		parent = scmi_powercap_get_parent_zone(spz);
+		if (!parent)
+			parent = &pr->instance_root;
 		if (parent && !parent->registered) {
 			zones_stack[sp++] = spz;
 			spz = parent;
@@ -562,8 +611,11 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 	int ret, i;
 	struct scmi_powercap_root *pr;
 	struct scmi_powercap_zone *spz;
+	struct scmi_powercap_zone *ir;
 	struct scmi_protocol_handle *ph;
 	struct device *dev = &sdev->dev;
+	char *instance_name;
+	struct powercap_zone *z;
 
 	if (!sdev->handle)
 		return -ENODEV;
@@ -591,7 +643,7 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 		return -ENOMEM;
 
 	/* Allocate for worst possible scenario of maximum tree height. */
-	pr->registered_zones = devm_kcalloc(dev, pr->num_zones,
+	pr->registered_zones = devm_kcalloc(dev, pr->num_zones + 1,
 					    sizeof(*pr->registered_zones),
 					    GFP_KERNEL);
 	if (!pr->registered_zones)
@@ -599,6 +651,9 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 
 	INIT_LIST_HEAD(&pr->scmi_zones);
 
+	for (i = 0; i <= pr->num_zones; i++)
+		INIT_LIST_HEAD(&pr->registered_zones[i]);
+
 	for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) {
 		/*
 		 * Powercap domains are validate by the protocol layer, i.e.
@@ -611,7 +666,6 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 		spz->ph = ph;
 		spz->spzones = pr->spzones;
 		INIT_LIST_HEAD(&spz->node);
-		INIT_LIST_HEAD(&pr->registered_zones[i]);
 
 		list_add_tail(&spz->node, &pr->scmi_zones);
 		/*
@@ -629,19 +683,44 @@ static int scmi_powercap_probe(struct scmi_device *sdev)
 		}
 	}
 
+	ir = &pr->instance_root;
+	ir->dev = dev;
+	INIT_LIST_HEAD(&ir->node);
+	instance_name = devm_kasprintf(dev, GFP_KERNEL, "instance_%s", dev_name(dev));
+	if (!instance_name)
+		return -ENOMEM;
+
+	z = powercap_register_zone(&ir->zone, scmi_top_pcntrl,
+				   instance_name, NULL, &instance_root_ops, 0,
+				   &instance_root_const_ops);
+
+	if (IS_ERR(z)) {
+		ret = PTR_ERR(z);
+		dev_err(dev, "Failed to register sysnthetic instance root: %d\n", ret);
+		return ret;
+	}
+
+	ir->registered = true;
+	ir->height = 0;
+	list_add_tail(&ir->node, &pr->registered_zones[0]);
+
 	/*
 	 * Scan array of retrieved SCMI powercap domains and register them
 	 * recursively starting from the root domains.
 	 */
 	ret = scmi_zones_register(dev, pr);
-	if (ret)
+	if (ret) {
+		scmi_powercap_unregister_all_zones(pr);
 		return ret;
+	}
 
 	INIT_LIST_HEAD(&pr->node);
 
 	ret = scmi_powercap_read_root_children_enable_state(pr, &pr->enabled);
-	if (ret)
+	if (ret) {
+		scmi_powercap_unregister_all_zones(pr);
 		return ret;
+	}
 
 	mutex_lock(&scmi_powercap_roots_lock);
 	list_add_tail(&pr->node, &scmi_powercap_roots);
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 12/13] powercap: arm_scmi: Add get_power_uw to synthetic node
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

Exposes the current power usage from the immediate children of the
synthetic (root) powercap node. Iterates over pr->spzones and sums per-zone
power.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/powercap/arm_scmi_powercap.c | 35 ++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index d45e4af0cdc7..e1bad4b19990 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -17,6 +17,9 @@
 #define to_scmi_powercap_zone(z)		\
 	container_of(z, struct scmi_powercap_zone, zone)
 
+#define to_scmi_powercap_root(z)		\
+	container_of(z, struct scmi_powercap_root, instance_root.zone)
+
 static const struct scmi_powercap_proto_ops *powercap_ops;
 
 struct scmi_powercap_zone {
@@ -411,9 +414,37 @@ static int instance_root_release(struct powercap_zone *pz)
 	return 0;
 }
 
-static int instance_root_get_power_uw(struct powercap_zone *pz, u64 *v)
+static int instance_root_get_power_uw(struct powercap_zone *pz, u64 *power_uw)
 {
-	*v = 0;
+	struct scmi_powercap_root *pr = to_scmi_powercap_root(pz);
+	struct scmi_powercap_zone *child;
+
+	u64 p, acc = 0;
+	int i, ret;
+
+	if (!pz || !power_uw)
+		return -EINVAL;
+
+	if (!pr)
+		return -ENODEV;
+
+	for (i = 0; i < pr->num_zones; i++) {
+		child = &pr->spzones[i];
+
+		if (!child->registered || child->invalid)
+			continue;
+
+		if (child->info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID)
+			continue;
+
+		ret = scmi_powercap_get_power_uw(&child->zone, &p);
+		if (!ret)
+			acc += p;
+		else
+			dev_dbg(child->dev, "Failed to read child power: %u\n", ret);
+	}
+
+	*power_uw = acc;
 	return 0;
 }
 
-- 
2.25.1



^ permalink raw reply related

* [PATCH v8 13/13] powercap: arm_scmi: Synthetic zone enable/disable
From: Philip Radford @ 2026-07-01 12:57 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, arm-scmi, linux-pm
  Cc: sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
	etienne.carriere, peng.fan, michal.simek, quic_sibis,
	dan.carpenter, d-gole, souvik.chakravarty, Philip Radford
In-Reply-To: <20260701125747.407921-1-philip.radford@arm.com>

The synthetic instance root contols the same set of top-level SCMI domains
already handled by the control-type enable/disable helpers previously
introduced.

Add synthetic zone enabled attribute to the existing per-instance helpers
instead of duplicating the enable-state tracking and rollback logic.

Signed-off-by: Philip Radford <philip.radford@arm.com>
---
 drivers/powercap/arm_scmi_powercap.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/powercap/arm_scmi_powercap.c b/drivers/powercap/arm_scmi_powercap.c
index e1bad4b19990..23708f9934d4 100644
--- a/drivers/powercap/arm_scmi_powercap.c
+++ b/drivers/powercap/arm_scmi_powercap.c
@@ -458,10 +458,34 @@ static int instance_root_get_constraint(struct powercap_zone *pz, int cid, u64 *
 	return -EOPNOTSUPP;
 }
 
+static int instance_root_set_enable(struct powercap_zone *pz, bool mode)
+{
+	struct scmi_powercap_root *pr = to_scmi_powercap_root(pz);
+
+	return scmi_powercap_set_root_children_enable_state(pr, mode);
+}
+
+static int instance_root_get_enable(struct powercap_zone *pz, bool *mode)
+{
+	struct scmi_powercap_root *pr = to_scmi_powercap_root(pz);
+	int ret;
+
+	if (!mode)
+		return -EINVAL;
+
+	ret = scmi_powercap_read_root_children_enable_state(pr, mode);
+	if (!ret)
+		pr->enabled = *mode;
+
+	return ret;
+}
+
 static const struct powercap_zone_ops instance_root_ops = {
 	.get_max_power_range_uw = scmi_powercap_get_max_power_range_uw,
 	.get_power_uw = instance_root_get_power_uw,
 	.release = instance_root_release,
+	.set_enable = instance_root_set_enable,
+	.get_enable = instance_root_get_enable,
 };
 
 static const struct powercap_zone_constraint_ops instance_root_const_ops = {
-- 
2.25.1



^ permalink raw reply related

* Re: [PATCH rc v7 0/7] iommu/arm-smmu-v3: Fix device crash on kdump kernel
From: Mostafa Saleh @ 2026-07-01 13:05 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Pranjal Shrivastava, Nicolin Chen, will, robin.murphy, joro, kees,
	baolu.lu, kevin.tian, miko.lenczewski, linux-arm-kernel, iommu,
	linux-kernel, stable, jamien
In-Reply-To: <20260630185942.GF7481@nvidia.com>

On Tue, Jun 30, 2026 at 03:59:42PM -0300, Jason Gunthorpe wrote:
> On Tue, Jun 30, 2026 at 03:33:12PM +0000, Mostafa Saleh wrote:
> 
> > For example patch#1 verifies log2size and split and both are read
> > from HW registers. Same for the base address or other addresses as
> > the page tables, they  might be corrupted due to a buggy driver.
> > My point is that, it is really hard to assume that the previous state
> > of registers/STE/page-tables were valid or even consistent, when the
> > kernel crashed and did not transition the state gracefully.
> 
> Sure, and this mechanism is probably not very useful for debugging
> these kinds of errors in the SMMU driver. Oh well, that isn't a common
> source of kernel crashes :)

I hope not! Although memory corruption can happen due to many other
reasons :/

I am not trying to bikeshed, but I wondering if there is a more
reliable way rather than doing archaeology from a panicked kernel
SMMUv3 configuration, as I am worried that will be even harder to
debug if it goes wrong.

>  
> > Similarly for TLBs, the kernel might have panicked in the middle of an
> > unmap or free domain. (not to mention what that means for RPM where
> > a device reset with unknown TLBs)
> 
> TLB is fine. kdump works by carving out a chunk of memory for the
> future crash kernel. When the kernel boots it ignores all the memory
> used by the prior kernel. So DMA can keep running into the old kernels
> memory with no issue. It doesn't matter if the TLBs are inconsistent or
> not.

Ideally if a TLB is to be missed (because of the panic), it should not
point to kdump memory as it is carved-out. However, it is still a leap to
assume that the TLBs are in a good shape as I mentioned with RPM (or
even if the device resets transiently for some reason) it can end up
with garbage in its TLBs.

Thanks,
Mostafa

> 
> Jason


^ permalink raw reply

* [PATCH 01/42] drm/mediatek: Rename OVL format naming
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
	robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	dri-devel, linux-mediatek, devicetree, linux-kernel,
	linux-arm-kernel, justin.yeh, jason-jh.lin, kernel, Paul-pl Chen
In-Reply-To: <20260701122057.19648-1-angelogioacchino.delregno@collabora.com>

From: Paul-pl Chen <paul-pl.chen@mediatek.com>

Rename format arrays from mt8173_formats[] to mt8173_ovl_formats[]
to explicitly indicate that these format definitions are specific
to OVL (Overlay) components.

This naming improvement is necessary because MT8196 introduces new
display components (EXDMA, BLENDER, OUTPROC) that support different
format capabilities than OVL. Without clear naming, it becomes
ambiguous which formats apply to which component type.

Examples of format differences between components:
- EXDMA supports 10-bit RGB formats that some OVL variants don't
- BLENDER has different YUV handling requirements
- Component-specific format conversion capabilities vary

The explicit naming:
- Prevents confusion when debugging format-related issues
- Makes it immediately clear which component a format array belongs to
- Improves code searchability (grep for "ovl_formats")
- Follows consistent naming convention for component-specific definitions
- Prepares for adding exdma_formats[], blender_formats[] arrays

This is a preparatory patch for MT8196 component support, which
requires clear distinction between OVL formats and EXDMA/BLENDER
formats to avoid applying incorrect format configurations.

Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 36 ++++++++++++-------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index c4b5a262fa8a..87c2b5e6d6b0 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -101,7 +101,7 @@ static inline bool is_10bit_rgb(u32 fmt)
 	return false;
 }
 
-static const u32 mt8173_formats[] = {
+static const u32 mt8173_ovl_formats[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
 	DRM_FORMAT_BGRX8888,
@@ -115,7 +115,7 @@ static const u32 mt8173_formats[] = {
 	DRM_FORMAT_YUYV,
 };
 
-static const u32 mt8195_formats[] = {
+static const u32 mt8195_ovl_formats[] = {
 	DRM_FORMAT_XRGB8888,
 	DRM_FORMAT_ARGB8888,
 	DRM_FORMAT_XRGB2101010,
@@ -673,8 +673,8 @@ static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
 	.gmc_bits = 8,
 	.layer_nr = 4,
 	.fmt_rgb565_is_0 = false,
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
@@ -683,8 +683,8 @@ static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
 	.layer_nr = 4,
 	.fmt_rgb565_is_0 = true,
 	.smi_id_en = true,
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
@@ -692,8 +692,8 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
 	.gmc_bits = 8,
 	.layer_nr = 4,
 	.fmt_rgb565_is_0 = true,
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
@@ -701,8 +701,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
 	.gmc_bits = 10,
 	.layer_nr = 4,
 	.fmt_rgb565_is_0 = true,
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
@@ -710,8 +710,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
 	.gmc_bits = 10,
 	.layer_nr = 2,
 	.fmt_rgb565_is_0 = true,
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
@@ -723,8 +723,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
 	.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
 		       BIT(DRM_MODE_BLEND_COVERAGE) |
 		       BIT(DRM_MODE_BLEND_PIXEL_NONE),
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
@@ -736,8 +736,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
 	.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
 		       BIT(DRM_MODE_BLEND_COVERAGE) |
 		       BIT(DRM_MODE_BLEND_PIXEL_NONE),
-	.formats = mt8173_formats,
-	.num_formats = ARRAY_SIZE(mt8173_formats),
+	.formats = mt8173_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8173_ovl_formats),
 };
 
 static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
@@ -750,8 +750,8 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
 	.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
 		       BIT(DRM_MODE_BLEND_COVERAGE) |
 		       BIT(DRM_MODE_BLEND_PIXEL_NONE),
-	.formats = mt8195_formats,
-	.num_formats = ARRAY_SIZE(mt8195_formats),
+	.formats = mt8195_ovl_formats,
+	.num_formats = ARRAY_SIZE(mt8195_ovl_formats),
 	.supports_clrfmt_ext = true,
 };
 
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v4 1/5] dt-bindings: arm: coresight-tnoc: Add standalone qcom,coresight-agtnoc compatible
From: Konrad Dybcio @ 2026-07-01 13:09 UTC (permalink / raw)
  To: Jie Gan, Krzysztof Kozlowski
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Tingwei Zhang, Jingyi Wang, Abel Vesa,
	Suzuki K Poulose, Mike Leach, James Clark, Leo Yan,
	Yuanfang Zhang, Abel Vesa, Alexander Shishkin, linux-arm-msm,
	devicetree, linux-kernel, coresight, linux-arm-kernel
In-Reply-To: <d4669b9e-bf07-42dd-95c5-792e358c505e@oss.qualcomm.com>

On 7/1/26 2:54 PM, Jie Gan wrote:
> 
> 
> On 7/1/2026 7:02 PM, Konrad Dybcio wrote:
>> On 7/1/26 9:31 AM, Jie Gan wrote:
>>>
>>>
>>> On 7/1/2026 3:26 PM, Krzysztof Kozlowski wrote:
>>>> On 01/07/2026 09:16, Jie Gan wrote:
>>>>>
>>>>>
>>>>> On 7/1/2026 2:57 PM, Krzysztof Kozlowski wrote:
>>>>>> On Wed, Jul 01, 2026 at 09:53:41AM +0800, Jie Gan wrote:
>>>>>>> The TNOC compatible previously only allowed the two-string AMBA form
>>>>>>> "qcom,coresight-tnoc", "arm,primecell", which forces the device onto the
>>>>>>> AMBA bus.
>>>>>>>
>>>>>>> Convert the compatible to a oneOf and add a standalone
>>>>>>> "qcom,coresight-agtnoc" compatible alongside the existing AMBA form. The
>>>>>>> standalone string carries no "arm,primecell" entry, so the device is
>>>>>>> created on the platform bus instead of the AMBA bus.
>>
>> [...]
>>
>>>>> AMBA primecell identification. The purpose of the new compatible is to
>>>>> clearly distinguish this platform-specific case from the standard
>>>>> AMBA-based implementation. Or shall I re-use the existing compatible
>>>>> "qcom,coresight-tnoc" as platform standalone compatible?
>>>>>
>>>>> We already have a similar pattern for the interconnect TraceNoC device,
>>>>> which uses the platform-specific compatible string qcom,coresight-itnoc.
>>>> I do not see there a fake, duplicated compatible for the same device.
>>>> Can you elaborate how is that relevant?
>>>
>>> Will fix it by removing AMBA related description.
>>>
>>> Shall I update the clock name from apb_pclk to apb as a platform device?
>>
>> Why?
> 
> For the previous platform devices, we got comments to add the clock-name with "apb" instead of "apb_pclk".
> 
> Please check the qcom,coresight-ctcu.yaml and qcom,coresight-itnoc.yaml

Well, if you need to break the bindings already, might as well on
the grounds of choosing a saner ("clock names shouldn't include _clk")
name.. Not sure if Krzysztof will like it

Konrad


^ permalink raw reply

* [PATCH 5/6] soc: mediatek: mtk-mmsys: Rework routes to specify component ID
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
  To: chunkuang.hu
  Cc: p.zabel, maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
	matthias.bgg, angelogioacchino.delregno, andi.shyti, djakov,
	broonie, jitao.shi, ck.hu, dri-devel, linux-mediatek, devicetree,
	linux-kernel, linux-stm32, linux-arm-kernel, justin.yeh,
	jason-jh.lin, kernel
In-Reply-To: <20260701122043.19612-1-angelogioacchino.delregno@collabora.com>

In preparation for a refactoring of multimedia related MediaTek
drivers, including mmsys, mutex and mediatek-drm, rework all of
the MMSYS routes to specify a hardware component instance number
(or "SubID") alongside the hardware component type.

This also is one step of preparation towards the removal of the
catch-all mtk_ddp_comp_id enumeration and towards the migration
from a predefined-coupling static hardware component IDSubID
mapping (carrying around a very long enumeration and also some
multiple big arrays in mediatek-drm) to a more flexible map of
Component ID (Type) decoupled from Component SubID (HW Instance)
as then, anyway, techniques to handle components are always the
same on a type basis.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/soc/mediatek/mt6893-mmsys.h |  34 +++---
 drivers/soc/mediatek/mt8167-mmsys.h |  21 ++--
 drivers/soc/mediatek/mt8173-mmsys.h |  28 ++---
 drivers/soc/mediatek/mt8183-mmsys.h |  14 +--
 drivers/soc/mediatek/mt8186-mmsys.h |  22 ++--
 drivers/soc/mediatek/mt8188-mmsys.h |  78 ++++++------
 drivers/soc/mediatek/mt8192-mmsys.h |  20 +--
 drivers/soc/mediatek/mt8195-mmsys.h | 181 ++++++++++++++--------------
 drivers/soc/mediatek/mt8365-mmsys.h |  20 +--
 drivers/soc/mediatek/mtk-mmsys.h    |  20 +--
 10 files changed, 220 insertions(+), 218 deletions(-)

diff --git a/drivers/soc/mediatek/mt6893-mmsys.h b/drivers/soc/mediatek/mt6893-mmsys.h
index c8654f591a83..2fd472b2b8c1 100644
--- a/drivers/soc/mediatek/mt6893-mmsys.h
+++ b/drivers/soc/mediatek/mt6893-mmsys.h
@@ -82,55 +82,55 @@
 #define DSI1_SEL_IN_DITHER1_MOUT			1
 
 static const struct mtk_mmsys_routes mmsys_mt6893_routing_table[] = {
-	MMSYS_ROUTE(OVL_2L0, OVL0,
+	MMSYS_ROUTE(OVL_2L, 0, OVL, 0,
 		    MT6893_DISP_OVL0_2L_OVL1_OVL1_2L_BGOUT_SEL, MT6893_DISP_SEL_IN_MASK,
 		    MT6893_DISP_OVL0_2L_OVL1_OVL1_2L_BGOUT_SEL_OVL0_2L),
-	MMSYS_ROUTE(COLOR0, CCORR,
+	MMSYS_ROUTE(COLOR, 0, CCORR, 0,
 		    MT6893_DISP_COLOR0_OUT_SEL_IN, MT6893_DISP_COLOR0_OUT_SIN_MASK,
 		    MT6893_DISP_COLOR0_OUT_SEL_IN_COLOR0),
-	MMSYS_ROUTE(CCORR, AAL0,
+	MMSYS_ROUTE(CCORR, 0, AAL, 0,
 		    MT6893_DISP_AAL0_SEL_IN, MT6893_DISP_AAL0_SEL_IN_CCORR0_SOUT,
 		    MT6893_DISP_AAL0_SEL_IN_CCORR0_SOUT),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT6893_DSI0_SEL_IN, MT6893_DSI0_SEL_IN_DITHER0_MOUT,
 		    MT6893_DSI0_SEL_IN_DITHER0_MOUT),
-	MMSYS_ROUTE(DITHER1, DSI1,
+	MMSYS_ROUTE(DITHER, 1, DSI, 1,
 		    MT6893_DSI1_SEL_IN, DSI1_SEL_IN_DITHER1_MOUT,
 		    DSI1_SEL_IN_DITHER1_MOUT),
-	MMSYS_ROUTE(RDMA4, DP_INTF0,
+	MMSYS_ROUTE(RDMA, 4, DP_INTF, 0,
 		    MT6893_DISP_DP_WRAP_SEL_IN, MT6893_DISP_DP_WRAP_MASK,
 		    MT6893_DISP_DISP_RDMA4_SOUT_DP_INTF0),
-	MMSYS_ROUTE(RDMA4, DSC0,
+	MMSYS_ROUTE(RDMA, 4, DSC, 0,
 		    MT6893_DISP_RDMA4_MERGE0_SEL_IN, MT6893_DISP_RDMA4_MERGE0_SEL_IN_MASK,
 		    MT6893_DISP_RDMA4_SOUT_RDMA4_MERGE0_SEL),
-	MMSYS_ROUTE(OVL_2L1, OVL1,
+	MMSYS_ROUTE(OVL_2L, 1, OVL, 1,
 		    MT6893_DISP_OVL1_2L_BGOUT_SOUT_SEL, MT6893_DISP_OVL1_2L_BGOUT_SOUT_MASK,
 		    MT6893_DISP_OVL1_2L_BGOUT_SOUT_OVL1),
-	MMSYS_ROUTE(CCORR, AAL0,
+	MMSYS_ROUTE(CCORR, 0, AAL, 0,
 		    MT6893_DISP_CCORR0_SOUT_SEL, MT6893_DISP_CCORR0_SOUT_AAL0_SEL,
 		    MT6893_DISP_CCORR0_SOUT_AAL0_SEL),
-	MMSYS_ROUTE(RDMA4, MERGE1,
+	MMSYS_ROUTE(RDMA, 4, MERGE, 1,
 		    MT6893_DISP_RDMA4_SOUT, MT6893_DISP_RDMA4_SOUT_MASK,
 		    MT6893_DISP_RDMA4_MERGE1_SEL),
-	MMSYS_ROUTE(RDMA4, DP_INTF0,
+	MMSYS_ROUTE(RDMA, 4, DP_INTF, 0,
 		    MT6893_DISP_RDMA4_SOUT, MT6893_DISP_RDMA4_DP_WRAP_SEL,
 		    MT6893_DISP_RDMA4_DP_WRAP_SEL),
-	MMSYS_ROUTE(DSC0, DP_INTF0,
+	MMSYS_ROUTE(DSC, 0, DP_INTF, 0,
 		    MT6893_DISP_DSC_WRAP_SOUT_SEL, MT6893_DISP_DSC_WRAP_SOUT_DP_WRAP_SEL,
 		    MT6893_DISP_DSC_WRAP_SOUT_DP_WRAP_SEL),
-	MMSYS_ROUTE(OVL_2L0, OVL0,
+	MMSYS_ROUTE(OVL_2L, 0, OVL, 0,
 		    MT6893_MMSYS_OVL_CON, MT6893_DISP_OVL0_2L_OVL0_2L_OVL1_OVL1_2L_BGOUT,
 		    MT6893_DISP_OVL0_2L_OVL0_2L_OVL1_OVL1_2L_BGOUT),
-	MMSYS_ROUTE(OVL_2L1, OVL1,
+	MMSYS_ROUTE(OVL_2L, 1, OVL, 1,
 		    MT6893_MMSYS_OVL_CON, MT6893_DISP_OVL0_2L_OVL1_2L_OVL1_OVL1_2L_BGOUT,
 		    MT6893_DISP_OVL0_2L_OVL1_2L_OVL1_OVL1_2L_BGOUT),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT6893_DISP_DITHER0_MOUT_EN, MT6893_DISP_DITHER0_MOUT_MASK,
 		    MT6893_DISP_DITHER0_MOUT_EN_DSI0_SEL),
-	MMSYS_ROUTE(DITHER1, DSI1,
+	MMSYS_ROUTE(DITHER, 1, DSI, 1,
 		    MT6893_DISP_DITHER1_MOUT_EN, MT6893_DISP_DITHER1_MOUT_MASK,
 		    MT6893_DISP_DITHER1_MOUT_EN_DSI1_SEL),
-	MMSYS_ROUTE(OVL_2L2, RDMA4,
+	MMSYS_ROUTE(OVL_2L, 2, RDMA, 4,
 		    MT6893_DISP_OVL2_2L_OUT0_MOUT, MT6893_DISP_OVL2_2L_OUT0_MOUT_MASK,
 		    MT6893_DISP_OVL2_2L_OUT0_MOUT_RDMA4),
 };
diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h
index eef14083c47b..d579feee4212 100644
--- a/drivers/soc/mediatek/mt8167-mmsys.h
+++ b/drivers/soc/mediatek/mt8167-mmsys.h
@@ -10,29 +10,24 @@
 #define MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN	0x06c
 
 #define MT8167_DITHER_MOUT_EN_RDMA0			0x1
-#define MT8167_DITHER_MOUT_EN_MASK			0x7
-
 #define MT8167_RDMA0_SOUT_DSI0				0x2
-#define MT8167_RDMA0_SOUT_MASK				0x3
-
 #define MT8167_DSI0_SEL_IN_RDMA0			0x1
-#define MT8167_DSI0_SEL_IN_MASK				0x3
 
 static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = {
-	MMSYS_ROUTE(OVL0, COLOR0,
+	MMSYS_ROUTE(OVL, 0, COLOR, 0,
 		    MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0,
 		    OVL0_MOUT_EN_COLOR0),
-	MMSYS_ROUTE(DITHER0, RDMA0,
-		    MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_MASK,
+	MMSYS_ROUTE(DITHER, 0, RDMA, 0,
+		    MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_RDMA0,
 		    MT8167_DITHER_MOUT_EN_RDMA0),
-	MMSYS_ROUTE(OVL0, COLOR0,
+	MMSYS_ROUTE(OVL, 0, COLOR, 0,
 		    MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0,
 		    COLOR0_SEL_IN_OVL0),
-	MMSYS_ROUTE(RDMA0, DSI0,
-		    MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_MASK,
+	MMSYS_ROUTE(RDMA, 0, DSI, 0,
+		    MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_RDMA0,
 		    MT8167_DSI0_SEL_IN_RDMA0),
-	MMSYS_ROUTE(RDMA0, DSI0,
-		    MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_MASK,
+	MMSYS_ROUTE(RDMA, 0, DSI, 0,
+		    MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_DSI0,
 		    MT8167_RDMA0_SOUT_DSI0),
 };
 
diff --git a/drivers/soc/mediatek/mt8173-mmsys.h b/drivers/soc/mediatek/mt8173-mmsys.h
index 957876d7c166..af67879ff8b4 100644
--- a/drivers/soc/mediatek/mt8173-mmsys.h
+++ b/drivers/soc/mediatek/mt8173-mmsys.h
@@ -33,46 +33,46 @@
 #define MT8173_RDMA0_SOUT_COLOR0			BIT(0)
 
 static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = {
-	MMSYS_ROUTE(OVL0, COLOR0,
+	MMSYS_ROUTE(OVL, 0, COLOR, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, MT8173_OVL0_MOUT_EN_COLOR0,
 		    MT8173_OVL0_MOUT_EN_COLOR0),
-	MMSYS_ROUTE(OD0, RDMA0,
+	MMSYS_ROUTE(OD, 0, RDMA, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN, MT8173_OD0_MOUT_EN_RDMA0,
 		    MT8173_OD0_MOUT_EN_RDMA0),
-	MMSYS_ROUTE(UFOE, DSI0,
+	MMSYS_ROUTE(UFOE, 0, DSI, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, MT8173_UFOE_MOUT_EN_DSI0,
 		    MT8173_UFOE_MOUT_EN_DSI0),
-	MMSYS_ROUTE(COLOR0, AAL0,
+	MMSYS_ROUTE(COLOR, 0, AAL, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN, MT8173_COLOR0_SOUT_MERGE,
 		    0 /* SOUT to AAL */),
-	MMSYS_ROUTE(RDMA0, UFOE,
+	MMSYS_ROUTE(RDMA, 0, UFOE, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8173_RDMA0_SOUT_COLOR0,
 		    0 /* SOUT to UFOE */),
-	MMSYS_ROUTE(OVL0, COLOR0,
+	MMSYS_ROUTE(OVL, 0, COLOR, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, MT8173_COLOR0_SEL_IN_OVL0,
 		    MT8173_COLOR0_SEL_IN_OVL0),
-	MMSYS_ROUTE(AAL0, COLOR0,
+	MMSYS_ROUTE(AAL, 0, COLOR, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN, MT8173_AAL_SEL_IN_MERGE,
 		    0 /* SEL_IN from COLOR0 */),
-	MMSYS_ROUTE(RDMA0, UFOE,
+	MMSYS_ROUTE(RDMA, 0, UFOE, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN, MT8173_UFOE_SEL_IN_RDMA0,
 		    0 /* SEL_IN from RDMA0 */),
-	MMSYS_ROUTE(UFOE, DSI0,
+	MMSYS_ROUTE(UFOE, 0, DSI, 0,
 		    MT8173_DISP_REG_CONFIG_DSI0_SEL_IN, MT8173_DSI0_SEL_IN_UFOE,
 		    0 /* SEL_IN from UFOE */),
-	MMSYS_ROUTE(OVL1, COLOR1,
+	MMSYS_ROUTE(OVL, 1, COLOR, 1,
 		    MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, MT8173_OVL1_MOUT_EN_COLOR1,
 		    MT8173_OVL1_MOUT_EN_COLOR1),
-	MMSYS_ROUTE(GAMMA, RDMA1,
+	MMSYS_ROUTE(GAMMA, 0, RDMA, 1,
 		    MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, MT8173_GAMMA_MOUT_EN_RDMA1,
 		    MT8173_GAMMA_MOUT_EN_RDMA1),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK,
 		    RDMA1_SOUT_DPI0),
-	MMSYS_ROUTE(OVL1, COLOR1,
+	MMSYS_ROUTE(OVL, 1, COLOR, 1,
 		    MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1,
 		    COLOR1_SEL_IN_OVL1),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8173_DISP_REG_CONFIG_DPI_SEL_IN, MT8173_DPI0_SEL_IN_MASK,
 		    MT8173_DPI0_SEL_IN_RDMA1),
 };
diff --git a/drivers/soc/mediatek/mt8183-mmsys.h b/drivers/soc/mediatek/mt8183-mmsys.h
index 123384958c4b..cf221ef203d2 100644
--- a/drivers/soc/mediatek/mt8183-mmsys.h
+++ b/drivers/soc/mediatek/mt8183-mmsys.h
@@ -28,25 +28,25 @@
 #define MT8183_MMSYS_SW0_RST_B			0x140
 
 static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = {
-	MMSYS_ROUTE(OVL0, OVL_2L0,
+	MMSYS_ROUTE(OVL, 0, OVL_2L, 0,
 		    MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L,
 		    MT8183_OVL0_MOUT_EN_OVL0_2L),
-	MMSYS_ROUTE(OVL_2L0, RDMA0,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 0,
 		    MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0,
 		    MT8183_OVL0_2L_MOUT_EN_DISP_PATH0),
-	MMSYS_ROUTE(OVL_2L1, RDMA1,
+	MMSYS_ROUTE(OVL_2L, 1, RDMA, 1,
 		    MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1,
 		    MT8183_OVL1_2L_MOUT_EN_RDMA1),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0,
 		    MT8183_DITHER0_MOUT_IN_DSI0),
-	MMSYS_ROUTE(OVL_2L0, RDMA0,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 0,
 		    MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L,
 		    MT8183_DISP_PATH0_SEL_IN_OVL0_2L),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1,
 		    MT8183_DPI0_SEL_IN_RDMA1),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0,
 		    MT8183_RDMA0_SOUT_COLOR0),
 };
diff --git a/drivers/soc/mediatek/mt8186-mmsys.h b/drivers/soc/mediatek/mt8186-mmsys.h
index 354664be72bd..0c6941be6fa5 100644
--- a/drivers/soc/mediatek/mt8186-mmsys.h
+++ b/drivers/soc/mediatek/mt8186-mmsys.h
@@ -63,37 +63,37 @@
 #define MT8186_MMSYS_SW0_RST_B				0x160
 
 static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = {
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK,
 		    MT8186_OVL0_MOUT_TO_RDMA0),
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK,
 		    MT8186_RDMA0_FROM_OVL0),
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK,
 		    MT8186_OVL0_GO_BLEND),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK,
 		    MT8186_RDMA0_SOUT_TO_COLOR0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK,
 		    MT8186_DITHER0_MOUT_TO_DSI0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK,
 		    MT8186_DSI0_FROM_DITHER0),
-	MMSYS_ROUTE(OVL_2L0, RDMA1,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 1,
 		    MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK,
 		    MT8186_OVL0_2L_MOUT_TO_RDMA1),
-	MMSYS_ROUTE(OVL_2L0, RDMA1,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 1,
 		    MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK,
 		    MT8186_RDMA1_FROM_OVL0_2L),
-	MMSYS_ROUTE(OVL_2L0, RDMA1,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 1,
 		    MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK,
 		    MT8186_OVL0_2L_GO_BLEND),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK,
 		    MT8186_RDMA1_MOUT_TO_DPI0_SEL),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK,
 		    MT8186_DPI0_FROM_RDMA1),
 };
diff --git a/drivers/soc/mediatek/mt8188-mmsys.h b/drivers/soc/mediatek/mt8188-mmsys.h
index 99080afead7e..c70c4b462381 100644
--- a/drivers/soc/mediatek/mt8188-mmsys.h
+++ b/drivers/soc/mediatek/mt8188-mmsys.h
@@ -202,124 +202,124 @@ static const u8 mmsys_mt8188_vdo1_rst_tb[] = {
 };
 
 static const struct mtk_mmsys_routes mmsys_mt8188_routing_table[] = {
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0,
 		    MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0),
-	MMSYS_ROUTE(OVL0, WDMA0,
+	MMSYS_ROUTE(OVL, 0, WDMA, 0,
 		    MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0,
 		    MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0),
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8188_VDO0_DISP_RDMA_SEL, MT8188_SEL_IN_DISP_RDMA0_FROM_MASK,
 		    MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
 		    MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(DITHER0, MERGE0,
+	MMSYS_ROUTE(DITHER, 0, MERGE, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
 		    MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(DITHER0, DSC0,
+	MMSYS_ROUTE(DITHER, 0, DSC, 0,
 		    MT8188_VDO0_DSC_WARP_SEL, MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK,
 		    MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(DITHER0, DP_INTF0,
+	MMSYS_ROUTE(DITHER, 0, DP_INTF, 0,
 		    MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
 		    MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(DSC0, MERGE0,
+	MMSYS_ROUTE(DSC, 0, MERGE, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK,
 		    MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(MERGE0, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 0,
 		    MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK,
 		    MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
-	MMSYS_ROUTE(DSC0, DSI0,
+	MMSYS_ROUTE(DSC, 0, DSI, 0,
 		    MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK,
 		    MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8188_VDO0_DISP_RDMA_SEL, GENMASK(1, 0),
 		    MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0),
-	MMSYS_ROUTE(DITHER0, DSC0,
+	MMSYS_ROUTE(DITHER, 0, DSC, 0,
 		    MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8188_SOUT_DISP_DITHER0_TO_DSI0),
-	MMSYS_ROUTE(DITHER0, MERGE0,
+	MMSYS_ROUTE(DITHER, 0, MERGE, 0,
 		    MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0),
-	MMSYS_ROUTE(DITHER0, DP_INTF0,
+	MMSYS_ROUTE(DITHER, 0, DP_INTF, 0,
 		    MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0),
-	MMSYS_ROUTE(MERGE0, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
 		    MT8188_SOUT_VPP_MERGE_TO_DP_INTF0),
-	MMSYS_ROUTE(MERGE0, DPI0,
+	MMSYS_ROUTE(MERGE, 0, DPI, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
 		    MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(MERGE0, WDMA0,
+	MMSYS_ROUTE(MERGE, 0, WDMA, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
 		    MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0),
-	MMSYS_ROUTE(MERGE0, DSC0,
+	MMSYS_ROUTE(MERGE, 0, DSC, 0,
 		    MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK,
 		    MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
-	MMSYS_ROUTE(DSC0, DSI0,
+	MMSYS_ROUTE(DSC, 0, DSI, 0,
 		    MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0),
-	MMSYS_ROUTE(DSC0, MERGE0,
+	MMSYS_ROUTE(DSC, 0, MERGE, 0,
 		    MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
 };
 
 static const struct mtk_mmsys_routes mmsys_mt8188_vdo1_routing_table[] = {
-	MMSYS_ROUTE(MDP_RDMA0, MERGE1,
+	MMSYS_ROUTE(MDP_RDMA, 0, MERGE, 1,
 		    MT8188_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
 		    MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
-	MMSYS_ROUTE(MDP_RDMA1, MERGE1,
+	MMSYS_ROUTE(MDP_RDMA, 1, MERGE, 1,
 		    MT8188_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
 		    MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
-	MMSYS_ROUTE(MDP_RDMA2, MERGE2,
+	MMSYS_ROUTE(MDP_RDMA, 2, MERGE, 2,
 		    MT8188_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
 		    MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
-	MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8188_SOUT_TO_MIXER_IN1_SEL),
-	MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8188_SOUT_TO_MIXER_IN2_SEL),
-	MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8188_SOUT_TO_MIXER_IN3_SEL),
-	MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8188_SOUT_TO_MIXER_IN4_SEL),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8188_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
 		    MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
-	MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
 		    MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
 		    MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
 		    MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0,
 		    MT8188_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
 		    MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8188_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
 		    MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8188_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
 		    MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
-	MMSYS_ROUTE(MERGE5, DPI1,
+	MMSYS_ROUTE(MERGE, 5, DPI, 1,
 		    MT8188_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
 		    MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
-	MMSYS_ROUTE(MERGE5, DPI1,
+	MMSYS_ROUTE(MERGE, 5, DPI, 1,
 		    MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
 		    MT8188_MERGE4_SOUT_TO_DPI1_SEL),
-	MMSYS_ROUTE(MERGE5, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 1,
 		    MT8188_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
 		    MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
-	MMSYS_ROUTE(MERGE5, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 1,
 		    MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0),
 		    MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL),
 };
diff --git a/drivers/soc/mediatek/mt8192-mmsys.h b/drivers/soc/mediatek/mt8192-mmsys.h
index 7cafa2455fd0..37ced5152ba7 100644
--- a/drivers/soc/mediatek/mt8192-mmsys.h
+++ b/drivers/soc/mediatek/mt8192-mmsys.h
@@ -31,34 +31,34 @@
 #define MT8192_DSI0_SEL_IN_DITHER0			0x1
 
 static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = {
-	MMSYS_ROUTE(OVL_2L0, RDMA0,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 0,
 		    MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0,
 		    MT8192_OVL0_MOUT_EN_DISP_RDMA0),
-	MMSYS_ROUTE(OVL_2L2, RDMA4,
+	MMSYS_ROUTE(OVL_2L, 2, RDMA, 4,
 		    MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4,
 		    MT8192_OVL2_2L_MOUT_EN_RDMA4),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0,
 		    MT8192_DITHER0_MOUT_IN_DSI0),
-	MMSYS_ROUTE(OVL_2L0, RDMA0,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 0,
 		    MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L,
 		    MT8192_RDMA0_SEL_IN_OVL0_2L),
-	MMSYS_ROUTE(CCORR, AAL0,
+	MMSYS_ROUTE(CCORR, 0, AAL, 0,
 		    MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0,
 		    MT8192_AAL0_SEL_IN_CCORR0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0,
 		    MT8192_DSI0_SEL_IN_DITHER0),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0,
 		    MT8192_RDMA0_SOUT_COLOR0),
-	MMSYS_ROUTE(CCORR, AAL0,
+	MMSYS_ROUTE(CCORR, 0, AAL, 0,
 		    MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0,
 		    MT8192_CCORR0_SOUT_AAL0),
-	MMSYS_ROUTE(OVL0, OVL_2L0,
+	MMSYS_ROUTE(OVL, 0, OVL_2L, 0,
 		    MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG,
 		    MT8192_DISP_OVL0_GO_BG),
-	MMSYS_ROUTE(OVL_2L0, RDMA0,
+	MMSYS_ROUTE(OVL_2L, 0, RDMA, 0,
 		    MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND,
 		    MT8192_DISP_OVL0_2L_GO_BLEND),
 };
diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h
index f69929a2a4d4..3a58b9b74282 100644
--- a/drivers/soc/mediatek/mt8195-mmsys.h
+++ b/drivers/soc/mediatek/mt8195-mmsys.h
@@ -160,278 +160,279 @@
 #define MT8195_SVPP3_MDP_RSZ					BIT(5)
 
 static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = {
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0,
 		    MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0),
-	MMSYS_ROUTE(OVL0, WDMA0,
+	MMSYS_ROUTE(OVL, 0, WDMA, 0,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0,
 		    MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0),
-	MMSYS_ROUTE(OVL0, OVL1,
+	MMSYS_ROUTE(OVL, 0, OVL, 1,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1,
 		    MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1),
-	MMSYS_ROUTE(OVL1, RDMA1,
+	MMSYS_ROUTE(OVL, 1, RDMA, 1,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1,
 		    MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1),
-	MMSYS_ROUTE(OVL1, WDMA1,
+	MMSYS_ROUTE(OVL, 1, WDMA, 1,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1,
 		    MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1),
-	MMSYS_ROUTE(OVL1, OVL0,
+	MMSYS_ROUTE(OVL, 1, OVL, 0,
 		    MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0,
 		    MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0),
-	MMSYS_ROUTE(DSC0, MERGE0,
+	MMSYS_ROUTE(DSC, 0, MERGE, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
 		    MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(DITHER1, MERGE0,
+	MMSYS_ROUTE(DITHER, 1, MERGE, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
 		    MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(MERGE5, MERGE0,
+	MMSYS_ROUTE(MERGE, 5, MERGE, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK,
 		    MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0),
-	MMSYS_ROUTE(DITHER0, DSC0,
+	MMSYS_ROUTE(DITHER, 0, DSC, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(MERGE0, DSC0,
+	MMSYS_ROUTE(MERGE, 0, DSC, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE),
-	MMSYS_ROUTE(DITHER1, DSC1,
+	MMSYS_ROUTE(DITHER, 1, DSC, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(MERGE0, DSC1,
+	MMSYS_ROUTE(MERGE, 0, DSC, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE),
-	MMSYS_ROUTE(MERGE0, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
-	MMSYS_ROUTE(MERGE0, DPI0,
+	MMSYS_ROUTE(MERGE, 0, DPI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
-	MMSYS_ROUTE(MERGE0, DPI1,
+	MMSYS_ROUTE(MERGE, 0, DPI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE),
-	MMSYS_ROUTE(DSC1, DP_INTF1,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DSC1, DPI0,
+	MMSYS_ROUTE(DSC, 1, DPI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DSC1, DPI1,
+	MMSYS_ROUTE(DSC, 1, DPI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DSC0, DP_INTF1,
+	MMSYS_ROUTE(DSC, 0, DP_INTF, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(DSC0, DPI0,
+	MMSYS_ROUTE(DSC, 0, DPI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(DSC0, DPI1,
+	MMSYS_ROUTE(DSC, 0, DPI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK,
 		    MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(DSC1, DP_INTF0,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
 		    MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(MERGE0, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
 		    MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE),
-	MMSYS_ROUTE(MERGE5, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK,
 		    MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0),
-	MMSYS_ROUTE(DSC0, DSI0,
+	MMSYS_ROUTE(DSC, 0, DSI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
 		    MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK,
 		    MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0),
-	MMSYS_ROUTE(DSC1, DSI1,
+	MMSYS_ROUTE(DSC, 1, DSI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
 		    MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(MERGE0, DSI1,
+	MMSYS_ROUTE(MERGE, 0, DSI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK,
 		    MT8195_SEL_IN_DSI1_FROM_VPP_MERGE),
-	MMSYS_ROUTE(OVL1, WDMA1,
+	MMSYS_ROUTE(OVL, 1, WDMA, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
 		    MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1),
-	MMSYS_ROUTE(MERGE0, WDMA1,
+	MMSYS_ROUTE(MERGE, 0, WDMA, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK,
 		    MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE),
-	MMSYS_ROUTE(DSC1, DSI1,
+	MMSYS_ROUTE(DSC, 1, DSI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC1, DP_INTF0,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC1, DP_INTF1,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC1, DPI0,
+	MMSYS_ROUTE(DSC, 1, DPI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC1, DPI1,
+	MMSYS_ROUTE(DSC, 1, DPI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC1, MERGE0,
+	MMSYS_ROUTE(DSC, 1, MERGE, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DITHER1, DSI1,
+	MMSYS_ROUTE(DITHER, 1, DSI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(DITHER1, DP_INTF0,
+	MMSYS_ROUTE(DITHER, 1, DP_INTF, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(DITHER1, DPI0,
+	MMSYS_ROUTE(DITHER, 1, DPI, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(DITHER1, DPI1,
+	MMSYS_ROUTE(DITHER, 1, DPI, 1,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK,
 		    MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1),
-	MMSYS_ROUTE(OVL0, WDMA0,
+	MMSYS_ROUTE(OVL, 0, WDMA, 0,
 		    MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK,
 		    MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0),
-	MMSYS_ROUTE(DITHER0, DSC0,
+	MMSYS_ROUTE(DITHER, 0, DSC, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER0_TO_DSI0),
-	MMSYS_ROUTE(DITHER1, DSC1,
+	MMSYS_ROUTE(DITHER, 1, DSC, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DITHER1, MERGE0,
+	MMSYS_ROUTE(DITHER, 1, MERGE, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE),
-	MMSYS_ROUTE(DITHER1, DSI1,
+	MMSYS_ROUTE(DITHER, 1, DSI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DITHER1, DP_INTF0,
+	MMSYS_ROUTE(DITHER, 1, DP_INTF, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DITHER1, DP_INTF1,
+	MMSYS_ROUTE(DITHER, 1, DP_INTF, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DITHER1, DPI0,
+	MMSYS_ROUTE(DITHER, 1, DPI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(DITHER1, DPI1,
+	MMSYS_ROUTE(DITHER, 1, DPI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK,
 		    MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT),
-	MMSYS_ROUTE(MERGE5, MERGE0,
+	MMSYS_ROUTE(MERGE, 5, MERGE, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
 		    MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE),
-	MMSYS_ROUTE(MERGE5, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK,
 		    MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0),
-	MMSYS_ROUTE(MERGE0, DSI1,
+	MMSYS_ROUTE(MERGE, 0, DSI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_DSI1),
-	MMSYS_ROUTE(MERGE0, DP_INTF0,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_DP_INTF0),
-	MMSYS_ROUTE(MERGE0, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 0, DP_INTF, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(MERGE0, DPI0,
+	MMSYS_ROUTE(MERGE, 0, DPI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(MERGE0, DPI1,
+	MMSYS_ROUTE(MERGE, 0, DPI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(MERGE0, WDMA1,
+	MMSYS_ROUTE(MERGE, 0, WDMA, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1),
-	MMSYS_ROUTE(MERGE0, DSC0,
+	MMSYS_ROUTE(MERGE, 0, DSC, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN),
-	MMSYS_ROUTE(MERGE0, DSC1,
+	MMSYS_ROUTE(MERGE, 0, DSC, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK,
 		    MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN),
-	MMSYS_ROUTE(DSC0, DSI0,
+	MMSYS_ROUTE(DSC, 0, DSI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0),
-	MMSYS_ROUTE(DSC0, DP_INTF1,
+	MMSYS_ROUTE(DSC, 0, DP_INTF, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
-	MMSYS_ROUTE(DSC0, DPI0,
+	MMSYS_ROUTE(DSC, 0, DPI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
-	MMSYS_ROUTE(DSC0, DPI1,
+	MMSYS_ROUTE(DSC, 0, DPI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0),
-	MMSYS_ROUTE(DSC0, MERGE0,
+	MMSYS_ROUTE(DSC, 0, MERGE, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE),
-	MMSYS_ROUTE(DSC1, DSI1,
+	MMSYS_ROUTE(DSC, 1, DSI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1),
-	MMSYS_ROUTE(DSC1, DP_INTF0,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0),
-	MMSYS_ROUTE(DSC1, DP_INTF1,
+	MMSYS_ROUTE(DSC, 1, DP_INTF, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(DSC1, DPI0,
+	MMSYS_ROUTE(DSC, 1, DPI, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(DSC1, DPI1,
+	MMSYS_ROUTE(DSC, 1, DPI, 1,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0),
-	MMSYS_ROUTE(DSC1, MERGE0,
+	MMSYS_ROUTE(DSC, 1, MERGE, 0,
 		    MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK,
 		    MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE),
 };
 
 static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = {
-	MMSYS_ROUTE(MDP_RDMA0, MERGE1,
+	MMSYS_ROUTE(MDP_RDMA, 0, MERGE, 1,
 		    MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0),
 		    MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0),
-	MMSYS_ROUTE(MDP_RDMA1, MERGE1,
+	MMSYS_ROUTE(MDP_RDMA, 1, MERGE, 1,
 		    MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0),
 		    MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1),
-	MMSYS_ROUTE(MDP_RDMA2, MERGE2,
+	MMSYS_ROUTE(MDP_RDMA, 2, MERGE, 2,
 		    MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0),
 		    MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2),
-	MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_SOUT_TO_MIXER_IN1_SEL),
-	MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_SOUT_TO_MIXER_IN2_SEL),
-	MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_SOUT_TO_MIXER_IN3_SEL),
-	MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_SOUT_TO_MIXER_IN4_SEL),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8195_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0),
 		    MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL),
-	MMSYS_ROUTE(MERGE1, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0),
 		    MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE2, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0),
 		    MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE3, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0),
 		    MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT),
-	MMSYS_ROUTE(MERGE4, ETHDR_MIXER,
+	MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0,
 		    MT8195_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0),
 		    MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8195_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0),
 		    MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER),
-	MMSYS_ROUTE(ETHDR_MIXER, MERGE5,
+	MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5,
 		    MT8195_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0),
 		    MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT),
-	MMSYS_ROUTE(MERGE5, DPI1,
+	MMSYS_ROUTE(MERGE, 5, DPI, 1,
 		    MT8195_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0),
 		    MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT),
-	MMSYS_ROUTE(MERGE5, DPI1,
+	MMSYS_ROUTE(MERGE, 5, DPI, 1,
 		    MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_MERGE4_SOUT_TO_DPI1_SEL),
-	MMSYS_ROUTE(MERGE5, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 1,
 		    MT8195_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0),
 		    MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT),
-	MMSYS_ROUTE(MERGE5, DP_INTF1,
+	MMSYS_ROUTE(MERGE, 5, DP_INTF, 1,
 		    MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0),
 		    MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL),
 };
+
 #endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */
diff --git a/drivers/soc/mediatek/mt8365-mmsys.h b/drivers/soc/mediatek/mt8365-mmsys.h
index 533a3fd0923b..b438ab7ae00b 100644
--- a/drivers/soc/mediatek/mt8365-mmsys.h
+++ b/drivers/soc/mediatek/mt8365-mmsys.h
@@ -28,35 +28,35 @@
 #define MT8365_DPI0_SEL_IN_RDMA1			0x0
 
 static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = {
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_OVL0_MOUT_PATH0_SEL),
-	MMSYS_ROUTE(OVL0, RDMA0,
+	MMSYS_ROUTE(OVL, 0, RDMA, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SEL_IN_OVL0),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SOUT_COLOR0),
-	MMSYS_ROUTE(COLOR0, CCORR,
+	MMSYS_ROUTE(COLOR, 0, CCORR, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_DISP_COLOR_SEL_IN_COLOR0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_DITHER_MOUT_EN_DSI0),
-	MMSYS_ROUTE(DITHER0, DSI0,
+	MMSYS_ROUTE(DITHER, 0, DSI, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_DSI0_SEL_IN_DITHER),
-	MMSYS_ROUTE(RDMA0, COLOR0,
+	MMSYS_ROUTE(RDMA, 0, COLOR, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00,
 		    MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK,
 		    MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_DPI0_SEL_IN_RDMA1),
-	MMSYS_ROUTE(RDMA1, DPI0,
+	MMSYS_ROUTE(RDMA, 1, DPI, 0,
 		    MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL,
 		    MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA1_SOUT_DPI0),
 };
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index fe628d5f5198..b37d859b6c14 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -80,18 +80,24 @@
 
 #define MMSYS_RST_NR(bank, bit) (((bank) * 32) + (bit))
 
+/* Temporary compatibility definitions */
+#define DDP_COMPONENT_CCORR0		DDP_COMPONENT_CCORR
+#define DDP_COMPONENT_UFOE0		DDP_COMPONENT_UFOE
+#define DDP_COMPONENT_GAMMA0		DDP_COMPONENT_GAMMA
+#define DDP_COMPONENT_ETHDR_MIXER0	DDP_COMPONENT_ETHDR_MIXER
+
 /*
  * This macro adds a compile time check to make sure that the in/out
  * selection bit(s) fit in the register mask, similar to bitfield
  * macros, but this does not transform the value.
  */
-#define MMSYS_ROUTE(from, to, reg_addr, reg_mask, selection)		\
-	{ DDP_COMPONENT_##from, DDP_COMPONENT_##to, reg_addr, reg_mask,	\
-	  (__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") +	\
-	   __BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection),		\
-				   #selection " does not fit in "	\
-				   #reg_mask) +				\
-	   (selection))							\
+#define MMSYS_ROUTE(from, fsid, to, tsid, reg_addr, reg_mask, selection)	\
+	{ DDP_COMPONENT_##from##fsid, DDP_COMPONENT_##to##tsid, reg_addr, reg_mask,	\
+	  (__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") +		\
+	   __BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection),			\
+				   #selection " does not fit in "		\
+				   #reg_mask) +					\
+	   (selection))								\
 	}
 
 struct mtk_mmsys_routes {
-- 
2.54.0



^ permalink raw reply related

* [PATCH 00/15] MT8189: Add support for system and base clock controllers
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Louis-Alexis Eyraud, Irving-CH Lin

This series is a continuation by AngeloGioacchino Del Regno and I of a
previous series ([1]), that adds the clock controller support for
the Mediatek MT8189 SoC and its variants (MT8371, MT8391).  

The first major changes is the split of the series in two:
- one for all basic clock controllers including system ones (this
series)
- one for the multimedia and graphics related clock controllers (to be
send in the future)

We chose to separate the multimedia clock drivers from the base system
ones, as there is currently an unsolvable inter-dependency between the
power domains and multimedia clocks; the power domains need a
dual-stage bring-up, where only a part of the multimedia clocks are
accessible in the first power domain powerup stage, and the rest when
the second stage (SRAM enablement) is done.
The current workarounds for this issue, such as removing the is_enabled
operation from the impacted clock controllers clk_ops table or
let the multimedia power domain always on, were quickly discarded
for upstream.

The second major change is the dt-bindings patch that got heavily
reworked, not only because of the split choice. We took the opportunity
to regroup in the MT8186 clock and system clock dt-bindings the
description of several other Mediatek SoC (MT8188, MT8192 and MT8195)
and add in them the MT8189 new ones.
The rationale is to ease maintainability and have common files for
several currently supported SoC or new future ones, that have the same
kind of clock controller design.

Finally the pending remarks from peer reviews on the v6 revision of [1]
were also taken into account and new fixes and cleanups were also
added.

A more detailed changelog between [1] and this series:
- Removed multimedia and graphics related clock controllers code and
  definitions from series
- Added new dt-bindings patches to factorise existing MT8188, MT8192
  and MT8195 in MT8186 clock dt-bindings
- Heavily modified the MT8189 dt-bindings to add new compatibles 
  in MT8186 clock dt-bindings
- Created a new dt-bindings include for the MT8189 reset controller
  definitions (include/dt-bindings/reset/mediatek,mt8189-resets.h)
- Removed unnecessary `syscon` compatible fallback from MT8189 base
  clock controllers
- Added missing 'mediatek,mt8189-fhctl' compatible declaration in
  dt-bindings
- Modified Kconfig to COMMON_CLK_MT8189 be tristate (and not bool) to 
  allow all MT8189 clock controller drivers to be built as modules (it
  was partial) 
- Fix pll unregisters in clk_mt8189_apmixed_probe error case
- Reparent several clocks to correct 26M references in clk-mt8189-bus.c,
  clk-mt8189-topckgen.c and clk-mt8189-vlpckgen.c
- Removed CLK_SET_RATE_NO_REPARENT flag from mfg_sel_mfgpll
- Rename TOPCKGEN_fmipi_csi_up26m clock to fmipi_csi_up26m to remove caps usage
- Implemented reset controllers in clk-mt8189-ufs.c
- Updated all file headers to update copyrights and add all authors
- Added all co-developed-by trailers

The series is based on linux-next tree (tag: next-20260630) and has
been tested on Mediatek Genio 520-EVK (MT8371) and 720-EVK (MT8391) boards
with board hardware enablement patch series (new series revision for
those boards to be sent soon after this one).

[1]: https://lore.kernel.org/linux-mediatek/20260309120512.3624804-1-irving-ch.lin@mediatek.com/
[2]: https://lore.kernel.org/linux-mediatek/20260309120512.3624804-2-irving-ch.lin@mediatek.com/

---
Louis-Alexis Eyraud (15):
      dt-bindings: clock: mediatek: reorder MT8186 compatibles
      dt-bindings: clock: mediatek: regroup MT8188 dt-bindings into MT8186
      dt-bindings: clock: mediatek: regroup MT8192 dt-bindings into MT8186
      dt-bindings: clock: mediatek: regroup MT8195 dt-bindings into MT8186
      dt-bindings: clock: mediatek: Add MT8189 clocks
      clk: mediatek: Add MT8189 apmixedsys clock support
      clk: mediatek: Add MT8189 topckgen clock support
      clk: mediatek: Add MT8189 vlpckgen clock support
      clk: mediatek: Add MT8189 vlpcfg clock support
      clk: mediatek: Add MT8189 bus clock support
      clk: mediatek: Add MT8189 dbgao clock support
      clk: mediatek: Add MT8189 dvfsrc clock support
      clk: mediatek: Add MT8189 i2c clock support
      clk: mediatek: Add MT8189 scp clock support
      clk: mediatek: Add MT8189 ufs clock support

 .../bindings/clock/mediatek,mt8186-clock.yaml      |  171 +++-
 .../bindings/clock/mediatek,mt8186-fhctl.yaml      |    1 +
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml  |   42 +-
 .../bindings/clock/mediatek,mt8188-clock.yaml      |   93 --
 .../bindings/clock/mediatek,mt8188-sys-clock.yaml  |   58 --
 .../bindings/clock/mediatek,mt8192-clock.yaml      |  191 ----
 .../bindings/clock/mediatek,mt8192-sys-clock.yaml  |   68 --
 .../bindings/clock/mediatek,mt8195-clock.yaml      |  238 -----
 .../bindings/clock/mediatek,mt8195-sys-clock.yaml  |   76 --
 drivers/clk/mediatek/Kconfig                       |   79 ++
 drivers/clk/mediatek/Makefile                      |    8 +
 drivers/clk/mediatek/clk-mt8189-apmixedsys.c       |  196 ++++
 drivers/clk/mediatek/clk-mt8189-bus.c              |  200 ++++
 drivers/clk/mediatek/clk-mt8189-dbgao.c            |   98 ++
 drivers/clk/mediatek/clk-mt8189-dvfsrc.c           |   58 ++
 drivers/clk/mediatek/clk-mt8189-iic.c              |  122 +++
 drivers/clk/mediatek/clk-mt8189-scp.c              |   77 ++
 drivers/clk/mediatek/clk-mt8189-topckgen.c         | 1024 ++++++++++++++++++++
 drivers/clk/mediatek/clk-mt8189-ufs.c              |  133 +++
 drivers/clk/mediatek/clk-mt8189-vlpcfg.c           |  115 +++
 drivers/clk/mediatek/clk-mt8189-vlpckgen.c         |  284 ++++++
 include/dt-bindings/clock/mediatek,mt8189-clk.h    |  433 +++++++++
 include/dt-bindings/reset/mediatek,mt8189-resets.h |   17 +
 23 files changed, 3046 insertions(+), 736 deletions(-)
---
base-commit: ba7c57499e5999aeae8dd4f954eb2600589d80aa
change-id: 20260630-mt8189-clocks-system-base-70714e4ff2aa

Best regards,
-- 
Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>



^ permalink raw reply

* [PATCH 01/15] dt-bindings: clock: mediatek: reorder MT8186 compatibles
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

In order to prepare regrouping several Mediatek SoC clock controller
dt-bindings files into the MT8186 ones, reorder the MT8186 clock
controller compatibles so they are sorted alphanumerically.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 .../bindings/clock/mediatek,mt8186-clock.yaml           | 17 +++++++++--------
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml       |  4 ++--
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
index f4e58bfa504f..37e1d7487ab4 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
@@ -23,18 +23,19 @@ properties:
   compatible:
     items:
       - enum:
-          - mediatek,mt8186-imp_iic_wrap
-          - mediatek,mt8186-mfgsys
-          - mediatek,mt8186-wpesys
-          - mediatek,mt8186-imgsys1
-          - mediatek,mt8186-imgsys2
-          - mediatek,mt8186-vdecsys
-          - mediatek,mt8186-vencsys
           - mediatek,mt8186-camsys
           - mediatek,mt8186-camsys_rawa
           - mediatek,mt8186-camsys_rawb
-          - mediatek,mt8186-mdpsys
+          - mediatek,mt8186-imgsys1
+          - mediatek,mt8186-imgsys2
+          - mediatek,mt8186-imp_iic_wrap
           - mediatek,mt8186-ipesys
+          - mediatek,mt8186-mdpsys
+          - mediatek,mt8186-mfgsys
+          - mediatek,mt8186-vdecsys
+          - mediatek,mt8186-vencsys
+          - mediatek,mt8186-wpesys
+
   reg:
     maxItems: 1
 
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
index 1c446fbc5108..c857a40ca2f0 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
@@ -27,10 +27,10 @@ properties:
   compatible:
     items:
       - enum:
+          - mediatek,mt8186-apmixedsys
+          - mediatek,mt8186-infracfg_ao
           - mediatek,mt8186-mcusys
           - mediatek,mt8186-topckgen
-          - mediatek,mt8186-infracfg_ao
-          - mediatek,mt8186-apmixedsys
       - const: syscon
 
   reg:

-- 
2.54.0



^ permalink raw reply related

* [PATCH 02/15] dt-bindings: clock: mediatek: regroup MT8188 dt-bindings into MT8186
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

Regroup the MT8188 clock and system clock dt-bindings into MT8186 ones
to ease maintainability and have common files for several currently
supported SoC or new future ones, that have the same kind of clock
controller design.

Note:
The `#clock-cells` property is a required property for all compatibles
declared in MT8188 clock and system clock dt-bindings but not in MT8186
ones.
To avoid ABI breakage, conditional blocks to check this requirement
for MT8188 compatibles are added, rather than enforcing it for MT8186
compatibles.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 .../bindings/clock/mediatek,mt8186-clock.yaml      | 82 ++++++++++++++++++-
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml  | 20 ++++-
 .../bindings/clock/mediatek,mt8188-clock.yaml      | 93 ----------------------
 .../bindings/clock/mediatek,mt8188-sys-clock.yaml  | 58 --------------
 4 files changed, 100 insertions(+), 153 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
index 37e1d7487ab4..28e05b5fb23b 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/clock/mediatek,mt8186-clock.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: MediaTek Functional Clock Controller for MT8186
+title: MediaTek Functional Clock Controller for Mediatek SoCs
 
 maintainers:
   - Chun-Jie Chen <chun-jie.chen@mediatek.com>
@@ -35,6 +35,30 @@ properties:
           - mediatek,mt8186-vdecsys
           - mediatek,mt8186-vencsys
           - mediatek,mt8186-wpesys
+          - mediatek,mt8188-adsp-audio26m
+          - mediatek,mt8188-camsys
+          - mediatek,mt8188-camsys-rawa
+          - mediatek,mt8188-camsys-rawb
+          - mediatek,mt8188-camsys-yuva
+          - mediatek,mt8188-camsys-yuvb
+          - mediatek,mt8188-ccusys
+          - mediatek,mt8188-imgsys
+          - mediatek,mt8188-imgsys-wpe1
+          - mediatek,mt8188-imgsys-wpe2
+          - mediatek,mt8188-imgsys-wpe3
+          - mediatek,mt8188-imgsys1-dip-nr
+          - mediatek,mt8188-imgsys1-dip-top
+          - mediatek,mt8188-imp-iic-wrap-c
+          - mediatek,mt8188-imp-iic-wrap-en
+          - mediatek,mt8188-imp-iic-wrap-w
+          - mediatek,mt8188-ipesys
+          - mediatek,mt8188-mfgcfg
+          - mediatek,mt8188-vdecsys
+          - mediatek,mt8188-vdecsys-soc
+          - mediatek,mt8188-vencsys
+          - mediatek,mt8188-wpesys
+          - mediatek,mt8188-wpesys-vpp0
+
 
   reg:
     maxItems: 1
@@ -42,10 +66,66 @@ properties:
   '#clock-cells':
     const: 1
 
+  '#reset-cells':
+    const: 1
+
 required:
   - compatible
   - reg
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - mediatek,mt8188-adsp-audio26m
+            - mediatek,mt8188-camsys
+            - mediatek,mt8188-camsys-rawa
+            - mediatek,mt8188-camsys-rawb
+            - mediatek,mt8188-camsys-yuva
+            - mediatek,mt8188-camsys-yuvb
+            - mediatek,mt8188-ccusys
+            - mediatek,mt8188-imgsys
+            - mediatek,mt8188-imgsys-wpe1
+            - mediatek,mt8188-imgsys-wpe2
+            - mediatek,mt8188-imgsys-wpe3
+            - mediatek,mt8188-imgsys1-dip-nr
+            - mediatek,mt8188-imgsys1-dip-top
+            - mediatek,mt8188-imp-iic-wrap-c
+            - mediatek,mt8188-imp-iic-wrap-en
+            - mediatek,mt8188-imp-iic-wrap-w
+            - mediatek,mt8188-ipesys
+            - mediatek,mt8188-mfgcfg
+            - mediatek,mt8188-vdecsys
+            - mediatek,mt8188-vdecsys-soc
+            - mediatek,mt8188-vencsys
+            - mediatek,mt8188-wpesys
+            - mediatek,mt8188-wpesys-vpp0
+    then:
+      required:
+        - '#clock-cells'
+
+  - if:
+      properties:
+        compatible:
+          enum:
+            - mediatek,mt8188-camsys-rawa
+            - mediatek,mt8188-camsys-rawb
+            - mediatek,mt8188-camsys-yuva
+            - mediatek,mt8188-camsys-yuvb
+            - mediatek,mt8188-imgsys-wpe1
+            - mediatek,mt8188-imgsys-wpe2
+            - mediatek,mt8188-imgsys-wpe3
+            - mediatek,mt8188-imgsys1-dip-nr
+            - mediatek,mt8188-imgsys1-dip-top
+            - mediatek,mt8188-ipesys
+    then:
+      required:
+        - '#reset-cells'
+    else:
+      properties:
+        reset-cells: false
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
index c857a40ca2f0..edf9562ca8b9 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
@@ -4,7 +4,7 @@
 $id: http://devicetree.org/schemas/clock/mediatek,mt8186-sys-clock.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: MediaTek System Clock Controller for MT8186
+title: MediaTek System Clock Controller for  Mediatek SoCs
 
 maintainers:
   - Chun-Jie Chen <chun-jie.chen@mediatek.com>
@@ -31,6 +31,10 @@ properties:
           - mediatek,mt8186-infracfg_ao
           - mediatek,mt8186-mcusys
           - mediatek,mt8186-topckgen
+          - mediatek,mt8188-apmixedsys
+          - mediatek,mt8188-infracfg-ao
+          - mediatek,mt8188-pericfg-ao
+          - mediatek,mt8188-topckgen
       - const: syscon
 
   reg:
@@ -46,6 +50,20 @@ required:
   - compatible
   - reg
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - mediatek,mt8188-apmixedsys
+              - mediatek,mt8188-infracfg-ao
+              - mediatek,mt8188-pericfg-ao
+              - mediatek,mt8188-topckgen
+    then:
+      required:
+        - '#clock-cells'
+
 additionalProperties: false
 
 examples:
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml
deleted file mode 100644
index 5403242545ab..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml
+++ /dev/null
@@ -1,93 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8188-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek Functional Clock Controller for MT8188
-
-maintainers:
-  - Garmin Chang <garmin.chang@mediatek.com>
-
-description: |
-  The clock architecture in MediaTek like below
-  PLLs -->
-          dividers -->
-                      muxes
-                           -->
-                              clock gate
-
-  The devices provide clock gate control in different IP blocks.
-
-properties:
-  compatible:
-    enum:
-      - mediatek,mt8188-adsp-audio26m
-      - mediatek,mt8188-camsys
-      - mediatek,mt8188-camsys-rawa
-      - mediatek,mt8188-camsys-rawb
-      - mediatek,mt8188-camsys-yuva
-      - mediatek,mt8188-camsys-yuvb
-      - mediatek,mt8188-ccusys
-      - mediatek,mt8188-imgsys
-      - mediatek,mt8188-imgsys-wpe1
-      - mediatek,mt8188-imgsys-wpe2
-      - mediatek,mt8188-imgsys-wpe3
-      - mediatek,mt8188-imgsys1-dip-nr
-      - mediatek,mt8188-imgsys1-dip-top
-      - mediatek,mt8188-imp-iic-wrap-c
-      - mediatek,mt8188-imp-iic-wrap-en
-      - mediatek,mt8188-imp-iic-wrap-w
-      - mediatek,mt8188-ipesys
-      - mediatek,mt8188-mfgcfg
-      - mediatek,mt8188-vdecsys
-      - mediatek,mt8188-vdecsys-soc
-      - mediatek,mt8188-vencsys
-      - mediatek,mt8188-wpesys
-      - mediatek,mt8188-wpesys-vpp0
-
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-  '#reset-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-  - '#clock-cells'
-
-allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            enum:
-              - mediatek,mt8188-camsys-rawa
-              - mediatek,mt8188-camsys-rawb
-              - mediatek,mt8188-camsys-yuva
-              - mediatek,mt8188-camsys-yuvb
-              - mediatek,mt8188-imgsys-wpe1
-              - mediatek,mt8188-imgsys-wpe2
-              - mediatek,mt8188-imgsys-wpe3
-              - mediatek,mt8188-imgsys1-dip-nr
-              - mediatek,mt8188-imgsys1-dip-top
-              - mediatek,mt8188-ipesys
-
-    then:
-      required:
-        - '#reset-cells'
-
-additionalProperties: false
-
-examples:
-  - |
-    clock-controller@11283000 {
-        compatible = "mediatek,mt8188-imp-iic-wrap-c";
-        reg = <0x11283000 0x1000>;
-        #clock-cells = <1>;
-    };
-
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml
deleted file mode 100644
index db13d51a4903..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8188-sys-clock.yaml
+++ /dev/null
@@ -1,58 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8188-sys-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek System Clock Controller for MT8188
-
-maintainers:
-  - Garmin Chang <garmin.chang@mediatek.com>
-
-description: |
-  The clock architecture in MediaTek like below
-  PLLs -->
-          dividers -->
-                      muxes
-                           -->
-                              clock gate
-
-  The apmixedsys provides most of PLLs which generated from SoC 26m.
-  The topckgen provides dividers and muxes which provide the clock source to other IP blocks.
-  The infracfg_ao provides clock gate in peripheral and infrastructure IP blocks.
-  The mcusys provides mux control to select the clock source in AP MCU.
-  The device nodes also provide the system control capacity for configuration.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - mediatek,mt8188-apmixedsys
-          - mediatek,mt8188-infracfg-ao
-          - mediatek,mt8188-pericfg-ao
-          - mediatek,mt8188-topckgen
-      - const: syscon
-
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-  '#reset-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-  - '#clock-cells'
-
-additionalProperties: false
-
-examples:
-  - |
-    clock-controller@10000000 {
-        compatible = "mediatek,mt8188-topckgen", "syscon";
-        reg = <0x10000000 0x1000>;
-        #clock-cells = <1>;
-    };

-- 
2.54.0



^ permalink raw reply related

* [PATCH 03/15] dt-bindings: clock: mediatek: regroup MT8192 dt-bindings into MT8186
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

Regroup the MT8192 clock and system clock dt-bindings into MT8186 ones
to ease maintainability and have common files for several currently
supported SoC or new future ones, that have the same kind of clock
controller design.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 .../bindings/clock/mediatek,mt8186-clock.yaml      |  21 ++-
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml  |   4 +
 .../bindings/clock/mediatek,mt8192-clock.yaml      | 191 ---------------------
 .../bindings/clock/mediatek,mt8192-sys-clock.yaml  |  68 --------
 4 files changed, 24 insertions(+), 260 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
index 28e05b5fb23b..3b543c810f18 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
@@ -58,7 +58,26 @@ properties:
           - mediatek,mt8188-vencsys
           - mediatek,mt8188-wpesys
           - mediatek,mt8188-wpesys-vpp0
-
+          - mediatek,mt8192-camsys
+          - mediatek,mt8192-camsys_rawa
+          - mediatek,mt8192-camsys_rawb
+          - mediatek,mt8192-camsys_rawc
+          - mediatek,mt8192-imgsys
+          - mediatek,mt8192-imgsys2
+          - mediatek,mt8192-imp_iic_wrap_c
+          - mediatek,mt8192-imp_iic_wrap_e
+          - mediatek,mt8192-imp_iic_wrap_s
+          - mediatek,mt8192-imp_iic_wrap_ws
+          - mediatek,mt8192-imp_iic_wrap_w
+          - mediatek,mt8192-imp_iic_wrap_n
+          - mediatek,mt8192-ipesys
+          - mediatek,mt8192-mdpsys
+          - mediatek,mt8192-mfgcfg
+          - mediatek,mt8192-msdc_top
+          - mediatek,mt8192-scp_adsp
+          - mediatek,mt8192-vdecsys_soc
+          - mediatek,mt8192-vdecsys
+          - mediatek,mt8192-vencsys
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
index edf9562ca8b9..4500842b20de 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
@@ -35,6 +35,10 @@ properties:
           - mediatek,mt8188-infracfg-ao
           - mediatek,mt8188-pericfg-ao
           - mediatek,mt8188-topckgen
+          - mediatek,mt8192-apmixedsys
+          - mediatek,mt8192-infracfg
+          - mediatek,mt8192-pericfg
+          - mediatek,mt8192-topckgen
       - const: syscon
 
   reg:
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8192-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8192-clock.yaml
deleted file mode 100644
index b8d690e28bdc..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8192-clock.yaml
+++ /dev/null
@@ -1,191 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8192-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek Functional Clock Controller for MT8192
-
-maintainers:
-  - Chun-Jie Chen <chun-jie.chen@mediatek.com>
-
-description:
-  The Mediatek functional clock controller provides various clocks on MT8192.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - mediatek,mt8192-scp_adsp
-          - mediatek,mt8192-imp_iic_wrap_c
-          - mediatek,mt8192-imp_iic_wrap_e
-          - mediatek,mt8192-imp_iic_wrap_s
-          - mediatek,mt8192-imp_iic_wrap_ws
-          - mediatek,mt8192-imp_iic_wrap_w
-          - mediatek,mt8192-imp_iic_wrap_n
-          - mediatek,mt8192-msdc_top
-          - mediatek,mt8192-mfgcfg
-          - mediatek,mt8192-imgsys
-          - mediatek,mt8192-imgsys2
-          - mediatek,mt8192-vdecsys_soc
-          - mediatek,mt8192-vdecsys
-          - mediatek,mt8192-vencsys
-          - mediatek,mt8192-camsys
-          - mediatek,mt8192-camsys_rawa
-          - mediatek,mt8192-camsys_rawb
-          - mediatek,mt8192-camsys_rawc
-          - mediatek,mt8192-ipesys
-          - mediatek,mt8192-mdpsys
-
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-
-additionalProperties: false
-
-examples:
-  - |
-    scp_adsp: clock-controller@10720000 {
-        compatible = "mediatek,mt8192-scp_adsp";
-        reg = <0x10720000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_c: clock-controller@11007000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_c";
-        reg = <0x11007000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_e: clock-controller@11cb1000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_e";
-        reg = <0x11cb1000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_s: clock-controller@11d03000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_s";
-        reg = <0x11d03000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_ws: clock-controller@11d23000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_ws";
-        reg = <0x11d23000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_w: clock-controller@11e01000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_w";
-        reg = <0x11e01000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_n: clock-controller@11f02000 {
-        compatible = "mediatek,mt8192-imp_iic_wrap_n";
-        reg = <0x11f02000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    msdc_top: clock-controller@11f10000 {
-        compatible = "mediatek,mt8192-msdc_top";
-        reg = <0x11f10000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    mfgcfg: clock-controller@13fbf000 {
-        compatible = "mediatek,mt8192-mfgcfg";
-        reg = <0x13fbf000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys: clock-controller@15020000 {
-        compatible = "mediatek,mt8192-imgsys";
-        reg = <0x15020000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys2: clock-controller@15820000 {
-        compatible = "mediatek,mt8192-imgsys2";
-        reg = <0x15820000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vdecsys_soc: clock-controller@1600f000 {
-        compatible = "mediatek,mt8192-vdecsys_soc";
-        reg = <0x1600f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vdecsys: clock-controller@1602f000 {
-        compatible = "mediatek,mt8192-vdecsys";
-        reg = <0x1602f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vencsys: clock-controller@17000000 {
-        compatible = "mediatek,mt8192-vencsys";
-        reg = <0x17000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys: clock-controller@1a000000 {
-        compatible = "mediatek,mt8192-camsys";
-        reg = <0x1a000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_rawa: clock-controller@1a04f000 {
-        compatible = "mediatek,mt8192-camsys_rawa";
-        reg = <0x1a04f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_rawb: clock-controller@1a06f000 {
-        compatible = "mediatek,mt8192-camsys_rawb";
-        reg = <0x1a06f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_rawc: clock-controller@1a08f000 {
-        compatible = "mediatek,mt8192-camsys_rawc";
-        reg = <0x1a08f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    ipesys: clock-controller@1b000000 {
-        compatible = "mediatek,mt8192-ipesys";
-        reg = <0x1b000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    mdpsys: clock-controller@1f000000 {
-        compatible = "mediatek,mt8192-mdpsys";
-        reg = <0x1f000000 0x1000>;
-        #clock-cells = <1>;
-    };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8192-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8192-sys-clock.yaml
deleted file mode 100644
index bf8c9aacdf1e..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8192-sys-clock.yaml
+++ /dev/null
@@ -1,68 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8192-sys-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek System Clock Controller for MT8192
-
-maintainers:
-  - Chun-Jie Chen <chun-jie.chen@mediatek.com>
-
-description:
-  The Mediatek system clock controller provides various clocks and system configuration
-  like reset and bus protection on MT8192.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - mediatek,mt8192-topckgen
-          - mediatek,mt8192-infracfg
-          - mediatek,mt8192-pericfg
-          - mediatek,mt8192-apmixedsys
-      - const: syscon
-
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-  '#reset-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-
-additionalProperties: false
-
-examples:
-  - |
-    topckgen: syscon@10000000 {
-        compatible = "mediatek,mt8192-topckgen", "syscon";
-        reg = <0x10000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    infracfg: syscon@10001000 {
-        compatible = "mediatek,mt8192-infracfg", "syscon";
-        reg = <0x10001000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    pericfg: syscon@10003000 {
-        compatible = "mediatek,mt8192-pericfg", "syscon";
-        reg = <0x10003000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    apmixedsys: syscon@1000c000 {
-        compatible = "mediatek,mt8192-apmixedsys", "syscon";
-        reg = <0x1000c000 0x1000>;
-        #clock-cells = <1>;
-    };

-- 
2.54.0



^ permalink raw reply related

* [PATCH 04/15] dt-bindings: clock: mediatek: regroup MT8195 dt-bindings into MT8186
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

Regroup the MT8195 clock and system clock dt-bindings into MT8186 ones
to ease maintainability and have common files for several currently
supported SoC or new future ones, that have the same kind of clock
controller design.

Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 .../bindings/clock/mediatek,mt8186-clock.yaml      |  25 +++
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml  |   4 +
 .../bindings/clock/mediatek,mt8195-clock.yaml      | 238 ---------------------
 .../bindings/clock/mediatek,mt8195-sys-clock.yaml  |  76 -------
 4 files changed, 29 insertions(+), 314 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
index 3b543c810f18..84e602c7d326 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
@@ -78,6 +78,31 @@ properties:
           - mediatek,mt8192-vdecsys_soc
           - mediatek,mt8192-vdecsys
           - mediatek,mt8192-vencsys
+          - mediatek,mt8195-apusys_pll
+          - mediatek,mt8195-camsys
+          - mediatek,mt8195-camsys_rawa
+          - mediatek,mt8195-camsys_yuva
+          - mediatek,mt8195-camsys_rawb
+          - mediatek,mt8195-camsys_yuvb
+          - mediatek,mt8195-camsys_mraw
+          - mediatek,mt8195-ccusys
+          - mediatek,mt8195-imgsys
+          - mediatek,mt8195-imgsys1_dip_top
+          - mediatek,mt8195-imgsys1_dip_nr
+          - mediatek,mt8195-imgsys1_wpe
+          - mediatek,mt8195-imp_iic_wrap_s
+          - mediatek,mt8195-imp_iic_wrap_w
+          - mediatek,mt8195-ipesys
+          - mediatek,mt8195-mfgcfg
+          - mediatek,mt8195-scp_adsp
+          - mediatek,mt8195-vdecsys_soc
+          - mediatek,mt8195-vdecsys
+          - mediatek,mt8195-vdecsys_core1
+          - mediatek,mt8195-vencsys
+          - mediatek,mt8195-vencsys_core1
+          - mediatek,mt8195-wpesys
+          - mediatek,mt8195-wpesys_vpp0
+          - mediatek,mt8195-wpesys_vpp1
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
index 4500842b20de..c4288b91e6b6 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
@@ -39,6 +39,10 @@ properties:
           - mediatek,mt8192-infracfg
           - mediatek,mt8192-pericfg
           - mediatek,mt8192-topckgen
+          - mediatek,mt8195-apmixedsys
+          - mediatek,mt8195-infracfg_ao
+          - mediatek,mt8195-pericfg_ao
+          - mediatek,mt8195-topckgen
       - const: syscon
 
   reg:
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8195-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8195-clock.yaml
deleted file mode 100644
index fcc963aff087..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8195-clock.yaml
+++ /dev/null
@@ -1,238 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8195-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek Functional Clock Controller for MT8195
-
-maintainers:
-  - Chun-Jie Chen <chun-jie.chen@mediatek.com>
-
-description:
-  The clock architecture in Mediatek like below
-  PLLs -->
-          dividers -->
-                      muxes
-                           -->
-                              clock gate
-
-  The devices except apusys_pll provide clock gate control in different IP blocks.
-  The apusys_pll provides Plls which generated from SoC 26m for AI Processing Unit.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - mediatek,mt8195-scp_adsp
-          - mediatek,mt8195-imp_iic_wrap_s
-          - mediatek,mt8195-imp_iic_wrap_w
-          - mediatek,mt8195-mfgcfg
-          - mediatek,mt8195-wpesys
-          - mediatek,mt8195-wpesys_vpp0
-          - mediatek,mt8195-wpesys_vpp1
-          - mediatek,mt8195-imgsys
-          - mediatek,mt8195-imgsys1_dip_top
-          - mediatek,mt8195-imgsys1_dip_nr
-          - mediatek,mt8195-imgsys1_wpe
-          - mediatek,mt8195-ipesys
-          - mediatek,mt8195-camsys
-          - mediatek,mt8195-camsys_rawa
-          - mediatek,mt8195-camsys_yuva
-          - mediatek,mt8195-camsys_rawb
-          - mediatek,mt8195-camsys_yuvb
-          - mediatek,mt8195-camsys_mraw
-          - mediatek,mt8195-ccusys
-          - mediatek,mt8195-vdecsys_soc
-          - mediatek,mt8195-vdecsys
-          - mediatek,mt8195-vdecsys_core1
-          - mediatek,mt8195-vencsys
-          - mediatek,mt8195-vencsys_core1
-          - mediatek,mt8195-apusys_pll
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-
-additionalProperties: false
-
-examples:
-  - |
-    scp_adsp: clock-controller@10720000 {
-        compatible = "mediatek,mt8195-scp_adsp";
-        reg = <0x10720000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_s: clock-controller@11d03000 {
-        compatible = "mediatek,mt8195-imp_iic_wrap_s";
-        reg = <0x11d03000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imp_iic_wrap_w: clock-controller@11e05000 {
-        compatible = "mediatek,mt8195-imp_iic_wrap_w";
-        reg = <0x11e05000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    mfgcfg: clock-controller@13fbf000 {
-        compatible = "mediatek,mt8195-mfgcfg";
-        reg = <0x13fbf000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    wpesys: clock-controller@14e00000 {
-        compatible = "mediatek,mt8195-wpesys";
-        reg = <0x14e00000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    wpesys_vpp0: clock-controller@14e02000 {
-        compatible = "mediatek,mt8195-wpesys_vpp0";
-        reg = <0x14e02000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    wpesys_vpp1: clock-controller@14e03000 {
-        compatible = "mediatek,mt8195-wpesys_vpp1";
-        reg = <0x14e03000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys: clock-controller@15000000 {
-        compatible = "mediatek,mt8195-imgsys";
-        reg = <0x15000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys1_dip_top: clock-controller@15110000 {
-        compatible = "mediatek,mt8195-imgsys1_dip_top";
-        reg = <0x15110000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys1_dip_nr: clock-controller@15130000 {
-        compatible = "mediatek,mt8195-imgsys1_dip_nr";
-        reg = <0x15130000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    imgsys1_wpe: clock-controller@15220000 {
-        compatible = "mediatek,mt8195-imgsys1_wpe";
-        reg = <0x15220000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    ipesys: clock-controller@15330000 {
-        compatible = "mediatek,mt8195-ipesys";
-        reg = <0x15330000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys: clock-controller@16000000 {
-        compatible = "mediatek,mt8195-camsys";
-        reg = <0x16000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_rawa: clock-controller@1604f000 {
-        compatible = "mediatek,mt8195-camsys_rawa";
-        reg = <0x1604f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_yuva: clock-controller@1606f000 {
-        compatible = "mediatek,mt8195-camsys_yuva";
-        reg = <0x1606f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_rawb: clock-controller@1608f000 {
-        compatible = "mediatek,mt8195-camsys_rawb";
-        reg = <0x1608f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_yuvb: clock-controller@160af000 {
-        compatible = "mediatek,mt8195-camsys_yuvb";
-        reg = <0x160af000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    camsys_mraw: clock-controller@16140000 {
-        compatible = "mediatek,mt8195-camsys_mraw";
-        reg = <0x16140000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    ccusys: clock-controller@17200000 {
-        compatible = "mediatek,mt8195-ccusys";
-        reg = <0x17200000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vdecsys_soc: clock-controller@1800f000 {
-        compatible = "mediatek,mt8195-vdecsys_soc";
-        reg = <0x1800f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vdecsys: clock-controller@1802f000 {
-        compatible = "mediatek,mt8195-vdecsys";
-        reg = <0x1802f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vdecsys_core1: clock-controller@1803f000 {
-        compatible = "mediatek,mt8195-vdecsys_core1";
-        reg = <0x1803f000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vencsys: clock-controller@1a000000 {
-        compatible = "mediatek,mt8195-vencsys";
-        reg = <0x1a000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    vencsys_core1: clock-controller@1b000000 {
-        compatible = "mediatek,mt8195-vencsys_core1";
-        reg = <0x1b000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    apusys_pll: clock-controller@190f3000 {
-        compatible = "mediatek,mt8195-apusys_pll";
-        reg = <0x190f3000 0x1000>;
-        #clock-cells = <1>;
-    };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8195-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8195-sys-clock.yaml
deleted file mode 100644
index 69f096eb168d..000000000000
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8195-sys-clock.yaml
+++ /dev/null
@@ -1,76 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/clock/mediatek,mt8195-sys-clock.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: MediaTek System Clock Controller for MT8195
-
-maintainers:
-  - Chun-Jie Chen <chun-jie.chen@mediatek.com>
-
-description:
-  The clock architecture in Mediatek like below
-  PLLs -->
-          dividers -->
-                      muxes
-                           -->
-                              clock gate
-
-  The apmixedsys provides most of PLLs which generated from SoC 26m.
-  The topckgen provides dividers and muxes which provide the clock source to other IP blocks.
-  The infracfg_ao and pericfg_ao provides clock gate in peripheral and infrastructure IP blocks.
-
-properties:
-  compatible:
-    items:
-      - enum:
-          - mediatek,mt8195-topckgen
-          - mediatek,mt8195-infracfg_ao
-          - mediatek,mt8195-apmixedsys
-          - mediatek,mt8195-pericfg_ao
-      - const: syscon
-
-  reg:
-    maxItems: 1
-
-  '#clock-cells':
-    const: 1
-
-  '#reset-cells':
-    const: 1
-
-required:
-  - compatible
-  - reg
-
-additionalProperties: false
-
-examples:
-  - |
-    topckgen: syscon@10000000 {
-        compatible = "mediatek,mt8195-topckgen", "syscon";
-        reg = <0x10000000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    infracfg_ao: syscon@10001000 {
-        compatible = "mediatek,mt8195-infracfg_ao", "syscon";
-        reg = <0x10001000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    apmixedsys: syscon@1000c000 {
-        compatible = "mediatek,mt8195-apmixedsys", "syscon";
-        reg = <0x1000c000 0x1000>;
-        #clock-cells = <1>;
-    };
-
-  - |
-    pericfg_ao: syscon@11003000 {
-        compatible = "mediatek,mt8195-pericfg_ao", "syscon";
-        reg = <0x11003000 0x1000>;
-        #clock-cells = <1>;
-    };

-- 
2.54.0



^ permalink raw reply related

* [PATCH 05/15] dt-bindings: clock: mediatek: Add MT8189 clocks
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Irving-CH Lin, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

Add dt schema and IDs for the clocks of MediaTek MT8189 SoC.
The MT8189 clock IP provide clock control for main system
(apmixedsys, topcksys and vlpcksys) and subsys (eg. peri, scp,
ufs...).

Also, add compatible for frequency hopping and spread spectrum clock
functionality and reset controller header file for MT8189 UFS reset
controller support.

Co-developed-by: Irving-CH Lin <irving-ch.lin@mediatek.com>
Signed-off-by: Irving-CH Lin <irving-ch.lin@mediatek.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 .../bindings/clock/mediatek,mt8186-clock.yaml      |  28 ++
 .../bindings/clock/mediatek,mt8186-fhctl.yaml      |   1 +
 .../bindings/clock/mediatek,mt8186-sys-clock.yaml  |  10 +
 include/dt-bindings/clock/mediatek,mt8189-clk.h    | 433 +++++++++++++++++++++
 include/dt-bindings/reset/mediatek,mt8189-resets.h |  17 +
 5 files changed, 489 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
index 84e602c7d326..e30ed16f321d 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml
@@ -58,6 +58,19 @@ properties:
           - mediatek,mt8188-vencsys
           - mediatek,mt8188-wpesys
           - mediatek,mt8188-wpesys-vpp0
+          - mediatek,mt8189-dbg-ao
+          - mediatek,mt8189-dem
+          - mediatek,mt8189-dvfsrc-top
+          - mediatek,mt8189-iic-wrap-e
+          - mediatek,mt8189-iic-wrap-en
+          - mediatek,mt8189-iic-wrap-s
+          - mediatek,mt8189-iic-wrap-ws
+          - mediatek,mt8189-scp-clk
+          - mediatek,mt8189-scp-i2c-clk
+          - mediatek,mt8189-ufscfg-ao
+          - mediatek,mt8189-ufscfg-pdn
+          - mediatek,mt8189-vlpcfg
+          - mediatek,mt8189-vlpcfg-ao
           - mediatek,mt8192-camsys
           - mediatek,mt8192-camsys_rawa
           - mediatek,mt8192-camsys_rawb
@@ -145,6 +158,19 @@ allOf:
             - mediatek,mt8188-vencsys
             - mediatek,mt8188-wpesys
             - mediatek,mt8188-wpesys-vpp0
+            - mediatek,mt8189-dbg-ao
+            - mediatek,mt8189-dem
+            - mediatek,mt8189-dvfsrc-top
+            - mediatek,mt8189-iic-wrap-e
+            - mediatek,mt8189-iic-wrap-en
+            - mediatek,mt8189-iic-wrap-s
+            - mediatek,mt8189-iic-wrap-ws
+            - mediatek,mt8189-scp-clk
+            - mediatek,mt8189-scp-i2c-clk
+            - mediatek,mt8189-ufscfg-ao
+            - mediatek,mt8189-ufscfg-pdn
+            - mediatek,mt8189-vlpcfg
+            - mediatek,mt8189-vlpcfg-ao
     then:
       required:
         - '#clock-cells'
@@ -163,6 +189,8 @@ allOf:
             - mediatek,mt8188-imgsys1-dip-nr
             - mediatek,mt8188-imgsys1-dip-top
             - mediatek,mt8188-ipesys
+            - mediatek,mt8189-ufscfg-ao
+            - mediatek,mt8189-ufscfg-pdn
     then:
       required:
         - '#reset-cells'
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml
index d00327d12e1e..824e3b2bd6c0 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-fhctl.yaml
@@ -20,6 +20,7 @@ properties:
       - mediatek,mt6795-fhctl
       - mediatek,mt8173-fhctl
       - mediatek,mt8186-fhctl
+      - mediatek,mt8189-fhctl
       - mediatek,mt8192-fhctl
       - mediatek,mt8195-fhctl
 
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
index c4288b91e6b6..35094ed68548 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml
@@ -35,6 +35,11 @@ properties:
           - mediatek,mt8188-infracfg-ao
           - mediatek,mt8188-pericfg-ao
           - mediatek,mt8188-topckgen
+          - mediatek,mt8189-apmixedsys
+          - mediatek,mt8189-infra-ao
+          - mediatek,mt8189-peri-ao
+          - mediatek,mt8189-topckgen
+          - mediatek,mt8189-vlpckgen
           - mediatek,mt8192-apmixedsys
           - mediatek,mt8192-infracfg
           - mediatek,mt8192-pericfg
@@ -68,6 +73,11 @@ allOf:
               - mediatek,mt8188-infracfg-ao
               - mediatek,mt8188-pericfg-ao
               - mediatek,mt8188-topckgen
+              - mediatek,mt8189-apmixedsys
+              - mediatek,mt8189-infra-ao
+              - mediatek,mt8189-peri-ao
+              - mediatek,mt8189-topckgen
+              - mediatek,mt8189-vlpckgen
     then:
       required:
         - '#clock-cells'
diff --git a/include/dt-bindings/clock/mediatek,mt8189-clk.h b/include/dt-bindings/clock/mediatek,mt8189-clk.h
new file mode 100644
index 000000000000..ca433f969698
--- /dev/null
+++ b/include/dt-bindings/clock/mediatek,mt8189-clk.h
@@ -0,0 +1,433 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)  */
+/*
+ * Copyright (C) 2025-2026 MediaTek Inc.
+ *                    Qiqi Wang <qiqi.wang@mediatek.com>
+ *                    Irving-CH Lin <irving-ch.lin@mediatek.com>
+ * Copyright (C) 2026 Collabora Ltd.
+ *                    Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT8189_H
+#define _DT_BINDINGS_CLK_MT8189_H
+
+/* TOPCKGEN */
+#define CLK_TOP_AXI_SEL					0
+#define CLK_TOP_AXI_PERI_SEL				1
+#define CLK_TOP_AXI_U_SEL				2
+#define CLK_TOP_BUS_AXIMEM_SEL				3
+#define CLK_TOP_DISP0_SEL				4
+#define CLK_TOP_MMINFRA_SEL				5
+#define CLK_TOP_UART_SEL				6
+#define CLK_TOP_SPI0_SEL				7
+#define CLK_TOP_SPI1_SEL				8
+#define CLK_TOP_SPI2_SEL				9
+#define CLK_TOP_SPI3_SEL				10
+#define CLK_TOP_SPI4_SEL				11
+#define CLK_TOP_SPI5_SEL				12
+#define CLK_TOP_MSDC_MACRO_0P_SEL			13
+#define CLK_TOP_MSDC50_0_HCLK_SEL			14
+#define CLK_TOP_MSDC50_0_SEL				15
+#define CLK_TOP_AES_MSDCFDE_SEL				16
+#define CLK_TOP_MSDC_MACRO_1P_SEL			17
+#define CLK_TOP_MSDC30_1_SEL				18
+#define CLK_TOP_MSDC30_1_HCLK_SEL			19
+#define CLK_TOP_MSDC_MACRO_2P_SEL			20
+#define CLK_TOP_MSDC30_2_SEL				21
+#define CLK_TOP_MSDC30_2_HCLK_SEL			22
+#define CLK_TOP_AUD_INTBUS_SEL				23
+#define CLK_TOP_ATB_SEL					24
+#define CLK_TOP_DISP_PWM_SEL				25
+#define CLK_TOP_USB_TOP_P0_SEL				26
+#define CLK_TOP_USB_XHCI_P0_SEL				27
+#define CLK_TOP_USB_TOP_P1_SEL				28
+#define CLK_TOP_USB_XHCI_P1_SEL				29
+#define CLK_TOP_USB_TOP_P2_SEL				30
+#define CLK_TOP_USB_XHCI_P2_SEL				31
+#define CLK_TOP_USB_TOP_P3_SEL				32
+#define CLK_TOP_USB_XHCI_P3_SEL				33
+#define CLK_TOP_USB_TOP_P4_SEL				34
+#define CLK_TOP_USB_XHCI_P4_SEL				35
+#define CLK_TOP_I2C_SEL					36
+#define CLK_TOP_SENINF_SEL				37
+#define CLK_TOP_SENINF1_SEL				38
+#define CLK_TOP_AUD_ENGEN1_SEL				39
+#define CLK_TOP_AUD_ENGEN2_SEL				40
+#define CLK_TOP_AES_UFSFDE_SEL				41
+#define CLK_TOP_U_SEL					42
+#define CLK_TOP_U_MBIST_SEL				43
+#define CLK_TOP_AUD_1_SEL				44
+#define CLK_TOP_AUD_2_SEL				45
+#define CLK_TOP_VENC_SEL				46
+#define CLK_TOP_VDEC_SEL				47
+#define CLK_TOP_PWM_SEL					48
+#define CLK_TOP_AUDIO_H_SEL				49
+#define CLK_TOP_MCUPM_SEL				50
+#define CLK_TOP_MEM_SUB_SEL				51
+#define CLK_TOP_MEM_SUB_PERI_SEL			52
+#define CLK_TOP_MEM_SUB_U_SEL				53
+#define CLK_TOP_EMI_N_SEL				54
+#define CLK_TOP_DSI_OCC_SEL				55
+#define CLK_TOP_AP2CONN_HOST_SEL			56
+#define CLK_TOP_IMG1_SEL				57
+#define CLK_TOP_IPE_SEL					58
+#define CLK_TOP_CAM_SEL					59
+#define CLK_TOP_CAMTM_SEL				60
+#define CLK_TOP_DSP_SEL					61
+#define CLK_TOP_SR_PKA_SEL				62
+#define CLK_TOP_DXCC_SEL				63
+#define CLK_TOP_MFG_REF_SEL				64
+#define CLK_TOP_MDP0_SEL				65
+#define CLK_TOP_DP_SEL					66
+#define CLK_TOP_EDP_SEL					67
+#define CLK_TOP_EDP_FAVT_SEL				68
+#define CLK_TOP_ETH_250M_SEL				69
+#define CLK_TOP_ETH_62P4M_PTP_SEL			70
+#define CLK_TOP_ETH_50M_RMII_SEL			71
+#define CLK_TOP_SFLASH_SEL				72
+#define CLK_TOP_GCPU_SEL				73
+#define CLK_TOP_MAC_TL_SEL				74
+#define CLK_TOP_VDSTX_DG_CTS_SEL			75
+#define CLK_TOP_PLL_DPIX_SEL				76
+#define CLK_TOP_ECC_SEL					77
+#define CLK_TOP_APLL_I2SIN0_MCK_SEL			78
+#define CLK_TOP_APLL_I2SIN1_MCK_SEL			79
+#define CLK_TOP_APLL_I2SIN2_MCK_SEL			80
+#define CLK_TOP_APLL_I2SIN3_MCK_SEL			81
+#define CLK_TOP_APLL_I2SIN4_MCK_SEL			82
+#define CLK_TOP_APLL_I2SIN6_MCK_SEL			83
+#define CLK_TOP_APLL_I2SOUT0_MCK_SEL			84
+#define CLK_TOP_APLL_I2SOUT1_MCK_SEL			85
+#define CLK_TOP_APLL_I2SOUT2_MCK_SEL			86
+#define CLK_TOP_APLL_I2SOUT3_MCK_SEL			87
+#define CLK_TOP_APLL_I2SOUT4_MCK_SEL			88
+#define CLK_TOP_APLL_I2SOUT6_MCK_SEL			89
+#define CLK_TOP_APLL_FMI2S_MCK_SEL			90
+#define CLK_TOP_APLL_TDMOUT_MCK_SEL			91
+#define CLK_TOP_MFG_SEL_MFGPLL				92
+#define CLK_TOP_APLL12_CK_DIV_I2SIN0			93
+#define CLK_TOP_APLL12_CK_DIV_I2SIN1			94
+#define CLK_TOP_APLL12_CK_DIV_I2SOUT0			95
+#define CLK_TOP_APLL12_CK_DIV_I2SOUT1			96
+#define CLK_TOP_APLL12_CK_DIV_FMI2S			97
+#define CLK_TOP_APLL12_CK_DIV_TDMOUT_M			98
+#define CLK_TOP_APLL12_CK_DIV_TDMOUT_B			99
+#define CLK_TOP_MAINPLL_D3				100
+#define CLK_TOP_MAINPLL_D4				101
+#define CLK_TOP_MAINPLL_D4_D2				102
+#define CLK_TOP_MAINPLL_D4_D4				103
+#define CLK_TOP_MAINPLL_D4_D8				104
+#define CLK_TOP_MAINPLL_D5				105
+#define CLK_TOP_MAINPLL_D5_D2				106
+#define CLK_TOP_MAINPLL_D5_D4				107
+#define CLK_TOP_MAINPLL_D5_D8				108
+#define CLK_TOP_MAINPLL_D6				109
+#define CLK_TOP_MAINPLL_D6_D2				110
+#define CLK_TOP_MAINPLL_D6_D4				111
+#define CLK_TOP_MAINPLL_D6_D8				112
+#define CLK_TOP_MAINPLL_D7				113
+#define CLK_TOP_MAINPLL_D7_D2				114
+#define CLK_TOP_MAINPLL_D7_D4				115
+#define CLK_TOP_MAINPLL_D7_D8				116
+#define CLK_TOP_MAINPLL_D9				117
+#define CLK_TOP_UNIVPLL_D2				118
+#define CLK_TOP_UNIVPLL_D3				119
+#define CLK_TOP_UNIVPLL_D4				120
+#define CLK_TOP_UNIVPLL_D4_D2				121
+#define CLK_TOP_UNIVPLL_D4_D4				122
+#define CLK_TOP_UNIVPLL_D4_D8				123
+#define CLK_TOP_UNIVPLL_D5				124
+#define CLK_TOP_UNIVPLL_D5_D2				125
+#define CLK_TOP_UNIVPLL_D5_D4				126
+#define CLK_TOP_UNIVPLL_D6				127
+#define CLK_TOP_UNIVPLL_D6_D2				128
+#define CLK_TOP_UNIVPLL_D6_D4				129
+#define CLK_TOP_UNIVPLL_D6_D8				130
+#define CLK_TOP_UNIVPLL_D6_D16				131
+#define CLK_TOP_UNIVPLL_D7				132
+#define CLK_TOP_UNIVPLL_D7_D2				133
+#define CLK_TOP_UNIVPLL_D7_D3				134
+#define CLK_TOP_LVDSTX_DG_CTS				135
+#define CLK_TOP_UNIVPLL_192M				136
+#define CLK_TOP_UNIVPLL_192M_D2				137
+#define CLK_TOP_UNIVPLL_192M_D4				138
+#define CLK_TOP_UNIVPLL_192M_D8				139
+#define CLK_TOP_UNIVPLL_192M_D10			140
+#define CLK_TOP_UNIVPLL_192M_D16			141
+#define CLK_TOP_UNIVPLL_192M_D32			142
+#define CLK_TOP_APLL1_D2				143
+#define CLK_TOP_APLL1_D4				144
+#define CLK_TOP_APLL1_D8				145
+#define CLK_TOP_APLL1_D3				146
+#define CLK_TOP_APLL2_D2				147
+#define CLK_TOP_APLL2_D4				148
+#define CLK_TOP_APLL2_D8				149
+#define CLK_TOP_APLL2_D3				150
+#define CLK_TOP_MMPLL_D4				151
+#define CLK_TOP_MMPLL_D4_D2				152
+#define CLK_TOP_MMPLL_D4_D4				153
+#define CLK_TOP_VPLL_DPIX				154
+#define CLK_TOP_MMPLL_D5				155
+#define CLK_TOP_MMPLL_D5_D2				156
+#define CLK_TOP_MMPLL_D5_D4				157
+#define CLK_TOP_MMPLL_D6				158
+#define CLK_TOP_MMPLL_D6_D2				159
+#define CLK_TOP_MMPLL_D7				160
+#define CLK_TOP_MMPLL_D9				161
+#define CLK_TOP_TVDPLL1_D2				162
+#define CLK_TOP_TVDPLL1_D4				163
+#define CLK_TOP_TVDPLL1_D8				164
+#define CLK_TOP_TVDPLL1_D16				165
+#define CLK_TOP_TVDPLL2_D2				166
+#define CLK_TOP_TVDPLL2_D4				167
+#define CLK_TOP_TVDPLL2_D8				168
+#define CLK_TOP_TVDPLL2_D16				169
+#define CLK_TOP_ETHPLL_D2				170
+#define CLK_TOP_ETHPLL_D8				171
+#define CLK_TOP_ETHPLL_D10				172
+#define CLK_TOP_MSDCPLL_D2				173
+#define CLK_TOP_UFSPLL_D2				174
+#define CLK_TOP_F26M_CK_D2				175
+#define CLK_TOP_OSC_D2					176
+#define CLK_TOP_OSC_D4					177
+#define CLK_TOP_OSC_D8					178
+#define CLK_TOP_OSC_D16					179
+#define CLK_TOP_OSC_D3					180
+#define CLK_TOP_OSC_D7					181
+#define CLK_TOP_OSC_D10					182
+#define CLK_TOP_OSC_D20					183
+#define CLK_TOP_FMCNT_P0_EN				184
+#define CLK_TOP_FMCNT_P1_EN				185
+#define CLK_TOP_FMCNT_P2_EN				186
+#define CLK_TOP_FMCNT_P3_EN				187
+#define CLK_TOP_FMCNT_P4_EN				188
+#define CLK_TOP_USB_F26M_CK_EN				189
+#define CLK_TOP_SSPXTP_F26M_CK_EN			190
+#define CLK_TOP_USB2_PHY_RF_P0_EN			191
+#define CLK_TOP_USB2_PHY_RF_P1_EN			192
+#define CLK_TOP_USB2_PHY_RF_P2_EN			193
+#define CLK_TOP_USB2_PHY_RF_P3_EN			194
+#define CLK_TOP_USB2_PHY_RF_P4_EN			195
+#define CLK_TOP_USB2_26M_CK_P0_EN			196
+#define CLK_TOP_USB2_26M_CK_P1_EN			197
+#define CLK_TOP_USB2_26M_CK_P2_EN			198
+#define CLK_TOP_USB2_26M_CK_P3_EN			199
+#define CLK_TOP_USB2_26M_CK_P4_EN			200
+#define CLK_TOP_F26M_CK_EN				201
+#define CLK_TOP_AP2CON_EN				202
+#define CLK_TOP_EINT_N_EN				203
+#define CLK_TOP_TOPCKGEN_FMIPI_CSI_UP26M_CK_EN		204
+#define CLK_TOP_EINT_E_EN				205
+#define CLK_TOP_EINT_W_EN				206
+#define CLK_TOP_EINT_S_EN				207
+
+/* INFRACFG_AO */
+#define CLK_IFRAO_CQ_DMA_FPC				0
+#define CLK_IFRAO_DEBUGSYS				1
+#define CLK_IFRAO_DBG_TRACE				2
+#define CLK_IFRAO_CQ_DMA				3
+
+/* APMIXEDSYS */
+#define CLK_APMIXED_ARMPLL_LL				0
+#define CLK_APMIXED_ARMPLL_BL				1
+#define CLK_APMIXED_CCIPLL				2
+#define CLK_APMIXED_MAINPLL				3
+#define CLK_APMIXED_UNIVPLL				4
+#define CLK_APMIXED_MMPLL				5
+#define CLK_APMIXED_MFGPLL				6
+#define CLK_APMIXED_APLL1				7
+#define CLK_APMIXED_APLL2				8
+#define CLK_APMIXED_EMIPLL				9
+#define CLK_APMIXED_APUPLL2				10
+#define CLK_APMIXED_APUPLL				11
+#define CLK_APMIXED_TVDPLL1				12
+#define CLK_APMIXED_TVDPLL2				13
+#define CLK_APMIXED_ETHPLL				14
+#define CLK_APMIXED_MSDCPLL				15
+#define CLK_APMIXED_UFSPLL				16
+
+/* PERICFG_AO */
+#define CLK_PERAO_UART0					0
+#define CLK_PERAO_UART1					1
+#define CLK_PERAO_UART2					2
+#define CLK_PERAO_UART3					3
+#define CLK_PERAO_PWM_H					4
+#define CLK_PERAO_PWM_B					5
+#define CLK_PERAO_PWM_FB1				6
+#define CLK_PERAO_PWM_FB2				7
+#define CLK_PERAO_PWM_FB3				8
+#define CLK_PERAO_PWM_FB4				9
+#define CLK_PERAO_DISP_PWM0				10
+#define CLK_PERAO_DISP_PWM1				11
+#define CLK_PERAO_SPI0_B				12
+#define CLK_PERAO_SPI1_B				13
+#define CLK_PERAO_SPI2_B				14
+#define CLK_PERAO_SPI3_B				15
+#define CLK_PERAO_SPI4_B				16
+#define CLK_PERAO_SPI5_B				17
+#define CLK_PERAO_SPI0_H				18
+#define CLK_PERAO_SPI1_H				19
+#define CLK_PERAO_SPI2_H				20
+#define CLK_PERAO_SPI3_H				21
+#define CLK_PERAO_SPI4_H				22
+#define CLK_PERAO_SPI5_H				23
+#define CLK_PERAO_AXI					24
+#define CLK_PERAO_AHB_APB				25
+#define CLK_PERAO_TL					26
+#define CLK_PERAO_REF					27
+#define CLK_PERAO_I2C					28
+#define CLK_PERAO_DMA_B					29
+#define CLK_PERAO_SSUSB0_REF				30
+#define CLK_PERAO_SSUSB0_FRMCNT				31
+#define CLK_PERAO_SSUSB0_SYS				32
+#define CLK_PERAO_SSUSB0_XHCI				33
+#define CLK_PERAO_SSUSB0_F				34
+#define CLK_PERAO_SSUSB0_H				35
+#define CLK_PERAO_SSUSB1_REF				36
+#define CLK_PERAO_SSUSB1_FRMCNT				37
+#define CLK_PERAO_SSUSB1_SYS				38
+#define CLK_PERAO_SSUSB1_XHCI				39
+#define CLK_PERAO_SSUSB1_F				40
+#define CLK_PERAO_SSUSB1_H				41
+#define CLK_PERAO_SSUSB2_REF				42
+#define CLK_PERAO_SSUSB2_FRMCNT				43
+#define CLK_PERAO_SSUSB2_SYS				44
+#define CLK_PERAO_SSUSB2_XHCI				45
+#define CLK_PERAO_SSUSB2_F				46
+#define CLK_PERAO_SSUSB2_H				47
+#define CLK_PERAO_SSUSB3_REF				48
+#define CLK_PERAO_SSUSB3_FRMCNT				49
+#define CLK_PERAO_SSUSB3_SYS				50
+#define CLK_PERAO_SSUSB3_XHCI				51
+#define CLK_PERAO_SSUSB3_F				52
+#define CLK_PERAO_SSUSB3_H				53
+#define CLK_PERAO_SSUSB4_REF				54
+#define CLK_PERAO_SSUSB4_FRMCNT				55
+#define CLK_PERAO_SSUSB4_SYS				56
+#define CLK_PERAO_SSUSB4_XHCI				57
+#define CLK_PERAO_SSUSB4_F				58
+#define CLK_PERAO_SSUSB4_H				59
+#define CLK_PERAO_MSDC0					60
+#define CLK_PERAO_MSDC0_H				61
+#define CLK_PERAO_MSDC0_FAES				62
+#define CLK_PERAO_MSDC0_MST_F				63
+#define CLK_PERAO_MSDC0_SLV_H				64
+#define CLK_PERAO_MSDC1					65
+#define CLK_PERAO_MSDC1_H				66
+#define CLK_PERAO_MSDC1_MST_F				67
+#define CLK_PERAO_MSDC1_SLV_H				68
+#define CLK_PERAO_MSDC2					69
+#define CLK_PERAO_MSDC2_H				70
+#define CLK_PERAO_MSDC2_MST_F				71
+#define CLK_PERAO_MSDC2_SLV_H				72
+#define CLK_PERAO_SFLASH				73
+#define CLK_PERAO_SFLASH_F				74
+#define CLK_PERAO_SFLASH_H				75
+#define CLK_PERAO_SFLASH_P				76
+#define CLK_PERAO_AUDIO0				77
+#define CLK_PERAO_AUDIO1				78
+#define CLK_PERAO_AUDIO2				79
+#define CLK_PERAO_AUXADC_26M				80
+
+/* UFSCFG_AO_REG */
+#define CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM			0
+#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0		1
+#define CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1		2
+#define CLK_UFSCFG_AO_REG_UNIPRO_SYS			3
+#define CLK_UFSCFG_AO_REG_U_SAP_CFG			4
+#define CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS		5
+
+/* UFSCFG_PDN_REG */
+#define CLK_UFSCFG_REG_UFSHCI_UFS			0
+#define CLK_UFSCFG_REG_UFSHCI_AES			1
+#define CLK_UFSCFG_REG_UFSHCI_U_AHB			2
+#define CLK_UFSCFG_REG_UFSHCI_U_AXI			3
+
+/* IMP_IIC_WRAP_WS */
+#define CLK_IMPWS_I2C2					0
+
+/* IMP_IIC_WRAP_E */
+#define CLK_IMPE_I2C0					0
+#define CLK_IMPE_I2C1					1
+
+/* IMP_IIC_WRAP_S */
+#define CLK_IMPS_I2C3					0
+#define CLK_IMPS_I2C4					1
+#define CLK_IMPS_I2C5					2
+#define CLK_IMPS_I2C6					3
+
+/* IMP_IIC_WRAP_EN */
+#define CLK_IMPEN_I2C7					0
+#define CLK_IMPEN_I2C8					1
+
+/* VLPCFG_REG */
+#define CLK_VLPCFG_REG_SCP				0
+#define CLK_VLPCFG_REG_RG_R_APXGPT_26M			1
+#define CLK_VLPCFG_REG_DPMSRCK_TEST			2
+#define CLK_VLPCFG_REG_RG_DPMSRRTC_TEST			3
+#define CLK_VLPCFG_REG_DPMSRULP_TEST			4
+#define CLK_VLPCFG_REG_SPMI_P_MST			5
+#define CLK_VLPCFG_REG_SPMI_P_MST_32K			6
+#define CLK_VLPCFG_REG_PMIF_SPMI_P_SYS			7
+#define CLK_VLPCFG_REG_PMIF_SPMI_P_TMR			8
+#define CLK_VLPCFG_REG_PMIF_SPMI_M_SYS			9
+#define CLK_VLPCFG_REG_PMIF_SPMI_M_TMR			10
+#define CLK_VLPCFG_REG_DVFSRC				11
+#define CLK_VLPCFG_REG_PWM_VLP				12
+#define CLK_VLPCFG_REG_SRCK				13
+#define CLK_VLPCFG_REG_SSPM_F26M			14
+#define CLK_VLPCFG_REG_SSPM_F32K			15
+#define CLK_VLPCFG_REG_SSPM_ULPOSC			16
+#define CLK_VLPCFG_REG_VLP_32K_COM			17
+#define CLK_VLPCFG_REG_VLP_26M_COM			18
+
+/* VLP_CKSYS */
+#define CLK_VLP_CK_SCP_SEL				0
+#define CLK_VLP_CK_PWRAP_ULPOSC_SEL			1
+#define CLK_VLP_CK_SPMI_P_MST_SEL			2
+#define CLK_VLP_CK_DVFSRC_SEL				3
+#define CLK_VLP_CK_PWM_VLP_SEL				4
+#define CLK_VLP_CK_AXI_VLP_SEL				5
+#define CLK_VLP_CK_SYSTIMER_26M_SEL			6
+#define CLK_VLP_CK_SSPM_SEL				7
+#define CLK_VLP_CK_SSPM_F26M_SEL			8
+#define CLK_VLP_CK_SRCK_SEL				9
+#define CLK_VLP_CK_SCP_SPI_SEL				10
+#define CLK_VLP_CK_SCP_IIC_SEL				11
+#define CLK_VLP_CK_SCP_SPI_HIGH_SPD_SEL			12
+#define CLK_VLP_CK_SCP_IIC_HIGH_SPD_SEL			13
+#define CLK_VLP_CK_SSPM_ULPOSC_SEL			14
+#define CLK_VLP_CK_APXGPT_26M_SEL			15
+#define CLK_VLP_CK_VADSP_SEL				16
+#define CLK_VLP_CK_VADSP_VOWPLL_SEL			17
+#define CLK_VLP_CK_VADSP_UARTHUB_BCLK_SEL		18
+#define CLK_VLP_CK_CAMTG0_SEL				19
+#define CLK_VLP_CK_CAMTG1_SEL				20
+#define CLK_VLP_CK_CAMTG2_SEL				21
+#define CLK_VLP_CK_AUD_ADC_SEL				22
+#define CLK_VLP_CK_KP_IRQ_GEN_SEL			23
+#define CLK_VLP_CK_VADSYS_VLP_26M_EN			24
+#define CLK_VLP_CK_FMIPI_CSI_UP26M_CK_EN		25
+
+/* SCP_IIC */
+#define CLK_SCP_IIC_I2C0_W1S				0
+#define CLK_SCP_IIC_I2C1_W1S				1
+
+/* SCP */
+#define CLK_SCP_SET_SPI0				0
+#define CLK_SCP_SET_SPI1				1
+
+/* VLPCFG_AO_REG */
+#define CLK_VLPCFG_AO_APEINT_RX				0
+
+/* DVFSRC_TOP */
+#define CLK_DVFSRC_TOP_DVFSRC_EN			0
+
+/* DBGAO */
+#define CLK_DBGAO_ATB_EN				0
+
+/* DEM */
+#define CLK_DEM_ATB_EN					0
+#define CLK_DEM_BUSCLK_EN				1
+#define CLK_DEM_SYSCLK_EN				2
+
+#endif /* _DT_BINDINGS_CLK_MT8189_H */
diff --git a/include/dt-bindings/reset/mediatek,mt8189-resets.h b/include/dt-bindings/reset/mediatek,mt8189-resets.h
new file mode 100644
index 000000000000..0f31984374be
--- /dev/null
+++ b/include/dt-bindings/reset/mediatek,mt8189-resets.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2026 Collabora Ltd.
+ * Author: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8189
+#define _DT_BINDINGS_RESET_CONTROLLER_MT8189
+
+/* UFS resets */
+#define MT8189_UFSAO_RST_UFS_MPHY		0
+
+#define MT8189_UFSPDN_RST_UFS_UNIPRO		0
+#define MT8189_UFSPDN_RST_UFS_CRYPTO		1
+#define MT8189_UFSPDN_RST_UFS_HCI		2
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT8189 */

-- 
2.54.0



^ permalink raw reply related

* [PATCH 06/15] clk: mediatek: Add MT8189 apmixedsys clock support
From: Louis-Alexis Eyraud @ 2026-07-01 13:11 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Chun-Jie Chen, Philipp Zabel,
	Edward-JW Yang, Richard Cochran
  Cc: kernel, linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	linux-mediatek, netdev, Irving-CH Lin, Louis-Alexis Eyraud
In-Reply-To: <20260701-mt8189-clocks-system-base-v1-0-2b048feea50a@collabora.com>

Add support for the MT8189 apmixedsys clock controller, which provides
PLLs generated from SoC 26m.

Co-developed-by: Irving-CH Lin <irving-ch.lin@mediatek.com>
Signed-off-by: Irving-CH Lin <irving-ch.lin@mediatek.com>
Co-developed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
 drivers/clk/mediatek/Kconfig                 |  13 ++
 drivers/clk/mediatek/Makefile                |   1 +
 drivers/clk/mediatek/clk-mt8189-apmixedsys.c | 196 +++++++++++++++++++++++++++
 3 files changed, 210 insertions(+)

diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 2c09fd729bab..f67dfb6cd019 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -815,6 +815,19 @@ config COMMON_CLK_MT8188_WPESYS
 	help
 	  This driver supports MediaTek MT8188 Warp Engine clocks.
 
+config COMMON_CLK_MT8189
+	tristate "Clock driver for MediaTek MT8189"
+	depends on ARM64 || COMPILE_TEST
+	select COMMON_CLK_MEDIATEK
+	select COMMON_CLK_MEDIATEK_FHCTL
+	default ARCH_MEDIATEK
+	help
+	  Enable this option to support the clock management for MediaTek MT8189 SoC. This
+	  includes handling of all primary clock functions and features specific to the MT8189
+	  platform. Enabling this driver ensures that the system's clock functionality aligns
+	  with the MediaTek MT8189 hardware capabilities, providing efficient management of
+	  clock speeds and power consumption.
+
 config COMMON_CLK_MT8192
 	tristate "Clock driver for MediaTek MT8192"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index d8736a060dbd..66577ccb9b93 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -123,6 +123,7 @@ obj-$(CONFIG_COMMON_CLK_MT8188_VDOSYS) += clk-mt8188-vdo0.o clk-mt8188-vdo1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VENCSYS) += clk-mt8188-venc.o
 obj-$(CONFIG_COMMON_CLK_MT8188_VPPSYS) += clk-mt8188-vpp0.o clk-mt8188-vpp1.o
 obj-$(CONFIG_COMMON_CLK_MT8188_WPESYS) += clk-mt8188-wpe.o
+obj-$(CONFIG_COMMON_CLK_MT8189) += clk-mt8189-apmixedsys.o
 obj-$(CONFIG_COMMON_CLK_MT8192) += clk-mt8192-apmixedsys.o clk-mt8192.o
 obj-$(CONFIG_COMMON_CLK_MT8192_AUDSYS) += clk-mt8192-aud.o
 obj-$(CONFIG_COMMON_CLK_MT8192_CAMSYS) += clk-mt8192-cam.o
diff --git a/drivers/clk/mediatek/clk-mt8189-apmixedsys.c b/drivers/clk/mediatek/clk-mt8189-apmixedsys.c
new file mode 100644
index 000000000000..0657a50c30d9
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt8189-apmixedsys.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025-2026 MediaTek Inc.
+ *                    Qiqi Wang <qiqi.wang@mediatek.com>
+ *                    Irving-CH Lin <irving-ch.lin@mediatek.com>
+ * Copyright (C) 2026 Collabora Ltd.
+ *                    AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ *                    Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "clk-fhctl.h"
+#include "clk-mtk.h"
+#include "clk-pll.h"
+
+#include <dt-bindings/clock/mediatek,mt8189-clk.h>
+
+#define MT8189_PLL_FMAX		(3800UL * MHZ)
+#define MT8189_PLL_FMIN		(1500UL * MHZ)
+#define MT8189_PLLEN_OFS	0x70
+#define MT8189_INTEGER_BITS	8
+
+#define PLL_SETCLR(_id, _name, _reg, _en_setclr_bit,		\
+			_rstb_setclr_bit, _flags, _pd_reg,	\
+			_pd_shift, _tuner_reg, _tuner_en_reg,	\
+			_tuner_en_bit, _pcw_reg, _pcw_shift,	\
+			_pcwbits) {				\
+		.id = _id,					\
+		.name = _name,					\
+		.en_reg = MT8189_PLLEN_OFS,			\
+		.reg = _reg,					\
+		.pll_en_bit = _en_setclr_bit,			\
+		.rst_bar_mask = BIT(_rstb_setclr_bit),		\
+		.flags = _flags,				\
+		.fmax = MT8189_PLL_FMAX,			\
+		.fmin = MT8189_PLL_FMIN,			\
+		.pd_reg = _pd_reg,				\
+		.pd_shift = _pd_shift,				\
+		.tuner_reg = _tuner_reg,			\
+		.tuner_en_reg = _tuner_en_reg,			\
+		.tuner_en_bit = _tuner_en_bit,			\
+		.pcw_reg = _pcw_reg,				\
+		.pcw_shift = _pcw_shift,			\
+		.pcwbits = _pcwbits,				\
+		.pcwibits = MT8189_INTEGER_BITS,		\
+	}
+
+static const struct mtk_pll_data apmixed_plls[] = {
+	PLL_SETCLR(CLK_APMIXED_ARMPLL_LL, "armpll-ll", 0x204, 18,
+		   0, PLL_AO, 0x208, 24, 0, 0, 0, 0x208, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_ARMPLL_BL, "armpll-bl", 0x214, 17,
+		   0, PLL_AO, 0x218, 24, 0, 0, 0, 0x218, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_CCIPLL, "ccipll", 0x224, 16,
+		   0, PLL_AO, 0x228, 24, 0, 0, 0, 0x228, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MAINPLL, "mainpll", 0x304, 15,
+		   23, HAVE_RST_BAR | PLL_AO,
+		   0x308, 24, 0, 0, 0, 0x308, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_UNIVPLL, "univpll", 0x314, 14,
+		   23, HAVE_RST_BAR, 0x318, 24, 0, 0, 0, 0x318, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MMPLL, "mmpll", 0x324, 13,
+		   23, HAVE_RST_BAR, 0x328, 24, 0, 0, 0, 0x328, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MFGPLL, "mfgpll", 0x504, 7,
+		   0, 0, 0x508, 24, 0, 0, 0, 0x508, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APLL1, "apll1", 0x404, 11,
+		   0, 0, 0x408, 24, 0x040, 0x00c, 0, 0x40c, 0, 32),
+	PLL_SETCLR(CLK_APMIXED_APLL2, "apll2", 0x418, 10,
+		   0, 0, 0x41c, 24, 0x044, 0x00c, 1, 0x420, 0, 32),
+	PLL_SETCLR(CLK_APMIXED_EMIPLL, "emipll", 0x334, 12,
+		   0, PLL_AO, 0x338, 24, 0, 0, 0, 0x338, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APUPLL2, "apupll2", 0x614, 2,
+		   0, 0, 0x618, 24, 0, 0, 0, 0x618, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_APUPLL, "apupll", 0x604, 3,
+		   0, 0, 0x608, 24, 0, 0, 0, 0x608, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_TVDPLL1, "tvdpll1", 0x42c, 9,
+		   0, 0, 0x430, 24, 0, 0, 0, 0x430, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_TVDPLL2, "tvdpll2", 0x43c, 8,
+		   0, 0, 0x440, 24, 0, 0, 0, 0x440, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_ETHPLL, "ethpll", 0x514, 6,
+		   0, 0, 0x518, 24, 0, 0, 0, 0x518, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_MSDCPLL, "msdcpll", 0x524, 5,
+		   0, 0, 0x528, 24, 0, 0, 0, 0x528, 0, 22),
+	PLL_SETCLR(CLK_APMIXED_UFSPLL, "ufspll", 0x534, 4,
+		   0, 0, 0x538, 24, 0, 0, 0, 0x538, 0, 22),
+};
+
+#define FH(_pllid, _fhid, _offset) {				\
+		.data = {					\
+			.pll_id = _pllid,			\
+			.fh_id = _fhid,				\
+			.fh_ver = FHCTL_PLLFH_V2,		\
+			.fhx_offset = _offset,			\
+			.dds_mask = GENMASK(21, 0),		\
+			.slope0_value = 0x6003c97,		\
+			.slope1_value = 0x6003c97,		\
+			.sfstrx_en = BIT(2),			\
+			.frddsx_en = BIT(1),			\
+			.fhctlx_en = BIT(0),			\
+			.tgl_org = BIT(31),			\
+			.dvfs_tri = BIT(31),			\
+			.pcwchg = BIT(31),			\
+			.dt_val = 0x0,				\
+			.df_val = 0x9,				\
+			.updnlmt_shft = 16,			\
+			.msk_frddsx_dys = GENMASK(23, 20),	\
+			.msk_frddsx_dts = GENMASK(19, 16),	\
+		},						\
+	}
+
+static struct mtk_pllfh_data pllfhs[] = {
+	FH(CLK_APMIXED_ARMPLL_LL, 0, 0x003C),
+	FH(CLK_APMIXED_ARMPLL_BL, 1, 0x0050),
+	FH(CLK_APMIXED_CCIPLL, 2, 0x0064),
+	FH(CLK_APMIXED_MAINPLL, 3, 0x0078),
+	FH(CLK_APMIXED_MMPLL, 4, 0x008C),
+	FH(CLK_APMIXED_MFGPLL, 5, 0x00A0),
+	FH(CLK_APMIXED_EMIPLL, 6, 0x00B4),
+	FH(CLK_APMIXED_TVDPLL1, 7, 0x00C8),
+	FH(CLK_APMIXED_TVDPLL2, 8, 0x00DC),
+	FH(CLK_APMIXED_MSDCPLL, 9, 0x00F0),
+	FH(CLK_APMIXED_UFSPLL, 10, 0x0104),
+	FH(CLK_APMIXED_APUPLL, 11, 0x0118),
+	FH(CLK_APMIXED_APUPLL2, 12, 0x012c),
+};
+
+static const struct of_device_id of_match_clk_mt8189_apmixed[] = {
+	{ .compatible = "mediatek,mt8189-apmixedsys" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt8189_apmixed);
+
+static int clk_mt8189_apmixed_probe(struct platform_device *pdev)
+{
+	int r;
+	struct clk_hw_onecell_data *clk_data;
+	struct device_node *node = pdev->dev.of_node;
+	const u8 *fhctl_node = "mediatek,mt8189-fhctl";
+
+	clk_data = mtk_alloc_clk_data(ARRAY_SIZE(apmixed_plls));
+	if (!clk_data)
+		return -ENOMEM;
+
+	fhctl_parse_dt(fhctl_node, pllfhs, ARRAY_SIZE(pllfhs));
+
+	r = mtk_clk_register_pllfhs(&pdev->dev, apmixed_plls, ARRAY_SIZE(apmixed_plls),
+				    pllfhs, ARRAY_SIZE(pllfhs), clk_data);
+	if (r)
+		goto free_apmixed_data;
+
+	r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+	if (r)
+		goto unregister_plls;
+
+	platform_set_drvdata(pdev, clk_data);
+
+	return 0;
+
+unregister_plls:
+	mtk_clk_unregister_pllfhs(apmixed_plls, ARRAY_SIZE(apmixed_plls), pllfhs,
+				  ARRAY_SIZE(pllfhs), clk_data);
+free_apmixed_data:
+	mtk_free_clk_data(clk_data);
+	return r;
+}
+
+static void clk_mt8189_apmixed_remove(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
+
+	of_clk_del_provider(node);
+	mtk_clk_unregister_pllfhs(apmixed_plls, ARRAY_SIZE(apmixed_plls), pllfhs,
+				  ARRAY_SIZE(pllfhs), clk_data);
+	mtk_free_clk_data(clk_data);
+}
+
+static struct platform_driver clk_mt8189_apmixed_drv = {
+	.probe = clk_mt8189_apmixed_probe,
+	.remove = clk_mt8189_apmixed_remove,
+	.driver = {
+		.name = "clk-mt8189-apmixed",
+		.of_match_table = of_match_clk_mt8189_apmixed,
+	},
+};
+module_platform_driver(clk_mt8189_apmixed_drv);
+
+MODULE_DESCRIPTION("MediaTek MT8189 apmixed clocks driver");
+MODULE_LICENSE("GPL");

-- 
2.54.0



^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox