U-Boot Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Charles Perry <charles.perry@microchip.com>
To: <u-boot@lists.denx.de>
Cc: Rahul Pathak <rahul@summations.net>,
	Anup Patel <anup@brainfault.org>,
	Charles Perry <charles.perry@microchip.com>,
	Tom Rini <trini@konsulko.com>,
	Jaehoon Chung <jh80.chung@samsung.com>,
	Peng Fan <peng.fan@nxp.com>,
	"Neil Armstrong" <neil.armstrong@linaro.org>,
	Simon Glass <sjg@chromium.org>,
	"Kory Maincent" <kory.maincent@bootlin.com>,
	Kuan-Wei Chiu <visitorckw@gmail.com>,
	Raymond Mao <raymond.mao@riscstar.com>,
	Quentin Schulz <quentin.schulz@cherry.de>,
	Stefan Roese <stefan.roese@mailbox.org>,
	"Jerome Forissier" <jerome.forissier@arm.com>,
	Philip Molloy <philip.molloy@analog.com>,
	Tien Fong Chee <tien.fong.chee@altera.com>,
	"Casey Connolly" <casey.connolly@linaro.org>,
	Balaji Selvanathan <balaji.selvanathan@oss.qualcomm.com>,
	Alif Zakuan Yuslaimi <alif.zakuan.yuslaimi@altera.com>,
	Sumit Garg <sumit.garg@oss.qualcomm.com>,
	"Markus Schneider-Pargmann (TI.com)" <msp@baylibre.com>,
	Marek Vasut <marek.vasut@mailbox.org>,
	Aswin Murugan <aswin.murugan@oss.qualcomm.com>
Subject: [PATCH 5/7] drivers: power: add support for RPMI power domains
Date: Fri, 26 Jun 2026 13:15:46 -0700	[thread overview]
Message-ID: <20260626201613.1035208-6-charles.perry@microchip.com> (raw)
In-Reply-To: <20260626201613.1035208-1-charles.perry@microchip.com>

The RISC-V Platform Management Interface (RPMI) defines the device power
service group [1] that is used to control power domains. This is used to
implement a UCLASS_POWER_DOMAIN driver.

[1]: https://github.com/riscv-non-isa/riscv-rpmi (chapter 4.9)

Signed-off-by: Charles Perry <charles.perry@microchip.com>
---
 MAINTAINERS                              |   1 +
 drivers/power/domain/Kconfig             |   7 +
 drivers/power/domain/Makefile            |   1 +
 drivers/power/domain/rpmi-power-domain.c | 229 +++++++++++++++++++++++
 include/rpmi_proto.h                     |  18 ++
 5 files changed, 256 insertions(+)
 create mode 100644 drivers/power/domain/rpmi-power-domain.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0bf6582ef493..d2b18d9b13db 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1694,6 +1694,7 @@ M:	Charles Perry <charles.perry@microchip.com>
 S:	Maintained
 F:	drivers/clk/clk_rpmi.c
 F:	drivers/firmware/rpmi/
+F:	drivers/power/domain/rpmi-power-domain.c
 F:	include/rpmi*
 
 SANDBOX
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 4112b777371d..e8484b193cad 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -106,6 +106,13 @@ config RENESAS_R8A78000_POWER_DOMAIN
 	  and reset driver. The MDLC is responsible for managing both
 	  power domains and resets on R-Car R8A78000 X5H SoC.
 
+config RPMI_POWER_DOMAIN
+	bool "Enable the RPMI Power domain driver"
+	depends on POWER_DOMAIN && RPMI_FIRMWARE
+	help
+	  Enable this option if you want to support power domains managed by
+	  the RISC-V Platform Management Interface (RPMI) protocol.
+
 config SANDBOX_POWER_DOMAIN
 	bool "Enable the sandbox power domain test driver"
 	depends on POWER_DOMAIN && SANDBOX
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 110153d5cf81..9c42160e18be 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
 obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o
 obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o
 obj-$(CONFIG_RENESAS_R8A78000_POWER_DOMAIN) += renesas-r8a78000-power-domain.o
+obj-$(CONFIG_RPMI_POWER_DOMAIN) += rpmi-power-domain.o
 obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
 obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
 obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o
diff --git a/drivers/power/domain/rpmi-power-domain.c b/drivers/power/domain/rpmi-power-domain.c
new file mode 100644
index 000000000000..f00ebab86686
--- /dev/null
+++ b/drivers/power/domain/rpmi-power-domain.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Microchip Technology Inc. All rights reserved.
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <power-domain.h>
+#include <power-domain-uclass.h>
+#include <rpmi.h>
+#include <dm/device_compat.h>
+
+struct rpmi_get_num_pd_rx {
+	__le32 status;
+	__le32 num_pd;
+};
+
+struct rpmi_get_attrs_tx {
+	__le32 pd_id;
+};
+
+struct rpmi_get_attrs_rx {
+	__le32 status;
+	__le32 flags;
+	__le32 trans_latency;
+	char name[RPMI_DPWR_NAME_LEN];
+};
+
+struct rpmi_set_state_tx {
+	__le32 pd_id;
+	__le32 state;
+};
+
+struct rpmi_set_state_rx {
+	__le32 status;
+};
+
+struct rpmi_pd_def {
+	u32 transition_latency;
+	char name[RPMI_DPWR_NAME_LEN + 1];
+};
+
+struct rpmi_pd_priv {
+	struct rpmi_chan chan;
+	struct udevice *dev;
+	u32 num_pd;
+	struct rpmi_pd_def *defs;
+};
+
+static int rpmi_pd_get_attrs(struct rpmi_pd_priv *priv, u32 pd_id,
+			     struct rpmi_pd_def *def)
+{
+	struct rpmi_get_attrs_tx tx = {
+		.pd_id = cpu_to_le32(pd_id),
+	};
+	struct rpmi_get_attrs_rx rx;
+	int ret, status;
+
+	ret = rpmi_send_with_resp(&priv->chan, RPMI_DPWR_SRV_GET_ATTRIBUTES,
+				  &tx, sizeof(tx), &rx, sizeof(rx), NULL);
+	if (ret)
+		return ret;
+
+	status = le32_to_cpu(rx.status);
+	if (status)
+		return rpmi_to_linux_error(status);
+
+	def->transition_latency = le32_to_cpu(rx.trans_latency);
+	memcpy(def->name, rx.name, RPMI_DPWR_NAME_LEN);
+	def->name[RPMI_DPWR_NAME_LEN] = '\0';
+
+	return 0;
+}
+
+static int rpmi_pd_set_state(struct rpmi_pd_priv *priv, u32 pd_id, u32 state)
+{
+	struct rpmi_set_state_tx tx = {
+		.pd_id = cpu_to_le32(pd_id),
+		.state = cpu_to_le32(state),
+	};
+	struct rpmi_set_state_rx rx;
+	int ret, status;
+
+	ret = rpmi_send_with_resp(&priv->chan, RPMI_DPWR_SRV_SET_DPWR_STATE,
+				  &tx, sizeof(tx), &rx, sizeof(rx), NULL);
+
+	if (ret)
+		return ret;
+
+	status = le32_to_cpu(rx.status);
+	if (status)
+		return rpmi_to_linux_error(status);
+
+	return 0;
+}
+
+static int rpmi_power_domain_on(struct power_domain *power_domain)
+{
+	return rpmi_pd_set_state(dev_get_plat(power_domain->dev),
+				 power_domain->id, RPMI_DPWR_STATE_ON);
+}
+
+static int rpmi_power_domain_off(struct power_domain *power_domain)
+{
+	return rpmi_pd_set_state(dev_get_plat(power_domain->dev),
+				 power_domain->id, RPMI_DPWR_STATE_OFF);
+}
+
+static int rpmi_power_domain_xlate(struct power_domain *power_domain,
+				   struct ofnode_phandle_args *args)
+{
+	struct rpmi_pd_priv *priv = dev_get_plat(power_domain->dev);
+
+	if (args->args_count != 1)
+		return -EINVAL;
+
+	if (args->args[0] >= priv->num_pd)
+		return -EINVAL;
+
+	power_domain->id = args->args[0];
+
+	return 0;
+}
+
+static int rpmi_pd_get_num_domains(struct rpmi_pd_priv *priv)
+{
+	struct rpmi_get_num_pd_rx rx;
+	int ret, status;
+
+	ret = rpmi_send_with_resp(&priv->chan, RPMI_DPWR_SRV_GET_NUM_DOMAINS,
+				  NULL, 0, &rx, sizeof(rx), NULL);
+	if (ret)
+		return ret;
+
+	status = le32_to_cpu(rx.status);
+	if (status)
+		return rpmi_to_linux_error(status);
+
+	priv->num_pd = le32_to_cpu(rx.num_pd);
+
+	return 0;
+}
+
+static int rpmi_pd_probe(struct udevice *dev)
+{
+	struct rpmi_pd_priv *priv = (struct rpmi_pd_priv *)dev_get_plat(dev);
+	struct rpmi_chan *chan = &priv->chan;
+	int ret, i;
+
+	priv->dev = dev;
+
+	ret = rpmi_open(chan);
+	if (ret)
+		return ret;
+
+	ret = rpmi_check_versions(chan, RPMI_MKVER(1, 0),
+				  RPMI_SRVGRP_DEVICE_POWER, RPMI_MKVER(1, 0));
+	if (ret)
+		goto err_out;
+
+	ret = rpmi_pd_get_num_domains(priv);
+	if (ret)
+		goto err_out;
+
+	priv->defs = calloc(priv->num_pd, sizeof(struct rpmi_pd_def));
+	if (!priv->defs) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	for (i = 0; i < priv->num_pd; i++) {
+		ret = rpmi_pd_get_attrs(priv, i, &priv->defs[i]);
+		if (ret)
+			goto err_out;
+	}
+
+	dev_dbg(dev, "num pd = %i\n", priv->num_pd);
+
+	return 0;
+
+err_out:
+	if (priv->defs)
+		free(priv->defs);
+	rpmi_close(chan);
+
+	return ret;
+}
+
+static int rpmi_pd_remove(struct udevice *dev)
+{
+	struct rpmi_pd_priv *priv = (struct rpmi_pd_priv *)dev_get_plat(dev);
+	struct rpmi_chan *chan = &priv->chan;
+
+	if (priv->defs)
+		free(priv->defs);
+	rpmi_close(chan);
+
+	return 0;
+}
+
+static int rpmi_pd_to_plat(struct udevice *dev)
+{
+	struct rpmi_pd_priv *priv = (struct rpmi_pd_priv *)dev_get_plat(dev);
+
+	return rpmi_get_by_index(dev, 0, &priv->chan);
+}
+
+static const struct power_domain_ops rpmi_pd_ops = {
+	.of_xlate = rpmi_power_domain_xlate,
+	.on = rpmi_power_domain_on,
+	.off = rpmi_power_domain_off,
+};
+
+static const struct udevice_id rpmi_pd_ids[] = {
+	{ .compatible = "riscv,rpmi-device-power" },
+	{}
+};
+
+U_BOOT_DRIVER(rpmi_pd) = {
+	.name = "rpmi-device-power",
+	.id = UCLASS_POWER_DOMAIN,
+	.of_match = rpmi_pd_ids,
+	.probe = rpmi_pd_probe,
+	.remove = rpmi_pd_remove,
+	.ops = &rpmi_pd_ops,
+	.of_to_plat = rpmi_pd_to_plat,
+	.plat_auto = sizeof(struct rpmi_pd_priv),
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/include/rpmi_proto.h b/include/rpmi_proto.h
index dc0937ce7053..d2512617f75c 100644
--- a/include/rpmi_proto.h
+++ b/include/rpmi_proto.h
@@ -122,4 +122,22 @@ enum rpmi_clock_type {
 
 #define RPMI_CLOCK_RATE_INVALID		(-1ULL)
 
+/* RPMI Device_Power (DPWR) service IDs */
+enum rpmi_dpwr_service_id {
+	RPMI_DPWR_SRV_ENABLE_NOTIFICATION = 0x01,
+	RPMI_DPWR_SRV_GET_NUM_DOMAINS = 0x02,
+	RPMI_DPWR_SRV_GET_ATTRIBUTES = 0x03,
+	RPMI_DPWR_SRV_SET_DPWR_STATE = 0x04,
+	RPMI_DPWR_SRV_GET_DPWR_STATE = 0x05,
+	RPMI_DPWR_SRV_ID_MAX,
+};
+
+enum rpmi_dpwr_state {
+	RPMI_DPWR_STATE_INVALID = -1,
+	RPMI_DPWR_STATE_ON = 0,
+	RPMI_DPWR_STATE_OFF = 3,
+};
+
+#define RPMI_DPWR_NAME_LEN 16
+
 #endif
-- 
2.47.3


  parent reply	other threads:[~2026-06-26 21:21 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-26 20:15 [PATCH 0/7] Add support for RPMI to U-Boot Charles Perry
2026-06-26 20:15 ` [PATCH 1/7] firmware: add support for RPMI Charles Perry
2026-06-27  1:09   ` Yao Zi
2026-06-26 20:15 ` [PATCH 2/7] firmware: rpmi: add support for the SBI MPXY transport Charles Perry
2026-06-27  1:30   ` Yao Zi
2026-06-26 20:15 ` [PATCH 3/7] firmware: rpmi: add support for shared memory transport Charles Perry
2026-06-26 20:15 ` [PATCH 4/7] drivers: clk: add support for RPMI clocks Charles Perry
2026-06-27  1:47   ` Yao Zi
2026-06-26 20:15 ` Charles Perry [this message]
2026-06-26 20:15 ` [PATCH 6/7] firmware: rpmi: add a test and a sandbox driver Charles Perry
2026-06-26 20:15 ` [PATCH 7/7] firmware: rpmi: add a test and sandbox for device power Charles Perry

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=20260626201613.1035208-6-charles.perry@microchip.com \
    --to=charles.perry@microchip.com \
    --cc=alif.zakuan.yuslaimi@altera.com \
    --cc=anup@brainfault.org \
    --cc=aswin.murugan@oss.qualcomm.com \
    --cc=balaji.selvanathan@oss.qualcomm.com \
    --cc=casey.connolly@linaro.org \
    --cc=jerome.forissier@arm.com \
    --cc=jh80.chung@samsung.com \
    --cc=kory.maincent@bootlin.com \
    --cc=marek.vasut@mailbox.org \
    --cc=msp@baylibre.com \
    --cc=neil.armstrong@linaro.org \
    --cc=peng.fan@nxp.com \
    --cc=philip.molloy@analog.com \
    --cc=quentin.schulz@cherry.de \
    --cc=rahul@summations.net \
    --cc=raymond.mao@riscstar.com \
    --cc=sjg@chromium.org \
    --cc=stefan.roese@mailbox.org \
    --cc=sumit.garg@oss.qualcomm.com \
    --cc=tien.fong.chee@altera.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=visitorckw@gmail.com \
    /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