* [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support
@ 2026-09-02 11:29 Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 01/12] dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware property Geert Uytterhoeven
` (11 more replies)
0 siblings, 12 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Hi all,
TL;DR:
Describe hardware in DT, and perform mapping to abstractions offered
by SCMI in Linux.
The Renesas R-Car X5H-based Ironhide board is the first Renesas
SoC/board combination that implements the ARM System Control and
Management Interface (SCMI).
This means Linux can no longer perform various system operations (e.g.
clock, power domain, and reset control) by accessing the hardware
directly. Instead, these operations are abstracted according to various
SCMI sub-protocols, and Linux has to send messages to an SCMI-compliant
firmware running on a System Control Processor (SCP).
More specifically, the R-Car X5H SCP FW SCMI controls access to:
1. Core clocks and module clocks,
2. Module resets,
3. Power domains,
4. System power.
The latter is not relevant for this discussion.
Using SCMI also has an impact on the board DTS: besides the addition of
a firmware/scmi node with protocol-specific subnodes, devices using
SCMI-abstracted system resources now have to refer to these resources
using resource specifiers containing phandles to the SCMI protocol
subnodes, and firmware-specific object IDs[1].
Unfortunately we encountered several issues with this:
- The clock, reset, and power domain IDs are not stable by design,
causing DT incompatibilities.
SCMI requires that the ID space exposed to an agent (i.e. Linux)
starts at zero and is contiguous. Hence any change in system
partitioning (Application CPU core vs. Realtime CPU core,
virtualization, ...) may mean a renumbering of all SCMI IDs,
implying a massive change to the DT.
- There may be different SCP firmware lineages, e.g. proprietary and
certified variants, and FLOSS variants,
- SCMI features may differ across firmware versions,
- SCMI may abstract the hardware in a different way, requiring changes
in (possibly existing) DT bindings and drivers to support the same
hardware with and without SCMI:
- E.g. the number of SCMI clocks inputs to a hardware block may
differ from the actual hardware,
- E.g. hardware clock inputs may be abstracted as SCMI power
domains (or vice versa), like on Qualcomm SA8255P[2].
Experience has taught that not describing the hardware in DT may
lead to major issues later.
- SCMI does not support the concept of a clock domain, so existing
drivers can no longer rely on Runtime PM, but need to be changed to
manage functional clocks explicitly,
- U-Boot IPL (Initial Program Loader) needs a proper hardware
description in DT, not using SCMI.
This list deliberately ignores ID instability and the need for SCMI
quirks during development of the SCMI firmware. While upstream Linux
must only support sufficiently mature firmware versions, vendor trees
(e.g. renesas-lts) may still want to support development firmware
versions.
During last OSSJ/LPC, Marek Vasut pondered if we could keep our own ID
lists stable, and perform a mapping to the IDs used by the actual SCMI
implementation running on the system. This was also briefly discussed
at LPC[3]. After some refining of the initial idea, this series takes a
slightly different approach, by:
1. Describing the actual hardware components in DT, plus a minimum
SCMI glue,
2. Mapping DT hardware descriptions to SCMI-backed objects and
abstractions (or replacements, in case they are unusable,
unavailable, or too different), in Linux drivers, based on the
detected firmware version.
This has the following advantages:
1. The DT ABI is stable,
2. DT bindings and drivers for existing hardware blocks do not need to
be modified,
2. Current and future firmware can be handled in driver code,
3. U-Boot IPL can use almost the same DTS; it just needs stripping of
SCMI-related nodes and properties.
4. If ever needed, the Clock Pulse Generator (CPG) and Module
Controller (MDLC) drivers can be extended to program the hardware
directly if SCMI is not present,
This series consists of four parts:
1. Patches 1-2 update the DT bindings for the R-Car X5H Clock Pulse
Generator (CPG) and Module Controller (MDLC) blocks,
2. Patches 3-7 add new interfaces needed by the remapping support,
3. Patches 8-10 prepare and add SCMI remapping support to the R-Car
X5H CPG and MDLC drivers,
4. Patches 11-12 enable more SCMI protocols on R-Car X5H Ironhide, and
link the CPG and MDLC blocks to their SCMI provider.
Changes compared to v2[4]:
- New patches:
"[PATCH v3 06/12] reset: Extract __reset_control_get_from_provider()",
"[PATCH v3 08/12] clk: renesas: r8a78000: Add clk_hw to clk_map",
- Move DT binding patches forward in series,
- Add "renesas" vendor prefix and "scmi-" function prefix to the
"firmware" property (I still think the vendor property should be
dropped, or replaced by "arm"),
- Add "of_" prefix to genpd_get_from_provider(),
- Replace reset_controller_get_provider() by
reset_control_get_from_provider_exclusive(),
- Add kerneldoc,
- Rebase,
- Consistently use /* sentinel */ for zero sentinels,
- Call reset_control_*() APIs instead of internal reset_control_ops
methods,
- Rename struct mod_map to struct mod_map_in,
- Add struct mod_map, which also contains a reset_control pointer,
- Add fill_mod_map() to obtain all SCMI reset_control structures
up-front, as one can no longer use lazy look-up,
- Prefix DEFINE_MDLC_RESET_WRAPPER() parameters with underscores.
Changes compared to v1[5]:
- Drop SCMI quirks and SCMI mapping tables,
- Move CPG/MDLC DT bindings and minimal base drivers to a separate
series,
- Add that SCMI may provide different abstractions,
- Add missing asterisk to blank kerneldoc line,
- Let scmi_get_base_info() return -EPROBE_DEFER or -EOPNOTSUPP instead
of -ENOENT, and propagate these errors in callers,
- Fall back to the default support when SCMI support or firmware is
not available, or when the detected SCMI firmware version is not
supported by the driver,
- Improve error message on scmi_get_base_info() failure,
- Check if SCMI firmware node is available,
- Use reverse xmas ordering in r8a78000_cpg_probe(),
- Replace the scmi_*_np members of struct r8a78000_*_priv by local
variables in the probe functions, and pass them to the fill_*_map()
functions,
- Join split short lines,
- Move check for supported firmware version up,
- Fix DT misindentations,
- Add scmi_clk node, as it is no longer added in earlier commits.
Note that in reponse of feedback on v1, I did try to use SCMI IDs in DT,
and handle most issues in Linux SCMI drivers and SCMI quirks[6]. While
the result worked, it did not solve everything in the issues list above.
Note that this series does not include actual SCMI quirks and CPG/MDLC
mapping tables, as the SCMI firmware for R-Car X5H is still under
development.
For testing, I have pushed this series plus additional work to[7].
Thanks for your comments!
[1] Documentation/devicetree/bindings/firmware/arm,scmi.yaml
[2] "[PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p"
https://lore.kernel.org/20260629-qcom-sa8255p-emac-v11-1-1b7fb95b51f9@oss.qualcomm.com
[3] "Firmware ABI stability" at Linux Plumbers Conference 2025
https://lpc.events/event/19/contributions/2153/
[4] "[PATCH v2 00/10] R-Car X5H Ironhide CPG/MDLC SCMI remapping
support"
https://lore.kernel.org/cover.1783505329.git.geert+renesas@glider.be
[5] "[PATCH/RFC 00/14] R-Car X5H Ironhide SCMI CPG/MDLC remapping"
https://lore.kernel.org/cover.1776793163.git.geert+renesas@glider.be
[6] "[PATCH/RFC 0/9] R-Car X5H Ironhide pure SCMI proof-of-concept"
https://lore.kernel.org/cover.1781171705.git.geert+renesas@glider.be/
[7] topic/rcar-x5h-ironhide-scmi-cpg-mdlc-remapping-v3 branch of
https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git
Geert Uytterhoeven (12):
dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware
property
dt-bindings: power: renesas,r8a78000-mdlc: Add firmware property
firmware: arm_scmi: Add scmi_get_base_info()
of: property: fw_devlink: Add support for renesas,scmi-firmware
pmdomain: Make genpd_get_from_provider() public
reset: Extract __reset_control_get_from_provider()
reset: Add reset_control_get_from_provider_exclusive()
clk: renesas: r8a78000: Add clk_hw to clk_map
clk: renesas: r8a78000: Add SCMI remapping support
pmdomain: renesas: r8a78000: Add SCMI remapping support
arm64: dts: renesas: ironhide: Enable SCMI devpd, sys, clock, and
reset
arm64: dts: renesas: ironhide: Add CPG/MDLC renesas,scmi-firmware
properties
.../bindings/clock/renesas,r8a78000-cpg.yaml | 9 +
.../bindings/power/renesas,r8a78000-mdlc.yaml | 9 +
.../boot/dts/renesas/r8a78000-ironhide.dts | 135 ++++++
drivers/clk/renesas/r8a78000-cpg.c | 230 +++++++++--
drivers/firmware/arm_scmi/driver.c | 33 ++
drivers/of/property.c | 2 +
drivers/pmdomain/core.c | 22 +-
drivers/pmdomain/renesas/r8a78000-mdlc.c | 383 ++++++++++++++++--
drivers/reset/core.c | 119 ++++--
include/linux/pm_domain.h | 7 +
include/linux/reset.h | 8 +
include/linux/scmi_protocol.h | 8 +
12 files changed, 859 insertions(+), 106 deletions(-)
--
2.43.0
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 01/12] dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware property
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 02/12] dt-bindings: power: renesas,r8a78000-mdlc: Add firmware property Geert Uytterhoeven
` (10 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
On systems using the ARM System Control and Management Interface (SCMI),
the Clock Pulse Generator hardware registers must not be accessed
directly. Instead, the SCMI message protocol must be used for inquiry,
configuration, and control of clocks.
Add a "renesas,scmi-firmware" property to distinguish between systems
with and without SCMI, and to indicate which SCMI firmware interface
provider to communicate with.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Add "renesas" vendor prefix to the property (I still think it
should be dropped, or replaced by "arm"),
- Add "scmi-" prefix to the property,
- Elaborate rationale,
- Move forward in series,
v2:
- Spin off from "dt-bindings: clock: Document Renesas R-Car X5H Clock
Pulse Generator".
---
.../devicetree/bindings/clock/renesas,r8a78000-cpg.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a78000-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,r8a78000-cpg.yaml
index 4e23bba334382346..d4123b1d1890c624 100644
--- a/Documentation/devicetree/bindings/clock/renesas,r8a78000-cpg.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,r8a78000-cpg.yaml
@@ -35,6 +35,14 @@ properties:
<dt-bindings/clock/renesas,r8a78000-cpg.h>.
const: 1
+ renesas,scmi-firmware:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ On systems where the CPG must not be accessed directly, but only through
+ an SCMI firmware interface provider, this property must be present and
+ reference the device node that describes the SCMI compliant firmware
+ interface provider to use instead.
+
required:
- compatible
- reg
@@ -52,4 +60,5 @@ examples:
clocks = <&extal_clk>, <&extalr_clk>;
clock-names = "extal", "extalr";
#clock-cells = <1>;
+ renesas,scmi-firmware = <&scmi>;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 02/12] dt-bindings: power: renesas,r8a78000-mdlc: Add firmware property
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 01/12] dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware property Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 03/12] firmware: arm_scmi: Add scmi_get_base_info() Geert Uytterhoeven
` (9 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
On systems using the ARM System Control and Management Interface (SCMI),
Module Controller hardware registers must not be accessed directly.
Instead, the SCMI message protocol must be used for inquiry,
configuration, and control of power domains, clocks, and resets.
Add a "renesas,scmi-firmware" property to distinguish between systems
with and without SCMI, and to indicate which SCMI firmware interface
provider to communicate with.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Add "renesas" vendor prefix to the property (I still think it
should be dropped, or replaced by "arm"),
- Add "scmi-" prefix to the property,
- Elaborate rationale,
- Move forward in series,
v2:
- Spin off from "dt-bindings: power: Document Renesas R-Car X5H Module
Controller".
---
.../devicetree/bindings/power/renesas,r8a78000-mdlc.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/renesas,r8a78000-mdlc.yaml b/Documentation/devicetree/bindings/power/renesas,r8a78000-mdlc.yaml
index 1dba1e1b1c5b52d0..27d85dd49f954623 100644
--- a/Documentation/devicetree/bindings/power/renesas,r8a78000-mdlc.yaml
+++ b/Documentation/devicetree/bindings/power/renesas,r8a78000-mdlc.yaml
@@ -43,6 +43,14 @@ properties:
and thus identical to the second power domain specifier cell.
const: 1
+ renesas,scmi-firmware:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ On systems where the MDLC must not be accessed directly, but only through
+ an SCMI firmware interface provider, this property must be present and
+ reference the device node that describes the SCMI compliant firmware
+ interface provider to use instead.
+
required:
- compatible
- reg
@@ -58,4 +66,5 @@ examples:
reg = <0xc3060000 0x1000>;
#power-domain-cells = <2>;
#reset-cells = <1>;
+ renesas,scmi-firmware = <&scmi>;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 03/12] firmware: arm_scmi: Add scmi_get_base_info()
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 01/12] dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware property Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 02/12] dt-bindings: power: renesas,r8a78000-mdlc: Add firmware property Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 04/12] of: property: fw_devlink: Add support for renesas,scmi-firmware Geert Uytterhoeven
` (8 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Currently non-SCMI drivers cannot find out what the specific versions of
each SCMI provider implementation on the running system are.
However, different versions may use different ABIs (e.g. different clock
IDs), provide different abstractions, or behave different, requiring
remapping or workarounds in other drivers.
Add a public function to obtain base protocol information for the
selected SCMI provider. This will be used by the R-Car X5H Clock Pulse
Generator and Module Controller drivers, to map hardware descriptions in
DT to SCMI abstractions offered by the SCMI firmware implementation
present.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- No changes,
v2:
- Add that SCMI may provide different abstractions,
- Add missing asterisk to blank kerneldoc line,
- Return -EPROBE_DEFER or -EOPNOTSUPP instead of -ENOENT.
---
drivers/firmware/arm_scmi/driver.c | 33 ++++++++++++++++++++++++++++++
include/linux/scmi_protocol.h | 8 ++++++++
2 files changed, 41 insertions(+)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index ef29fd223287dd58..478f25ae0587e422 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -3525,6 +3525,39 @@ int scmi_inflight_count(const struct scmi_handle *handle)
}
}
+/**
+ * scmi_get_base_info() - Get SCMI base protocol information
+ *
+ * @of_node: pointer to a device node for an SCMI provider
+ * @version: pointer to write base protocol information
+ *
+ * Check if an SCMI device has been instantiated for the passed device node
+ * pointer, and, if found, return its base info.
+ *
+ * Return: 0 on Success,
+ * -EPROBE_DEFER if the SCMI provider is not ready yet,
+ * -EOPNOTSUPP if SCMI support is disabled.
+ */
+int scmi_get_base_info(struct device_node *of_node,
+ struct scmi_base_info *version)
+{
+ int ret = -EPROBE_DEFER;
+ struct scmi_info *info;
+
+ mutex_lock(&scmi_list_mutex);
+ list_for_each_entry(info, &scmi_list, node) {
+ if (info->dev->of_node == of_node) {
+ *version = info->version;
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&scmi_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(scmi_get_base_info);
+
static int __init scmi_driver_init(void)
{
scmi_quirks_initialize();
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 5ab73b1ab9aa4fa8..fd2d648964f68f53 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -971,6 +971,8 @@ struct scmi_driver {
int scmi_driver_register(struct scmi_driver *driver,
struct module *owner, const char *mod_name);
void scmi_driver_unregister(struct scmi_driver *driver);
+int scmi_get_base_info(struct device_node *of_node,
+ struct scmi_base_info *version);
#else
static inline int
scmi_driver_register(struct scmi_driver *driver, struct module *owner,
@@ -980,6 +982,12 @@ scmi_driver_register(struct scmi_driver *driver, struct module *owner,
}
static inline void scmi_driver_unregister(struct scmi_driver *driver) {}
+
+static inline int scmi_get_base_info(struct device_node *of_node,
+ struct scmi_base_info *version)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_ARM_SCMI_PROTOCOL */
#define scmi_register(driver) \
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 04/12] of: property: fw_devlink: Add support for renesas,scmi-firmware
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (2 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 03/12] firmware: arm_scmi: Add scmi_get_base_info() Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 05/12] pmdomain: Make genpd_get_from_provider() public Geert Uytterhoeven
` (7 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Let fw_devlink create device links between consumers and suppliers of
SCMI firmware on Renesas platforms, and enforce these dependencies.
This prevents probing of drivers before the firmware they depend on
becomes available, thus avoiding unneeded probe deferrals.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- s/firmware/renesas,scmi-firmware/,
v2:
- No changes.
---
drivers/of/property.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 72cf12907de034e9..e79cd3cce4e2e41a 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1417,6 +1417,7 @@ DEFINE_SIMPLE_PROP(power_supplies, "power-supplies", NULL)
DEFINE_SIMPLE_PROP(mmc_pwrseq, "mmc-pwrseq", NULL)
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
+DEFINE_SIMPLE_PROP(renesas_scmi_firmware, "renesas,scmi-firmware", NULL)
static struct device_node *parse_pinctrl_n(struct device_node *np,
const char *prop_name, int index)
@@ -1574,6 +1575,7 @@ static const struct supplier_bindings of_supplier_bindings[] = {
{ .parse_prop = parse_regulators, },
{ .parse_prop = parse_gpio, },
{ .parse_prop = parse_gpios, },
+ { .parse_prop = parse_renesas_scmi_firmware, },
{
.parse_prop = parse_post_init_providers,
.fwlink_flags = FWLINK_FLAG_IGNORE,
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 05/12] pmdomain: Make genpd_get_from_provider() public
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (3 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 04/12] of: property: fw_devlink: Add support for renesas,scmi-firmware Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider() Geert Uytterhoeven
` (6 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Unlike the corresponding function in the clock subsystem
(of_clk_get_from_provider()), genpd_get_from_provider() is private, and
thus cannot be used by PM Domain drivers.
Make it public, so it be used by the R-Car X5H Module Controller driver.
Add an "of_"-prefix for consistency with public genpd function naming.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Add "of_" prefix,
v2:
- No changes.
---
drivers/pmdomain/core.c | 22 +++++++++++-----------
include/linux/pm_domain.h | 7 +++++++
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 842c4169e290677c..ac3a07066e7fc0e7 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -2890,7 +2890,7 @@ void of_genpd_del_provider(struct device_node *np)
EXPORT_SYMBOL_GPL(of_genpd_del_provider);
/**
- * genpd_get_from_provider() - Look-up PM domain
+ * of_genpd_get_from_provider() - Look-up PM domain
* @genpdspec: OF phandle args to use for look-up
*
* Looks for a PM domain provider under the node specified by @genpdspec and if
@@ -2900,8 +2900,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
* Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
* on failure.
*/
-static struct generic_pm_domain *genpd_get_from_provider(
- const struct of_phandle_args *genpdspec)
+struct generic_pm_domain *of_genpd_get_from_provider(const struct of_phandle_args *genpdspec)
{
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
struct of_genpd_provider *provider;
@@ -2923,6 +2922,7 @@ static struct generic_pm_domain *genpd_get_from_provider(
return genpd;
}
+EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
/**
* of_genpd_add_child_ids() - Parse power-domains-child-ids property
@@ -2995,7 +2995,7 @@ int of_genpd_add_child_ids(struct device_node *np,
goto err_unwind;
/* Get the parent domain */
- parent_genpd = genpd_get_from_provider(&parent_args);
+ parent_genpd = of_genpd_get_from_provider(&parent_args);
of_node_put(parent_args.np);
if (IS_ERR(parent_genpd)) {
pr_err("Failed to get parent domain for %pOF: %ld\n",
@@ -3078,7 +3078,7 @@ int of_genpd_remove_child_ids(struct device_node *np,
if (ret)
continue;
- parent_genpd = genpd_get_from_provider(&parent_args);
+ parent_genpd = of_genpd_get_from_provider(&parent_args);
of_node_put(parent_args.np);
if (IS_ERR(parent_genpd))
continue;
@@ -3109,7 +3109,7 @@ int of_genpd_add_device(const struct of_phandle_args *genpdspec, struct device *
mutex_lock(&gpd_list_lock);
- genpd = genpd_get_from_provider(genpdspec);
+ genpd = of_genpd_get_from_provider(genpdspec);
if (IS_ERR(genpd)) {
ret = PTR_ERR(genpd);
goto out;
@@ -3141,13 +3141,13 @@ int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
mutex_lock(&gpd_list_lock);
- parent = genpd_get_from_provider(parent_spec);
+ parent = of_genpd_get_from_provider(parent_spec);
if (IS_ERR(parent)) {
ret = PTR_ERR(parent);
goto out;
}
- subdomain = genpd_get_from_provider(subdomain_spec);
+ subdomain = of_genpd_get_from_provider(subdomain_spec);
if (IS_ERR(subdomain)) {
ret = PTR_ERR(subdomain);
goto out;
@@ -3179,13 +3179,13 @@ int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec,
mutex_lock(&gpd_list_lock);
- parent = genpd_get_from_provider(parent_spec);
+ parent = of_genpd_get_from_provider(parent_spec);
if (IS_ERR(parent)) {
ret = PTR_ERR(parent);
goto out;
}
- subdomain = genpd_get_from_provider(subdomain_spec);
+ subdomain = of_genpd_get_from_provider(subdomain_spec);
if (IS_ERR(subdomain)) {
ret = PTR_ERR(subdomain);
goto out;
@@ -3373,7 +3373,7 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
return ret;
mutex_lock(&gpd_list_lock);
- pd = genpd_get_from_provider(&pd_args);
+ pd = of_genpd_get_from_provider(&pd_args);
of_node_put(pd_args.np);
if (IS_ERR(pd)) {
mutex_unlock(&gpd_list_lock);
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index f925614aebdbc914..0ef717428f2935e7 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -458,6 +458,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
int of_genpd_add_provider_onecell(struct device_node *np,
struct genpd_onecell_data *data);
void of_genpd_del_provider(struct device_node *np);
+struct generic_pm_domain *of_genpd_get_from_provider(const struct of_phandle_args *genpdspec);
int of_genpd_add_device(const struct of_phandle_args *args, struct device *dev);
int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec,
const struct of_phandle_args *subdomain_spec);
@@ -492,6 +493,12 @@ static inline int of_genpd_add_provider_onecell(struct device_node *np,
static inline void of_genpd_del_provider(struct device_node *np) {}
+static inline struct generic_pm_domain *of_genpd_get_from_provider(
+ const struct of_phandle_args *genpdspec)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline int of_genpd_add_device(const struct of_phandle_args *args,
struct device *dev)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider()
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (4 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 05/12] pmdomain: Make genpd_get_from_provider() public Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-03 8:55 ` Philipp Zabel
2026-09-02 11:29 ` [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive() Geert Uytterhoeven
` (5 subsequent siblings)
11 siblings, 1 reply; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Extract the code to create a reset_control structure from a given
provider into its own function, so it can be reused later.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- New.
---
drivers/reset/core.c | 92 ++++++++++++++++++++++++--------------------
1 file changed, 50 insertions(+), 42 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 38e189d04d09b270..8af7cd2e8a5029df 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -1135,6 +1135,54 @@ __reset_find_rcdev(const struct fwnode_reference_args *args, bool gpio_fallback)
return NULL;
}
+static struct reset_control *
+__reset_control_get_from_provider(const struct fwnode_reference_args *args,
+ struct fwnode_handle *consumer, int index,
+ bool gpio_fallback,
+ enum reset_control_flags flags)
+{
+ struct reset_control *rstc = ERR_PTR(-EINVAL);
+ struct reset_controller_dev *rcdev;
+ int rstc_id = -EINVAL;
+
+ guard(mutex)(&reset_list_mutex);
+
+ rcdev = __reset_find_rcdev(args, gpio_fallback);
+ if (!rcdev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ if (WARN_ON(args->nargs != rcdev->fwnode_reset_n_cells))
+ return ERR_PTR(-EINVAL);
+
+ if (rcdev->of_xlate && is_of_node(consumer)) {
+ struct device_node *np = to_of_node(consumer);
+ struct of_phandle_args of_args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(np,
+ gpio_fallback ? "reset-gpios" : "resets",
+ gpio_fallback ? "#gpio-cells" : "#reset-cells",
+ gpio_fallback ? 0 : index,
+ &of_args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ rstc_id = rcdev->of_xlate(rcdev, &of_args);
+ of_node_put(of_args.np);
+ } else if (rcdev->fwnode_xlate) {
+ rstc_id = rcdev->fwnode_xlate(rcdev, args);
+ }
+ if (rstc_id < 0)
+ return ERR_PTR(rstc_id);
+
+ flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
+
+ scoped_guard(mutex, &rcdev->lock)
+ rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
+
+ return rstc;
+}
+
struct reset_control *
__fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int index,
enum reset_control_flags flags)
@@ -1142,10 +1190,7 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
bool gpio_fallback = false;
struct reset_control *rstc = ERR_PTR(-EINVAL);
- struct reset_controller_dev *rcdev;
struct fwnode_reference_args args;
- struct of_phandle_args of_args;
- int rstc_id = -EINVAL;
int ret;
if (!fwnode)
@@ -1185,46 +1230,9 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
}
}
- guard(mutex)(&reset_list_mutex);
-
- rcdev = __reset_find_rcdev(&args, gpio_fallback);
- if (!rcdev) {
- rstc = ERR_PTR(-EPROBE_DEFER);
- goto out_put;
- }
-
- if (WARN_ON(args.nargs != rcdev->fwnode_reset_n_cells)) {
- rstc = ERR_PTR(-EINVAL);
- goto out_put;
- }
-
- if (rcdev->of_xlate && is_of_node(fwnode)) {
- ret = of_parse_phandle_with_args(to_of_node(fwnode),
- gpio_fallback ? "reset-gpios" : "resets",
- gpio_fallback ? "#gpio-cells" : "#reset-cells",
- gpio_fallback ? 0 : index,
- &of_args);
- if (ret) {
- rstc = ERR_PTR(ret);
- goto out_put;
- }
-
- rstc_id = rcdev->of_xlate(rcdev, &of_args);
- of_node_put(of_args.np);
- } else if (rcdev->fwnode_xlate) {
- rstc_id = rcdev->fwnode_xlate(rcdev, &args);
- }
- if (rstc_id < 0) {
- rstc = ERR_PTR(rstc_id);
- goto out_put;
- }
-
- flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
-
- scoped_guard(mutex, &rcdev->lock)
- rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
+ rstc = __reset_control_get_from_provider(&args, fwnode, index,
+ gpio_fallback, flags);
-out_put:
fwnode_handle_put(args.fwnode);
return rstc;
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive()
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (5 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider() Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:44 ` Geert Uytterhoeven
2026-09-03 10:03 ` Philipp Zabel
2026-09-02 11:29 ` [PATCH v3 08/12] clk: renesas: r8a78000: Add clk_hw to clk_map Geert Uytterhoeven
` (4 subsequent siblings)
11 siblings, 2 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
When stacking two reset controllers, the upper one should go through the
proper channels: request exclusive reset controls and use them via the
reset_control_*() APIs. However, unlike the clock subsystem, which has
of_clk_get_from_provider(), the reset subsystem does not offer a way to
lookup and obtain a reset from a reset provider.
Hence add a public helper reset_control_get_from_provider_exclusive()
to lookup and obtain an exclusive reference to a reset controller, based
on the recently introduced __reset_control_get_from_provider() helper.
This will be used by the R-Car X5H Module Controller driver.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Replace reset_controller_get_provider() by
reset_control_get_from_provider_exclusive(),
- Add kerneldoc,
v2:
- No changes.
---
drivers/reset/core.c | 37 ++++++++++++++++++++++++++++++++-----
include/linux/reset.h | 8 ++++++++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 8af7cd2e8a5029df..6d4c95b3edb18248 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -1141,6 +1141,7 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
bool gpio_fallback,
enum reset_control_flags flags)
{
+ struct fwnode_handle *fwnode = consumer ?: args->fwnode;
struct reset_control *rstc = ERR_PTR(-EINVAL);
struct reset_controller_dev *rcdev;
int rstc_id = -EINVAL;
@@ -1154,18 +1155,26 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
if (WARN_ON(args->nargs != rcdev->fwnode_reset_n_cells))
return ERR_PTR(-EINVAL);
- if (rcdev->of_xlate && is_of_node(consumer)) {
- struct device_node *np = to_of_node(consumer);
+ if (rcdev->of_xlate && is_of_node(fwnode)) {
+ struct device_node *np = to_of_node(fwnode);
struct of_phandle_args of_args;
int ret;
- ret = of_parse_phandle_with_args(np,
+ if (consumer) {
+ ret = of_parse_phandle_with_args(np,
gpio_fallback ? "reset-gpios" : "resets",
gpio_fallback ? "#gpio-cells" : "#reset-cells",
gpio_fallback ? 0 : index,
&of_args);
- if (ret)
- return ERR_PTR(ret);
+ if (ret)
+ return ERR_PTR(ret);
+ } else {
+ of_args.np = of_node_get(np);
+ of_args.args_count = args->nargs;
+
+ for (unsigned int i = 0; i < args->nargs; i++)
+ of_args.args[i] = args->args[i];
+ }
rstc_id = rcdev->of_xlate(rcdev, &of_args);
of_node_put(of_args.np);
@@ -1257,6 +1266,24 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
}
EXPORT_SYMBOL_GPL(__reset_control_get);
+/**
+ * reset_control_get_from_provider_exclusive - Lookup and obtain an exclusive
+ * reference to a reset controller.
+ * @args: Reference to the reset controller provider with all the args like
+ * reset number
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ * If this function is called more than once for the same reset control it will
+ * return -EBUSY.
+ */
+struct reset_control *
+reset_control_get_from_provider_exclusive(const struct fwnode_reference_args *args)
+{
+ return __reset_control_get_from_provider(args, NULL, 0, false,
+ RESET_CONTROL_EXCLUSIVE);
+}
+EXPORT_SYMBOL_GPL(reset_control_get_from_provider_exclusive);
+
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
enum reset_control_flags flags)
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 9c391cf0c82298a0..09ee47b27f88d3b1 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -90,6 +90,8 @@ struct reset_control *__fwnode_reset_control_get(struct fwnode_handle *fwnode,
const char *id, int index, enum reset_control_flags flags);
struct reset_control *__reset_control_get(struct device *dev, const char *id,
int index, enum reset_control_flags flags);
+struct reset_control *reset_control_get_from_provider_exclusive(
+ const struct fwnode_reference_args *args);
void reset_control_put(struct reset_control *rstc);
int __reset_control_bulk_get(struct device *dev, int num_rstcs,
struct reset_control_bulk_data *rstcs,
@@ -173,6 +175,12 @@ static inline struct reset_control *__reset_control_get(
return optional ? NULL : ERR_PTR(-ENOTSUPP);
}
+static inline struct reset_control *reset_control_get_from_provider_exclusive(
+ const struct fwnode_reference_args *args)
+{
+ return NULL;
+}
+
static inline int
reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 08/12] clk: renesas: r8a78000: Add clk_hw to clk_map
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (6 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive() Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 09/12] clk: renesas: r8a78000: Add SCMI remapping support Geert Uytterhoeven
` (3 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Prepare for mapping to other than fixed-rate clocks by adding a clk_hw
pointer to the clk_map structure, and populating it up-front.
Move r8a78000_cpg_priv.fixed_hws into fill_clk_map(), as it is no longer
needed afterwards, and drop NUM_FIXED_CLKS.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- New.
---
drivers/clk/renesas/r8a78000-cpg.c | 78 +++++++++++++++++++++---------
1 file changed, 56 insertions(+), 22 deletions(-)
diff --git a/drivers/clk/renesas/r8a78000-cpg.c b/drivers/clk/renesas/r8a78000-cpg.c
index 7946f9d0b423def1..873d521ed3d6f705 100644
--- a/drivers/clk/renesas/r8a78000-cpg.c
+++ b/drivers/clk/renesas/r8a78000-cpg.c
@@ -16,18 +16,23 @@
#include <dt-bindings/clock/renesas,r8a78000-cpg.h>
+struct clk_map_in {
+ int dt_id; /* DT binding clock ID or -1 sentinel */
+ u32 fw_id; /* FIXED_CLK() ID */
+};
+
struct clk_map {
int dt_id; /* DT binding clock ID or -1 sentinel */
u32 fw_id; /* FIXED_CLK() ID */
+ struct clk_hw *hw;
};
enum fixed_clk {
FIXED_CLK_66M,
FIXED_CLK_266M,
- NUM_FIXED_CLKS
};
-static const unsigned long fixed_clk_rates[NUM_FIXED_CLKS] = {
+static const unsigned long fixed_clk_rates[] = {
[FIXED_CLK_66M] = 66666000,
[FIXED_CLK_266M] = 266660000,
};
@@ -39,12 +44,10 @@ static const unsigned long fixed_clk_rates[NUM_FIXED_CLKS] = {
*
* @dev: CPG device
* @map: Mapping from DT clock IDs to fixed-rate clocks
- * @fixed_hws: Fixed rate clocks
*/
struct r8a78000_cpg_priv {
struct device *dev;
const struct clk_map *map;
- struct clk_hw *fixed_hws[NUM_FIXED_CLKS];
};
static const struct clk_map *clk_map_find(const struct clk_map *map, u32 id)
@@ -81,8 +84,7 @@ static struct clk_hw *r8a78000_clk_get(struct of_phandle_args *spec,
}
dev_dbg(dev, "Mapping DT clock %u to fixed clock %u\n", id, map->fw_id);
-
- hw = priv->fixed_hws[map->fw_id];
+ hw = map->hw;
dev_dbg(dev, "clock %u is %s at %lu Hz\n", id, clk_hw_get_name(hw),
clk_hw_get_rate(hw));
@@ -90,35 +92,69 @@ static struct clk_hw *r8a78000_clk_get(struct of_phandle_args *spec,
return hw;
}
-static int register_fixed_clks(struct r8a78000_cpg_priv *priv)
+static struct clk_hw **register_fixed_clks(struct device *dev)
{
- struct device *dev = priv->dev;
+ unsigned int n = ARRAY_SIZE(fixed_clk_rates);
+ struct clk_hw **hws, *hw;
unsigned long rate;
- struct clk_hw *hw;
const char *name;
- for (unsigned int i = 0; i < ARRAY_SIZE(fixed_clk_rates); i++) {
+ hws = devm_kcalloc(dev, n, sizeof(*hws), GFP_KERNEL);
+ if (!hws)
+ return ERR_PTR(-ENOMEM);
+
+ for (unsigned int i = 0; i < n; i++) {
rate = fixed_clk_rates[i];
name = devm_kasprintf(dev, GFP_KERNEL, "cpg-%lu", rate);
if (!name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
hw = devm_clk_hw_register_fixed_rate(dev, name, NULL, 0, rate);
if (IS_ERR(hw))
- return PTR_ERR(hw);
+ return ERR_CAST(hw);
- priv->fixed_hws[i] = hw;
+ hws[i] = hw;
}
- return 0;
+ return hws;
+}
+
+static const struct clk_map *fill_clk_map(struct r8a78000_cpg_priv *priv,
+ const struct clk_map_in *map_in)
+{
+ struct device *dev = priv->dev;
+ struct clk_hw **fixed_hws;
+ struct clk_map *map;
+ unsigned int i;
+
+ fixed_hws = register_fixed_clks(dev);
+ if (IS_ERR(fixed_hws))
+ return ERR_CAST(fixed_hws);
+
+ for (i = 0; map_in[i].dt_id >= 0; i++) { }
+
+ map = devm_kcalloc(dev, i + 1, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; ; i++) {
+ map[i].dt_id = map_in[i].dt_id;
+ if (map[i].dt_id < 0)
+ break;
+
+ map[i].fw_id = map_in[i].fw_id;
+ map[i].hw = fixed_hws[map[i].fw_id];
+ }
+
+ devm_kfree(dev, fixed_hws);
+ return map;
}
static int r8a78000_cpg_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct r8a78000_cpg_priv *priv;
- const struct clk_map *map;
- int ret;
+ const struct clk_map_in *map;
map = of_device_get_match_data(dev);
if (!map)
@@ -129,16 +165,14 @@ static int r8a78000_cpg_probe(struct platform_device *pdev)
return -ENOMEM;
priv->dev = dev;
- priv->map = map;
-
- ret = register_fixed_clks(priv);
- if (ret)
- return ret;
+ priv->map = fill_clk_map(priv, map);
+ if (IS_ERR(priv->map))
+ return PTR_ERR(priv->map);
return devm_of_clk_add_hw_provider(dev, r8a78000_clk_get, priv);
}
-static const struct clk_map r8a78000_cpg_default[] = {
+static const struct clk_map_in r8a78000_cpg_default[] = {
{ R8A78000_CPG_SGASYNCD4_PERW_BUS, FIXED_CLK(266M) },
{ R8A78000_CPG_SGASYNCD16_PERW_BUS, FIXED_CLK(66M) },
{ -1 }
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 09/12] clk: renesas: r8a78000: Add SCMI remapping support
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (7 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 08/12] clk: renesas: r8a78000: Add clk_hw to clk_map Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 10/12] pmdomain: " Geert Uytterhoeven
` (2 subsequent siblings)
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Extend the Clock Pulse Generator driver for R-Car X5H with SCMI support,
to remap DT clock IDs to abstractions (clocks) offered by the SCMI
firmware implementation present when running on a system with a
supported SCMI firmware implementation. Take into account peculiarities
of the detected SCMI firmware version, and use fixed-rate clocks as
replacements for SCMI clocks that are known to be unusable.
This lets us avoid putting unstable SCMI IDs in DT, and allows us to use
the same hardware description in SoC DTS for systems with and without
SCMI firmware.
Note that this only includes SCMI remapping support, and does not
include yet any mapping tables for specific SCMI firmware versions.
Suggested-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Rebase,
- Consistently use /* sentinel */ for zero sentinels,
- s/firmware/renesas,scmi-firmware/,
- Reword,
v2:
- Spin off from "clk: renesas: Add R-Car X5H CPG SCMI remapping
driver",
- Use reverse xmas ordering in r8a78000_cpg_probe(),
- Propagate error codes from scmi_get_base_info() now it can return
-EPROBE_DEFER,
- Improve error message on scmi_get_base_info() failure,
- Check if SCMI firmware node is available,
- Replace the scmi_clk_np member of struct r8a78000_cpg_priv by a
local variable in r8a78000_cpg_probe(), and pass it to
fill_clk_map(),
- Join split short lines,
- Fall back to the default support when SCMI support or firmware is
not available, or when the detected SCMI firmware version is not
supported by the driver,
- Drop mapping tables.
---
drivers/clk/renesas/r8a78000-cpg.c | 164 +++++++++++++++++++++++++++--
1 file changed, 153 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/renesas/r8a78000-cpg.c b/drivers/clk/renesas/r8a78000-cpg.c
index 873d521ed3d6f705..2273047315db51ff 100644
--- a/drivers/clk/renesas/r8a78000-cpg.c
+++ b/drivers/clk/renesas/r8a78000-cpg.c
@@ -5,6 +5,7 @@
* Copyright (C) 2026 Glider bv
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/dev_printk.h>
@@ -12,21 +13,32 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/scmi_protocol.h>
#include <linux/slab.h>
#include <dt-bindings/clock/renesas,r8a78000-cpg.h>
struct clk_map_in {
int dt_id; /* DT binding clock ID or -1 sentinel */
- u32 fw_id; /* FIXED_CLK() ID */
+ u32 fw_id; /* SCMI firmware clock ID or FIXED_CLK() ID */
};
struct clk_map {
int dt_id; /* DT binding clock ID or -1 sentinel */
- u32 fw_id; /* FIXED_CLK() ID */
+ u32 fw_id; /* SCMI firmware clock ID or FIXED_CLK() ID */
struct clk_hw *hw;
};
+struct fw_map {
+ u32 impl_ver;
+ const struct clk_map_in *map;
+};
+
+struct cpg_data {
+ const struct clk_map_in *default_map;
+ const struct fw_map *fw_map;
+};
+
enum fixed_clk {
FIXED_CLK_66M,
FIXED_CLK_266M,
@@ -37,13 +49,14 @@ static const unsigned long fixed_clk_rates[] = {
[FIXED_CLK_266M] = 266660000,
};
-#define FIXED_CLK(rate) FIXED_CLK_ ## rate
+#define FIXED_CLK_OFFSET 0x80000000
+#define FIXED_CLK(rate) FIXED_CLK_OFFSET + FIXED_CLK_ ## rate
/**
* struct r8a78000_cpg_priv - Clock Pulse Generator Private Data
*
* @dev: CPG device
- * @map: Mapping from DT clock IDs to fixed-rate clocks
+ * @map: Mapping from DT clock IDs to SCMI or fixed-rate clocks
*/
struct r8a78000_cpg_priv {
struct device *dev;
@@ -83,8 +96,19 @@ static struct clk_hw *r8a78000_clk_get(struct of_phandle_args *spec,
return ERR_PTR(-ENOENT);
}
- dev_dbg(dev, "Mapping DT clock %u to fixed clock %u\n", id, map->fw_id);
+ if (map->fw_id < FIXED_CLK_OFFSET)
+ dev_dbg(dev, "Mapping DT clock %u to SCMI clock %u\n", id,
+ map->fw_id);
+ else
+ dev_dbg(dev, "Mapping DT clock %u to fixed clock %u\n", id,
+ map->fw_id - FIXED_CLK_OFFSET);
+
hw = map->hw;
+ if (!hw) {
+ /* CLOCK_ATTRIBUTES is not supported */
+ dev_err(dev, "Clock %u is not available\n", id);
+ return ERR_PTR(-ENOENT);
+ }
dev_dbg(dev, "clock %u is %s at %lu Hz\n", id, clk_hw_get_name(hw),
clk_hw_get_rate(hw));
@@ -92,6 +116,21 @@ static struct clk_hw *r8a78000_clk_get(struct of_phandle_args *spec,
return hw;
}
+static struct device_node *scmi_find_proto(struct device_node *scmi, u32 proto)
+{
+ for_each_available_child_of_node_scoped(scmi, child) {
+ u32 reg;
+
+ if (of_property_read_u32(child, "reg", ®))
+ continue;
+
+ if (reg == proto)
+ return_ptr(child);
+ }
+
+ return NULL;
+}
+
static struct clk_hw **register_fixed_clks(struct device *dev)
{
unsigned int n = ARRAY_SIZE(fixed_clk_rates);
@@ -120,11 +159,15 @@ static struct clk_hw **register_fixed_clks(struct device *dev)
}
static const struct clk_map *fill_clk_map(struct r8a78000_cpg_priv *priv,
- const struct clk_map_in *map_in)
+ const struct clk_map_in *map_in,
+ struct device_node *scmi_clk_np)
{
+ struct of_phandle_args scmi_spec;
struct device *dev = priv->dev;
struct clk_hw **fixed_hws;
struct clk_map *map;
+ struct clk_hw *hw;
+ struct clk *clk;
unsigned int i;
fixed_hws = register_fixed_clks(dev);
@@ -143,7 +186,38 @@ static const struct clk_map *fill_clk_map(struct r8a78000_cpg_priv *priv,
break;
map[i].fw_id = map_in[i].fw_id;
- map[i].hw = fixed_hws[map[i].fw_id];
+ if (map[i].fw_id >= FIXED_CLK_OFFSET) {
+ enum fixed_clk idx = map[i].fw_id - FIXED_CLK_OFFSET;
+
+ map[i].hw = fixed_hws[idx];
+ continue;
+ }
+
+ scmi_spec.np = scmi_clk_np;
+ scmi_spec.args_count = 1;
+ scmi_spec.args[0] = map[i].fw_id;
+
+ clk = of_clk_get_from_provider(&scmi_spec);
+ if (IS_ERR(clk))
+ return dev_err_cast_probe(dev, clk,
+ "Failed to get SCMI clock %u\n", map[i].fw_id);
+
+ hw = __clk_get_hw(clk);
+ if (IS_ERR(hw))
+ return dev_err_cast_probe(dev, hw,
+ "Failed to get SCMI clock hw %u\n",
+ map[i].fw_id);
+
+ if (!hw) {
+ /* CLOCK_ATTRIBUTES is not supported */
+ dev_warn(dev, "SCMI clock %u is NULL\n", map[i].fw_id);
+ continue;
+ }
+
+ dev_dbg(priv->dev, "SCMI clock %u is %s at %lu Hz\n",
+ map[i].fw_id, clk_hw_get_name(hw), clk_hw_get_rate(hw));
+
+ map[i].hw = hw;
}
devm_kfree(dev, fixed_hws);
@@ -152,20 +226,79 @@ static const struct clk_map *fill_clk_map(struct r8a78000_cpg_priv *priv,
static int r8a78000_cpg_probe(struct platform_device *pdev)
{
+ struct device_node *scmi __free(device_node) = NULL;
+ struct device_node *scmi_clk_np = NULL;
struct device *dev = &pdev->dev;
+ const struct cpg_data *cpg_data;
struct r8a78000_cpg_priv *priv;
+ struct scmi_base_info version;
const struct clk_map_in *map;
+ const struct fw_map *fw_map;
+ int ret;
- map = of_device_get_match_data(dev);
- if (!map)
+ cpg_data = of_device_get_match_data(dev);
+ if (!cpg_data)
return -ENODEV;
+ map = cpg_data->default_map;
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
- priv->map = fill_clk_map(priv, map);
+
+ scmi = of_parse_phandle(dev->of_node, "renesas,scmi-firmware", 0);
+ if (!scmi) {
+ dev_dbg(dev, "Cannot find SCMI firmware node\n");
+ goto fallback;
+ }
+
+ if (!of_device_is_available(scmi)) {
+ dev_dbg(dev, "SCMI firmware node is not available\n");
+ goto fallback;
+ }
+
+ scmi_clk_np = scmi_find_proto(scmi, SCMI_PROTOCOL_CLOCK);
+ if (!scmi_clk_np) {
+ dev_dbg(dev, "Cannot find SCMI clock management protocol\n");
+ goto fallback;
+ }
+
+ ret = scmi_get_base_info(scmi, &version);
+ if (ret == -EPROBE_DEFER)
+ return dev_err_probe(dev, ret, "SCMI provider not ready\n");
+ if (ret) {
+ dev_dbg(dev, "SCMI is not available\n");
+ goto fallback;
+ }
+
+ if (strcmp(version.vendor_id, "Renesas") ||
+ strcmp(version.sub_vendor_id, "None")) {
+ dev_warn(dev, "Unsupported SCMI firmware %s/%s\n",
+ version.vendor_id, version.sub_vendor_id);
+ goto fallback;
+ }
+
+ for (fw_map = cpg_data->fw_map; fw_map->map; fw_map++) {
+ if (fw_map->impl_ver == version.impl_ver)
+ break;
+ }
+
+ if (!fw_map->map) {
+ dev_warn(dev, "Unsupported SCMI firmware version 0x%08x\n",
+ version.impl_ver);
+ goto fallback;
+ }
+
+ map = fw_map->map;
+
+fallback:
+ /*
+ * We cannot do lazy look-up in r8a78000_clk_get(), as that function is
+ * called with of_clk_mutex already held.
+ */
+ priv->map = fill_clk_map(priv, map, scmi_clk_np);
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
@@ -178,10 +311,19 @@ static const struct clk_map_in r8a78000_cpg_default[] = {
{ -1 }
};
+static const struct fw_map r8a78000_cpg_fw_map[] = {
+ { /* sentinel */ }
+};
+
+static const struct cpg_data r8a78000_cpg_data = {
+ .default_map = r8a78000_cpg_default,
+ .fw_map = r8a78000_cpg_fw_map,
+};
+
static const struct of_device_id r8a78000_cpg_match[] = {
{
.compatible = "renesas,r8a78000-cpg",
- .data = &r8a78000_cpg_default,
+ .data = &r8a78000_cpg_data,
},
{ /* sentinel */ }
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 10/12] pmdomain: renesas: r8a78000: Add SCMI remapping support
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (8 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 09/12] clk: renesas: r8a78000: Add SCMI remapping support Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 11/12] arm64: dts: renesas: ironhide: Enable SCMI devpd, sys, clock, and reset Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 12/12] arm64: dts: renesas: ironhide: Add CPG/MDLC renesas,scmi-firmware properties Geert Uytterhoeven
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Extend the Module Controller driver for R-Car X5H with SCMI support, to
remap hardware power domain, module, and reset IDs to abstractions
(power domains, clocks, and resets) offered by the SCMI firmware
implementation present when running on a system with a supported SCMI
firmware implementation. Take into account peculiarities of the
detected SCMI firmware version, like missing resets.
Note that SCMI clocks representing hardware modules expose access to
Module Standby control: they are fake clocks, with a zero clock rate,
that can just be enabled and disabled. Hence they are controlled from
the clock domain's start/stop callbacks.
This lets us avoid putting unstable SCMI IDs in DT, and allows us to use
the same hardware description in SoC DTS for systems with and without
SCMI firmware.
Note that this only includes SCMI remapping support, and does not
include yet any mapping tables for specific SCMI firmware versions.
Suggested-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- Rebase to v7.3-rc1,
- Consistently use /* sentinel */ for zero sentinels,
- s/genpd_get_from_provider/of_genpd_get_from_provider/,
- s/firmware/renesas,scmi-firmware/,
- Replace reset_controller_get_provider() by
reset_control_get_from_provider_exclusive(),
- Call reset_control_*() APIs instead of internal reset_control_ops
methods,
- Rename struct mod_map to struct mod_map_in,
- Add struct mod_map, which also contains a reset_control pointer,
- Add fill_mod_map() to obtain all SCMI reset_control structures
up-front, as one can no longer use lazy look-up,
- Prefix DEFINE_MDLC_RESET_WRAPPER() parameters with underscores,
- Reword,
v2:
- Spin off from "pmdomain: renesas: Add R-Car X5H MDLC SCMI remapping
driver".
- Propagate error codes from scmi_get_base_info() now it can return
-EPROBE_DEFER,
- Improve error message on scmi_get_base_info() failure,
- Check if SCMI firmware node is available,
- Replace scmi_power_np and scmi_reset_np members of struct
r8a78000_mdlc_priv by local variables in r8a78000_mdlc_probe(), and
pass the former to fill_power_map(),
- Move check for supported firmware version up,
- Fall back to the default support when SCMI support or firmware is
not available, or when the detected SCMI firmware version is not
supported by the driver,
- Drop mapping tables.
---
drivers/pmdomain/renesas/r8a78000-mdlc.c | 383 +++++++++++++++++++++--
1 file changed, 357 insertions(+), 26 deletions(-)
diff --git a/drivers/pmdomain/renesas/r8a78000-mdlc.c b/drivers/pmdomain/renesas/r8a78000-mdlc.c
index 2668fc2ac9cbd388..0238bf8c1e3856b4 100644
--- a/drivers/pmdomain/renesas/r8a78000-mdlc.c
+++ b/drivers/pmdomain/renesas/r8a78000-mdlc.c
@@ -5,24 +5,58 @@
* Copyright (C) 2026 Glider bv
*/
+#include <linux/cleanup.h>
+#include <linux/clk.h>
#include <linux/dev_printk.h>
#include <linux/device-id/of.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
+#include <linux/reset.h>
+#include <linux/scmi_protocol.h>
#include <linux/slab.h>
#include <dt-bindings/power/renesas,r8a78000-mdlc.h>
+struct power_map_in {
+ int hw_id; /* Hardware power domain ID or -1 sentinel */
+ u32 fw_id; /* SCMI firmware power domain ID */
+};
+
+struct power_map {
+ int hw_id; /* Hardware power domain ID or -1 sentinel */
+ u32 fw_id; /* SCMI firmware power domain ID */
+ struct generic_pm_domain *genpd;
+};
+
+struct mod_map_in {
+ int hw_id; /* Hardware module ID or -1 sentinel */
+ u32 fw_id; /* SCMI clock and reset IDs are identical */
+};
+
struct mod_map {
int hw_id; /* Hardware module ID or -1 sentinel */
+ u32 fw_id; /* SCMI clock and reset IDs are identical */
+ struct reset_control *rstc;
};
struct mdlc_info {
u32 base;
- const struct mod_map *mod_map;
+ const struct power_map_in *power_map;
+ const struct mod_map_in *mod_map;
+};
+
+struct fw_map {
+ u32 impl_ver;
+ const struct mdlc_info *info;
+};
+
+struct mdlc_data {
+ const struct mdlc_info *default_info;
+ const struct fw_map *fw_map;
};
/**
@@ -33,7 +67,9 @@ struct mdlc_info {
* @rcdev: Reset controller entity
* @dev: MDLC device
* @np: Device node in DT representing the MDLC
- * @mod_map: Mapping from hardware module IDs
+ * @scmi_clk_np: Device node in DT for the SCMI firmware clock protocol
+ * @power_map: Mapping from hardware power domain IDs to SCMI power domains
+ * @mod_map: Mapping from hardware module IDs to SCMI clocks and resets
*/
struct r8a78000_mdlc_priv {
struct hlist_node link;
@@ -41,6 +77,8 @@ struct r8a78000_mdlc_priv {
struct reset_controller_dev rcdev;
struct device *dev;
struct device_node *np;
+ struct device_node *scmi_clk_np;
+ const struct power_map *power_map;
const struct mod_map *mod_map;
};
@@ -48,12 +86,28 @@ static struct generic_pm_domain *r8a78000_genpd_always_on;
static HLIST_HEAD(r8a78000_mdlc_list);
static DEFINE_MUTEX(r8a78000_mdlc_lock); /* protects the two above */
+static const struct power_map *power_map_find(const struct power_map *map,
+ u32 id)
+{
+ if (!map)
+ return NULL;
+
+ for (; map->hw_id >= 0; map++) {
+ if (map->hw_id == id)
+ return map;
+ }
+
+ return NULL;
+}
+
static struct generic_pm_domain *r8a78000_genpd_xlate(
const struct of_phandle_args *spec, void *data)
{
struct r8a78000_mdlc_priv *priv = container_of(data,
struct r8a78000_mdlc_priv, genpd_data);
+ struct generic_pm_domain *genpd;
struct device *dev = priv->dev;
+ const struct power_map *map;
u32 id;
if (spec->args_count != 2)
@@ -68,9 +122,18 @@ static struct generic_pm_domain *r8a78000_genpd_xlate(
return r8a78000_genpd_always_on;
}
- /* For now only always-on domains are supported */
- dev_err(dev, "Unknown power domain 0x%x\n", id);
- return ERR_PTR(-ENOENT);
+ map = power_map_find(priv->power_map, id);
+ if (!map) {
+ dev_err(dev, "Unknown power domain 0x%x\n", id);
+ return ERR_PTR(-ENOENT);
+ }
+
+ dev_dbg(dev, "Mapping HW power domain 0x%x to SCMI power domain %u\n",
+ id, map->fw_id);
+
+ genpd = map->genpd;
+
+ return genpd;
}
#define rcdev_to_priv(_rcdev) \
@@ -108,24 +171,37 @@ static int r8a78000_mdlc_reset_xlate(struct reset_controller_dev *rcdev,
return -ENOENT;
}
- dev_dbg(dev, "Ignoring HW reset 0x%x\n", id);
- return id;
+ if (!map->rstc)
+ dev_dbg(dev, "Ignoring HW reset 0x%x\n", id);
+ else
+ dev_dbg(dev, "Mapping HW reset 0x%x to SCMI reset %u\n", id,
+ map->fw_id);
+
+ return map - priv->mod_map;
}
-#define DEFINE_MDLC_RESET_WRAPPER(op) \
- static int r8a78000_mdlc_ ## op(struct reset_controller_dev *rcdev, \
- unsigned long id) \
- { \
- struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev); \
- \
- dev_dbg(priv->dev, "%s: Ignoring\n", __func__); \
- return 0; \
+#define DEFINE_MDLC_RESET_WRAPPER(_op, _ignore_eopnotsupp) \
+ static int r8a78000_mdlc_ ## _op(struct reset_controller_dev *rcdev, \
+ unsigned long id) \
+ { \
+ struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev); \
+ int ret; \
+ \
+ ret = reset_control_ ## _op(priv->mod_map[id].rstc); \
+ if (_ignore_eopnotsupp && ret == -EOPNOTSUPP) { \
+ dev_dbg(priv->dev, \
+ "%s: Ignoring unsupported reset %lu\n", \
+ __func__, id); \
+ return 0; \
+ } \
+ \
+ return ret; \
}
-DEFINE_MDLC_RESET_WRAPPER(reset)
-DEFINE_MDLC_RESET_WRAPPER(assert)
-DEFINE_MDLC_RESET_WRAPPER(deassert)
-DEFINE_MDLC_RESET_WRAPPER(status)
+DEFINE_MDLC_RESET_WRAPPER(reset, true)
+DEFINE_MDLC_RESET_WRAPPER(assert, true)
+DEFINE_MDLC_RESET_WRAPPER(deassert, true)
+DEFINE_MDLC_RESET_WRAPPER(status, false)
static const struct reset_control_ops r8a78000_mdlc_reset_ops = {
.reset = r8a78000_mdlc_reset,
@@ -134,14 +210,30 @@ static const struct reset_control_ops r8a78000_mdlc_reset_ops = {
.status = r8a78000_mdlc_status,
};
+static struct device_node *scmi_find_proto(struct device_node *scmi, u32 proto)
+{
+ for_each_available_child_of_node_scoped(scmi, child) {
+ u32 reg;
+
+ if (of_property_read_u32(child, "reg", ®))
+ continue;
+
+ if (reg == proto)
+ return_ptr(child);
+ }
+
+ return NULL;
+}
+
static int r8a78000_mdlc_attach_dev(struct generic_pm_domain *domain,
struct device *dev)
{
+ struct of_phandle_args pd_spec, scmi_spec;
struct device_node *np = dev->of_node;
struct r8a78000_mdlc_priv *priv;
- struct of_phandle_args pd_spec;
const struct mod_map *map;
unsigned int id;
+ struct clk *clk;
int ret;
ret = of_parse_phandle_with_args(np, "power-domains",
@@ -171,8 +263,152 @@ static int r8a78000_mdlc_attach_dev(struct generic_pm_domain *domain,
return -ENOENT;
}
- dev_dbg(dev, "Ignoring HW module 0x%x\n", id);
+ if (!priv->scmi_clk_np) {
+ dev_dbg(dev, "Ignoring HW module 0x%x\n", id);
+ return 0;
+ }
+
+ dev_dbg(dev, "Mapping HW module 0x%x to SCMI clock %u\n", id,
+ map->fw_id);
+
+ scmi_spec.np = priv->scmi_clk_np;
+ scmi_spec.args_count = 1;
+ scmi_spec.args[0] = map->fw_id;
+
+ clk = of_clk_get_from_provider(&scmi_spec);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Cannot get SCMI clock %u: %pe\n", map->fw_id,
+ clk);
+ return PTR_ERR(clk);
+ }
+
+ dev_dbg(dev, "SCMI clock %u is %pC\n", map->fw_id, clk);
+
+ if (!clk) {
+ /* Ignore missing SCMI module clocks */
+ return 0;
+ }
+
+ ret = pm_clk_create(dev);
+ if (ret)
+ goto fail_put;
+
+ ret = pm_clk_add_clk(dev, clk);
+ if (ret)
+ goto fail_destroy;
+
return 0;
+
+fail_destroy:
+ pm_clk_destroy(dev);
+fail_put:
+ clk_put(clk);
+ return ret;
+}
+
+static void r8a78000_mdlc_detach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ if (!pm_clk_no_clocks(dev))
+ pm_clk_destroy(dev);
+}
+
+static const struct power_map *fill_power_map(struct r8a78000_mdlc_priv *priv,
+ const struct power_map_in *map_in,
+ struct device_node *scmi_power_np)
+{
+ struct of_phandle_args scmi_spec;
+ struct generic_pm_domain *genpd;
+ struct device *dev = priv->dev;
+ struct power_map *map;
+ unsigned int i;
+
+ if (!map_in)
+ return NULL;
+
+ for (i = 0; map_in[i].hw_id >= 0; i++) { }
+
+ map = devm_kcalloc(dev, i + 1, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; ; i++) {
+ map[i].hw_id = map_in[i].hw_id;
+ if (map[i].hw_id < 0)
+ break;
+
+ map[i].fw_id = map_in[i].fw_id;
+
+ scmi_spec.np = scmi_power_np;
+ scmi_spec.args_count = 1;
+ scmi_spec.args[0] = map[i].fw_id;
+
+ genpd = of_genpd_get_from_provider(&scmi_spec);
+ if (IS_ERR(genpd))
+ return dev_err_cast_probe(dev, genpd,
+ "Failed to get SCMI power domain %u\n",
+ map[i].fw_id);
+
+ dev_dbg(dev, "SCMI power domain %u is %s\n", map[i].fw_id,
+ genpd->name);
+
+ map[i].genpd = genpd;
+
+ /* Hook up clock domain support */
+ genpd->attach_dev = r8a78000_mdlc_attach_dev;
+ genpd->detach_dev = r8a78000_mdlc_detach_dev;
+ /* Setting flags this late has no impact, but does not hurt */
+ genpd->flags |= GENPD_FLAG_PM_CLK;
+ genpd->dev_ops.stop = pm_clk_suspend;
+ genpd->dev_ops.start = pm_clk_resume;
+ }
+
+ return map;
+}
+
+static const struct mod_map *fill_mod_map(struct r8a78000_mdlc_priv *priv,
+ const struct mod_map_in *map_in,
+ struct fwnode_handle *scmi_reset_fwnode)
+{
+ struct fwnode_reference_args scmi_spec;
+ struct device *dev = priv->dev;
+ struct reset_control *rstc;
+ struct mod_map *map;
+ unsigned int i;
+
+ if (!map_in)
+ return NULL;
+
+ for (i = 0; map_in[i].hw_id >= 0; i++) { }
+
+ map = devm_kcalloc(dev, i + 1, sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; ; i++) {
+ map[i].hw_id = map_in[i].hw_id;
+ if (map[i].hw_id < 0)
+ break;
+
+ map[i].fw_id = map_in[i].fw_id;
+
+ if (!scmi_reset_fwnode)
+ continue;
+
+ scmi_spec.fwnode = scmi_reset_fwnode;
+ scmi_spec.nargs = 1;
+ scmi_spec.args[0] = map[i].fw_id;
+
+ rstc = reset_control_get_from_provider_exclusive(&scmi_spec);
+ if (IS_ERR(rstc))
+ return dev_err_cast_probe(dev, rstc,
+ "Failed to get SCMI reset %u\n",
+ map[i].fw_id);
+
+ map[i].rstc = rstc;
+ }
+
+ return map;
}
static void r8a78000_mdlc_unlink(void *data)
@@ -205,6 +441,8 @@ static int r8a78000_genpd_always_on_singleton(struct device *dev)
genpd->name = "always-on";
genpd->attach_dev = r8a78000_mdlc_attach_dev;
+ genpd->detach_dev = r8a78000_mdlc_detach_dev;
+ genpd->flags |= GENPD_FLAG_PM_CLK;
ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false);
if (ret) {
@@ -221,8 +459,15 @@ static int r8a78000_mdlc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ struct device_node *scmi __free(device_node) = NULL;
+ struct device_node *scmi_power_np = NULL;
+ const struct mdlc_data *mdlc_data;
+ struct device_node *scmi_reset_np;
+ struct device_node *scmi_clk_np;
struct r8a78000_mdlc_priv *priv;
+ struct scmi_base_info version;
const struct mdlc_info *info;
+ const struct fw_map *fw_map;
struct resource *res;
int ret;
@@ -230,10 +475,12 @@ static int r8a78000_mdlc_probe(struct platform_device *pdev)
if (ret)
return ret;
- info = of_device_get_match_data(dev);
- if (!info)
+ mdlc_data = of_device_get_match_data(dev);
+ if (!mdlc_data)
return -ENODEV;
+ info = mdlc_data->default_info;
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -241,6 +488,66 @@ static int r8a78000_mdlc_probe(struct platform_device *pdev)
priv->dev = dev;
priv->np = np;
+ scmi = of_parse_phandle(dev->of_node, "renesas,scmi-firmware", 0);
+ if (!scmi) {
+ dev_dbg(dev, "Cannot find SCMI firmware node\n");
+ goto fallback;
+ }
+
+ if (!of_device_is_available(scmi)) {
+ dev_dbg(dev, "SCMI firmware node is not available\n");
+ goto fallback;
+ }
+
+ scmi_power_np = scmi_find_proto(scmi, SCMI_PROTOCOL_POWER);
+ if (!scmi_power_np) {
+ dev_dbg(dev,
+ "Cannot find SCMI power domain management protocol\n");
+ goto fallback;
+ }
+
+ scmi_clk_np = scmi_find_proto(scmi, SCMI_PROTOCOL_CLOCK);
+ if (!scmi_clk_np) {
+ dev_dbg(dev, "Cannot find SCMI clock management protocol\n");
+ goto fallback;
+ }
+
+ scmi_reset_np = scmi_find_proto(scmi, SCMI_PROTOCOL_RESET);
+ if (!scmi_reset_np) {
+ dev_dbg(dev, "Cannot find SCMI reset management protocol\n");
+ goto fallback;
+ }
+
+ ret = scmi_get_base_info(scmi, &version);
+ if (ret == -EPROBE_DEFER)
+ return dev_err_probe(dev, ret, "SCMI provider not ready\n");
+ if (ret) {
+ dev_dbg(dev, "SCMI is not available\n");
+ goto fallback;
+ }
+
+ if (strcmp(version.vendor_id, "Renesas") ||
+ strcmp(version.sub_vendor_id, "None")) {
+ dev_warn(dev, "Unsupported SCMI firmware %s/%s\n",
+ version.vendor_id, version.sub_vendor_id);
+ goto fallback;
+ }
+
+ for (fw_map = mdlc_data->fw_map; fw_map->info; fw_map++) {
+ if (fw_map->impl_ver == version.impl_ver)
+ break;
+ }
+
+ if (!fw_map->info) {
+ dev_warn(dev, "Unsupported SCMI firmware version 0x%08x\n",
+ version.impl_ver);
+ goto fallback;
+ }
+
+ priv->scmi_clk_np = scmi_clk_np;
+ info = fw_map->info;
+
+fallback:
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
@@ -255,7 +562,22 @@ static int r8a78000_mdlc_probe(struct platform_device *pdev)
return -ENODEV;
}
- priv->mod_map = info->mod_map;
+ /*
+ * We cannot do lazy look-up in r8a78000_genpd_xlate(), as that
+ * function is called with of_genpd_mutex already held.
+ */
+ priv->power_map = fill_power_map(priv, info->power_map, scmi_power_np);
+ if (IS_ERR(priv->power_map))
+ return PTR_ERR(priv->power_map);
+
+ /*
+ * We cannot do lazy look-up in r8a78000_mdlc_reset_xlate(), as that
+ * function is called with reset_list_mutex already held.
+ */
+ priv->mod_map = fill_mod_map(priv, info->mod_map,
+ of_fwnode_handle(scmi_reset_np));
+ if (IS_ERR(priv->mod_map))
+ return PTR_ERR(priv->mod_map);
scoped_guard(mutex, &r8a78000_mdlc_lock) {
hlist_add_head(&priv->link, &r8a78000_mdlc_list);
@@ -290,7 +612,7 @@ static int r8a78000_mdlc_probe(struct platform_device *pdev)
return 0;
}
-static const struct mod_map r8a78000_mdlc_perw_mod_default[] = {
+static const struct mod_map_in r8a78000_mdlc_perw_mod_default[] = {
{ 0x54 }, /* HSCIF0 */
{ -1 }
};
@@ -303,10 +625,19 @@ static const struct mdlc_info r8a78000_mdlc_default[] = {
{ /* sentinel */ }
};
+static const struct fw_map r8a78000_mdlc_fw_map[] = {
+ { /* sentinel */ }
+};
+
+static const struct mdlc_data r8a78000_mdlc_data = {
+ .default_info = r8a78000_mdlc_default,
+ .fw_map = r8a78000_mdlc_fw_map,
+};
+
static const struct of_device_id r8a78000_mdlc_match[] = {
{
.compatible = "renesas,r8a78000-mdlc",
- .data = &r8a78000_mdlc_default,
+ .data = &r8a78000_mdlc_data,
},
{ /* sentinel */ }
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 11/12] arm64: dts: renesas: ironhide: Enable SCMI devpd, sys, clock, and reset
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (9 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 10/12] pmdomain: " Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 12/12] arm64: dts: renesas: ironhide: Add CPG/MDLC renesas,scmi-firmware properties Geert Uytterhoeven
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
SCP FW SDKv4.28.0 and later for Renesas R-Car X5H Ironhide not only
implement the SCMI base protocol, but also the SCMI power domain, system
power, clock, and reset domain management protocols.
Enable support for the latter by adding the corresponding SCMI protocol
subnodes.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- No changes,
v2:
- Fix misindentations,
- Add scmi_clk node, as it is no longer added in earlier commits.
---
.../boot/dts/renesas/r8a78000-ironhide.dts | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
index 0ab303863155e1ca..04291f04da2b7fb5 100644
--- a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
+++ b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
@@ -31,6 +31,25 @@ scmi: scmi {
arm,no-completion-irq;
#address-cells = <1>;
#size-cells = <0>;
+
+ scmi_devpd: protocol@11 {
+ reg = <0x11>;
+ #power-domain-cells = <1>;
+ };
+
+ scmi_sys: protocol@12 {
+ reg = <0x12>;
+ };
+
+ scmi_clk: protocol@14 {
+ reg = <0x14>;
+ #clock-cells = <1>;
+ };
+
+ scmi_reset: protocol@16 {
+ reg = <0x16>;
+ #reset-cells = <1>;
+ };
};
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v3 12/12] arm64: dts: renesas: ironhide: Add CPG/MDLC renesas,scmi-firmware properties
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
` (10 preceding siblings ...)
2026-09-02 11:29 ` [PATCH v3 11/12] arm64: dts: renesas: ironhide: Enable SCMI devpd, sys, clock, and reset Geert Uytterhoeven
@ 2026-09-02 11:29 ` Geert Uytterhoeven
11 siblings, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:29 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Link the various Clock Pulse Generator (CPG) and Module Controller
(MDLC) device nodes to their SCMI provider.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
v3:
- s/firmware/renesas,scmi-firmware/,
v2:
- No changes.
---
.../boot/dts/renesas/r8a78000-ironhide.dts | 116 ++++++++++++++++++
1 file changed, 116 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
index 04291f04da2b7fb5..a6f055a1f38a8449 100644
--- a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
+++ b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
@@ -170,6 +170,10 @@ ecc@1e66660000 {
};
};
+&cpg {
+ renesas,scmi-firmware = <&scmi>;
+};
+
&extal_clk {
clock-frequency = <16666600>;
};
@@ -183,6 +187,118 @@ &hscif0 {
status = "okay";
};
+&mdlc_aon {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_cmnn {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_cmns {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr0 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr1 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr2 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr3 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr4 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr5 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr6 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ddr7 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_dsp {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_gpc {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_hscn {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_hscs {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_imn {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_ims {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_mm {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_npu0 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_npu1 {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_pere {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_perw {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_rt {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_scp {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_top {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_vio {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_vipn {
+ renesas,scmi-firmware = <&scmi>;
+};
+
+&mdlc_vips {
+ renesas,scmi-firmware = <&scmi>;
+};
+
&mfis_scp {
status = "okay";
};
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive()
2026-09-02 11:29 ` [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive() Geert Uytterhoeven
@ 2026-09-02 11:44 ` Geert Uytterhoeven
2026-09-03 10:03 ` Philipp Zabel
1 sibling, 0 replies; 16+ messages in thread
From: Geert Uytterhoeven @ 2026-09-02 11:44 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Stephen Boyd,
Brian Masney, Jerome Brunet, Sudeep Holla, Cristian Marussi,
Saravana Kannan, Ulf Hansson, Philipp Zabel, Rafael J . Wysocki,
Marek Vasut, Bartosz Golaszewski, Konrad Dybcio, Kevin Hilman,
Vinod Koul, Wolfram Sang, Kuninori Morimoto,
Clément Le Goffic, devicetree, arm-scmi, linux-arm-kernel,
linux-clk, linux-pm, linux-renesas-soc, linux-kernel
On Wed, 2 Sept 2026 at 13:30, Geert Uytterhoeven
<geert+renesas@glider.be> wrote:
> When stacking two reset controllers, the upper one should go through the
> proper channels: request exclusive reset controls and use them via the
> reset_control_*() APIs. However, unlike the clock subsystem, which has
> of_clk_get_from_provider(), the reset subsystem does not offer a way to
> lookup and obtain a reset from a reset provider.
>
> Hence add a public helper reset_control_get_from_provider_exclusive()
> to lookup and obtain an exclusive reference to a reset controller, based
> on the recently introduced __reset_control_get_from_provider() helper.
> This will be used by the R-Car X5H Module Controller driver.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v3:
> - Replace reset_controller_get_provider() by
> reset_control_get_from_provider_exclusive(),
> - Add kerneldoc,
>
> v2:
> - No changes.
> ---
> drivers/reset/core.c | 37 ++++++++++++++++++++++++++++++++-----
> include/linux/reset.h | 8 ++++++++
> 2 files changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 8af7cd2e8a5029df..6d4c95b3edb18248 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -1141,6 +1141,7 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
> bool gpio_fallback,
> enum reset_control_flags flags)
> {
> + struct fwnode_handle *fwnode = consumer ?: args->fwnode;
> struct reset_control *rstc = ERR_PTR(-EINVAL);
> struct reset_controller_dev *rcdev;
> int rstc_id = -EINVAL;
> @@ -1154,18 +1155,26 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
> if (WARN_ON(args->nargs != rcdev->fwnode_reset_n_cells))
> return ERR_PTR(-EINVAL);
>
> - if (rcdev->of_xlate && is_of_node(consumer)) {
> - struct device_node *np = to_of_node(consumer);
> + if (rcdev->of_xlate && is_of_node(fwnode)) {
> + struct device_node *np = to_of_node(fwnode);
> struct of_phandle_args of_args;
> int ret;
>
> - ret = of_parse_phandle_with_args(np,
> + if (consumer) {
> + ret = of_parse_phandle_with_args(np,
> gpio_fallback ? "reset-gpios" : "resets",
> gpio_fallback ? "#gpio-cells" : "#reset-cells",
> gpio_fallback ? 0 : index,
> &of_args);
> - if (ret)
> - return ERR_PTR(ret);
> + if (ret)
> + return ERR_PTR(ret);
> + } else {
> + of_args.np = of_node_get(np);
> + of_args.args_count = args->nargs;
> +
> + for (unsigned int i = 0; i < args->nargs; i++)
> + of_args.args[i] = args->args[i];
> + }
>
> rstc_id = rcdev->of_xlate(rcdev, &of_args);
> of_node_put(of_args.np);
> @@ -1257,6 +1266,24 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
> }
> EXPORT_SYMBOL_GPL(__reset_control_get);
>
> +/**
> + * reset_control_get_from_provider_exclusive - Lookup and obtain an exclusive
> + * reference to a reset controller.
> + * @args: Reference to the reset controller provider with all the args like
> + * reset number
> + *
> + * Returns a struct reset_control or IS_ERR() condition containing errno.
> + * If this function is called more than once for the same reset control it will
> + * return -EBUSY.
> + */
> +struct reset_control *
> +reset_control_get_from_provider_exclusive(const struct fwnode_reference_args *args)
> +{
> + return __reset_control_get_from_provider(args, NULL, 0, false,
> + RESET_CONTROL_EXCLUSIVE);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_get_from_provider_exclusive);
> +
> int __reset_control_bulk_get(struct device *dev, int num_rstcs,
> struct reset_control_bulk_data *rstcs,
> enum reset_control_flags flags)
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index 9c391cf0c82298a0..09ee47b27f88d3b1 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -90,6 +90,8 @@ struct reset_control *__fwnode_reset_control_get(struct fwnode_handle *fwnode,
> const char *id, int index, enum reset_control_flags flags);
> struct reset_control *__reset_control_get(struct device *dev, const char *id,
> int index, enum reset_control_flags flags);
> +struct reset_control *reset_control_get_from_provider_exclusive(
> + const struct fwnode_reference_args *args);
> void reset_control_put(struct reset_control *rstc);
> int __reset_control_bulk_get(struct device *dev, int num_rstcs,
> struct reset_control_bulk_data *rstcs,
> @@ -173,6 +175,12 @@ static inline struct reset_control *__reset_control_get(
> return optional ? NULL : ERR_PTR(-ENOTSUPP);
> }
>
> +static inline struct reset_control *reset_control_get_from_provider_exclusive(
> + const struct fwnode_reference_args *args)
> +{
> + return NULL;
As reported by Sashiko, this dummy should return ERR_PTR(-ENOTSUPP)
instead.
> +}
> +
> static inline int
> reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs)
> {
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider()
2026-09-02 11:29 ` [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider() Geert Uytterhoeven
@ 2026-09-03 8:55 ` Philipp Zabel
0 siblings, 0 replies; 16+ messages in thread
From: Philipp Zabel @ 2026-09-03 8:55 UTC (permalink / raw)
To: Geert Uytterhoeven, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stephen Boyd, Brian Masney, Jerome Brunet,
Sudeep Holla, Cristian Marussi, Saravana Kannan, Ulf Hansson,
Rafael J . Wysocki, Marek Vasut, Bartosz Golaszewski,
Konrad Dybcio, Kevin Hilman, Vinod Koul, Wolfram Sang,
Kuninori Morimoto, Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel
On Mi, 2026-09-02 at 13:29 +0200, Geert Uytterhoeven wrote:
> Extract the code to create a reset_control structure from a given
> provider into its own function, so it can be reused later.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v3:
> - New.
> ---
> drivers/reset/core.c | 92 ++++++++++++++++++++++++--------------------
> 1 file changed, 50 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 38e189d04d09b270..8af7cd2e8a5029df 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -1135,6 +1135,54 @@ __reset_find_rcdev(const struct fwnode_reference_args *args, bool gpio_fallback)
> return NULL;
> }
>
> +static struct reset_control *
> +__reset_control_get_from_provider(const struct fwnode_reference_args *args,
> + struct fwnode_handle *consumer, int index,
> + bool gpio_fallback,
> + enum reset_control_flags flags)
> +{
> + struct reset_control *rstc = ERR_PTR(-EINVAL);
> + struct reset_controller_dev *rcdev;
> + int rstc_id = -EINVAL;
> +
> + guard(mutex)(&reset_list_mutex);
> +
> + rcdev = __reset_find_rcdev(args, gpio_fallback);
> + if (!rcdev)
> + return ERR_PTR(-EPROBE_DEFER);
> +
> + if (WARN_ON(args->nargs != rcdev->fwnode_reset_n_cells))
> + return ERR_PTR(-EINVAL);
> +
> + if (rcdev->of_xlate && is_of_node(consumer)) {
> + struct device_node *np = to_of_node(consumer);
> + struct of_phandle_args of_args;
> + int ret;
> +
> + ret = of_parse_phandle_with_args(np,
> + gpio_fallback ? "reset-gpios" : "resets",
> + gpio_fallback ? "#gpio-cells" : "#reset-cells",
> + gpio_fallback ? 0 : index,
> + &of_args);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + rstc_id = rcdev->of_xlate(rcdev, &of_args);
> + of_node_put(of_args.np);
> + } else if (rcdev->fwnode_xlate) {
> + rstc_id = rcdev->fwnode_xlate(rcdev, args);
> + }
> + if (rstc_id < 0)
> + return ERR_PTR(rstc_id);
> +
> + flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
This should stay in __fwnode_reset_control_get().
> +
> + scoped_guard(mutex, &rcdev->lock)
> + rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
> +
> + return rstc;
Just return __reset_control_get_internal(...) directly, the rstc local
variable is not needed.
> +}
> +
> struct reset_control *
> __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int index,
> enum reset_control_flags flags)
> @@ -1142,10 +1190,7 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
> bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL;
> bool gpio_fallback = false;
> struct reset_control *rstc = ERR_PTR(-EINVAL);
> - struct reset_controller_dev *rcdev;
> struct fwnode_reference_args args;
> - struct of_phandle_args of_args;
> - int rstc_id = -EINVAL;
> int ret;
>
> if (!fwnode)
> @@ -1185,46 +1230,9 @@ __fwnode_reset_control_get(struct fwnode_handle *fwnode, const char *id, int ind
> }
> }
>
> - guard(mutex)(&reset_list_mutex);
> -
> - rcdev = __reset_find_rcdev(&args, gpio_fallback);
> - if (!rcdev) {
> - rstc = ERR_PTR(-EPROBE_DEFER);
> - goto out_put;
> - }
> -
> - if (WARN_ON(args.nargs != rcdev->fwnode_reset_n_cells)) {
> - rstc = ERR_PTR(-EINVAL);
> - goto out_put;
> - }
> -
> - if (rcdev->of_xlate && is_of_node(fwnode)) {
> - ret = of_parse_phandle_with_args(to_of_node(fwnode),
> - gpio_fallback ? "reset-gpios" : "resets",
> - gpio_fallback ? "#gpio-cells" : "#reset-cells",
> - gpio_fallback ? 0 : index,
Hmm, I think this gpio_fallback disambiguation is not needed. In the
gpio_fallback case (lookup via "reset-gpios") we should always get a
reset_gpio rcdev with fwnode_xlate, not of_xlate.
Not an issue for this refactor, though.
> - &of_args);
> - if (ret) {
> - rstc = ERR_PTR(ret);
> - goto out_put;
> - }
> -
> - rstc_id = rcdev->of_xlate(rcdev, &of_args);
> - of_node_put(of_args.np);
> - } else if (rcdev->fwnode_xlate) {
> - rstc_id = rcdev->fwnode_xlate(rcdev, &args);
> - }
> - if (rstc_id < 0) {
> - rstc = ERR_PTR(rstc_id);
> - goto out_put;
> - }
> -
> - flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL;
Keep this here.
> -
> - scoped_guard(mutex, &rcdev->lock)
> - rstc = __reset_control_get_internal(rcdev, rstc_id, flags);
> + rstc = __reset_control_get_from_provider(&args, fwnode, index,
> + gpio_fallback, flags);
>
> -out_put:
> fwnode_handle_put(args.fwnode);
>
> return rstc;
With that,
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
regards
Philipp
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive()
2026-09-02 11:29 ` [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive() Geert Uytterhoeven
2026-09-02 11:44 ` Geert Uytterhoeven
@ 2026-09-03 10:03 ` Philipp Zabel
1 sibling, 0 replies; 16+ messages in thread
From: Philipp Zabel @ 2026-09-03 10:03 UTC (permalink / raw)
To: Geert Uytterhoeven, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stephen Boyd, Brian Masney, Jerome Brunet,
Sudeep Holla, Cristian Marussi, Saravana Kannan, Ulf Hansson,
Rafael J . Wysocki, Marek Vasut, Bartosz Golaszewski,
Konrad Dybcio, Kevin Hilman, Vinod Koul, Wolfram Sang,
Kuninori Morimoto, Clément Le Goffic
Cc: devicetree, arm-scmi, linux-arm-kernel, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel
On Mi, 2026-09-02 at 13:29 +0200, Geert Uytterhoeven wrote:
> When stacking two reset controllers, the upper one should go through the
> proper channels: request exclusive reset controls and use them via the
> reset_control_*() APIs. However, unlike the clock subsystem, which has
> of_clk_get_from_provider(), the reset subsystem does not offer a way to
> lookup and obtain a reset from a reset provider.
>
> Hence add a public helper reset_control_get_from_provider_exclusive()
> to lookup and obtain an exclusive reference to a reset controller, based
> on the recently introduced __reset_control_get_from_provider() helper.
> This will be used by the R-Car X5H Module Controller driver.
>
> Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> v3:
> - Replace reset_controller_get_provider() by
> reset_control_get_from_provider_exclusive(),
> - Add kerneldoc,
>
> v2:
> - No changes.
> ---
> drivers/reset/core.c | 37 ++++++++++++++++++++++++++++++++-----
> include/linux/reset.h | 8 ++++++++
> 2 files changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 8af7cd2e8a5029df..6d4c95b3edb18248 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -1141,6 +1141,7 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
> bool gpio_fallback,
> enum reset_control_flags flags)
> {
> + struct fwnode_handle *fwnode = consumer ?: args->fwnode;
> struct reset_control *rstc = ERR_PTR(-EINVAL);
> struct reset_controller_dev *rcdev;
> int rstc_id = -EINVAL;
> @@ -1154,18 +1155,26 @@ __reset_control_get_from_provider(const struct fwnode_reference_args *args,
> if (WARN_ON(args->nargs != rcdev->fwnode_reset_n_cells))
> return ERR_PTR(-EINVAL);
>
> - if (rcdev->of_xlate && is_of_node(consumer)) {
> - struct device_node *np = to_of_node(consumer);
> + if (rcdev->of_xlate && is_of_node(fwnode)) {
> + struct device_node *np = to_of_node(fwnode);
> struct of_phandle_args of_args;
> int ret;
>
> - ret = of_parse_phandle_with_args(np,
> + if (consumer) {
> + ret = of_parse_phandle_with_args(np,
> gpio_fallback ? "reset-gpios" : "resets",
> gpio_fallback ? "#gpio-cells" : "#reset-cells",
> gpio_fallback ? 0 : index,
> &of_args);
> - if (ret)
> - return ERR_PTR(ret);
> + if (ret)
> + return ERR_PTR(ret);
> + } else {
> + of_args.np = of_node_get(np);
> + of_args.args_count = args->nargs;
> +
> + for (unsigned int i = 0; i < args->nargs; i++)
> + of_args.args[i] = args->args[i];
This should error out if args->args[i] > U32_MAX.
> + }
>
> rstc_id = rcdev->of_xlate(rcdev, &of_args);
> of_node_put(of_args.np);
> @@ -1257,6 +1266,24 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
> }
> EXPORT_SYMBOL_GPL(__reset_control_get);
>
> +/**
> + * reset_control_get_from_provider_exclusive - Lookup and obtain an exclusive
> + * reference to a reset controller.
> + * @args: Reference to the reset controller provider with all the args like
> + * reset number
It is implied, but should this explicitly mention that this must not be
a reference to a GPIO provider?
> + *
> + * Returns a struct reset_control or IS_ERR() condition containing errno.
> + * If this function is called more than once for the same reset control it will
> + * return -EBUSY.
> + */
> +struct reset_control *
> +reset_control_get_from_provider_exclusive(const struct fwnode_reference_args *args)
> +{
> + return __reset_control_get_from_provider(args, NULL, 0, false,
> + RESET_CONTROL_EXCLUSIVE);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_get_from_provider_exclusive);
regards
Philipp
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-09-03 10:03 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 11:29 [PATCH v3 00/12] R-Car X5H Ironhide CPG/MDLC SCMI remapping support Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 01/12] dt-bindings: clock: renesas,r8a78000-cpg: Add renesas,scmi-firmware property Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 02/12] dt-bindings: power: renesas,r8a78000-mdlc: Add firmware property Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 03/12] firmware: arm_scmi: Add scmi_get_base_info() Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 04/12] of: property: fw_devlink: Add support for renesas,scmi-firmware Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 05/12] pmdomain: Make genpd_get_from_provider() public Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 06/12] reset: Extract __reset_control_get_from_provider() Geert Uytterhoeven
2026-09-03 8:55 ` Philipp Zabel
2026-09-02 11:29 ` [PATCH v3 07/12] reset: Add reset_control_get_from_provider_exclusive() Geert Uytterhoeven
2026-09-02 11:44 ` Geert Uytterhoeven
2026-09-03 10:03 ` Philipp Zabel
2026-09-02 11:29 ` [PATCH v3 08/12] clk: renesas: r8a78000: Add clk_hw to clk_map Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 09/12] clk: renesas: r8a78000: Add SCMI remapping support Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 10/12] pmdomain: " Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 11/12] arm64: dts: renesas: ironhide: Enable SCMI devpd, sys, clock, and reset Geert Uytterhoeven
2026-09-02 11:29 ` [PATCH v3 12/12] arm64: dts: renesas: ironhide: Add CPG/MDLC renesas,scmi-firmware properties Geert Uytterhoeven
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox