From 96f662b167f98affa544beec285f60b584a6e7ef Mon Sep 17 00:00:00 2001 From: Chen Pei Date: Thu, 16 Jan 2025 16:03:27 +0800 Subject: [PATCH] platform: Add xuantie_pmc for PMC test This is an example implementation of power management using C907 PMC, which mainly implements sbi_hsm_device, sbi_system_reset_device and sbi_system_suspend_device defined by opensbi. DTS example: ``` { model = "xuantie,dummy"; compatible = "xuantie,dummy"; pmc: xuantie_ipmc@26900000 { compatible = "xuantie,pmc"; status = "okay"; reg = <0x00000000 0x26900000 0x00000000 0x00001000>; }; } ``` Signed-off-by: Chen Pei --- platform/generic/Kconfig | 4 + platform/generic/configs/defconfig | 1 + platform/generic/xuantie/objects.mk | 6 + platform/generic/xuantie/xuantie_pmc.c | 215 +++++++++++++++++++++++++ platform/generic/xuantie/xuantie_pmc.h | 52 ++++++ 5 files changed, 278 insertions(+) create mode 100644 platform/generic/xuantie/objects.mk create mode 100644 platform/generic/xuantie/xuantie_pmc.c create mode 100644 platform/generic/xuantie/xuantie_pmc.h diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index a902cf37..1ee758b6 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -65,6 +65,10 @@ config PLATFORM_THEAD select THEAD_C9XX_PMU default n +config PLATFORM_XUANTIE + bool "XuanTie 9xx support" + default n + source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig" source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig" diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 177b8ddb..b04f64c7 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y CONFIG_PLATFORM_SOPHGO_SG2042=y CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_PLATFORM_THEAD=y +CONFIG_PLATFORM_XUANTIE=y CONFIG_FDT_GPIO=y CONFIG_FDT_GPIO_DESIGNWARE=y CONFIG_FDT_GPIO_SIFIVE=y diff --git a/platform/generic/xuantie/objects.mk b/platform/generic/xuantie/objects.mk new file mode 100644 index 00000000..b1686a10 --- /dev/null +++ b/platform/generic/xuantie/objects.mk @@ -0,0 +1,6 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# + +carray-platform_override_modules-$(CONFIG_PLATFORM_XUANTIE) += xuantie_pmc +platform-objs-$(CONFIG_PLATFORM_XUANTIE) += xuantie/xuantie_pmc.o diff --git a/platform/generic/xuantie/xuantie_pmc.c b/platform/generic/xuantie/xuantie_pmc.c new file mode 100644 index 00000000..57180130 --- /dev/null +++ b/platform/generic/xuantie/xuantie_pmc.c @@ -0,0 +1,215 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xuantie_pmc.h" + +static struct xuantie_pmc_data pmc = { 0 }; +static unsigned long zsb_addr = 0; + +static inline void xuantie_riscv_cfg_init(void) +{ + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr(); + + if (!zsb_addr) { + zsb_addr = scratch->next_addr - 0x00008000; + } +} + +static inline int pmc_set_command(struct xuantie_pmc_data *pmc, u32 hartid, u32 blkid, u32 val) +{ + u64 pmc_base, blk_sw_mode_ctl; + + if (pmc) { + pmc_base = pmc->pmc_addr + 0x1000 * hartid; + blk_sw_mode_ctl = 0x100 + 0x4 * blkid; + writel_relaxed(val, (void *)(uintptr_t)(pmc_base + blk_sw_mode_ctl)); + return 0; + } else + return SBI_EINVAL; +} + +static inline void xuantie_hart_poweroff(u32 hartid, bool is_dynamic) +{ + if (is_dynamic) { + /* cpu_idle power down, set trans bit to dynamic mode */ + pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DYNAMIC | PMC_BLK_MODE_CONFIG_OFF); + pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DYNAMIC | PMC_BLK_LOW_POWER_STATE_OFF); + } else { + /* cpu_hotplug power down, set trans bit to direct mode */ + pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_OFF); + pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_OFF); + } + + /* close the prefetch */ + csr_clear(THEAD_C9XX_CSR_MHINT, 0x1 << 2); + + /* clean and invalid core's dcache */ + asm volatile(XUANTIE_DCACHE_INVAL_CLEAN_ALL); + + /* close the dcache */ + csr_clear(THEAD_C9XX_CSR_MHCR, 0x1 << 1); + + /* close the snoop */ + csr_clear(THEAD_C9XX_CSR_MSMPR, 0x1 << 0); + + /* sync.s */ + asm volatile(XUANTIE_SYNC_S); + + wfi(); +} + +static int xuantie_hart_suspend(u32 suspend_type) +{ + u32 hartid = current_hartid(); + + /* Use the generic code for retentive suspend. */ + if (!(suspend_type & SBI_HSM_SUSP_NON_RET_BIT)) + return SBI_ENOTSUPP; + + xuantie_hart_poweroff(hartid, true); + + return 0; +} + +static void xuantie_hart_resume(void) +{ + u32 hartid = current_hartid(); + + pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_ON); + pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_RET); +} + +int xuantie_hart_start(u32 hartid, ulong saddr) +{ + pmc_set_command(&pmc, hartid, PMC_BLK_CORE, PMC_TRANS_MODE_DIRECT | PMC_BLK_MODE_CONFIG_ON); + pmc_set_command(&pmc, hartid, PMC_BLK_CORE_VFPU, PMC_TRANS_MODE_DIRECT | PMC_BLK_LOW_POWER_STATE_RET); + + return 0; +} + +int xuantie_hart_stop(void) +{ + u32 hartid = current_hartid(); + + xuantie_hart_poweroff(hartid, false); + + return 0; +} + +static const struct sbi_hsm_device xuantie_hsm = { + .name = "xuantie-hsm", + .hart_suspend = xuantie_hart_suspend, + .hart_resume = xuantie_hart_resume, + .hart_start = xuantie_hart_start, + .hart_stop = xuantie_hart_stop, +}; + +static int xuantie_system_suspend_check(u32 sleep_type) +{ + return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? 0 : SBI_EINVAL; +} + +static int xuantie_system_suspend(u32 sleep_type, unsigned long mmode_resume_addr) +{ + u32 hartid = current_hartid(); + + if (sleep_type != SBI_SUSP_SLEEP_TYPE_SUSPEND) + return SBI_EINVAL; + + /* cpu poweroff after wfi */ + xuantie_hart_poweroff(hartid, true); + + return 0; +} + +static struct sbi_system_suspend_device xuantie_system_suspend_dev = { + .name = "xuantie-system-suspend", + .system_suspend_check = xuantie_system_suspend_check, + .system_suspend = xuantie_system_suspend, +}; + +static int xuantie_system_reset_check(u32 type, u32 reason) +{ + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + return 1; + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + return 255; + } + + return 0; +} + +static void xuantie_system_reset(u32 type, u32 reason) +{ +} + +static struct sbi_system_reset_device xuantie_reset = { + .name = "xuantie-reset", + .system_reset_check = xuantie_system_reset_check, + .system_reset = xuantie_system_reset +}; + +static int xuantie_pmc_test_device_init(void) +{ + int nodeoffset, rc; + void *fdt = fdt_get_address(); + + nodeoffset = fdt_node_offset_by_compatible(fdt, -1, "xuantie,pmc"); + if (nodeoffset < 0) + return nodeoffset; + + rc = fdt_get_node_addr_size(fdt, nodeoffset, 0, (uint64_t *)&pmc.pmc_addr, NULL); + if (rc) + return SBI_ENODEV; + + if (!fdt_node_is_enabled(fdt, nodeoffset)) + return SBI_ENODEV; + + sbi_system_reset_add_device(&xuantie_reset); + sbi_hsm_set_device(&xuantie_hsm); + sbi_system_suspend_set_device(&xuantie_system_suspend_dev); + + return 0; +} + +static int xuantie_final_init(bool cold_boot, const struct fdt_match *match) +{ + if (cold_boot) { + xuantie_riscv_cfg_init(); + xuantie_pmc_test_device_init(); + } + + return 0; +} + +static const struct fdt_match xuantie_pmc_match[] = { + { .compatible = "xuantie,dummy" }, + { }, +}; + +const struct platform_override xuantie_pmc = { + .match_table = xuantie_pmc_match, + .final_init = xuantie_final_init, +}; diff --git a/platform/generic/xuantie/xuantie_pmc.h b/platform/generic/xuantie/xuantie_pmc.h new file mode 100644 index 00000000..40ba0072 --- /dev/null +++ b/platform/generic/xuantie/xuantie_pmc.h @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __XUANTIE_PMC_H__ +#define __XUANTIE_PMC_H__ + +#include + +/* clang-format off */ + +#define XUANTIE_DCACHE_INVAL_CLEAN_ALL ".long 0x0030000b" +#define XUANTIE_SYNC_S ".long 0x0190000b" + +/* + core PMC: blk1 = VFPU; blk2 = MPU + cluster PMC: blk1 = l2cache + */ +#define PMC_BLK_CORE 0 +#define PMC_BLK_CORE_VFPU 1 +#define PMC_BLK_CORE_MPU 2 +#define PMC_BLK_CLUSTER 0 +#define PMC_BLK_CLUSTER_L2 1 + +#define PMC_TRANS_MODE_SHIFT 4 +#define PMC_TRANS_MODE_DIRECT (_UL(1) << PMC_TRANS_MODE_SHIFT) +#define PMC_TRANS_MODE_DYNAMIC (_UL(0) << PMC_TRANS_MODE_SHIFT) +/*pmc_blk_mode_config (basic type)*/ +#define PMC_BLK_MODE_CONFIG_0 0 // OFF pstate enable +#define PMC_BLK_MODE_CONFIG_1 1 +#define PMC_BLK_MODE_CONFIG_2 2 +#define PMC_BLK_MODE_CONFIG_3 3 +#define PMC_BLK_MODE_CONFIG_4 4 +#define PMC_BLK_MODE_CONFIG_5 5 +#define PMC_BLK_MODE_CONFIG_6 6 +#define PMC_BLK_MODE_CONFIG_7 7 +#define PMC_BLK_MODE_CONFIG_8 8 // ON pstate enable +#define PMC_BLK_MODE_CONFIG_9 9 +#define PMC_BLK_MODE_CONFIG_ON PMC_BLK_MODE_CONFIG_8 +#define PMC_BLK_MODE_CONFIG_OFF PMC_BLK_MODE_CONFIG_0 +/*pmc_blk_mode_config (pe type)*/ +#define PMC_BLK_LOW_POWER_STATE_OFF 0 +#define PMC_BLK_LOW_POWER_STATE_RET 1 + + +/* clang-format on */ + +struct xuantie_pmc_data { + unsigned long pmc_addr; +}; + +#endif /* __XUANTIE_PMC_H__ */