* [PATCH v3 0/3] Add RISC-V RPMI device power service support
@ 2026-09-03 9:23 ` Joshua Yeong
0 siblings, 0 replies; 12+ messages in thread
From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw)
To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw,
palmer, aou
Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree,
linux-kernel
The RISC-V Platform Management Interface (RPMI) specification defines a
modular and extensible messaging protocol between the supervisor software
and a platform microcontroller (PuC). Among the service groups it defines
is the device power service group (service group ID 0x00009), which allows
the supervisor to enumerate the power domains of platform devices managed
by the PuC, query their attributes, and get/set their power state.
This series adds supervisor-side support for that service group:
- DT bindings for the power domain controller exposed to the supervisor
("riscv,rpmi-device-power") and for the SBI MPXY channel that the SBI
implementation uses to expose the service group to the supervisor
("riscv,rpmi-mpxy-device-power").
- A generic power domain (genpd) provider driver under
drivers/pmdomain/riscv/ which talks to the PuC over an SBI MPXY
mailbox channel. At probe it queries GET_NUM_DOMAINS, then for each
domain queries GET_ATTRS for the name and transition latency and
GET_STATE for the initial state, and registers the whole set as a
onecell genpd provider. Domain power on/off is driven through
SET_STATE with the generic ON/OFF power state parameters, so devices
can simply reference a domain through the "power-domains" property.
The series is based on the existing RISC-V RPMI/MPXY infrastructure
already present in the tree (drivers/mailbox/riscv-sbi-mpxy-mbox.c and
include/linux/mailbox/riscv-rpmi-message.h), and only adds the device
power service group definitions on top of it.
Changes in v3:
- Move the MAINTAINERS change into its own patch, and add a new
"RISC-V RPMI DEVICE POWER DRIVER" section scoped to this driver and
its bindings instead of adding an M: entry to the existing "RISC-V
RPMI AND MPXY DRIVERS" section, which covers drivers maintained by
others.
- Drop the redundant trailing "bindings" from the dt-bindings subject.
- Compare only the value field of the RPMI power state word. The word
also carries a context bit, so a full word comparison would report
-EIO after a successful transition, and would drop a domain at probe,
whenever the PuC reports context as lost.
- Check the pm_genpd_init() return value and leave a failed domain out
of the onecell array. Every failure path in pm_genpd_init() returns
before the genpd is linked into gpd_list, so the previous code could
hand a half initialised genpd to of_genpd_add_provider_onecell() and
then list_del() an uninitialised list head in the unwind loop.
- Set GENPD_FLAG_DEV_NAME_FW. The domain names come from the PuC and
are not guaranteed to be unique or non-empty, and were used verbatim
as the sysfs and debugfs names, where a duplicate fails device_add()
with -EEXIST and takes down the whole provider.
v1: https://lore.kernel.org/r/20260829205520.1691-1-joshua.yeong@starfivetech.com
v2: https://lore.kernel.org/r/20260830152812.312663-1-joshua.yeong@starfivetech.com
Testing
=======
The series was tested under QEMU with the RPMI device power service
implemented in firmware.
Components:
- OpenSBI: latest master branch
https://github.com/riscv-software-src/opensbi
- QEMU: the RPMI-enabled tree at
https://github.com/yeongjoshua/qemu/tree/rpmi-v11.1.0
Kernel config: enable CONFIG_RISCV_RPMI_DEVICE_POWER (default y on RISC-V
when MAILBOX is enabled) along with the SBI MPXY mailbox driver.
Run with:
qemu-system-riscv64 \
-M virt -m 2G -smp 4 \
-bios fw_dynamic.bin \
-kernel Image \
-M rpmi=true \
-nographic \
-initrd rootfs-busybox.cpio \
-append "root=/dev/ram rw console=ttyS0,115200 no_console_suspend mem=2048M earlycon=uart8250,mmio,0x10000000"
The RPMI device power domains advertised by the emulated platform
microcontroller show up as generic power domains and can be inspected
through /sys/kernel/debug/pm_genpd/. The series was additionally booted
with CONFIG_PROVE_LOCKING, CONFIG_DEBUG_MUTEXES and
CONFIG_DEBUG_ATOMIC_SLEEP enabled, with no lockdep reports.
Joshua Yeong (3):
dt-bindings: power: Add RPMI device power service
pmdomain: riscv: Add RPMI device power service
MAINTAINERS: Add RISC-V RPMI device power driver
.../power/riscv,rpmi-device-power.yaml | 65 +++
.../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++
MAINTAINERS | 8 +
drivers/pmdomain/Kconfig | 1 +
drivers/pmdomain/Makefile | 1 +
drivers/pmdomain/riscv/Kconfig | 15 +
drivers/pmdomain/riscv/Makefile | 3 +
.../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++
include/linux/mailbox/riscv-rpmi-message.h | 11 +
9 files changed, 654 insertions(+)
create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml
create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml
create mode 100644 drivers/pmdomain/riscv/Kconfig
create mode 100644 drivers/pmdomain/riscv/Makefile
create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c
base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v3 0/3] Add RISC-V RPMI device power service support @ 2026-09-03 9:23 ` Joshua Yeong 0 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel The RISC-V Platform Management Interface (RPMI) specification defines a modular and extensible messaging protocol between the supervisor software and a platform microcontroller (PuC). Among the service groups it defines is the device power service group (service group ID 0x00009), which allows the supervisor to enumerate the power domains of platform devices managed by the PuC, query their attributes, and get/set their power state. This series adds supervisor-side support for that service group: - DT bindings for the power domain controller exposed to the supervisor ("riscv,rpmi-device-power") and for the SBI MPXY channel that the SBI implementation uses to expose the service group to the supervisor ("riscv,rpmi-mpxy-device-power"). - A generic power domain (genpd) provider driver under drivers/pmdomain/riscv/ which talks to the PuC over an SBI MPXY mailbox channel. At probe it queries GET_NUM_DOMAINS, then for each domain queries GET_ATTRS for the name and transition latency and GET_STATE for the initial state, and registers the whole set as a onecell genpd provider. Domain power on/off is driven through SET_STATE with the generic ON/OFF power state parameters, so devices can simply reference a domain through the "power-domains" property. The series is based on the existing RISC-V RPMI/MPXY infrastructure already present in the tree (drivers/mailbox/riscv-sbi-mpxy-mbox.c and include/linux/mailbox/riscv-rpmi-message.h), and only adds the device power service group definitions on top of it. Changes in v3: - Move the MAINTAINERS change into its own patch, and add a new "RISC-V RPMI DEVICE POWER DRIVER" section scoped to this driver and its bindings instead of adding an M: entry to the existing "RISC-V RPMI AND MPXY DRIVERS" section, which covers drivers maintained by others. - Drop the redundant trailing "bindings" from the dt-bindings subject. - Compare only the value field of the RPMI power state word. The word also carries a context bit, so a full word comparison would report -EIO after a successful transition, and would drop a domain at probe, whenever the PuC reports context as lost. - Check the pm_genpd_init() return value and leave a failed domain out of the onecell array. Every failure path in pm_genpd_init() returns before the genpd is linked into gpd_list, so the previous code could hand a half initialised genpd to of_genpd_add_provider_onecell() and then list_del() an uninitialised list head in the unwind loop. - Set GENPD_FLAG_DEV_NAME_FW. The domain names come from the PuC and are not guaranteed to be unique or non-empty, and were used verbatim as the sysfs and debugfs names, where a duplicate fails device_add() with -EEXIST and takes down the whole provider. v1: https://lore.kernel.org/r/20260829205520.1691-1-joshua.yeong@starfivetech.com v2: https://lore.kernel.org/r/20260830152812.312663-1-joshua.yeong@starfivetech.com Testing ======= The series was tested under QEMU with the RPMI device power service implemented in firmware. Components: - OpenSBI: latest master branch https://github.com/riscv-software-src/opensbi - QEMU: the RPMI-enabled tree at https://github.com/yeongjoshua/qemu/tree/rpmi-v11.1.0 Kernel config: enable CONFIG_RISCV_RPMI_DEVICE_POWER (default y on RISC-V when MAILBOX is enabled) along with the SBI MPXY mailbox driver. Run with: qemu-system-riscv64 \ -M virt -m 2G -smp 4 \ -bios fw_dynamic.bin \ -kernel Image \ -M rpmi=true \ -nographic \ -initrd rootfs-busybox.cpio \ -append "root=/dev/ram rw console=ttyS0,115200 no_console_suspend mem=2048M earlycon=uart8250,mmio,0x10000000" The RPMI device power domains advertised by the emulated platform microcontroller show up as generic power domains and can be inspected through /sys/kernel/debug/pm_genpd/. The series was additionally booted with CONFIG_PROVE_LOCKING, CONFIG_DEBUG_MUTEXES and CONFIG_DEBUG_ATOMIC_SLEEP enabled, with no lockdep reports. Joshua Yeong (3): dt-bindings: power: Add RPMI device power service pmdomain: riscv: Add RPMI device power service MAINTAINERS: Add RISC-V RPMI device power driver .../power/riscv,rpmi-device-power.yaml | 65 +++ .../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++ MAINTAINERS | 8 + drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/riscv/Kconfig | 15 + drivers/pmdomain/riscv/Makefile | 3 + .../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++ include/linux/mailbox/riscv-rpmi-message.h | 11 + 9 files changed, 654 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml create mode 100644 drivers/pmdomain/riscv/Kconfig create mode 100644 drivers/pmdomain/riscv/Makefile create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f -- 2.43.0 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 1/3] dt-bindings: power: Add RPMI device power service 2026-09-03 9:23 ` Joshua Yeong @ 2026-09-03 9:23 ` Joshua Yeong -1 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add device tree bindings for the RISC-V Platform Management Interface (RPMI) device power service group, both for the supervisor-facing power domain controller and for the SBI MPXY channel which the SBI implementation uses to expose the service group. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- .../power/riscv,rpmi-device-power.yaml | 65 +++++++++++++++++++ .../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml diff --git a/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml b/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml new file mode 100644 index 000000000000..5afdc40df7e0 --- /dev/null +++ b/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/riscv,rpmi-device-power.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI device power service group based power domain controller + +maintainers: + - Joshua Yeong <joshua.yeong@starfivetech.com> + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines device power service group for + accessing and controlling the power state of platform devices managed + by a platform microcontroller. The supervisor software can access RPMI + device power service group via SBI MPXY channel or some dedicated + supervisor-mode RPMI transport. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the supervisor software. + const: riscv,rpmi-device-power + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport or SBI message proxy channel. + + "#power-domain-cells": + const: 1 + description: + Platform specific DOMAIN_ID as defined by the RISC-V Platform Management + Interface (RPMI) specification. + +required: + - compatible + - mboxes + - "#power-domain-cells" + +additionalProperties: false + +examples: + - | + power-controller { + compatible = "riscv,rpmi-device-power"; + mboxes = <&mpxy_mbox 0x1002 0x0>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml b/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml new file mode 100644 index 000000000000..2b7df66ba172 --- /dev/null +++ b/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/riscv,rpmi-mpxy-device-power.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI device power service group based message proxy + +maintainers: + - Joshua Yeong <joshua.yeong@starfivetech.com> + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines device power service group for + accessing and controlling the power state of platform devices managed + by a platform microcontroller. The SBI implementation (machine mode + firmware or hypervisor) can implement an SBI MPXY channel to allow RPMI + device power service group access to the supervisor software. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the SBI implementation. + const: riscv,rpmi-mpxy-device-power + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport. + + riscv,sbi-mpxy-channel-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The SBI MPXY channel id to be used for providing RPMI access to + the supervisor software. + +required: + - compatible + - mboxes + - riscv,sbi-mpxy-channel-id + +additionalProperties: false + +examples: + - | + device-power-service { + compatible = "riscv,rpmi-mpxy-device-power"; + mboxes = <&rpmi_shmem_mbox 0x9>; + riscv,sbi-mpxy-channel-id = <0x1002>; + }; +... -- 2.43.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 1/3] dt-bindings: power: Add RPMI device power service @ 2026-09-03 9:23 ` Joshua Yeong 0 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add device tree bindings for the RISC-V Platform Management Interface (RPMI) device power service group, both for the supervisor-facing power domain controller and for the SBI MPXY channel which the SBI implementation uses to expose the service group. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- .../power/riscv,rpmi-device-power.yaml | 65 +++++++++++++++++++ .../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml diff --git a/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml b/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml new file mode 100644 index 000000000000..5afdc40df7e0 --- /dev/null +++ b/Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/riscv,rpmi-device-power.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI device power service group based power domain controller + +maintainers: + - Joshua Yeong <joshua.yeong@starfivetech.com> + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines device power service group for + accessing and controlling the power state of platform devices managed + by a platform microcontroller. The supervisor software can access RPMI + device power service group via SBI MPXY channel or some dedicated + supervisor-mode RPMI transport. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the supervisor software. + const: riscv,rpmi-device-power + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport or SBI message proxy channel. + + "#power-domain-cells": + const: 1 + description: + Platform specific DOMAIN_ID as defined by the RISC-V Platform Management + Interface (RPMI) specification. + +required: + - compatible + - mboxes + - "#power-domain-cells" + +additionalProperties: false + +examples: + - | + power-controller { + compatible = "riscv,rpmi-device-power"; + mboxes = <&mpxy_mbox 0x1002 0x0>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml b/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml new file mode 100644 index 000000000000..2b7df66ba172 --- /dev/null +++ b/Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/riscv,rpmi-mpxy-device-power.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V RPMI device power service group based message proxy + +maintainers: + - Joshua Yeong <joshua.yeong@starfivetech.com> + +description: | + The RISC-V Platform Management Interface (RPMI) [1] defines a + messaging protocol which is modular and extensible. The supervisor + software can send/receive RPMI messages via SBI MPXY extension [2] + or some dedicated supervisor-mode RPMI transport. + + The RPMI specification [1] defines device power service group for + accessing and controlling the power state of platform devices managed + by a platform microcontroller. The SBI implementation (machine mode + firmware or hypervisor) can implement an SBI MPXY channel to allow RPMI + device power service group access to the supervisor software. + + =========================================== + References + =========================================== + + [1] RISC-V Platform Management Interface (RPMI) v1.0 (or higher) + https://github.com/riscv-non-isa/riscv-rpmi/releases + + [2] RISC-V Supervisor Binary Interface (SBI) v3.0 (or higher) + https://github.com/riscv-non-isa/riscv-sbi-doc/releases + +properties: + compatible: + description: + Intended for use by the SBI implementation. + const: riscv,rpmi-mpxy-device-power + + mboxes: + maxItems: 1 + description: + Mailbox channel of the underlying RPMI transport. + + riscv,sbi-mpxy-channel-id: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The SBI MPXY channel id to be used for providing RPMI access to + the supervisor software. + +required: + - compatible + - mboxes + - riscv,sbi-mpxy-channel-id + +additionalProperties: false + +examples: + - | + device-power-service { + compatible = "riscv,rpmi-mpxy-device-power"; + mboxes = <&rpmi_shmem_mbox 0x9>; + riscv,sbi-mpxy-channel-id = <0x1002>; + }; +... -- 2.43.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: power: Add RPMI device power service 2026-09-03 9:23 ` Joshua Yeong @ 2026-09-03 17:22 ` Conor Dooley -1 siblings, 0 replies; 12+ messages in thread From: Conor Dooley @ 2026-09-03 17:22 UTC (permalink / raw) To: Joshua Yeong Cc: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou, alex, linux-riscv, linux-pm, devicetree, linux-kernel [-- Attachment #1: Type: text/plain, Size: 476 bytes --] On Thu, Sep 03, 2026 at 05:23:45PM +0800, Joshua Yeong wrote: > Add device tree bindings for the RISC-V Platform Management Interface > (RPMI) device power service group, both for the supervisor-facing power > domain controller and for the SBI MPXY channel which the SBI > implementation uses to expose the service group. > > Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> Reviewed-by: Conor Dooley <conor.dooley@microchip.com> pw-bot: not-applicable [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/3] dt-bindings: power: Add RPMI device power service @ 2026-09-03 17:22 ` Conor Dooley 0 siblings, 0 replies; 12+ messages in thread From: Conor Dooley @ 2026-09-03 17:22 UTC (permalink / raw) To: Joshua Yeong Cc: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou, alex, linux-riscv, linux-pm, devicetree, linux-kernel [-- Attachment #1.1: Type: text/plain, Size: 476 bytes --] On Thu, Sep 03, 2026 at 05:23:45PM +0800, Joshua Yeong wrote: > Add device tree bindings for the RISC-V Platform Management Interface > (RPMI) device power service group, both for the supervisor-facing power > domain controller and for the SBI MPXY channel which the SBI > implementation uses to expose the service group. > > Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> Reviewed-by: Conor Dooley <conor.dooley@microchip.com> pw-bot: not-applicable [-- Attachment #1.2: signature.asc --] [-- Type: application/pgp-signature, Size: 228 bytes --] [-- Attachment #2: Type: text/plain, Size: 161 bytes --] _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] pmdomain: riscv: Add RPMI device power service 2026-09-03 9:23 ` Joshua Yeong @ 2026-09-03 9:23 ` Joshua Yeong -1 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add a generic power domain provider on top of the RISC-V Platform Management Interface (RPMI) device power service group, reached through an SBI MPXY channel. The driver enumerates the device power domains advertised by the platform microcontroller, queries their attributes and initial state, and registers them as an onecell genpd provider so that devices can reference them through the "power-domains" property. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/riscv/Kconfig | 15 + drivers/pmdomain/riscv/Makefile | 3 + .../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++ include/linux/mailbox/riscv-rpmi-message.h | 11 + 6 files changed, 516 insertions(+) create mode 100644 drivers/pmdomain/riscv/Kconfig create mode 100644 drivers/pmdomain/riscv/Makefile create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig index 23076ae90e66..5341dff669be 100644 --- a/drivers/pmdomain/Kconfig +++ b/drivers/pmdomain/Kconfig @@ -11,6 +11,7 @@ source "drivers/pmdomain/marvell/Kconfig" source "drivers/pmdomain/mediatek/Kconfig" source "drivers/pmdomain/qcom/Kconfig" source "drivers/pmdomain/renesas/Kconfig" +source "drivers/pmdomain/riscv/Kconfig" source "drivers/pmdomain/rockchip/Kconfig" source "drivers/pmdomain/samsung/Kconfig" source "drivers/pmdomain/st/Kconfig" diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile index ebc802f13eb9..d7aee13ae571 100644 --- a/drivers/pmdomain/Makefile +++ b/drivers/pmdomain/Makefile @@ -9,6 +9,7 @@ obj-y += marvell/ obj-y += mediatek/ obj-y += qcom/ obj-y += renesas/ +obj-y += riscv/ obj-y += rockchip/ obj-y += samsung/ obj-y += st/ diff --git a/drivers/pmdomain/riscv/Kconfig b/drivers/pmdomain/riscv/Kconfig new file mode 100644 index 000000000000..97232edc294a --- /dev/null +++ b/drivers/pmdomain/riscv/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config RISCV_RPMI_DEVICE_POWER + bool "RISC-V RPMI Based Device Power driver" + depends on RISCV || COMPILE_TEST + depends on MAILBOX + depends on PM + default RISCV + select PM_GENERIC_DOMAINS + help + Support for device power domains based on the device power service + group defined by the RISC-V platform management interface (RPMI) + specification. The power domains advertised by the platform + microcontroller are registered as generic power domains, so that + devices can reference them through the "power-domains" property. diff --git a/drivers/pmdomain/riscv/Makefile b/drivers/pmdomain/riscv/Makefile new file mode 100644 index 000000000000..2cb0ee8ad413 --- /dev/null +++ b/drivers/pmdomain/riscv/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_RISCV_RPMI_DEVICE_POWER) += riscv-rpmi-device-power.o diff --git a/drivers/pmdomain/riscv/riscv-rpmi-device-power.c b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c new file mode 100644 index 000000000000..c7c46717dd73 --- /dev/null +++ b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RISC-V RPMI Based Device Power Driver through SBI MPXY + * + * Copyright (C) 2026 Shanghai StarFive Technology Co., Ltd. + * + * Implements a Device Power driver on top of SBI RPMI Message Proxy Extension (MPXY) + * + * Each SBI MPXY Device Power instance is associated, through the means of a proper DT + * entry description, to a specific Transport ID. + */ + +#include <linux/bitfield.h> +#include <linux/mailbox/riscv-rpmi-message.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> + +#define RPMI_PM_DOMAIN_NAME_LEN 16 + +/* power state for device power domains */ +#define RPMI_POWER_STATE_CONTEXT_MASK GENMASK(16, 16) +#define RPMI_POWER_STATE_CONTEXT_PRESERVED 0 +#define RPMI_POWER_STATE_CONTEXT_LOST 1 +#define RPMI_POWER_STATE_VALUE_MASK GENMASK(15, 0) +#define RPMI_POWER_STATE_VALUE_ON 0 +#define RPMI_POWER_STATE_VALUE_OFF 3 + +#define RPMI_POWER_STATE_PARAM(context_type, state_value) \ + ((FIELD_PREP(RPMI_POWER_STATE_CONTEXT_MASK, context_type)) | \ + (FIELD_PREP(RPMI_POWER_STATE_VALUE_MASK, state_value))) + +#define RPMI_POWER_STATE_GENERIC_ON \ + RPMI_POWER_STATE_PARAM(RPMI_POWER_STATE_CONTEXT_PRESERVED, \ + RPMI_POWER_STATE_VALUE_ON) + +#define RPMI_POWER_STATE_GENERIC_OFF \ + RPMI_POWER_STATE_PARAM(RPMI_POWER_STATE_CONTEXT_PRESERVED, \ + RPMI_POWER_STATE_VALUE_OFF) + +/** + * struct rpmi_ctx - RPMI transport context shared by all power domains + * + * @chan: mailbox channel of the underlying SBI MPXY transport + * @client: mailbox client bound to @chan + * @lock: serialises RPMI transactions on @chan + */ +struct rpmi_ctx { + struct mbox_chan *chan; + struct mbox_client client; + /* serialises RPMI transactions on @chan */ + struct mutex lock; +}; + +/** + * struct rpmi_device_power_domain - describe one available MPXY Device Power Domain + * + * @id: the power domain ID as advertised by PuC + * @transition_latency: worst case transition latency of power domain from one state + * to another + * @dev: device associated with this power domain + * @mpxy_ctx: RPMI transport context used to reach the PuC + * @genpd: generic power domain registered with the genpd core + * @name: device power domain name assigned by PuC + */ +struct rpmi_device_power_domain { + u32 id; + u32 transition_latency; + struct device *dev; + struct rpmi_ctx *mpxy_ctx; + struct generic_pm_domain genpd; + char name[RPMI_PM_DOMAIN_NAME_LEN]; +}; + +#define to_rpmi_pd(gpd) container_of(gpd, struct rpmi_device_power_domain, genpd) + +/* Service: GET_POWER_DOMAINS */ +struct rpmi_pm_get_num_domain_rx { + __le32 status; + __le32 num_domains; +}; + +/* Service: GET_POWER_DOMAIN_ATTRS */ +struct rpmi_pm_get_domain_attrs_tx { + __le32 domain_id; +}; + +/* pm domain attributes response data */ +struct rpmi_pm_get_domain_attrs_rx { + __le32 status; + __le32 flags; + __le32 transition_latency; + char name[RPMI_PM_DOMAIN_NAME_LEN]; +}; + +/* Service: SET_POWER_DOMAIN_STATE */ +struct rpmi_pm_set_power_state_tx { + __le32 domain_id; + __le32 power_state; +}; + +struct rpmi_pm_set_power_state_rx { + __le32 status; +}; + +/* Service: GET_POWER_DOMAIN_STATE */ +struct rpmi_pm_get_power_state_tx { + __le32 domain_id; +}; + +struct rpmi_pm_get_power_state_rx { + __le32 status; + __le32 power_state; +}; + +static int rpmi_pm_send_message(struct rpmi_ctx *mpxy_ctx, + struct rpmi_mbox_message *msg) +{ + guard(mutex)(&mpxy_ctx->lock); + + return rpmi_mbox_send_message(mpxy_ctx->chan, msg); +} + +static int rpmi_power_state_get(struct rpmi_device_power_domain *mpxy_pm_domain, + u32 domain_id, u32 *state) +{ + struct rpmi_pm_get_power_state_rx rx = { }; + struct rpmi_pm_get_power_state_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_STATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + *state = le32_to_cpu(rx.power_state); + + return 0; +} + +static int rpmi_power_state_set(struct rpmi_device_power_domain *mpxy_pm_domain, + u32 domain_id, u32 state) +{ + struct rpmi_pm_set_power_state_rx rx = { }; + struct rpmi_pm_set_power_state_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + tx.power_state = cpu_to_le32(state); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_SET_STATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + return 0; +} + +static int rpmi_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct rpmi_device_power_domain *mpxy_pm_domain; + u32 state, ret_state, domain_id; + int ret; + + if (power_on) + state = RPMI_POWER_STATE_GENERIC_ON; + else + state = RPMI_POWER_STATE_GENERIC_OFF; + + mpxy_pm_domain = to_rpmi_pd(domain); + domain_id = mpxy_pm_domain->id; + + ret = rpmi_power_state_set(mpxy_pm_domain, domain_id, state); + if (ret) + return ret; + + ret = rpmi_power_state_get(mpxy_pm_domain, domain_id, &ret_state); + if (ret) + return ret; + + if (FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, ret_state) != + FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, state)) + return -EIO; + + return ret; +} + +static int rpmi_pd_power_on(struct generic_pm_domain *domain) +{ + return rpmi_pd_power(domain, true); +} + +static int rpmi_pd_power_off(struct generic_pm_domain *domain) +{ + return rpmi_pd_power(domain, false); +} + +static int rpmi_pm_get_num_domains(struct rpmi_ctx *mpxy_ctx, u32 *domain) +{ + struct rpmi_pm_get_num_domain_rx rx = { }; + struct rpmi_mbox_message msg; + int ret; + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_NUM_DOMAINS, + NULL, 0, &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + *domain = le32_to_cpu(rx.num_domains); + + return 0; +} + +/* obtain the MPXY device power domain attributes */ +static int rpmi_device_power_get_attrs(u32 domain_id, + struct rpmi_device_power_domain *mpxy_pm_domain) +{ + struct rpmi_pm_get_domain_attrs_rx rx = { }; + struct rpmi_pm_get_domain_attrs_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_ATTRS, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + mpxy_pm_domain->transition_latency = le32_to_cpu(rx.transition_latency); + strscpy(mpxy_pm_domain->name, rx.name, sizeof(mpxy_pm_domain->name)); + + return 0; +} + +static int rpmi_pm_attr_setup(struct device *dev, struct rpmi_ctx *mpxy_ctx) +{ + struct rpmi_mbox_message msg; + int ret; + + /* Validate RPMI specification version */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SPEC_VERSION); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get spec version\n"); + return ret; + } + + if (msg.attr.value < RPMI_MKVER(1, 0)) { + dev_dbg(dev, + "msg protocol version mismatch, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + return -EINVAL; + } + + /* Validate device power service group ID */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_ID); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get service group ID\n"); + return ret; + } + + if (msg.attr.value != RPMI_SRVGRP_DEVICE_POWER) { + dev_dbg(dev, + "service group match failed, expected 0x%x, found 0x%x\n", + RPMI_SRVGRP_DEVICE_POWER, msg.attr.value); + return -EINVAL; + } + + /* Validate device power service group version */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_VERSION); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get service group version\n"); + return ret; + } + + if (msg.attr.value < RPMI_MKVER(1, 0)) { + dev_dbg(dev, + "service group version failed, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + return -EINVAL; + } + + return 0; +} + +static void rpmi_pm_domain_mbox_chan_release(void *data) +{ + mbox_free_channel((struct mbox_chan *)data); +} + +static int rpmi_pm_domain_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct rpmi_device_power_domain *mpxy_pd; + struct genpd_onecell_data *mpxy_pd_data; + struct generic_pm_domain **domains; + struct device *dev = &pdev->dev; + struct rpmi_ctx *mpxy_ctx; + u32 num_domains = 0; + int ret; + u32 i; + + mpxy_ctx = devm_kzalloc(&pdev->dev, sizeof(*mpxy_ctx), GFP_KERNEL); + if (!mpxy_ctx) + return -ENOMEM; + + ret = devm_mutex_init(dev, &mpxy_ctx->lock); + if (ret) + return ret; + + /* Setup mailbox client */ + mpxy_ctx->client.dev = dev; + mpxy_ctx->client.rx_callback = NULL; + mpxy_ctx->client.tx_block = false; + mpxy_ctx->client.knows_txdone = true; + mpxy_ctx->client.tx_tout = 0; + + /* Request mailbox channel */ + mpxy_ctx->chan = mbox_request_channel(&mpxy_ctx->client, 0); + if (IS_ERR(mpxy_ctx->chan)) + return PTR_ERR(mpxy_ctx->chan); + + ret = devm_add_action_or_reset(dev, rpmi_pm_domain_mbox_chan_release, + mpxy_ctx->chan); + if (ret) + return dev_err_probe(dev, ret, + "failed to add rpmi mbox channel cleanup\n"); + + ret = rpmi_pm_attr_setup(dev, mpxy_ctx); + if (ret) + return dev_err_probe(dev, ret, + "failed to verify RPMI attribute\n"); + + /* Get number of device power domain */ + ret = rpmi_pm_get_num_domains(mpxy_ctx, &num_domains); + if (ret) + return dev_err_probe(dev, ret, + "failed to get number of pm domains\n"); + + if (!num_domains) + return dev_err_probe(dev, -EINVAL, "No PM domains found!\n"); + + dev_info(&pdev->dev, "%u MPXY PM domains are found\n", num_domains); + + mpxy_pd = devm_kcalloc(&pdev->dev, num_domains, sizeof(*mpxy_pd), GFP_KERNEL); + if (!mpxy_pd) + return -ENOMEM; + + domains = devm_kcalloc(&pdev->dev, num_domains, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + mpxy_pd_data = devm_kzalloc(&pdev->dev, sizeof(*mpxy_pd_data), GFP_KERNEL); + if (!mpxy_pd_data) + return -ENOMEM; + + for (i = 0; i < num_domains; i++, mpxy_pd++) { + u32 state; + + mpxy_pd->dev = &pdev->dev; + mpxy_pd->mpxy_ctx = mpxy_ctx; + mpxy_pd->id = i; + + ret = rpmi_device_power_get_attrs(i, mpxy_pd); + if (ret) { + dev_warn(mpxy_pd->dev, + "power domain %u initialization failed\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + ret = rpmi_power_state_get(mpxy_pd, i, &state); + if (ret) { + dev_warn(mpxy_pd->dev, + "failed to get state for power domain %u\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + state = FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, state); + if (state != RPMI_POWER_STATE_VALUE_OFF && + state != RPMI_POWER_STATE_VALUE_ON) { + dev_warn(mpxy_pd->dev, + "unsupported state 0x%x for power domain %u\n", + state, mpxy_pd->id); + domains[i] = NULL; + continue; + } + + mpxy_pd->genpd.name = mpxy_pd->name; + mpxy_pd->genpd.power_off = rpmi_pd_power_off; + mpxy_pd->genpd.power_on = rpmi_pd_power_on; + /* + * Domain names come from the PuC and are not guaranteed to be + * unique or non-empty, so let genpd derive unique device names + * from them rather than using them verbatim. + */ + mpxy_pd->genpd.flags = GENPD_FLAG_DEV_NAME_FW; + + ret = pm_genpd_init(&mpxy_pd->genpd, NULL, + state == RPMI_POWER_STATE_VALUE_OFF); + if (ret) { + dev_warn(mpxy_pd->dev, + "failed to init power domain %u\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + domains[i] = &mpxy_pd->genpd; + } + + mpxy_pd_data->domains = domains; + mpxy_pd_data->num_domains = num_domains; + + ret = of_genpd_add_provider_onecell(np, mpxy_pd_data); + if (ret) { + while (i--) { + if (domains[i]) + pm_genpd_remove(domains[i]); + } + + return dev_err_probe(dev, ret, "failed to add genpd provider\n"); + } + + return 0; +} + +static const struct of_device_id rpmi_pm_domain_of_match[] = { + { .compatible = "riscv,rpmi-device-power" }, + {}, +}; + +static struct platform_driver rpmi_pm_domain_platdrv = { + .driver = { + .name = "riscv-rpmi-device-power", + .of_match_table = rpmi_pm_domain_of_match, + .suppress_bind_attrs = true, + }, + .probe = rpmi_pm_domain_probe, +}; + +builtin_platform_driver(rpmi_pm_domain_platdrv); + +MODULE_AUTHOR("Joshua Yeong <joshua.yeong@starfivetech.com>"); +MODULE_DESCRIPTION("Device Power Driver based on RPMI message protocol"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h index e135c6564d0c..d5362b5821f9 100644 --- a/include/linux/mailbox/riscv-rpmi-message.h +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -93,6 +93,7 @@ static inline int rpmi_to_linux_error(int rpmi_error) /* RPMI service group IDs */ #define RPMI_SRVGRP_SYSTEM_MSI 0x00002 #define RPMI_SRVGRP_CLOCK 0x00008 +#define RPMI_SRVGRP_DEVICE_POWER 0x00009 /* RPMI clock service IDs */ enum rpmi_clock_service_id { @@ -119,6 +120,16 @@ enum rpmi_sysmsi_service_id { RPMI_SYSMSI_SRV_ID_MAX_COUNT }; +/* RPMI device power service IDs */ +enum rpmi_device_power_service_id { + RPMI_DP_SRV_ENABLE_NOTIFICATION = 0x01, + RPMI_DP_SRV_GET_NUM_DOMAINS = 0x02, + RPMI_DP_SRV_GET_ATTRS = 0x03, + RPMI_DP_SRV_SET_STATE = 0x04, + RPMI_DP_SRV_GET_STATE = 0x05, + RPMI_DP_SRV_ID_MAX_COUNT, +}; + /* RPMI Linux mailbox attribute IDs */ enum rpmi_mbox_attribute_id { RPMI_MBOX_ATTR_SPEC_VERSION, -- 2.43.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 2/3] pmdomain: riscv: Add RPMI device power service @ 2026-09-03 9:23 ` Joshua Yeong 0 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add a generic power domain provider on top of the RISC-V Platform Management Interface (RPMI) device power service group, reached through an SBI MPXY channel. The driver enumerates the device power domains advertised by the platform microcontroller, queries their attributes and initial state, and registers them as an onecell genpd provider so that devices can reference them through the "power-domains" property. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/riscv/Kconfig | 15 + drivers/pmdomain/riscv/Makefile | 3 + .../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++ include/linux/mailbox/riscv-rpmi-message.h | 11 + 6 files changed, 516 insertions(+) create mode 100644 drivers/pmdomain/riscv/Kconfig create mode 100644 drivers/pmdomain/riscv/Makefile create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig index 23076ae90e66..5341dff669be 100644 --- a/drivers/pmdomain/Kconfig +++ b/drivers/pmdomain/Kconfig @@ -11,6 +11,7 @@ source "drivers/pmdomain/marvell/Kconfig" source "drivers/pmdomain/mediatek/Kconfig" source "drivers/pmdomain/qcom/Kconfig" source "drivers/pmdomain/renesas/Kconfig" +source "drivers/pmdomain/riscv/Kconfig" source "drivers/pmdomain/rockchip/Kconfig" source "drivers/pmdomain/samsung/Kconfig" source "drivers/pmdomain/st/Kconfig" diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile index ebc802f13eb9..d7aee13ae571 100644 --- a/drivers/pmdomain/Makefile +++ b/drivers/pmdomain/Makefile @@ -9,6 +9,7 @@ obj-y += marvell/ obj-y += mediatek/ obj-y += qcom/ obj-y += renesas/ +obj-y += riscv/ obj-y += rockchip/ obj-y += samsung/ obj-y += st/ diff --git a/drivers/pmdomain/riscv/Kconfig b/drivers/pmdomain/riscv/Kconfig new file mode 100644 index 000000000000..97232edc294a --- /dev/null +++ b/drivers/pmdomain/riscv/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config RISCV_RPMI_DEVICE_POWER + bool "RISC-V RPMI Based Device Power driver" + depends on RISCV || COMPILE_TEST + depends on MAILBOX + depends on PM + default RISCV + select PM_GENERIC_DOMAINS + help + Support for device power domains based on the device power service + group defined by the RISC-V platform management interface (RPMI) + specification. The power domains advertised by the platform + microcontroller are registered as generic power domains, so that + devices can reference them through the "power-domains" property. diff --git a/drivers/pmdomain/riscv/Makefile b/drivers/pmdomain/riscv/Makefile new file mode 100644 index 000000000000..2cb0ee8ad413 --- /dev/null +++ b/drivers/pmdomain/riscv/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_RISCV_RPMI_DEVICE_POWER) += riscv-rpmi-device-power.o diff --git a/drivers/pmdomain/riscv/riscv-rpmi-device-power.c b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c new file mode 100644 index 000000000000..c7c46717dd73 --- /dev/null +++ b/drivers/pmdomain/riscv/riscv-rpmi-device-power.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RISC-V RPMI Based Device Power Driver through SBI MPXY + * + * Copyright (C) 2026 Shanghai StarFive Technology Co., Ltd. + * + * Implements a Device Power driver on top of SBI RPMI Message Proxy Extension (MPXY) + * + * Each SBI MPXY Device Power instance is associated, through the means of a proper DT + * entry description, to a specific Transport ID. + */ + +#include <linux/bitfield.h> +#include <linux/mailbox/riscv-rpmi-message.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> + +#define RPMI_PM_DOMAIN_NAME_LEN 16 + +/* power state for device power domains */ +#define RPMI_POWER_STATE_CONTEXT_MASK GENMASK(16, 16) +#define RPMI_POWER_STATE_CONTEXT_PRESERVED 0 +#define RPMI_POWER_STATE_CONTEXT_LOST 1 +#define RPMI_POWER_STATE_VALUE_MASK GENMASK(15, 0) +#define RPMI_POWER_STATE_VALUE_ON 0 +#define RPMI_POWER_STATE_VALUE_OFF 3 + +#define RPMI_POWER_STATE_PARAM(context_type, state_value) \ + ((FIELD_PREP(RPMI_POWER_STATE_CONTEXT_MASK, context_type)) | \ + (FIELD_PREP(RPMI_POWER_STATE_VALUE_MASK, state_value))) + +#define RPMI_POWER_STATE_GENERIC_ON \ + RPMI_POWER_STATE_PARAM(RPMI_POWER_STATE_CONTEXT_PRESERVED, \ + RPMI_POWER_STATE_VALUE_ON) + +#define RPMI_POWER_STATE_GENERIC_OFF \ + RPMI_POWER_STATE_PARAM(RPMI_POWER_STATE_CONTEXT_PRESERVED, \ + RPMI_POWER_STATE_VALUE_OFF) + +/** + * struct rpmi_ctx - RPMI transport context shared by all power domains + * + * @chan: mailbox channel of the underlying SBI MPXY transport + * @client: mailbox client bound to @chan + * @lock: serialises RPMI transactions on @chan + */ +struct rpmi_ctx { + struct mbox_chan *chan; + struct mbox_client client; + /* serialises RPMI transactions on @chan */ + struct mutex lock; +}; + +/** + * struct rpmi_device_power_domain - describe one available MPXY Device Power Domain + * + * @id: the power domain ID as advertised by PuC + * @transition_latency: worst case transition latency of power domain from one state + * to another + * @dev: device associated with this power domain + * @mpxy_ctx: RPMI transport context used to reach the PuC + * @genpd: generic power domain registered with the genpd core + * @name: device power domain name assigned by PuC + */ +struct rpmi_device_power_domain { + u32 id; + u32 transition_latency; + struct device *dev; + struct rpmi_ctx *mpxy_ctx; + struct generic_pm_domain genpd; + char name[RPMI_PM_DOMAIN_NAME_LEN]; +}; + +#define to_rpmi_pd(gpd) container_of(gpd, struct rpmi_device_power_domain, genpd) + +/* Service: GET_POWER_DOMAINS */ +struct rpmi_pm_get_num_domain_rx { + __le32 status; + __le32 num_domains; +}; + +/* Service: GET_POWER_DOMAIN_ATTRS */ +struct rpmi_pm_get_domain_attrs_tx { + __le32 domain_id; +}; + +/* pm domain attributes response data */ +struct rpmi_pm_get_domain_attrs_rx { + __le32 status; + __le32 flags; + __le32 transition_latency; + char name[RPMI_PM_DOMAIN_NAME_LEN]; +}; + +/* Service: SET_POWER_DOMAIN_STATE */ +struct rpmi_pm_set_power_state_tx { + __le32 domain_id; + __le32 power_state; +}; + +struct rpmi_pm_set_power_state_rx { + __le32 status; +}; + +/* Service: GET_POWER_DOMAIN_STATE */ +struct rpmi_pm_get_power_state_tx { + __le32 domain_id; +}; + +struct rpmi_pm_get_power_state_rx { + __le32 status; + __le32 power_state; +}; + +static int rpmi_pm_send_message(struct rpmi_ctx *mpxy_ctx, + struct rpmi_mbox_message *msg) +{ + guard(mutex)(&mpxy_ctx->lock); + + return rpmi_mbox_send_message(mpxy_ctx->chan, msg); +} + +static int rpmi_power_state_get(struct rpmi_device_power_domain *mpxy_pm_domain, + u32 domain_id, u32 *state) +{ + struct rpmi_pm_get_power_state_rx rx = { }; + struct rpmi_pm_get_power_state_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_STATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + *state = le32_to_cpu(rx.power_state); + + return 0; +} + +static int rpmi_power_state_set(struct rpmi_device_power_domain *mpxy_pm_domain, + u32 domain_id, u32 state) +{ + struct rpmi_pm_set_power_state_rx rx = { }; + struct rpmi_pm_set_power_state_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + tx.power_state = cpu_to_le32(state); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_SET_STATE, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + return 0; +} + +static int rpmi_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct rpmi_device_power_domain *mpxy_pm_domain; + u32 state, ret_state, domain_id; + int ret; + + if (power_on) + state = RPMI_POWER_STATE_GENERIC_ON; + else + state = RPMI_POWER_STATE_GENERIC_OFF; + + mpxy_pm_domain = to_rpmi_pd(domain); + domain_id = mpxy_pm_domain->id; + + ret = rpmi_power_state_set(mpxy_pm_domain, domain_id, state); + if (ret) + return ret; + + ret = rpmi_power_state_get(mpxy_pm_domain, domain_id, &ret_state); + if (ret) + return ret; + + if (FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, ret_state) != + FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, state)) + return -EIO; + + return ret; +} + +static int rpmi_pd_power_on(struct generic_pm_domain *domain) +{ + return rpmi_pd_power(domain, true); +} + +static int rpmi_pd_power_off(struct generic_pm_domain *domain) +{ + return rpmi_pd_power(domain, false); +} + +static int rpmi_pm_get_num_domains(struct rpmi_ctx *mpxy_ctx, u32 *domain) +{ + struct rpmi_pm_get_num_domain_rx rx = { }; + struct rpmi_mbox_message msg; + int ret; + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_NUM_DOMAINS, + NULL, 0, &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + *domain = le32_to_cpu(rx.num_domains); + + return 0; +} + +/* obtain the MPXY device power domain attributes */ +static int rpmi_device_power_get_attrs(u32 domain_id, + struct rpmi_device_power_domain *mpxy_pm_domain) +{ + struct rpmi_pm_get_domain_attrs_rx rx = { }; + struct rpmi_pm_get_domain_attrs_tx tx; + struct rpmi_mbox_message msg; + int ret; + + tx.domain_id = cpu_to_le32(domain_id); + + rpmi_mbox_init_send_with_response(&msg, RPMI_DP_SRV_GET_ATTRS, + &tx, sizeof(tx), &rx, sizeof(rx)); + ret = rpmi_pm_send_message(mpxy_pm_domain->mpxy_ctx, &msg); + if (ret) + return ret; + + if (rx.status) + return rpmi_to_linux_error(le32_to_cpu(rx.status)); + + if (msg.data.out_response_len < sizeof(rx)) + return -EPROTO; + + mpxy_pm_domain->transition_latency = le32_to_cpu(rx.transition_latency); + strscpy(mpxy_pm_domain->name, rx.name, sizeof(mpxy_pm_domain->name)); + + return 0; +} + +static int rpmi_pm_attr_setup(struct device *dev, struct rpmi_ctx *mpxy_ctx) +{ + struct rpmi_mbox_message msg; + int ret; + + /* Validate RPMI specification version */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SPEC_VERSION); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get spec version\n"); + return ret; + } + + if (msg.attr.value < RPMI_MKVER(1, 0)) { + dev_dbg(dev, + "msg protocol version mismatch, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + return -EINVAL; + } + + /* Validate device power service group ID */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_ID); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get service group ID\n"); + return ret; + } + + if (msg.attr.value != RPMI_SRVGRP_DEVICE_POWER) { + dev_dbg(dev, + "service group match failed, expected 0x%x, found 0x%x\n", + RPMI_SRVGRP_DEVICE_POWER, msg.attr.value); + return -EINVAL; + } + + /* Validate device power service group version */ + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_VERSION); + ret = rpmi_pm_send_message(mpxy_ctx, &msg); + if (ret) { + dev_dbg(dev, "Failed to get service group version\n"); + return ret; + } + + if (msg.attr.value < RPMI_MKVER(1, 0)) { + dev_dbg(dev, + "service group version failed, expected 0x%x, found 0x%x\n", + RPMI_MKVER(1, 0), msg.attr.value); + return -EINVAL; + } + + return 0; +} + +static void rpmi_pm_domain_mbox_chan_release(void *data) +{ + mbox_free_channel((struct mbox_chan *)data); +} + +static int rpmi_pm_domain_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct rpmi_device_power_domain *mpxy_pd; + struct genpd_onecell_data *mpxy_pd_data; + struct generic_pm_domain **domains; + struct device *dev = &pdev->dev; + struct rpmi_ctx *mpxy_ctx; + u32 num_domains = 0; + int ret; + u32 i; + + mpxy_ctx = devm_kzalloc(&pdev->dev, sizeof(*mpxy_ctx), GFP_KERNEL); + if (!mpxy_ctx) + return -ENOMEM; + + ret = devm_mutex_init(dev, &mpxy_ctx->lock); + if (ret) + return ret; + + /* Setup mailbox client */ + mpxy_ctx->client.dev = dev; + mpxy_ctx->client.rx_callback = NULL; + mpxy_ctx->client.tx_block = false; + mpxy_ctx->client.knows_txdone = true; + mpxy_ctx->client.tx_tout = 0; + + /* Request mailbox channel */ + mpxy_ctx->chan = mbox_request_channel(&mpxy_ctx->client, 0); + if (IS_ERR(mpxy_ctx->chan)) + return PTR_ERR(mpxy_ctx->chan); + + ret = devm_add_action_or_reset(dev, rpmi_pm_domain_mbox_chan_release, + mpxy_ctx->chan); + if (ret) + return dev_err_probe(dev, ret, + "failed to add rpmi mbox channel cleanup\n"); + + ret = rpmi_pm_attr_setup(dev, mpxy_ctx); + if (ret) + return dev_err_probe(dev, ret, + "failed to verify RPMI attribute\n"); + + /* Get number of device power domain */ + ret = rpmi_pm_get_num_domains(mpxy_ctx, &num_domains); + if (ret) + return dev_err_probe(dev, ret, + "failed to get number of pm domains\n"); + + if (!num_domains) + return dev_err_probe(dev, -EINVAL, "No PM domains found!\n"); + + dev_info(&pdev->dev, "%u MPXY PM domains are found\n", num_domains); + + mpxy_pd = devm_kcalloc(&pdev->dev, num_domains, sizeof(*mpxy_pd), GFP_KERNEL); + if (!mpxy_pd) + return -ENOMEM; + + domains = devm_kcalloc(&pdev->dev, num_domains, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + mpxy_pd_data = devm_kzalloc(&pdev->dev, sizeof(*mpxy_pd_data), GFP_KERNEL); + if (!mpxy_pd_data) + return -ENOMEM; + + for (i = 0; i < num_domains; i++, mpxy_pd++) { + u32 state; + + mpxy_pd->dev = &pdev->dev; + mpxy_pd->mpxy_ctx = mpxy_ctx; + mpxy_pd->id = i; + + ret = rpmi_device_power_get_attrs(i, mpxy_pd); + if (ret) { + dev_warn(mpxy_pd->dev, + "power domain %u initialization failed\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + ret = rpmi_power_state_get(mpxy_pd, i, &state); + if (ret) { + dev_warn(mpxy_pd->dev, + "failed to get state for power domain %u\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + state = FIELD_GET(RPMI_POWER_STATE_VALUE_MASK, state); + if (state != RPMI_POWER_STATE_VALUE_OFF && + state != RPMI_POWER_STATE_VALUE_ON) { + dev_warn(mpxy_pd->dev, + "unsupported state 0x%x for power domain %u\n", + state, mpxy_pd->id); + domains[i] = NULL; + continue; + } + + mpxy_pd->genpd.name = mpxy_pd->name; + mpxy_pd->genpd.power_off = rpmi_pd_power_off; + mpxy_pd->genpd.power_on = rpmi_pd_power_on; + /* + * Domain names come from the PuC and are not guaranteed to be + * unique or non-empty, so let genpd derive unique device names + * from them rather than using them verbatim. + */ + mpxy_pd->genpd.flags = GENPD_FLAG_DEV_NAME_FW; + + ret = pm_genpd_init(&mpxy_pd->genpd, NULL, + state == RPMI_POWER_STATE_VALUE_OFF); + if (ret) { + dev_warn(mpxy_pd->dev, + "failed to init power domain %u\n", + mpxy_pd->id); + domains[i] = NULL; + continue; + } + + domains[i] = &mpxy_pd->genpd; + } + + mpxy_pd_data->domains = domains; + mpxy_pd_data->num_domains = num_domains; + + ret = of_genpd_add_provider_onecell(np, mpxy_pd_data); + if (ret) { + while (i--) { + if (domains[i]) + pm_genpd_remove(domains[i]); + } + + return dev_err_probe(dev, ret, "failed to add genpd provider\n"); + } + + return 0; +} + +static const struct of_device_id rpmi_pm_domain_of_match[] = { + { .compatible = "riscv,rpmi-device-power" }, + {}, +}; + +static struct platform_driver rpmi_pm_domain_platdrv = { + .driver = { + .name = "riscv-rpmi-device-power", + .of_match_table = rpmi_pm_domain_of_match, + .suppress_bind_attrs = true, + }, + .probe = rpmi_pm_domain_probe, +}; + +builtin_platform_driver(rpmi_pm_domain_platdrv); + +MODULE_AUTHOR("Joshua Yeong <joshua.yeong@starfivetech.com>"); +MODULE_DESCRIPTION("Device Power Driver based on RPMI message protocol"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h index e135c6564d0c..d5362b5821f9 100644 --- a/include/linux/mailbox/riscv-rpmi-message.h +++ b/include/linux/mailbox/riscv-rpmi-message.h @@ -93,6 +93,7 @@ static inline int rpmi_to_linux_error(int rpmi_error) /* RPMI service group IDs */ #define RPMI_SRVGRP_SYSTEM_MSI 0x00002 #define RPMI_SRVGRP_CLOCK 0x00008 +#define RPMI_SRVGRP_DEVICE_POWER 0x00009 /* RPMI clock service IDs */ enum rpmi_clock_service_id { @@ -119,6 +120,16 @@ enum rpmi_sysmsi_service_id { RPMI_SYSMSI_SRV_ID_MAX_COUNT }; +/* RPMI device power service IDs */ +enum rpmi_device_power_service_id { + RPMI_DP_SRV_ENABLE_NOTIFICATION = 0x01, + RPMI_DP_SRV_GET_NUM_DOMAINS = 0x02, + RPMI_DP_SRV_GET_ATTRS = 0x03, + RPMI_DP_SRV_SET_STATE = 0x04, + RPMI_DP_SRV_GET_STATE = 0x05, + RPMI_DP_SRV_ID_MAX_COUNT, +}; + /* RPMI Linux mailbox attribute IDs */ enum rpmi_mbox_attribute_id { RPMI_MBOX_ATTR_SPEC_VERSION, -- 2.43.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] MAINTAINERS: Add RISC-V RPMI device power driver 2026-09-03 9:23 ` Joshua Yeong @ 2026-09-03 9:23 ` Joshua Yeong -1 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add a separate entry for the RPMI device power driver and its bindings, rather than extending the existing RISC-V RPMI and MPXY drivers entry, which covers drivers maintained by others. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8014b9f8253e..4716da916aa1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23308,6 +23308,14 @@ F: drivers/irqchip/irq-riscv-rpmi-sysmsi.c F: drivers/mailbox/riscv-sbi-mpxy-mbox.c F: include/linux/mailbox/riscv-rpmi-message.h +RISC-V RPMI DEVICE POWER DRIVER +M: Joshua Yeong <joshua.yeong@starfivetech.com> +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml +F: Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml +F: drivers/pmdomain/riscv/ + RISC-V SPACEMIT SoC Support M: Yixun Lan <dlan@kernel.org> L: linux-riscv@lists.infradead.org -- 2.43.0 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 3/3] MAINTAINERS: Add RISC-V RPMI device power driver @ 2026-09-03 9:23 ` Joshua Yeong 0 siblings, 0 replies; 12+ messages in thread From: Joshua Yeong @ 2026-09-03 9:23 UTC (permalink / raw) To: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou Cc: alex, joshua.yeong, linux-riscv, linux-pm, devicetree, linux-kernel Add a separate entry for the RPMI device power driver and its bindings, rather than extending the existing RISC-V RPMI and MPXY drivers entry, which covers drivers maintained by others. Signed-off-by: Joshua Yeong <joshua.yeong@starfivetech.com> --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8014b9f8253e..4716da916aa1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23308,6 +23308,14 @@ F: drivers/irqchip/irq-riscv-rpmi-sysmsi.c F: drivers/mailbox/riscv-sbi-mpxy-mbox.c F: include/linux/mailbox/riscv-rpmi-message.h +RISC-V RPMI DEVICE POWER DRIVER +M: Joshua Yeong <joshua.yeong@starfivetech.com> +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml +F: Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml +F: drivers/pmdomain/riscv/ + RISC-V SPACEMIT SoC Support M: Yixun Lan <dlan@kernel.org> L: linux-riscv@lists.infradead.org -- 2.43.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/3] Add RISC-V RPMI device power service support 2026-09-03 9:23 ` Joshua Yeong @ 2026-09-21 14:32 ` Ulf Hansson -1 siblings, 0 replies; 12+ messages in thread From: Ulf Hansson @ 2026-09-21 14:32 UTC (permalink / raw) To: Joshua Yeong Cc: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou, alex, linux-riscv, linux-pm, devicetree, linux-kernel On Thu, Sep 3, 2026 at 11:24 AM Joshua Yeong <joshua.yeong@starfivetech.com> wrote: > > The RISC-V Platform Management Interface (RPMI) specification defines a > modular and extensible messaging protocol between the supervisor software > and a platform microcontroller (PuC). Among the service groups it defines > is the device power service group (service group ID 0x00009), which allows > the supervisor to enumerate the power domains of platform devices managed > by the PuC, query their attributes, and get/set their power state. > > This series adds supervisor-side support for that service group: > > - DT bindings for the power domain controller exposed to the supervisor > ("riscv,rpmi-device-power") and for the SBI MPXY channel that the SBI > implementation uses to expose the service group to the supervisor > ("riscv,rpmi-mpxy-device-power"). > > - A generic power domain (genpd) provider driver under > drivers/pmdomain/riscv/ which talks to the PuC over an SBI MPXY > mailbox channel. At probe it queries GET_NUM_DOMAINS, then for each > domain queries GET_ATTRS for the name and transition latency and > GET_STATE for the initial state, and registers the whole set as a > onecell genpd provider. Domain power on/off is driven through > SET_STATE with the generic ON/OFF power state parameters, so devices > can simply reference a domain through the "power-domains" property. > > The series is based on the existing RISC-V RPMI/MPXY infrastructure > already present in the tree (drivers/mailbox/riscv-sbi-mpxy-mbox.c and > include/linux/mailbox/riscv-rpmi-message.h), and only adds the device > power service group definitions on top of it. > > Changes in v3: > - Move the MAINTAINERS change into its own patch, and add a new > "RISC-V RPMI DEVICE POWER DRIVER" section scoped to this driver and > its bindings instead of adding an M: entry to the existing "RISC-V > RPMI AND MPXY DRIVERS" section, which covers drivers maintained by > others. > - Drop the redundant trailing "bindings" from the dt-bindings subject. > - Compare only the value field of the RPMI power state word. The word > also carries a context bit, so a full word comparison would report > -EIO after a successful transition, and would drop a domain at probe, > whenever the PuC reports context as lost. > - Check the pm_genpd_init() return value and leave a failed domain out > of the onecell array. Every failure path in pm_genpd_init() returns > before the genpd is linked into gpd_list, so the previous code could > hand a half initialised genpd to of_genpd_add_provider_onecell() and > then list_del() an uninitialised list head in the unwind loop. > - Set GENPD_FLAG_DEV_NAME_FW. The domain names come from the PuC and > are not guaranteed to be unique or non-empty, and were used verbatim > as the sysfs and debugfs names, where a duplicate fails device_add() > with -EEXIST and takes down the whole provider. > > v1: https://lore.kernel.org/r/20260829205520.1691-1-joshua.yeong@starfivetech.com > v2: https://lore.kernel.org/r/20260830152812.312663-1-joshua.yeong@starfivetech.com > > Testing > ======= > > The series was tested under QEMU with the RPMI device power service > implemented in firmware. > > Components: > > - OpenSBI: latest master branch > https://github.com/riscv-software-src/opensbi > > - QEMU: the RPMI-enabled tree at > https://github.com/yeongjoshua/qemu/tree/rpmi-v11.1.0 > > Kernel config: enable CONFIG_RISCV_RPMI_DEVICE_POWER (default y on RISC-V > when MAILBOX is enabled) along with the SBI MPXY mailbox driver. > > Run with: > > qemu-system-riscv64 \ > -M virt -m 2G -smp 4 \ > -bios fw_dynamic.bin \ > -kernel Image \ > -M rpmi=true \ > -nographic \ > -initrd rootfs-busybox.cpio \ > -append "root=/dev/ram rw console=ttyS0,115200 no_console_suspend mem=2048M earlycon=uart8250,mmio,0x10000000" > > The RPMI device power domains advertised by the emulated platform > microcontroller show up as generic power domains and can be inspected > through /sys/kernel/debug/pm_genpd/. The series was additionally booted > with CONFIG_PROVE_LOCKING, CONFIG_DEBUG_MUTEXES and > CONFIG_DEBUG_ATOMIC_SLEEP enabled, with no lockdep reports. > > Joshua Yeong (3): > dt-bindings: power: Add RPMI device power service > pmdomain: riscv: Add RPMI device power service > MAINTAINERS: Add RISC-V RPMI device power driver > > .../power/riscv,rpmi-device-power.yaml | 65 +++ > .../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++ > MAINTAINERS | 8 + > drivers/pmdomain/Kconfig | 1 + > drivers/pmdomain/Makefile | 1 + > drivers/pmdomain/riscv/Kconfig | 15 + > drivers/pmdomain/riscv/Makefile | 3 + > .../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++ > include/linux/mailbox/riscv-rpmi-message.h | 11 + > 9 files changed, 654 insertions(+) > create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml > create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml > create mode 100644 drivers/pmdomain/riscv/Kconfig > create mode 100644 drivers/pmdomain/riscv/Makefile > create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c > > > base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f > -- > 2.43.0 The v3 series applied for next, thanks! Kind regards Uffe ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/3] Add RISC-V RPMI device power service support @ 2026-09-21 14:32 ` Ulf Hansson 0 siblings, 0 replies; 12+ messages in thread From: Ulf Hansson @ 2026-09-21 14:32 UTC (permalink / raw) To: Joshua Yeong Cc: rahul, anup, lftan.linux, robh, krzk+dt, conor+dt, ulfh, pjw, palmer, aou, alex, linux-riscv, linux-pm, devicetree, linux-kernel On Thu, Sep 3, 2026 at 11:24 AM Joshua Yeong <joshua.yeong@starfivetech.com> wrote: > > The RISC-V Platform Management Interface (RPMI) specification defines a > modular and extensible messaging protocol between the supervisor software > and a platform microcontroller (PuC). Among the service groups it defines > is the device power service group (service group ID 0x00009), which allows > the supervisor to enumerate the power domains of platform devices managed > by the PuC, query their attributes, and get/set their power state. > > This series adds supervisor-side support for that service group: > > - DT bindings for the power domain controller exposed to the supervisor > ("riscv,rpmi-device-power") and for the SBI MPXY channel that the SBI > implementation uses to expose the service group to the supervisor > ("riscv,rpmi-mpxy-device-power"). > > - A generic power domain (genpd) provider driver under > drivers/pmdomain/riscv/ which talks to the PuC over an SBI MPXY > mailbox channel. At probe it queries GET_NUM_DOMAINS, then for each > domain queries GET_ATTRS for the name and transition latency and > GET_STATE for the initial state, and registers the whole set as a > onecell genpd provider. Domain power on/off is driven through > SET_STATE with the generic ON/OFF power state parameters, so devices > can simply reference a domain through the "power-domains" property. > > The series is based on the existing RISC-V RPMI/MPXY infrastructure > already present in the tree (drivers/mailbox/riscv-sbi-mpxy-mbox.c and > include/linux/mailbox/riscv-rpmi-message.h), and only adds the device > power service group definitions on top of it. > > Changes in v3: > - Move the MAINTAINERS change into its own patch, and add a new > "RISC-V RPMI DEVICE POWER DRIVER" section scoped to this driver and > its bindings instead of adding an M: entry to the existing "RISC-V > RPMI AND MPXY DRIVERS" section, which covers drivers maintained by > others. > - Drop the redundant trailing "bindings" from the dt-bindings subject. > - Compare only the value field of the RPMI power state word. The word > also carries a context bit, so a full word comparison would report > -EIO after a successful transition, and would drop a domain at probe, > whenever the PuC reports context as lost. > - Check the pm_genpd_init() return value and leave a failed domain out > of the onecell array. Every failure path in pm_genpd_init() returns > before the genpd is linked into gpd_list, so the previous code could > hand a half initialised genpd to of_genpd_add_provider_onecell() and > then list_del() an uninitialised list head in the unwind loop. > - Set GENPD_FLAG_DEV_NAME_FW. The domain names come from the PuC and > are not guaranteed to be unique or non-empty, and were used verbatim > as the sysfs and debugfs names, where a duplicate fails device_add() > with -EEXIST and takes down the whole provider. > > v1: https://lore.kernel.org/r/20260829205520.1691-1-joshua.yeong@starfivetech.com > v2: https://lore.kernel.org/r/20260830152812.312663-1-joshua.yeong@starfivetech.com > > Testing > ======= > > The series was tested under QEMU with the RPMI device power service > implemented in firmware. > > Components: > > - OpenSBI: latest master branch > https://github.com/riscv-software-src/opensbi > > - QEMU: the RPMI-enabled tree at > https://github.com/yeongjoshua/qemu/tree/rpmi-v11.1.0 > > Kernel config: enable CONFIG_RISCV_RPMI_DEVICE_POWER (default y on RISC-V > when MAILBOX is enabled) along with the SBI MPXY mailbox driver. > > Run with: > > qemu-system-riscv64 \ > -M virt -m 2G -smp 4 \ > -bios fw_dynamic.bin \ > -kernel Image \ > -M rpmi=true \ > -nographic \ > -initrd rootfs-busybox.cpio \ > -append "root=/dev/ram rw console=ttyS0,115200 no_console_suspend mem=2048M earlycon=uart8250,mmio,0x10000000" > > The RPMI device power domains advertised by the emulated platform > microcontroller show up as generic power domains and can be inspected > through /sys/kernel/debug/pm_genpd/. The series was additionally booted > with CONFIG_PROVE_LOCKING, CONFIG_DEBUG_MUTEXES and > CONFIG_DEBUG_ATOMIC_SLEEP enabled, with no lockdep reports. > > Joshua Yeong (3): > dt-bindings: power: Add RPMI device power service > pmdomain: riscv: Add RPMI device power service > MAINTAINERS: Add RISC-V RPMI device power driver > > .../power/riscv,rpmi-device-power.yaml | 65 +++ > .../power/riscv,rpmi-mpxy-device-power.yaml | 65 +++ > MAINTAINERS | 8 + > drivers/pmdomain/Kconfig | 1 + > drivers/pmdomain/Makefile | 1 + > drivers/pmdomain/riscv/Kconfig | 15 + > drivers/pmdomain/riscv/Makefile | 3 + > .../pmdomain/riscv/riscv-rpmi-device-power.c | 485 ++++++++++++++++++ > include/linux/mailbox/riscv-rpmi-message.h | 11 + > 9 files changed, 654 insertions(+) > create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-device-power.yaml > create mode 100644 Documentation/devicetree/bindings/power/riscv,rpmi-mpxy-device-power.yaml > create mode 100644 drivers/pmdomain/riscv/Kconfig > create mode 100644 drivers/pmdomain/riscv/Makefile > create mode 100644 drivers/pmdomain/riscv/riscv-rpmi-device-power.c > > > base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f > -- > 2.43.0 The v3 series applied for next, thanks! Kind regards Uffe _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-09-21 14:33 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-03 9:23 [PATCH v3 0/3] Add RISC-V RPMI device power service support Joshua Yeong 2026-09-03 9:23 ` Joshua Yeong 2026-09-03 9:23 ` [PATCH v3 1/3] dt-bindings: power: Add RPMI device power service Joshua Yeong 2026-09-03 9:23 ` Joshua Yeong 2026-09-03 17:22 ` Conor Dooley 2026-09-03 17:22 ` Conor Dooley 2026-09-03 9:23 ` [PATCH v3 2/3] pmdomain: riscv: " Joshua Yeong 2026-09-03 9:23 ` Joshua Yeong 2026-09-03 9:23 ` [PATCH v3 3/3] MAINTAINERS: Add RISC-V RPMI device power driver Joshua Yeong 2026-09-03 9:23 ` Joshua Yeong 2026-09-21 14:32 ` [PATCH v3 0/3] Add RISC-V RPMI device power service support Ulf Hansson 2026-09-21 14:32 ` Ulf Hansson
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.