summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBen Zong-You Xie <[email protected]>2025-12-29 15:19:10 +0800
committerAnup Patel <[email protected]>2026-02-11 12:03:50 +0530
commit9ffacc8ae1ca07ed36d57f887d62a65ae7a44223 (patch)
tree5afcb8ec6848672d817dffc27462c5f6f8429357 /lib
parent74434f255873d74e56cc50aa762d1caf24c099f8 (diff)
lib: utils/hsm: factor out ATCSMU code into an HSM driver
Refactor ATCSMU (System Management Unit) support by moving it from a system utility into a dedicated FDT-based HSM driver. Key changes include: - Moving the functions in lib/utils/sys/atcsmu.c into the new HSM driver - Moving hart start and stop operations on AE350 platform into the new HSM driver - Converting the assembly-based functions in sleep.S to C code for the readability - Updating the ATCWDT200 driver Signed-off-by: Ben Zong-You Xie <[email protected]> Signed-off-by: Leo Yu-Chi Liang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Anup Patel <[email protected]>
Diffstat (limited to 'lib')
-rw-r--r--lib/utils/hsm/Kconfig4
-rw-r--r--lib/utils/hsm/fdt_hsm_andes_atcsmu.c167
-rw-r--r--lib/utils/hsm/objects.mk5
-rw-r--r--lib/utils/reset/Kconfig2
-rw-r--r--lib/utils/reset/fdt_reset_atcwdt200.c22
-rw-r--r--lib/utils/sys/Kconfig4
-rw-r--r--lib/utils/sys/atcsmu.c89
-rw-r--r--lib/utils/sys/objects.mk1
8 files changed, 181 insertions, 113 deletions
diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
index 94973c8f..1dfb243e 100644
--- a/lib/utils/hsm/Kconfig
+++ b/lib/utils/hsm/Kconfig
@@ -9,6 +9,10 @@ config FDT_HSM
if FDT_HSM
+config FDT_HSM_ANDES_ATCSMU
+ bool "FDT Andes ATCSMU driver"
+ default n
+
config FDT_HSM_RPMI
bool "FDT RPMI HSM driver"
depends on FDT_MAILBOX && RPMI_MAILBOX
diff --git a/lib/utils/hsm/fdt_hsm_andes_atcsmu.c b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
new file mode 100644
index 00000000..a9621773
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm_andes_atcsmu.c
@@ -0,0 +1,167 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Andes Technology Corporation
+ */
+
+#include <andes/andes.h>
+#include <libfdt.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ecall_interface.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_init.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/hsm/fdt_hsm_andes_atcsmu.h>
+
+static unsigned long atcsmu_base;
+
+void atcsmu_set_wakeup_events(u32 events, u32 hartid)
+{
+ writel_relaxed(events, (char *)atcsmu_base + PCSm_WE_OFFSET(hartid));
+}
+
+bool atcsmu_support_sleep_mode(u32 sleep_type, u32 hartid)
+{
+ u32 pcs_cfg;
+ u32 mask;
+ const char *sleep_mode;
+
+ pcs_cfg = readl_relaxed((char *)atcsmu_base + PCSm_CFG_OFFSET(hartid));
+ switch (sleep_type) {
+ case SBI_SUSP_AE350_LIGHT_SLEEP:
+ mask = PCS_CFG_LIGHT_SLEEP;
+ sleep_mode = "light sleep";
+ break;
+ case SBI_SUSP_SLEEP_TYPE_SUSPEND:
+ mask = PCS_CFG_DEEP_SLEEP;
+ sleep_mode = "deep sleep";
+ break;
+ default:
+ return false;
+ }
+
+ if (!EXTRACT_FIELD(pcs_cfg, mask)) {
+ sbi_printf("ATCSMU: hart%d (PCS%d) does not support %s mode\n",
+ hartid, hartid + 3, sleep_mode);
+ return false;
+ }
+
+ return true;
+}
+
+void atcsmu_set_command(u32 pcs_ctl, u32 hartid)
+{
+ writel_relaxed(pcs_ctl, (char *)atcsmu_base + PCSm_CTL_OFFSET(hartid));
+}
+
+int atcsmu_set_reset_vector(u64 wakeup_addr, u32 hartid)
+{
+ u32 vec_lo;
+ u32 vec_hi;
+ u64 reset_vector;
+
+ writel((u32)wakeup_addr, (char *)atcsmu_base + HARTn_RESET_VEC_LO(hartid));
+ writel((u32)(wakeup_addr >> 32), (char *)atcsmu_base + HARTn_RESET_VEC_HI(hartid));
+ vec_lo = readl((char *)atcsmu_base + HARTn_RESET_VEC_LO(hartid));
+ vec_hi = readl((char *)atcsmu_base + HARTn_RESET_VEC_HI(hartid));
+ reset_vector = (u64)vec_hi << 32 | vec_lo;
+ if (reset_vector != wakeup_addr) {
+ sbi_printf("ATCSMU: hart%d (PCS%d): failed to program the reset vector\n",
+ hartid, hartid + 3);
+ return SBI_EFAIL;
+ }
+
+ return SBI_OK;
+}
+
+u32 atcsmu_get_sleep_type(u32 hartid)
+{
+ return readl_relaxed((char *)atcsmu_base + PCSm_SCRATCH_OFFSET(hartid));
+}
+
+static int ae350_hart_start(u32 hartid, ulong saddr)
+{
+ u32 hartindex = sbi_hartid_to_hartindex(hartid);
+
+ /*
+ * Don't send wakeup command when:
+ * 1) boot time
+ * 2) the target hart is non-sleepable 25-series hart0
+ */
+ if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0))
+ return sbi_ipi_raw_send(hartindex, false);
+
+ atcsmu_set_command(WAKEUP_CMD, hartid);
+ return 0;
+}
+
+static int ae350_hart_stop(void)
+{
+ u32 hartid = current_hartid();
+ u32 sleep_type = atcsmu_get_sleep_type(hartid);
+ int rc;
+
+ /*
+ * For Andes AX25MP, the hart0 shares power domain with the last level
+ * cache. Instead of turning it off, it should fall through and jump to
+ * warmboot_addr.
+ */
+ if (is_andes(25) && hartid == 0)
+ return SBI_ENOTSUPP;
+
+ if (!atcsmu_support_sleep_mode(sleep_type, hartid))
+ return SBI_ENOTSUPP;
+
+ /* Prevent the core leaving the WFI mode unexpectedly */
+ csr_write(CSR_MIE, 0);
+
+ atcsmu_set_wakeup_events(0x0, hartid);
+ atcsmu_set_command(DEEP_SLEEP_CMD, hartid);
+ rc = atcsmu_set_reset_vector((ulong)ae350_enable_coherency_warmboot, hartid);
+ if (rc)
+ return SBI_EFAIL;
+
+ ae350_disable_coherency();
+ wfi();
+ return 0;
+}
+
+static const struct sbi_hsm_device hsm_andes_atcsmu = {
+ .name = "andes_atcsmu",
+ .hart_start = ae350_hart_start,
+ .hart_stop = ae350_hart_stop,
+};
+
+static int hsm_andes_atcsmu_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+ int poff, rc;
+ u64 addr;
+
+ /* Need to find the parent for the address property */
+ poff = fdt_parent_offset(fdt, nodeoff);
+ if (poff < 0)
+ return SBI_EINVAL;
+
+ rc = fdt_get_node_addr_size(fdt, poff, 0, &addr, NULL);
+ if (rc < 0 || !addr)
+ return SBI_ENODEV;
+ atcsmu_base = addr;
+
+ sbi_hsm_set_device(&hsm_andes_atcsmu);
+ return 0;
+}
+
+static const struct fdt_match hsm_andes_atcsmu_match[] = {
+ { .compatible = "andestech,atcsmu-hsm" },
+ { },
+};
+
+const struct fdt_driver fdt_hsm_andes_atcsmu = {
+ .match_table = hsm_andes_atcsmu_match,
+ .init = hsm_andes_atcsmu_probe,
+};
diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
index 0d005449..f76af03c 100644
--- a/lib/utils/hsm/objects.mk
+++ b/lib/utils/hsm/objects.mk
@@ -7,6 +7,9 @@
# Anup Patel <[email protected]>
#
+carray-fdt_early_drivers-$(CONFIG_FDT_HSM_ANDES_ATCSMU) += fdt_hsm_andes_atcsmu
+libsbiutils-objs-$(CONFIG_FDT_HSM_ANDES_ATCSMU) += hsm/fdt_hsm_andes_atcsmu.o
+
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
@@ -14,4 +17,4 @@ carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SPACEMIT) += fdt_hsm_spacemit
libsbiutils-objs-$(CONFIG_FDT_HSM_SPACEMIT) += hsm/fdt_hsm_spacemit.o
carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += fdt_hsm_sifive_tmc0
-libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o \ No newline at end of file
+libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig
index 68e66716..4835921f 100644
--- a/lib/utils/reset/Kconfig
+++ b/lib/utils/reset/Kconfig
@@ -11,7 +11,7 @@ if FDT_RESET
config FDT_RESET_ATCWDT200
bool "Andes WDT FDT reset driver"
- depends on SYS_ATCSMU
+ depends on FDT_HSM_ANDES_ATCSMU
default n
config FDT_RESET_GPIO
diff --git a/lib/utils/reset/fdt_reset_atcwdt200.c b/lib/utils/reset/fdt_reset_atcwdt200.c
index 2304582a..5dad8ac9 100644
--- a/lib/utils/reset/fdt_reset_atcwdt200.c
+++ b/lib/utils/reset/fdt_reset_atcwdt200.c
@@ -1,10 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2022 Andes Technology Corporation
- *
- * Authors:
- * Yu Chien Peter Lin <[email protected]>
+ * Copyright (c) 2025 Andes Technology Corporation
*/
#include <libfdt.h>
@@ -15,7 +12,7 @@
#include <sbi/sbi_system.h>
#include <sbi_utils/fdt/fdt_driver.h>
#include <sbi_utils/fdt/fdt_helper.h>
-#include <sbi_utils/sys/atcsmu.h>
+#include <sbi_utils/hsm/fdt_hsm_andes_atcsmu.h>
#define ATCWDT200_WP_NUM 0x5aa5
#define WREN_REG 0x18
@@ -41,8 +38,9 @@
#define CLK_PCLK (1 << 1)
#define WDT_EN (1 << 0)
+#define AE350_FLASH_BASE 0x80000000
+
static volatile char *wdt_addr = NULL;
-static struct smu_data smu = { 0 };
static int ae350_system_reset_check(u32 type, u32 reason)
{
@@ -59,7 +57,7 @@ static int ae350_system_reset_check(u32 type, u32 reason)
static void ae350_system_reset(u32 type, u32 reason)
{
sbi_for_each_hartindex(i)
- if (smu_set_reset_vector(&smu, FLASH_BASE, i))
+ if (atcsmu_set_reset_vector(AE350_FLASH_BASE, i))
goto fail;
/* Program WDT control register */
@@ -88,16 +86,6 @@ static int atcwdt200_reset_init(const void *fdt, int nodeoff,
return SBI_ENODEV;
wdt_addr = (volatile char *)(unsigned long)reg_addr;
-
- /*
- * The reset device requires smu to program the reset
- * vector for each hart.
- */
- if (fdt_parse_compat_addr(fdt, &reg_addr, "andestech,atcsmu"))
- return SBI_ENODEV;
-
- smu.addr = (unsigned long)reg_addr;
-
sbi_system_reset_add_device(&atcwdt200_reset);
return 0;
diff --git a/lib/utils/sys/Kconfig b/lib/utils/sys/Kconfig
index a22191cd..fc388665 100644
--- a/lib/utils/sys/Kconfig
+++ b/lib/utils/sys/Kconfig
@@ -2,10 +2,6 @@
menu "System Device Support"
-config SYS_ATCSMU
- bool "Andes System Management Unit (SMU) support"
- default n
-
config SYS_HTIF
bool "Host transfere interface (HTIF) support"
default n
diff --git a/lib/utils/sys/atcsmu.c b/lib/utils/sys/atcsmu.c
deleted file mode 100644
index 2cba0eb7..00000000
--- a/lib/utils/sys/atcsmu.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2023 Andes Technology Corporation
- *
- * Authors:
- * Yu Chien Peter Lin <[email protected]>
- */
-
-#include <sbi_utils/sys/atcsmu.h>
-#include <sbi/riscv_io.h>
-#include <sbi/sbi_console.h>
-#include <sbi/sbi_error.h>
-#include <sbi/sbi_bitops.h>
-
-inline int smu_set_wakeup_events(struct smu_data *smu, u32 events, u32 hartid)
-{
- if (smu) {
- writel(events, (void *)(smu->addr + PCSm_WE_OFFSET(hartid)));
- return 0;
- } else
- return SBI_EINVAL;
-}
-
-inline bool smu_support_sleep_mode(struct smu_data *smu, u32 sleep_mode,
- u32 hartid)
-{
- u32 pcs_cfg;
-
- if (!smu) {
- sbi_printf("%s(): Failed to access smu_data\n", __func__);
- return false;
- }
-
- pcs_cfg = readl((void *)(smu->addr + PCSm_CFG_OFFSET(hartid)));
-
- switch (sleep_mode) {
- case LIGHTSLEEP_MODE:
- if (EXTRACT_FIELD(pcs_cfg, PCS_CFG_LIGHT_SLEEP) == 0) {
- sbi_printf("SMU: hart%d (PCS%d) does not support light sleep mode\n",
- hartid, hartid + 3);
- return false;
- }
- break;
- case DEEPSLEEP_MODE:
- if (EXTRACT_FIELD(pcs_cfg, PCS_CFG_DEEP_SLEEP) == 0) {
- sbi_printf("SMU: hart%d (PCS%d) does not support deep sleep mode\n",
- hartid, hartid + 3);
- return false;
- }
- break;
- }
-
- return true;
-}
-
-inline int smu_set_command(struct smu_data *smu, u32 pcs_ctl, u32 hartid)
-{
- if (smu) {
- writel(pcs_ctl, (void *)(smu->addr + PCSm_CTL_OFFSET(hartid)));
- return 0;
- } else
- return SBI_EINVAL;
-}
-
-inline int smu_set_reset_vector(struct smu_data *smu, ulong wakeup_addr,
- u32 hartid)
-{
- u32 vec_lo, vec_hi;
- u64 reset_vector;
-
- if (!smu)
- return SBI_EINVAL;
-
- writel(wakeup_addr, (void *)(smu->addr + HARTn_RESET_VEC_LO(hartid)));
- writel((u64)wakeup_addr >> 32,
- (void *)(smu->addr + HARTn_RESET_VEC_HI(hartid)));
-
- vec_lo = readl((void *)(smu->addr + HARTn_RESET_VEC_LO(hartid)));
- vec_hi = readl((void *)(smu->addr + HARTn_RESET_VEC_HI(hartid)));
- reset_vector = ((u64)vec_hi << 32) | vec_lo;
-
- if (reset_vector != (u64)wakeup_addr) {
- sbi_printf("hart%d (PCS%d): Failed to program the reset vector.\n",
- hartid, hartid + 3);
- return SBI_EFAIL;
- } else
- return 0;
-}
diff --git a/lib/utils/sys/objects.mk b/lib/utils/sys/objects.mk
index 409d7e8c..d9c67077 100644
--- a/lib/utils/sys/objects.mk
+++ b/lib/utils/sys/objects.mk
@@ -8,4 +8,3 @@
#
libsbiutils-objs-$(CONFIG_SYS_HTIF) += sys/htif.o
-libsbiutils-objs-$(CONFIG_SYS_ATCSMU) += sys/atcsmu.o