diff --git a/include/sbi_utils/hsm/fdt_hsm_andes_atcsmu.h b/include/sbi_utils/hsm/fdt_hsm_andes_atcsmu.h new file mode 100644 index 00000000..881d8b21 --- /dev/null +++ b/include/sbi_utils/hsm/fdt_hsm_andes_atcsmu.h @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Andes Technology Corporation + */ + +#ifndef __FDT_HSM_ANDES_ATCSMU_H__ +#define __FDT_HSM_ANDES_ATCSMU_H__ + +#include + +/* clang-format off */ + +#define RESET_VEC_LO_OFFSET 0x50 +#define RESET_VEC_HI_OFFSET 0x60 +#define RESET_VEC_8CORE_OFFSET 0x1a0 +#define HARTn_RESET_VEC_LO(n) (RESET_VEC_LO_OFFSET + \ + ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ + ((n) * 0x4)) +#define HARTn_RESET_VEC_HI(n) (RESET_VEC_HI_OFFSET + \ + ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ + ((n) * 0x4)) + +#define PCS0_CFG_OFFSET 0x80 +#define PCSm_CFG_OFFSET(i) ((i + 3) * 0x20 + PCS0_CFG_OFFSET) +#define PCS_CFG_LIGHT_SLEEP BIT(2) +#define PCS_CFG_DEEP_SLEEP BIT(3) + +#define PCS0_SCRATCH_OFFSET 0x84 +#define PCSm_SCRATCH_OFFSET(i) ((i + 3) * 0x20 + PCS0_SCRATCH_OFFSET) + +#define PCS0_WE_OFFSET 0x90 +#define PCSm_WE_OFFSET(i) ((i + 3) * 0x20 + PCS0_WE_OFFSET) + +#define PCS0_CTL_OFFSET 0x94 +#define PCSm_CTL_OFFSET(i) ((i + 3) * 0x20 + PCS0_CTL_OFFSET) +#define LIGHT_SLEEP_CMD 0x3 +#define WAKEUP_CMD 0x8 +#define DEEP_SLEEP_CMD 0xb + +/* clang-format on */ + +void atcsmu_set_wakeup_events(u32 events, u32 hartid); +bool atcsmu_support_sleep_mode(u32 sleep_type, u32 hartid); +void atcsmu_set_command(u32 pcs_ctl, u32 hartid); +int atcsmu_set_reset_vector(u64 wakeup_addr, u32 hartid); +u32 atcsmu_get_sleep_type(u32 hartid); + +#endif diff --git a/include/sbi_utils/sys/atcsmu.h b/include/sbi_utils/sys/atcsmu.h deleted file mode 100644 index 07be22ee..00000000 --- a/include/sbi_utils/sys/atcsmu.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 2023 Andes Technology Corporation - */ - -#ifndef _SYS_ATCSMU_H -#define _SYS_ATCSMU_H - -#include - -/* clang-format off */ - -#define PCS0_WE_OFFSET 0x90 -#define PCSm_WE_OFFSET(i) ((i + 3) * 0x20 + PCS0_WE_OFFSET) - -#define PCS0_CTL_OFFSET 0x94 -#define PCSm_CTL_OFFSET(i) ((i + 3) * 0x20 + PCS0_CTL_OFFSET) -#define PCS_CTL_CMD_SHIFT 0 -#define PCS_CTL_PARAM_SHIFT 3 -#define SLEEP_CMD 0x3 -#define WAKEUP_CMD (0x0 | (1 << PCS_CTL_PARAM_SHIFT)) -#define LIGHTSLEEP_MODE 0 -#define DEEPSLEEP_MODE 1 -#define LIGHT_SLEEP_CMD (SLEEP_CMD | (LIGHTSLEEP_MODE << PCS_CTL_PARAM_SHIFT)) -#define DEEP_SLEEP_CMD (SLEEP_CMD | (DEEPSLEEP_MODE << PCS_CTL_PARAM_SHIFT)) - -#define PCS0_CFG_OFFSET 0x80 -#define PCSm_CFG_OFFSET(i) ((i + 3) * 0x20 + PCS0_CFG_OFFSET) -#define PCS_CFG_LIGHT_SLEEP_SHIFT 2 -#define PCS_CFG_LIGHT_SLEEP (1 << PCS_CFG_LIGHT_SLEEP_SHIFT) -#define PCS_CFG_DEEP_SLEEP_SHIFT 3 -#define PCS_CFG_DEEP_SLEEP (1 << PCS_CFG_DEEP_SLEEP_SHIFT) - -#define RESET_VEC_LO_OFFSET 0x50 -#define RESET_VEC_HI_OFFSET 0x60 -#define RESET_VEC_8CORE_OFFSET 0x1a0 -#define HARTn_RESET_VEC_LO(n) (RESET_VEC_LO_OFFSET + \ - ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ - ((n) * 0x4)) -#define HARTn_RESET_VEC_HI(n) (RESET_VEC_HI_OFFSET + \ - ((n) < 4 ? 0 : RESET_VEC_8CORE_OFFSET) + \ - ((n) * 0x4)) - -#define PCS_MAX_NR 8 -#define FLASH_BASE 0x80000000ULL - -/* clang-format on */ - -struct smu_data { - unsigned long addr; -}; - -int smu_set_wakeup_events(struct smu_data *smu, u32 events, u32 hartid); -bool smu_support_sleep_mode(struct smu_data *smu, u32 sleep_mode, u32 hartid); -int smu_set_command(struct smu_data *smu, u32 pcs_ctl, u32 hartid); -int smu_set_reset_vector(struct smu_data *smu, ulong wakeup_addr, u32 hartid); - -#endif /* _SYS_ATCSMU_H */ 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 # +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 + * Copyright (c) 2025 Andes Technology Corporation */ #include @@ -15,7 +12,7 @@ #include #include #include -#include +#include #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, ®_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 - */ - -#include -#include -#include -#include -#include - -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 diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 716fab42..0c11fbd2 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -36,7 +36,6 @@ config PLATFORM_ALLWINNER_D1 config PLATFORM_ANDES_AE350 bool "Andes AE350 support" - select SYS_ATCSMU select ANDES_PMU select ANDES_PMA default n diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c index 08080657..fa3f0368 100644 --- a/platform/generic/andes/ae350.c +++ b/platform/generic/andes/ae350.c @@ -1,121 +1,25 @@ /* * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2022 Andes Technology Corporation - * - * Authors: - * Yu Chien Peter Lin + * Copyright (c) 2025 Andes Technology Corporation */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include +#include +#include -static struct smu_data smu = { 0 }; -extern void __ae350_enable_coherency_warmboot(void); -extern void __ae350_disable_coherency(void); +extern void _start_warm(void); -static int ae350_hart_start(u32 hartid, ulong saddr) +void ae350_enable_coherency_warmboot(void) { - 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); - - /* Write wakeup command to the sleep hart */ - smu_set_command(&smu, WAKEUP_CMD, hartid); - - return 0; -} - -static int ae350_hart_stop(void) -{ - int rc; - u32 hartid = current_hartid(); - - /** - * For Andes AX25MP, the hart0 shares power domain with - * L2-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 (!smu_support_sleep_mode(&smu, 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(&smu, 0x0, hartid); - smu_set_command(&smu, DEEP_SLEEP_CMD, hartid); - - rc = smu_set_reset_vector(&smu, - (ulong)__ae350_enable_coherency_warmboot, - hartid); - if (rc) - goto fail; - - __ae350_disable_coherency(); - - wfi(); - -fail: - /* 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(const void *fdt) -{ - int rc; - - 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) -{ - if (cold_boot) { - const void *fdt = fdt_get_address(); - - ae350_hsm_device_init(fdt); - } - - return generic_final_init(cold_boot); + ae350_enable_coherency(); + _start_warm(); } static int ae350_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { - generic_platform_ops.final_init = ae350_final_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/andes/objects.mk b/platform/generic/andes/objects.mk index f85ad481..660546c3 100644 --- a/platform/generic/andes/objects.mk +++ b/platform/generic/andes/objects.mk @@ -3,7 +3,7 @@ # carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350 -platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o +platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_QILAI) += andes_qilai platform-objs-$(CONFIG_PLATFORM_ANDES_QILAI) += andes/qilai.o diff --git a/platform/generic/andes/sleep.S b/platform/generic/andes/sleep.S deleted file mode 100644 index 361aff3a..00000000 --- a/platform/generic/andes/sleep.S +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2023 Andes Technology Corporation - * - * Authors: - * Yu Chien Peter Lin - */ - -#include -#include -#include - - .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 diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index aab1560f..d85da930 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -23,6 +23,7 @@ CONFIG_FDT_GPIO_DESIGNWARE=y CONFIG_FDT_GPIO_SIFIVE=y CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_HSM=y +CONFIG_FDT_HSM_ANDES_ATCSMU=y CONFIG_FDT_HSM_RPMI=y CONFIG_FDT_HSM_SIFIVE_TMC0=y CONFIG_FDT_I2C=y diff --git a/platform/generic/include/andes/andes.h b/platform/generic/include/andes/andes.h index bfedf034..1b589392 100644 --- a/platform/generic/include/andes/andes.h +++ b/platform/generic/include/andes/andes.h @@ -6,6 +6,9 @@ #ifndef _RISCV_ANDES_H #define _RISCV_ANDES_H +#include +#include + /* Memory and Miscellaneous Registers */ #define CSR_MCACHE_CTL 0x7ca #define CSR_MCCTLCOMMAND 0x7cc @@ -43,13 +46,23 @@ #define MMSC_IOCP_OFFSET 47 #define MMSC_IOCP_MASK (1ULL << MMSC_IOCP_OFFSET) +#define MCACHE_CTL_IC_EN_MASK BIT(0) +#define MCACHE_CTL_DC_EN_MASK BIT(1) #define MCACHE_CTL_CCTL_SUEN_OFFSET 8 #define MCACHE_CTL_CCTL_SUEN_MASK (1 << MCACHE_CTL_CCTL_SUEN_OFFSET) +#define MCACHE_CTL_DC_COHEN_MASK BIT(19) +#define MCACHE_CTL_DC_COHSTA_MASK BIT(20) /* Performance monitor */ #define MMSC_CFG_PMNDS_MASK (1 << 15) #define MIP_PMOVI (1 << 18) +/* Cache control commands */ +#define MCCTLCOMMAND_L1D_WBINVAL_ALL 6 + +/* AE350 platform specific sleep types */ +#define SBI_SUSP_AE350_LIGHT_SLEEP SBI_SUSP_PLATFORM_SLEEP_START + #ifndef __ASSEMBLER__ #define is_andes(series) \ @@ -67,4 +80,53 @@ #endif /* __ASSEMBLER__ */ +void ae350_enable_coherency_warmboot(void); + +/* + * On Andes 4X-series CPUs, disabling the L1 data cache causes the CPU to fetch + * data directly from RAM. However, L1 cache flushes write data back to the + * Last Level Cache (LLC). This discrepancy can lead to return address + * corruption on the stack. To prevent this, the following functions must + * be inlined. + */ +static inline void ae350_disable_coherency(void) +{ + /* + * To disable cache coherency of a core in AE350 platform, follow below steps: + * + * 1) Disable I/D-Cache + * 2) Write back and invalidate D-Cache + * 3) Disable D-Cache coherency + * 4) Wait for D-Cache disengaged from the coherence management + */ + csr_clear(CSR_MCACHE_CTL, MCACHE_CTL_IC_EN_MASK | MCACHE_CTL_DC_EN_MASK); + csr_write(CSR_MCCTLCOMMAND, MCCTLCOMMAND_L1D_WBINVAL_ALL); + csr_clear(CSR_MCACHE_CTL, MCACHE_CTL_DC_COHEN_MASK); + while (csr_read(CSR_MCACHE_CTL) & MCACHE_CTL_DC_COHSTA_MASK) + ; +} + +static inline void ae350_enable_coherency(void) +{ + /* + * To enable cache coherency of a core in AE350 platform, follow below steps: + * + * 1) Enable D-Cache coherency + * 2) Wait for D-Cache engaging in the coherence management + * 3) Enable I/D-Cache + */ + csr_set(CSR_MCACHE_CTL, MCACHE_CTL_DC_COHEN_MASK); + + /* + * mcache_ctl.DC_COHEN is hardwired to 0 if there is no coherence + * manager. In such situation, just enable the I/D-Cache to prevent + * permanently being stuck in the while loop. + */ + if (csr_read(CSR_MCACHE_CTL) & MCACHE_CTL_DC_COHEN_MASK) + while (!(csr_read(CSR_MCACHE_CTL) & MCACHE_CTL_DC_COHSTA_MASK)) + ; + + csr_set(CSR_MCACHE_CTL, MCACHE_CTL_IC_EN_MASK | MCACHE_CTL_DC_EN_MASK); +} + #endif /* _RISCV_ANDES_H */