lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <20260108-sifive-pd-drivers-v4-3-2a523d7d51a0@sifive.com>
Date: Thu, 08 Jan 2026 00:58:26 -0800
From: Nick Hu <nick.hu@...ive.com>
To: "Rafael J. Wysocki" <rafael@...nel.org>, 
 Daniel Lezcano <daniel.lezcano@...aro.org>, Paul Walmsley <pjw@...nel.org>, 
 Palmer Dabbelt <palmer@...belt.com>, Albert Ou <aou@...s.berkeley.edu>, 
 Alexandre Ghiti <alex@...ti.fr>, Anup Patel <anup@...infault.org>, 
 Samuel Holland <samuel.holland@...ive.com>, Rob Herring <robh@...nel.org>, 
 Krzysztof Kozlowski <krzk+dt@...nel.org>, 
 Conor Dooley <conor+dt@...nel.org>, Cyan Yang <cyan.yang@...ive.com>, 
 Nick Hu <nick.hu@...ive.com>
Cc: linux-kernel@...r.kernel.org, linux-pm@...r.kernel.org, 
 linux-riscv@...ts.infradead.org, devicetree@...r.kernel.org
Subject: [PATCH v4 3/3] cpuidle: Add SiFive power provider driver

The SiFive DMC is the power provider of the devices that inside the
SiFive CPU power domains, which include Tile, Cluster and Core Complex
power domains. Before the cpu entering the firmware-based idle state,
each devices that inside the corresponding domain should be suspended
properly. this driver will create the power provider and set the correct
domain idle state.

Signed-off-by: Nick Hu <nick.hu@...ive.com>
---
 drivers/cpuidle/Kconfig.riscv               |  12 +++
 drivers/cpuidle/Makefile                    |   1 +
 drivers/cpuidle/cpuidle-sifive-dmc-domain.c | 124 ++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+)

diff --git a/drivers/cpuidle/Kconfig.riscv b/drivers/cpuidle/Kconfig.riscv
index b813018ce401..2fe0912f8027 100644
--- a/drivers/cpuidle/Kconfig.riscv
+++ b/drivers/cpuidle/Kconfig.riscv
@@ -22,3 +22,15 @@ config RISCV_SBI_CPUIDLE_DOMAIN
 	  Select this option to enable RISC-V SBI firmware based CPU idle
 	  driver to use PM domains, which is needed to support the hierarchical
 	  DT based layout of the idle state.
+
+config SIFIVE_DMC_CPUIDLE_DOMAIN
+	bool "SiFive DMC CPU idle Domain"
+	depends on ARCH_SIFIVE
+	depends on RISCV_SBI_CPUIDLE
+	depends on PM_GENERIC_DOMAINS_OF
+	select DT_IDLE_GENPD
+	default y
+	help
+	  Select this option to enable RISC-V SBI firmware based CPU idle
+	  driver to use PM domains on SiFive Platforms, which is needed to
+	  support the hierarchical DT based layout of the idle state.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 82595849b75d..eead4c049414 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_POWERNV_CPUIDLE)		+= cpuidle-powernv.o
 # RISC-V drivers
 obj-$(CONFIG_RISCV_SBI_CPUIDLE)		+= cpuidle-riscv-sbi.o
 obj-$(CONFIG_RISCV_SBI_CPUIDLE_DOMAIN)	+= cpuidle-riscv-sbi-domain.o
+obj-$(CONFIG_SIFIVE_DMC_CPUIDLE_DOMAIN)	+= cpuidle-sifive-dmc-domain.o
diff --git a/drivers/cpuidle/cpuidle-sifive-dmc-domain.c b/drivers/cpuidle/cpuidle-sifive-dmc-domain.c
new file mode 100644
index 000000000000..5174bc525a13
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-sifive-dmc-domain.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SiFive CPUIDLE DMC driver
+ */
+
+#define pr_fmt(fmt) "sifive_dmc_cpuidle_domain: " fmt
+
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include "cpuidle-riscv-sbi.h"
+#include "dt_idle_genpd.h"
+
+static bool use_osi = true;
+
+static int sifive_cpuidle_dmc_power_off(struct generic_pm_domain *pd)
+{
+	struct genpd_power_state *state = &pd->states[pd->state_idx];
+	u32 *pd_state;
+
+	if (!state->data)
+		return 0;
+
+	/* OSI mode is enabled, set the corresponding domain state. */
+	pd_state = state->data;
+	sbi_set_domain_state(*pd_state);
+
+	return 0;
+}
+
+static int sifive_dmc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct of_phandle_args child, parent;
+	struct device *dev = &pdev->dev;
+	struct generic_pm_domain *pd;
+	int ret = -ENOMEM;
+
+	pd = dt_idle_pd_alloc(np, sbi_dt_parse_state_node);
+	if (!pd)
+		goto out;
+
+	pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
+	if (use_osi)
+		pd->power_off = sifive_cpuidle_dmc_power_off;
+	else
+		pd->flags |= GENPD_FLAG_ALWAYS_ON;
+
+	ret = pm_genpd_init(pd, &pm_domain_cpu_gov, false);
+	if (ret)
+		goto free_pd;
+
+	ret = of_genpd_add_provider_simple(np, pd);
+	if (ret)
+		goto remove_pd;
+
+	if (!of_parse_phandle_with_args(np, "power-domains", "#power-domain-cells", 0, &parent)) {
+		child.np = np;
+		child.args_count = 0;
+
+		ret = of_genpd_add_subdomain(&parent, &child);
+		of_node_put(parent.np);
+		if (ret) {
+			pr_err("%pOF failed to add subdomain: %pOF\n", parent.np, child.np);
+			goto remove_pd;
+		}
+	}
+
+	pm_runtime_enable(dev);
+	pr_info("init PM domain %s\n", dev_name(dev));
+	return 0;
+
+remove_pd:
+	pm_genpd_remove(pd);
+free_pd:
+	dt_idle_pd_free(pd);
+out:
+	pr_err("failed to init PM domain ret=%d %pOF\n", ret, np);
+	return ret;
+}
+
+static const struct of_device_id sifive_dmc_of_match[] = {
+	{ .compatible = "sifive,tmc1", },
+	{ .compatible = "sifive,tmc0", },
+	{ .compatible = "sifive,smc1", },
+	{ .compatible = "sifive,smc0", },
+	{ .compatible = "sifive,cmc2", },
+	{}
+};
+
+static struct platform_driver sifive_dmc_driver = {
+	.probe = sifive_dmc_probe,
+	.driver = {
+		.name = "sifive_dmc",
+		.of_match_table = sifive_dmc_of_match,
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init sifive_dmc_domain_init(void)
+{
+	int cpu;
+
+	/* Detect OSI support based on CPU DT nodes */
+	for_each_possible_cpu(cpu) {
+		struct device_node *np __free(device_node) = of_cpu_device_node_get(cpu);
+		if (np &&
+		    of_property_present(np, "power-domains") &&
+		    of_property_present(np, "power-domain-names")) {
+			continue;
+		} else {
+			use_osi = false;
+			break;
+		}
+	}
+
+	sbi_set_osi_mode(use_osi);
+
+	/* Only probe the DMCs when OSI supported */
+	return platform_driver_register(&sifive_dmc_driver);
+}
+core_initcall(sifive_dmc_domain_init);

-- 
2.43.7


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ