From a27b4d7e4f6247a1a1364e0a23681e2a0b1d39bc Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:14:52 +0800 Subject: [PATCH 01/18] add force_emulate_time_csr --- include/sbi/riscv_encoding.h | 2 ++ include/sbi/sbi_platform.h | 17 +++++++++++++++ lib/sbi/sbi_hart.c | 8 ++++++- lib/sbi/sbi_pmu.c | 3 +++ platform/generic/sophgo/sg2042.c | 36 +++++++++++++++++++++++++++++--- 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index b5a4ce816be..9dbecd98cd1 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -732,6 +732,8 @@ /* Counter Overflow CSR */ #define CSR_SCOUNTOVF 0xda0 +#define MCOUNTEREN_TM (_UL(1) << 1) + /* Debug/Trace Registers */ #define CSR_TSELECT 0x7a0 #define CSR_TDATA1 0x7a1 diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index e65d9877dfc..7593b027fc3 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -76,6 +76,9 @@ struct sbi_platform_operations { /* Check if specified HART is allowed to do cold boot */ bool (*cold_boot_allowed)(u32 hartid); + /* Check if platform force emulate time csr, instead of using csr directly */ + bool (*force_emulate_time_csr)(void); + /* Check if platform requires single firmware region */ bool (*single_fw_region)(void); @@ -350,6 +353,20 @@ static inline bool sbi_platform_cold_boot_allowed( return true; } +/** + * Check whether given platform should force emulate time CSR + * + * @param plat pointer to struct sbi_platform + * + * @return true such platform force emulate time CSR, false otherwise + */ +static inline bool sbi_platform_force_emulate_time_csr(const struct sbi_platform *plat) +{ + if (plat && sbi_platform_ops(plat)->force_emulate_time_csr) + return sbi_platform_ops(plat)->force_emulate_time_csr(); + return false; +} + /** * Check whether platform requires single firmware region * diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 60e95bca3a8..faf9abdb03d 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -60,6 +60,11 @@ static void mstatus_init(struct sbi_scratch *scratch) if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) csr_write(CSR_MCOUNTEREN, -1); + if (sbi_platform_force_emulate_time_csr(sbi_platform_thishart_ptr())) { + csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM); + csr_clear(CSR_SCOUNTEREN, MCOUNTEREN_TM); + } + /* All programmable counters will start running at runtime after S-mode request */ if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_11) csr_write(CSR_MCOUNTINHIBIT, 0xFFFFFFF8); @@ -670,7 +675,8 @@ static int hart_detect_features(struct sbi_scratch *scratch) __set_bit(__csr_id, hfeatures->csrs); __check_csr_existence(CSR_CYCLE, SBI_HART_CSR_CYCLE); - __check_csr_existence(CSR_TIME, SBI_HART_CSR_TIME); + if (!sbi_platform_force_emulate_time_csr(sbi_platform_thishart_ptr())) + __check_csr_existence(CSR_TIME, SBI_HART_CSR_TIME); __check_csr_existence(CSR_INSTRET, SBI_HART_CSR_INSTRET); #undef __check_csr_existence diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index e084005d11f..db4a8d52bc8 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -1135,6 +1135,9 @@ void sbi_pmu_exit(struct sbi_scratch *scratch) if (sbi_hart_priv_version(scratch) >= SBI_HART_PRIV_VER_1_10) csr_write(CSR_MCOUNTEREN, -1); + if (sbi_platform_force_emulate_time_csr(sbi_platform_thishart_ptr())) + csr_clear(CSR_MCOUNTEREN, MCOUNTEREN_TM); + if (unlikely(!phs)) return; diff --git a/platform/generic/sophgo/sg2042.c b/platform/generic/sophgo/sg2042.c index c2447c3c2df..7def95b5f76 100644 --- a/platform/generic/sophgo/sg2042.c +++ b/platform/generic/sophgo/sg2042.c @@ -5,7 +5,7 @@ * Inochi Amaoto * */ - +#include #include #include #include @@ -19,7 +19,18 @@ #define SOPHGO_SG2042_TIMER_BASE 0x70ac000000ULL #define SOPHGO_SG2042_TIMER_SIZE 0x10000UL -#define SOPHGO_SG2042_TIMER_NUM 16 + +extern struct sbi_platform platform; +static u32 selected_hartid = -1; +static bool force_emulate_time_csr; + +static bool mango_cold_boot_allowed(u32 hartid) +{ + if (selected_hartid != -1) + return (selected_hartid == hartid); + + return (hartid < 64); +} static int sophgo_sg2042_early_init(bool cold_boot) { @@ -39,7 +50,7 @@ static int sophgo_sg2042_early_init(bool cold_boot) return sbi_domain_root_add_memrange( (ulong)SOPHGO_SG2042_TIMER_BASE, SOPHGO_SG2042_TIMER_SIZE * - SOPHGO_SG2042_TIMER_NUM, + sbi_platform_hart_count(&platform), MTIMER_REGION_ALIGN, (SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_M_READABLE | @@ -58,17 +69,36 @@ static int sophgo_sg2042_extensions_init(struct sbi_hart_features *hfeatures) return rc; thead_c9xx_register_pmu_device(); + hfeatures->mhpm_mask = 0x0003e3f8; + hfeatures->mhpm_bits = 64; + return 0; } +static bool mango_force_emulate_time_csr(void) +{ + return force_emulate_time_csr; +} + static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { + if (platform.hart_stack_size < 16384) + platform.hart_stack_size = 16384; + + if (fdt_node_offset_by_compatible(fdt, 0, "sophgo,sg2042-global-mtimer") > 0) + force_emulate_time_csr = true; + else + force_emulate_time_csr = false; + generic_platform_ops.early_init = sophgo_sg2042_early_init; generic_platform_ops.extensions_init = sophgo_sg2042_extensions_init; + generic_platform_ops.cold_boot_allowed = mango_cold_boot_allowed; + generic_platform_ops.force_emulate_time_csr = mango_force_emulate_time_csr; return 0; } + static const struct fdt_match sophgo_sg2042_match[] = { { .compatible = "sophgo,sg2042" }, { }, From c8fee0e606b57faac8668da66997d623b9856ee5 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:25:51 +0800 Subject: [PATCH 02/18] mtime add use_extern_domain --- include/sbi_utils/timer/aclint_mtimer.h | 1 + lib/utils/ipi/fdt_ipi_mswi.c | 1 + lib/utils/timer/aclint_mtimer.c | 2 +- lib/utils/timer/fdt_timer_mtimer.c | 10 ++++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/sbi_utils/timer/aclint_mtimer.h b/include/sbi_utils/timer/aclint_mtimer.h index f8d2e5b4c21..f34c5950445 100644 --- a/include/sbi_utils/timer/aclint_mtimer.h +++ b/include/sbi_utils/timer/aclint_mtimer.h @@ -35,6 +35,7 @@ struct aclint_mtimer_data { u32 hart_count; bool has_64bit_mmio; bool has_shared_mtime; + bool use_extern_domain; /* Private details (initialized and used by ACLINT MTIMER library) */ struct aclint_mtimer_data *time_delta_reference; unsigned long time_delta_computed; diff --git a/lib/utils/ipi/fdt_ipi_mswi.c b/lib/utils/ipi/fdt_ipi_mswi.c index 6d8f6bf3af2..df435497419 100644 --- a/lib/utils/ipi/fdt_ipi_mswi.c +++ b/lib/utils/ipi/fdt_ipi_mswi.c @@ -56,6 +56,7 @@ static const struct fdt_match ipi_mswi_match[] = { { .compatible = "riscv,clint0", .data = &clint_offset }, { .compatible = "sifive,clint0", .data = &clint_offset }, { .compatible = "thead,c900-clint", .data = &clint_offset }, + { .compatible = "thead,c900-clint-mswi", .data = &clint_offset }, { .compatible = "thead,c900-aclint-mswi" }, { .compatible = "mips,p8700-aclint-mswi" }, { .compatible = "riscv,aclint-mswi" }, diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c index fd6189aaa52..854584fc7a7 100644 --- a/lib/utils/timer/aclint_mtimer.c +++ b/lib/utils/timer/aclint_mtimer.c @@ -255,7 +255,7 @@ int aclint_mtimer_cold_init(struct aclint_mtimer_data *mt, SBI_DOMAIN_MEMREGION_M_WRITABLE)); if (rc) return rc; - } else { + } else if (!mt->use_extern_domain) { rc = sbi_domain_root_add_memrange(mt->mtime_addr, mt->mtime_size, MTIMER_REGION_ALIGN, (SBI_DOMAIN_MEMREGION_MMIO | diff --git a/lib/utils/timer/fdt_timer_mtimer.c b/lib/utils/timer/fdt_timer_mtimer.c index d5520fad936..77cbe7bc048 100644 --- a/lib/utils/timer/fdt_timer_mtimer.c +++ b/lib/utils/timer/fdt_timer_mtimer.c @@ -20,6 +20,7 @@ struct timer_mtimer_quirks { unsigned int clint_mtime_offset; bool clint_without_mtime; bool has_64bit_mmio; + bool use_extern_domain; }; struct timer_mtimer_node { @@ -87,6 +88,7 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff, /* Apply additional quirks */ if (quirks) { mt->has_64bit_mmio = quirks->has_64bit_mmio; + mt->use_extern_domain = quirks->use_extern_domain; } /* Check if MTIMER device has shared MTIME address */ @@ -156,12 +158,20 @@ static const struct timer_mtimer_quirks thead_aclint_quirks = { .has_64bit_mmio = false, }; +static const struct timer_mtimer_quirks thead_clint_sep_quirks = { + .clint_mtime_offset = CLINT_MTIMER_OFFSET, + .clint_without_mtime = true, + .use_extern_domain = true, +}; + static const struct fdt_match timer_mtimer_match[] = { { .compatible = "mips,p8700-aclint-mtimer" }, { .compatible = "riscv,clint0", .data = &sifive_clint_quirks }, { .compatible = "sifive,clint0", .data = &sifive_clint_quirks }, { .compatible = "sifive,clint2", .data = &sifive_clint_quirks }, { .compatible = "thead,c900-clint", .data = &thead_clint_quirks }, + { .compatible = "thead,c900-clint-mtimer", + .data = &thead_clint_sep_quirks }, { .compatible = "thead,c900-aclint-mtimer", .data = &thead_aclint_quirks }, { .compatible = "riscv,aclint-mtimer" }, From c898ab4ddbb3c3c9098999966cc7b6c5506adfc0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:41:03 +0800 Subject: [PATCH 03/18] lib:utils:add sophgo-mcu, power management device --- lib/utils/reset/Kconfig | 5 + lib/utils/reset/fdt_reset_sophgo_mcu.c | 154 +++++++++++++++++++++++++ lib/utils/reset/objects.mk | 3 + platform/generic/configs/defconfig | 1 + 4 files changed, 163 insertions(+) create mode 100644 lib/utils/reset/fdt_reset_sophgo_mcu.c diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig index 68e667163b5..7619bc6849e 100644 --- a/lib/utils/reset/Kconfig +++ b/lib/utils/reset/Kconfig @@ -33,6 +33,11 @@ config FDT_RESET_SG2042_HWMON_MCU bool "Sophgo SG2042 hwmon MCU FDT reset driver" default n +config FDT_RESET_SOPHGO_MCU + bool "Sophgo MCU FDT reset driver" + select SYS_SOPHGO_MCU + default n + config FDT_RESET_SUNXI_WDT bool "Sunxi WDT FDT reset driver" default n diff --git a/lib/utils/reset/fdt_reset_sophgo_mcu.c b/lib/utils/reset/fdt_reset_sophgo_mcu.c new file mode 100644 index 00000000000..dc10bda2504 --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_mcu.c @@ -0,0 +1,154 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Lin Chunzhi + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MANGO_BOARD_TYPE 0x80 + +#define REG_MCU_BOARD_TYPE 0x00 +#define REG_MCU_CMD 0x03 + +#define CMD_POWEROFF 0x02 +#define CMD_RESET 0x03 +#define CMD_REBOOT 0x07 + +static struct { + struct i2c_adapter *adapter; + uint32_t reg; +} mango; + +static int mango_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 inline int mango_sanity_check(struct i2c_adapter *adap, uint32_t reg) +{ + static uint8_t val; + int ret; + + /* check board type*/ + ret = i2c_adapter_reg_read(adap, reg, REG_MCU_BOARD_TYPE, &val); + if (ret) + return ret; + + if (val != MANGO_BOARD_TYPE) + return SBI_ENODEV; + + return 0; +} + +static inline int mango_shutdown(struct i2c_adapter *adap, uint32_t reg) +{ + int ret; + ret = i2c_adapter_reg_write(adap, reg, REG_MCU_CMD, CMD_POWEROFF); + + if (ret) + return ret; + + return 0; +} + +static inline int mango_reset(struct i2c_adapter *adap, uint32_t reg) +{ + int ret; + ret = i2c_adapter_reg_write(adap, reg, REG_MCU_CMD, CMD_REBOOT); + + if (ret) + return ret; + + return 0; +} + +static void mango_system_reset(u32 type, u32 reason) +{ + struct i2c_adapter *adap = mango.adapter; + uint32_t reg = mango.reg; + int ret; + if (adap) { + /* sanity check */ + ret = mango_sanity_check(adap, reg); + if (ret) { + sbi_printf("%s: chip is not mango\n", __func__); + goto skip_reset; + } + + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + mango_shutdown(adap, reg); + break; + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + mango_reset(adap, reg); + break; + } + } + +skip_reset: + sbi_hart_hang(); +} + +static struct sbi_system_reset_device mango_reset_i2c = { + .name = "mango-reset", + .system_reset_check = mango_system_reset_check, + .system_reset = mango_system_reset +}; + +static int mango_reset_init(const void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc, i2c_bus; + struct i2c_adapter *adapter; + uint64_t addr; + + /* we are mango,mcu node */ + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL); + if (rc) + return rc; + + mango.reg = addr; + + /* find i2c bus parent node */ + i2c_bus = fdt_parent_offset(fdt, nodeoff); + if (i2c_bus < 0) + return i2c_bus; + + /* i2c adapter get */ + rc = fdt_i2c_adapter_get(fdt, i2c_bus, &adapter); + if (rc) + return rc; + + mango.adapter = adapter; + + sbi_system_reset_add_device(&mango_reset_i2c); + + return 0; +} + +static const struct fdt_match mango_reset_match[] = { + { .compatible = "mango,reset", .data = (void *)true}, + { }, +}; + +const struct fdt_driver fdt_reset_sophgo_mcu = { + .match_table = mango_reset_match, + .init = mango_reset_init, +}; diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk index ac38b49df05..209bece48f9 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -29,3 +29,6 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_SYSCON) += reset/fdt_reset_syscon.o carray-fdt_early_drivers-$(CONFIG_FDT_RESET_RPMI) += fdt_reset_rpmi libsbiutils-objs-$(CONFIG_FDT_RESET_RPMI) += reset/fdt_reset_rpmi.o + +carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_MCU) += fdt_reset_sophgo_mcu +libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_MCU) += reset/fdt_reset_sophgo_mcu.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index aab1560f239..60de801e69e 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -48,6 +48,7 @@ CONFIG_FDT_RESET_RPMI=y CONFIG_FDT_RESET_SG2042_HWMON_MCU=y CONFIG_FDT_RESET_SUNXI_WDT=y CONFIG_FDT_RESET_SYSCON=y +CONFIG_FDT_RESET_SOPHGO_MCU=y CONFIG_FDT_SERIAL=y CONFIG_FDT_SERIAL_CADENCE=y CONFIG_FDT_SERIAL_GAISLER=y From 6d0209c3a310051de5c1d8f78a16244db602fe60 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:51:12 +0800 Subject: [PATCH 04/18] lib: sbi_trap: Workaroud for cpu still using i-utlb when into m mode --- firmware/fw_base.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index bce9e226842..fc27f2545ff 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -647,6 +647,8 @@ memcmp: .align 3 .globl _trap_handler _trap_handler: + sfence.vma zero, t0 + TRAP_SAVE_AND_SETUP_SP_T0 TRAP_SAVE_MEPC_MSTATUS 0 From 45a1e7dfdb96fb901f23298f16f6433b94233983 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:53:55 +0800 Subject: [PATCH 05/18] lib:utils:delete mango-reset device node after register it --- lib/utils/reset/fdt_reset_sophgo_mcu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/reset/fdt_reset_sophgo_mcu.c b/lib/utils/reset/fdt_reset_sophgo_mcu.c index dc10bda2504..ae28c90eafa 100644 --- a/lib/utils/reset/fdt_reset_sophgo_mcu.c +++ b/lib/utils/reset/fdt_reset_sophgo_mcu.c @@ -139,6 +139,7 @@ static int mango_reset_init(const void *fdt, int nodeoff, mango.adapter = adapter; sbi_system_reset_add_device(&mango_reset_i2c); + fdt_del_node(fdt, nodeoff); return 0; } From f6725809e81656a162a6bac8c55f09d2244d8d54 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:55:39 +0800 Subject: [PATCH 06/18] util:reset:mango-reset device support to X4 and milkv --- lib/utils/reset/fdt_reset_sophgo_mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/reset/fdt_reset_sophgo_mcu.c b/lib/utils/reset/fdt_reset_sophgo_mcu.c index ae28c90eafa..06862af19a1 100644 --- a/lib/utils/reset/fdt_reset_sophgo_mcu.c +++ b/lib/utils/reset/fdt_reset_sophgo_mcu.c @@ -16,6 +16,7 @@ #define MANGO_BOARD_TYPE 0x80 #define REG_MCU_BOARD_TYPE 0x00 +#define MANGO_BOARD_TYPE_MASK 1 << 7 #define REG_MCU_CMD 0x03 #define CMD_POWEROFF 0x02 @@ -50,7 +51,7 @@ static inline int mango_sanity_check(struct i2c_adapter *adap, uint32_t reg) if (ret) return ret; - if (val != MANGO_BOARD_TYPE) + if ((val & MANGO_BOARD_TYPE_MASK) != MANGO_BOARD_TYPE) return SBI_ENODEV; return 0; @@ -139,7 +140,6 @@ static int mango_reset_init(const void *fdt, int nodeoff, mango.adapter = adapter; sbi_system_reset_add_device(&mango_reset_i2c); - fdt_del_node(fdt, nodeoff); return 0; } From a6a17aa73e082d61375966bb644811b807f59069 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 20:57:56 +0800 Subject: [PATCH 07/18] barrier: add more stronger constraint --- include/sbi/riscv_barrier.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h index 3d4a038c95e..7d2d8bb525e 100644 --- a/include/sbi/riscv_barrier.h +++ b/include/sbi/riscv_barrier.h @@ -25,19 +25,19 @@ #define mb() RISCV_FENCE(iorw,iorw) /* Read Memory barrier */ -#define rmb() RISCV_FENCE(ir,ir) +#define rmb() RISCV_FENCE(ir,iorw) /* Write Memory barrier */ -#define wmb() RISCV_FENCE(ow,ow) +#define wmb() RISCV_FENCE(iorw,ow) /* SMP Read & Write Memory barrier */ #define smp_mb() RISCV_FENCE(rw,rw) /* SMP Read Memory barrier */ -#define smp_rmb() RISCV_FENCE(r,r) +#define smp_rmb() RISCV_FENCE(r,rw) /* SMP Write Memory barrier */ -#define smp_wmb() RISCV_FENCE(w,w) +#define smp_wmb() RISCV_FENCE(rw,w) /* CPU relax for busy loop */ #define cpu_relax() \ From 2a6f692c8847f37548d0d1b39d2a74f2652a83f0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 21:02:27 +0800 Subject: [PATCH 08/18] set tlb fifo entry number to 128 --- platform/generic/sophgo/sg2042.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platform/generic/sophgo/sg2042.c b/platform/generic/sophgo/sg2042.c index 7def95b5f76..e96a8659ede 100644 --- a/platform/generic/sophgo/sg2042.c +++ b/platform/generic/sophgo/sg2042.c @@ -80,6 +80,11 @@ static bool mango_force_emulate_time_csr(void) return force_emulate_time_csr; } +static u32 mango_tlb_num_entries(void) +{ + return 128; +} + static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { if (platform.hart_stack_size < 16384) @@ -94,6 +99,7 @@ static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struc generic_platform_ops.extensions_init = sophgo_sg2042_extensions_init; generic_platform_ops.cold_boot_allowed = mango_cold_boot_allowed; generic_platform_ops.force_emulate_time_csr = mango_force_emulate_time_csr; + generic_platform_ops.get_tlb_num_entries = mango_tlb_num_entries; return 0; } From ce2f67db9fd141c9d20e3501ea5dfbf11f2bf132 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 21:05:49 +0800 Subject: [PATCH 09/18] Fix system cannot boot when the some CPU status is set to disabled --- firmware/fw_base.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/fw_base.S b/firmware/fw_base.S index fc27f2545ff..606ea569246 100644 --- a/firmware/fw_base.S +++ b/firmware/fw_base.S @@ -349,7 +349,7 @@ _start_warm: add a4, a4, 1 blt a4, s7, 1b 2: add s6, a4, zero -3: bge s6, s7, _start_hang +3: bgeu s6, s7, _start_hang /* Find the scratch space based on HART index */ lla tp, _fw_end From c46b633765b2f81e45844199a6687478a43f3f12 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 21:40:44 +0800 Subject: [PATCH 10/18] lib:utils:add reset and gpio device --- lib/utils/gpio/Kconfig | 4 + lib/utils/gpio/fdt_gpio_sophgo.c | 140 ++++++++++++++++++++++++ lib/utils/gpio/objects.mk | 3 + lib/utils/reset/Kconfig | 10 ++ lib/utils/reset/fdt_reset_sophgo_cpld.c | 123 +++++++++++++++++++++ lib/utils/reset/fdt_reset_sophgo_wdt.c | 122 +++++++++++++++++++++ lib/utils/reset/objects.mk | 6 + platform/generic/configs/defconfig | 3 + 8 files changed, 411 insertions(+) create mode 100644 lib/utils/gpio/fdt_gpio_sophgo.c create mode 100644 lib/utils/reset/fdt_reset_sophgo_cpld.c create mode 100644 lib/utils/reset/fdt_reset_sophgo_wdt.c diff --git a/lib/utils/gpio/Kconfig b/lib/utils/gpio/Kconfig index 1a437e67d97..ac8a4f2b6df 100644 --- a/lib/utils/gpio/Kconfig +++ b/lib/utils/gpio/Kconfig @@ -18,6 +18,10 @@ config FDT_GPIO_SIFIVE bool "SiFive GPIO FDT driver" default n +config FDT_GPIO_SOPHGO + bool "Sophgo GPIO FDT driver" + default n + config FDT_GPIO_STARFIVE bool "StarFive GPIO FDT driver" default n diff --git a/lib/utils/gpio/fdt_gpio_sophgo.c b/lib/utils/gpio/fdt_gpio_sophgo.c new file mode 100644 index 00000000000..9693b726713 --- /dev/null +++ b/lib/utils/gpio/fdt_gpio_sophgo.c @@ -0,0 +1,140 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Author: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include + +#define SOPHGO_GPIO_CHIP_MAX 3 + +#define SOPHGO_GPIO_PINS_MIN 0 +#define SOPHGO_GPIO_PINS_MAX 31 +#define SOPHGO_GPIO_PINS_DEF 16 + +#define SOPHGO_GPIO_SWPORTA_DR_OFFSET 0x00 +#define SOPHGO_GPIO_SWPORTA_DDR_OFFSET 0x04 +#define SOPHGO_GPIO_SWPORTA_CTL_OFFSET 0x08 + +#define SOPHGO_GPIO_BIT(offset) (1U << (offset)) + +struct sophgo_gpio_chip { + unsigned long addr; + struct gpio_chip chip; +}; + +static unsigned int sophgo_gpio_chip_count; +static struct sophgo_gpio_chip sophgo_gpio_chip_array[SOPHGO_GPIO_CHIP_MAX]; + +static int sophgo_gpio_direction_output(struct gpio_pin *gp, int value) +{ + unsigned int v; + struct sophgo_gpio_chip *chip = + container_of(gp->chip, struct sophgo_gpio_chip, chip); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + v |= SOPHGO_GPIO_BIT(gp->offset); + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + if (!value) + v &= ~SOPHGO_GPIO_BIT(gp->offset); + else + v |= SOPHGO_GPIO_BIT(gp->offset); + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + return 0; +} + +static void sophgo_gpio_set(struct gpio_pin *gp, int value) +{ + unsigned int v; + struct sophgo_gpio_chip *chip = + container_of(gp->chip, struct sophgo_gpio_chip, chip); + + v = readl((volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + if (!value) + v &= ~SOPHGO_GPIO_BIT(gp->offset); + else + v |= SOPHGO_GPIO_BIT(gp->offset); + + writel(v, (volatile void *)(chip->addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + + return; +} + +static int sophgo_gpio_addr_get(const void *fdt, int nodeoff, unsigned long *addr) +{ + int rc; + unsigned long addr_high, addr_low; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 1, &addr_low, NULL); + if (rc) + return rc; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr_high, NULL); + if (rc) + return rc; + + *addr = addr_high << 32 | addr_low; + + return 0; +} + +extern const struct fdt_gpio fdt_gpio_sophgo; + +static int sophgo_gpio_init(const void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc; + struct sophgo_gpio_chip *chip; + unsigned long addr; + + if (SOPHGO_GPIO_CHIP_MAX <= sophgo_gpio_chip_count) { + rc = SBI_ENOSPC; + return rc; + } + + chip = &sophgo_gpio_chip_array[sophgo_gpio_chip_count]; + + rc = sophgo_gpio_addr_get(fdt, nodeoff, &addr); + if (rc) + return rc; + + chip->addr = addr; + chip->chip.driver = &fdt_gpio_sophgo; + chip->chip.id = nodeoff; + chip->chip.ngpio = SOPHGO_GPIO_PINS_MAX; + chip->chip.direction_output = sophgo_gpio_direction_output; + chip->chip.set = sophgo_gpio_set; + rc = gpio_chip_add(&chip->chip); + + if (rc) + return rc; + + sophgo_gpio_chip_count++; + + return 0; +} + +static const struct fdt_match sophgo_gpio_match[] = { + { .compatible = "sophgo,gpio0" }, + { }, +}; + +const struct fdt_gpio fdt_gpio_sophgo = { + .driver = { + .match_table = sophgo_gpio_match, + .init = sophgo_gpio_init, + }, + .xlate = fdt_gpio_simple_xlate, +}; diff --git a/lib/utils/gpio/objects.mk b/lib/utils/gpio/objects.mk index 521068388db..fdd5ea051d5 100644 --- a/lib/utils/gpio/objects.mk +++ b/lib/utils/gpio/objects.mk @@ -16,6 +16,9 @@ libsbiutils-objs-$(CONFIG_FDT_GPIO_DESIGNWARE) += gpio/fdt_gpio_designware.o carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SIFIVE) += fdt_gpio_sifive libsbiutils-objs-$(CONFIG_FDT_GPIO_SIFIVE) += gpio/fdt_gpio_sifive.o +carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_SOPHGO) += fdt_gpio_sophgo +libsbiutils-objs-$(CONFIG_FDT_GPIO_SOPHGO) += gpio/fdt_gpio_sophgo.o + carray-fdt_gpio_drivers-$(CONFIG_FDT_GPIO_STARFIVE) += fdt_gpio_starfive libsbiutils-objs-$(CONFIG_FDT_GPIO_STARFIVE) += gpio/fdt_gpio_starfive.o diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig index 7619bc6849e..f937078e566 100644 --- a/lib/utils/reset/Kconfig +++ b/lib/utils/reset/Kconfig @@ -33,11 +33,21 @@ config FDT_RESET_SG2042_HWMON_MCU bool "Sophgo SG2042 hwmon MCU FDT reset driver" default n +config FDT_RESET_SOPHGO_CPLD + bool "Sophgo CPLD FDT reset driver" + select SYS_SOPHGO_CPLD + default n + config FDT_RESET_SOPHGO_MCU bool "Sophgo MCU FDT reset driver" select SYS_SOPHGO_MCU default n +config FDT_RESET_SOPHGO_WDT + bool "Sophgo WDT FDT reset driver" + select SYS_SOPHGO_WDT + default n + config FDT_RESET_SUNXI_WDT bool "Sunxi WDT FDT reset driver" default n diff --git a/lib/utils/reset/fdt_reset_sophgo_cpld.c b/lib/utils/reset/fdt_reset_sophgo_cpld.c new file mode 100644 index 00000000000..8889b0cb71e --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_cpld.c @@ -0,0 +1,123 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Authors: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cpld_reset { + struct gpio_pin pin; + u32 active_delay; + u32 inactive_delay; +}; + +static struct cpld_reset poweroff = { + .active_delay = 300, + .inactive_delay = 300 +}; + +static struct cpld_reset *cpld_reset_get(u32 type) +{ + struct cpld_reset *reset = NULL; + + switch (type) { + case SBI_SRST_RESET_TYPE_SHUTDOWN: + reset = &poweroff; + break; + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + break; + } + + if (reset && !reset->pin.chip) + reset = NULL; + + return reset; +} + +static void cpld_reset_exec(struct cpld_reset *reset) +{ + if (reset) { + /* drive it active, also inactive->active edge */ + gpio_direction_output(&reset->pin, 1); + sbi_timer_mdelay(reset->active_delay); + + /* drive inactive, also active->inactive edge */ + gpio_set(&reset->pin, 0); + sbi_timer_mdelay(reset->inactive_delay); + } + /* hang !!! */ + sbi_hart_hang(); +} + +static int cpld_system_poweroff_check(u32 type, u32 reason) +{ + if (cpld_reset_get(type)) + return 128; + + return 0; +} + +static void cpld_system_poweroff(u32 type, u32 reason) +{ + cpld_reset_exec(cpld_reset_get(type)); +} + +static struct sbi_system_reset_device mango_reset_gpio = { + .name = "mango-cpld", + .system_reset_check = cpld_system_poweroff_check, + .system_reset = cpld_system_poweroff +}; + +static int mango_cpld_reset_init(const void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int rc, len; + const fdt32_t *val; + struct cpld_reset *reset = &poweroff; + const char *dir_prop = "output"; + + rc = fdt_gpio_pin_get(fdt, nodeoff, 0, &reset->pin); + if (rc) + return rc; + + if (fdt_getprop(fdt, nodeoff, dir_prop, &len)) { + rc = gpio_direction_output(&reset->pin, 0); + if (rc) + return rc; + } + + val = fdt_getprop(fdt, nodeoff, "active-delay-ms", &len); + if (len > 0) + reset->active_delay = fdt32_to_cpu(*val); + + val = fdt_getprop(fdt, nodeoff, "inactive-delay-ms", &len); + if (len > 0) + reset->inactive_delay = fdt32_to_cpu(*val); + + sbi_system_reset_add_device(&mango_reset_gpio); + + return rc; +} + +static const struct fdt_match mango_cpld_reset_match[] = { + { .compatible = "mango,cpld-reset", .data = (void *)true}, + { }, +}; + +const struct fdt_driver fdt_reset_sophgo_cpld = { + .match_table = mango_cpld_reset_match, + .init = mango_cpld_reset_init, +}; diff --git a/lib/utils/reset/fdt_reset_sophgo_wdt.c b/lib/utils/reset/fdt_reset_sophgo_wdt.c new file mode 100644 index 00000000000..f15c0e9b6bf --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_wdt.c @@ -0,0 +1,122 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Sophgo + * + * Authors: + * Chunzhi Lin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TOP_BASE 0x7030010000 +#define SOPHGO_TOP_CTRL_REG_OFFSET 0x008 + +#define REG_BIT(offset) (1U << (offset)) +#define BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN REG_BIT(2) + +#define SOPHGO_WDT_CR_REG_OFFSET 0x00 +#define SOPHGO_WDT_TORR_REG_OFFSET 0x04 +#define SOPHGO_WDT_CRR_REG_OFFSET 0x0C + +static volatile char *sophgo_wdt_base; +static volatile char *sophgo_top_base; + +static void sophgo_wdt_system_reset(u32 type, u32 reason) +{ + u32 val; + + val = readl(sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET); + writel((val | BIT_MASK_TOP_CTRL_SW_ROOT_RESET_EN), + sophgo_top_base + SOPHGO_TOP_CTRL_REG_OFFSET); + sbi_timer_udelay(1); + + /*next reset time = 2^(16 + 0x0b) / 100M = 1.34s */ + writel(0x0b, sophgo_wdt_base + SOPHGO_WDT_TORR_REG_OFFSET); + sbi_timer_udelay(1); + + /* a safety feature for counter restart register */ + writel(0x76, sophgo_wdt_base + SOPHGO_WDT_CRR_REG_OFFSET); + sbi_timer_udelay(1); + + /* reset pluse length: 32 pclk cycles; enable wdt */ + writel(0x11, sophgo_wdt_base + SOPHGO_WDT_CR_REG_OFFSET); + + return; +} + +static int sophgo_wdt_system_reset_check(u32 type, u32 reason) +{ + switch (type) { + case SBI_SRST_RESET_TYPE_COLD_REBOOT: + case SBI_SRST_RESET_TYPE_WARM_REBOOT: + return 1; + } + + return 0; +} + +static int sophgo_wdt_system_get_top_base(const void *fdt, + int nodeoff, unsigned long *addr) +{ + const fdt32_t *val; + int len, noff; + + val = fdt_getprop(fdt, nodeoff, "subctrl-syscon", &len); + if (val || len >= sizeof(fdt32_t)) { + noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*val)); + if (noff < 0) + return noff; + return fdt_get_node_addr_size(fdt, noff, 0, addr, NULL); + } + return SBI_ENODEV; +} + +static struct sbi_system_reset_device mango_reset_wdt = { + .name = "mango-wdt", + .system_reset_check = sophgo_wdt_system_reset_check, + .system_reset = sophgo_wdt_system_reset, +}; + +static int mango_wdt_reset_init(const void *fdt, int nodeoff, + const struct fdt_match *match) +{ + unsigned long wdt_addr, top_addr; + int rc; + // struct device_node *np; + + rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &wdt_addr, NULL); + if (rc < 0 || !wdt_addr) { + return SBI_ENODEV; + } + + sophgo_wdt_base = (volatile char *)(unsigned long)wdt_addr; + + rc = sophgo_wdt_system_get_top_base(fdt, nodeoff, &top_addr); + if (rc < 0 || !top_addr) + return SBI_ENODEV; + + sophgo_top_base = (volatile char *)(unsigned long)top_addr; + + sbi_system_reset_add_device(&mango_reset_wdt); + + return 0; +} + +static const struct fdt_match mango_wdt_reset_match[] = { + { .compatible = "mango,wdt-reset", .data = (void *)true}, + { }, +}; + +const struct fdt_driver fdt_reset_sophgo_wdt = { + .match_table = mango_wdt_reset_match, + .init = mango_wdt_reset_init, +}; diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk index 209bece48f9..a8f0340e91e 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -32,3 +32,9 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_RPMI) += reset/fdt_reset_rpmi.o carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_MCU) += fdt_reset_sophgo_mcu libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_MCU) += reset/fdt_reset_sophgo_mcu.o + +carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld +libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += reset/fdt_reset_sophgo_cpld.o + +carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_WDT) += fdt_reset_sophgo_wdt +libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_WDT) += reset/fdt_reset_sophgo_wdt.o diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 60de801e69e..0aee3d97ab9 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -21,6 +21,7 @@ CONFIG_FDT_CPPC_RPMI=y CONFIG_FDT_GPIO=y CONFIG_FDT_GPIO_DESIGNWARE=y CONFIG_FDT_GPIO_SIFIVE=y +CONFIG_FDT_GPIO_SOPHGO=y CONFIG_FDT_GPIO_STARFIVE=y CONFIG_FDT_HSM=y CONFIG_FDT_HSM_RPMI=y @@ -48,7 +49,9 @@ CONFIG_FDT_RESET_RPMI=y CONFIG_FDT_RESET_SG2042_HWMON_MCU=y CONFIG_FDT_RESET_SUNXI_WDT=y CONFIG_FDT_RESET_SYSCON=y +CONFIG_FDT_RESET_SOPHGO_CPLD=y CONFIG_FDT_RESET_SOPHGO_MCU=y +CONFIG_FDT_RESET_SOPHGO_WDT=y CONFIG_FDT_SERIAL=y CONFIG_FDT_SERIAL_CADENCE=y CONFIG_FDT_SERIAL_GAISLER=y From 877f33ef8b7120a39c6a0873cfd624a34f8c0ad0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:11:44 +0800 Subject: [PATCH 11/18] lib:utils:support pisces's system reboot pisces system reboot will ecall gpio chip but not watchdog, and pull up cpu gpio5 to tell CPLD. CPLD will help for cold reboot. Add the function, gpio chip will pull up gpio16 after chip is probed. Signed-off-by: chunzhi.lin --- lib/utils/gpio/fdt_gpio_sophgo.c | 33 ++++++++++--- lib/utils/reset/fdt_reset_sophgo_cpld.c | 64 ++++++++++++++++++++----- lib/utils/reset/fdt_reset_sophgo_wdt.c | 1 - lib/utils/reset/objects.mk | 4 +- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/lib/utils/gpio/fdt_gpio_sophgo.c b/lib/utils/gpio/fdt_gpio_sophgo.c index 9693b726713..287b2a47020 100644 --- a/lib/utils/gpio/fdt_gpio_sophgo.c +++ b/lib/utils/gpio/fdt_gpio_sophgo.c @@ -25,6 +25,7 @@ #define SOPHGO_GPIO_SWPORTA_CTL_OFFSET 0x08 #define SOPHGO_GPIO_BIT(offset) (1U << (offset)) +#define SOPHGO_GPIO_STARTUP_FLAG SOPHGO_GPIO_BIT(16) struct sophgo_gpio_chip { unsigned long addr; @@ -74,22 +75,39 @@ static void sophgo_gpio_set(struct gpio_pin *gp, int value) static int sophgo_gpio_addr_get(const void *fdt, int nodeoff, unsigned long *addr) { - int rc; + int parent, len; unsigned long addr_high, addr_low; + const fdt32_t *prop_addr; - rc = fdt_get_node_addr_size(fdt, nodeoff, 1, &addr_low, NULL); - if (rc) - return rc; + parent = fdt_parent_offset(fdt, nodeoff); + if (parent < 0) + return parent; - rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr_high, NULL); - if (rc) - return rc; + prop_addr = fdt_getprop(fdt, parent, "reg", &len); + if (!prop_addr) + return SBI_ENODEV; + + addr_high = fdt32_to_cpu(*prop_addr++); + addr_low = fdt32_to_cpu(*prop_addr); *addr = addr_high << 32 | addr_low; return 0; } +static void sophgo_system_normal_startup_flag(unsigned long addr) +{ + unsigned int v; + + v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + v |= SOPHGO_GPIO_STARTUP_FLAG; + writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DDR_OFFSET)); + + v = readl((volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); + v |= SOPHGO_GPIO_STARTUP_FLAG; + writel(v, (volatile void *)(addr + SOPHGO_GPIO_SWPORTA_DR_OFFSET)); +} + extern const struct fdt_gpio fdt_gpio_sophgo; static int sophgo_gpio_init(const void *fdt, int nodeoff, @@ -122,6 +140,7 @@ static int sophgo_gpio_init(const void *fdt, int nodeoff, return rc; sophgo_gpio_chip_count++; + sophgo_system_normal_startup_flag(addr); return 0; } diff --git a/lib/utils/reset/fdt_reset_sophgo_cpld.c b/lib/utils/reset/fdt_reset_sophgo_cpld.c index 8889b0cb71e..0a0e164ac50 100644 --- a/lib/utils/reset/fdt_reset_sophgo_cpld.c +++ b/lib/utils/reset/fdt_reset_sophgo_cpld.c @@ -24,20 +24,28 @@ struct cpld_reset { }; static struct cpld_reset poweroff = { - .active_delay = 300, - .inactive_delay = 300 + .active_delay = 300, + .inactive_delay = 300 }; -static struct cpld_reset *cpld_reset_get(u32 type) +static struct cpld_reset reboot = { + .active_delay = 300, + .inactive_delay = 300 +}; + +static struct cpld_reset *cpld_reset_get(bool is_poweroff, u32 type) { struct cpld_reset *reset = NULL; switch (type) { case SBI_SRST_RESET_TYPE_SHUTDOWN: - reset = &poweroff; + if (is_poweroff) + reset = &poweroff; break; case SBI_SRST_RESET_TYPE_COLD_REBOOT: case SBI_SRST_RESET_TYPE_WARM_REBOOT: + if (!is_poweroff) + reset = &reboot; break; } @@ -64,7 +72,7 @@ static void cpld_reset_exec(struct cpld_reset *reset) static int cpld_system_poweroff_check(u32 type, u32 reason) { - if (cpld_reset_get(type)) + if (cpld_reset_get(true, type)) return 128; return 0; @@ -72,21 +80,42 @@ static int cpld_system_poweroff_check(u32 type, u32 reason) static void cpld_system_poweroff(u32 type, u32 reason) { - cpld_reset_exec(cpld_reset_get(type)); + cpld_reset_exec(cpld_reset_get(true, type)); } -static struct sbi_system_reset_device mango_reset_gpio = { +static struct sbi_system_reset_device mango_reset_gpio_poweroff = { .name = "mango-cpld", .system_reset_check = cpld_system_poweroff_check, .system_reset = cpld_system_poweroff }; +static int cpld_system_reboot_check(u32 type, u32 reason) +{ + if (cpld_reset_get(false, type)) + return 128; + + return 0; +} + +static void cpld_system_reboot(u32 type, u32 reason) +{ + cpld_reset_exec(cpld_reset_get(false, type)); +} + +static struct sbi_system_reset_device mango_reset_gpio_reboot = { + .name = "mango-cpld", + .system_reset_check = cpld_system_reboot_check, + .system_reset = cpld_system_reboot +}; + + static int mango_cpld_reset_init(const void *fdt, int nodeoff, const struct fdt_match *match) { int rc, len; const fdt32_t *val; - struct cpld_reset *reset = &poweroff; + bool is_poweroff = (ulong)match->data; + struct cpld_reset *reset = (is_poweroff) ? &poweroff : &reboot; const char *dir_prop = "output"; rc = fdt_gpio_pin_get(fdt, nodeoff, 0, &reset->pin); @@ -107,17 +136,30 @@ static int mango_cpld_reset_init(const void *fdt, int nodeoff, if (len > 0) reset->inactive_delay = fdt32_to_cpu(*val); - sbi_system_reset_add_device(&mango_reset_gpio); + if (is_poweroff) + sbi_system_reset_add_device(&mango_reset_gpio_poweroff); + else + sbi_system_reset_add_device(&mango_reset_gpio_reboot); return rc; } +static const struct fdt_match mango_cpld_poweroff_match[] = { + { .compatible = "mango,cpld-poweroff", .data = (void *)true}, + { }, +}; + +const struct fdt_driver fdt_reset_sophgo_cpld_poweroff = { + .match_table = mango_cpld_poweroff_match, + .init = mango_cpld_reset_init, +}; + static const struct fdt_match mango_cpld_reset_match[] = { - { .compatible = "mango,cpld-reset", .data = (void *)true}, + { .compatible = "mango,cpld-reboot", .data = (void *)false}, { }, }; -const struct fdt_driver fdt_reset_sophgo_cpld = { +const struct fdt_driver fdt_reset_sophgo_cpld_reboot = { .match_table = mango_cpld_reset_match, .init = mango_cpld_reset_init, }; diff --git a/lib/utils/reset/fdt_reset_sophgo_wdt.c b/lib/utils/reset/fdt_reset_sophgo_wdt.c index f15c0e9b6bf..4e6f57a7288 100644 --- a/lib/utils/reset/fdt_reset_sophgo_wdt.c +++ b/lib/utils/reset/fdt_reset_sophgo_wdt.c @@ -91,7 +91,6 @@ static int mango_wdt_reset_init(const void *fdt, int nodeoff, { unsigned long wdt_addr, top_addr; int rc; - // struct device_node *np; rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &wdt_addr, NULL); if (rc < 0 || !wdt_addr) { diff --git a/lib/utils/reset/objects.mk b/lib/utils/reset/objects.mk index a8f0340e91e..fe86ef9ec78 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -33,8 +33,10 @@ libsbiutils-objs-$(CONFIG_FDT_RESET_RPMI) += reset/fdt_reset_rpmi.o carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_MCU) += fdt_reset_sophgo_mcu libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_MCU) += reset/fdt_reset_sophgo_mcu.o -carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld +carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld_poweroff +carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += fdt_reset_sophgo_cpld_reboot libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_CPLD) += reset/fdt_reset_sophgo_cpld.o + carray-fdt_early_drivers-$(CONFIG_FDT_RESET_SOPHGO_WDT) += fdt_reset_sophgo_wdt libsbiutils-objs-$(CONFIG_FDT_RESET_SOPHGO_WDT) += reset/fdt_reset_sophgo_wdt.o From 5c58e010a63c2d6425a9ba9f2a56d50f9f0c51f1 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:13:36 +0800 Subject: [PATCH 12/18] SG2042: spinlock: Fix deadlock issue This problem was found on sg2042 server platform with the litmus test. This patch is based on Guo Ren's patch [1]. [1] https://github.com/c-sky/csky-linux/commit/c53925298d15b1d7aac736766ba31116d1c03ba3 riscv: qspinlock: errata: Add ERRATA_THEAD_WRITE_ONCE fixup The early version of T-Head C9xx cores has a store merge buffer delay problem. The store merge buffer could improve the store queue performance by merging multi-store requests, but when there are not continued store requests, the prior single store request would be waiting in the store queue for a long time. That would cause significant problems for communication between multi-cores. This problem was found on sg2042 & th1520 platforms with the qspinlock lock torture test. So appending a fence w.o could immediately flush the store merge buffer and let other cores see the write result. This will apply the WRITE_ONCE errata to handle the non-standard behavior via appending a fence w.o instruction for WRITE_ONCE(). Signed-off-by: haijiao.liu@sophgo.com --- include/sbi/riscv_barrier.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h index 7d2d8bb525e..6578c382efa 100644 --- a/include/sbi/riscv_barrier.h +++ b/include/sbi/riscv_barrier.h @@ -48,11 +48,20 @@ do { \ /* clang-format on */ +#ifdef CONFIG_PLATFORM_SOPHGO_MANGO + #define __smp_store_release(p, v) \ + do { \ + RISCV_FENCE(rw, w); \ + *(p) = (v); \ + RISCV_FENCE(w, rw); \ + } while (0) +#else #define __smp_store_release(p, v) \ do { \ RISCV_FENCE(rw, w); \ *(p) = (v); \ } while (0) +#endif #define __smp_load_acquire(p) \ ({ \ From d3d5445920585aaf1ba351f97fc88231e65c56c0 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:25:35 +0800 Subject: [PATCH 13/18] platform: generic: allwinner: Clear the overflow generated during the deletion process Signed-off-by: haijiao.liu --- lib/sbi/sbi_pmu.c | 2 ++ platform/generic/thead/thead_c9xx_pmu.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index db4a8d52bc8..aad0e141049 100644 --- a/lib/sbi/sbi_pmu.c +++ b/lib/sbi/sbi_pmu.c @@ -689,6 +689,8 @@ int sbi_pmu_ctr_stop(unsigned long cbase, unsigned long cmask, ret = pmu_ctr_stop_hw(cidx); if (cidx > (CSR_INSTRET - CSR_CYCLE) && flag & SBI_PMU_STOP_FLAG_RESET) { + if (pmu_dev && pmu_dev->hw_counter_disable_irq) + pmu_dev->hw_counter_disable_irq(cidx); phs->active_events[cidx] = SBI_PMU_EVENT_IDX_INVALID; pmu_reset_hw_mhpmevent(cidx); } diff --git a/platform/generic/thead/thead_c9xx_pmu.c b/platform/generic/thead/thead_c9xx_pmu.c index 0b61e92acf2..768eda508c3 100644 --- a/platform/generic/thead/thead_c9xx_pmu.c +++ b/platform/generic/thead/thead_c9xx_pmu.c @@ -44,6 +44,12 @@ static void thead_c9xx_pmu_ctr_enable_irq(uint32_t ctr_idx) static void thead_c9xx_pmu_ctr_disable_irq(uint32_t ctr_idx) { + unsigned long mip_val; + if (ctr_idx >= SBI_PMU_HW_CTR_MAX) + return; + mip_val = csr_read(CSR_MIP); + if (mip_val & BIT(THEAD_C9XX_IRQ_PMU_OVF)) + csr_clear(THEAD_C9XX_CSR_MCOUNTEROF, BIT(ctr_idx)); /** * There is no need to clear the bit of mcounterwen, it will expire * after setting the csr mcountinhibit. From 3fd02ff433c10eac0f1786d59492ade8a857d6dc Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:29:40 +0800 Subject: [PATCH 14/18] lib: ipi/timer: in favor of upstream linux settings Signed-off-by: Inochi Amaoto --- lib/utils/ipi/fdt_ipi_mswi.c | 1 + lib/utils/timer/fdt_timer_mtimer.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/utils/ipi/fdt_ipi_mswi.c b/lib/utils/ipi/fdt_ipi_mswi.c index df435497419..bbc59cbbab3 100644 --- a/lib/utils/ipi/fdt_ipi_mswi.c +++ b/lib/utils/ipi/fdt_ipi_mswi.c @@ -56,6 +56,7 @@ static const struct fdt_match ipi_mswi_match[] = { { .compatible = "riscv,clint0", .data = &clint_offset }, { .compatible = "sifive,clint0", .data = &clint_offset }, { .compatible = "thead,c900-clint", .data = &clint_offset }, + { .compatible = "sophgo,sg2042-clint-mswi", .data = &clint_offset }, { .compatible = "thead,c900-clint-mswi", .data = &clint_offset }, { .compatible = "thead,c900-aclint-mswi" }, { .compatible = "mips,p8700-aclint-mswi" }, diff --git a/lib/utils/timer/fdt_timer_mtimer.c b/lib/utils/timer/fdt_timer_mtimer.c index 77cbe7bc048..68c869237b4 100644 --- a/lib/utils/timer/fdt_timer_mtimer.c +++ b/lib/utils/timer/fdt_timer_mtimer.c @@ -172,6 +172,8 @@ static const struct fdt_match timer_mtimer_match[] = { { .compatible = "thead,c900-clint", .data = &thead_clint_quirks }, { .compatible = "thead,c900-clint-mtimer", .data = &thead_clint_sep_quirks }, + { .compatible = "sophgo,sg2042-clint-mtimer", + .data = &thead_clint_sep_quirks }, { .compatible = "thead,c900-aclint-mtimer", .data = &thead_aclint_quirks }, { .compatible = "riscv,aclint-mtimer" }, From 607ad58308ebe2c3183c03d61ef5551cdc4f204b Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:50:36 +0800 Subject: [PATCH 15/18] SG2042: add virtual global timer device driver Add a virtual global timer device driver. It uses a global timer register as timer counter, and it uses mtimecmp CSR of clint as interrupt source. Using this virtul timer resolves dual way timer sync issue. On dual way system, we should enable this driver and on single way system, we should use standard risc-v clint timer. 1. Add a virtual global timer device driver, it is probed by fdt sg2042-global-mtimer@70300101c0 { compatible = "sophgo,sg2042-global-mtimer"; reg = < 0x00000070 0x300101c0 0x00000000 0x00000008 0x00000070 0xac000000 0x00000000 0x00200000>; clock-frequency = <50000000 50000000>; }; Its compatible should be "sophgo,sg2042-global-mtimer". And the first region delcared in reg prop is the address of global timer. The second region delcared in reg prop is the base of clint timers. The first clock in clock-frequency is the actual frequency of global timer, the second clock is the actual frequency of clint timer. 2. Add a quirk in platform specific code. Add a function sbi_platform_force_emulate_time_csr, it indicates if opensbi should skip time CSR detection and make software in supervisor and user mode use emulated time CSR. Signed-off-by: Chao Wei --- include/sbi_utils/timer/sg2042_gmt.h | 21 ++++ lib/utils/timer/Kconfig | 9 ++ lib/utils/timer/fdt_timer_sg2042_gmt.c | 59 +++++++++++ lib/utils/timer/objects.mk | 4 + lib/utils/timer/sg2042_gmt.c | 136 +++++++++++++++++++++++++ 5 files changed, 229 insertions(+) create mode 100644 include/sbi_utils/timer/sg2042_gmt.h create mode 100644 lib/utils/timer/fdt_timer_sg2042_gmt.c create mode 100644 lib/utils/timer/sg2042_gmt.c diff --git a/include/sbi_utils/timer/sg2042_gmt.h b/include/sbi_utils/timer/sg2042_gmt.h new file mode 100644 index 00000000000..cef24f5ac66 --- /dev/null +++ b/include/sbi_utils/timer/sg2042_gmt.h @@ -0,0 +1,21 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 SOPHGO Corporation + * + * Authors: + * Chao Wei + */ + +#ifndef __SG2042_GMT_H__ +#define __SG2042_GMT_H__ + +int sg2042gmt_cold_timer_init(unsigned long mtimer_base, + unsigned long mtimecmp_base, + unsigned long mtimecmp_size, + unsigned long delcared_freq, + unsigned long actual_freq, + unsigned long timecmp_freq); +int sg2042gmt_warm_timer_init(void); + +#endif /* __SG2042_GMT_H__ */ diff --git a/lib/utils/timer/Kconfig b/lib/utils/timer/Kconfig index ba211b62204..a8ab0dc8e07 100644 --- a/lib/utils/timer/Kconfig +++ b/lib/utils/timer/Kconfig @@ -19,6 +19,11 @@ config FDT_TIMER_PLMT select TIMER_PLMT default n +config FDT_TIMER_SG2042_GMT + bool "SOPHGO SG2042 global mtimer FDT driver" + select TIMER_SG2042_GMT + default n + endif config TIMER_MTIMER @@ -29,4 +34,8 @@ config TIMER_PLMT bool "Andes PLMT support" default n +config TIMER_SG2042_GMT + bool "SOPHGO SG2042 GMT support" + default n + endmenu diff --git a/lib/utils/timer/fdt_timer_sg2042_gmt.c b/lib/utils/timer/fdt_timer_sg2042_gmt.c new file mode 100644 index 00000000000..8a174f0f6e6 --- /dev/null +++ b/lib/utils/timer/fdt_timer_sg2042_gmt.c @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Andes Technology Corporation + * + * Authors: + * Yu Chien Peter Lin + */ + +#include +#include +#include +#include +#include + +static int fdt_sg2042gmt_cold_timer_init(const void *fdt, int nodeoff, + const struct fdt_match *match) +{ + int err; + unsigned long mtimer_base, mtimer_size, + mtimecmp_base, mtimecmp_size, + declared_freq, actual_freq, timecmp_freq; + const fdt32_t *val; + int len; + + err = fdt_get_node_addr_size(fdt, nodeoff, 0, &mtimer_base, &mtimer_size); + if (err) + return err; + + err = fdt_get_node_addr_size(fdt, nodeoff, 1, &mtimecmp_base, &mtimecmp_size); + if (err) + return err; + + + err = fdt_parse_timebase_frequency(fdt, &declared_freq); + if (err) + return err; + + val = (fdt32_t *)fdt_getprop(fdt, nodeoff, "clock-frequency", &len); + if (len < 8 || val == NULL) + return SBI_EINVAL; + + actual_freq = fdt32_to_cpu(*val); + timecmp_freq = fdt32_to_cpu(*(val + 1)); + + return sg2042gmt_cold_timer_init(mtimer_base, + mtimecmp_base, mtimecmp_size, + declared_freq, actual_freq, timecmp_freq); +} + +static const struct fdt_match timer_sg2042gmt_match[] = { + { .compatible = "sophgo,sg2042-global-mtimer" }, + {}, +}; + +const struct fdt_driver fdt_timer_sg2042_gmt = { + .match_table = timer_sg2042gmt_match, + .init = fdt_sg2042gmt_cold_timer_init, +}; diff --git a/lib/utils/timer/objects.mk b/lib/utils/timer/objects.mk index 92e0927e11c..74d1f5266c9 100644 --- a/lib/utils/timer/objects.mk +++ b/lib/utils/timer/objects.mk @@ -9,6 +9,7 @@ libsbiutils-objs-$(CONFIG_TIMER_MTIMER) += timer/aclint_mtimer.o libsbiutils-objs-$(CONFIG_TIMER_PLMT) += timer/andes_plmt.o +libsbiutils-objs-$(CONFIG_TIMER_SG2042_GMT) += timer/sg2042_gmt.o libsbiutils-objs-$(CONFIG_FDT_TIMER) += timer/fdt_timer.o libsbiutils-objs-$(CONFIG_FDT_TIMER) += timer/fdt_timer_drivers.carray.o @@ -18,3 +19,6 @@ libsbiutils-objs-$(CONFIG_FDT_TIMER_MTIMER) += timer/fdt_timer_mtimer.o carray-fdt_timer_drivers-$(CONFIG_FDT_TIMER_PLMT) += fdt_timer_plmt libsbiutils-objs-$(CONFIG_FDT_TIMER_PLMT) += timer/fdt_timer_plmt.o + +carray-fdt_timer_drivers-$(CONFIG_FDT_TIMER_SG2042_GMT) += fdt_timer_sg2042_gmt +libsbiutils-objs-$(CONFIG_FDT_TIMER_SG2042_GMT) += timer/fdt_timer_sg2042_gmt.o diff --git a/lib/utils/timer/sg2042_gmt.c b/lib/utils/timer/sg2042_gmt.c new file mode 100644 index 00000000000..bbffc689e06 --- /dev/null +++ b/lib/utils/timer/sg2042_gmt.c @@ -0,0 +1,136 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Andes Technology Corporation + * + * Authors: + * Yu Chien Peter Lin + */ + +#include +#include +#include +#include +#include +#include +#include + +struct sg2042gmt_data { + unsigned long mtimer_base; + unsigned long mtimecmp_base; + unsigned long mtimecmp_size; + unsigned long declared_freq; + unsigned long actual_freq; + unsigned long timecmp_freq; +} sg2042gmt; + +#define SG2042GMT_TIMECMP_CLUSTER_SIZE 0x10000 +#define SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT 4 + +static void *timecmp_addr(unsigned int hart_id) +{ + unsigned int cluster_id = hart_id / SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT; + unsigned int cluster_offset = hart_id % SG2042GMT_TIMECMP_CLUSTER_CORE_COUNT; + + return (void *)(sg2042gmt.mtimecmp_base + 0x4000 + + cluster_id * SG2042GMT_TIMECMP_CLUSTER_SIZE + + cluster_offset * 8); +} + +static u64 sg2042gmt_timer_value(void) +{ + u64 global_timer = readq_relaxed((void *)sg2042gmt.mtimer_base); + + /* convert global timer to declared frequency */ + return global_timer / (sg2042gmt.actual_freq / sg2042gmt.declared_freq); +} + +static void sg2042gmt_timer_event_stop(void) +{ + unsigned int hart_id = current_hartid(); + + writel_relaxed(-1U, timecmp_addr(hart_id)); + writel_relaxed(-1U, timecmp_addr(hart_id) + 4); +} + +static void sg2042gmt_timer_event_start(u64 next_event) +{ + unsigned int hart_id = current_hartid(); + + u64 global_timer = readq_relaxed((void *)sg2042gmt.mtimer_base); + u64 clint_timer = csr_read(CSR_TIME); + u64 delta_global_timer, delta_clint_timer; + + delta_global_timer = + (next_event * (sg2042gmt.actual_freq / sg2042gmt.declared_freq)) - global_timer; + + delta_clint_timer = delta_global_timer * (sg2042gmt.timecmp_freq / sg2042gmt.actual_freq); + + next_event = clint_timer + delta_clint_timer; + + writel_relaxed(next_event >> 32, timecmp_addr(hart_id) + 4); + writel_relaxed(next_event & 0xffffffff, timecmp_addr(hart_id)); +} + +static struct sbi_timer_device sg2042gmt_timer = { + .name = "sg2042gmt", + .timer_freq = 50000000, + .timer_value = sg2042gmt_timer_value, + .timer_event_start = sg2042gmt_timer_event_start, + .timer_event_stop = sg2042gmt_timer_event_stop, + .warm_init = sg2042gmt_warm_timer_init, +}; + +int sg2042gmt_cold_timer_init(unsigned long mtimer_base, + unsigned long mtimecmp_base, + unsigned long mtimecmp_size, + unsigned long declared_freq, + unsigned long actual_freq, + unsigned long timecmp_freq) +{ + int err; + + /* Add SG2042 GMT timer and time compare region to the root domain */ +#if 0 + err = sbi_domain_root_add_memrange( + mtimer_base, 4096, 4096, + SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_READABLE); + if (err) { + sbi_printf("add timer to root domain failed\n"); + return err; + } +#endif + + err = sbi_domain_root_add_memrange( + mtimecmp_base, mtimecmp_size, 4096, + SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_READABLE | + SBI_DOMAIN_MEMREGION_WRITEABLE); + if (err) { + return err; + } + + + sg2042gmt_timer.timer_freq = declared_freq; + + sg2042gmt.mtimer_base = mtimer_base; + sg2042gmt.mtimecmp_base = mtimecmp_base; + sg2042gmt.mtimecmp_size = mtimecmp_size; + sg2042gmt.declared_freq = declared_freq; + sg2042gmt.actual_freq = actual_freq; + sg2042gmt.timecmp_freq = timecmp_freq; + + sbi_timer_set_device(&sg2042gmt_timer); + + return 0; +} + +int sg2042gmt_warm_timer_init(void) +{ + if (!sg2042gmt.mtimer_base) + return SBI_ENODEV; + + sg2042gmt_timer_event_stop(); + + return 0; +} From fc7320b2a5e925eab4a9eadc0e360e0587299fac Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 22:59:46 +0800 Subject: [PATCH 16/18] sg2042: pisces: fix c9xx merged buffer Signed-off-by: Han Gao --- lib/sbi/riscv_locks.c | 3 +++ lib/sbi/sbi_init.c | 1 + 2 files changed, 4 insertions(+) diff --git a/lib/sbi/riscv_locks.c b/lib/sbi/riscv_locks.c index c29a965907b..a220ad3d29a 100644 --- a/lib/sbi/riscv_locks.c +++ b/lib/sbi/riscv_locks.c @@ -64,6 +64,8 @@ void spin_lock(spinlock_t *lock) #error "need A or Zaamo or Zalrsc" #endif + "fence w, o\n" + /* Did we get the lock? */ " srli %1, %0, %6\n" " and %1, %1, %5\n" @@ -83,4 +85,5 @@ void spin_lock(spinlock_t *lock) void spin_unlock(spinlock_t *lock) { __smp_store_release(&lock->owner, lock->owner + 1); + RISCV_FENCE(w, o); } diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 5259064b191..7711d944f74 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -216,6 +216,7 @@ static void wake_coldboot_harts(struct sbi_scratch *scratch) { /* Mark coldboot done */ __smp_store_release(&coldboot_done, 1); + RISCV_FENCE(w, o); } static unsigned long entry_count_offset; From 6e30e5268594916639877375cb6c9583f1047df5 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 31 Dec 2025 21:49:51 +0800 Subject: [PATCH 17/18] fixup dt for sg2042 --- platform/generic/sophgo/sg2042.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/platform/generic/sophgo/sg2042.c b/platform/generic/sophgo/sg2042.c index e96a8659ede..6a29f2ac5c3 100644 --- a/platform/generic/sophgo/sg2042.c +++ b/platform/generic/sophgo/sg2042.c @@ -85,6 +85,31 @@ static u32 mango_tlb_num_entries(void) return 128; } +static int mango_final_init(bool cold_boot) +{ + int noff; + void *fdt; + + if (!cold_boot) + return 0; + + fdt = fdt_get_address_rw(); + + noff = fdt_node_offset_by_compatible(fdt, 0, "mango,reset"); + if (noff > 0) + fdt_del_node(fdt, noff); + + noff = fdt_node_offset_by_compatible(fdt, 0, "mango,cpld-poweroff"); + if (noff > 0) + fdt_del_node(fdt, noff); + + noff = fdt_node_offset_by_compatible(fdt, 0, "mango,cpld-reboot"); + if (noff > 0) + fdt_del_node(fdt, noff); + + return generic_final_init(cold_boot); +} + static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { if (platform.hart_stack_size < 16384) @@ -100,6 +125,7 @@ static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struc generic_platform_ops.cold_boot_allowed = mango_cold_boot_allowed; generic_platform_ops.force_emulate_time_csr = mango_force_emulate_time_csr; generic_platform_ops.get_tlb_num_entries = mango_tlb_num_entries; + generic_platform_ops.final_init = mango_final_init; return 0; } From 117a94df1c9e1de25bcedb128980181104415261 Mon Sep 17 00:00:00 2001 From: Xiang W Date: Wed, 7 Jan 2026 21:43:16 +0800 Subject: [PATCH 18/18] Allows the platform to customize TLB operations --- include/sbi/sbi_platform.h | 90 ++++++++++++++++++++ lib/sbi/sbi_tlb.c | 28 ++++++ platform/generic/include/thead/c9xx_errata.h | 1 + platform/generic/sophgo/sg2042.c | 29 +++++++ platform/generic/thead/thead-generic.c | 38 ++++++++- 5 files changed, 185 insertions(+), 1 deletion(-) diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h index 7593b027fc3..be992a75404 100644 --- a/include/sbi/sbi_platform.h +++ b/include/sbi/sbi_platform.h @@ -56,6 +56,7 @@ struct sbi_domain_memregion; struct sbi_ecall_return; struct sbi_trap_regs; struct sbi_hart_features; +struct sbi_tlb_info; union sbi_ldst_data; /** Possible feature flags of a platform */ @@ -128,6 +129,20 @@ struct sbi_platform_operations { /** Get tlb fifo num entries*/ u32 (*get_tlb_num_entries)(void); + void (*local_fence_i)(struct sbi_tlb_info *tinfo); + + void (*local_sfence_vma)(struct sbi_tlb_info *tinfo); + + void (*local_sfence_vma_asid)(struct sbi_tlb_info *tinfo); + + void (*local_hfence_gvma_vmid)(struct sbi_tlb_info *tinfo); + + void (*local_hfence_gvma)(struct sbi_tlb_info *tinfo); + + void (*local_hfence_vvma_asid)(struct sbi_tlb_info *tinfo); + + void (*local_hfence_vvma)(struct sbi_tlb_info *tinfo); + /** Initialize platform timer during cold boot */ int (*timer_init)(void); @@ -308,6 +323,81 @@ static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *p return sbi_hart_count(); } +static inline u32 sbi_platform_local_fence_i( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_fence_i) { + sbi_platform_ops(plat)->local_fence_i(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} + +static inline u32 sbi_platform_local_sfence_vma( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_sfence_vma) { + sbi_platform_ops(plat)->local_sfence_vma(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} + +static inline u32 sbi_platform_local_sfence_vma_asid( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_sfence_vma_asid) { + sbi_platform_ops(plat)->local_sfence_vma_asid(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} + +static inline u32 sbi_platform_local_hfence_gvma_vmid( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_hfence_gvma_vmid) { + sbi_platform_ops(plat)->local_hfence_gvma_vmid(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} + +static inline u32 sbi_platform_local_hfence_gvma( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_hfence_gvma) { + sbi_platform_ops(plat)->local_hfence_gvma(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} +static inline u32 sbi_platform_local_hfence_vvma_asid( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_hfence_vvma_asid) { + sbi_platform_ops(plat)->local_hfence_vvma_asid(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} +static inline u32 sbi_platform_local_hfence_vvma( + const struct sbi_platform *plat, + struct sbi_tlb_info *tinfo) +{ + if (plat && sbi_platform_ops(plat)->local_hfence_vvma) { + sbi_platform_ops(plat)->local_hfence_vvma(tinfo); + return 0; + } + return SBI_ENOTSUPP; +} + /** * Get total number of HARTs supported by the platform * diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c index ada60c329d5..fcbba7af824 100644 --- a/lib/sbi/sbi_tlb.c +++ b/lib/sbi/sbi_tlb.c @@ -43,6 +43,10 @@ static void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_RCVD); + if (sbi_platform_local_hfence_vvma( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + hgatp = csr_swap(CSR_HGATP, (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK); @@ -67,6 +71,10 @@ static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_RCVD); + if (sbi_platform_local_hfence_gvma( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { __sbi_hfence_gvma_all(); return; @@ -85,6 +93,10 @@ static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_RCVD); + if (sbi_platform_local_sfence_vma( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { __sbi_sfence_vma_all(); return; @@ -108,6 +120,10 @@ static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD); + if (sbi_platform_local_hfence_vvma_asid( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + hgatp = csr_swap(CSR_HGATP, (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK); @@ -133,6 +149,10 @@ static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD); + if (sbi_platform_local_hfence_gvma_vmid( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { __sbi_hfence_gvma_vmid(vmid); return; @@ -152,6 +172,10 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo) sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD); + if (sbi_platform_local_sfence_vma_asid( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + /* Flush entire MM context for a given ASID */ if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { __asm__ __volatile__("sfence.vma x0, %0" @@ -173,6 +197,10 @@ static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo) { sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_RECVD); + if (sbi_platform_local_fence_i( + sbi_platform_thishart_ptr(), tinfo) == SBI_OK) + return; + __asm__ __volatile("fence.i"); } diff --git a/platform/generic/include/thead/c9xx_errata.h b/platform/generic/include/thead/c9xx_errata.h index 40c1587bcf7..7a419e4169f 100644 --- a/platform/generic/include/thead/c9xx_errata.h +++ b/platform/generic/include/thead/c9xx_errata.h @@ -8,6 +8,7 @@ */ #define THEAD_QUIRK_ERRATA_TLB_FLUSH BIT(0) #define THEAD_QUIRK_ERRATA_THEAD_PMU BIT(1) +#define THEAD_QUIRK_ERRATA_JTLB BIT(2) void thead_register_tlb_flush_trap_handler(void); diff --git a/platform/generic/sophgo/sg2042.c b/platform/generic/sophgo/sg2042.c index 6a29f2ac5c3..b892d730645 100644 --- a/platform/generic/sophgo/sg2042.c +++ b/platform/generic/sophgo/sg2042.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -110,6 +111,32 @@ static int mango_final_init(bool cold_boot) return generic_final_init(cold_boot); } +static void sophgo_sg2042_jtlb_local_sfence_vma(struct sbi_tlb_info *tinfo) +{ + __asm__ __volatile__("sfence.vma"); +} + +static void sophgo_sg2042_jtlb_local_hfence_vma_asid(struct sbi_tlb_info *tinfo) +{ + unsigned long start = tinfo->start; + unsigned long size = tinfo->size; + unsigned long asid = tinfo->asid; + + /* Flush entire MM context for a given ASID */ + if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { + __asm__ __volatile__("sfence.vma x0, %0" + : + : "r"(asid) + : "memory"); + return; + } + + __asm__ __volatile__("sfence.vma x0, %0" + : + : "r"(asid) + : "memory"); +} + static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { if (platform.hart_stack_size < 16384) @@ -126,6 +153,8 @@ static int sophgo_sg2042_platform_init(const void *fdt, int nodeoff, const struc generic_platform_ops.force_emulate_time_csr = mango_force_emulate_time_csr; generic_platform_ops.get_tlb_num_entries = mango_tlb_num_entries; generic_platform_ops.final_init = mango_final_init; + generic_platform_ops.local_sfence_vma = sophgo_sg2042_jtlb_local_sfence_vma; + generic_platform_ops.local_sfence_vma_asid = sophgo_sg2042_jtlb_local_hfence_vma_asid; return 0; } diff --git a/platform/generic/thead/thead-generic.c b/platform/generic/thead/thead-generic.c index ddb4f0bf425..41662182462 100644 --- a/platform/generic/thead/thead-generic.c +++ b/platform/generic/thead/thead-generic.c @@ -13,6 +13,7 @@ #include #include #include +#include #include struct thead_generic_quirks { @@ -39,6 +40,32 @@ static int thead_pmu_extensions_init(struct sbi_hart_features *hfeatures) return 0; } +static void thead_jtlb_local_sfence_vma(struct sbi_tlb_info *tinfo) +{ + __asm__ __volatile__("sfence.vma"); +} + +static void thead_jtlb_local_hfence_vma_asid(struct sbi_tlb_info *tinfo) +{ + unsigned long start = tinfo->start; + unsigned long size = tinfo->size; + unsigned long asid = tinfo->asid; + + /* Flush entire MM context for a given ASID */ + if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) { + __asm__ __volatile__("sfence.vma x0, %0" + : + : "r"(asid) + : "memory"); + return; + } + + __asm__ __volatile__("sfence.vma x0, %0" + : + : "r"(asid) + : "memory"); +} + static int thead_generic_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) { @@ -49,6 +76,11 @@ static int thead_generic_platform_init(const void *fdt, int nodeoff, if (quirks->errata & THEAD_QUIRK_ERRATA_THEAD_PMU) generic_platform_ops.extensions_init = thead_pmu_extensions_init; + if (quirks->errata &THEAD_QUIRK_ERRATA_JTLB) { + generic_platform_ops.local_sfence_vma = thead_jtlb_local_sfence_vma; + generic_platform_ops.local_sfence_vma_asid = thead_jtlb_local_hfence_vma_asid; + } + return 0; } @@ -60,13 +92,17 @@ static const struct thead_generic_quirks thead_pmu_quirks = { .errata = THEAD_QUIRK_ERRATA_THEAD_PMU, }; +static const struct thead_generic_quirks thead_pmu_jtlb_quirks = { + .errata = THEAD_QUIRK_ERRATA_THEAD_PMU | THEAD_QUIRK_ERRATA_JTLB, +}; + static const struct fdt_match thead_generic_match[] = { { .compatible = "canaan,kendryte-k230", .data = &thead_pmu_quirks }, { .compatible = "sophgo,cv1800b", .data = &thead_pmu_quirks }, { .compatible = "sophgo,cv1812h", .data = &thead_pmu_quirks }, { .compatible = "sophgo,sg2000", .data = &thead_pmu_quirks }, { .compatible = "sophgo,sg2002", .data = &thead_pmu_quirks }, - { .compatible = "sophgo,sg2044", .data = &thead_pmu_quirks }, + { .compatible = "sophgo,sg2044", .data = &thead_pmu_jtlb_quirks }, { .compatible = "thead,th1520", .data = &thead_th1520_quirks }, { }, };