From: Ulf Hansson <ulf.hansson@linaro.org>
To: Sudeep Holla <sudeep.holla@arm.com>,
Cristian Marussi <cristian.marussi@arm.com>,
Viresh Kumar <vireshk@kernel.org>, Nishanth Menon <nm@ti.com>,
Stephen Boyd <sboyd@kernel.org>
Cc: Nikunj Kela <nkela@quicinc.com>,
Prasad Sodagudi <psodagud@quicinc.com>,
Alexandre Torgue <alexandre.torgue@foss.st.com>,
Ulf Hansson <ulf.hansson@linaro.org>,
linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v2 10/11] firmware: arm_scmi: Add the SCMI performance domain
Date: Thu, 13 Jul 2023 16:17:37 +0200 [thread overview]
Message-ID: <20230713141738.23970-11-ulf.hansson@linaro.org> (raw)
In-Reply-To: <20230713141738.23970-1-ulf.hansson@linaro.org>
To enable support for performance scaling (DVFS) for generic devices with
the SCMI performance protocol, let's add an SCMI performance domain. This
is being modelled as a genpd provider, with support for performance scaling
through genpd's ->set_performance_state() callback.
Note that, this adds the initial support that allows consumer drivers for
attached devices, to vote for a new performance state via calling the
dev_pm_genpd_set_performance_state(). However, this should be avoided as
it's in most cases preferred to use the OPP library to vote for a new OPP
instead. The support using the OPP library isn't part of this change, but
needs to be implemented from subsequent changes.
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
Changes in v2:
- Converted to use the new ->domain_info_get() callback.
---
drivers/firmware/arm_scmi/Kconfig | 12 ++
drivers/firmware/arm_scmi/Makefile | 1 +
drivers/firmware/arm_scmi/scmi_perf_domain.c | 155 +++++++++++++++++++
3 files changed, 168 insertions(+)
create mode 100644 drivers/firmware/arm_scmi/scmi_perf_domain.c
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig
index ea0f5083ac47..706d1264d038 100644
--- a/drivers/firmware/arm_scmi/Kconfig
+++ b/drivers/firmware/arm_scmi/Kconfig
@@ -181,6 +181,18 @@ config ARM_SCMI_POWER_DOMAIN
will be called scmi_pm_domain. Note this may needed early in boot
before rootfs may be available.
+config ARM_SCMI_PERF_DOMAIN
+ tristate "SCMI performance domain driver"
+ depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ default y
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCMI performance domains which can be
+ enabled or disabled via the SCP firmware.
+
+ This driver can also be built as a module. If so, the module will be
+ called scmi_perf_domain.
+
config ARM_SCMI_POWER_CONTROL
tristate "SCMI system power control driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile
index b31d78fa66cc..afee66a65dcb 100644
--- a/drivers/firmware/arm_scmi/Makefile
+++ b/drivers/firmware/arm_scmi/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
+obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
diff --git a/drivers/firmware/arm_scmi/scmi_perf_domain.c b/drivers/firmware/arm_scmi/scmi_perf_domain.c
new file mode 100644
index 000000000000..4ed2401995be
--- /dev/null
+++ b/drivers/firmware/arm_scmi/scmi_perf_domain.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCMI performance domain support.
+ *
+ * Copyright (C) 2023 Linaro Ltd.
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/scmi_protocol.h>
+#include <linux/slab.h>
+
+struct scmi_perf_domain {
+ struct generic_pm_domain genpd;
+ const struct scmi_perf_proto_ops *perf_ops;
+ const struct scmi_protocol_handle *ph;
+ const struct scmi_perf_domain_info *info;
+ u32 domain_id;
+};
+
+#define to_scmi_pd(pd) container_of(pd, struct scmi_perf_domain, genpd)
+
+static int
+scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state)
+{
+ struct scmi_perf_domain *pd = to_scmi_pd(genpd);
+ int ret;
+
+ if (!pd->info->set_perf)
+ return 0;
+
+ ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, true);
+ if (ret)
+ dev_warn(&genpd->dev, "Failed with %d when trying to set %d perf level",
+ ret, state);
+
+ return ret;
+}
+
+static int scmi_perf_domain_probe(struct scmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ const struct scmi_handle *handle = sdev->handle;
+ const struct scmi_perf_proto_ops *perf_ops;
+ struct scmi_protocol_handle *ph;
+ struct scmi_perf_domain *scmi_pd;
+ struct genpd_onecell_data *scmi_pd_data;
+ struct generic_pm_domain **domains;
+ int num_domains, i, ret = 0;
+ u32 perf_level;
+
+ if (!handle)
+ return -ENODEV;
+
+ /* The OF node must specify us as a power-domain provider. */
+ if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
+ return 0;
+
+ perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph);
+ if (IS_ERR(perf_ops))
+ return PTR_ERR(perf_ops);
+
+ num_domains = perf_ops->num_domains_get(ph);
+ if (num_domains < 0) {
+ dev_warn(dev, "Failed with %d when getting num perf domains\n",
+ num_domains);
+ return num_domains;
+ } else if (!num_domains) {
+ return 0;
+ }
+
+ scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL);
+ if (!scmi_pd)
+ return -ENOMEM;
+
+ scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL);
+ if (!scmi_pd_data)
+ return -ENOMEM;
+
+ domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < num_domains; i++, scmi_pd++) {
+ scmi_pd->info = perf_ops->domain_info_get(ph, i);
+
+ scmi_pd->domain_id = i;
+ scmi_pd->perf_ops = perf_ops;
+ scmi_pd->ph = ph;
+ scmi_pd->genpd.name = scmi_pd->info->name;
+ scmi_pd->genpd.flags = GENPD_FLAG_OPP_TABLE_FW;
+ scmi_pd->genpd.set_performance_state = scmi_pd_set_perf_state;
+
+ ret = perf_ops->level_get(ph, i, &perf_level, false);
+ if (ret) {
+ dev_dbg(dev, "Failed to get perf level for %s",
+ scmi_pd->genpd.name);
+ perf_level = 0;
+ }
+
+ /* Let the perf level indicate the power-state too. */
+ ret = pm_genpd_init(&scmi_pd->genpd, NULL, perf_level == 0);
+ if (ret)
+ goto err;
+
+ domains[i] = &scmi_pd->genpd;
+ }
+
+ scmi_pd_data->domains = domains;
+ scmi_pd_data->num_domains = num_domains;
+
+ ret = of_genpd_add_provider_onecell(dev->of_node, scmi_pd_data);
+ if (ret)
+ goto err;
+
+ dev_set_drvdata(dev, scmi_pd_data);
+ dev_info(dev, "Initialized %d performance domains", num_domains);
+ return 0;
+err:
+ for (i--; i >= 0; i--)
+ pm_genpd_remove(domains[i]);
+ return ret;
+}
+
+static void scmi_perf_domain_remove(struct scmi_device *sdev)
+{
+ struct device *dev = &sdev->dev;
+ struct genpd_onecell_data *scmi_pd_data = dev_get_drvdata(dev);
+ int i;
+
+ of_genpd_del_provider(dev->of_node);
+
+ for (i = 0; i < scmi_pd_data->num_domains; i++)
+ pm_genpd_remove(scmi_pd_data->domains[i]);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_PERF, "perf" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_perf_domain_driver = {
+ .name = "scmi-perf-domain",
+ .probe = scmi_perf_domain_probe,
+ .remove = scmi_perf_domain_remove,
+ .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_perf_domain_driver);
+
+MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org>");
+MODULE_DESCRIPTION("ARM SCMI perf domain driver");
+MODULE_LICENSE("GPL v2");
--
2.34.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2023-07-13 14:19 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-13 14:17 [PATCH v2 00/11] arm_scmi/cpufreq: Add generic performance scaling support Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 01/11] firmware: arm_scmi: Extend perf protocol ops to get number of domains Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 02/11] firmware: arm_scmi: Extend perf protocol ops to get information of a domain Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 03/11] cpufreq: scmi: Prepare to move OF parsing of domain-id to cpufreq Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 04/11] firmware: arm_scmi: Align perf ops to use domain-id as in-parameter Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 05/11] firmware: arm_scmi: Drop redundant ->device_domain_id() from perf ops Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 06/11] cpufreq: scmi: Avoid one OF parsing in scmi_get_sharing_cpus() Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 07/11] PM: domains: Allow genpd providers to manage OPP tables directly by its FW Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 08/11] dt-bindings: firmware: arm,scmi: Extend bindings for protocol@13 Ulf Hansson
2023-07-19 15:17 ` Sudeep Holla
2023-07-21 11:42 ` Ulf Hansson
2023-07-21 11:55 ` Sudeep Holla
2023-07-21 14:33 ` Rob Herring
2023-07-21 18:38 ` Sudeep Holla
[not found] ` <CAPDyKFqsaz=hruktv+sPQz-ttOtWa9O_Jvp2iLnpxQqX2r7yBQ@mail.gmail.com>
2023-08-21 14:32 ` Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 09/11] cpufreq: scmi: Add support to parse domain-id using #power-domain-cells Ulf Hansson
2023-07-19 15:24 ` Sudeep Holla
2023-07-21 11:52 ` Ulf Hansson
2023-07-21 11:59 ` Sudeep Holla
2023-07-21 14:37 ` Rob Herring
[not found] ` <CAPDyKFr9V6iPJhXXrv5RxgAE-YvXDboN5GP8E=q2VHnjs8cL5w@mail.gmail.com>
2023-08-21 14:23 ` Ulf Hansson
2023-07-13 14:17 ` Ulf Hansson [this message]
2023-07-19 14:51 ` [PATCH v2 10/11] firmware: arm_scmi: Add the SCMI performance domain Cristian Marussi
2023-07-19 15:59 ` Sudeep Holla
2023-07-21 15:19 ` Ulf Hansson
[not found] ` <ZME4MQpYd7kJmFzF@e120937-lin>
2023-07-27 11:37 ` Ulf Hansson
2023-07-13 14:17 ` [PATCH v2 11/11] cpufreq: scmi: Drop redundant ifdef in scmi_cpufreq_probe() Ulf Hansson
2023-07-19 15:32 ` Sudeep Holla
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230713141738.23970-11-ulf.hansson@linaro.org \
--to=ulf.hansson@linaro.org \
--cc=alexandre.torgue@foss.st.com \
--cc=cristian.marussi@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=nkela@quicinc.com \
--cc=nm@ti.com \
--cc=psodagud@quicinc.com \
--cc=sboyd@kernel.org \
--cc=sudeep.holla@arm.com \
--cc=vireshk@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).