diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 688da3f4..a24d6ab2 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -68,6 +68,10 @@ config PLATFORM_THEAD select THEAD_C9XX_PMU default n +config PLATFORM_MIPS_P8700 + bool "MIPS P8700 support" + default n + source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig" source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig" diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index bb260626..c7a6531e 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -6,6 +6,7 @@ CONFIG_PLATFORM_SIFIVE_FU740=y CONFIG_PLATFORM_SOPHGO_SG2042=y CONFIG_PLATFORM_STARFIVE_JH7110=y CONFIG_PLATFORM_THEAD=y +CONFIG_PLATFORM_MIPS_P8700=y CONFIG_FDT_CPPC=y CONFIG_FDT_CPPC_RPMI=y CONFIG_FDT_GPIO=y diff --git a/platform/generic/include/mips/board.h b/platform/generic/include/mips/board.h new file mode 100644 index 00000000..6fe7b8b6 --- /dev/null +++ b/platform/generic/include/mips/board.h @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 MIPS + * + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +/* Please review all defines to change for your board. */ + +/* Use in stw.S, p8700.c, p8700.h, mips-cm.h */ +#define CM_BASE 0x16100000 + +/* Use in mips-cm.h, p8700.c */ +#define CLUSTERS_IN_PLATFORM 1 +#if CLUSTERS_IN_PLATFORM > 1 +/* Define global CM bases for cluster 0, 1, 2, and more. */ +#define GLOBAL_CM_BASE0 0 +#define GLOBAL_CM_BASE1 0 +#define GLOBAL_CM_BASE2 0 +#endif + +/* Use in stw.S */ +#define TIMER_ADDR (CM_BASE + 0x8050) + +/* Use in cps-vec.S */ +#define DRAM_ADDRESS 0x80000000 +#define DRAM_SIZE 0x80000000 +#define DRAM_PMP_ADDR ((DRAM_ADDRESS >> 2) | ((DRAM_SIZE - 1) >> 3)) + +#endif diff --git a/platform/generic/include/mips/mips-cm.h b/platform/generic/include/mips/mips-cm.h new file mode 100644 index 00000000..419e8407 --- /dev/null +++ b/platform/generic/include/mips/mips-cm.h @@ -0,0 +1,88 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 MIPS + * + */ + +#ifndef __MIPS_CM_H__ +#define __MIPS_CM_H__ + +#include +#include + +/* Define 1 to print out CM read and write info */ +#define DEBUG_CM 0 + +#if CLUSTERS_IN_PLATFORM > 1 +static long GLOBAL_CM_BASE[CLUSTERS_IN_PLATFORM] = {GLOBAL_CM_BASE0, GLOBAL_CM_BASE1, GLOBAL_CM_BASE2}; +#else +static long GLOBAL_CM_BASE[CLUSTERS_IN_PLATFORM] = {CM_BASE}; +#endif + +#define CPS_ACCESSOR_R(unit, sz, base, off, name) \ +static inline u##sz read_##unit##_##name(u32 hartid, bool local_p) \ +{ \ + u##sz value; \ + long cmd_reg; \ + int cl, co; \ + cl = cpu_cluster(hartid); \ + co = cpu_core(hartid); \ + cmd_reg = (local_p ? (base) : ((base) - CM_BASE + GLOBAL_CM_BASE[cl])) \ + + (co << CM_BASE_CORE_SHIFT) \ + + off; \ + if (DEBUG_CM) \ + sbi_printf("CM READ%d cmd_reg=%lx\n", sz, cmd_reg); \ + if (sz == 32) \ + asm volatile("lw %0,0(%1)":"=r"(value):"r"(cmd_reg)); \ + else if (sz == 64) \ + asm volatile("ld %0,0(%1)":"=r"(value):"r"(cmd_reg)); \ + asm volatile("fence"); \ + return value; \ +} + +#define CPS_ACCESSOR_W(unit, sz, base, off, name) \ +static inline void write_##unit##_##name(u32 hartid, u##sz value, bool local_p) \ +{ \ + long cmd_reg; \ + int cl, co; \ + cl = cpu_cluster(hartid); \ + co = cpu_core(hartid); \ + cmd_reg = (local_p ? (base) : ((base) - CM_BASE + GLOBAL_CM_BASE[cl])) \ + + (co << CM_BASE_CORE_SHIFT) \ + + off; \ + if (DEBUG_CM) \ + sbi_printf("CM WRITE%d cmd_reg=%lx value=%lx\n", sz, \ + cmd_reg, (unsigned long)value); \ + if (sz == 32) \ + asm volatile("sw %0,0(%1)"::"r"(value),"r"(cmd_reg)); \ + else if (sz == 64) \ + asm volatile("sd %0,0(%1)"::"r"(value),"r"(cmd_reg)); \ + asm volatile("fence"); \ +} + +#define CPS_ACCESSOR_RW(unit, sz, base, off, name) \ + CPS_ACCESSOR_R(unit, sz, base, off, name) \ + CPS_ACCESSOR_W(unit, sz, base, off, name) + +#define CPC_CX_ACCESSOR_RW(sz, off, name) \ + CPS_ACCESSOR_RW(cpc, sz, CPC_BASE, CPC_OFF_LOCAL + (off), co_##name) + +#define GCR_CX_ACCESSOR_RW(sz, off, name) \ + CPS_ACCESSOR_RW(gcr, sz, CM_BASE, GCR_OFF_LOCAL + (off), co_##name) + +GCR_CX_ACCESSOR_RW(64, cpu_hart(hartid) << CM_BASE_HART_SHIFT, reset_base) +GCR_CX_ACCESSOR_RW(32, GCR_CORE_COH_EN, coherence) + +CPC_CX_ACCESSOR_RW(32, CPC_Cx_VP_RUN, vp_run) +CPC_CX_ACCESSOR_RW(32, CPC_Cx_VP_STOP, vp_stop) +CPC_CX_ACCESSOR_RW(32, CPC_Cx_CMD, cmd) +CPC_CX_ACCESSOR_RW(32, CPC_Cx_STAT_CONF, stat_conf) + +#define CPC_ACCESSOR_RW(sz, off, name) \ + CPS_ACCESSOR_RW(cpc, sz, CPC_BASE, off, name) + +CPC_ACCESSOR_RW(32, CPC_PWRUP_CTL, pwrup_ctl) +CPC_ACCESSOR_RW(32, CPC_CM_STAT_CONF, cm_stat_conf) + +#endif diff --git a/platform/generic/include/mips/p8700.h b/platform/generic/include/mips/p8700.h new file mode 100644 index 00000000..b02aaed4 --- /dev/null +++ b/platform/generic/include/mips/p8700.h @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 MIPS + * + */ + +#ifndef __P8700_H__ +#define __P8700_H__ + +#include + +/* PMA */ +#define CSR_MIPSPMACFG0 0x7e0 +#define CSR_MIPSPMACFG1 0x7e1 +#define CSR_MIPSPMACFG2 0x7e2 +#define CSR_MIPSPMACFG3 0x7e3 +#define CSR_MIPSPMACFG4 0x7e4 +#define CSR_MIPSPMACFG5 0x7e5 +#define CSR_MIPSPMACFG6 0x7e6 +#define CSR_MIPSPMACFG7 0x7e7 +#define CSR_MIPSPMACFG8 0x7e8 +#define CSR_MIPSPMACFG9 0x7e9 +#define CSR_MIPSPMACFG10 0x7ea +#define CSR_MIPSPMACFG11 0x7eb +#define CSR_MIPSPMACFG12 0x7ec +#define CSR_MIPSPMACFG13 0x7ed +#define CSR_MIPSPMACFG14 0x7ee +#define CSR_MIPSPMACFG15 0x7ef + +/* MIPS CCA */ +#define CCA_CACHE_ENABLE 0 +#define CCA_CACHE_DISABLE 2 +#define PMA_SPECULATION (1 << 3) + +/* MIPS CSR */ +#define CSR_MIPSTVEC 0x7c0 +#define CSR_MIPSCONFIG0 0x7d0 +#define CSR_MIPSCONFIG1 0x7d1 +#define CSR_MIPSCONFIG2 0x7d2 +#define CSR_MIPSCONFIG3 0x7d3 +#define CSR_MIPSCONFIG4 0x7d4 +#define CSR_MIPSCONFIG5 0x7d5 +#define CSR_MIPSCONFIG6 0x7d6 +#define CSR_MIPSCONFIG7 0x7d7 +#define CSR_MIPSCONFIG8 0x7d8 +#define CSR_MIPSCONFIG9 0x7d9 +#define CSR_MIPSCONFIG10 0x7da +#define CSR_MIPSCONFIG11 0x7db + +#define MIPSCONFIG5_MTW 4 + +#define GEN_MASK(h, l) (((1ul << ((h) + 1 - (l))) - 1) << (l)) +#define EXT(val, mask) (((val) & (mask)) >> (__builtin_ffs(mask) - 1)) + +/* + * We allocate the number of bits to encode clusters, cores, and harts + * from the original mhartid to a new dense index. + */ +#define NUM_OF_BITS_FOR_CLUSTERS 4 +#define NUM_OF_BITS_FOR_CORES 12 +#define NUM_OF_BITS_FOR_HARTS 4 + +/* To get the field from new/hashed mhartid */ +#define NEW_CLUSTER_SHIFT (NUM_OF_BITS_FOR_CORES + NUM_OF_BITS_FOR_HARTS) +#define NEW_CLUSTER_MASK ((1 << NUM_OF_BITS_FOR_CLUSTERS) - 1) +#define NEW_CORE_SHIFT NUM_OF_BITS_FOR_HARTS +#define NEW_CORE_MASK ((1 << NUM_OF_BITS_FOR_CORES) - 1) +#define NEW_HART_MASK ((1 << NUM_OF_BITS_FOR_HARTS) - 1) +#define cpu_cluster(i) (((i) >> NEW_CLUSTER_SHIFT) & NEW_CLUSTER_MASK) +#define cpu_core(i) (((i) >> NEW_CORE_SHIFT) & NEW_CORE_MASK) +#define cpu_hart(i) ((i) & NEW_HART_MASK) + +#define CPC_BASE (CM_BASE + 0x8000) + +#define SIZE_FOR_CPC_MTIME 0x10000 /* The size must be 2^order */ +#define AIA_BASE (CM_BASE + 0x40000) +#define SIZE_FOR_AIA_M_MODE 0x20000 /* The size must be 2^order */ +#define P8700_ALIGN 0x10000 + +#define CM_BASE_HART_SHIFT 3 +#define CM_BASE_CORE_SHIFT 8 +#define CM_BASE_CLUSTER_SHIFT 19 + +/* GCR Block offsets */ +#define GCR_OFF_LOCAL 0x2000 + +#define GCR_BASE_OFFSET 0x0008 +#define GCR_CORE_COH_EN 0x00f8 +#define GCR_CORE_COH_EN_EN (0x1 << 0) + +#define L2_PFT_CONTROL_OFFSET 0x0300 +#define L2_PFT_CONTROL_B_OFFSET 0x0308 + +/* CPC Block offsets */ +#define CPC_PWRUP_CTL 0x0030 +#define CPC_CM_STAT_CONF 0x1008 + +#define CPC_OFF_LOCAL 0x2000 + +#define CPC_Cx_VP_STOP 0x0020 +#define CPC_Cx_VP_RUN 0x0028 +#define CPC_Cx_CMD 0x0000 + +#define CPC_Cx_CMD_PWRUP 0x3 +#define CPC_Cx_CMD_RESET 0x4 + +#define CPC_Cx_STAT_CONF 0x0008 +#define CPC_Cx_STAT_CONF_SEQ_STATE GEN_MASK(22, 19) +#define CPC_Cx_STAT_CONF_SEQ_STATE_U5 6 +#define CPC_Cx_STAT_CONF_SEQ_STATE_U6 7 + +#endif diff --git a/platform/generic/mips/objects.mk b/platform/generic/mips/objects.mk new file mode 100644 index 00000000..bbbc15a0 --- /dev/null +++ b/platform/generic/mips/objects.mk @@ -0,0 +1,8 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# + +ifeq ($(PLATFORM_RISCV_XLEN), 64) +carray-platform_override_modules-$(CONFIG_PLATFORM_MIPS_P8700) += mips_p8700 +platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o +endif diff --git a/platform/generic/mips/p8700.c b/platform/generic/mips/p8700.c new file mode 100644 index 00000000..6b687179 --- /dev/null +++ b/platform/generic/mips/p8700.c @@ -0,0 +1,270 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 MIPS + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CLUSTERS_IN_PLATFORM > 1 +static void power_up_other_cluster(u32 hartid) +{ + unsigned int stat; + unsigned int timeout; + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid)); + + /* Power up cluster cl core 0 hart 0 */ + write_cpc_pwrup_ctl(hartid, 1, local_p); + + /* Wait for the CM to start up */ + timeout = 100; + while (true) { + stat = read_cpc_cm_stat_conf(hartid, local_p); + stat = EXT(stat, CPC_Cx_STAT_CONF_SEQ_STATE); + if (stat == CPC_Cx_STAT_CONF_SEQ_STATE_U5) + break; + + /* Delay a little while before we start warning */ + if (timeout) { + sbi_dprintf("Delay a little while before we start warning\n"); + timeout--; + } + else { + sbi_printf("Waiting for cluster %u CM to power up... STAT_CONF=0x%x\n", + cpu_cluster(hartid), stat); + break; + } + } +} +#endif + +static int mips_hart_start(u32 hartid, ulong saddr) +{ + unsigned int stat; + unsigned int timeout; + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid)); + + /* Hart 0 is the boot hart, and we don't use the CPC cmd to start. */ + if (hartid == 0) + return SBI_ENOTSUPP; + + if (cpu_hart(hartid) == 0) { + /* Ensure its coherency is disabled */ + write_gcr_co_coherence(hartid, 0, local_p); + + /* Start cluster cl core co hart 0 */ + write_cpc_co_vp_run(hartid, 1 << cpu_hart(hartid), local_p); + + /* Reset cluster cl core co hart 0 */ + write_cpc_co_cmd(hartid, CPC_Cx_CMD_RESET, local_p); + + timeout = 100; + while (true) { + stat = read_cpc_co_stat_conf(hartid, local_p); + stat = EXT(stat, CPC_Cx_STAT_CONF_SEQ_STATE); + if (stat == CPC_Cx_STAT_CONF_SEQ_STATE_U6) + break; + + /* Delay a little while before we start warning */ + if (timeout) { + sbi_timer_mdelay(10); + timeout--; + } + else { + sbi_printf("Waiting for cluster %u core %u hart %u to start... STAT_CONF=0x%x\n", + cpu_cluster(hartid), + cpu_core(hartid), cpu_hart(hartid), + stat); + break; + } + } + } + else { + write_cpc_co_vp_run(hartid, 1 << cpu_hart(hartid), local_p); + } + + return 0; +} + +static int mips_hart_stop() +{ + u32 hartid = current_hartid(); + bool local_p = (cpu_cluster(current_hartid()) == cpu_cluster(hartid)); + + /* Hart 0 is the boot hart, and we don't use the CPC cmd to stop. */ + if (hartid == 0) + return SBI_ENOTSUPP; + + write_cpc_co_vp_stop(hartid, 1 << cpu_hart(hartid), local_p); + + return 0; +} + +static const struct sbi_hsm_device mips_hsm = { + .name = "mips_hsm", + .hart_start = mips_hart_start, + .hart_stop = mips_hart_stop, +}; + +static int mips_p8700_final_init(bool cold_boot) +{ + if (cold_boot) + sbi_hsm_set_device(&mips_hsm); + + return generic_final_init(cold_boot); +} + +static int mips_p8700_early_init(bool cold_boot) +{ + int rc; + + rc = generic_early_init(cold_boot); + if (rc) + return rc; + + if (cold_boot) { +#if CLUSTERS_IN_PLATFORM > 1 + int i; + /* Power up other clusters in the platform. */ + for (i = 1; i < CLUSTERS_IN_PLATFORM; i++) { + power_up_other_cluster(i << NEW_CLUSTER_SHIFT); + } +#endif + + /* For the CPC mtime region, the minimum size is 0x10000. */ + rc = sbi_domain_root_add_memrange(CM_BASE, SIZE_FOR_CPC_MTIME, + P8700_ALIGN, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); + if (rc) + return rc; + + /* For the APLIC and ACLINT m-mode region */ + rc = sbi_domain_root_add_memrange(AIA_BASE, SIZE_FOR_AIA_M_MODE, + P8700_ALIGN, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); + if (rc) + return rc; + +#if CLUSTERS_IN_PLATFORM > 1 + for (i = 0; i < CLUSTERS_IN_PLATFORM; i++) { + /* For the CPC mtime region, the minimum size is 0x10000. */ + rc = sbi_domain_root_add_memrange(GLOBAL_CM_BASE[i], SIZE_FOR_CPC_MTIME, + P8700_ALIGN, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); + if (rc) + return rc; + + /* For the APLIC and ACLINT m-mode region */ + rc = sbi_domain_root_add_memrange(AIA_BASE - CM_BASE + GLOBAL_CM_BASE[i], SIZE_FOR_AIA_M_MODE, + P8700_ALIGN, + (SBI_DOMAIN_MEMREGION_MMIO | + SBI_DOMAIN_MEMREGION_M_READABLE | + SBI_DOMAIN_MEMREGION_M_WRITABLE)); + if (rc) + return rc; + } +#endif + } + + return 0; +} + +static int mips_p8700_nascent_init(void) +{ + u64 hartid = current_hartid(); + u64 cm_base = CM_BASE; + int i; + + /* Coherence enable for every core */ + if (cpu_hart(hartid) == 0) { + cm_base += (cpu_core(hartid) << CM_BASE_CORE_SHIFT); + __raw_writeq(GCR_CORE_COH_EN_EN, + (void *)(cm_base + GCR_OFF_LOCAL + + GCR_CORE_COH_EN)); + mb(); + } + + /* Set up pmp for DRAM */ + csr_write(CSR_PMPADDR14, DRAM_PMP_ADDR); + /* All from 0x0 */ + csr_write(CSR_PMPADDR15, 0x1fffffffffffffff); + csr_write(CSR_PMPCFG2, ((PMP_A_NAPOT|PMP_R|PMP_W|PMP_X)<<56)| + ((PMP_A_NAPOT|PMP_R|PMP_W|PMP_X)<<48)); + /* Set cacheable for pmp6, uncacheable for pmp7 */ + csr_write(CSR_MIPSPMACFG2, ((u64)CCA_CACHE_DISABLE << 56)| + ((u64)CCA_CACHE_ENABLE << 48)); + /* Reset pmpcfg0 */ + csr_write(CSR_PMPCFG0, 0); + /* Reset pmacfg0 */ + csr_write(CSR_MIPSPMACFG0, 0); + mb(); + + /* Per cluster set up */ + if (cpu_core(hartid) == 0 && cpu_hart(hartid) == 0) { + /* Enable L2 prefetch */ + __raw_writel(0xfffff110, + (void *)(cm_base + L2_PFT_CONTROL_OFFSET)); + __raw_writel(0x15ff, + (void *)(cm_base + L2_PFT_CONTROL_B_OFFSET)); + } + + /* Per core set up */ + if (cpu_hart(hartid) == 0) { + /* Enable load pair, store pair, and HTW */ + csr_clear(CSR_MIPSCONFIG7, (1<<12)|(1<<13)|(1<<7)); + + /* Disable noRFO, misaligned load/store */ + csr_set(CSR_MIPSCONFIG7, (1<<25)|(1<<9)); + + /* Enable L1-D$ Prefetch */ + csr_write(CSR_MIPSCONFIG11, 0xff); + + for (i = 0; i < 8; i++) { + csr_set(CSR_MIPSCONFIG8, 4 + 0x100 * i); + csr_set(CSR_MIPSCONFIG9, 8); + mb(); + RISCV_FENCE_I; + } + } + + /* Per hart set up */ + /* Enable AMO and RDTIME illegal instruction exceptions. */ + csr_set(CSR_MIPSCONFIG6, (1<<2)|(1<<1)); + + return 0; +} + +static int mips_p8700_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) +{ + generic_platform_ops.early_init = mips_p8700_early_init; + generic_platform_ops.final_init = mips_p8700_final_init; + generic_platform_ops.nascent_init = mips_p8700_nascent_init; + + return 0; +} + +static const struct fdt_match mips_p8700_match[] = { + { .compatible = "mips,p8700" }, + { }, +}; + +const struct fdt_driver mips_p8700 = { + .match_table = mips_p8700_match, + .init = mips_p8700_platform_init, +};