[PATCH/RFC 03/14] firmware: arm_scmi: quirk: Handle critical clocks on R-Car X5H

Geert Uytterhoeven
2026-04-21T18:12:13Z

Renesas R-Car X5H SCP FW SDKv4.28.0, v4.31.0, and v4.32.0 advertise a
few clocks that crash the system when disabled. Add quirks to prevent
such crashes.

As SCMI clock IDs are identical for SDKv4.31.0 and v4.32.0, the quirk
for these two versions can be shared.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Some of these could be handled by improving hardware descriptions in DT,
or by the CPG and MDLC drivers.
---
drivers/firmware/arm_scmi/clock.c | 23 +++++++++++++++++++++++
drivers/firmware/arm_scmi/quirks.c | 6 ++++++
drivers/firmware/arm_scmi/quirks.h | 2 ++
3 files changed, 31 insertions(+)

diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index d530882a0bac88c3..4fec8c3216df7a51 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -920,6 +920,26 @@ scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
return ret;
}

+#define QUIRK_RCAR_X5H_4_28_CRIT_CLOCKS \
+ ({ \
+ switch (clk_id) { \
+ case 468: /* MDLC_INTAP0 */ \
+ case 498: /* MDLC_APRTMGINT0 */ \
+ case 840: /* CLK_ZD_APU0 */ \
+ return -EPERM; \
+ } \
+ })
+
+#define QUIRK_RCAR_X5H_4_31_CRIT_CLOCKS \
+ ({ \
+ switch (clk_id) { \
+ case 464: /* MDLC_INTAP0 */ \
+ case 494: /* MDLC_APRTMGINT0 */ \
+ case 836: /* CLK_ZD_APU0 */ \
+ return -EPERM; \
+ } \
+ })
+
static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic)
{
@@ -950,6 +970,9 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,
if (clk->state_ctrl_forbidden)
return -EACCES;

+ SCMI_QUIRK(clock_rcar_x5h_4_28_crit_clocks, QUIRK_RCAR_X5H_4_28_CRIT_CLOCKS);
+ SCMI_QUIRK(clock_rcar_x5h_4_31_crit_clocks, QUIRK_RCAR_X5H_4_31_CRIT_CLOCKS);
+
return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE,
NULL_OEM_TYPE, 0, atomic);
}
diff --git a/drivers/firmware/arm_scmi/quirks.c b/drivers/firmware/arm_scmi/quirks.c
index e27c21b14220ab5f..4ca6d06f85ebc7b2 100644
--- a/drivers/firmware/arm_scmi/quirks.c
+++ b/drivers/firmware/arm_scmi/quirks.c
@@ -173,6 +173,10 @@ struct scmi_quirk {
DEFINE_SCMI_QUIRK(clock_rates_triplet_out_of_spec, NULL, NULL, NULL);
DEFINE_SCMI_QUIRK(clock_rcar_x5h_no_attributes, "Renesas", NULL, "0x10a0000-",
"renesas,r8a78000");
+DEFINE_SCMI_QUIRK(clock_rcar_x5h_4_28_crit_clocks, "Renesas", NULL, "0x10a0000",
+ "renesas,r8a78000");
+DEFINE_SCMI_QUIRK(clock_rcar_x5h_4_31_crit_clocks, "Renesas", NULL,
+ "0x10d0000-0x10e0000", "renesas,r8a78000");
DEFINE_SCMI_QUIRK(perf_level_get_fc_force, "Qualcomm", NULL, "0x20000-");
DEFINE_SCMI_QUIRK(power_rcar_x5h_4_28_bad_domains, "Renesas", NULL,
"0x10a0000-0x10e0000", "renesas,r8a78000");
@@ -186,6 +190,8 @@ DEFINE_SCMI_QUIRK(power_rcar_x5h_4_28_bad_domains, "Renesas", NULL,
static struct scmi_quirk *scmi_quirks_table[] = {
__DECLARE_SCMI_QUIRK_ENTRY(clock_rates_triplet_out_of_spec),
__DECLARE_SCMI_QUIRK_ENTRY(clock_rcar_x5h_no_attributes),
+ __DECLARE_SCMI_QUIRK_ENTRY(clock_rcar_x5h_4_28_crit_clocks),
+ __DECLARE_SCMI_QUIRK_ENTRY(clock_rcar_x5h_4_31_crit_clocks),
__DECLARE_SCMI_QUIRK_ENTRY(perf_level_get_fc_force),
__DECLARE_SCMI_QUIRK_ENTRY(power_rcar_x5h_4_28_bad_domains),
NULL
diff --git a/drivers/firmware/arm_scmi/quirks.h b/drivers/firmware/arm_scmi/quirks.h
index 67818b6cf0909f8e..56adb5fa87de0127 100644
--- a/drivers/firmware/arm_scmi/quirks.h
+++ b/drivers/firmware/arm_scmi/quirks.h
@@ -48,6 +48,8 @@ static inline void scmi_quirks_enable(struct device *dev, const char *vend,
/* Quirk delarations */
DECLARE_SCMI_QUIRK(clock_rates_triplet_out_of_spec);
DECLARE_SCMI_QUIRK(clock_rcar_x5h_no_attributes);
+DECLARE_SCMI_QUIRK(clock_rcar_x5h_4_28_crit_clocks);
+DECLARE_SCMI_QUIRK(clock_rcar_x5h_4_31_crit_clocks);
DECLARE_SCMI_QUIRK(perf_level_get_fc_force);
DECLARE_SCMI_QUIRK(power_rcar_x5h_4_28_bad_domains);

--
2.43.0