[PATCH 2/5] platform: generic/andes: add CSR save and restore functions for AE350 platform

Ben Zong-You Xie ben717 at andestech.com
Sun Dec 28 23:19:11 PST 2025


Implement a save and restore mechanism for Andes-specific CSRs to support
hardware power-saving modes, such as CPU hotplug or suspend to RAM.

Signed-off-by: Ben Zong-You Xie <ben717 at andestech.com>
Signed-off-by: Leo Yu-Chi Liang <ycliang at andestech.com>
---
 lib/utils/hsm/fdt_hsm_andes_atcsmu.c   |  1 +
 platform/generic/andes/ae350.c         | 55 ++++++++++++++++++++++++++
 platform/generic/include/andes/andes.h | 22 ++++++++++-
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/lib/utils/hsm/fdt_hsm_andes_atcsmu.c b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
index ee7873dc6d00..3fe931aa1816 100644
--- a/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
+++ b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
@@ -126,6 +126,7 @@ static int ae350_hart_stop(void)
 	if (rc)
 		return SBI_EFAIL;
 
+	ae350_non_ret_save(sbi_scratch_thishart_ptr());
 	ae350_disable_coherency();
 	wfi();
 	return 0;
diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c
index fa3f03685bba..9bd1554394b7 100644
--- a/platform/generic/andes/ae350.c
+++ b/platform/generic/andes/ae350.c
@@ -8,18 +8,73 @@
 #include <andes/andes_pmu.h>
 #include <andes/andes_sbi.h>
 #include <platform_override.h>
+#include <sbi/sbi_init.h>
+#include <sbi/sbi_scratch.h>
 #include <sbi_utils/fdt/fdt_helper.h>
 
+static unsigned long andes_hart_data_offset;
 extern void _start_warm(void);
 
+void ae350_non_ret_save(struct sbi_scratch *scratch)
+{
+	struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch,
+								     andes_hart_data_offset);
+
+	andes_hdata->mcache_ctl = csr_read(CSR_MCACHE_CTL);
+	andes_hdata->mmisc_ctl = csr_read(CSR_MMISC_CTL);
+	andes_hdata->mpft_ctl = csr_read(CSR_MPFT_CTL);
+	andes_hdata->mslideleg = csr_read(CSR_MSLIDELEG);
+	andes_hdata->mxstatus = csr_read(CSR_MXSTATUS);
+	andes_hdata->slie = csr_read(CSR_SLIE);
+	andes_hdata->slip = csr_read(CSR_SLIP);
+	andes_hdata->pmacfg0 = csr_read(CSR_PMACFG0);
+	andes_hdata->pmacfg2 = csr_read_num(CSR_PMACFG0 + 2);
+	for (int i = 0; i < 16; i++)
+		andes_hdata->pmaaddrX[i] = csr_read_num(CSR_PMAADDR0 + i);
+}
+
+void ae350_non_ret_restore(struct sbi_scratch *scratch)
+{
+	struct andes_hart_data *andes_hdata = sbi_scratch_offset_ptr(scratch,
+								     andes_hart_data_offset);
+
+	csr_write(CSR_MCACHE_CTL, andes_hdata->mcache_ctl);
+	csr_write(CSR_MMISC_CTL, andes_hdata->mmisc_ctl);
+	csr_write(CSR_MPFT_CTL, andes_hdata->mpft_ctl);
+	csr_write(CSR_MSLIDELEG, andes_hdata->mslideleg);
+	csr_write(CSR_MXSTATUS, andes_hdata->mxstatus);
+	csr_write(CSR_SLIE, andes_hdata->slie);
+	csr_write(CSR_SLIP, andes_hdata->slip);
+	csr_write(CSR_PMACFG0, andes_hdata->pmacfg0);
+	csr_write_num(CSR_PMACFG0 + 2, andes_hdata->pmacfg2);
+	for (int i = 0; i < 16; i++)
+		csr_write_num(CSR_PMAADDR0 + i, andes_hdata->pmaaddrX[i]);
+}
+
 void ae350_enable_coherency_warmboot(void)
 {
 	ae350_enable_coherency();
 	_start_warm();
 }
 
+static int ae350_early_init(bool cold_boot)
+{
+	if (cold_boot) {
+		andes_hart_data_offset = sbi_scratch_alloc_offset(sizeof(struct andes_hart_data));
+		if (!andes_hart_data_offset)
+			return SBI_ENOMEM;
+	}
+
+	/* Don't restore Andes CSRs during boot */
+	if (sbi_init_count(current_hartindex()))
+		ae350_non_ret_restore(sbi_scratch_thishart_ptr());
+
+	return generic_early_init(cold_boot);
+}
+
 static int ae350_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
 {
+	generic_platform_ops.early_init = ae350_early_init;
 	generic_platform_ops.extensions_init = andes_pmu_extensions_init;
 	generic_platform_ops.pmu_init = andes_pmu_init;
 	generic_platform_ops.vendor_ext_provider = andes_sbi_vendor_ext_provider;
diff --git a/platform/generic/include/andes/andes.h b/platform/generic/include/andes/andes.h
index 1b5893925c10..dd2451718d00 100644
--- a/platform/generic/include/andes/andes.h
+++ b/platform/generic/include/andes/andes.h
@@ -10,16 +10,21 @@
 #include <sbi/sbi_scratch.h>
 
 /* Memory and Miscellaneous Registers */
+#define CSR_MPFT_CTL		0x7c5
 #define CSR_MCACHE_CTL		0x7ca
 #define CSR_MCCTLCOMMAND	0x7cc
+#define CSR_MMISC_CTL		0x7d0
 
 /* Configuration Control & Status Registers */
 #define CSR_MICM_CFG		0xfc0
 #define CSR_MDCM_CFG		0xfc1
 #define CSR_MMSC_CFG		0xfc2
 
-/* Machine Trap Related Registers */
+/* Trap Related Registers */
+#define CSR_MXSTATUS		0x7c4
 #define CSR_MSLIDELEG		0x7d5
+#define CSR_SLIE		0x9c4
+#define CSR_SLIP		0x9c5
 
 /* Counter Related Registers */
 #define CSR_MCOUNTERWEN		0x7ce
@@ -80,6 +85,21 @@
 
 #endif /* __ASSEMBLER__ */
 
+struct andes_hart_data {
+	unsigned long mcache_ctl;
+	unsigned long mmisc_ctl;
+	unsigned long mpft_ctl;
+	unsigned long mslideleg;
+	unsigned long mxstatus;
+	unsigned long slie;
+	unsigned long slip;
+	unsigned long pmacfg0;
+	unsigned long pmacfg2;
+	unsigned long pmaaddrX[16];
+};
+
+void ae350_non_ret_save(struct sbi_scratch *scratch);
+void ae350_non_ret_restore(struct sbi_scratch *scratch);
 void ae350_enable_coherency_warmboot(void);
 
 /*
-- 
2.34.1




More information about the opensbi mailing list