diff --git a/firmware/fw_base.S b/firmware/fw_base.S index bce9e226842..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 @@ -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 diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h index 3d4a038c95e..6578c382efa 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() \ @@ -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) \ ({ \ 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..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 */ @@ -76,6 +77,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); @@ -125,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); @@ -305,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 * @@ -350,6 +443,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/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/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/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_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_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; diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c index e084005d11f..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); } @@ -1135,6 +1137,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/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/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..287b2a47020 --- /dev/null +++ b/lib/utils/gpio/fdt_gpio_sophgo.c @@ -0,0 +1,159 @@ +/* + * 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)) +#define SOPHGO_GPIO_STARTUP_FLAG SOPHGO_GPIO_BIT(16) + +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 parent, len; + unsigned long addr_high, addr_low; + const fdt32_t *prop_addr; + + parent = fdt_parent_offset(fdt, nodeoff); + if (parent < 0) + return parent; + + 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, + 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++; + sophgo_system_normal_startup_flag(addr); + + 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/ipi/fdt_ipi_mswi.c b/lib/utils/ipi/fdt_ipi_mswi.c index 6d8f6bf3af2..bbc59cbbab3 100644 --- a/lib/utils/ipi/fdt_ipi_mswi.c +++ b/lib/utils/ipi/fdt_ipi_mswi.c @@ -56,6 +56,8 @@ 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" }, { .compatible = "riscv,aclint-mswi" }, diff --git a/lib/utils/reset/Kconfig b/lib/utils/reset/Kconfig index 68e667163b5..f937078e566 100644 --- a/lib/utils/reset/Kconfig +++ b/lib/utils/reset/Kconfig @@ -33,6 +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..0a0e164ac50 --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_cpld.c @@ -0,0 +1,165 @@ +/* + * 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 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: + 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; + } + + 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(true, type)) + return 128; + + return 0; +} + +static void cpld_system_poweroff(u32 type, u32 reason) +{ + cpld_reset_exec(cpld_reset_get(true, type)); +} + +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; + 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); + 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); + + 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-reboot", .data = (void *)false}, + { }, +}; + +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_mcu.c b/lib/utils/reset/fdt_reset_sophgo_mcu.c new file mode 100644 index 00000000000..06862af19a1 --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_mcu.c @@ -0,0 +1,155 @@ +/* + * 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 MANGO_BOARD_TYPE_MASK 1 << 7 +#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_MASK) != 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/fdt_reset_sophgo_wdt.c b/lib/utils/reset/fdt_reset_sophgo_wdt.c new file mode 100644 index 00000000000..4e6f57a7288 --- /dev/null +++ b/lib/utils/reset/fdt_reset_sophgo_wdt.c @@ -0,0 +1,121 @@ +/* + * 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; + + 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 ac38b49df05..fe86ef9ec78 100644 --- a/lib/utils/reset/objects.mk +++ b/lib/utils/reset/objects.mk @@ -29,3 +29,14 @@ 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 + +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 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/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..68c869237b4 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,22 @@ 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 = "sophgo,sg2042-clint-mtimer", + .data = &thead_clint_sep_quirks }, { .compatible = "thead,c900-aclint-mtimer", .data = &thead_aclint_quirks }, { .compatible = "riscv,aclint-mtimer" }, 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; +} diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index aab1560f239..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,6 +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 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 c2447c3c2df..b892d730645 100644 --- a/platform/generic/sophgo/sg2042.c +++ b/platform/generic/sophgo/sg2042.c @@ -5,7 +5,7 @@ * Inochi Amaoto * */ - +#include #include #include #include @@ -14,12 +14,24 @@ #include #include #include +#include #include #include #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 +51,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 +70,96 @@ 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 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 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) + 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; + 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; } + static const struct fdt_match sophgo_sg2042_match[] = { { .compatible = "sophgo,sg2042" }, { }, 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 }, { }, }; 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.