@@ -10,6 +10,89 @@
#include <platform_override.h>
#include <sbi_utils/fdt/fdt_helper.h>
#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/sys/atcsmu.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_init.h>
+
+struct smu_data smu;
+extern void __ae350_enable_coherency_warmboot(void);
+extern void __ae350_disable_coherency(void);
+
+static int ae350_hart_start(u32 hartid, ulong saddr)
+{
+ if (!sbi_init_count(hartid) || (is_andes25() && hartid == 0))
+ return sbi_ipi_raw_send(hartid);
+
+ /* Write wakeup command to the sleep hart */
+ smu_set_command(WAKEUP_CMD, hartid);
+
+ return 0;
+}
+
+static int ae350_hart_stop(void)
+{
+ u32 hartid = current_hartid();
+
+ /**
+ * The hart0 shares power domain with L2-cache,
+ * instead of turning it off, it falls through
+ * and jump to warmboot_addr.
+ */
+ if (is_andes25() && hartid == 0)
+ return SBI_ENOTSUPP;
+
+ if (!smu_support_sleep_mode(DEEPSLEEP_MODE, hartid))
+ return SBI_ENOTSUPP;
+
+ /**
+ * disable all events, the current hart will be
+ * woken up from reset vector when other hart
+ * writes its PCS (power control slot) control
+ * register
+ */
+ smu_set_wakeup_events(0x0, hartid);
+ smu_set_command(DEEP_SLEEP_CMD, hartid);
+ smu_set_reset_vector((ulong)__ae350_enable_coherency_warmboot,
+ hartid);
+ __ae350_disable_coherency();
+
+ wfi();
+
+ /* It should never reach here */
+ sbi_hart_hang();
+ return 0;
+}
+
+static const struct sbi_hsm_device andes_smu = {
+ .name = "andes_smu",
+ .hart_start = ae350_hart_start,
+ .hart_stop = ae350_hart_stop,
+};
+
+static void ae350_hsm_device_init(void)
+{
+ int rc;
+ void *fdt;
+
+ fdt = fdt_get_address();
+
+ rc = fdt_parse_compat_addr(fdt, (uint64_t *)&smu.addr,
+ "andestech,atcsmu");
+
+ if (!rc) {
+ sbi_hsm_set_device(&andes_smu);
+ }
+}
+
+static int ae350_final_init(bool cold_boot, const struct fdt_match *match)
+{
+ if (cold_boot)
+ ae350_hsm_device_init();
+
+ return 0;
+}
static const struct fdt_match andes_ae350_match[] = {
{ .compatible = "andestech,ae350" },
@@ -18,4 +101,5 @@ static const struct fdt_match andes_ae350_match[] = {
const struct platform_override andes_ae350 = {
.match_table = andes_ae350_match,
+ .final_init = ae350_final_init,
};
@@ -3,4 +3,4 @@
#
carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
-platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o
+platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
new file mode 100644
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Andes Technology Corporation
+ *
+ * Authors:
+ * Yu Chien Peter Lin <peterlin@andestech.com>
+ */
+
+#include <sbi/riscv_encoding.h>
+#include <sbi/riscv_asm.h>
+#include <andes/andes45.h>
+
+ .section .text, "ax", %progbits
+ .align 3
+ .global __ae350_disable_coherency
+__ae350_disable_coherency:
+ /* flush d-cache */
+ csrw CSR_MCCTLCOMMAND, 0x6
+ /* disable i/d-cache */
+ csrc CSR_MCACHE_CTL, 0x3
+ /* disable d-cache coherency */
+ lui t1, 0x80
+ csrc CSR_MCACHE_CTL, t1
+ /*
+ * wait for mcache_ctl.DC_COHSTA to be cleared,
+ * the bit is hard-wired 0 on platforms w/o CM
+ * (Coherence Manager)
+ */
+check_cm_disabled:
+ csrr t1, CSR_MCACHE_CTL
+ srli t1, t1, 20
+ andi t1, t1, 0x1
+ bnez t1, check_cm_disabled
+
+ ret
+
+ .section .text, "ax", %progbits
+ .align 3
+ .global __ae350_enable_coherency
+__ae350_enable_coherency:
+ /* enable d-cache coherency */
+ lui t1, 0x80
+ csrs CSR_MCACHE_CTL, t1
+ /*
+ * mcache_ctl.DC_COHEN is hard-wired 0 on platforms
+ * w/o CM support
+ */
+ csrr t1, CSR_MCACHE_CTL
+ srli t1, t1, 19
+ andi t1, t1, 0x1
+ beqz t1, enable_L1_cache
+ /* wait for mcache_ctl.DC_COHSTA to be set */
+check_cm_enabled:
+ csrr t1, CSR_MCACHE_CTL
+ srli t1, t1, 20
+ andi t1, t1, 0x1
+ beqz t1, check_cm_enabled
+enable_L1_cache:
+ /* enable i/d-cache */
+ csrs CSR_MCACHE_CTL, 0x3
+
+ ret
+
+ .section .text, "ax", %progbits
+ .align 3
+ .global __ae350_enable_coherency_warmboot
+__ae350_enable_coherency_warmboot:
+ call ra, __ae350_enable_coherency
+ j _start_warm
new file mode 100644
@@ -0,0 +1,10 @@
+#ifndef _RISCV_ANDES45_H
+#define _RISCV_ANDES45_H
+
+#define CSR_MARCHID_MICROID 0xfff
+
+/* Memory and Miscellaneous Registers */
+#define CSR_MCACHE_CTL 0x7ca
+#define CSR_MCCTLCOMMAND 0x7cc
+
+#endif /* _RISCV_ANDES45_H */