feat(dsu): support power control and autonomous powerdown config
This patch allows platforms to enable certain DSU settings
to ensure memory retention and control over
cache power requests. We also move the driver out of css
into drivers/arm. Platforms can configure the
CLUSTERPWRCTLR and CLUSTERPWRDN registers [1] to improve
power efficiency.
These registers enable finer-grained control of
DSU power state transitions, including
powerdown and retention.
IMP_CLUSTERPWRCTLR_EL1 provides:
- Functional retention: Allows configuration of the
duration of inactivity before the DSU uses
CLUSTERPACTIVE to request functional retention.
- Cache power request: These bits are output on
CLUSTERPACTIVE[19:16] to indicate to the power controller
which cache portions must remain powered.
IMP_CLUSTERPWRDN_EL1 includes:
- Powerdown: Triggers full cluster powerdown, including
control logic.
- Memory retention: Requests memory retention mode,
keeping L3 RAM contents while powering off
the rest of the DSU.
The DSU-120 TRM [2] provides the full field definitions,
which are used as references in the `dsu_driver_data` structure.
References:
[1]: https://developer.arm.com/documentation/100453/latest/
[2]: https://developer.arm.com/documentation/102547/0201/?lang=en
Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
Change-Id: I2eba808b8f2a27797782a333c65dd092b03208fe
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index b607945..5506cb1 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1576,7 +1576,7 @@
/*******************************************************************************
* Definitions for DynamicIQ Shared Unit registers
******************************************************************************/
-#define CLUSTERPWRDN_EL1 S3_0_c15_c3_6
+#define CLUSTERPWRDN_EL1 S3_0_C15_C3_6
/*******************************************************************************
* FEAT_FPMR - Floating point Mode Register
diff --git a/include/drivers/arm/css/dsu.h b/include/drivers/arm/css/dsu.h
deleted file mode 100644
index 4d7822b..0000000
--- a/include/drivers/arm/css/dsu.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef DSU_H
-#define DSU_H
-
-#define PMCR_N_MAX 0x1f
-
-#define save_pmu_reg(state, reg) state->reg = read_##reg()
-
-#define restore_pmu_reg(context, reg) write_##reg(context->reg)
-
-typedef struct cluster_pmu_state{
- uint64_t clusterpmcr;
- uint64_t clusterpmcntenset;
- uint64_t clusterpmccntr;
- uint64_t clusterpmovsset;
- uint64_t clusterpmselr;
- uint64_t clusterpmsevtyper;
- uint64_t counter_val[PMCR_N_MAX];
- uint64_t counter_type[PMCR_N_MAX];
-} cluster_pmu_state_t;
-
-static inline unsigned int read_cluster_eventctr_num(void)
-{
- return ((read_clusterpmcr() >> CLUSTERPMCR_N_SHIFT) &
- CLUSTERPMCR_N_MASK);
-}
-
-
-void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
-
-void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
-
-void cluster_on_dsu_pmu_context_restore(void);
-
-void cluster_off_dsu_pmu_context_save(void);
-
-#endif /* DSU_H */
diff --git a/include/drivers/arm/dsu.h b/include/drivers/arm/dsu.h
new file mode 100644
index 0000000..492babd
--- /dev/null
+++ b/include/drivers/arm/dsu.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DSU_H
+#define DSU_H
+
+#if defined(__aarch64__)
+#include <dsu_def.h>
+
+/*
+ * Power Control Registers enable bit of Auxilary Control register.
+ * ACTLR_EL3_PWREN_BIT definition is same among cores like Cortex-X925,
+ * Cortex-X4, Cortex-A520, Cortex-A725 that are used in a cluster
+ * with DSU.
+ */
+#define ACTLR_EL3_PWREN_BIT BIT(7)
+
+#define PMCR_N_MAX 0x1f
+
+#define save_pmu_reg(state, reg) state->reg = read_##reg()
+
+#define restore_pmu_reg(context, reg) write_##reg(context->reg)
+
+typedef struct cluster_pmu_state {
+ uint64_t clusterpmcr;
+ uint64_t clusterpmcntenset;
+ uint64_t clusterpmccntr;
+ uint64_t clusterpmovsset;
+ uint64_t clusterpmselr;
+ uint64_t clusterpmsevtyper;
+ uint64_t counter_val[PMCR_N_MAX];
+ uint64_t counter_type[PMCR_N_MAX];
+} cluster_pmu_state_t;
+
+typedef struct dsu_driver_data {
+ uint8_t clusterpwrdwn_pwrdn;
+ uint8_t clusterpwrdwn_memret;
+ uint8_t clusterpwrctlr_cachepwr;
+ uint8_t clusterpwrctlr_funcret;
+} dsu_driver_data_t;
+
+extern const dsu_driver_data_t plat_dsu_data;
+
+static inline unsigned int read_cluster_eventctr_num(void)
+{
+ return ((read_clusterpmcr() >> CLUSTERPMCR_N_SHIFT) &
+ CLUSTERPMCR_N_MASK);
+}
+
+void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
+
+void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
+
+void cluster_on_dsu_pmu_context_restore(void);
+
+void cluster_off_dsu_pmu_context_save(void);
+
+void dsu_driver_init(const dsu_driver_data_t *data);
+#endif
+#endif /* DSU_H */
diff --git a/include/lib/cpus/aarch64/dsu_def.h b/include/lib/cpus/aarch64/dsu_def.h
index 3f6dbfe..089ea52 100644
--- a/include/lib/cpus/aarch64/dsu_def.h
+++ b/include/lib/cpus/aarch64/dsu_def.h
@@ -32,13 +32,27 @@
* DSU Cluster Auxiliary Control registers definitions
********************************************************************/
#define CLUSTERACTLR_EL1 S3_0_C15_C3_3
-#define CLUSTERPWRCTLR_EL1 S3_0_C15_C3_5
+
+/* CLUSTERPWRCTLR_EL1 register definitions */
+#define CLUSTERPWRCTLR_EL1 S3_0_C15_C3_5
+#define CLUSTERPWRCTLR_FUNCRET_WIDTH U(3)
+#define CLUSTERPWRCTLR_FUNCRET_SHIFT U(0)
+#define CLUSTERPWRCTLR_FUNCRET_RESET U(0)
+#define CLUSTERPWRCTLR_CACHEPWR_WIDTH U(4)
+#define CLUSTERPWRCTLR_CACHEPWR_SHIFT U(4)
+#define CLUSTERPWRCTLR_CACHEPWR_RESET U(7)
#define CLUSTERACTLR_EL1_ASSERT_CBUSY (ULL(1) << 8)
#define CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING (ULL(1) << 15)
#define CLUSTERACTLR_EL1_DISABLE_SCLK_GATING (ULL(3) << 15)
#define CLUSTERACTLR_EL1_IGNORE_INTERCONNECT_CBUSY (ULL(3) << 20)
+/* CLUSTERPWRDN_EL1 register definitions */
+#define CLUSTERPWRDN_PWRDN_WIDTH U(1)
+#define CLUSTERPWRDN_PWRDN_SHIFT U(0)
+#define CLUSTERPWRDN_MEMRET_WIDTH U(1)
+#define CLUSTERPWRDN_MEMRET_SHIFT U(1)
+
/********************************************************************
* Masks applied for DSU errata workarounds
********************************************************************/
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index 68e464a..7dcc5ce 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -86,6 +86,12 @@
#define EXTRACT(regfield, reg) \
(((reg) & MASK(regfield)) >> (regfield##_SHIFT))
+#define UPDATE_REG_FIELD(regfield, reg, val) \
+ do { \
+ (reg) &= ~(MASK(regfield)); \
+ (reg) |= ((uint64_t)(val) << (regfield##_SHIFT)); \
+ } while (0)
+
/*
* This variant of div_round_up can be used in macro definition but should not
* be used in C code as the `div` parameter is evaluated twice.